Subject: Re: hypersparc smp tailspin
To: Christopher SEKIYA <wileyc@rezrov.net>
From: Brett Lymn <blymn@baesystems.com.au>
List: port-sparc
Date: 02/06/2003 21:54:38
On Wed, Feb 05, 2003 at 10:21:46PM +0900, Christopher SEKIYA wrote:
> 
> ... and it sits there forever.  Little light is blinking, so it's alive and
> waiting for something to complete.  ddb trace looks like:
> 

OK - mrg posted a patch that effectively disables the instruction
cache for the hypersparcs which makes SMP work but does mean a
performance hit so it is not the ideal solution.  Below are some
patches for a recent-ish -current that try to may hypersparcs work
with their caches on.  They are not quite right as I still experience
core dumps when the machine is pushed but with these patches I can get
the machine booted to multiuser on a 3-way 100MHz hypersparc machine
and get away with some light usage without too much strangeness.  I
suspect that there are still some places that some cache flushing
needs to be done... hopefully we can nail those down soon.

Anyway, for the brave, try these patches.  I would be very interested
in hearing how they work for other people...

Index: cache.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/sparc/cache.c,v
retrieving revision 1.77
diff -u -r1.77 cache.c
--- cache.c	2003/01/20 22:15:54	1.77
+++ cache.c	2003/02/03 11:27:30
@@ -597,6 +597,17 @@
 	setcontext4m(ctx);
 	for (; --i >= 0; p += ls)
 		sta(p, ASI_IDCACHELFC, 0);
+#if defined(MULTIPROCESSOR)
+	/*
+	 * The page flush operation will have caused a MMU table walk
+	 * on Hypersparc because the is physically tagged. Since the pmap
+	 * functions will not always cross flush it in the MP case (because
+	 * may not be active on this CPU) we flush the TLB entry now.
+	 */
+	if (cpuinfo.cpu_type == CPUTYP_HS_MBUS)
+		sta(ASI_SRMMUFP_L0, ASI_SRMMUFP, 0);
+
+#endif
 	setcontext4m(octx);
 	trapon();
 }
@@ -697,6 +708,100 @@
 		sta(va | ASI_SRMMUFP_L3, ASI_SRMMUFP, 0);
 
 #endif
+	setcontext4m(octx);
+	trapon();
+}
+
+
+/*
+ * Flush the given virtual region from the cache.
+ *
+ * This is also done by writing to each cache line, except that
+ * now the addresses must include the virtual region number, and
+ * we use the `flush region' space.
+ */
+void
+hypersparc_vcache_flush_region(vreg, ctx)
+	int vreg;
+	int ctx;
+{
+	int i, ls, octx;
+	char *p;
+
+	cachestats.cs_nrgflush++;
+	p = (char *)VRTOVA(vreg);	/* reg..reg+sz rather than 0..sz */
+	ls = CACHEINFO.c_linesize;
+	i = NBPG >> CACHEINFO.c_l2linesize;
+	octx = getcontext4m();
+	trapoff();
+	setcontext4m(ctx);
+	hypersparc625_flush_region(p, i, ls);
+	sta(VRTOVA(vreg) | ASI_SRMMUFP_L1, ASI_SRMMUFP, 0);
+	setcontext4m(octx);
+	trapon();
+}
+
+/*
+ * Flush the given virtual segment from the cache.
+ *
+ * This is also done by writing to each cache line, except that
+ * now the addresses must include the virtual segment number, and
+ * we use the `flush segment' space.
+ *
+ * Again, for hardware, we just write each page (in hw-flush space).
+ */
+void
+hypersparc_vcache_flush_segment(vreg, vseg, ctx)
+	int vreg, vseg, ctx;
+{
+	int i, ls, octx;
+	char *p;
+
+	cachestats.cs_nsgflush++;
+	p = (char *)VSTOVA(vreg, vseg);	/* seg..seg+sz rather than 0..sz */
+	ls = CACHEINFO.c_linesize;
+	i = NBPG >> CACHEINFO.c_l2linesize;
+	octx = getcontext4m();
+	trapoff();
+	setcontext4m(ctx);
+	hypersparc625_flush_segment(p, i, ls);
+
+	  /*
+	   * flush the TLB entries put there by the table walks during
+	   * cache flush
+	   */
+	sta(VSTOVA(vreg, vseg) | ASI_SRMMUFP_L2, ASI_SRMMUFP, 0);
+	setcontext4m(octx);
+	trapon();
+}
+
+/*
+ * Flush the given virtual page from the cache.
+ * (va is the actual address, and must be aligned on a page boundary.)
+ * Again we write to each cache line.
+ */
+void
+hypersparc_vcache_flush_page(va, ctx)
+	int va;
+	int ctx;
+{
+	int i, ls, octx;
+	char *p;
+
+#ifdef DEBUG
+	if (va & PGOFSET)
+		panic("cache_flush_page: asked to flush misaligned va 0x%x",va);
+#endif
+
+	cachestats.cs_npgflush++;
+	p = (char *)va;
+	ls = CACHEINFO.c_linesize;
+	i = NBPG >> CACHEINFO.c_l2linesize;
+	octx = getcontext4m();
+	trapoff();
+	setcontext4m(ctx);
+	hypersparc625_flush_page(p, i, ls);
+	sta(va | ASI_SRMMUFP_L3, ASI_SRMMUFP, 0);
 	setcontext4m(octx);
 	trapon();
 }
Index: cache.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/sparc/cache.h,v
retrieving revision 1.28
diff -u -r1.28 cache.h
--- cache.h	2003/01/20 21:43:38	1.28
+++ cache.h	2003/02/03 11:27:34
@@ -182,6 +182,13 @@
 void	viking_pcache_flush_page __P((paddr_t, int));
 void	srmmu_pcache_flush_line __P((int, int));
 void	hypersparc_pure_vcache_flush __P((void));
+void    hypersparc_vcache_flush_region __P((int, int));
+void    hypersparc_vcache_flush_segment __P((int, int, int));
+void    hypersparc_vcache_flush_page __P((int, int));
+void	hypersparc_cache_flush __P((caddr_t, u_int));/* flush region */
+void    hypersparc625_flush_region __P((caddr_t, int, int));
+void    hypersparc625_flush_segment __P((caddr_t, int, int));
+void    hypersparc625_flush_page __P((caddr_t, int, int));
 
 void	ms1_cache_flush_all __P((void));
 void	srmmu_cache_flush_all __P((void));
Index: cpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/sparc/cpu.c,v
retrieving revision 1.171
diff -u -r1.171 cpu.c
--- cpu.c	2003/01/23 11:50:50	1.171
+++ cpu.c	2003/02/03 11:27:55
@@ -522,6 +522,7 @@
 			SET_CACHE_FUNC(vcache_flush_context);
 		}
 	}
+
 #endif /* MULTIPROCESSOR */
 }
 
@@ -1499,9 +1500,9 @@
 	hypersparc_get_syncflt,
 	hypersparc_get_asyncflt,
 	srmmu_cache_flush,
-	srmmu_vcache_flush_page,
-	srmmu_vcache_flush_segment,
-	srmmu_vcache_flush_region,
+	hypersparc_vcache_flush_page,
+	hypersparc_vcache_flush_segment,
+	hypersparc_vcache_flush_region,
 	srmmu_vcache_flush_context,
 	noop_pcache_flush_page,
 	hypersparc_pure_vcache_flush,
Index: genassym.cf
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/sparc/genassym.cf,v
retrieving revision 1.41
diff -u -r1.41 genassym.cf
--- genassym.cf	2003/01/18 06:45:03	1.41
+++ genassym.cf	2003/02/03 11:27:58
@@ -94,6 +94,7 @@
 include <machine/cpu.h>
 include <machine/oldmon.h>
 include <machine/bsd_openprom.h>
+include <machine/pte.h>
 
 include <sparc/sparc/cpuvar.h>
 
@@ -109,6 +110,7 @@
 
 include <sparc/dev/fdreg.h>
 include <sparc/dev/fdvar.h>
+include <sparc/sparc/iommureg.h>
 
 # general constants
 define	BSD		BSD
@@ -170,10 +172,16 @@
 define	SRMMU_TETYPE	SRMMU_TETYPE
 define	SRMMU_TEPTE	SRMMU_TEPTE
 define	SRMMU_PROT_MASK	SRMMU_PROT_MASK
+define  SRMMU_PG_R	SRMMU_PG_R
 define	PPROT_R_RW	PPROT_R_RW
 define	PPROT_RX_RX	PPROT_RX_RX
 define	PPROT_RWX_RWX	PPROT_RWX_RWX
 define	PPROT_WRITE	PPROT_WRITE
+
+define  IOMMU_FLUSH_MASK IOMMU_FLUSH_MASK
+define  NBPG		NBPG
+define	NBPSG		NBPSG
+define	NBPRG		NBPRG
 
 # FPU state
 define	FS_REGS		offsetof(struct fpstate, fs_regs)
Index: locore.s
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/sparc/locore.s,v
retrieving revision 1.185
diff -u -r1.185 locore.s
--- locore.s	2003/01/18 06:45:03	1.185
+++ locore.s	2003/02/03 11:28:58
@@ -6754,6 +6754,99 @@
 	retl
 	 sta	%g0, [%g0] ASI_HICACHECLR
 
+/*
+ * Flush a page on the hypersparc, we need to check that the page
+ * is mapped first.  On entry %o0 is the address to flush,
+ * %o1 is the number of cache lines to flush and %o2 is the
+ * size of a cache line.
+ */
+_ENTRY(_C_LABEL(hypersparc625_flush_page))
+        and     %o0, IOMMU_FLUSH_MASK, %o3 ! get the page number
+        lda     [%o3] ASI_SRMMUFP, %o3     ! probe for the address in tlb
+        set     SRMMU_SFSR, %o4            ! set up to clear possible faults
+        and     %o3, SRMMU_TETYPE, %o3     ! strip out the page type bits
+        cmp     %o3, SRMMU_TEPTE           ! do we have a PTE?
+        bne     2f                         ! bail if we don't
+         lda     [%o4] ASI_SRMMU, %o4      ! clear sfsr of probe faults
+1:
+        deccc   %o1                             ! for each cache line in the
+                                                ! page
+        sta     %g0, [%o0] ASI_IDCACHELFP       ! flush the cache
+        bne     1b
+         add    %o0, %o2, %o0                   ! address of next line to do
+
+2:
+        retl
+        nop
+
+/*
+ * Flush a segment on the hypersparc, we need to check that the segment
+ * is mapped first.  On entry %o0 is the address to flush,
+ * %o1 is the number of cache lines to flush and %o2 is the
+ * size of a cache line.
+ */
+_ENTRY(_C_LABEL(hypersparc625_flush_segment))
+	set	(NBPSG / NBPG), %o5
+1:
+	mov	%o1, %o3
+	mov	%o0, %o4
+2:
+        and     %o0, IOMMU_FLUSH_MASK, %g3	! get the page number
+        lda     [%g3] ASI_SRMMUFP, %g3     ! probe for the address in tlb
+        and     %g3, SRMMU_TETYPE, %g3     ! strip out the page type bits
+        cmp     %g3, SRMMU_TEPTE           ! do we have a PTE?
+        set     SRMMU_SFSR, %g3            ! set up to clear possible faults
+        bne     3f                         ! next page if we don't
+         lda     [%g3] ASI_SRMMU, %g3      ! clear sfsr of probe faults
+	
+        deccc   %o3                             ! for each cache line in the
+                                                ! page
+        sta     %g0, [%o4] ASI_IDCACHELFP       ! flush the cache
+        bne     2b
+         add    %o4, %o2, %o4                   ! address of next line to do
+
+3:
+        deccc   %o5                        ! decrement page count
+        bne     1b                         ! do next page (if any)
+         add    %o0, NBPG, %o0             ! address of next page
+
+        retl
+        nop
+
+/*
+ * Flush a region on the hypersparc, we need to check that the page
+ * is mapped first.  On entry %o0 is the address to flush,
+ * %o1 is the number of cache lines to flush and %o2 is the
+ * size of a cache line.
+ */
+_ENTRY(_C_LABEL(hypersparc625_flush_region))
+	set	(NBPRG / NBPG), %o5
+1:
+	mov	%o1, %o3
+	mov	%o0, %o4
+2:
+        and     %o0, IOMMU_FLUSH_MASK, %g3	! get the page number
+        lda     [%g3] ASI_SRMMUFP, %g3     ! probe for the address in tlb
+        and     %g3, SRMMU_TETYPE, %g3     ! strip out the page type bits
+        cmp     %g3, SRMMU_TEPTE           ! do we have a PTE?
+        set     SRMMU_SFSR, %g3            ! set up to clear possible faults
+        bne     3f                         ! next page if we don't have PTE
+         lda     [%g3] ASI_SRMMU, %g3      ! clear sfsr of probe faults
+
+	deccc   %o3                             ! for each cache line in the
+                                                ! page
+        sta     %g0, [%o4] ASI_IDCACHELFP       ! flush the cache
+        bne     2b
+         add    %o4, %o2, %o4                   ! address of next line to do
+
+3:
+        deccc   %o5                        ! decrement page count
+        bne     1b                         ! do next page (if any)
+         add    %o0, NBPG, %o0             ! address of next page
+
+        retl
+        nop
+
 #endif /* SUN4M */
 
 #if !defined(MSIIEP)	/* normal suns */


-- 
Brett Lymn