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.faine...@gmail.com>
---
 drivers/bus/brcmstb_gisb.c | 96 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 7579439971e3..7355fa2cb439 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -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))
-- 
2.25.1

Reply via email to