1a7b613d4Smatt /*-
2a7b613d4Smatt * Copyright (c) 2013 The NetBSD Foundation, Inc.
3a7b613d4Smatt * All rights reserved.
4a7b613d4Smatt *
5a7b613d4Smatt * This code is derived from software contributed to The NetBSD Foundation
6a7b613d4Smatt * by Matt Thomas of 3am Software Foundry.
7a7b613d4Smatt *
8a7b613d4Smatt * Redistribution and use in source and binary forms, with or without
9a7b613d4Smatt * modification, are permitted provided that the following conditions
10a7b613d4Smatt * are met:
11a7b613d4Smatt * 1. Redistributions of source code must retain the above copyright
12a7b613d4Smatt * notice, this list of conditions and the following disclaimer.
13a7b613d4Smatt * 2. Redistributions in binary form must reproduce the above copyright
14a7b613d4Smatt * notice, this list of conditions and the following disclaimer in the
15a7b613d4Smatt * documentation and/or other materials provided with the distribution.
16a7b613d4Smatt *
17a7b613d4Smatt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18a7b613d4Smatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19a7b613d4Smatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20a7b613d4Smatt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21a7b613d4Smatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22a7b613d4Smatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23a7b613d4Smatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24a7b613d4Smatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25a7b613d4Smatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26a7b613d4Smatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27a7b613d4Smatt * POSSIBILITY OF SUCH DAMAGE.
28a7b613d4Smatt */
29cd0fc78fSskrll
30fee210abSskrll #include "opt_cputypes.h"
31cd0fc78fSskrll #include "opt_multiprocessor.h"
32cd0fc78fSskrll
33a7b613d4Smatt #include <sys/cdefs.h>
34*bf021c82Sskrll __KERNEL_RCSID(1, "$NetBSD: arm32_tlb.c,v 1.15 2021/10/02 14:28:04 skrll Exp $");
35a7b613d4Smatt
36a7b613d4Smatt #include <sys/param.h>
37a7b613d4Smatt #include <sys/types.h>
38a7b613d4Smatt
39a7b613d4Smatt #include <uvm/uvm.h>
40a7b613d4Smatt
41a7b613d4Smatt #include <arm/locore.h>
42a7b613d4Smatt
43a7b613d4Smatt bool arm_has_tlbiasid_p; // CPU supports TLBIASID system coprocessor op
4491a285acSjmcneill bool arm_has_mpext_p; // CPU supports MP extensions
45a7b613d4Smatt
46a7b613d4Smatt tlb_asid_t
tlb_get_asid(void)47a7b613d4Smatt tlb_get_asid(void)
48a7b613d4Smatt {
49a7b613d4Smatt return armreg_contextidr_read() & 0xff;
50a7b613d4Smatt }
51a7b613d4Smatt
52a7b613d4Smatt void
tlb_set_asid(tlb_asid_t asid,pmap_t pm)53*bf021c82Sskrll tlb_set_asid(tlb_asid_t asid, pmap_t pm)
54a7b613d4Smatt {
55ce993bccSskrll dsb(sy);
566e760360Sskrll if (asid == KERNEL_PID) {
57a7b613d4Smatt armreg_ttbcr_write(armreg_ttbcr_read() | TTBCR_S_PD0);
58ce993bccSskrll isb();
59a7b613d4Smatt }
60a7b613d4Smatt armreg_contextidr_write(asid);
61ce993bccSskrll isb();
62a7b613d4Smatt }
63a7b613d4Smatt
64a7b613d4Smatt void
tlb_invalidate_all(void)65a7b613d4Smatt tlb_invalidate_all(void)
66a7b613d4Smatt {
6713066d82Smatt const bool vivt_icache_p = arm_pcache.icache_type == CACHE_TYPE_VIVT;
68ce993bccSskrll dsb(sy);
6991a285acSjmcneill if (arm_has_mpext_p) {
7015819bafSmatt armreg_tlbiallis_write(0);
7191a285acSjmcneill } else {
72a7b613d4Smatt armreg_tlbiall_write(0);
7391a285acSjmcneill }
74ce993bccSskrll isb();
7513066d82Smatt if (__predict_false(vivt_icache_p)) {
7613066d82Smatt if (arm_has_tlbiasid_p) {
7713066d82Smatt armreg_icialluis_write(0);
7813066d82Smatt } else {
7913066d82Smatt armreg_iciallu_write(0);
8013066d82Smatt }
8113066d82Smatt }
82ce993bccSskrll dsb(sy);
83ce993bccSskrll isb();
84a7b613d4Smatt }
85a7b613d4Smatt
86a7b613d4Smatt void
tlb_invalidate_globals(void)87a7b613d4Smatt tlb_invalidate_globals(void)
88a7b613d4Smatt {
89a7b613d4Smatt tlb_invalidate_all();
90a7b613d4Smatt }
91a7b613d4Smatt
92a7b613d4Smatt void
tlb_invalidate_asids(tlb_asid_t lo,tlb_asid_t hi)93a7b613d4Smatt tlb_invalidate_asids(tlb_asid_t lo, tlb_asid_t hi)
94a7b613d4Smatt {
9513066d82Smatt const bool vivt_icache_p = arm_pcache.icache_type == CACHE_TYPE_VIVT;
96ce993bccSskrll dsb(sy);
97a7b613d4Smatt if (arm_has_tlbiasid_p) {
98a7b613d4Smatt for (; lo <= hi; lo++) {
9991a285acSjmcneill if (arm_has_mpext_p) {
100b33445f5Smatt armreg_tlbiasidis_write(lo);
10191a285acSjmcneill } else {
102a3f6924aShsuenaga armreg_tlbiasid_write(lo);
10391a285acSjmcneill }
104a7b613d4Smatt }
105ce993bccSskrll dsb(sy);
106ce993bccSskrll isb();
10713066d82Smatt if (__predict_false(vivt_icache_p)) {
10891a285acSjmcneill if (arm_has_mpext_p) {
10913066d82Smatt armreg_icialluis_write(0);
11091a285acSjmcneill } else {
111a3f6924aShsuenaga armreg_iciallu_write(0);
11291a285acSjmcneill }
11313066d82Smatt }
11413066d82Smatt } else {
11513066d82Smatt armreg_tlbiall_write(0);
116ce993bccSskrll isb();
11713066d82Smatt if (__predict_false(vivt_icache_p)) {
11813066d82Smatt armreg_iciallu_write(0);
11913066d82Smatt }
120a7b613d4Smatt }
121ce993bccSskrll isb();
122a7b613d4Smatt }
123a7b613d4Smatt
124a7b613d4Smatt void
tlb_invalidate_addr(vaddr_t va,tlb_asid_t asid)125a7b613d4Smatt tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid)
126a7b613d4Smatt {
127ce993bccSskrll dsb(sy);
128a7b613d4Smatt va = trunc_page(va) | asid;
129a7b613d4Smatt for (vaddr_t eva = va + PAGE_SIZE; va < eva; va += L2_S_SIZE) {
13091a285acSjmcneill if (arm_has_mpext_p) {
13115819bafSmatt armreg_tlbimvais_write(va);
13291a285acSjmcneill } else {
133a7b613d4Smatt armreg_tlbimva_write(va);
13491a285acSjmcneill }
135a7b613d4Smatt }
136ce993bccSskrll isb();
137a7b613d4Smatt }
138a7b613d4Smatt
139a7b613d4Smatt bool
tlb_update_addr(vaddr_t va,tlb_asid_t asid,pt_entry_t pte,bool insert_p)140a7b613d4Smatt tlb_update_addr(vaddr_t va, tlb_asid_t asid, pt_entry_t pte, bool insert_p)
141a7b613d4Smatt {
142a7b613d4Smatt tlb_invalidate_addr(va, asid);
143a7b613d4Smatt return true;
144a7b613d4Smatt }
145a7b613d4Smatt
14629299275Sjmcneill #if !defined(MULTIPROCESSOR)
147a7b613d4Smatt static u_int
tlb_cortex_a5_record_asids(u_long * mapp,tlb_asid_t asid_max)148fc444195Smatt tlb_cortex_a5_record_asids(u_long *mapp, tlb_asid_t asid_max)
149a7b613d4Smatt {
150a7b613d4Smatt u_int nasids = 0;
151a7b613d4Smatt for (size_t va_index = 0; va_index < 63; va_index++) {
152a7b613d4Smatt for (size_t way = 0; way < 2; way++) {
153a7b613d4Smatt armreg_tlbdataop_write(
154a7b613d4Smatt __SHIFTIN(way, ARM_TLBDATAOP_WAY)
155a7b613d4Smatt | __SHIFTIN(va_index, ARM_A5_TLBDATAOP_INDEX));
156ce993bccSskrll isb();
157a7b613d4Smatt const uint64_t d = ((uint64_t) armreg_tlbdata1_read())
158a7b613d4Smatt | armreg_tlbdata0_read();
159a7b613d4Smatt if (!(d & ARM_TLBDATA_VALID)
16075034e42Sjmcneill || !(d & ARM_A5_TLBDATA_nG))
161a7b613d4Smatt continue;
162a7b613d4Smatt
163a7b613d4Smatt const tlb_asid_t asid = __SHIFTOUT(d,
16475034e42Sjmcneill ARM_A5_TLBDATA_ASID);
165a7b613d4Smatt const u_long mask = 1L << (asid & 31);
166a7b613d4Smatt const size_t idx = asid >> 5;
167a7b613d4Smatt if (mapp[idx] & mask)
168a7b613d4Smatt continue;
169a7b613d4Smatt
170a7b613d4Smatt mapp[idx] |= mask;
171a7b613d4Smatt nasids++;
172a7b613d4Smatt }
173a7b613d4Smatt }
174a7b613d4Smatt return nasids;
175a7b613d4Smatt }
176a7b613d4Smatt #endif
177a7b613d4Smatt
17829299275Sjmcneill #if !defined(MULTIPROCESSOR)
179a7b613d4Smatt static u_int
tlb_cortex_a7_record_asids(u_long * mapp,tlb_asid_t asid_max)180fc444195Smatt tlb_cortex_a7_record_asids(u_long *mapp, tlb_asid_t asid_max)
181a7b613d4Smatt {
182a7b613d4Smatt u_int nasids = 0;
183a7b613d4Smatt for (size_t va_index = 0; va_index < 128; va_index++) {
184a7b613d4Smatt for (size_t way = 0; way < 2; way++) {
185a7b613d4Smatt armreg_tlbdataop_write(
186a7b613d4Smatt __SHIFTIN(way, ARM_TLBDATAOP_WAY)
187a7b613d4Smatt | __SHIFTIN(va_index, ARM_A7_TLBDATAOP_INDEX));
188ce993bccSskrll isb();
189a7b613d4Smatt const uint32_t d0 = armreg_tlbdata0_read();
190a7b613d4Smatt const uint32_t d1 = armreg_tlbdata1_read();
191a7b613d4Smatt if (!(d0 & ARM_TLBDATA_VALID)
192a7b613d4Smatt || !(d1 & ARM_A7_TLBDATA1_nG))
193a7b613d4Smatt continue;
194a7b613d4Smatt
195a7b613d4Smatt const uint64_t d01 = ((uint64_t) d1)|d0;
196a7b613d4Smatt const tlb_asid_t asid = __SHIFTOUT(d01,
197a7b613d4Smatt ARM_A7_TLBDATA01_ASID);
198a7b613d4Smatt const u_long mask = 1L << (asid & 31);
199a7b613d4Smatt const size_t idx = asid >> 5;
200a7b613d4Smatt if (mapp[idx] & mask)
201a7b613d4Smatt continue;
202a7b613d4Smatt
203a7b613d4Smatt mapp[idx] |= mask;
204a7b613d4Smatt nasids++;
205a7b613d4Smatt }
206a7b613d4Smatt }
207a7b613d4Smatt return nasids;
208a7b613d4Smatt }
209a7b613d4Smatt #endif
210a7b613d4Smatt
211a7b613d4Smatt u_int
tlb_record_asids(u_long * mapp,tlb_asid_t asid_max)212fc444195Smatt tlb_record_asids(u_long *mapp, tlb_asid_t asid_max)
213a7b613d4Smatt {
214a7b613d4Smatt #ifndef MULTIPROCESSOR
215a7b613d4Smatt if (CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid))
216fc444195Smatt return tlb_cortex_a5_record_asids(mapp, asid_max);
217a7b613d4Smatt if (CPU_ID_CORTEX_A7_P(curcpu()->ci_arm_cpuid))
218fc444195Smatt return tlb_cortex_a7_record_asids(mapp, asid_max);
219a7b613d4Smatt #endif /* MULTIPROCESSOR */
220a7b613d4Smatt #ifdef DIAGNOSTIC
221a7b613d4Smatt mapp[0] = 0xfffffffe;
222a7b613d4Smatt mapp[1] = 0xffffffff;
223a7b613d4Smatt mapp[2] = 0xffffffff;
224a7b613d4Smatt mapp[3] = 0xffffffff;
225a7b613d4Smatt mapp[4] = 0xffffffff;
226a7b613d4Smatt mapp[5] = 0xffffffff;
227a7b613d4Smatt mapp[6] = 0xffffffff;
228a7b613d4Smatt mapp[7] = 0xffffffff;
229a7b613d4Smatt #endif
230a7b613d4Smatt return 255;
231a7b613d4Smatt }
232a7b613d4Smatt
233a7b613d4Smatt void
tlb_walk(void * ctx,bool (* func)(void *,vaddr_t,tlb_asid_t,pt_entry_t))234a7b613d4Smatt tlb_walk(void *ctx, bool (*func)(void *, vaddr_t, tlb_asid_t, pt_entry_t))
235a7b613d4Smatt {
236a7b613d4Smatt /* no way to view the TLB */
237a7b613d4Smatt }
238