Skip to content

Commit c9c88a4

Browse files
dcpleungcarlescufi
authored andcommitted
xtensa: mmu: cache and TLB actions when adding thread to domain
When adding a thread to a memory domain, we need to also update the mapped page table if it is the current running thread on the same CPU. If it's not on the same CPU, we need to notify the other CPUs in case the thread is running in one of them. Signed-off-by: Daniel Leung <[email protected]> Signed-off-by: Anas Nashif <[email protected]> Signed-off-by: Flavio Ceolin <[email protected]>
1 parent 81ea436 commit c9c88a4

File tree

1 file changed

+53
-27
lines changed

1 file changed

+53
-27
lines changed

arch/xtensa/core/xtensa_mmu.c

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
#include <kernel_arch_func.h>
1717
#include <mmu.h>
1818

19+
/* Skip TLB IPI when updating page tables.
20+
* This allows us to send IPI only after the last
21+
* changes of a series.
22+
*/
23+
#define OPTION_NO_TLB_IPI BIT(0)
24+
1925
/* Level 1 contains page table entries
2026
* necessary to map the page table itself.
2127
*/
@@ -995,7 +1001,8 @@ static int region_map_update(uint32_t *ptables, uintptr_t start,
9951001
}
9961002

9971003
static inline int update_region(uint32_t *ptables, uintptr_t start,
998-
size_t size, uint32_t ring, uint32_t flags)
1004+
size_t size, uint32_t ring, uint32_t flags,
1005+
uint32_t option)
9991006
{
10001007
int ret;
10011008
k_spinlock_key_t key;
@@ -1027,28 +1034,19 @@ static inline int update_region(uint32_t *ptables, uintptr_t start,
10271034
#endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */
10281035

10291036
#if CONFIG_MP_MAX_NUM_CPUS > 1
1030-
z_xtensa_mmu_tlb_ipi();
1037+
if ((option & OPTION_NO_TLB_IPI) != OPTION_NO_TLB_IPI) {
1038+
z_xtensa_mmu_tlb_ipi();
1039+
}
10311040
#endif
10321041

10331042
k_spin_unlock(&xtensa_mmu_lock, key);
10341043

10351044
return ret;
10361045
}
10371046

1038-
static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size)
1047+
static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, uint32_t option)
10391048
{
1040-
return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W);
1041-
}
1042-
1043-
void xtensa_set_stack_perms(struct k_thread *thread)
1044-
{
1045-
if ((thread->base.user_options & K_USER) == 0) {
1046-
return;
1047-
}
1048-
1049-
update_region(thread_page_tables_get(thread),
1050-
thread->stack_info.start, thread->stack_info.size,
1051-
Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB);
1049+
return update_region(ptables, start, size, Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_W, option);
10521050
}
10531051

10541052
void xtensa_user_stack_perms(struct k_thread *thread)
@@ -1058,7 +1056,7 @@ void xtensa_user_stack_perms(struct k_thread *thread)
10581056

10591057
update_region(thread_page_tables_get(thread),
10601058
thread->stack_info.start, thread->stack_info.size,
1061-
Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB);
1059+
Z_XTENSA_USER_RING, Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, 0);
10621060
}
10631061

10641062
int arch_mem_domain_max_partitions_get(void)
@@ -1073,7 +1071,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
10731071

10741072
/* Reset the partition's region back to defaults */
10751073
return reset_region(domain->arch.ptables, partition->start,
1076-
partition->size);
1074+
partition->size, 0);
10771075
}
10781076

10791077
int arch_mem_domain_partition_add(struct k_mem_domain *domain,
@@ -1083,7 +1081,7 @@ int arch_mem_domain_partition_add(struct k_mem_domain *domain,
10831081
struct k_mem_partition *partition = &domain->partitions[partition_id];
10841082

10851083
return update_region(domain->arch.ptables, partition->start,
1086-
partition->size, ring, partition->attr);
1084+
partition->size, ring, partition->attr, 0);
10871085
}
10881086

10891087
/* These APIs don't need to do anything */
@@ -1101,19 +1099,42 @@ int arch_mem_domain_thread_add(struct k_thread *thread)
11011099
is_user = (thread->base.user_options & K_USER) != 0;
11021100
is_migration = (old_ptables != NULL) && is_user;
11031101

1104-
/* Give access to the thread's stack in its new
1105-
* memory domain if it is migrating.
1106-
*/
1107-
if (is_migration) {
1108-
xtensa_set_stack_perms(thread);
1109-
}
1110-
11111102
if (is_migration) {
1103+
/* Give access to the thread's stack in its new
1104+
* memory domain if it is migrating.
1105+
*/
1106+
update_region(thread_page_tables_get(thread),
1107+
thread->stack_info.start, thread->stack_info.size,
1108+
Z_XTENSA_USER_RING,
1109+
Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB,
1110+
OPTION_NO_TLB_IPI);
1111+
/* and reset thread's stack permission in
1112+
* the old page tables.
1113+
*/
11121114
ret = reset_region(old_ptables,
11131115
thread->stack_info.start,
1114-
thread->stack_info.size);
1116+
thread->stack_info.size, 0);
1117+
}
1118+
1119+
/* Need to switch to new page tables if this is
1120+
* the current thread running.
1121+
*/
1122+
if (thread == _current_cpu->current) {
1123+
switch_page_tables(thread->arch.ptables, true, true);
11151124
}
11161125

1126+
#if CONFIG_MP_MAX_NUM_CPUS > 1
1127+
/* Need to tell other CPUs to switch to the new page table
1128+
* in case the thread is running on one of them.
1129+
*
1130+
* Note that there is no need to send TLB IPI if this is
1131+
* migration as it was sent above during reset_region().
1132+
*/
1133+
if ((thread != _current_cpu->current) && !is_migration) {
1134+
z_xtensa_mmu_tlb_ipi();
1135+
}
1136+
#endif
1137+
11171138
return ret;
11181139
}
11191140

@@ -1136,10 +1157,15 @@ int arch_mem_domain_thread_remove(struct k_thread *thread)
11361157

11371158
/* Restore permissions on the thread's stack area since it is no
11381159
* longer a member of the domain.
1160+
*
1161+
* Note that, since every thread must have an associated memory
1162+
* domain, removing a thread from domain will be followed by
1163+
* adding it back to another. So there is no need to send TLB IPI
1164+
* at this point.
11391165
*/
11401166
return reset_region(domain->arch.ptables,
11411167
thread->stack_info.start,
1142-
thread->stack_info.size);
1168+
thread->stack_info.size, OPTION_NO_TLB_IPI);
11431169
}
11441170

11451171
static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool write)

0 commit comments

Comments
 (0)