| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * The file intends to implement the platform dependent EEH operations on |
|---|
| 3 | | - * powernv platform. Actually, the powernv was created in order to fully |
|---|
| 4 | | - * hypervisor support. |
|---|
| 3 | + * PowerNV Platform dependent EEH operations |
|---|
| 5 | 4 | * |
|---|
| 6 | 5 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | 6 | */ |
|---|
| 13 | 7 | |
|---|
| 14 | 8 | #include <linux/atomic.h> |
|---|
| .. | .. |
|---|
| 40 | 34 | |
|---|
| 41 | 35 | #include "powernv.h" |
|---|
| 42 | 36 | #include "pci.h" |
|---|
| 37 | +#include "../../../../drivers/pci/pci.h" |
|---|
| 43 | 38 | |
|---|
| 44 | 39 | static int eeh_event_irq = -EINVAL; |
|---|
| 45 | 40 | |
|---|
| 46 | | -void pnv_pcibios_bus_add_device(struct pci_dev *pdev) |
|---|
| 41 | +static void pnv_pcibios_bus_add_device(struct pci_dev *pdev) |
|---|
| 47 | 42 | { |
|---|
| 48 | | - struct pci_dn *pdn = pci_get_pdn(pdev); |
|---|
| 49 | | - |
|---|
| 50 | | - if (!pdev->is_virtfn) |
|---|
| 51 | | - return; |
|---|
| 52 | | - |
|---|
| 53 | | - /* |
|---|
| 54 | | - * The following operations will fail if VF's sysfs files |
|---|
| 55 | | - * aren't created or its resources aren't finalized. |
|---|
| 56 | | - */ |
|---|
| 57 | | - eeh_add_device_early(pdn); |
|---|
| 58 | | - eeh_add_device_late(pdev); |
|---|
| 59 | | - eeh_sysfs_add_device(pdev); |
|---|
| 60 | | -} |
|---|
| 61 | | - |
|---|
| 62 | | -static int pnv_eeh_init(void) |
|---|
| 63 | | -{ |
|---|
| 64 | | - struct pci_controller *hose; |
|---|
| 65 | | - struct pnv_phb *phb; |
|---|
| 66 | | - int max_diag_size = PNV_PCI_DIAG_BUF_SIZE; |
|---|
| 67 | | - |
|---|
| 68 | | - if (!firmware_has_feature(FW_FEATURE_OPAL)) { |
|---|
| 69 | | - pr_warn("%s: OPAL is required !\n", |
|---|
| 70 | | - __func__); |
|---|
| 71 | | - return -EINVAL; |
|---|
| 72 | | - } |
|---|
| 73 | | - |
|---|
| 74 | | - /* Set probe mode */ |
|---|
| 75 | | - eeh_add_flag(EEH_PROBE_MODE_DEV); |
|---|
| 76 | | - |
|---|
| 77 | | - /* |
|---|
| 78 | | - * P7IOC blocks PCI config access to frozen PE, but PHB3 |
|---|
| 79 | | - * doesn't do that. So we have to selectively enable I/O |
|---|
| 80 | | - * prior to collecting error log. |
|---|
| 81 | | - */ |
|---|
| 82 | | - list_for_each_entry(hose, &hose_list, list_node) { |
|---|
| 83 | | - phb = hose->private_data; |
|---|
| 84 | | - |
|---|
| 85 | | - if (phb->model == PNV_PHB_MODEL_P7IOC) |
|---|
| 86 | | - eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); |
|---|
| 87 | | - |
|---|
| 88 | | - if (phb->diag_data_size > max_diag_size) |
|---|
| 89 | | - max_diag_size = phb->diag_data_size; |
|---|
| 90 | | - |
|---|
| 91 | | - /* |
|---|
| 92 | | - * PE#0 should be regarded as valid by EEH core |
|---|
| 93 | | - * if it's not the reserved one. Currently, we |
|---|
| 94 | | - * have the reserved PE#255 and PE#127 for PHB3 |
|---|
| 95 | | - * and P7IOC separately. So we should regard |
|---|
| 96 | | - * PE#0 as valid for PHB3 and P7IOC. |
|---|
| 97 | | - */ |
|---|
| 98 | | - if (phb->ioda.reserved_pe_idx != 0) |
|---|
| 99 | | - eeh_add_flag(EEH_VALID_PE_ZERO); |
|---|
| 100 | | - |
|---|
| 101 | | - break; |
|---|
| 102 | | - } |
|---|
| 103 | | - |
|---|
| 104 | | - eeh_set_pe_aux_size(max_diag_size); |
|---|
| 105 | | - ppc_md.pcibios_bus_add_device = pnv_pcibios_bus_add_device; |
|---|
| 106 | | - |
|---|
| 107 | | - return 0; |
|---|
| 43 | + dev_dbg(&pdev->dev, "EEH: Setting up device\n"); |
|---|
| 44 | + eeh_probe_device(pdev); |
|---|
| 108 | 45 | } |
|---|
| 109 | 46 | |
|---|
| 110 | 47 | static irqreturn_t pnv_eeh_event(int irq, void *data) |
|---|
| .. | .. |
|---|
| 150 | 87 | return -EINVAL; |
|---|
| 151 | 88 | |
|---|
| 152 | 89 | /* Retrieve PE */ |
|---|
| 153 | | - pe = eeh_pe_get(hose, pe_no, 0); |
|---|
| 90 | + pe = eeh_pe_get(hose, pe_no); |
|---|
| 154 | 91 | if (!pe) |
|---|
| 155 | 92 | return -ENODEV; |
|---|
| 156 | 93 | |
|---|
| .. | .. |
|---|
| 205 | 142 | |
|---|
| 206 | 143 | #endif /* CONFIG_DEBUG_FS */ |
|---|
| 207 | 144 | |
|---|
| 145 | +static void pnv_eeh_enable_phbs(void) |
|---|
| 146 | +{ |
|---|
| 147 | + struct pci_controller *hose; |
|---|
| 148 | + struct pnv_phb *phb; |
|---|
| 149 | + |
|---|
| 150 | + list_for_each_entry(hose, &hose_list, list_node) { |
|---|
| 151 | + phb = hose->private_data; |
|---|
| 152 | + /* |
|---|
| 153 | + * If EEH is enabled, we're going to rely on that. |
|---|
| 154 | + * Otherwise, we restore to conventional mechanism |
|---|
| 155 | + * to clear frozen PE during PCI config access. |
|---|
| 156 | + */ |
|---|
| 157 | + if (eeh_enabled()) |
|---|
| 158 | + phb->flags |= PNV_PHB_FLAG_EEH; |
|---|
| 159 | + else |
|---|
| 160 | + phb->flags &= ~PNV_PHB_FLAG_EEH; |
|---|
| 161 | + } |
|---|
| 162 | +} |
|---|
| 163 | + |
|---|
| 208 | 164 | /** |
|---|
| 209 | 165 | * pnv_eeh_post_init - EEH platform dependent post initialization |
|---|
| 210 | 166 | * |
|---|
| .. | .. |
|---|
| 219 | 175 | struct pnv_phb *phb; |
|---|
| 220 | 176 | int ret = 0; |
|---|
| 221 | 177 | |
|---|
| 222 | | - /* Probe devices & build address cache */ |
|---|
| 223 | | - eeh_probe_devices(); |
|---|
| 224 | | - eeh_addr_cache_build(); |
|---|
| 225 | | - |
|---|
| 226 | | - if (eeh_has_flag(EEH_POSTPONED_PROBE)) { |
|---|
| 227 | | - eeh_clear_flag(EEH_POSTPONED_PROBE); |
|---|
| 228 | | - if (eeh_enabled()) |
|---|
| 229 | | - pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); |
|---|
| 230 | | - else |
|---|
| 231 | | - pr_info("EEH: No capable adapters found\n"); |
|---|
| 232 | | - } |
|---|
| 178 | + eeh_show_enabled(); |
|---|
| 233 | 179 | |
|---|
| 234 | 180 | /* Register OPAL event notifier */ |
|---|
| 235 | 181 | eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR)); |
|---|
| .. | .. |
|---|
| 251 | 197 | if (!eeh_enabled()) |
|---|
| 252 | 198 | disable_irq(eeh_event_irq); |
|---|
| 253 | 199 | |
|---|
| 200 | + pnv_eeh_enable_phbs(); |
|---|
| 201 | + |
|---|
| 254 | 202 | list_for_each_entry(hose, &hose_list, list_node) { |
|---|
| 255 | 203 | phb = hose->private_data; |
|---|
| 256 | | - |
|---|
| 257 | | - /* |
|---|
| 258 | | - * If EEH is enabled, we're going to rely on that. |
|---|
| 259 | | - * Otherwise, we restore to conventional mechanism |
|---|
| 260 | | - * to clear frozen PE during PCI config access. |
|---|
| 261 | | - */ |
|---|
| 262 | | - if (eeh_enabled()) |
|---|
| 263 | | - phb->flags |= PNV_PHB_FLAG_EEH; |
|---|
| 264 | | - else |
|---|
| 265 | | - phb->flags &= ~PNV_PHB_FLAG_EEH; |
|---|
| 266 | 204 | |
|---|
| 267 | 205 | /* Create debugfs entries */ |
|---|
| 268 | 206 | #ifdef CONFIG_DEBUG_FS |
|---|
| .. | .. |
|---|
| 352 | 290 | return 0; |
|---|
| 353 | 291 | } |
|---|
| 354 | 292 | |
|---|
| 293 | +static struct eeh_pe *pnv_eeh_get_upstream_pe(struct pci_dev *pdev) |
|---|
| 294 | +{ |
|---|
| 295 | + struct pci_controller *hose = pdev->bus->sysdata; |
|---|
| 296 | + struct pnv_phb *phb = hose->private_data; |
|---|
| 297 | + struct pci_dev *parent = pdev->bus->self; |
|---|
| 298 | + |
|---|
| 299 | +#ifdef CONFIG_PCI_IOV |
|---|
| 300 | + /* for VFs we use the PF's PE as the upstream PE */ |
|---|
| 301 | + if (pdev->is_virtfn) |
|---|
| 302 | + parent = pdev->physfn; |
|---|
| 303 | +#endif |
|---|
| 304 | + |
|---|
| 305 | + /* otherwise use the PE of our parent bridge */ |
|---|
| 306 | + if (parent) { |
|---|
| 307 | + struct pnv_ioda_pe *ioda_pe = pnv_ioda_get_pe(parent); |
|---|
| 308 | + |
|---|
| 309 | + return eeh_pe_get(phb->hose, ioda_pe->pe_number); |
|---|
| 310 | + } |
|---|
| 311 | + |
|---|
| 312 | + return NULL; |
|---|
| 313 | +} |
|---|
| 314 | + |
|---|
| 355 | 315 | /** |
|---|
| 356 | 316 | * pnv_eeh_probe - Do probe on PCI device |
|---|
| 357 | | - * @pdn: PCI device node |
|---|
| 358 | | - * @data: unused |
|---|
| 317 | + * @pdev: pci_dev to probe |
|---|
| 359 | 318 | * |
|---|
| 360 | | - * When EEH module is installed during system boot, all PCI devices |
|---|
| 361 | | - * are checked one by one to see if it supports EEH. The function |
|---|
| 362 | | - * is introduced for the purpose. By default, EEH has been enabled |
|---|
| 363 | | - * on all PCI devices. That's to say, we only need do necessary |
|---|
| 364 | | - * initialization on the corresponding eeh device and create PE |
|---|
| 365 | | - * accordingly. |
|---|
| 366 | | - * |
|---|
| 367 | | - * It's notable that's unsafe to retrieve the EEH device through |
|---|
| 368 | | - * the corresponding PCI device. During the PCI device hotplug, which |
|---|
| 369 | | - * was possiblly triggered by EEH core, the binding between EEH device |
|---|
| 370 | | - * and the PCI device isn't built yet. |
|---|
| 319 | + * Create, or find the existing, eeh_dev for this pci_dev. |
|---|
| 371 | 320 | */ |
|---|
| 372 | | -static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) |
|---|
| 321 | +static struct eeh_dev *pnv_eeh_probe(struct pci_dev *pdev) |
|---|
| 373 | 322 | { |
|---|
| 323 | + struct pci_dn *pdn = pci_get_pdn(pdev); |
|---|
| 374 | 324 | struct pci_controller *hose = pdn->phb; |
|---|
| 375 | 325 | struct pnv_phb *phb = hose->private_data; |
|---|
| 376 | 326 | struct eeh_dev *edev = pdn_to_eeh_dev(pdn); |
|---|
| 327 | + struct eeh_pe *upstream_pe; |
|---|
| 377 | 328 | uint32_t pcie_flags; |
|---|
| 378 | 329 | int ret; |
|---|
| 379 | 330 | int config_addr = (pdn->busno << 8) | (pdn->devfn); |
|---|
| .. | .. |
|---|
| 387 | 338 | if (!edev || edev->pe) |
|---|
| 388 | 339 | return NULL; |
|---|
| 389 | 340 | |
|---|
| 390 | | - /* Skip for PCI-ISA bridge */ |
|---|
| 391 | | - if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) |
|---|
| 392 | | - return NULL; |
|---|
| 393 | | - |
|---|
| 394 | | - /* Skip if we haven't probed yet */ |
|---|
| 395 | | - if (phb->ioda.pe_rmap[config_addr] == IODA_INVALID_PE) { |
|---|
| 396 | | - eeh_add_flag(EEH_POSTPONED_PROBE); |
|---|
| 397 | | - return NULL; |
|---|
| 341 | + /* already configured? */ |
|---|
| 342 | + if (edev->pdev) { |
|---|
| 343 | + pr_debug("%s: found existing edev for %04x:%02x:%02x.%01x\n", |
|---|
| 344 | + __func__, hose->global_number, config_addr >> 8, |
|---|
| 345 | + PCI_SLOT(config_addr), PCI_FUNC(config_addr)); |
|---|
| 346 | + return edev; |
|---|
| 398 | 347 | } |
|---|
| 399 | 348 | |
|---|
| 349 | + /* Skip for PCI-ISA bridge */ |
|---|
| 350 | + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) |
|---|
| 351 | + return NULL; |
|---|
| 352 | + |
|---|
| 353 | + eeh_edev_dbg(edev, "Probing device\n"); |
|---|
| 354 | + |
|---|
| 400 | 355 | /* Initialize eeh device */ |
|---|
| 401 | | - edev->class_code = pdn->class_code; |
|---|
| 402 | 356 | edev->mode &= 0xFFFFFF00; |
|---|
| 403 | 357 | edev->pcix_cap = pnv_eeh_find_cap(pdn, PCI_CAP_ID_PCIX); |
|---|
| 404 | 358 | edev->pcie_cap = pnv_eeh_find_cap(pdn, PCI_CAP_ID_EXP); |
|---|
| 405 | 359 | edev->af_cap = pnv_eeh_find_cap(pdn, PCI_CAP_ID_AF); |
|---|
| 406 | 360 | edev->aer_cap = pnv_eeh_find_ecap(pdn, PCI_EXT_CAP_ID_ERR); |
|---|
| 407 | | - if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { |
|---|
| 361 | + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { |
|---|
| 408 | 362 | edev->mode |= EEH_DEV_BRIDGE; |
|---|
| 409 | 363 | if (edev->pcie_cap) { |
|---|
| 410 | 364 | pnv_pci_cfg_read(pdn, edev->pcie_cap + PCI_EXP_FLAGS, |
|---|
| .. | .. |
|---|
| 419 | 373 | |
|---|
| 420 | 374 | edev->pe_config_addr = phb->ioda.pe_rmap[config_addr]; |
|---|
| 421 | 375 | |
|---|
| 376 | + upstream_pe = pnv_eeh_get_upstream_pe(pdev); |
|---|
| 377 | + |
|---|
| 422 | 378 | /* Create PE */ |
|---|
| 423 | | - ret = eeh_add_to_parent_pe(edev); |
|---|
| 379 | + ret = eeh_pe_tree_insert(edev, upstream_pe); |
|---|
| 424 | 380 | if (ret) { |
|---|
| 425 | | - pr_warn("%s: Can't add PCI dev %04x:%02x:%02x.%01x to parent PE (%x)\n", |
|---|
| 426 | | - __func__, hose->global_number, pdn->busno, |
|---|
| 427 | | - PCI_SLOT(pdn->devfn), PCI_FUNC(pdn->devfn), ret); |
|---|
| 381 | + eeh_edev_warn(edev, "Failed to add device to PE (code %d)\n", ret); |
|---|
| 428 | 382 | return NULL; |
|---|
| 429 | 383 | } |
|---|
| 430 | 384 | |
|---|
| .. | .. |
|---|
| 473 | 427 | * Enable EEH explicitly so that we will do EEH check |
|---|
| 474 | 428 | * while accessing I/O stuff |
|---|
| 475 | 429 | */ |
|---|
| 476 | | - eeh_add_flag(EEH_ENABLED); |
|---|
| 430 | + if (!eeh_has_flag(EEH_ENABLED)) { |
|---|
| 431 | + enable_irq(eeh_event_irq); |
|---|
| 432 | + pnv_eeh_enable_phbs(); |
|---|
| 433 | + eeh_add_flag(EEH_ENABLED); |
|---|
| 434 | + } |
|---|
| 477 | 435 | |
|---|
| 478 | 436 | /* Save memory bars */ |
|---|
| 479 | 437 | eeh_save_bars(edev); |
|---|
| 480 | 438 | |
|---|
| 481 | | - return NULL; |
|---|
| 439 | + eeh_edev_dbg(edev, "EEH enabled on device\n"); |
|---|
| 440 | + |
|---|
| 441 | + return edev; |
|---|
| 482 | 442 | } |
|---|
| 483 | 443 | |
|---|
| 484 | 444 | /** |
|---|
| .. | .. |
|---|
| 551 | 511 | return 0; |
|---|
| 552 | 512 | } |
|---|
| 553 | 513 | |
|---|
| 554 | | -/** |
|---|
| 555 | | - * pnv_eeh_get_pe_addr - Retrieve PE address |
|---|
| 556 | | - * @pe: EEH PE |
|---|
| 557 | | - * |
|---|
| 558 | | - * Retrieve the PE address according to the given tranditional |
|---|
| 559 | | - * PCI BDF (Bus/Device/Function) address. |
|---|
| 560 | | - */ |
|---|
| 561 | | -static int pnv_eeh_get_pe_addr(struct eeh_pe *pe) |
|---|
| 562 | | -{ |
|---|
| 563 | | - return pe->addr; |
|---|
| 564 | | -} |
|---|
| 565 | | - |
|---|
| 566 | 514 | static void pnv_eeh_get_phb_diag(struct eeh_pe *pe) |
|---|
| 567 | 515 | { |
|---|
| 568 | 516 | struct pnv_phb *phb = pe->phb->private_data; |
|---|
| .. | .. |
|---|
| 604 | 552 | EEH_STATE_MMIO_ENABLED | |
|---|
| 605 | 553 | EEH_STATE_DMA_ENABLED); |
|---|
| 606 | 554 | } else if (!(pe->state & EEH_PE_ISOLATED)) { |
|---|
| 607 | | - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); |
|---|
| 555 | + eeh_pe_mark_isolated(pe); |
|---|
| 608 | 556 | pnv_eeh_get_phb_diag(pe); |
|---|
| 609 | 557 | |
|---|
| 610 | 558 | if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) |
|---|
| .. | .. |
|---|
| 706 | 654 | if (phb->freeze_pe) |
|---|
| 707 | 655 | phb->freeze_pe(phb, pe->addr); |
|---|
| 708 | 656 | |
|---|
| 709 | | - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); |
|---|
| 657 | + eeh_pe_mark_isolated(pe); |
|---|
| 710 | 658 | pnv_eeh_get_phb_diag(pe); |
|---|
| 711 | 659 | |
|---|
| 712 | 660 | if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) |
|---|
| .. | .. |
|---|
| 857 | 805 | int aer = edev ? edev->aer_cap : 0; |
|---|
| 858 | 806 | u32 ctrl; |
|---|
| 859 | 807 | |
|---|
| 860 | | - pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", |
|---|
| 808 | + pr_debug("%s: Secondary Reset PCI bus %04x:%02x with option %d\n", |
|---|
| 861 | 809 | __func__, pci_domain_nr(dev->bus), |
|---|
| 862 | 810 | dev->bus->number, option); |
|---|
| 863 | 811 | |
|---|
| .. | .. |
|---|
| 866 | 814 | case EEH_RESET_HOT: |
|---|
| 867 | 815 | /* Don't report linkDown event */ |
|---|
| 868 | 816 | if (aer) { |
|---|
| 869 | | - eeh_ops->read_config(pdn, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 817 | + eeh_ops->read_config(edev, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 870 | 818 | 4, &ctrl); |
|---|
| 871 | 819 | ctrl |= PCI_ERR_UNC_SURPDN; |
|---|
| 872 | | - eeh_ops->write_config(pdn, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 820 | + eeh_ops->write_config(edev, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 873 | 821 | 4, ctrl); |
|---|
| 874 | 822 | } |
|---|
| 875 | 823 | |
|---|
| 876 | | - eeh_ops->read_config(pdn, PCI_BRIDGE_CONTROL, 2, &ctrl); |
|---|
| 824 | + eeh_ops->read_config(edev, PCI_BRIDGE_CONTROL, 2, &ctrl); |
|---|
| 877 | 825 | ctrl |= PCI_BRIDGE_CTL_BUS_RESET; |
|---|
| 878 | | - eeh_ops->write_config(pdn, PCI_BRIDGE_CONTROL, 2, ctrl); |
|---|
| 826 | + eeh_ops->write_config(edev, PCI_BRIDGE_CONTROL, 2, ctrl); |
|---|
| 879 | 827 | |
|---|
| 880 | 828 | msleep(EEH_PE_RST_HOLD_TIME); |
|---|
| 881 | 829 | break; |
|---|
| 882 | 830 | case EEH_RESET_DEACTIVATE: |
|---|
| 883 | | - eeh_ops->read_config(pdn, PCI_BRIDGE_CONTROL, 2, &ctrl); |
|---|
| 831 | + eeh_ops->read_config(edev, PCI_BRIDGE_CONTROL, 2, &ctrl); |
|---|
| 884 | 832 | ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; |
|---|
| 885 | | - eeh_ops->write_config(pdn, PCI_BRIDGE_CONTROL, 2, ctrl); |
|---|
| 833 | + eeh_ops->write_config(edev, PCI_BRIDGE_CONTROL, 2, ctrl); |
|---|
| 886 | 834 | |
|---|
| 887 | 835 | msleep(EEH_PE_RST_SETTLE_TIME); |
|---|
| 888 | 836 | |
|---|
| 889 | 837 | /* Continue reporting linkDown event */ |
|---|
| 890 | 838 | if (aer) { |
|---|
| 891 | | - eeh_ops->read_config(pdn, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 839 | + eeh_ops->read_config(edev, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 892 | 840 | 4, &ctrl); |
|---|
| 893 | 841 | ctrl &= ~PCI_ERR_UNC_SURPDN; |
|---|
| 894 | | - eeh_ops->write_config(pdn, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 842 | + eeh_ops->write_config(edev, aer + PCI_ERR_UNCOR_MASK, |
|---|
| 895 | 843 | 4, ctrl); |
|---|
| 896 | 844 | } |
|---|
| 897 | 845 | |
|---|
| .. | .. |
|---|
| 914 | 862 | /* Hot reset to the bus if firmware cannot handle */ |
|---|
| 915 | 863 | if (!dn || !of_get_property(dn, "ibm,reset-by-firmware", NULL)) |
|---|
| 916 | 864 | return __pnv_eeh_bridge_reset(pdev, option); |
|---|
| 865 | + |
|---|
| 866 | + pr_debug("%s: FW reset PCI bus %04x:%02x with option %d\n", |
|---|
| 867 | + __func__, pci_domain_nr(pdev->bus), |
|---|
| 868 | + pdev->bus->number, option); |
|---|
| 917 | 869 | |
|---|
| 918 | 870 | switch (option) { |
|---|
| 919 | 871 | case EEH_RESET_FUNDAMENTAL: |
|---|
| .. | .. |
|---|
| 956 | 908 | static void pnv_eeh_wait_for_pending(struct pci_dn *pdn, const char *type, |
|---|
| 957 | 909 | int pos, u16 mask) |
|---|
| 958 | 910 | { |
|---|
| 911 | + struct eeh_dev *edev = pdn->edev; |
|---|
| 959 | 912 | int i, status = 0; |
|---|
| 960 | 913 | |
|---|
| 961 | 914 | /* Wait for Transaction Pending bit to be cleared */ |
|---|
| 962 | 915 | for (i = 0; i < 4; i++) { |
|---|
| 963 | | - eeh_ops->read_config(pdn, pos, 2, &status); |
|---|
| 916 | + eeh_ops->read_config(edev, pos, 2, &status); |
|---|
| 964 | 917 | if (!(status & mask)) |
|---|
| 965 | 918 | return; |
|---|
| 966 | 919 | |
|---|
| .. | .. |
|---|
| 981 | 934 | if (WARN_ON(!edev->pcie_cap)) |
|---|
| 982 | 935 | return -ENOTTY; |
|---|
| 983 | 936 | |
|---|
| 984 | | - eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCAP, 4, ®); |
|---|
| 937 | + eeh_ops->read_config(edev, edev->pcie_cap + PCI_EXP_DEVCAP, 4, ®); |
|---|
| 985 | 938 | if (!(reg & PCI_EXP_DEVCAP_FLR)) |
|---|
| 986 | 939 | return -ENOTTY; |
|---|
| 987 | 940 | |
|---|
| .. | .. |
|---|
| 991 | 944 | pnv_eeh_wait_for_pending(pdn, "", |
|---|
| 992 | 945 | edev->pcie_cap + PCI_EXP_DEVSTA, |
|---|
| 993 | 946 | PCI_EXP_DEVSTA_TRPND); |
|---|
| 994 | | - eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 947 | + eeh_ops->read_config(edev, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 995 | 948 | 4, ®); |
|---|
| 996 | 949 | reg |= PCI_EXP_DEVCTL_BCR_FLR; |
|---|
| 997 | | - eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 950 | + eeh_ops->write_config(edev, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 998 | 951 | 4, reg); |
|---|
| 999 | 952 | msleep(EEH_PE_RST_HOLD_TIME); |
|---|
| 1000 | 953 | break; |
|---|
| 1001 | 954 | case EEH_RESET_DEACTIVATE: |
|---|
| 1002 | | - eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 955 | + eeh_ops->read_config(edev, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 1003 | 956 | 4, ®); |
|---|
| 1004 | 957 | reg &= ~PCI_EXP_DEVCTL_BCR_FLR; |
|---|
| 1005 | | - eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 958 | + eeh_ops->write_config(edev, edev->pcie_cap + PCI_EXP_DEVCTL, |
|---|
| 1006 | 959 | 4, reg); |
|---|
| 1007 | 960 | msleep(EEH_PE_RST_SETTLE_TIME); |
|---|
| 1008 | 961 | break; |
|---|
| .. | .. |
|---|
| 1019 | 972 | if (WARN_ON(!edev->af_cap)) |
|---|
| 1020 | 973 | return -ENOTTY; |
|---|
| 1021 | 974 | |
|---|
| 1022 | | - eeh_ops->read_config(pdn, edev->af_cap + PCI_AF_CAP, 1, &cap); |
|---|
| 975 | + eeh_ops->read_config(edev, edev->af_cap + PCI_AF_CAP, 1, &cap); |
|---|
| 1023 | 976 | if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR)) |
|---|
| 1024 | 977 | return -ENOTTY; |
|---|
| 1025 | 978 | |
|---|
| .. | .. |
|---|
| 1034 | 987 | pnv_eeh_wait_for_pending(pdn, "AF", |
|---|
| 1035 | 988 | edev->af_cap + PCI_AF_CTRL, |
|---|
| 1036 | 989 | PCI_AF_STATUS_TP << 8); |
|---|
| 1037 | | - eeh_ops->write_config(pdn, edev->af_cap + PCI_AF_CTRL, |
|---|
| 990 | + eeh_ops->write_config(edev, edev->af_cap + PCI_AF_CTRL, |
|---|
| 1038 | 991 | 1, PCI_AF_CTRL_FLR); |
|---|
| 1039 | 992 | msleep(EEH_PE_RST_HOLD_TIME); |
|---|
| 1040 | 993 | break; |
|---|
| 1041 | 994 | case EEH_RESET_DEACTIVATE: |
|---|
| 1042 | | - eeh_ops->write_config(pdn, edev->af_cap + PCI_AF_CTRL, 1, 0); |
|---|
| 995 | + eeh_ops->write_config(edev, edev->af_cap + PCI_AF_CTRL, 1, 0); |
|---|
| 1043 | 996 | msleep(EEH_PE_RST_SETTLE_TIME); |
|---|
| 1044 | 997 | break; |
|---|
| 1045 | 998 | } |
|---|
| .. | .. |
|---|
| 1054 | 1007 | int ret; |
|---|
| 1055 | 1008 | |
|---|
| 1056 | 1009 | /* The VF PE should have only one child device */ |
|---|
| 1057 | | - edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, list); |
|---|
| 1010 | + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); |
|---|
| 1058 | 1011 | pdn = eeh_dev_to_pdn(edev); |
|---|
| 1059 | 1012 | if (!pdn) |
|---|
| 1060 | 1013 | return -ENXIO; |
|---|
| .. | .. |
|---|
| 1133 | 1086 | return -EIO; |
|---|
| 1134 | 1087 | } |
|---|
| 1135 | 1088 | |
|---|
| 1136 | | - /* |
|---|
| 1137 | | - * If dealing with the root bus (or the bus underneath the |
|---|
| 1138 | | - * root port), we reset the bus underneath the root port. |
|---|
| 1139 | | - * |
|---|
| 1140 | | - * The cxl driver depends on this behaviour for bi-modal card |
|---|
| 1141 | | - * switching. |
|---|
| 1142 | | - */ |
|---|
| 1143 | | - if (pci_is_root_bus(bus) || |
|---|
| 1144 | | - pci_is_root_bus(bus->parent)) |
|---|
| 1089 | + if (pci_is_root_bus(bus)) |
|---|
| 1145 | 1090 | return pnv_eeh_root_reset(hose, option); |
|---|
| 1146 | 1091 | |
|---|
| 1147 | | - return pnv_eeh_bridge_reset(bus->self, option); |
|---|
| 1148 | | -} |
|---|
| 1149 | | - |
|---|
| 1150 | | -/** |
|---|
| 1151 | | - * pnv_eeh_wait_state - Wait for PE state |
|---|
| 1152 | | - * @pe: EEH PE |
|---|
| 1153 | | - * @max_wait: maximal period in millisecond |
|---|
| 1154 | | - * |
|---|
| 1155 | | - * Wait for the state of associated PE. It might take some time |
|---|
| 1156 | | - * to retrieve the PE's state. |
|---|
| 1157 | | - */ |
|---|
| 1158 | | -static int pnv_eeh_wait_state(struct eeh_pe *pe, int max_wait) |
|---|
| 1159 | | -{ |
|---|
| 1160 | | - int ret; |
|---|
| 1161 | | - int mwait; |
|---|
| 1162 | | - |
|---|
| 1163 | | - while (1) { |
|---|
| 1164 | | - ret = pnv_eeh_get_state(pe, &mwait); |
|---|
| 1165 | | - |
|---|
| 1092 | + /* |
|---|
| 1093 | + * For hot resets try use the generic PCI error recovery reset |
|---|
| 1094 | + * functions. These correctly handles the case where the secondary |
|---|
| 1095 | + * bus is behind a hotplug slot and it will use the slot provided |
|---|
| 1096 | + * reset methods to prevent spurious hotplug events during the reset. |
|---|
| 1097 | + * |
|---|
| 1098 | + * Fundemental resets need to be handled internally to EEH since the |
|---|
| 1099 | + * PCI core doesn't really have a concept of a fundemental reset, |
|---|
| 1100 | + * mainly because there's no standard way to generate one. Only a |
|---|
| 1101 | + * few devices require an FRESET so it should be fine. |
|---|
| 1102 | + */ |
|---|
| 1103 | + if (option != EEH_RESET_FUNDAMENTAL) { |
|---|
| 1166 | 1104 | /* |
|---|
| 1167 | | - * If the PE's state is temporarily unavailable, |
|---|
| 1168 | | - * we have to wait for the specified time. Otherwise, |
|---|
| 1169 | | - * the PE's state will be returned immediately. |
|---|
| 1105 | + * NB: Skiboot and pnv_eeh_bridge_reset() also no-op the |
|---|
| 1106 | + * de-assert step. It's like the OPAL reset API was |
|---|
| 1107 | + * poorly designed or something... |
|---|
| 1170 | 1108 | */ |
|---|
| 1171 | | - if (ret != EEH_STATE_UNAVAILABLE) |
|---|
| 1172 | | - return ret; |
|---|
| 1109 | + if (option == EEH_RESET_DEACTIVATE) |
|---|
| 1110 | + return 0; |
|---|
| 1173 | 1111 | |
|---|
| 1174 | | - if (max_wait <= 0) { |
|---|
| 1175 | | - pr_warn("%s: Timeout getting PE#%x's state (%d)\n", |
|---|
| 1176 | | - __func__, pe->addr, max_wait); |
|---|
| 1177 | | - return EEH_STATE_NOT_SUPPORT; |
|---|
| 1178 | | - } |
|---|
| 1179 | | - |
|---|
| 1180 | | - max_wait -= mwait; |
|---|
| 1181 | | - msleep(mwait); |
|---|
| 1112 | + rc = pci_bus_error_reset(bus->self); |
|---|
| 1113 | + if (!rc) |
|---|
| 1114 | + return 0; |
|---|
| 1182 | 1115 | } |
|---|
| 1183 | 1116 | |
|---|
| 1184 | | - return EEH_STATE_NOT_SUPPORT; |
|---|
| 1117 | + /* otherwise, use the generic bridge reset. this might call into FW */ |
|---|
| 1118 | + if (pci_is_root_bus(bus->parent)) |
|---|
| 1119 | + return pnv_eeh_root_reset(hose, option); |
|---|
| 1120 | + return pnv_eeh_bridge_reset(bus->self, option); |
|---|
| 1185 | 1121 | } |
|---|
| 1186 | 1122 | |
|---|
| 1187 | 1123 | /** |
|---|
| .. | .. |
|---|
| 1290 | 1226 | return false; |
|---|
| 1291 | 1227 | } |
|---|
| 1292 | 1228 | |
|---|
| 1293 | | -static int pnv_eeh_read_config(struct pci_dn *pdn, |
|---|
| 1229 | +static int pnv_eeh_read_config(struct eeh_dev *edev, |
|---|
| 1294 | 1230 | int where, int size, u32 *val) |
|---|
| 1295 | 1231 | { |
|---|
| 1232 | + struct pci_dn *pdn = eeh_dev_to_pdn(edev); |
|---|
| 1233 | + |
|---|
| 1296 | 1234 | if (!pdn) |
|---|
| 1297 | 1235 | return PCIBIOS_DEVICE_NOT_FOUND; |
|---|
| 1298 | 1236 | |
|---|
| .. | .. |
|---|
| 1304 | 1242 | return pnv_pci_cfg_read(pdn, where, size, val); |
|---|
| 1305 | 1243 | } |
|---|
| 1306 | 1244 | |
|---|
| 1307 | | -static int pnv_eeh_write_config(struct pci_dn *pdn, |
|---|
| 1245 | +static int pnv_eeh_write_config(struct eeh_dev *edev, |
|---|
| 1308 | 1246 | int where, int size, u32 val) |
|---|
| 1309 | 1247 | { |
|---|
| 1248 | + struct pci_dn *pdn = eeh_dev_to_pdn(edev); |
|---|
| 1249 | + |
|---|
| 1310 | 1250 | if (!pdn) |
|---|
| 1311 | 1251 | return PCIBIOS_DEVICE_NOT_FOUND; |
|---|
| 1312 | 1252 | |
|---|
| .. | .. |
|---|
| 1418 | 1358 | } |
|---|
| 1419 | 1359 | |
|---|
| 1420 | 1360 | /* Find the PE according to PE# */ |
|---|
| 1421 | | - dev_pe = eeh_pe_get(hose, pe_no, 0); |
|---|
| 1361 | + dev_pe = eeh_pe_get(hose, pe_no); |
|---|
| 1422 | 1362 | if (!dev_pe) |
|---|
| 1423 | 1363 | return -EEXIST; |
|---|
| 1424 | 1364 | |
|---|
| .. | .. |
|---|
| 1611 | 1551 | if ((ret == EEH_NEXT_ERR_FROZEN_PE || |
|---|
| 1612 | 1552 | ret == EEH_NEXT_ERR_FENCED_PHB) && |
|---|
| 1613 | 1553 | !((*pe)->state & EEH_PE_ISOLATED)) { |
|---|
| 1614 | | - eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); |
|---|
| 1554 | + eeh_pe_mark_isolated(*pe); |
|---|
| 1615 | 1555 | pnv_eeh_get_phb_diag(*pe); |
|---|
| 1616 | 1556 | |
|---|
| 1617 | 1557 | if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) |
|---|
| .. | .. |
|---|
| 1640 | 1580 | } |
|---|
| 1641 | 1581 | |
|---|
| 1642 | 1582 | /* We possibly migrate to another PE */ |
|---|
| 1643 | | - eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); |
|---|
| 1583 | + eeh_pe_mark_isolated(*pe); |
|---|
| 1644 | 1584 | } |
|---|
| 1645 | 1585 | |
|---|
| 1646 | 1586 | /* |
|---|
| .. | .. |
|---|
| 1660 | 1600 | return ret; |
|---|
| 1661 | 1601 | } |
|---|
| 1662 | 1602 | |
|---|
| 1663 | | -static int pnv_eeh_restore_config(struct pci_dn *pdn) |
|---|
| 1603 | +static int pnv_eeh_restore_config(struct eeh_dev *edev) |
|---|
| 1664 | 1604 | { |
|---|
| 1665 | | - struct eeh_dev *edev = pdn_to_eeh_dev(pdn); |
|---|
| 1666 | 1605 | struct pnv_phb *phb; |
|---|
| 1667 | 1606 | s64 ret = 0; |
|---|
| 1668 | | - int config_addr = (pdn->busno << 8) | (pdn->devfn); |
|---|
| 1669 | 1607 | |
|---|
| 1670 | 1608 | if (!edev) |
|---|
| 1671 | 1609 | return -EEXIST; |
|---|
| 1672 | 1610 | |
|---|
| 1673 | | - /* |
|---|
| 1674 | | - * We have to restore the PCI config space after reset since the |
|---|
| 1675 | | - * firmware can't see SRIOV VFs. |
|---|
| 1676 | | - * |
|---|
| 1677 | | - * FIXME: The MPS, error routing rules, timeout setting are worthy |
|---|
| 1678 | | - * to be exported by firmware in extendible way. |
|---|
| 1679 | | - */ |
|---|
| 1680 | | - if (edev->physfn) { |
|---|
| 1681 | | - ret = eeh_restore_vf_config(pdn); |
|---|
| 1682 | | - } else { |
|---|
| 1683 | | - phb = pdn->phb->private_data; |
|---|
| 1684 | | - ret = opal_pci_reinit(phb->opal_id, |
|---|
| 1685 | | - OPAL_REINIT_PCI_DEV, config_addr); |
|---|
| 1686 | | - } |
|---|
| 1611 | + if (edev->physfn) |
|---|
| 1612 | + return 0; |
|---|
| 1613 | + |
|---|
| 1614 | + phb = edev->controller->private_data; |
|---|
| 1615 | + ret = opal_pci_reinit(phb->opal_id, |
|---|
| 1616 | + OPAL_REINIT_PCI_DEV, edev->bdfn); |
|---|
| 1687 | 1617 | |
|---|
| 1688 | 1618 | if (ret) { |
|---|
| 1689 | 1619 | pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n", |
|---|
| 1690 | | - __func__, config_addr, ret); |
|---|
| 1620 | + __func__, edev->bdfn, ret); |
|---|
| 1691 | 1621 | return -EIO; |
|---|
| 1692 | 1622 | } |
|---|
| 1693 | 1623 | |
|---|
| .. | .. |
|---|
| 1696 | 1626 | |
|---|
| 1697 | 1627 | static struct eeh_ops pnv_eeh_ops = { |
|---|
| 1698 | 1628 | .name = "powernv", |
|---|
| 1699 | | - .init = pnv_eeh_init, |
|---|
| 1700 | 1629 | .probe = pnv_eeh_probe, |
|---|
| 1701 | 1630 | .set_option = pnv_eeh_set_option, |
|---|
| 1702 | | - .get_pe_addr = pnv_eeh_get_pe_addr, |
|---|
| 1703 | 1631 | .get_state = pnv_eeh_get_state, |
|---|
| 1704 | 1632 | .reset = pnv_eeh_reset, |
|---|
| 1705 | | - .wait_state = pnv_eeh_wait_state, |
|---|
| 1706 | 1633 | .get_log = pnv_eeh_get_log, |
|---|
| 1707 | 1634 | .configure_bridge = pnv_eeh_configure_bridge, |
|---|
| 1708 | 1635 | .err_inject = pnv_eeh_err_inject, |
|---|
| .. | .. |
|---|
| 1739 | 1666 | */ |
|---|
| 1740 | 1667 | static int __init eeh_powernv_init(void) |
|---|
| 1741 | 1668 | { |
|---|
| 1669 | + int max_diag_size = PNV_PCI_DIAG_BUF_SIZE; |
|---|
| 1670 | + struct pci_controller *hose; |
|---|
| 1671 | + struct pnv_phb *phb; |
|---|
| 1742 | 1672 | int ret = -EINVAL; |
|---|
| 1743 | 1673 | |
|---|
| 1744 | | - ret = eeh_ops_register(&pnv_eeh_ops); |
|---|
| 1674 | + if (!firmware_has_feature(FW_FEATURE_OPAL)) { |
|---|
| 1675 | + pr_warn("%s: OPAL is required !\n", __func__); |
|---|
| 1676 | + return -EINVAL; |
|---|
| 1677 | + } |
|---|
| 1678 | + |
|---|
| 1679 | + /* Set probe mode */ |
|---|
| 1680 | + eeh_add_flag(EEH_PROBE_MODE_DEV); |
|---|
| 1681 | + |
|---|
| 1682 | + /* |
|---|
| 1683 | + * P7IOC blocks PCI config access to frozen PE, but PHB3 |
|---|
| 1684 | + * doesn't do that. So we have to selectively enable I/O |
|---|
| 1685 | + * prior to collecting error log. |
|---|
| 1686 | + */ |
|---|
| 1687 | + list_for_each_entry(hose, &hose_list, list_node) { |
|---|
| 1688 | + phb = hose->private_data; |
|---|
| 1689 | + |
|---|
| 1690 | + if (phb->model == PNV_PHB_MODEL_P7IOC) |
|---|
| 1691 | + eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); |
|---|
| 1692 | + |
|---|
| 1693 | + if (phb->diag_data_size > max_diag_size) |
|---|
| 1694 | + max_diag_size = phb->diag_data_size; |
|---|
| 1695 | + |
|---|
| 1696 | + break; |
|---|
| 1697 | + } |
|---|
| 1698 | + |
|---|
| 1699 | + /* |
|---|
| 1700 | + * eeh_init() allocates the eeh_pe and its aux data buf so the |
|---|
| 1701 | + * size needs to be set before calling eeh_init(). |
|---|
| 1702 | + */ |
|---|
| 1703 | + eeh_set_pe_aux_size(max_diag_size); |
|---|
| 1704 | + ppc_md.pcibios_bus_add_device = pnv_pcibios_bus_add_device; |
|---|
| 1705 | + |
|---|
| 1706 | + ret = eeh_init(&pnv_eeh_ops); |
|---|
| 1745 | 1707 | if (!ret) |
|---|
| 1746 | 1708 | pr_info("EEH: PowerNV platform initialized\n"); |
|---|
| 1747 | 1709 | else |
|---|
| .. | .. |
|---|
| 1749 | 1711 | |
|---|
| 1750 | 1712 | return ret; |
|---|
| 1751 | 1713 | } |
|---|
| 1752 | | -machine_early_initcall(powernv, eeh_powernv_init); |
|---|
| 1714 | +machine_arch_initcall(powernv, eeh_powernv_init); |
|---|