forked from Imagelibrary/rtems
leon, ahbstat: Use RTEMS 4.12 SMP interrupt lock
This commit is contained in:
committed by
Daniel Hellstrom
parent
c241236139
commit
c609cceabb
@@ -1,6 +1,6 @@
|
|||||||
/* AHB Status register driver
|
/* AHB Status register driver
|
||||||
*
|
*
|
||||||
* COPYRIGHT (c) 2009.
|
* COPYRIGHT (c) 2009 - 2017.
|
||||||
* Cobham Gaisler AB.
|
* Cobham Gaisler AB.
|
||||||
*
|
*
|
||||||
* The license and distribution terms for this file may be
|
* The license and distribution terms for this file may be
|
||||||
@@ -9,11 +9,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <rtems.h>
|
||||||
|
#include <rtems/bspIo.h>
|
||||||
#include <drvmgr/drvmgr.h>
|
#include <drvmgr/drvmgr.h>
|
||||||
#include <drvmgr/ambapp_bus.h>
|
#include <drvmgr/ambapp_bus.h>
|
||||||
|
|
||||||
#include <bsp/ahbstat.h>
|
#include <bsp/ahbstat.h>
|
||||||
#include <rtems/bspIo.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);
|
void ahbstat_isr(void *arg);
|
||||||
|
|
||||||
@@ -51,12 +63,17 @@ int (*ahbstat_error)(
|
|||||||
#define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
|
#define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
|
||||||
#define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
|
#define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
|
||||||
|
|
||||||
|
enum { DEVNAME_LEN = 9 };
|
||||||
struct ahbstat_priv {
|
struct ahbstat_priv {
|
||||||
struct drvmgr_dev *dev;
|
struct drvmgr_dev *dev;
|
||||||
struct ahbstat_regs *regs;
|
struct ahbstat_regs *regs;
|
||||||
|
char devname[DEVNAME_LEN];
|
||||||
int minor;
|
int minor;
|
||||||
|
/* Cached error */
|
||||||
uint32_t last_status;
|
uint32_t last_status;
|
||||||
uint32_t last_address;
|
uint32_t last_address;
|
||||||
|
/* Spin-lock ISR protection */
|
||||||
|
SPIN_IRQ_DECLARE(devlock);
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ahbstat_init2(struct drvmgr_dev *dev);
|
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->regs = (struct ahbstat_regs *)ambadev->info.apb_slv->start;
|
||||||
priv->minor = dev->minor_drv;
|
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 */
|
/* Initialize hardware */
|
||||||
priv->regs->status = 0;
|
REG_WRITE(&priv->regs->status, 0);
|
||||||
|
|
||||||
/* Install IRQ handler */
|
/* 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;
|
return DRVMGR_OK;
|
||||||
}
|
}
|
||||||
@@ -127,26 +152,29 @@ void ahbstat_isr(void *arg)
|
|||||||
struct ahbstat_priv *priv = arg;
|
struct ahbstat_priv *priv = arg;
|
||||||
uint32_t fadr, status;
|
uint32_t fadr, status;
|
||||||
int rc;
|
int rc;
|
||||||
|
SPIN_IRQ_CTX lock_context;
|
||||||
|
|
||||||
/* Get hardware status */
|
/* Get hardware status */
|
||||||
status = priv->regs->status;
|
status = REG_READ(&priv->regs->status);
|
||||||
if ((status & AHBSTAT_STS_NE) == 0)
|
if ((status & AHBSTAT_STS_NE) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* IRQ generated by AHBSTAT core... handle it here */
|
/* IRQ generated by AHBSTAT core... handle it here */
|
||||||
|
|
||||||
/* Get Failing address */
|
/* 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_status = status;
|
||||||
priv->last_address = fadr;
|
priv->last_address = fadr;
|
||||||
|
SPIN_IRQ_UNLOCK_ISR(&priv->devlock, lock_context);
|
||||||
|
|
||||||
/* Let user handle error, default to print the error and reenable HW
|
/* Let user handle error, default to print the error and reenable HW
|
||||||
*
|
*
|
||||||
* User return
|
* User return
|
||||||
* 0: print error and reenable AHBSTAT
|
* 0: print error and reenable AHBSTAT
|
||||||
* 1: just reenable AHBSTAT
|
* 1: just reenable AHBSTAT
|
||||||
* 2: just print error reenable
|
* 2: just print error
|
||||||
* 3: do nothing
|
* 3: do nothing
|
||||||
*/
|
*/
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@@ -154,18 +182,18 @@ void ahbstat_isr(void *arg)
|
|||||||
rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
|
rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
|
||||||
|
|
||||||
if ((rc & 0x1) == 0) {
|
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",
|
" at 0x%08lx\n",
|
||||||
status & AHBSTAT_STS_CE ? "single" : "non-correctable",
|
status & AHBSTAT_STS_CE ? "single" : "non-correctable",
|
||||||
status & AHBSTAT_STS_HW ? "write" : "read",
|
status & AHBSTAT_STS_HW ? "write" : "read",
|
||||||
(status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
|
(int) (status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
|
||||||
(status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
|
(int) (status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
|
||||||
fadr);
|
fadr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rc & 0x2) == 0) {
|
if ((rc & 0x2) == 0) {
|
||||||
/* Trigger new interrupts */
|
/* 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 drvmgr_dev *dev;
|
||||||
struct ahbstat_priv *priv;
|
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)) {
|
if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
priv = (struct ahbstat_priv *)dev->priv;
|
priv = (struct ahbstat_priv *)dev->priv;
|
||||||
|
|
||||||
*status = priv->last_status;
|
/* Read information cached by ISR */
|
||||||
*address = priv->last_address;
|
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);
|
||||||
|
|
||||||
return (priv->last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
|
*status = last_status;
|
||||||
|
*address = last_address;
|
||||||
|
|
||||||
|
return (last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get AHBSTAT registers address from minor. NULL returned if no such device */
|
/* Get AHBSTAT registers address from minor. NULL returned if no such device */
|
||||||
|
|||||||
Reference in New Issue
Block a user