From: Martin Aberg <mab...@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

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to