Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4460d028
Commit
4460d028
authored
Aug 31, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/topic/rbtree' into regmap-next
parents
db00cb99
3f4ff561
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
150 additions
and
117 deletions
+150
-117
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+1
-13
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache-rbtree.c
+130
-51
drivers/base/regmap/regcache.c
drivers/base/regmap/regcache.c
+19
-53
No files found.
drivers/base/regmap/internal.h
View file @
4460d028
...
...
@@ -128,9 +128,6 @@ struct regmap {
void
*
cache
;
u32
cache_dirty
;
unsigned
long
*
cache_present
;
unsigned
int
cache_present_nbits
;
struct
reg_default
*
patch
;
int
patch_regs
;
...
...
@@ -203,6 +200,7 @@ int regcache_write(struct regmap *map,
unsigned
int
reg
,
unsigned
int
value
);
int
regcache_sync
(
struct
regmap
*
map
);
int
regcache_sync_block
(
struct
regmap
*
map
,
void
*
block
,
unsigned
long
*
cache_present
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
);
...
...
@@ -218,16 +216,6 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
bool
regcache_set_val
(
struct
regmap
*
map
,
void
*
base
,
unsigned
int
idx
,
unsigned
int
val
);
int
regcache_lookup_reg
(
struct
regmap
*
map
,
unsigned
int
reg
);
int
regcache_set_reg_present
(
struct
regmap
*
map
,
unsigned
int
reg
);
static
inline
bool
regcache_reg_present
(
struct
regmap
*
map
,
unsigned
int
reg
)
{
if
(
!
map
->
cache_present
)
return
false
;
if
(
reg
>
map
->
cache_present_nbits
)
return
false
;
return
map
->
cache_present
[
BIT_WORD
(
reg
)]
&
BIT_MASK
(
reg
);
}
int
_regmap_raw_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
const
void
*
val
,
size_t
val_len
,
bool
async
);
...
...
drivers/base/regmap/regcache-rbtree.c
View file @
4460d028
...
...
@@ -29,6 +29,8 @@ struct regcache_rbtree_node {
unsigned
int
base_reg
;
/* block of adjacent registers */
void
*
block
;
/* Which registers are present */
long
*
cache_present
;
/* number of registers available in the block */
unsigned
int
blklen
;
}
__attribute__
((
packed
));
...
...
@@ -57,6 +59,7 @@ static void regcache_rbtree_set_register(struct regmap *map,
struct
regcache_rbtree_node
*
rbnode
,
unsigned
int
idx
,
unsigned
int
val
)
{
set_bit
(
idx
,
rbnode
->
cache_present
);
regcache_set_val
(
map
,
rbnode
->
block
,
idx
,
val
);
}
...
...
@@ -146,13 +149,13 @@ static int rbtree_show(struct seq_file *s, void *ignored)
map
->
lock
(
map
->
lock_arg
);
mem_size
=
sizeof
(
*
rbtree_ctx
);
mem_size
+=
BITS_TO_LONGS
(
map
->
cache_present_nbits
)
*
sizeof
(
long
);
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
!=
NULL
;
node
=
rb_next
(
node
))
{
n
=
container_of
(
node
,
struct
regcache_rbtree_node
,
node
);
mem_size
+=
sizeof
(
*
n
);
mem_size
+=
(
n
->
blklen
*
map
->
cache_word_size
);
mem_size
+=
BITS_TO_LONGS
(
n
->
blklen
)
*
sizeof
(
long
);
regcache_rbtree_get_base_top_reg
(
map
,
n
,
&
base
,
&
top
);
this_registers
=
((
top
-
base
)
/
map
->
reg_stride
)
+
1
;
...
...
@@ -245,6 +248,7 @@ static int regcache_rbtree_exit(struct regmap *map)
rbtree_node
=
rb_entry
(
next
,
struct
regcache_rbtree_node
,
node
);
next
=
rb_next
(
&
rbtree_node
->
node
);
rb_erase
(
&
rbtree_node
->
node
,
&
rbtree_ctx
->
root
);
kfree
(
rbtree_node
->
cache_present
);
kfree
(
rbtree_node
->
block
);
kfree
(
rbtree_node
);
}
...
...
@@ -265,7 +269,7 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode
=
regcache_rbtree_lookup
(
map
,
reg
);
if
(
rbnode
)
{
reg_tmp
=
(
reg
-
rbnode
->
base_reg
)
/
map
->
reg_stride
;
if
(
!
regcache_reg_present
(
map
,
reg
))
if
(
!
test_bit
(
reg_tmp
,
rbnode
->
cache_present
))
return
-
ENOENT
;
*
value
=
regcache_rbtree_get_register
(
map
,
rbnode
,
reg_tmp
);
}
else
{
...
...
@@ -278,27 +282,45 @@ static int regcache_rbtree_read(struct regmap *map,
static
int
regcache_rbtree_insert_to_block
(
struct
regmap
*
map
,
struct
regcache_rbtree_node
*
rbnode
,
unsigned
int
pos
,
unsigned
int
reg
,
unsigned
int
base_reg
,
unsigned
int
top_reg
,
unsigned
int
reg
,
unsigned
int
value
)
{
unsigned
int
blklen
;
unsigned
int
pos
,
offset
;
unsigned
long
*
present
;
u8
*
blk
;
blklen
=
(
top_reg
-
base_reg
)
/
map
->
reg_stride
+
1
;
pos
=
(
reg
-
base_reg
)
/
map
->
reg_stride
;
offset
=
(
rbnode
->
base_reg
-
base_reg
)
/
map
->
reg_stride
;
blk
=
krealloc
(
rbnode
->
block
,
(
rbnode
->
blklen
+
1
)
*
map
->
cache_word_size
,
blklen
*
map
->
cache_word_size
,
GFP_KERNEL
);
if
(
!
blk
)
return
-
ENOMEM
;
present
=
krealloc
(
rbnode
->
cache_present
,
BITS_TO_LONGS
(
blklen
)
*
sizeof
(
*
present
),
GFP_KERNEL
);
if
(
!
present
)
{
kfree
(
blk
);
return
-
ENOMEM
;
}
/* insert the register value in the correct place in the rbnode block */
memmove
(
blk
+
(
pos
+
1
)
*
map
->
cache_word_size
,
blk
+
pos
*
map
->
cache_word_size
,
(
rbnode
->
blklen
-
pos
)
*
map
->
cache_word_size
);
if
(
pos
==
0
)
{
memmove
(
blk
+
offset
*
map
->
cache_word_size
,
blk
,
rbnode
->
blklen
*
map
->
cache_word_size
);
bitmap_shift_right
(
present
,
present
,
offset
,
blklen
);
}
/* update the rbnode block, its size and the base register */
rbnode
->
block
=
blk
;
rbnode
->
blklen
++
;
if
(
!
pos
)
rbnode
->
base_reg
=
reg
;
rbnode
->
blklen
=
blklen
;
rbnode
->
base_reg
=
base_reg
;
rbnode
->
cache_present
=
present
;
regcache_rbtree_set_register
(
map
,
rbnode
,
pos
,
value
);
return
0
;
...
...
@@ -325,8 +347,8 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
if
(
i
!=
map
->
rd_table
->
n_yes_ranges
)
{
range
=
&
map
->
rd_table
->
yes_ranges
[
i
];
rbnode
->
blklen
=
range
->
range_max
-
range
->
range_min
+
1
;
rbnode
->
blklen
=
(
range
->
range_max
-
range
->
range_min
)
/
map
->
reg_stride
+
1
;
rbnode
->
base_reg
=
range
->
range_min
;
}
}
...
...
@@ -338,12 +360,21 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
rbnode
->
block
=
kmalloc
(
rbnode
->
blklen
*
map
->
cache_word_size
,
GFP_KERNEL
);
if
(
!
rbnode
->
block
)
{
kfree
(
rbnode
);
return
NULL
;
}
if
(
!
rbnode
->
block
)
goto
err_free
;
rbnode
->
cache_present
=
kzalloc
(
BITS_TO_LONGS
(
rbnode
->
blklen
)
*
sizeof
(
*
rbnode
->
cache_present
),
GFP_KERNEL
);
if
(
!
rbnode
->
cache_present
)
goto
err_free_block
;
return
rbnode
;
err_free_block:
kfree
(
rbnode
->
block
);
err_free:
kfree
(
rbnode
);
return
NULL
;
}
static
int
regcache_rbtree_write
(
struct
regmap
*
map
,
unsigned
int
reg
,
...
...
@@ -353,15 +384,9 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
struct
regcache_rbtree_node
*
rbnode
,
*
rbnode_tmp
;
struct
rb_node
*
node
;
unsigned
int
reg_tmp
;
unsigned
int
pos
;
int
i
;
int
ret
;
rbtree_ctx
=
map
->
cache
;
/* update the reg_present bitmap, make space if necessary */
ret
=
regcache_set_reg_present
(
map
,
reg
);
if
(
ret
<
0
)
return
ret
;
/* if we can't locate it in the cached rbnode we'll have
* to traverse the rbtree looking for it.
...
...
@@ -371,30 +396,43 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
reg_tmp
=
(
reg
-
rbnode
->
base_reg
)
/
map
->
reg_stride
;
regcache_rbtree_set_register
(
map
,
rbnode
,
reg_tmp
,
value
);
}
else
{
unsigned
int
base_reg
,
top_reg
;
unsigned
int
new_base_reg
,
new_top_reg
;
unsigned
int
min
,
max
;
unsigned
int
max_dist
;
max_dist
=
map
->
reg_stride
*
sizeof
(
*
rbnode_tmp
)
/
map
->
cache_word_size
;
if
(
reg
<
max_dist
)
min
=
0
;
else
min
=
reg
-
max_dist
;
max
=
reg
+
max_dist
;
/* look for an adjacent register to the one we are about to add */
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
;
node
=
rb_next
(
node
))
{
rbnode_tmp
=
rb_entry
(
node
,
struct
regcache_rbtree_node
,
node
);
for
(
i
=
0
;
i
<
rbnode_tmp
->
blklen
;
i
++
)
{
reg_tmp
=
rbnode_tmp
->
base_reg
+
(
i
*
map
->
reg_stride
);
if
(
abs
(
reg_tmp
-
reg
)
!=
map
->
reg_stride
)
continue
;
/* decide where in the block to place our register */
if
(
reg_tmp
+
map
->
reg_stride
==
reg
)
pos
=
i
+
1
;
else
pos
=
i
;
ret
=
regcache_rbtree_insert_to_block
(
map
,
rbnode_tmp
,
pos
,
reg
,
value
);
if
(
ret
)
return
ret
;
rbtree_ctx
->
cached_rbnode
=
rbnode_tmp
;
return
0
;
regcache_rbtree_get_base_top_reg
(
map
,
rbnode_tmp
,
&
base_reg
,
&
top_reg
);
if
(
base_reg
<=
max
&&
top_reg
>=
min
)
{
new_base_reg
=
min
(
reg
,
base_reg
);
new_top_reg
=
max
(
reg
,
top_reg
);
}
else
{
continue
;
}
ret
=
regcache_rbtree_insert_to_block
(
map
,
rbnode_tmp
,
new_base_reg
,
new_top_reg
,
reg
,
value
);
if
(
ret
)
return
ret
;
rbtree_ctx
->
cached_rbnode
=
rbnode_tmp
;
return
0
;
}
/* We did not manage to find a place to insert it in
...
...
@@ -418,30 +456,34 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
struct
regcache_rbtree_ctx
*
rbtree_ctx
;
struct
rb_node
*
node
;
struct
regcache_rbtree_node
*
rbnode
;
unsigned
int
base_reg
,
top_reg
;
unsigned
int
start
,
end
;
int
ret
;
int
base
,
end
;
rbtree_ctx
=
map
->
cache
;
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
;
node
=
rb_next
(
node
))
{
rbnode
=
rb_entry
(
node
,
struct
regcache_rbtree_node
,
node
);
if
(
rbnode
->
base_reg
>
max
)
regcache_rbtree_get_base_top_reg
(
map
,
rbnode
,
&
base_reg
,
&
top_reg
);
if
(
base_reg
>
max
)
break
;
if
(
rbnode
->
base_reg
+
rbnode
->
blklen
<
min
)
if
(
top_reg
<
min
)
continue
;
if
(
min
>
rbnode
->
base_reg
)
base
=
min
-
rbnode
->
base_reg
;
if
(
min
>
base_reg
)
start
=
(
min
-
base_reg
)
/
map
->
reg_stride
;
else
base
=
0
;
start
=
0
;
if
(
max
<
rbnode
->
base_reg
+
rbnode
->
blklen
)
end
=
max
-
rbnode
->
base_reg
+
1
;
if
(
max
<
top_reg
)
end
=
(
max
-
base_reg
)
/
map
->
reg_stride
+
1
;
else
end
=
rbnode
->
blklen
;
ret
=
regcache_sync_block
(
map
,
rbnode
->
block
,
rbnode
->
base_reg
,
base
,
end
);
ret
=
regcache_sync_block
(
map
,
rbnode
->
block
,
rbnode
->
cache_present
,
rbnode
->
base_reg
,
start
,
end
);
if
(
ret
!=
0
)
return
ret
;
}
...
...
@@ -449,6 +491,42 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
return
regmap_async_complete
(
map
);
}
static
int
regcache_rbtree_drop
(
struct
regmap
*
map
,
unsigned
int
min
,
unsigned
int
max
)
{
struct
regcache_rbtree_ctx
*
rbtree_ctx
;
struct
regcache_rbtree_node
*
rbnode
;
struct
rb_node
*
node
;
unsigned
int
base_reg
,
top_reg
;
unsigned
int
start
,
end
;
rbtree_ctx
=
map
->
cache
;
for
(
node
=
rb_first
(
&
rbtree_ctx
->
root
);
node
;
node
=
rb_next
(
node
))
{
rbnode
=
rb_entry
(
node
,
struct
regcache_rbtree_node
,
node
);
regcache_rbtree_get_base_top_reg
(
map
,
rbnode
,
&
base_reg
,
&
top_reg
);
if
(
base_reg
>
max
)
break
;
if
(
top_reg
<
min
)
continue
;
if
(
min
>
base_reg
)
start
=
(
min
-
base_reg
)
/
map
->
reg_stride
;
else
start
=
0
;
if
(
max
<
top_reg
)
end
=
(
max
-
base_reg
)
/
map
->
reg_stride
+
1
;
else
end
=
rbnode
->
blklen
;
bitmap_clear
(
rbnode
->
cache_present
,
start
,
end
-
start
);
}
return
0
;
}
struct
regcache_ops
regcache_rbtree_ops
=
{
.
type
=
REGCACHE_RBTREE
,
.
name
=
"rbtree"
,
...
...
@@ -456,5 +534,6 @@ struct regcache_ops regcache_rbtree_ops = {
.
exit
=
regcache_rbtree_exit
,
.
read
=
regcache_rbtree_read
,
.
write
=
regcache_rbtree_write
,
.
sync
=
regcache_rbtree_sync
.
sync
=
regcache_rbtree_sync
,
.
drop
=
regcache_rbtree_drop
,
};
drivers/base/regmap/regcache.c
View file @
4460d028
...
...
@@ -121,8 +121,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
map
->
reg_defaults_raw
=
config
->
reg_defaults_raw
;
map
->
cache_word_size
=
DIV_ROUND_UP
(
config
->
val_bits
,
8
);
map
->
cache_size_raw
=
map
->
cache_word_size
*
config
->
num_reg_defaults_raw
;
map
->
cache_present
=
NULL
;
map
->
cache_present_nbits
=
0
;
map
->
cache
=
NULL
;
map
->
cache_ops
=
cache_types
[
i
];
...
...
@@ -181,7 +179,6 @@ void regcache_exit(struct regmap *map)
BUG_ON
(
!
map
->
cache_ops
);
kfree
(
map
->
cache_present
);
kfree
(
map
->
reg_defaults
);
if
(
map
->
cache_free
)
kfree
(
map
->
reg_defaults_raw
);
...
...
@@ -407,22 +404,16 @@ EXPORT_SYMBOL_GPL(regcache_sync_region);
int
regcache_drop_region
(
struct
regmap
*
map
,
unsigned
int
min
,
unsigned
int
max
)
{
unsigned
int
reg
;
int
ret
=
0
;
if
(
!
map
->
cache_
present
&&
!
(
map
->
cache_ops
&&
map
->
cache_ops
->
drop
)
)
if
(
!
map
->
cache_
ops
||
!
map
->
cache_ops
->
drop
)
return
-
EINVAL
;
map
->
lock
(
map
->
lock_arg
);
trace_regcache_drop_region
(
map
->
dev
,
min
,
max
);
if
(
map
->
cache_present
)
for
(
reg
=
min
;
reg
<
max
+
1
;
reg
++
)
clear_bit
(
reg
,
map
->
cache_present
);
if
(
map
->
cache_ops
&&
map
->
cache_ops
->
drop
)
ret
=
map
->
cache_ops
->
drop
(
map
,
min
,
max
);
ret
=
map
->
cache_ops
->
drop
(
map
,
min
,
max
);
map
->
unlock
(
map
->
lock_arg
);
...
...
@@ -490,42 +481,6 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL
(
regcache_cache_bypass
);
int
regcache_set_reg_present
(
struct
regmap
*
map
,
unsigned
int
reg
)
{
unsigned
long
*
cache_present
;
unsigned
int
cache_present_size
;
unsigned
int
nregs
;
int
i
;
nregs
=
reg
+
1
;
cache_present_size
=
BITS_TO_LONGS
(
nregs
);
cache_present_size
*=
sizeof
(
long
);
if
(
!
map
->
cache_present
)
{
cache_present
=
kmalloc
(
cache_present_size
,
GFP_KERNEL
);
if
(
!
cache_present
)
return
-
ENOMEM
;
bitmap_zero
(
cache_present
,
nregs
);
map
->
cache_present
=
cache_present
;
map
->
cache_present_nbits
=
nregs
;
}
if
(
nregs
>
map
->
cache_present_nbits
)
{
cache_present
=
krealloc
(
map
->
cache_present
,
cache_present_size
,
GFP_KERNEL
);
if
(
!
cache_present
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
nregs
;
i
++
)
if
(
i
>=
map
->
cache_present_nbits
)
clear_bit
(
i
,
cache_present
);
map
->
cache_present
=
cache_present
;
map
->
cache_present_nbits
=
nregs
;
}
set_bit
(
reg
,
map
->
cache_present
);
return
0
;
}
bool
regcache_set_val
(
struct
regmap
*
map
,
void
*
base
,
unsigned
int
idx
,
unsigned
int
val
)
{
...
...
@@ -617,7 +572,16 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
return
-
ENOENT
;
}
static
bool
regcache_reg_present
(
unsigned
long
*
cache_present
,
unsigned
int
idx
)
{
if
(
!
cache_present
)
return
true
;
return
test_bit
(
idx
,
cache_present
);
}
static
int
regcache_sync_block_single
(
struct
regmap
*
map
,
void
*
block
,
unsigned
long
*
cache_present
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
)
{
...
...
@@ -627,7 +591,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
for
(
i
=
start
;
i
<
end
;
i
++
)
{
regtmp
=
block_base
+
(
i
*
map
->
reg_stride
);
if
(
!
regcache_reg_present
(
map
,
regtmp
))
if
(
!
regcache_reg_present
(
cache_present
,
i
))
continue
;
val
=
regcache_get_val
(
map
,
block
,
i
);
...
...
@@ -678,6 +642,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
}
static
int
regcache_sync_block_raw
(
struct
regmap
*
map
,
void
*
block
,
unsigned
long
*
cache_present
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
)
{
...
...
@@ -690,7 +655,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
for
(
i
=
start
;
i
<
end
;
i
++
)
{
regtmp
=
block_base
+
(
i
*
map
->
reg_stride
);
if
(
!
regcache_reg_present
(
map
,
regtmp
))
{
if
(
!
regcache_reg_present
(
cache_present
,
i
))
{
ret
=
regcache_sync_block_raw_flush
(
map
,
&
data
,
base
,
regtmp
);
if
(
ret
!=
0
)
...
...
@@ -721,13 +686,14 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
}
int
regcache_sync_block
(
struct
regmap
*
map
,
void
*
block
,
unsigned
long
*
cache_present
,
unsigned
int
block_base
,
unsigned
int
start
,
unsigned
int
end
)
{
if
(
regmap_can_raw_write
(
map
))
return
regcache_sync_block_raw
(
map
,
block
,
block_base
,
start
,
end
);
return
regcache_sync_block_raw
(
map
,
block
,
cache_present
,
block_base
,
start
,
end
);
else
return
regcache_sync_block_single
(
map
,
block
,
block_base
,
start
,
end
);
return
regcache_sync_block_single
(
map
,
block
,
cache_present
,
block_base
,
start
,
end
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment