.. | .. |
---|
| 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); |
---|