From c609cceabbf8598be400fc9bb054d230a5eefcd6 Mon Sep 17 00:00:00 2001 From: Martin Aberg Date: Thu, 19 Jan 2017 18:57:58 +0100 Subject: leon, ahbstat: Use RTEMS 4.12 SMP interrupt lock --- c/src/lib/libbsp/sparc/shared/amba/ahbstat.c | 65 ++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c index 8fff66c8f5..ee697f6647 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,23 @@ */ #include +#include +#include #include #include #include -#include + +#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); @@ -51,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); @@ -113,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; } @@ -127,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; @@ -154,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 %ld" + printk("\n### AHBSTAT: %s %s error of size %ld by master %ld" " 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); } } @@ -180,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 */ -- cgit v1.2.3