18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* arch/sparc64/mm/tsb.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/preempt.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 118c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/page.h> 148c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 158c2ecf20Sopenharmony_ci#include <asm/setup.h> 168c2ecf20Sopenharmony_ci#include <asm/tsb.h> 178c2ecf20Sopenharmony_ci#include <asm/tlb.h> 188c2ecf20Sopenharmony_ci#include <asm/oplib.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciextern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES]; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic inline unsigned long tsb_hash(unsigned long vaddr, unsigned long hash_shift, unsigned long nentries) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci vaddr >>= hash_shift; 258c2ecf20Sopenharmony_ci return vaddr & (nentries - 1); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic inline int tag_compare(unsigned long tag, unsigned long vaddr) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci return (tag == (vaddr >> 22)); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic void flush_tsb_kernel_range_scan(unsigned long start, unsigned long end) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci unsigned long idx; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci for (idx = 0; idx < KERNEL_TSB_NENTRIES; idx++) { 388c2ecf20Sopenharmony_ci struct tsb *ent = &swapper_tsb[idx]; 398c2ecf20Sopenharmony_ci unsigned long match = idx << 13; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci match |= (ent->tag << 22); 428c2ecf20Sopenharmony_ci if (match >= start && match < end) 438c2ecf20Sopenharmony_ci ent->tag = (1UL << TSB_TAG_INVALID_BIT); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* TSB flushes need only occur on the processor initiating the address 488c2ecf20Sopenharmony_ci * space modification, not on each cpu the address space has run on. 498c2ecf20Sopenharmony_ci * Only the TLB flush needs that treatment. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_civoid flush_tsb_kernel_range(unsigned long start, unsigned long end) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned long v; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if ((end - start) >> PAGE_SHIFT >= 2 * KERNEL_TSB_NENTRIES) 578c2ecf20Sopenharmony_ci return flush_tsb_kernel_range_scan(start, end); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci for (v = start; v < end; v += PAGE_SIZE) { 608c2ecf20Sopenharmony_ci unsigned long hash = tsb_hash(v, PAGE_SHIFT, 618c2ecf20Sopenharmony_ci KERNEL_TSB_NENTRIES); 628c2ecf20Sopenharmony_ci struct tsb *ent = &swapper_tsb[hash]; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (tag_compare(ent->tag, v)) 658c2ecf20Sopenharmony_ci ent->tag = (1UL << TSB_TAG_INVALID_BIT); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void __flush_tsb_one_entry(unsigned long tsb, unsigned long v, 708c2ecf20Sopenharmony_ci unsigned long hash_shift, 718c2ecf20Sopenharmony_ci unsigned long nentries) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci unsigned long tag, ent, hash; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci v &= ~0x1UL; 768c2ecf20Sopenharmony_ci hash = tsb_hash(v, hash_shift, nentries); 778c2ecf20Sopenharmony_ci ent = tsb + (hash * sizeof(struct tsb)); 788c2ecf20Sopenharmony_ci tag = (v >> 22UL); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci tsb_flush(ent, tag); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift, 848c2ecf20Sopenharmony_ci unsigned long tsb, unsigned long nentries) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci unsigned long i; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci for (i = 0; i < tb->tlb_nr; i++) 898c2ecf20Sopenharmony_ci __flush_tsb_one_entry(tsb, tb->vaddrs[i], hash_shift, nentries); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 938c2ecf20Sopenharmony_cistatic void __flush_huge_tsb_one_entry(unsigned long tsb, unsigned long v, 948c2ecf20Sopenharmony_ci unsigned long hash_shift, 958c2ecf20Sopenharmony_ci unsigned long nentries, 968c2ecf20Sopenharmony_ci unsigned int hugepage_shift) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci unsigned int hpage_entries; 998c2ecf20Sopenharmony_ci unsigned int i; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci hpage_entries = 1 << (hugepage_shift - hash_shift); 1028c2ecf20Sopenharmony_ci for (i = 0; i < hpage_entries; i++) 1038c2ecf20Sopenharmony_ci __flush_tsb_one_entry(tsb, v + (i << hash_shift), hash_shift, 1048c2ecf20Sopenharmony_ci nentries); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void __flush_huge_tsb_one(struct tlb_batch *tb, unsigned long hash_shift, 1088c2ecf20Sopenharmony_ci unsigned long tsb, unsigned long nentries, 1098c2ecf20Sopenharmony_ci unsigned int hugepage_shift) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci unsigned long i; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci for (i = 0; i < tb->tlb_nr; i++) 1148c2ecf20Sopenharmony_ci __flush_huge_tsb_one_entry(tsb, tb->vaddrs[i], hash_shift, 1158c2ecf20Sopenharmony_ci nentries, hugepage_shift); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid flush_tsb_user(struct tlb_batch *tb) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct mm_struct *mm = tb->mm; 1228c2ecf20Sopenharmony_ci unsigned long nentries, base, flags; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci spin_lock_irqsave(&mm->context.lock, flags); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (tb->hugepage_shift < REAL_HPAGE_SHIFT) { 1278c2ecf20Sopenharmony_ci base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; 1288c2ecf20Sopenharmony_ci nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; 1298c2ecf20Sopenharmony_ci if (tlb_type == cheetah_plus || tlb_type == hypervisor) 1308c2ecf20Sopenharmony_ci base = __pa(base); 1318c2ecf20Sopenharmony_ci if (tb->hugepage_shift == PAGE_SHIFT) 1328c2ecf20Sopenharmony_ci __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); 1338c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) 1348c2ecf20Sopenharmony_ci else 1358c2ecf20Sopenharmony_ci __flush_huge_tsb_one(tb, PAGE_SHIFT, base, nentries, 1368c2ecf20Sopenharmony_ci tb->hugepage_shift); 1378c2ecf20Sopenharmony_ci#endif 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 1408c2ecf20Sopenharmony_ci else if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { 1418c2ecf20Sopenharmony_ci base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; 1428c2ecf20Sopenharmony_ci nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; 1438c2ecf20Sopenharmony_ci if (tlb_type == cheetah_plus || tlb_type == hypervisor) 1448c2ecf20Sopenharmony_ci base = __pa(base); 1458c2ecf20Sopenharmony_ci __flush_huge_tsb_one(tb, REAL_HPAGE_SHIFT, base, nentries, 1468c2ecf20Sopenharmony_ci tb->hugepage_shift); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mm->context.lock, flags); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_civoid flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, 1538c2ecf20Sopenharmony_ci unsigned int hugepage_shift) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci unsigned long nentries, base, flags; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci spin_lock_irqsave(&mm->context.lock, flags); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (hugepage_shift < REAL_HPAGE_SHIFT) { 1608c2ecf20Sopenharmony_ci base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; 1618c2ecf20Sopenharmony_ci nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; 1628c2ecf20Sopenharmony_ci if (tlb_type == cheetah_plus || tlb_type == hypervisor) 1638c2ecf20Sopenharmony_ci base = __pa(base); 1648c2ecf20Sopenharmony_ci if (hugepage_shift == PAGE_SHIFT) 1658c2ecf20Sopenharmony_ci __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, 1668c2ecf20Sopenharmony_ci nentries); 1678c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci __flush_huge_tsb_one_entry(base, vaddr, PAGE_SHIFT, 1708c2ecf20Sopenharmony_ci nentries, hugepage_shift); 1718c2ecf20Sopenharmony_ci#endif 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 1748c2ecf20Sopenharmony_ci else if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { 1758c2ecf20Sopenharmony_ci base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; 1768c2ecf20Sopenharmony_ci nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; 1778c2ecf20Sopenharmony_ci if (tlb_type == cheetah_plus || tlb_type == hypervisor) 1788c2ecf20Sopenharmony_ci base = __pa(base); 1798c2ecf20Sopenharmony_ci __flush_huge_tsb_one_entry(base, vaddr, REAL_HPAGE_SHIFT, 1808c2ecf20Sopenharmony_ci nentries, hugepage_shift); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci#endif 1838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mm->context.lock, flags); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define HV_PGSZ_IDX_BASE HV_PGSZ_IDX_8K 1878c2ecf20Sopenharmony_ci#define HV_PGSZ_MASK_BASE HV_PGSZ_MASK_8K 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 1908c2ecf20Sopenharmony_ci#define HV_PGSZ_IDX_HUGE HV_PGSZ_IDX_4MB 1918c2ecf20Sopenharmony_ci#define HV_PGSZ_MASK_HUGE HV_PGSZ_MASK_4MB 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsigned long tsb_bytes) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci unsigned long tsb_reg, base, tsb_paddr; 1978c2ecf20Sopenharmony_ci unsigned long page_sz, tte; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_nentries = 2008c2ecf20Sopenharmony_ci tsb_bytes / sizeof(struct tsb); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci switch (tsb_idx) { 2038c2ecf20Sopenharmony_ci case MM_TSB_BASE: 2048c2ecf20Sopenharmony_ci base = TSBMAP_8K_BASE; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 2078c2ecf20Sopenharmony_ci case MM_TSB_HUGE: 2088c2ecf20Sopenharmony_ci base = TSBMAP_4M_BASE; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci#endif 2118c2ecf20Sopenharmony_ci default: 2128c2ecf20Sopenharmony_ci BUG(); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci tte = pgprot_val(PAGE_KERNEL_LOCKED); 2168c2ecf20Sopenharmony_ci tsb_paddr = __pa(mm->context.tsb_block[tsb_idx].tsb); 2178c2ecf20Sopenharmony_ci BUG_ON(tsb_paddr & (tsb_bytes - 1UL)); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Use the smallest page size that can map the whole TSB 2208c2ecf20Sopenharmony_ci * in one TLB entry. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci switch (tsb_bytes) { 2238c2ecf20Sopenharmony_ci case 8192 << 0: 2248c2ecf20Sopenharmony_ci tsb_reg = 0x0UL; 2258c2ecf20Sopenharmony_ci#ifdef DCACHE_ALIASING_POSSIBLE 2268c2ecf20Sopenharmony_ci base += (tsb_paddr & 8192); 2278c2ecf20Sopenharmony_ci#endif 2288c2ecf20Sopenharmony_ci page_sz = 8192; 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci case 8192 << 1: 2328c2ecf20Sopenharmony_ci tsb_reg = 0x1UL; 2338c2ecf20Sopenharmony_ci page_sz = 64 * 1024; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci case 8192 << 2: 2378c2ecf20Sopenharmony_ci tsb_reg = 0x2UL; 2388c2ecf20Sopenharmony_ci page_sz = 64 * 1024; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci case 8192 << 3: 2428c2ecf20Sopenharmony_ci tsb_reg = 0x3UL; 2438c2ecf20Sopenharmony_ci page_sz = 64 * 1024; 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci case 8192 << 4: 2478c2ecf20Sopenharmony_ci tsb_reg = 0x4UL; 2488c2ecf20Sopenharmony_ci page_sz = 512 * 1024; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci case 8192 << 5: 2528c2ecf20Sopenharmony_ci tsb_reg = 0x5UL; 2538c2ecf20Sopenharmony_ci page_sz = 512 * 1024; 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci case 8192 << 6: 2578c2ecf20Sopenharmony_ci tsb_reg = 0x6UL; 2588c2ecf20Sopenharmony_ci page_sz = 512 * 1024; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci case 8192 << 7: 2628c2ecf20Sopenharmony_ci tsb_reg = 0x7UL; 2638c2ecf20Sopenharmony_ci page_sz = 4 * 1024 * 1024; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci default: 2678c2ecf20Sopenharmony_ci printk(KERN_ERR "TSB[%s:%d]: Impossible TSB size %lu, killing process.\n", 2688c2ecf20Sopenharmony_ci current->comm, current->pid, tsb_bytes); 2698c2ecf20Sopenharmony_ci do_exit(SIGSEGV); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci tte |= pte_sz_bits(page_sz); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (tlb_type == cheetah_plus || tlb_type == hypervisor) { 2748c2ecf20Sopenharmony_ci /* Physical mapping, no locked TLB entry for TSB. */ 2758c2ecf20Sopenharmony_ci tsb_reg |= tsb_paddr; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_reg_val = tsb_reg; 2788c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_map_vaddr = 0; 2798c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_map_pte = 0; 2808c2ecf20Sopenharmony_ci } else { 2818c2ecf20Sopenharmony_ci tsb_reg |= base; 2828c2ecf20Sopenharmony_ci tsb_reg |= (tsb_paddr & (page_sz - 1UL)); 2838c2ecf20Sopenharmony_ci tte |= (tsb_paddr & ~(page_sz - 1UL)); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_reg_val = tsb_reg; 2868c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_map_vaddr = base; 2878c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_idx].tsb_map_pte = tte; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Setup the Hypervisor TSB descriptor. */ 2918c2ecf20Sopenharmony_ci if (tlb_type == hypervisor) { 2928c2ecf20Sopenharmony_ci struct hv_tsb_descr *hp = &mm->context.tsb_descr[tsb_idx]; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci switch (tsb_idx) { 2958c2ecf20Sopenharmony_ci case MM_TSB_BASE: 2968c2ecf20Sopenharmony_ci hp->pgsz_idx = HV_PGSZ_IDX_BASE; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 2998c2ecf20Sopenharmony_ci case MM_TSB_HUGE: 3008c2ecf20Sopenharmony_ci hp->pgsz_idx = HV_PGSZ_IDX_HUGE; 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci#endif 3038c2ecf20Sopenharmony_ci default: 3048c2ecf20Sopenharmony_ci BUG(); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci hp->assoc = 1; 3078c2ecf20Sopenharmony_ci hp->num_ttes = tsb_bytes / 16; 3088c2ecf20Sopenharmony_ci hp->ctx_idx = 0; 3098c2ecf20Sopenharmony_ci switch (tsb_idx) { 3108c2ecf20Sopenharmony_ci case MM_TSB_BASE: 3118c2ecf20Sopenharmony_ci hp->pgsz_mask = HV_PGSZ_MASK_BASE; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 3148c2ecf20Sopenharmony_ci case MM_TSB_HUGE: 3158c2ecf20Sopenharmony_ci hp->pgsz_mask = HV_PGSZ_MASK_HUGE; 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci#endif 3188c2ecf20Sopenharmony_ci default: 3198c2ecf20Sopenharmony_ci BUG(); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci hp->tsb_base = tsb_paddr; 3228c2ecf20Sopenharmony_ci hp->resv = 0; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistruct kmem_cache *pgtable_cache __read_mostly; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct kmem_cache *tsb_caches[8] __read_mostly; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const char *tsb_cache_names[8] = { 3318c2ecf20Sopenharmony_ci "tsb_8KB", 3328c2ecf20Sopenharmony_ci "tsb_16KB", 3338c2ecf20Sopenharmony_ci "tsb_32KB", 3348c2ecf20Sopenharmony_ci "tsb_64KB", 3358c2ecf20Sopenharmony_ci "tsb_128KB", 3368c2ecf20Sopenharmony_ci "tsb_256KB", 3378c2ecf20Sopenharmony_ci "tsb_512KB", 3388c2ecf20Sopenharmony_ci "tsb_1MB", 3398c2ecf20Sopenharmony_ci}; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_civoid __init pgtable_cache_init(void) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci unsigned long i; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci pgtable_cache = kmem_cache_create("pgtable_cache", 3468c2ecf20Sopenharmony_ci PAGE_SIZE, PAGE_SIZE, 3478c2ecf20Sopenharmony_ci 0, 3488c2ecf20Sopenharmony_ci _clear_page); 3498c2ecf20Sopenharmony_ci if (!pgtable_cache) { 3508c2ecf20Sopenharmony_ci prom_printf("pgtable_cache_init(): Could not create!\n"); 3518c2ecf20Sopenharmony_ci prom_halt(); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tsb_cache_names); i++) { 3558c2ecf20Sopenharmony_ci unsigned long size = 8192 << i; 3568c2ecf20Sopenharmony_ci const char *name = tsb_cache_names[i]; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci tsb_caches[i] = kmem_cache_create(name, 3598c2ecf20Sopenharmony_ci size, size, 3608c2ecf20Sopenharmony_ci 0, NULL); 3618c2ecf20Sopenharmony_ci if (!tsb_caches[i]) { 3628c2ecf20Sopenharmony_ci prom_printf("Could not create %s cache\n", name); 3638c2ecf20Sopenharmony_ci prom_halt(); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint sysctl_tsb_ratio = -2; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic unsigned long tsb_size_to_rss_limit(unsigned long new_size) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci unsigned long num_ents = (new_size / sizeof(struct tsb)); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (sysctl_tsb_ratio < 0) 3758c2ecf20Sopenharmony_ci return num_ents - (num_ents >> -sysctl_tsb_ratio); 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci return num_ents + (num_ents >> sysctl_tsb_ratio); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* When the RSS of an address space exceeds tsb_rss_limit for a TSB, 3818c2ecf20Sopenharmony_ci * do_sparc64_fault() invokes this routine to try and grow it. 3828c2ecf20Sopenharmony_ci * 3838c2ecf20Sopenharmony_ci * When we reach the maximum TSB size supported, we stick ~0UL into 3848c2ecf20Sopenharmony_ci * tsb_rss_limit for that TSB so the grow checks in do_sparc64_fault() 3858c2ecf20Sopenharmony_ci * will not trigger any longer. 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * The TSB can be anywhere from 8K to 1MB in size, in increasing powers 3888c2ecf20Sopenharmony_ci * of two. The TSB must be aligned to it's size, so f.e. a 512K TSB 3898c2ecf20Sopenharmony_ci * must be 512K aligned. It also must be physically contiguous, so we 3908c2ecf20Sopenharmony_ci * cannot use vmalloc(). 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * The idea here is to grow the TSB when the RSS of the process approaches 3938c2ecf20Sopenharmony_ci * the number of entries that the current TSB can hold at once. Currently, 3948c2ecf20Sopenharmony_ci * we trigger when the RSS hits 3/4 of the TSB capacity. 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_civoid tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci unsigned long max_tsb_size = 1 * 1024 * 1024; 3998c2ecf20Sopenharmony_ci unsigned long new_size, old_size, flags; 4008c2ecf20Sopenharmony_ci struct tsb *old_tsb, *new_tsb; 4018c2ecf20Sopenharmony_ci unsigned long new_cache_index, old_cache_index; 4028c2ecf20Sopenharmony_ci unsigned long new_rss_limit; 4038c2ecf20Sopenharmony_ci gfp_t gfp_flags; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (max_tsb_size > (PAGE_SIZE << MAX_ORDER)) 4068c2ecf20Sopenharmony_ci max_tsb_size = (PAGE_SIZE << MAX_ORDER); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci new_cache_index = 0; 4098c2ecf20Sopenharmony_ci for (new_size = 8192; new_size < max_tsb_size; new_size <<= 1UL) { 4108c2ecf20Sopenharmony_ci new_rss_limit = tsb_size_to_rss_limit(new_size); 4118c2ecf20Sopenharmony_ci if (new_rss_limit > rss) 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci new_cache_index++; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (new_size == max_tsb_size) 4178c2ecf20Sopenharmony_ci new_rss_limit = ~0UL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ciretry_tsb_alloc: 4208c2ecf20Sopenharmony_ci gfp_flags = GFP_KERNEL; 4218c2ecf20Sopenharmony_ci if (new_size > (PAGE_SIZE * 2)) 4228c2ecf20Sopenharmony_ci gfp_flags |= __GFP_NOWARN | __GFP_NORETRY; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index], 4258c2ecf20Sopenharmony_ci gfp_flags, numa_node_id()); 4268c2ecf20Sopenharmony_ci if (unlikely(!new_tsb)) { 4278c2ecf20Sopenharmony_ci /* Not being able to fork due to a high-order TSB 4288c2ecf20Sopenharmony_ci * allocation failure is very bad behavior. Just back 4298c2ecf20Sopenharmony_ci * down to a 0-order allocation and force no TSB 4308c2ecf20Sopenharmony_ci * growing for this address space. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci if (mm->context.tsb_block[tsb_index].tsb == NULL && 4338c2ecf20Sopenharmony_ci new_cache_index > 0) { 4348c2ecf20Sopenharmony_ci new_cache_index = 0; 4358c2ecf20Sopenharmony_ci new_size = 8192; 4368c2ecf20Sopenharmony_ci new_rss_limit = ~0UL; 4378c2ecf20Sopenharmony_ci goto retry_tsb_alloc; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* If we failed on a TSB grow, we are under serious 4418c2ecf20Sopenharmony_ci * memory pressure so don't try to grow any more. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci if (mm->context.tsb_block[tsb_index].tsb != NULL) 4448c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_index].tsb_rss_limit = ~0UL; 4458c2ecf20Sopenharmony_ci return; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Mark all tags as invalid. */ 4498c2ecf20Sopenharmony_ci tsb_init(new_tsb, new_size); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Ok, we are about to commit the changes. If we are 4528c2ecf20Sopenharmony_ci * growing an existing TSB the locking is very tricky, 4538c2ecf20Sopenharmony_ci * so WATCH OUT! 4548c2ecf20Sopenharmony_ci * 4558c2ecf20Sopenharmony_ci * We have to hold mm->context.lock while committing to the 4568c2ecf20Sopenharmony_ci * new TSB, this synchronizes us with processors in 4578c2ecf20Sopenharmony_ci * flush_tsb_user() and switch_mm() for this address space. 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * But even with that lock held, processors run asynchronously 4608c2ecf20Sopenharmony_ci * accessing the old TSB via TLB miss handling. This is OK 4618c2ecf20Sopenharmony_ci * because those actions are just propagating state from the 4628c2ecf20Sopenharmony_ci * Linux page tables into the TSB, page table mappings are not 4638c2ecf20Sopenharmony_ci * being changed. If a real fault occurs, the processor will 4648c2ecf20Sopenharmony_ci * synchronize with us when it hits flush_tsb_user(), this is 4658c2ecf20Sopenharmony_ci * also true for the case where vmscan is modifying the page 4668c2ecf20Sopenharmony_ci * tables. The only thing we need to be careful with is to 4678c2ecf20Sopenharmony_ci * skip any locked TSB entries during copy_tsb(). 4688c2ecf20Sopenharmony_ci * 4698c2ecf20Sopenharmony_ci * When we finish committing to the new TSB, we have to drop 4708c2ecf20Sopenharmony_ci * the lock and ask all other cpus running this address space 4718c2ecf20Sopenharmony_ci * to run tsb_context_switch() to see the new TSB table. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci spin_lock_irqsave(&mm->context.lock, flags); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci old_tsb = mm->context.tsb_block[tsb_index].tsb; 4768c2ecf20Sopenharmony_ci old_cache_index = 4778c2ecf20Sopenharmony_ci (mm->context.tsb_block[tsb_index].tsb_reg_val & 0x7UL); 4788c2ecf20Sopenharmony_ci old_size = (mm->context.tsb_block[tsb_index].tsb_nentries * 4798c2ecf20Sopenharmony_ci sizeof(struct tsb)); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* Handle multiple threads trying to grow the TSB at the same time. 4838c2ecf20Sopenharmony_ci * One will get in here first, and bump the size and the RSS limit. 4848c2ecf20Sopenharmony_ci * The others will get in here next and hit this check. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ci if (unlikely(old_tsb && 4878c2ecf20Sopenharmony_ci (rss < mm->context.tsb_block[tsb_index].tsb_rss_limit))) { 4888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mm->context.lock, flags); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci kmem_cache_free(tsb_caches[new_cache_index], new_tsb); 4918c2ecf20Sopenharmony_ci return; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_index].tsb_rss_limit = new_rss_limit; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (old_tsb) { 4978c2ecf20Sopenharmony_ci extern void copy_tsb(unsigned long old_tsb_base, 4988c2ecf20Sopenharmony_ci unsigned long old_tsb_size, 4998c2ecf20Sopenharmony_ci unsigned long new_tsb_base, 5008c2ecf20Sopenharmony_ci unsigned long new_tsb_size, 5018c2ecf20Sopenharmony_ci unsigned long page_size_shift); 5028c2ecf20Sopenharmony_ci unsigned long old_tsb_base = (unsigned long) old_tsb; 5038c2ecf20Sopenharmony_ci unsigned long new_tsb_base = (unsigned long) new_tsb; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (tlb_type == cheetah_plus || tlb_type == hypervisor) { 5068c2ecf20Sopenharmony_ci old_tsb_base = __pa(old_tsb_base); 5078c2ecf20Sopenharmony_ci new_tsb_base = __pa(new_tsb_base); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size, 5108c2ecf20Sopenharmony_ci tsb_index == MM_TSB_BASE ? 5118c2ecf20Sopenharmony_ci PAGE_SHIFT : REAL_HPAGE_SHIFT); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci mm->context.tsb_block[tsb_index].tsb = new_tsb; 5158c2ecf20Sopenharmony_ci setup_tsb_params(mm, tsb_index, new_size); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mm->context.lock, flags); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* If old_tsb is NULL, we're being invoked for the first time 5208c2ecf20Sopenharmony_ci * from init_new_context(). 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_ci if (old_tsb) { 5238c2ecf20Sopenharmony_ci /* Reload it on the local cpu. */ 5248c2ecf20Sopenharmony_ci tsb_context_switch(mm); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* Now force other processors to do the same. */ 5278c2ecf20Sopenharmony_ci preempt_disable(); 5288c2ecf20Sopenharmony_ci smp_tsb_sync(mm); 5298c2ecf20Sopenharmony_ci preempt_enable(); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Now it is safe to free the old tsb. */ 5328c2ecf20Sopenharmony_ci kmem_cache_free(tsb_caches[old_cache_index], old_tsb); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciint init_new_context(struct task_struct *tsk, struct mm_struct *mm) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci unsigned long mm_rss = get_mm_rss(mm); 5398c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 5408c2ecf20Sopenharmony_ci unsigned long saved_hugetlb_pte_count; 5418c2ecf20Sopenharmony_ci unsigned long saved_thp_pte_count; 5428c2ecf20Sopenharmony_ci#endif 5438c2ecf20Sopenharmony_ci unsigned int i; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci spin_lock_init(&mm->context.lock); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci mm->context.sparc64_ctx_val = 0UL; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci mm->context.tag_store = NULL; 5508c2ecf20Sopenharmony_ci spin_lock_init(&mm->context.tag_lock); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 5538c2ecf20Sopenharmony_ci /* We reset them to zero because the fork() page copying 5548c2ecf20Sopenharmony_ci * will re-increment the counters as the parent PTEs are 5558c2ecf20Sopenharmony_ci * copied into the child address space. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_ci saved_hugetlb_pte_count = mm->context.hugetlb_pte_count; 5588c2ecf20Sopenharmony_ci saved_thp_pte_count = mm->context.thp_pte_count; 5598c2ecf20Sopenharmony_ci mm->context.hugetlb_pte_count = 0; 5608c2ecf20Sopenharmony_ci mm->context.thp_pte_count = 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci mm_rss -= saved_thp_pte_count * (HPAGE_SIZE / PAGE_SIZE); 5638c2ecf20Sopenharmony_ci#endif 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* copy_mm() copies over the parent's mm_struct before calling 5668c2ecf20Sopenharmony_ci * us, so we need to zero out the TSB pointer or else tsb_grow() 5678c2ecf20Sopenharmony_ci * will be confused and think there is an older TSB to free up. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci for (i = 0; i < MM_NUM_TSBS; i++) 5708c2ecf20Sopenharmony_ci mm->context.tsb_block[i].tsb = NULL; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* If this is fork, inherit the parent's TSB size. We would 5738c2ecf20Sopenharmony_ci * grow it to that size on the first page fault anyways. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci tsb_grow(mm, MM_TSB_BASE, mm_rss); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 5788c2ecf20Sopenharmony_ci if (unlikely(saved_hugetlb_pte_count + saved_thp_pte_count)) 5798c2ecf20Sopenharmony_ci tsb_grow(mm, MM_TSB_HUGE, 5808c2ecf20Sopenharmony_ci (saved_hugetlb_pte_count + saved_thp_pte_count) * 5818c2ecf20Sopenharmony_ci REAL_HPAGE_PER_HPAGE); 5828c2ecf20Sopenharmony_ci#endif 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (unlikely(!mm->context.tsb_block[MM_TSB_BASE].tsb)) 5858c2ecf20Sopenharmony_ci return -ENOMEM; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic void tsb_destroy_one(struct tsb_config *tp) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci unsigned long cache_index; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (!tp->tsb) 5958c2ecf20Sopenharmony_ci return; 5968c2ecf20Sopenharmony_ci cache_index = tp->tsb_reg_val & 0x7UL; 5978c2ecf20Sopenharmony_ci kmem_cache_free(tsb_caches[cache_index], tp->tsb); 5988c2ecf20Sopenharmony_ci tp->tsb = NULL; 5998c2ecf20Sopenharmony_ci tp->tsb_reg_val = 0UL; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_civoid destroy_context(struct mm_struct *mm) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci unsigned long flags, i; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci for (i = 0; i < MM_NUM_TSBS; i++) 6078c2ecf20Sopenharmony_ci tsb_destroy_one(&mm->context.tsb_block[i]); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctx_alloc_lock, flags); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (CTX_VALID(mm->context)) { 6128c2ecf20Sopenharmony_ci unsigned long nr = CTX_NRBITS(mm->context); 6138c2ecf20Sopenharmony_ci mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63)); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctx_alloc_lock, flags); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* If ADI tag storage was allocated for this task, free it */ 6198c2ecf20Sopenharmony_ci if (mm->context.tag_store) { 6208c2ecf20Sopenharmony_ci tag_storage_desc_t *tag_desc; 6218c2ecf20Sopenharmony_ci unsigned long max_desc; 6228c2ecf20Sopenharmony_ci unsigned char *tags; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci tag_desc = mm->context.tag_store; 6258c2ecf20Sopenharmony_ci max_desc = PAGE_SIZE/sizeof(tag_storage_desc_t); 6268c2ecf20Sopenharmony_ci for (i = 0; i < max_desc; i++) { 6278c2ecf20Sopenharmony_ci tags = tag_desc->tags; 6288c2ecf20Sopenharmony_ci tag_desc->tags = NULL; 6298c2ecf20Sopenharmony_ci kfree(tags); 6308c2ecf20Sopenharmony_ci tag_desc++; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci kfree(mm->context.tag_store); 6338c2ecf20Sopenharmony_ci mm->context.tag_store = NULL; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci} 636