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