[PATCH 23/30] leon, ahbstat: Use RTEMS 4.12 SMP interrupt lock

Daniel Hellstrom daniel at gaisler.com
Thu Apr 13 19:31:32 UTC 2017


From: Martin Aberg <maberg at gaisler.com>

---
 c/src/lib/libbsp/sparc/shared/amba/ahbstat.c | 64 ++++++++++++++++++++++------
 1 file changed, 51 insertions(+), 13 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
index a30f0b1..0119fc1 100644
--- a/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
+++ b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
@@ -1,6 +1,6 @@
 /*  AHB Status register driver
  *
- *  COPYRIGHT (c) 2009.
+ *  COPYRIGHT (c) 2009 - 2017.
  *  Cobham Gaisler AB.
  *
  *  The license and distribution terms for this file may be
@@ -9,11 +9,24 @@
  */
 
 #include <stdint.h>
+#include <rtems/bspIo.h>
 #include <drvmgr/drvmgr.h>
 #include <drvmgr/ambapp_bus.h>
 
 #include <bsp/ahbstat.h>
 
+#include <rtems/rtems/intr.h>
+#define SPIN_IRQ_DECLARE(name)          RTEMS_INTERRUPT_LOCK_DECLARE(, name)
+#define SPIN_IRQ_INIT(lock, name)       rtems_interrupt_lock_initialize(lock, name)
+#define SPIN_IRQ_LOCK(lock, ctx)        rtems_interrupt_lock_acquire(lock, &(ctx))
+#define SPIN_IRQ_UNLOCK(lock, ctx)      rtems_interrupt_lock_release(lock, &(ctx))
+#define SPIN_IRQ_LOCK_ISR(lock, ctx)    rtems_interrupt_lock_acquire_isr(lock, &(ctx))
+#define SPIN_IRQ_UNLOCK_ISR(lock, ctx)  rtems_interrupt_lock_release_isr(lock, &(ctx))
+#define SPIN_IRQ_CTX                    rtems_interrupt_lock_context
+
+#define REG_WRITE(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
+#define REG_READ(addr) (*(volatile uint32_t *)(addr))
+
 void ahbstat_isr(void *arg);
 
 /* AHB fail interrupt callback to user. This function is declared weak so that
@@ -50,12 +63,17 @@ int (*ahbstat_error)(
 #define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
 #define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
 
+enum { DEVNAME_LEN = 9 };
 struct ahbstat_priv {
 	struct drvmgr_dev *dev;
 	struct ahbstat_regs *regs;
+	char devname[DEVNAME_LEN];
 	int minor;
+	/* Cached error */
 	uint32_t last_status;
 	uint32_t last_address;
+	/* Spin-lock ISR protection */
+	SPIN_IRQ_DECLARE(devlock);
 };
 
 static int ahbstat_init2(struct drvmgr_dev *dev);
@@ -112,11 +130,19 @@ static int ahbstat_init2(struct drvmgr_dev *dev)
 	priv->regs = (struct ahbstat_regs *)ambadev->info.apb_slv->start;
 	priv->minor = dev->minor_drv;
 
+	strncpy(&priv->devname[0], "ahbstat0", DEVNAME_LEN);
+	priv->devname[7] += priv->minor;
+	/*
+	 * Initialize spinlock for AHBSTAT Device. It is used to protect user
+	 * API calls involivng priv structure from updates in ISR.
+	 */
+	SPIN_IRQ_INIT(&priv->devlock, priv->devname);
+
 	/* Initialize hardware */
-	priv->regs->status = 0;
+	REG_WRITE(&priv->regs->status, 0);
 
 	/* Install IRQ handler */
-	drvmgr_interrupt_register(dev, 0, "ahbstat", ahbstat_isr, priv);
+	drvmgr_interrupt_register(dev, 0, priv->devname, ahbstat_isr, priv);
 
 	return DRVMGR_OK;
 }
@@ -126,26 +152,29 @@ void ahbstat_isr(void *arg)
 	struct ahbstat_priv *priv = arg;
 	uint32_t fadr, status;
 	int rc;
+	SPIN_IRQ_CTX lock_context;
 
 	/* Get hardware status */
-	status = priv->regs->status;
+	status = REG_READ(&priv->regs->status);
 	if ((status & AHBSTAT_STS_NE) == 0)
 		return;
 
 	/* IRQ generated by AHBSTAT core... handle it here */
 
 	/* Get Failing address */
-	fadr = priv->regs->failing;
+	fadr = REG_READ(&priv->regs->failing);
 
+	SPIN_IRQ_LOCK_ISR(&priv->devlock, lock_context);
 	priv->last_status = status;
 	priv->last_address = fadr;
+	SPIN_IRQ_UNLOCK_ISR(&priv->devlock, lock_context);
 
 	/* Let user handle error, default to print the error and reenable HW
 	 *
 	 * User return 
 	 *  0: print error and reenable AHBSTAT
 	 *  1: just reenable AHBSTAT
-	 *  2: just print error reenable
+	 *  2: just print error
 	 *  3: do nothing
 	 */
 	rc = 0;
@@ -153,18 +182,18 @@ void ahbstat_isr(void *arg)
 		rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
 
 	if ((rc & 0x1) == 0) {
-		printk("\n### AHBSTAT: %s %s error of size %lu by master %d"
+		printk("\n### AHBSTAT: %s %s error of size %d by master %d"
 			" at 0x%08lx\n",
 			status & AHBSTAT_STS_CE ? "single" : "non-correctable",
 			status & AHBSTAT_STS_HW ? "write" : "read",
-			(status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
-			(status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
+			(int) (status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
+			(int) (status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
 			fadr);
 	}
 
 	if ((rc & 0x2) == 0) {
 		/* Trigger new interrupts */
-		priv->regs->status = 0;
+		REG_WRITE(&priv->regs->status, 0);
 	}
 }
 
@@ -179,16 +208,25 @@ int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address)
 {
 	struct drvmgr_dev *dev;
 	struct ahbstat_priv *priv;
+	uint32_t last_status;
+	uint32_t last_address;
+	SPIN_IRQ_CTX lock_context;
 
 	if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
 		return -1;
 	}
 	priv = (struct ahbstat_priv *)dev->priv;
 
-	*status = priv->last_status;
-	*address = priv->last_address;
+	/* Read information cached by ISR */
+	SPIN_IRQ_LOCK(&priv->devlock, lock_context);
+	last_status = REG_READ(&priv->last_status);
+	last_address = REG_READ(&priv->last_address);
+	SPIN_IRQ_UNLOCK(&priv->devlock, lock_context);
+
+	*status = last_status;
+	*address = last_address;
 
-	return (priv->last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
+	return (last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
 }
 
 /* Get AHBSTAT registers address from minor. NULL returned if no such device */
-- 
2.7.4




More information about the devel mailing list