2 * PARISC TLB and cache flushing support
3 * Copyright (C) 2000-2001 Hewlett-Packard (John Marvin)
4 * Copyright (C) 2001 Matthew Wilcox (willy at parisc-linux.org)
5 * Copyright (C) 2002 Richard Hirst (rhirst with parisc-linux.org)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * NOTE: fdc,fic, and pdc instructions that use base register modification
24 * should only use index and base registers that are not shadowed,
25 * so that the fast path emulation in the non access miss handler
43 #include <asm/assembly.h>
45 #include <asm/pgtable.h>
46 #include <asm/cache.h>
51 .export flush_tlb_all_local,code
59 * The pitlbe and pdtlbe instructions should only be used to
60 * flush the entire tlb. Also, there needs to be no intervening
61 * tlb operations, e.g. tlb misses, so the operation needs
62 * to happen in real mode with all interruptions disabled.
66 * Once again, we do the rfi dance ... some day we need examine
67 * all of our uses of this type of code and see what can be
71 rsm PSW_SM_I,%r19 /* relied upon translation! */
80 rsm PSW_SM_Q,%r0 /* Turn off Q bit to load iia queue */
81 ldil L%REAL_MODE_PSW, %r1
82 ldo R%REAL_MODE_PSW(%r1), %r1
84 mtctl %r0, %cr17 /* Clear IIASQ tail */
85 mtctl %r0, %cr17 /* Clear IIASQ head */
88 mtctl %r1, %cr18 /* IIAOQ head */
90 mtctl %r1, %cr18 /* IIAOQ tail */
94 1: ldil L%PA(cache_info),%r1
95 ldo R%PA(cache_info)(%r1),%r1
97 /* Flush Instruction Tlb */
99 LDREG ITLB_SID_BASE(%r1),%r20
100 LDREG ITLB_SID_STRIDE(%r1),%r21
101 LDREG ITLB_SID_COUNT(%r1),%r22
102 LDREG ITLB_OFF_BASE(%r1),%arg0
103 LDREG ITLB_OFF_STRIDE(%r1),%arg1
104 LDREG ITLB_OFF_COUNT(%r1),%arg2
105 LDREG ITLB_LOOP(%r1),%arg3
107 ADDIB= -1,%arg3,fitoneloop /* Preadjust and test */
108 movb,<,n %arg3,%r31,fitdone /* If loop < 0, skip */
109 copy %arg0,%r28 /* Init base addr */
111 fitmanyloop: /* Loop if LOOP >= 2 */
113 add %r21,%r20,%r20 /* increment space */
114 copy %arg2,%r29 /* Init middle loop count */
116 fitmanymiddle: /* Loop if LOOP >= 2 */
117 ADDIB> -1,%r31,fitmanymiddle /* Adjusted inner loop decr */
119 pitlbe,m %arg1(%sr1,%r28) /* Last pitlbe and addr adjust */
120 ADDIB> -1,%r29,fitmanymiddle /* Middle loop decr */
121 copy %arg3,%r31 /* Re-init inner loop count */
123 movb,tr %arg0,%r28,fitmanyloop /* Re-init base addr */
124 ADDIB<=,n -1,%r22,fitdone /* Outer loop count decr */
126 fitoneloop: /* Loop if LOOP = 1 */
128 copy %arg0,%r28 /* init base addr */
129 copy %arg2,%r29 /* init middle loop count */
131 fitonemiddle: /* Loop if LOOP = 1 */
132 ADDIB> -1,%r29,fitonemiddle /* Middle loop count decr */
133 pitlbe,m %arg1(%sr1,%r28) /* pitlbe for one loop */
135 ADDIB> -1,%r22,fitoneloop /* Outer loop count decr */
136 add %r21,%r20,%r20 /* increment space */
142 LDREG DTLB_SID_BASE(%r1),%r20
143 LDREG DTLB_SID_STRIDE(%r1),%r21
144 LDREG DTLB_SID_COUNT(%r1),%r22
145 LDREG DTLB_OFF_BASE(%r1),%arg0
146 LDREG DTLB_OFF_STRIDE(%r1),%arg1
147 LDREG DTLB_OFF_COUNT(%r1),%arg2
148 LDREG DTLB_LOOP(%r1),%arg3
150 ADDIB= -1,%arg3,fdtoneloop /* Preadjust and test */
151 movb,<,n %arg3,%r31,fdtdone /* If loop < 0, skip */
152 copy %arg0,%r28 /* Init base addr */
154 fdtmanyloop: /* Loop if LOOP >= 2 */
156 add %r21,%r20,%r20 /* increment space */
157 copy %arg2,%r29 /* Init middle loop count */
159 fdtmanymiddle: /* Loop if LOOP >= 2 */
160 ADDIB> -1,%r31,fdtmanymiddle /* Adjusted inner loop decr */
162 pdtlbe,m %arg1(%sr1,%r28) /* Last pdtlbe and addr adjust */
163 ADDIB> -1,%r29,fdtmanymiddle /* Middle loop decr */
164 copy %arg3,%r31 /* Re-init inner loop count */
166 movb,tr %arg0,%r28,fdtmanyloop /* Re-init base addr */
167 ADDIB<=,n -1,%r22,fdtdone /* Outer loop count decr */
169 fdtoneloop: /* Loop if LOOP = 1 */
171 copy %arg0,%r28 /* init base addr */
172 copy %arg2,%r29 /* init middle loop count */
174 fdtonemiddle: /* Loop if LOOP = 1 */
175 ADDIB> -1,%r29,fdtonemiddle /* Middle loop count decr */
176 pdtlbe,m %arg1(%sr1,%r28) /* pdtlbe for one loop */
178 ADDIB> -1,%r22,fdtoneloop /* Outer loop count decr */
179 add %r21,%r20,%r20 /* increment space */
183 /* Switch back to virtual mode */
185 rsm PSW_SM_Q,%r0 /* clear Q bit to load iia queue */
186 ldil L%KERNEL_PSW, %r1
187 ldo R%KERNEL_PSW(%r1), %r1
188 or %r1,%r19,%r1 /* Set I bit if set on entry */
190 mtctl %r0, %cr17 /* Clear IIASQ tail */
191 mtctl %r0, %cr17 /* Clear IIASQ head */
194 mtctl %r1, %cr18 /* IIAOQ head */
196 mtctl %r1, %cr18 /* IIAOQ tail */
206 .export flush_instruction_cache_local,code
207 .import cache_info,data
209 flush_instruction_cache_local:
215 ldil L%cache_info,%r1
216 ldo R%cache_info(%r1),%r1
218 /* Flush Instruction Cache */
220 LDREG ICACHE_BASE(%r1),%arg0
221 LDREG ICACHE_STRIDE(%r1),%arg1
222 LDREG ICACHE_COUNT(%r1),%arg2
223 LDREG ICACHE_LOOP(%r1),%arg3
224 rsm PSW_SM_I,%r22 /* No mmgt ops during loop*/
225 ADDIB= -1,%arg3,fioneloop /* Preadjust and test */
226 movb,<,n %arg3,%r31,fisync /* If loop < 0, do sync */
228 fimanyloop: /* Loop if LOOP >= 2 */
229 ADDIB> -1,%r31,fimanyloop /* Adjusted inner loop decr */
231 fice,m %arg1(%sr1,%arg0) /* Last fice and addr adjust */
232 movb,tr %arg3,%r31,fimanyloop /* Re-init inner loop count */
233 ADDIB<=,n -1,%arg2,fisync /* Outer loop decr */
235 fioneloop: /* Loop if LOOP = 1 */
236 ADDIB> -1,%arg2,fioneloop /* Outer loop count decr */
237 fice,m %arg1(%sr1,%arg0) /* Fice for one loop */
248 .export flush_data_cache_local,code
249 .import cache_info,data
251 flush_data_cache_local:
257 ldil L%cache_info,%r1
258 ldo R%cache_info(%r1),%r1
260 /* Flush Data Cache */
262 LDREG DCACHE_BASE(%r1),%arg0
263 LDREG DCACHE_STRIDE(%r1),%arg1
264 LDREG DCACHE_COUNT(%r1),%arg2
265 LDREG DCACHE_LOOP(%r1),%arg3
267 ADDIB= -1,%arg3,fdoneloop /* Preadjust and test */
268 movb,<,n %arg3,%r31,fdsync /* If loop < 0, do sync */
270 fdmanyloop: /* Loop if LOOP >= 2 */
271 ADDIB> -1,%r31,fdmanyloop /* Adjusted inner loop decr */
273 fdce,m %arg1(%sr1,%arg0) /* Last fdce and addr adjust */
274 movb,tr %arg3,%r31,fdmanyloop /* Re-init inner loop count */
275 ADDIB<=,n -1,%arg2,fdsync /* Outer loop decr */
277 fdoneloop: /* Loop if LOOP = 1 */
278 ADDIB> -1,%arg2,fdoneloop /* Outer loop count decr */
279 fdce,m %arg1(%sr1,%arg0) /* Fdce for one loop */
291 .export copy_user_page_asm,code
301 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
302 * bundles (very restricted rules for bundling). It probably
303 * does OK on PCXU and better, but we could do better with
304 * ldd/std instructions. Note that until (if) we start saving
305 * the full 64 bit register values on interrupt, we can't
306 * use ldd/std on a 32 bit kernel.
353 #if (TMPALIAS_MAP_START >= 0x80000000UL)
354 Warning TMPALIAS_MAP_START changed. If > 2 Gb, code in pacache.S is bogus
358 * NOTE: Code in clear_user_page has a hard coded dependency on the
359 * maximum alias boundary being 4 Mb. We've been assured by the
360 * parisc chip designers that there will not ever be a parisc
361 * chip with a larger alias boundary (Never say never :-) ).
363 * Subtle: the dtlb miss handlers support the temp alias region by
364 * "knowing" that if a dtlb miss happens within the temp alias
365 * region it must have occurred while in clear_user_page. Since
366 * this routine makes use of processor local translations, we
367 * don't want to insert them into the kernel page table. Instead,
368 * we load up some general registers (they need to be registers
369 * which aren't shadowed) with the physical page numbers (preshifted
370 * for tlb insertion) needed to insert the translations. When we
371 * miss on the translation, the dtlb miss handler inserts the
372 * translation into the tlb using these values:
374 * %r26 physical page (shifted for tlb insert) of "to" translation
375 * %r23 physical page (shifted for tlb insert) of "from" translation
381 * We can't do this since copy_user_page is used to bring in
382 * file data that might have instructions. Since the data would
383 * then need to be flushed out so the i-fetch can see it, it
384 * makes more sense to just copy through the kernel translation
387 * I'm still keeping this around because it may be possible to
388 * use it if more information is passed into copy_user_page().
389 * Have to do some measurements to see if it is worthwhile to
390 * lobby for such a change.
393 .export copy_user_page_asm,code
400 ldil L%(__PAGE_OFFSET),%r1
402 sub %r25,%r1,%r23 /* move physical addr into non shadowed reg */
404 ldil L%(TMPALIAS_MAP_START),%r28
406 extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
407 extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */
408 depd %r24,63,22,%r28 /* Form aliased virtual address 'to' */
409 depdi 0,63,12,%r28 /* Clear any offset bits */
411 depdi 1,41,1,%r29 /* Form aliased virtual address 'from' */
413 extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
414 extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */
415 depw %r24,31,22,%r28 /* Form aliased virtual address 'to' */
416 depwi 0,31,12,%r28 /* Clear any offset bits */
418 depwi 1,9,1,%r29 /* Form aliased virtual address 'from' */
421 /* Purge any old translations */
429 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
430 * bundles (very restricted rules for bundling). It probably
431 * does OK on PCXU and better, but we could do better with
432 * ldd/std instructions. Note that until (if) we start saving
433 * the full 64 bit register values on interrupt, we can't
434 * use ldd/std on a 32 bit kernel.
482 .export clear_user_page_asm,code
491 ldil L%(TMPALIAS_MAP_START),%r28
493 extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
494 depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */
495 depdi 0,63,12,%r28 /* Clear any offset bits */
497 extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
498 depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */
499 depwi 0,31,12,%r28 /* Clear any offset bits */
502 /* Purge any old translation */
534 .export flush_kernel_dcache_page
536 flush_kernel_dcache_page:
541 ldil L%dcache_stride,%r1
542 ldw R%dcache_stride(%r1),%r23
545 depdi,z 1,63-PAGE_SHIFT,1,%r25
547 depwi,z 1,31-PAGE_SHIFT,1,%r25
578 .export purge_kernel_dcache_page
580 purge_kernel_dcache_page:
585 ldil L%dcache_stride,%r1
586 ldw R%dcache_stride(%r1),%r23
589 depdi,z 1,63-PAGE_SHIFT,1,%r25
591 depwi,z 1,31-PAGE_SHIFT,1,%r25
622 /* Currently not used, but it still is a possible alternate
626 .export flush_alias_page
635 ldil L%(TMPALIAS_MAP_START),%r28
637 extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
638 depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */
639 depdi 0,63,12,%r28 /* Clear any offset bits */
641 extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
642 depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */
643 depwi 0,31,12,%r28 /* Clear any offset bits */
646 /* Purge any old translation */
650 ldil L%dcache_stride,%r1
651 ldw R%dcache_stride(%r1),%r23
654 depdi,z 1,63-PAGE_SHIFT,1,%r29
656 depwi,z 1,31-PAGE_SHIFT,1,%r29
687 .export flush_user_dcache_range_asm
689 flush_user_dcache_range_asm:
694 ldil L%dcache_stride,%r1
695 ldw R%dcache_stride(%r1),%r23
699 1: CMPB<<,n %r26,%r25,1b
700 fdc,m %r23(%sr3,%r26)
709 .export flush_kernel_dcache_range_asm
711 flush_kernel_dcache_range_asm:
716 ldil L%dcache_stride,%r1
717 ldw R%dcache_stride(%r1),%r23
721 1: CMPB<<,n %r26,%r25,1b
732 .export flush_user_icache_range_asm
734 flush_user_icache_range_asm:
739 ldil L%icache_stride,%r1
740 ldw R%icache_stride(%r1),%r23
744 1: CMPB<<,n %r26,%r25,1b
745 fic,m %r23(%sr3,%r26)
754 .export flush_kernel_icache_page
756 flush_kernel_icache_page:
761 ldil L%icache_stride,%r1
762 ldw R%icache_stride(%r1),%r23
765 depdi,z 1,63-PAGE_SHIFT,1,%r25
767 depwi,z 1,31-PAGE_SHIFT,1,%r25
798 .export flush_kernel_icache_range_asm
800 flush_kernel_icache_range_asm:
805 ldil L%icache_stride,%r1
806 ldw R%icache_stride(%r1),%r23
810 1: CMPB<<,n %r26,%r25,1b
822 .export disable_sr_hashing_asm,code
824 disable_sr_hashing_asm:
829 /* Switch to real mode */
831 ssm 0,%r0 /* relied upon translation! */
840 rsm (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q&I to load the iia queue */
841 ldil L%REAL_MODE_PSW, %r1
842 ldo R%REAL_MODE_PSW(%r1), %r1
844 mtctl %r0, %cr17 /* Clear IIASQ tail */
845 mtctl %r0, %cr17 /* Clear IIASQ head */
847 ldo R%PA(1f)(%r1),%r1
848 mtctl %r1, %cr18 /* IIAOQ head */
850 mtctl %r1, %cr18 /* IIAOQ tail */
854 1: cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs
855 cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl
856 cmpib,=,n SRHASH_PA20,%r26,srdis_pa20
861 /* Disable Space Register Hashing for PCXS,PCXT,PCXT' */
863 .word 0x141c1a00 /* mfdiag %dr0,%r28 */
864 .word 0x141c1a00 /* must issue twice */
865 depwi 0,18,1,%r28 /* Clear DHE (dcache hash enable) */
866 depwi 0,20,1,%r28 /* Clear IHE (icache hash enable) */
867 .word 0x141c1600 /* mtdiag %r28,%dr0 */
868 .word 0x141c1600 /* must issue twice */
873 /* Disable Space Register Hashing for PCXL */
875 .word 0x141c0600 /* mfdiag %dr0,%r28 */
876 depwi 0,28,2,%r28 /* Clear DHASH_EN & IHASH_EN */
877 .word 0x141c0240 /* mtdiag %r28,%dr0 */
882 /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */
884 .word 0x144008bc /* mfdiag %dr2,%r28 */
885 depdi 0,54,1,%r28 /* clear DIAG_SPHASH_ENAB (bit 54) */
886 .word 0x145c1840 /* mtdiag %r28,%dr2 */
890 /* Switch back to virtual mode */
892 rsm PSW_SM_Q,%r0 /* clear Q bit to load iia queue */
893 ldil L%KERNEL_PSW, %r1
894 ldo R%KERNEL_PSW(%r1), %r1
896 mtctl %r0, %cr17 /* Clear IIASQ tail */
897 mtctl %r0, %cr17 /* Clear IIASQ head */
900 mtctl %r1, %cr18 /* IIAOQ head */
902 mtctl %r1, %cr18 /* IIAOQ tail */