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:
Florian Fainelli 2020-04-17 17:21:32 -07:00
Родитель 541b6e6ee7
Коммит fb8a0b80c4
1 изменённых файлов: 95 добавлений и 1 удалений

Просмотреть файл

@ -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))