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