Commit fb8a0b80 authored by Florian Fainelli's avatar Florian Fainelli
Browse files

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: default avatarFlorian Fainelli <f.fainelli@gmail.com>
parent 541b6e6e
Loading
Loading
Loading
Loading
+95 −1
Original line number Diff line number Diff line
@@ -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))