Module Name:    src
Committed By:   matt
Date:           Fri Sep 14 03:51:01 UTC 2012

Modified Files:
        src/sys/arch/arm/cortex: pl310.c

Log Message:
Add L2 cache flush routines.  (not yet enabled).


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/cortex/pl310.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/cortex/pl310.c
diff -u src/sys/arch/arm/cortex/pl310.c:1.4 src/sys/arch/arm/cortex/pl310.c:1.5
--- src/sys/arch/arm/cortex/pl310.c:1.4	Fri Sep  7 21:18:58 2012
+++ src/sys/arch/arm/cortex/pl310.c	Fri Sep 14 03:51:01 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: pl310.c,v 1.4 2012/09/07 21:18:58 matt Exp $	*/
+/*	$NetBSD: pl310.c,v 1.5 2012/09/14 03:51:01 matt Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,12 +30,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pl310.c,v 1.4 2012/09/07 21:18:58 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pl310.c,v 1.5 2012/09/14 03:51:01 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/cpu.h>
 #include <sys/device.h>
+#include <sys/atomic.h>
 
 #include <arm/cortex/mpcore_var.h>
 #include <arm/cortex/pl310_reg.h>
@@ -51,14 +52,28 @@ struct arml2cc_softc {
 	device_t sc_dev;
 	bus_space_tag_t sc_memt;
 	bus_space_handle_t sc_memh;
+	kmutex_t sc_lock;
+	uint32_t sc_waymask;
+	struct evcnt sc_ev_inv __aligned(8);
+	struct evcnt sc_ev_wb;
+	struct evcnt sc_ev_wbinv;
+	bool sc_enabled;
 };
 
+__CTASSERT(offsetof(struct arml2cc_softc, sc_ev_inv.ev_count) % 8 == 0);
+__CTASSERT(offsetof(struct arml2cc_softc, sc_ev_wb.ev_count) % 8 == 0);
+__CTASSERT(offsetof(struct arml2cc_softc, sc_ev_wbinv.ev_count) % 8 == 0);
+
 CFATTACH_DECL_NEW(arml2cc, sizeof(struct arml2cc_softc),
     arml2cc_match, arml2cc_attach, NULL, NULL);
 
 static void arml2cc_disable(struct arml2cc_softc *);
+static void arml2cc_enable(struct arml2cc_softc *);
+static void arml2cc_sdcache_wb_range(vaddr_t, paddr_t, psize_t);
+static void arml2cc_sdcache_inv_range(vaddr_t, paddr_t, psize_t);
+static void arml2cc_sdcache_wbinv_range(vaddr_t, paddr_t, psize_t);
 
-static bool attached;
+static struct arml2cc_softc *arml2cc_sc;
 
 static inline uint32_t
 arml2cc_read_4(struct arml2cc_softc *sc, bus_size_t o)
@@ -79,7 +94,7 @@ arml2cc_match(device_t parent, cfdata_t 
 {
 	struct mpcore_attach_args * const mpcaa = aux;
 
-	if (attached)
+	if (arml2cc_sc)
 		return 0;
 
 	if (!CPU_ID_CORTEX_A9_P(curcpu()->ci_arm_cpuid))
@@ -116,9 +131,21 @@ arml2cc_attach(device_t parent, device_t
 {
         struct arml2cc_softc * const sc = device_private(self);
 	struct mpcore_attach_args * const mpcaa = aux;
+	const char * const xname = device_xname(self);
 
+	arml2cc_sc = sc;
 	sc->sc_dev = self;
 	sc->sc_memt = mpcaa->mpcaa_memt;
+	sc->sc_waymask = __BIT(arm_scache.dcache_ways) - 1;
+
+	evcnt_attach_dynamic(&sc->sc_ev_inv, EVCNT_TYPE_MISC, NULL,
+	    xname, "L2 inv requests");
+	evcnt_attach_dynamic(&sc->sc_ev_wb, EVCNT_TYPE_MISC, NULL,
+	    xname, "L2 wb requests");
+	evcnt_attach_dynamic(&sc->sc_ev_wbinv, EVCNT_TYPE_MISC, NULL,
+	    xname, "L2 wbinv requests");
+
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
 
 	bus_space_subregion(sc->sc_memt, mpcaa->mpcaa_memh, 
 	    L2CC_BASE, L2CC_SIZE, &sc->sc_memh);
@@ -140,33 +167,82 @@ arml2cc_attach(device_t parent, device_t
 	aprint_normal(": ARM PL310%s L2 Cache Controller%s\n",
 	    revstr, enabled_p ? "" : " (disabled)");
 
+#if 1
 	if (enabled_p) {
-		arml2cc_disable(sc);
+		if (1) {
+			arml2cc_disable(sc);
+			aprint_normal_dev(self, "cache %s\n",
+			    arml2cc_read_4(sc, L2C_CTL) ? "enabled" : "disabled");
+			sc->sc_enabled = false;
+		} else {
+			cpufuncs.cf_sdcache_wb_range = arml2cc_sdcache_wb_range;
+			cpufuncs.cf_sdcache_inv_range = arml2cc_sdcache_inv_range;
+			cpufuncs.cf_sdcache_wbinv_range = arml2cc_sdcache_wbinv_range;
+			sc->sc_enabled = true;
+		}
+	}
+#else
+	if (!enabled_p) {
+		arml2cc_enable(sc);
 		aprint_normal_dev(self, "cache %s\n",
 		    arml2cc_read_4(sc, L2C_CTL) ? "enabled" : "disabled");
 	}
+	cpufuncs.cf_sdcache_wb_range = arml2cc_sdcache_wb_range;
+	cpufuncs.cf_sdcache_inv_range = arml2cc_sdcache_inv_range;
+	cpufuncs.cf_sdcache_wbinv_range = arml2cc_sdcache_wbinv_range;
+	sc->sc_enabled = true;
+#endif
 
 	KASSERT(arm_pcache.dcache_line_size == arm_scache.dcache_line_size);
 }
 
-void
-arml2cc_disable(struct arml2cc_softc *sc)
+static inline void
+arml2cc_cache_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t val)
 {
-	uint32_t way_mask = __BIT(arm_scache.dcache_ways) - 1;
-	register_t psw = cpsid(I32_bit);
-
-	arml2cc_write_4(sc, L2C_CLEAN_INV_WAY, way_mask);
-	while (arml2cc_read_4(sc, L2C_CLEAN_INV_WAY) != 0) {
+	arml2cc_write_4(sc, off, val);
+	while (arml2cc_read_4(sc, off) & 1) {
 		/* spin */
 	}
+}
 
-	arml2cc_write_4(sc, L2C_CACHE_SYNC, 0);
-	while (arml2cc_read_4(sc, L2C_CACHE_SYNC) & 1) {
+static inline void
+arml2cc_cache_way_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t way_mask)
+{
+	arml2cc_write_4(sc, off, way_mask);
+	while (arml2cc_read_4(sc, off) & way_mask) {
 		/* spin */
 	}
+}
 
-	arml2cc_write_4(sc, L2C_CTL, 0);	// turn it off */
-	cpsie(psw);
+static inline void
+arml2cc_cache_sync(struct arml2cc_softc *sc)
+{
+	arml2cc_cache_op(sc, L2C_CACHE_SYNC, 0);
+}
+
+static inline void
+arml2cc_disable(struct arml2cc_softc *sc)
+{
+	mutex_spin_enter(&sc->sc_lock);
+
+	arml2cc_cache_way_op(sc, L2C_CLEAN_INV_WAY, sc->sc_waymask);
+	arml2cc_cache_sync(sc);
+
+	arml2cc_write_4(sc, L2C_CTL, 0);	// turn it off
+	mutex_spin_exit(&sc->sc_lock);
+}
+
+static inline void
+arml2cc_enable(struct arml2cc_softc *sc)
+{
+	mutex_spin_enter(&sc->sc_lock);
+
+	arml2cc_write_4(sc, L2C_CTL, 1);	// turn it on
+
+	//arml2cc_cache_way_op(sc, L2C_INV_WAY, sc->sc_waymask);
+	arml2cc_cache_sync(sc);
+
+	mutex_spin_exit(&sc->sc_lock);
 }
 
 void
@@ -198,36 +274,49 @@ arml2cc_init(bus_space_tag_t bst, bus_sp
 	}
 }
 
-#if 0
 static void
-arml2cc_dcache_wb_range(vaddr_t va, vsize_t len)
+arml2cc_cache_range_op(paddr_t pa, psize_t len, bus_size_t cache_op)
 {
-	const size_t line_size = arm_pcache.dcache_line_size;
+	struct arml2cc_softc * const sc = arml2cc_sc;
+	const size_t line_size = arm_scache.dcache_line_size;
 	const size_t line_mask = line_size - 1;
-	size_t off = va & line_mask;
-	size_t page_len = 0;
-	paddr_t pa = 0;
+	size_t off = pa & line_mask;
 	if (off) {
 		len += off;
-		va -= off;
+		pa -= off;
 	}
-	for (const vaddr_t endva = va + roundup2(len, line_size);
-	     va < endva;
-	     va += line_size) {
-		armreg_dccmvac(va);		/* this may fault */
-		__asm __volatile("dsb");
-		if (page_len == 0) {
-			armreg_ats1cpr_write(va);
-			pa = armreg_par_read();
-			const psize = __predict_false(pa & 1) ? L1_SS_SIZE : L2_S_SIZE;
-			pa &= -psize;
-			endpa = pa + psize;
-			page_len = (va & (psize - 1);
+	len = roundup2(len, line_size);
+	off = pa & PAGE_MASK;
+	for (const paddr_t endpa = pa + len; pa < endpa; off = 0) {
+		psize_t seglen = min(len, PAGE_SIZE - off);
+
+		mutex_spin_enter(&sc->sc_lock);
+		if (!sc->sc_enabled)
+			return;
+		for (paddr_t segend = pa + seglen; pa < segend; pa += line_size) {
+			arml2cc_cache_op(sc, cache_op, pa);
 		}
-		size_t set = va 
-		arml2cc_write_4(sc, L2C_CLEAN_PA, pa);
-		
-		va += line_size;
+		mutex_spin_exit(&sc->sc_lock);
 	}
 }
-#endif
+
+static void
+arml2cc_sdcache_inv_range(vaddr_t va, paddr_t pa, psize_t len)
+{
+	atomic_inc_64(&arml2cc_sc->sc_ev_inv.ev_count);
+	arml2cc_cache_range_op(pa, len, L2C_INV_PA);
+}
+
+static void
+arml2cc_sdcache_wb_range(vaddr_t va, paddr_t pa, psize_t len)
+{
+	atomic_inc_64(&arml2cc_sc->sc_ev_wb.ev_count);
+	arml2cc_cache_range_op(pa, len, L2C_CLEAN_PA);
+}
+
+static void
+arml2cc_sdcache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len)
+{
+	atomic_inc_64(&arml2cc_sc->sc_ev_wbinv.ev_count);
+	arml2cc_cache_range_op(pa, len, L2C_CLEAN_INV_PA);
+}

Reply via email to