svn commit: r265870 - in head/sys/arm: arm include
Ian Lepore
ian at FreeBSD.org
Sun May 11 04:24:58 UTC 2014
Author: ian
Date: Sun May 11 04:24:57 2014
New Revision: 265870
URL: http://svnweb.freebsd.org/changeset/base/265870
Log:
Add cpu_l2cache_drain_writebuf(), use it to implement generic_bs_barrier().
On modern ARM SoCs the L2 cache controller sits between the CPU and the
AXI bus, and most on-chip memory-mapped devices are on the AXI bus. We
map the device registers using the 'Device' memory attribute, which means
the memory is not cached, but writes to it are buffered. Ensuring that a
write has made it all the way to a device may require that the L2
controller take some action.
There is currently only one implementation of the new function, for the
PL310 cache controller. It invokes a function that the controller
manual calls "cache sync" but it actually has nothing to do with cache at
all, it triggers a drain of all pending store buffer writes and it blocks
until they complete.
The sheeva and xscale L2 controllers (which predate the concept of Device
memory) don't seem to have a corresponding function. It appears that the
standard armv5 drain_writebuf function includes draining all the way
through the L2 controller.
Modified:
head/sys/arm/arm/bus_space_generic.c
head/sys/arm/arm/cpufunc.c
head/sys/arm/arm/pl310.c
head/sys/arm/include/cpufunc.h
Modified: head/sys/arm/arm/bus_space_generic.c
==============================================================================
--- head/sys/arm/arm/bus_space_generic.c Sun May 11 04:18:51 2014 (r265869)
+++ head/sys/arm/arm/bus_space_generic.c Sun May 11 04:24:57 2014 (r265870)
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_extern.h>
#include <machine/bus.h>
+#include <machine/cpufunc.h>
#include <machine/devmap.h>
/* Prototypes for all the bus_space structure functions */
@@ -110,5 +111,16 @@ generic_bs_barrier(void *t, bus_space_ha
bus_size_t len, int flags)
{
- /* Nothing to do. */
+ /*
+ * dsb() will drain the L1 write buffer and establish a memory access
+ * barrier point on platforms where that has meaning. On a write we
+ * also need to drain the L2 write buffer, because most on-chip memory
+ * mapped devices are downstream of the L2 cache. Note that this needs
+ * to be done even for memory mapped as Device type, because while
+ * Device memory is not cached, writes to it are still buffered.
+ */
+ dsb();
+ if (flags & BUS_SPACE_BARRIER_WRITE) {
+ cpu_l2cache_drain_writebuf();
+ }
}
Modified: head/sys/arm/arm/cpufunc.c
==============================================================================
--- head/sys/arm/arm/cpufunc.c Sun May 11 04:18:51 2014 (r265869)
+++ head/sys/arm/arm/cpufunc.c Sun May 11 04:24:57 2014 (r265870)
@@ -150,6 +150,7 @@ struct cpu_functions arm9_cpufuncs = {
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -214,6 +215,7 @@ struct cpu_functions armv5_ec_cpufuncs =
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -276,6 +278,7 @@ struct cpu_functions sheeva_cpufuncs = {
sheeva_l2cache_wbinv_range, /* l2cache_wbinv_range */
sheeva_l2cache_inv_range, /* l2cache_inv_range */
sheeva_l2cache_wb_range, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -338,6 +341,7 @@ struct cpu_functions arm10_cpufuncs = {
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -401,6 +405,7 @@ struct cpu_functions pj4bv7_cpufuncs = {
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -466,6 +471,7 @@ struct cpu_functions xscale_cpufuncs = {
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -530,6 +536,7 @@ struct cpu_functions xscalec3_cpufuncs =
xscalec3_l2cache_purge_rng, /* l2cache_wbinv_range */
xscalec3_l2cache_flush_rng, /* l2cache_inv_range */
xscalec3_l2cache_clean_rng, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -593,6 +600,7 @@ struct cpu_functions fa526_cpufuncs = {
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -656,6 +664,7 @@ struct cpu_functions arm1136_cpufuncs =
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -718,6 +727,7 @@ struct cpu_functions arm1176_cpufuncs =
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
@@ -789,6 +799,7 @@ struct cpu_functions cortexa_cpufuncs =
(void *)cpufunc_nullop, /* l2cache_wbinv_range */
(void *)cpufunc_nullop, /* l2cache_inv_range */
(void *)cpufunc_nullop, /* l2cache_wb_range */
+ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */
/* Other functions */
Modified: head/sys/arm/arm/pl310.c
==============================================================================
--- head/sys/arm/arm/pl310.c Sun May 11 04:18:51 2014 (r265869)
+++ head/sys/arm/arm/pl310.c Sun May 11 04:24:57 2014 (r265870)
@@ -350,6 +350,18 @@ pl310_inv_range(vm_paddr_t start, vm_siz
}
static void
+pl310_drain_writebuf(void)
+{
+
+ if ((pl310_softc == NULL) || !pl310_softc->sc_enabled)
+ return;
+
+ PL310_LOCK(pl310_softc);
+ pl310_cache_sync();
+ PL310_UNLOCK(pl310_softc);
+}
+
+static void
pl310_set_way_sizes(struct pl310_softc *sc)
{
uint32_t aux_value;
@@ -484,6 +496,7 @@ pl310_attach(device_t dev)
cpufuncs.cf_l2cache_wbinv_range = pl310_wbinv_range;
cpufuncs.cf_l2cache_inv_range = pl310_inv_range;
cpufuncs.cf_l2cache_wb_range = pl310_wb_range;
+ cpufuncs.cf_l2cache_drain_writebuf = pl310_drain_writebuf;
return (0);
}
Modified: head/sys/arm/include/cpufunc.h
==============================================================================
--- head/sys/arm/include/cpufunc.h Sun May 11 04:18:51 2014 (r265869)
+++ head/sys/arm/include/cpufunc.h Sun May 11 04:24:57 2014 (r265870)
@@ -151,6 +151,7 @@ struct cpu_functions {
void (*cf_l2cache_wbinv_range) (vm_offset_t, vm_size_t);
void (*cf_l2cache_inv_range) (vm_offset_t, vm_size_t);
void (*cf_l2cache_wb_range) (vm_offset_t, vm_size_t);
+ void (*cf_l2cache_drain_writebuf) (void);
/* Other functions */
@@ -252,6 +253,7 @@ void tlb_broadcast(int);
#define cpu_l2cache_wb_range(a, s) cpufuncs.cf_l2cache_wb_range((a), (s))
#define cpu_l2cache_inv_range(a, s) cpufuncs.cf_l2cache_inv_range((a), (s))
#define cpu_l2cache_wbinv_range(a, s) cpufuncs.cf_l2cache_wbinv_range((a), (s))
+#define cpu_l2cache_drain_writebuf() cpufuncs.cf_l2cache_drain_writebuf()
#define cpu_flush_prefetchbuf() cpufuncs.cf_flush_prefetchbuf()
#define cpu_drain_writebuf() cpufuncs.cf_drain_writebuf()
More information about the svn-src-head
mailing list