@@ -28,9 +28,13 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
2828
2929static uint64_t xlat_tables [CONFIG_MAX_XLAT_TABLES * Ln_XLAT_NUM_ENTRIES ]
3030 __aligned (Ln_XLAT_NUM_ENTRIES * sizeof (uint64_t ));
31- static uint16_t xlat_use_count [CONFIG_MAX_XLAT_TABLES ];
31+ static int xlat_use_count [CONFIG_MAX_XLAT_TABLES ];
3232static struct k_spinlock xlat_lock ;
3333
34+ /* Usage count value range */
35+ #define XLAT_PTE_COUNT_MASK GENMASK(15, 0)
36+ #define XLAT_REF_COUNT_UNIT BIT(16)
37+
3438/* Returns a reference to a free table */
3539static uint64_t * new_table (void )
3640{
@@ -39,9 +43,9 @@ static uint64_t *new_table(void)
3943
4044 /* Look for a free table. */
4145 for (i = 0U ; i < CONFIG_MAX_XLAT_TABLES ; i ++ ) {
42- if (xlat_use_count [i ] == 0U ) {
46+ if (xlat_use_count [i ] == 0 ) {
4347 table = & xlat_tables [i * Ln_XLAT_NUM_ENTRIES ];
44- xlat_use_count [i ] = 1U ;
48+ xlat_use_count [i ] = XLAT_REF_COUNT_UNIT ;
4549 MMU_DEBUG ("allocating table [%d]%p\n" , i , table );
4650 return table ;
4751 }
@@ -59,29 +63,43 @@ static inline unsigned int table_index(uint64_t *pte)
5963 return i ;
6064}
6165
62- /* Makes a table free for reuse . */
63- static void free_table (uint64_t * table )
66+ /* Adjusts usage count and returns current count . */
67+ static int table_usage (uint64_t * table , int adjustment )
6468{
6569 unsigned int i = table_index (table );
70+ int prev_count = xlat_use_count [i ];
71+ int new_count = prev_count + adjustment ;
6672
67- MMU_DEBUG ("freeing table [%d]%p\n" , i , table );
68- __ASSERT (xlat_use_count [i ] == 1U , "table still in use" );
69- xlat_use_count [i ] = 0U ;
73+ if (IS_ENABLED (DUMP_PTE ) || new_count == 0 ) {
74+ MMU_DEBUG ("table [%d]%p: usage %#x -> %#x\n" , i , table , prev_count , new_count );
75+ }
76+
77+ __ASSERT (new_count >= 0 ,
78+ "table use count underflow" );
79+ __ASSERT (new_count == 0 || new_count >= XLAT_REF_COUNT_UNIT ,
80+ "table in use with no reference to it" );
81+ __ASSERT ((new_count & XLAT_PTE_COUNT_MASK ) <= Ln_XLAT_NUM_ENTRIES ,
82+ "table PTE count overflow" );
83+
84+ xlat_use_count [i ] = new_count ;
85+ return new_count ;
7086}
7187
72- /* Adjusts usage count and returns current count. */
73- static int table_usage (uint64_t * table , int adjustment )
88+ static inline void inc_table_ref (uint64_t * table )
7489{
75- unsigned int i = table_index (table );
90+ table_usage (table , XLAT_REF_COUNT_UNIT );
91+ }
7692
77- xlat_use_count [i ] += adjustment ;
78- __ASSERT (xlat_use_count [i ] > 0 , "usage count underflow" );
79- return xlat_use_count [i ];
93+ static inline void dec_table_ref (uint64_t * table )
94+ {
95+ int ref_unit = XLAT_REF_COUNT_UNIT ;
96+
97+ table_usage (table , - ref_unit );
8098}
8199
82100static inline bool is_table_unused (uint64_t * table )
83101{
84- return table_usage (table , 0 ) == 1 ;
102+ return ( table_usage (table , 0 ) & XLAT_PTE_COUNT_MASK ) == 0 ;
85103}
86104
87105static inline bool is_free_desc (uint64_t desc )
@@ -225,7 +243,6 @@ static uint64_t *expand_to_table(uint64_t *pte, unsigned int level)
225243
226244 /* Link the new table in place of the pte it replaces */
227245 set_pte_table_desc (pte , table , level );
228- table_usage (table , 1 );
229246
230247 return table ;
231248}
@@ -300,7 +317,7 @@ static int set_mapping(struct arm_mmu_ptables *ptables,
300317 /* recursively free unused tables if any */
301318 while (level != BASE_XLAT_LEVEL &&
302319 is_table_unused (pte )) {
303- free_table (pte );
320+ dec_table_ref (pte );
304321 pte = ptes [-- level ];
305322 set_pte_block_desc (pte , 0 , level );
306323 table_usage (pte , -1 );
@@ -347,8 +364,8 @@ static uint64_t *dup_table(uint64_t *src_table, unsigned int level)
347364 }
348365
349366 dst_table [i ] = src_table [i ];
350- if (is_table_desc (src_table [i ], level )) {
351- table_usage (pte_desc_table (src_table [i ]), 1 );
367+ if (is_table_desc (dst_table [i ], level )) {
368+ inc_table_ref (pte_desc_table (dst_table [i ]));
352369 }
353370 if (!is_free_desc (dst_table [i ])) {
354371 table_usage (dst_table , 1 );
@@ -388,8 +405,7 @@ static int privatize_table(uint64_t *dst_table, uint64_t *src_table,
388405 return - ENOMEM ;
389406 }
390407 set_pte_table_desc (& dst_table [i ], dst_subtable , level );
391- table_usage (dst_subtable , 1 );
392- table_usage (src_subtable , -1 );
408+ dec_table_ref (src_subtable );
393409 }
394410
395411 ret = privatize_table (dst_subtable , src_subtable ,
@@ -436,15 +452,14 @@ static void discard_table(uint64_t *table, unsigned int level)
436452
437453 for (i = 0U ; i < Ln_XLAT_NUM_ENTRIES ; i ++ ) {
438454 if (is_table_desc (table [i ], level )) {
439- table_usage (pte_desc_table (table [i ]), -1 );
440455 discard_table (pte_desc_table (table [i ]), level + 1 );
456+ dec_table_ref (pte_desc_table (table [i ]));
441457 }
442458 if (!is_free_desc (table [i ])) {
443459 table [i ] = 0U ;
444460 table_usage (table , -1 );
445461 }
446462 }
447- free_table (table );
448463}
449464
450465static int globalize_table (uint64_t * dst_table , uint64_t * src_table ,
@@ -497,15 +512,15 @@ static int globalize_table(uint64_t *dst_table, uint64_t *src_table,
497512 table_usage (dst_table , -1 );
498513 }
499514 if (is_table_desc (src_table [i ], level )) {
500- table_usage (pte_desc_table (src_table [i ]), 1 );
515+ inc_table_ref (pte_desc_table (src_table [i ]));
501516 }
502517 dst_table [i ] = src_table [i ];
503518 debug_show_pte (& dst_table [i ], level );
504519
505520 if (old_table ) {
506521 /* we can discard the whole branch */
507- table_usage (old_table , -1 );
508522 discard_table (old_table , level + 1 );
523+ dec_table_ref (old_table );
509524 }
510525 }
511526
0 commit comments