[PATCH 5/5] grlib/l2c: Prevent concurrent register access

Martin Åberg maberg at gaisler.com
Tue Jan 16 14:06:30 UTC 2024


Accesses to the L2C registers performed by the L2C driver are now
serialized with spin locks. This avoids concurrent access to the L2C
registers by multiple processors. Proposed by GRLIB-TN-0021.

Update #4925.
---
 bsps/shared/grlib/l2c/l2c.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/bsps/shared/grlib/l2c/l2c.c b/bsps/shared/grlib/l2c/l2c.c
index f989a8eda1..9e2d135179 100644
--- a/bsps/shared/grlib/l2c/l2c.c
+++ b/bsps/shared/grlib/l2c/l2c.c
@@ -38,6 +38,7 @@
 #include <grlib/grlib.h>
 #include <bsp.h>
 #include <grlib/l2c.h>
+#include <grlib/grlib_impl.h>
 
 /*#define STATIC*/
 #define STATIC static
@@ -317,6 +318,8 @@ struct l2cache_priv {
 	int ft_support;
 	int split_support;
 	int atomic_flush;
+	/* Avoid concurrent accesses to L2C registers. */
+	SPIN_DECLARE(devlock);
 
 	/* User defined ISR */
 	l2cache_isr_t isr;
@@ -383,8 +386,25 @@ static struct l2cache_priv *l2cachepriv = NULL;
 static char * repl_names[4] = {"LRU","Random","Master-Idx-1","Master-IDx-2"};
 #endif
 
-#define REG_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned int)(val))
-#define REG_READ(addr) (*(volatile unsigned int *)(addr))
+static void REG_WRITE(volatile unsigned int *addr, unsigned int val) {
+	struct l2cache_priv *priv = l2cachepriv;
+	SPIN_IRQFLAGS(irqflags);
+
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+	*addr = val;
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+}
+
+static unsigned int REG_READ(volatile unsigned int *addr) {
+	struct l2cache_priv *priv = l2cachepriv;
+	SPIN_IRQFLAGS(irqflags);
+	unsigned int val;
+
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+	val = *addr;
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+	return val;
+}
 
 #if defined(__sparc__)
 static inline uint32_t atomic_swap32(uint32_t *addr, uint32_t val) {
@@ -397,7 +417,15 @@ static inline uint32_t atomic_swap32(uint32_t *addr, uint32_t val) {
 	return val;
 }
 
-#define REG_WRITE_ATOMIC(addr, val) atomic_swap32((uint32_t *)addr, val)
+static void REG_WRITE_ATOMIC(volatile unsigned int *addr, unsigned int val) {
+	struct l2cache_priv *priv = l2cachepriv;
+	SPIN_IRQFLAGS(irqflags);
+
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+	atomic_swap32((uint32_t *) addr, val);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+}
+
 #else
 #define REG_WRITE_ATOMIC(addr, val) REG_WRITE(addr, val)
 #endif
@@ -513,6 +541,7 @@ int l2cache_init1(struct drvmgr_dev *dev)
 	priv->dev = dev;
 	strncpy(&priv->devname[0], "l2cache0", DEVNAME_LEN);
 	l2cachepriv = priv;
+	SPIN_INIT(&priv->devlock, priv->devname);
 
 	/* Initialize L2CACHE Hardware */
 	status = l2cache_init(priv);
-- 
2.34.1



More information about the devel mailing list