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