brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · ee29162 Raw
567 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014-2021 Broadcom4 */5 6#include <linux/init.h>7#include <linux/types.h>8#include <linux/module.h>9#include <linux/panic_notifier.h>10#include <linux/platform_device.h>11#include <linux/interrupt.h>12#include <linux/sysfs.h>13#include <linux/io.h>14#include <linux/string.h>15#include <linux/device.h>16#include <linux/list.h>17#include <linux/of.h>18#include <linux/bitops.h>19#include <linux/pm.h>20#include <linux/kernel.h>21#include <linux/kdebug.h>22#include <linux/notifier.h>23 24#ifdef CONFIG_MIPS25#include <asm/traps.h>26#endif27 28#define  ARB_ERR_CAP_CLEAR		(1 << 0)29#define  ARB_ERR_CAP_STATUS_TIMEOUT	(1 << 12)30#define  ARB_ERR_CAP_STATUS_TEA		(1 << 11)31#define  ARB_ERR_CAP_STATUS_WRITE	(1 << 1)32#define  ARB_ERR_CAP_STATUS_VALID	(1 << 0)33 34#define  ARB_BP_CAP_CLEAR		(1 << 0)35#define  ARB_BP_CAP_STATUS_PROT_SHIFT	1436#define  ARB_BP_CAP_STATUS_TYPE		(1 << 13)37#define  ARB_BP_CAP_STATUS_RSP_SHIFT	1038#define  ARB_BP_CAP_STATUS_MASK		GENMASK(1, 0)39#define  ARB_BP_CAP_STATUS_BS_SHIFT	240#define  ARB_BP_CAP_STATUS_WRITE	(1 << 1)41#define  ARB_BP_CAP_STATUS_VALID	(1 << 0)42 43enum {44	ARB_TIMER,45	ARB_BP_CAP_CLR,46	ARB_BP_CAP_HI_ADDR,47	ARB_BP_CAP_ADDR,48	ARB_BP_CAP_STATUS,49	ARB_BP_CAP_MASTER,50	ARB_ERR_CAP_CLR,51	ARB_ERR_CAP_HI_ADDR,52	ARB_ERR_CAP_ADDR,53	ARB_ERR_CAP_STATUS,54	ARB_ERR_CAP_MASTER,55};56 57static const int gisb_offsets_bcm7038[] = {58	[ARB_TIMER]		= 0x00c,59	[ARB_BP_CAP_CLR]	= 0x014,60	[ARB_BP_CAP_HI_ADDR]	= -1,61	[ARB_BP_CAP_ADDR]	= 0x0b8,62	[ARB_BP_CAP_STATUS]	= 0x0c0,63	[ARB_BP_CAP_MASTER]	= -1,64	[ARB_ERR_CAP_CLR]	= 0x0c4,65	[ARB_ERR_CAP_HI_ADDR]	= -1,66	[ARB_ERR_CAP_ADDR]	= 0x0c8,67	[ARB_ERR_CAP_STATUS]	= 0x0d0,68	[ARB_ERR_CAP_MASTER]	= -1,69};70 71static const int gisb_offsets_bcm7278[] = {72	[ARB_TIMER]		= 0x008,73	[ARB_BP_CAP_CLR]	= 0x01c,74	[ARB_BP_CAP_HI_ADDR]	= -1,75	[ARB_BP_CAP_ADDR]	= 0x220,76	[ARB_BP_CAP_STATUS]	= 0x230,77	[ARB_BP_CAP_MASTER]	= 0x234,78	[ARB_ERR_CAP_CLR]	= 0x7f8,79	[ARB_ERR_CAP_HI_ADDR]	= -1,80	[ARB_ERR_CAP_ADDR]	= 0x7e0,81	[ARB_ERR_CAP_STATUS]	= 0x7f0,82	[ARB_ERR_CAP_MASTER]	= 0x7f4,83};84 85static const int gisb_offsets_bcm7400[] = {86	[ARB_TIMER]		= 0x00c,87	[ARB_BP_CAP_CLR]	= 0x014,88	[ARB_BP_CAP_HI_ADDR]	= -1,89	[ARB_BP_CAP_ADDR]	= 0x0b8,90	[ARB_BP_CAP_STATUS]	= 0x0c0,91	[ARB_BP_CAP_MASTER]	= 0x0c4,92	[ARB_ERR_CAP_CLR]	= 0x0c8,93	[ARB_ERR_CAP_HI_ADDR]	= -1,94	[ARB_ERR_CAP_ADDR]	= 0x0cc,95	[ARB_ERR_CAP_STATUS]	= 0x0d4,96	[ARB_ERR_CAP_MASTER]	= 0x0d8,97};98 99static const int gisb_offsets_bcm74165[] = {100	[ARB_TIMER]		= 0x008,101	[ARB_BP_CAP_CLR]	= 0x044,102	[ARB_BP_CAP_HI_ADDR]	= -1,103	[ARB_BP_CAP_ADDR]	= 0x048,104	[ARB_BP_CAP_STATUS]	= 0x058,105	[ARB_BP_CAP_MASTER]	= 0x05c,106	[ARB_ERR_CAP_CLR]	= 0x038,107	[ARB_ERR_CAP_HI_ADDR]	= -1,108	[ARB_ERR_CAP_ADDR]	= 0x020,109	[ARB_ERR_CAP_STATUS]	= 0x030,110	[ARB_ERR_CAP_MASTER]	= 0x034,111};112 113static const int gisb_offsets_bcm7435[] = {114	[ARB_TIMER]		= 0x00c,115	[ARB_BP_CAP_CLR]	= 0x014,116	[ARB_BP_CAP_HI_ADDR]	= -1,117	[ARB_BP_CAP_ADDR]	= 0x158,118	[ARB_BP_CAP_STATUS]	= 0x160,119	[ARB_BP_CAP_MASTER]	= 0x164,120	[ARB_ERR_CAP_CLR]	= 0x168,121	[ARB_ERR_CAP_HI_ADDR]	= -1,122	[ARB_ERR_CAP_ADDR]	= 0x16c,123	[ARB_ERR_CAP_STATUS]	= 0x174,124	[ARB_ERR_CAP_MASTER]	= 0x178,125};126 127static const int gisb_offsets_bcm7445[] = {128	[ARB_TIMER]		= 0x008,129	[ARB_BP_CAP_CLR]	= 0x010,130	[ARB_BP_CAP_HI_ADDR]	= -1,131	[ARB_BP_CAP_ADDR]	= 0x1d8,132	[ARB_BP_CAP_STATUS]	= 0x1e0,133	[ARB_BP_CAP_MASTER]	= 0x1e4,134	[ARB_ERR_CAP_CLR]	= 0x7e4,135	[ARB_ERR_CAP_HI_ADDR]	= 0x7e8,136	[ARB_ERR_CAP_ADDR]	= 0x7ec,137	[ARB_ERR_CAP_STATUS]	= 0x7f4,138	[ARB_ERR_CAP_MASTER]	= 0x7f8,139};140 141struct brcmstb_gisb_arb_device {142	void __iomem	*base;143	const int	*gisb_offsets;144	bool		big_endian;145	struct mutex	lock;146	struct list_head next;147	u32 valid_mask;148	const char *master_names[sizeof(u32) * BITS_PER_BYTE];149	u32 saved_timeout;150};151 152static LIST_HEAD(brcmstb_gisb_arb_device_list);153 154static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)155{156	int offset = gdev->gisb_offsets[reg];157 158	if (offset < 0) {159		/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */160		if (reg == ARB_ERR_CAP_MASTER)161			return 1;162		else163			return 0;164	}165 166	if (gdev->big_endian)167		return ioread32be(gdev->base + offset);168	else169		return ioread32(gdev->base + offset);170}171 172static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)173{174	u64 value;175 176	value = gisb_read(gdev, ARB_ERR_CAP_ADDR);177	value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;178 179	return value;180}181 182static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev)183{184	u64 value;185 186	value = gisb_read(gdev, ARB_BP_CAP_ADDR);187	value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32;188 189	return value;190}191 192static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)193{194	int offset = gdev->gisb_offsets[reg];195 196	if (offset == -1)197		return;198 199	if (gdev->big_endian)200		iowrite32be(val, gdev->base + offset);201	else202		iowrite32(val, gdev->base + offset);203}204 205static ssize_t gisb_arb_get_timeout(struct device *dev,206				    struct device_attribute *attr,207				    char *buf)208{209	struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);210	u32 timeout;211 212	mutex_lock(&gdev->lock);213	timeout = gisb_read(gdev, ARB_TIMER);214	mutex_unlock(&gdev->lock);215 216	return sprintf(buf, "%d", timeout);217}218 219static ssize_t gisb_arb_set_timeout(struct device *dev,220				    struct device_attribute *attr,221				    const char *buf, size_t count)222{223	struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);224	int val, ret;225 226	ret = kstrtoint(buf, 10, &val);227	if (ret < 0)228		return ret;229 230	if (val == 0 || val >= 0xffffffff)231		return -EINVAL;232 233	mutex_lock(&gdev->lock);234	gisb_write(gdev, val, ARB_TIMER);235	mutex_unlock(&gdev->lock);236 237	return count;238}239 240static const char *241brcmstb_gisb_master_to_str(struct brcmstb_gisb_arb_device *gdev,242						u32 masters)243{244	u32 mask = gdev->valid_mask & masters;245 246	if (hweight_long(mask) != 1)247		return NULL;248 249	return gdev->master_names[ffs(mask) - 1];250}251 252static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,253					const char *reason)254{255	u32 cap_status;256	u64 arb_addr;257	u32 master;258	const char *m_name;259	char m_fmt[11];260 261	cap_status = gisb_read(gdev, ARB_ERR_CAP_STATUS);262 263	/* Invalid captured address, bail out */264	if (!(cap_status & ARB_ERR_CAP_STATUS_VALID))265		return 1;266 267	/* Read the address and master */268	arb_addr = gisb_read_address(gdev);269	master = gisb_read(gdev, ARB_ERR_CAP_MASTER);270 271	m_name = brcmstb_gisb_master_to_str(gdev, master);272	if (!m_name) {273		snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);274		m_name = m_fmt;275	}276 277	pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n",278		reason, arb_addr,279		cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',280		cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",281		m_name);282 283	/* clear the GISB error */284	gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);285 286	return 0;287}288 289#ifdef CONFIG_MIPS290static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)291{292	int ret = 0;293	struct brcmstb_gisb_arb_device *gdev;294	u32 cap_status;295 296	list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next) {297		cap_status = gisb_read(gdev, ARB_ERR_CAP_STATUS);298 299		/* Invalid captured address, bail out */300		if (!(cap_status & ARB_ERR_CAP_STATUS_VALID)) {301			is_fixup = 1;302			goto out;303		}304 305		ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error");306	}307out:308	return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;309}310#endif311 312static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id)313{314	brcmstb_gisb_arb_decode_addr(dev_id, "timeout");315 316	return IRQ_HANDLED;317}318 319static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)320{321	brcmstb_gisb_arb_decode_addr(dev_id, "target abort");322 323	return IRQ_HANDLED;324}325 326static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id)327{328	struct brcmstb_gisb_arb_device *gdev = dev_id;329	const char *m_name;330	u32 bp_status;331	u64 arb_addr;332	u32 master;333	char m_fmt[11];334 335	bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS);336 337	/* Invalid captured address, bail out */338	if (!(bp_status & ARB_BP_CAP_STATUS_VALID))339		return IRQ_HANDLED;340 341	/* Read the address and master */342	arb_addr = gisb_read_bp_address(gdev);343	master = gisb_read(gdev, ARB_BP_CAP_MASTER);344 345	m_name = brcmstb_gisb_master_to_str(gdev, master);346	if (!m_name) {347		snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);348		m_name = m_fmt;349	}350 351	pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n",352		arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R',353		m_name);354 355	/* clear the GISB error */356	gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);357 358	return IRQ_HANDLED;359}360 361/*362 * Dump out gisb errors on die or panic.363 */364static int dump_gisb_error(struct notifier_block *self, unsigned long v,365			   void *p);366 367static struct notifier_block gisb_die_notifier = {368	.notifier_call = dump_gisb_error,369};370 371static struct notifier_block gisb_panic_notifier = {372	.notifier_call = dump_gisb_error,373};374 375static int dump_gisb_error(struct notifier_block *self, unsigned long v,376			   void *p)377{378	struct brcmstb_gisb_arb_device *gdev;379	const char *reason = "panic";380 381	if (self == &gisb_die_notifier)382		reason = "die";383 384	/* iterate over each GISB arb registered handlers */385	list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)386		brcmstb_gisb_arb_decode_addr(gdev, reason);387 388	return NOTIFY_DONE;389}390 391static DEVICE_ATTR(gisb_arb_timeout, S_IWUSR | S_IRUGO,392		gisb_arb_get_timeout, gisb_arb_set_timeout);393 394static struct attribute *gisb_arb_sysfs_attrs[] = {395	&dev_attr_gisb_arb_timeout.attr,396	NULL,397};398 399static struct attribute_group gisb_arb_sysfs_attr_group = {400	.attrs = gisb_arb_sysfs_attrs,401};402 403static const struct of_device_id brcmstb_gisb_arb_of_match[] = {404	{ .compatible = "brcm,gisb-arb",         .data = gisb_offsets_bcm7445 },405	{ .compatible = "brcm,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 },406	{ .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },407	{ .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },408	{ .compatible = "brcm,bcm7278-gisb-arb", .data = gisb_offsets_bcm7278 },409	{ .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 },410	{ .compatible = "brcm,bcm74165-gisb-arb", .data = gisb_offsets_bcm74165 },411	{ },412};413MODULE_DEVICE_TABLE(of, brcmstb_gisb_arb_of_match);414 415static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)416{417	struct device_node *dn = pdev->dev.of_node;418	struct brcmstb_gisb_arb_device *gdev;419	const struct of_device_id *of_id;420	int err, timeout_irq, tea_irq, bp_irq;421	unsigned int num_masters, j = 0;422	int i, first, last;423 424	timeout_irq = platform_get_irq(pdev, 0);425	tea_irq = platform_get_irq(pdev, 1);426	bp_irq = platform_get_irq(pdev, 2);427 428	gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL);429	if (!gdev)430		return -ENOMEM;431 432	mutex_init(&gdev->lock);433	INIT_LIST_HEAD(&gdev->next);434 435	gdev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);436	if (IS_ERR(gdev->base))437		return PTR_ERR(gdev->base);438 439	of_id = of_match_node(brcmstb_gisb_arb_of_match, dn);440	if (!of_id) {441		pr_err("failed to look up compatible string\n");442		return -EINVAL;443	}444	gdev->gisb_offsets = of_id->data;445	gdev->big_endian = of_device_is_big_endian(dn);446 447	err = devm_request_irq(&pdev->dev, timeout_irq,448				brcmstb_gisb_timeout_handler, 0, pdev->name,449				gdev);450	if (err < 0)451		return err;452 453	err = devm_request_irq(&pdev->dev, tea_irq,454				brcmstb_gisb_tea_handler, 0, pdev->name,455				gdev);456	if (err < 0)457		return err;458 459	/* Interrupt is optional */460	if (bp_irq > 0) {461		err = devm_request_irq(&pdev->dev, bp_irq,462				       brcmstb_gisb_bp_handler, 0, pdev->name,463				       gdev);464		if (err < 0)465			return err;466	}467 468	/* If we do not have a valid mask, assume all masters are enabled */469	if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",470				&gdev->valid_mask))471		gdev->valid_mask = 0xffffffff;472 473	/* Proceed with reading the litteral names if we agree on the474	 * number of masters475	 */476	num_masters = of_property_count_strings(dn,477			"brcm,gisb-arb-master-names");478	if (hweight_long(gdev->valid_mask) == num_masters) {479		first = ffs(gdev->valid_mask) - 1;480		last = fls(gdev->valid_mask) - 1;481 482		for (i = first; i < last; i++) {483			if (!(gdev->valid_mask & BIT(i)))484				continue;485 486			of_property_read_string_index(dn,487					"brcm,gisb-arb-master-names", j,488					&gdev->master_names[i]);489			j++;490		}491	}492 493	err = sysfs_create_group(&pdev->dev.kobj, &gisb_arb_sysfs_attr_group);494	if (err)495		return err;496 497	platform_set_drvdata(pdev, gdev);498 499	list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);500 501#ifdef CONFIG_MIPS502	mips_set_be_handler(brcmstb_bus_error_handler);503#endif504 505	if (list_is_singular(&brcmstb_gisb_arb_device_list)) {506		register_die_notifier(&gisb_die_notifier);507		atomic_notifier_chain_register(&panic_notifier_list,508					       &gisb_panic_notifier);509	}510 511	dev_info(&pdev->dev, "registered irqs: %d, %d\n",512		 timeout_irq, tea_irq);513 514	return 0;515}516 517#ifdef CONFIG_PM_SLEEP518static int brcmstb_gisb_arb_suspend(struct device *dev)519{520	struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);521 522	gdev->saved_timeout = gisb_read(gdev, ARB_TIMER);523 524	return 0;525}526 527/* Make sure we provide the same timeout value that was configured before, and528 * do this before the GISB timeout interrupt handler has any chance to run.529 */530static int brcmstb_gisb_arb_resume_noirq(struct device *dev)531{532	struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);533 534	gisb_write(gdev, gdev->saved_timeout, ARB_TIMER);535 536	return 0;537}538#else539#define brcmstb_gisb_arb_suspend       NULL540#define brcmstb_gisb_arb_resume_noirq  NULL541#endif542 543static const struct dev_pm_ops brcmstb_gisb_arb_pm_ops = {544	.suspend	= brcmstb_gisb_arb_suspend,545	.resume_noirq	= brcmstb_gisb_arb_resume_noirq,546};547 548static struct platform_driver brcmstb_gisb_arb_driver = {549	.driver = {550		.name	= "brcm-gisb-arb",551		.of_match_table = brcmstb_gisb_arb_of_match,552		.pm	= &brcmstb_gisb_arb_pm_ops,553	},554};555 556static int __init brcm_gisb_driver_init(void)557{558	return platform_driver_probe(&brcmstb_gisb_arb_driver,559				     brcmstb_gisb_arb_probe);560}561 562module_init(brcm_gisb_driver_init);563 564MODULE_AUTHOR("Broadcom");565MODULE_DESCRIPTION("Broadcom STB GISB arbiter driver");566MODULE_LICENSE("GPL v2");567