bus: brcmstb_gisb: Add support for breakpoint interrupts
GISB breakpoint interrupts can be raised when a breakpoint has been enabled to match a specific master and/or GISB register address. Being able to print a message, similar to those done during target abort or timeout greatly helps debug systems. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
This commit is contained in:
Родитель
541b6e6ee7
Коммит
fb8a0b80c4
|
@ -30,8 +30,22 @@
|
|||
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
|
||||
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
|
||||
|
||||
#define ARB_BP_CAP_CLEAR (1 << 0)
|
||||
#define ARB_BP_CAP_STATUS_PROT_SHIFT 14
|
||||
#define ARB_BP_CAP_STATUS_TYPE (1 << 13)
|
||||
#define ARB_BP_CAP_STATUS_RSP_SHIFT 10
|
||||
#define ARB_BP_CAP_STATUS_MASK GENMASK(1, 0)
|
||||
#define ARB_BP_CAP_STATUS_BS_SHIFT 2
|
||||
#define ARB_BP_CAP_STATUS_WRITE (1 << 1)
|
||||
#define ARB_BP_CAP_STATUS_VALID (1 << 0)
|
||||
|
||||
enum {
|
||||
ARB_TIMER,
|
||||
ARB_BP_CAP_CLR,
|
||||
ARB_BP_CAP_HI_ADDR,
|
||||
ARB_BP_CAP_ADDR,
|
||||
ARB_BP_CAP_STATUS,
|
||||
ARB_BP_CAP_MASTER,
|
||||
ARB_ERR_CAP_CLR,
|
||||
ARB_ERR_CAP_HI_ADDR,
|
||||
ARB_ERR_CAP_ADDR,
|
||||
|
@ -41,6 +55,11 @@ enum {
|
|||
|
||||
static const int gisb_offsets_bcm7038[] = {
|
||||
[ARB_TIMER] = 0x00c,
|
||||
[ARB_BP_CAP_CLR] = 0x014,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x0b8,
|
||||
[ARB_BP_CAP_STATUS] = 0x0c0,
|
||||
[ARB_BP_CAP_MASTER] = -1,
|
||||
[ARB_ERR_CAP_CLR] = 0x0c4,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x0c8,
|
||||
|
@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = {
|
|||
|
||||
static const int gisb_offsets_bcm7278[] = {
|
||||
[ARB_TIMER] = 0x008,
|
||||
[ARB_BP_CAP_CLR] = 0x01c,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x220,
|
||||
[ARB_BP_CAP_STATUS] = 0x230,
|
||||
[ARB_BP_CAP_MASTER] = 0x234,
|
||||
[ARB_ERR_CAP_CLR] = 0x7f8,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x7e0,
|
||||
|
@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = {
|
|||
|
||||
static const int gisb_offsets_bcm7400[] = {
|
||||
[ARB_TIMER] = 0x00c,
|
||||
[ARB_BP_CAP_CLR] = 0x014,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x0b8,
|
||||
[ARB_BP_CAP_STATUS] = 0x0c0,
|
||||
[ARB_BP_CAP_MASTER] = 0x0c4,
|
||||
[ARB_ERR_CAP_CLR] = 0x0c8,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x0cc,
|
||||
|
@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = {
|
|||
|
||||
static const int gisb_offsets_bcm7435[] = {
|
||||
[ARB_TIMER] = 0x00c,
|
||||
[ARB_BP_CAP_CLR] = 0x014,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x158,
|
||||
[ARB_BP_CAP_STATUS] = 0x160,
|
||||
[ARB_BP_CAP_MASTER] = 0x164,
|
||||
[ARB_ERR_CAP_CLR] = 0x168,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x16c,
|
||||
|
@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = {
|
|||
|
||||
static const int gisb_offsets_bcm7445[] = {
|
||||
[ARB_TIMER] = 0x008,
|
||||
[ARB_BP_CAP_CLR] = 0x010,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x1d8,
|
||||
[ARB_BP_CAP_STATUS] = 0x1e0,
|
||||
[ARB_BP_CAP_MASTER] = 0x1e4,
|
||||
[ARB_ERR_CAP_CLR] = 0x7e4,
|
||||
[ARB_ERR_CAP_HI_ADDR] = 0x7e8,
|
||||
[ARB_ERR_CAP_ADDR] = 0x7ec,
|
||||
|
@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
|
|||
return value;
|
||||
}
|
||||
|
||||
static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
value = gisb_read(gdev, ARB_BP_CAP_ADDR);
|
||||
value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
|
||||
{
|
||||
int offset = gdev->gisb_offsets[reg];
|
||||
|
@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct brcmstb_gisb_arb_device *gdev = dev_id;
|
||||
const char *m_name;
|
||||
u32 bp_status;
|
||||
u64 arb_addr;
|
||||
u32 master;
|
||||
char m_fmt[11];
|
||||
|
||||
bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS);
|
||||
|
||||
/* Invalid captured address, bail out */
|
||||
if (!(bp_status & ARB_BP_CAP_STATUS_VALID))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Read the address and master */
|
||||
arb_addr = gisb_read_bp_address(gdev);
|
||||
master = gisb_read(gdev, ARB_BP_CAP_MASTER);
|
||||
|
||||
m_name = brcmstb_gisb_master_to_str(gdev, master);
|
||||
if (!m_name) {
|
||||
snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);
|
||||
m_name = m_fmt;
|
||||
}
|
||||
|
||||
pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n",
|
||||
arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R',
|
||||
m_name);
|
||||
|
||||
/* clear the GISB error */
|
||||
gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump out gisb errors on die or panic.
|
||||
*/
|
||||
|
@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
|
|||
struct brcmstb_gisb_arb_device *gdev;
|
||||
const struct of_device_id *of_id;
|
||||
struct resource *r;
|
||||
int err, timeout_irq, tea_irq;
|
||||
int err, timeout_irq, tea_irq, bp_irq;
|
||||
unsigned int num_masters, j = 0;
|
||||
int i, first, last;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
timeout_irq = platform_get_irq(pdev, 0);
|
||||
tea_irq = platform_get_irq(pdev, 1);
|
||||
bp_irq = platform_get_irq(pdev, 2);
|
||||
|
||||
gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL);
|
||||
if (!gdev)
|
||||
|
@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Interrupt is optional */
|
||||
if (bp_irq > 0) {
|
||||
err = devm_request_irq(&pdev->dev, bp_irq,
|
||||
brcmstb_gisb_bp_handler, 0, pdev->name,
|
||||
gdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* If we do not have a valid mask, assume all masters are enabled */
|
||||
if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",
|
||||
&gdev->valid_mask))
|
||||
|
|
Загрузка…
Ссылка в новой задаче