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.
354 * NOTE: Code in clear_user_page has a hard coded dependency on the
355 * maximum alias boundary being 4 Mb. We've been assured by the
356 * parisc chip designers that there will not ever be a parisc
357 * chip with a larger alias boundary (Never say never :-) ).
359 * Subtle: the dtlb miss handlers support the temp alias region by
360 * "knowing" that if a dtlb miss happens within the temp alias
361 * region it must have occurred while in clear_user_page. Since
362 * this routine makes use of processor local translations, we
363 * don't want to insert them into the kernel page table. Instead,
364 * we load up some general registers (they need to be registers
365 * which aren't shadowed) with the physical page numbers (preshifted
366 * for tlb insertion) needed to insert the translations. When we
367 * miss on the translation, the dtlb miss handler inserts the
368 * translation into the tlb using these values:
370 * %r26 physical page (shifted for tlb insert) of "to" translation
371 * %r23 physical page (shifted for tlb insert) of "from" translation
377 * We can't do this since copy_user_page is used to bring in
378 * file data that might have instructions. Since the data would
379 * then need to be flushed out so the i-fetch can see it, it
380 * makes more sense to just copy through the kernel translation
383 * I'm still keeping this around because it may be possible to
384 * use it if more information is passed into copy_user_page().
385 * Have to do some measurements to see if it is worthwhile to
386 * lobby for such a change.
389 .export copy_user_page_asm,code
396 ldil L%(__PAGE_OFFSET),%r1
398 sub %r25,%r1,%r23 /* move physical addr into non shadowed reg */
400 ldil L%(TMPALIAS_MAP_START),%r28
402 extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
403 extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */
404 depd %r24,63,22,%r28 /* Form aliased virtual address 'to' */
405 depdi 0,63,12,%r28 /* Clear any offset bits */
407 depdi 1,41,1,%r29 /* Form aliased virtual address 'from' */
409 extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
410 extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */
411 depw %r24,31,22,%r28 /* Form aliased virtual address 'to' */
412 depwi 0,31,12,%r28 /* Clear any offset bits */
414 depwi 1,9,1,%r29 /* Form aliased virtual address 'from' */
417 /* Purge any old translations */
425 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
426 * bundles (very restricted rules for bundling). It probably
427 * does OK on PCXU and better, but we could do better with
428 * ldd/std instructions. Note that until (if) we start saving
429 * the full 64 bit register values on interrupt, we can't
430 * use ldd/std on a 32 bit kernel.
478 .export clear_user_page_asm,code
487 ldil L%(TMPALIAS_MAP_START),%r28
489 #if (TMPALIAS_MAP_START >= 0x80000000)
490 depdi 0,31,32,%r28 /* clear any sign extension */
492 extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
493 depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */
494 depdi 0,63,12,%r28 /* Clear any offset bits */
496 extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
497 depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */
498 depwi 0,31,12,%r28 /* Clear any offset bits */
501 /* Purge any old translation */
533 .export flush_kernel_dcache_page
535 flush_kernel_dcache_page:
540 ldil L%dcache_stride,%r1
541 ldw R%dcache_stride(%r1),%r23
544 depdi,z 1,63-PAGE_SHIFT,1,%r25
546 depwi,z 1,31-PAGE_SHIFT,1,%r25
577 .export flush_user_dcache_page
579 flush_user_dcache_page:
584 ldil L%dcache_stride,%r1
585 ldw R%dcache_stride(%r1),%r23
588 depdi,z 1,63-PAGE_SHIFT,1,%r25
590 depwi,z 1,31-PAGE_SHIFT,1,%r25
596 1: fdc,m %r23(%sr3,%r26)
597 fdc,m %r23(%sr3,%r26)
598 fdc,m %r23(%sr3,%r26)
599 fdc,m %r23(%sr3,%r26)
600 fdc,m %r23(%sr3,%r26)
601 fdc,m %r23(%sr3,%r26)
602 fdc,m %r23(%sr3,%r26)
603 fdc,m %r23(%sr3,%r26)
604 fdc,m %r23(%sr3,%r26)
605 fdc,m %r23(%sr3,%r26)
606 fdc,m %r23(%sr3,%r26)
607 fdc,m %r23(%sr3,%r26)
608 fdc,m %r23(%sr3,%r26)
609 fdc,m %r23(%sr3,%r26)
610 fdc,m %r23(%sr3,%r26)
612 fdc,m %r23(%sr3,%r26)
621 .export flush_user_icache_page
623 flush_user_icache_page:
628 ldil L%dcache_stride,%r1
629 ldw R%dcache_stride(%r1),%r23
632 depdi,z 1,63-PAGE_SHIFT,1,%r25
634 depwi,z 1,31-PAGE_SHIFT,1,%r25
640 1: fic,m %r23(%sr3,%r26)
641 fic,m %r23(%sr3,%r26)
642 fic,m %r23(%sr3,%r26)
643 fic,m %r23(%sr3,%r26)
644 fic,m %r23(%sr3,%r26)
645 fic,m %r23(%sr3,%r26)
646 fic,m %r23(%sr3,%r26)
647 fic,m %r23(%sr3,%r26)
648 fic,m %r23(%sr3,%r26)
649 fic,m %r23(%sr3,%r26)
650 fic,m %r23(%sr3,%r26)
651 fic,m %r23(%sr3,%r26)
652 fic,m %r23(%sr3,%r26)
653 fic,m %r23(%sr3,%r26)
654 fic,m %r23(%sr3,%r26)
656 fic,m %r23(%sr3,%r26)
666 .export purge_kernel_dcache_page
668 purge_kernel_dcache_page:
673 ldil L%dcache_stride,%r1
674 ldw R%dcache_stride(%r1),%r23
677 depdi,z 1,63-PAGE_SHIFT,1,%r25
679 depwi,z 1,31-PAGE_SHIFT,1,%r25
710 /* Currently not used, but it still is a possible alternate
714 .export flush_alias_page
723 ldil L%(TMPALIAS_MAP_START),%r28
725 extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
726 depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */
727 depdi 0,63,12,%r28 /* Clear any offset bits */
729 extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
730 depw %r25,31,22,%r28 /* Form aliased virtual address 'to' */
731 depwi 0,31,12,%r28 /* Clear any offset bits */
734 /* Purge any old translation */
738 ldil L%dcache_stride,%r1
739 ldw R%dcache_stride(%r1),%r23
742 depdi,z 1,63-PAGE_SHIFT,1,%r29
744 depwi,z 1,31-PAGE_SHIFT,1,%r29
775 .export flush_user_dcache_range_asm
777 flush_user_dcache_range_asm:
782 ldil L%dcache_stride,%r1
783 ldw R%dcache_stride(%r1),%r23
787 1: CMPB<<,n %r26,%r25,1b
788 fdc,m %r23(%sr3,%r26)
797 .export flush_kernel_dcache_range_asm
799 flush_kernel_dcache_range_asm:
804 ldil L%dcache_stride,%r1
805 ldw R%dcache_stride(%r1),%r23
809 1: CMPB<<,n %r26,%r25,1b
820 .export flush_user_icache_range_asm
822 flush_user_icache_range_asm:
827 ldil L%icache_stride,%r1
828 ldw R%icache_stride(%r1),%r23
832 1: CMPB<<,n %r26,%r25,1b
833 fic,m %r23(%sr3,%r26)
842 .export flush_kernel_icache_page
844 flush_kernel_icache_page:
849 ldil L%icache_stride,%r1
850 ldw R%icache_stride(%r1),%r23
853 depdi,z 1,63-PAGE_SHIFT,1,%r25
855 depwi,z 1,31-PAGE_SHIFT,1,%r25
886 .export flush_kernel_icache_range_asm
888 flush_kernel_icache_range_asm:
893 ldil L%icache_stride,%r1
894 ldw R%icache_stride(%r1),%r23
898 1: CMPB<<,n %r26,%r25,1b
910 .export disable_sr_hashing_asm,code
912 disable_sr_hashing_asm:
917 /* Switch to real mode */
919 ssm 0,%r0 /* relied upon translation! */
928 rsm (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q&I to load the iia queue */
929 ldil L%REAL_MODE_PSW, %r1
930 ldo R%REAL_MODE_PSW(%r1), %r1
932 mtctl %r0, %cr17 /* Clear IIASQ tail */
933 mtctl %r0, %cr17 /* Clear IIASQ head */
935 ldo R%PA(1f)(%r1),%r1
936 mtctl %r1, %cr18 /* IIAOQ head */
938 mtctl %r1, %cr18 /* IIAOQ tail */
942 1: cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs
943 cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl
944 cmpib,=,n SRHASH_PA20,%r26,srdis_pa20
949 /* Disable Space Register Hashing for PCXS,PCXT,PCXT' */
951 .word 0x141c1a00 /* mfdiag %dr0,%r28 */
952 .word 0x141c1a00 /* must issue twice */
953 depwi 0,18,1,%r28 /* Clear DHE (dcache hash enable) */
954 depwi 0,20,1,%r28 /* Clear IHE (icache hash enable) */
955 .word 0x141c1600 /* mtdiag %r28,%dr0 */
956 .word 0x141c1600 /* must issue twice */
961 /* Disable Space Register Hashing for PCXL */
963 .word 0x141c0600 /* mfdiag %dr0,%r28 */
964 depwi 0,28,2,%r28 /* Clear DHASH_EN & IHASH_EN */
965 .word 0x141c0240 /* mtdiag %r28,%dr0 */
970 /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */
972 .word 0x144008bc /* mfdiag %dr2,%r28 */
973 depdi 0,54,1,%r28 /* clear DIAG_SPHASH_ENAB (bit 54) */
974 .word 0x145c1840 /* mtdiag %r28,%dr2 */
978 /* Switch back to virtual mode */
980 rsm PSW_SM_Q,%r0 /* clear Q bit to load iia queue */
981 ldil L%KERNEL_PSW, %r1
982 ldo R%KERNEL_PSW(%r1), %r1
984 mtctl %r0, %cr17 /* Clear IIASQ tail */
985 mtctl %r0, %cr17 /* Clear IIASQ head */
988 mtctl %r1, %cr18 /* IIAOQ head */
990 mtctl %r1, %cr18 /* IIAOQ tail */