diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/cpqphp_pci.c | 18 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_core.c | 7 | ||||
-rw-r--r-- | drivers/pci/pci.h | 20 | ||||
-rw-r--r-- | drivers/pci/pcie/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 5 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 71 | ||||
-rw-r--r-- | drivers/pci/pcie/pcie-dpc.c | 251 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/probe.c | 33 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 3 | ||||
-rw-r--r-- | drivers/pci/syscall.c | 4 | ||||
-rw-r--r-- | drivers/pci/xen-pcifront.c | 3 |
12 files changed, 236 insertions, 185 deletions
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index e220d49307bd..8897a7775b8c 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -89,7 +89,9 @@ int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func) pci_lock_rescan_remove(); if (func->pci_dev == NULL) - func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_domain_bus_and_slot(0, func->bus, + PCI_DEVFN(func->device, + func->function)); /* No pci device, we need to create it then */ if (func->pci_dev == NULL) { @@ -99,7 +101,9 @@ int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func) if (num) pci_bus_add_devices(ctrl->pci_dev->bus); - func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_domain_bus_and_slot(0, func->bus, + PCI_DEVFN(func->device, + func->function)); if (func->pci_dev == NULL) { dbg("ERROR: pci_dev still null\n"); goto out; @@ -129,7 +133,10 @@ int cpqhp_unconfigure_device(struct pci_func *func) pci_lock_rescan_remove(); for (j = 0; j < 8 ; j++) { - struct pci_dev *temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); + struct pci_dev *temp = pci_get_domain_bus_and_slot(0, + func->bus, + PCI_DEVFN(func->device, + j)); if (temp) { pci_dev_put(temp); pci_stop_and_remove_bus_device(temp); @@ -319,6 +326,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) int cloop = 0; int stop_it; int index; + u16 devfn; /* Decide which slots are supported */ @@ -416,7 +424,9 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) new_slot->switch_save = 0x10; /* In case of unsupported board */ new_slot->status = DevError; - new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + devfn = (new_slot->device << 3) | new_slot->function; + new_slot->pci_dev = pci_get_domain_bus_and_slot(0, + new_slot->bus, devfn); for (cloop = 0; cloop < 0x20; cloop++) { rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) &(new_slot->config_space[cloop])); diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 73cf84645c82..92dd88296817 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -707,7 +707,8 @@ static void ibm_unconfigure_device(struct pci_func *func) pci_lock_rescan_remove(); for (j = 0; j < 0x08; j++) { - temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); + temp = pci_get_domain_bus_and_slot(0, func->busno, + (func->device << 3) | j); if (temp) { pci_stop_and_remove_bus_device(temp); pci_dev_put(temp); @@ -780,7 +781,7 @@ static int ibm_configure_device(struct pci_func *func) if (!(bus_structure_fixup(func->busno))) flag = 1; if (func->dev == NULL) - func->dev = pci_get_bus_and_slot(func->busno, + func->dev = pci_get_domain_bus_and_slot(0, func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { @@ -793,7 +794,7 @@ static int ibm_configure_device(struct pci_func *func) if (num) pci_bus_add_devices(bus); - func->dev = pci_get_bus_and_slot(func->busno, + func->dev = pci_get_domain_bus_and_slot(0, func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { err("ERROR... : pci_dev still NULL\n"); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index f6b58b32a67c..e90009fff1a9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -342,6 +342,26 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, void pci_enable_acs(struct pci_dev *dev); +#ifdef CONFIG_PCIEASPM +void pcie_aspm_init_link_state(struct pci_dev *pdev); +void pcie_aspm_exit_link_state(struct pci_dev *pdev); +void pcie_aspm_pm_state_change(struct pci_dev *pdev); +void pcie_aspm_powersave_config_link(struct pci_dev *pdev); +#else +static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { } +static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { } +static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { } +static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { } +#endif + +#ifdef CONFIG_PCIEASPM_DEBUG +void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev); +void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev); +#else +static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { } +static inline void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { } +#endif + #ifdef CONFIG_PCIE_PTM void pci_ptm_init(struct pci_dev *dev); #else diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index ac53edbc9613..d658dfa53b87 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -92,7 +92,7 @@ config PCIE_PME config PCIE_DPC bool "PCIe Downstream Port Containment support" - depends on PCIEPORTBUS + depends on PCIEPORTBUS && PCIEAER default n help This enables PCI Express Downstream Port Containment (DPC) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 744805232155..92ec13a09a2a 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -633,7 +633,8 @@ static void aer_recover_work_func(struct work_struct *work) continue; } cper_print_aer(pdev, entry.severity, entry.regs); - do_recovery(pdev, entry.severity); + if (entry.severity != AER_CORRECTABLE) + do_recovery(pdev, entry.severity); pci_dev_put(pdev); } } @@ -660,7 +661,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) /* The device might not support AER */ if (!pos) - return 1; + return 0; if (info->severity == AER_CORRECTABLE) { pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 9783e10da3a9..3b9b4d50cd98 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -43,18 +43,6 @@ #define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \ ASPM_STATE_L1SS) -/* - * When L1 substates are enabled, the LTR L1.2 threshold is a timing parameter - * that decides whether L1.1 or L1.2 is entered (Refer PCIe spec for details). - * Not sure is there is a way to "calculate" this on the fly, but maybe we - * could turn it into a parameter in future. This value has been taken from - * the following files from Intel's coreboot (which is the only code I found - * to have used this): - * https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html - * https://review.coreboot.org/#/c/8832/ - */ -#define LTR_L1_2_THRESHOLD_BITS ((1 << 21) | (1 << 23) | (1 << 30)) - struct aspm_latency { u32 l0s; /* L0s latency (nsec) */ u32 l1; /* L1 latency (nsec) */ @@ -333,6 +321,32 @@ static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val) return 0; } +static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value) +{ + u64 threshold_ns = threshold_us * 1000; + + /* See PCIe r3.1, sec 7.33.3 and sec 6.18 */ + if (threshold_ns < 32) { + *scale = 0; + *value = threshold_ns; + } else if (threshold_ns < 1024) { + *scale = 1; + *value = threshold_ns >> 5; + } else if (threshold_ns < 32768) { + *scale = 2; + *value = threshold_ns >> 10; + } else if (threshold_ns < 1048576) { + *scale = 3; + *value = threshold_ns >> 15; + } else if (threshold_ns < 33554432) { + *scale = 4; + *value = threshold_ns >> 20; + } else { + *scale = 5; + *value = threshold_ns >> 25; + } +} + struct aspm_register_info { u32 support:2; u32 enabled:2; @@ -443,6 +457,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, struct aspm_register_info *dwreg) { u32 val1, val2, scale1, scale2; + u32 t_common_mode, t_power_on, l1_2_threshold, scale, value; link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr; link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr; @@ -454,16 +469,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, /* Choose the greater of the two Port Common_Mode_Restore_Times */ val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8; val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8; - if (val1 > val2) - link->l1ss.ctl1 |= val1 << 8; - else - link->l1ss.ctl1 |= val2 << 8; - - /* - * We currently use LTR L1.2 threshold to be fixed constant picked from - * Intel's coreboot. - */ - link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS; + t_common_mode = max(val1, val2); /* Choose the greater of the two Port T_POWER_ON times */ val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19; @@ -472,10 +478,27 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16; if (calc_l1ss_pwron(link->pdev, scale1, val1) > - calc_l1ss_pwron(link->downstream, scale2, val2)) + calc_l1ss_pwron(link->downstream, scale2, val2)) { link->l1ss.ctl2 |= scale1 | (val1 << 3); - else + t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1); + } else { link->l1ss.ctl2 |= scale2 | (val2 << 3); + t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2); + } + + /* + * Set LTR_L1.2_THRESHOLD to the time required to transition the + * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if + * downstream devices report (via LTR) that they can tolerate at + * least that much latency. + * + * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and + * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at + * least 4us. + */ + l1_2_threshold = 2 + 4 + t_common_mode + t_power_on; + encode_l12_threshold(l1_2_threshold, &scale, &value); + link->l1ss.ctl1 |= t_common_mode << 8 | scale << 29 | value << 16; } static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c index 2d976a623ddc..7eb9bc7d4bfd 100644 --- a/drivers/pci/pcie/pcie-dpc.c +++ b/drivers/pci/pcie/pcie-dpc.c @@ -15,34 +15,15 @@ #include <linux/pci.h> #include <linux/pcieport_if.h> #include "../pci.h" - -struct rp_pio_header_log_regs { - u32 dw0; - u32 dw1; - u32 dw2; - u32 dw3; -}; - -struct dpc_rp_pio_regs { - u32 status; - u32 mask; - u32 severity; - u32 syserror; - u32 exception; - - struct rp_pio_header_log_regs header_log; - u32 impspec_log; - u32 tlp_prefix_log[4]; - u32 log_size; - u16 first_error; -}; +#include "aer/aerdrv.h" struct dpc_dev { struct pcie_device *dev; struct work_struct work; - int cap_pos; - bool rp; + u16 cap_pos; + bool rp_extensions; u32 rp_pio_status; + u8 rp_log_size; }; static const char * const rp_pio_error_string[] = { @@ -72,13 +53,13 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc) unsigned long timeout = jiffies + HZ; struct pci_dev *pdev = dpc->dev->port; struct device *dev = &dpc->dev->device; - u16 status; + u16 cap = dpc->cap_pos, status; - pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); + pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); while (status & PCI_EXP_DPC_RP_BUSY && !time_after(jiffies, timeout)) { msleep(10); - pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); + pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); } if (status & PCI_EXP_DPC_RP_BUSY) { dev_warn(dev, "DPC root port still busy\n"); @@ -104,11 +85,12 @@ static void dpc_wait_link_inactive(struct dpc_dev *dpc) dev_warn(dev, "Link state not disabled for DPC event\n"); } -static void interrupt_event_handler(struct work_struct *work) +static void dpc_work(struct work_struct *work) { struct dpc_dev *dpc = container_of(work, struct dpc_dev, work); struct pci_dev *dev, *temp, *pdev = dpc->dev->port; struct pci_bus *parent = pdev->subordinate; + u16 cap = dpc->cap_pos, ctl; pci_lock_rescan_remove(); list_for_each_entry_safe_reverse(dev, temp, &parent->devices, @@ -124,159 +106,127 @@ static void interrupt_event_handler(struct work_struct *work) pci_unlock_rescan_remove(); dpc_wait_link_inactive(dpc); - if (dpc->rp && dpc_wait_rp_inactive(dpc)) + if (dpc->rp_extensions && dpc_wait_rp_inactive(dpc)) return; - if (dpc->rp && dpc->rp_pio_status) { - pci_write_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS, - dpc->rp_pio_status); + if (dpc->rp_extensions && dpc->rp_pio_status) { + pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, + dpc->rp_pio_status); dpc->rp_pio_status = 0; } - pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, + pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT); -} -static void dpc_rp_pio_print_tlp_header(struct device *dev, - struct rp_pio_header_log_regs *t) -{ - dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n", - t->dw0, t->dw1, t->dw2, t->dw3); + pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl); + pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL, + ctl | PCI_EXP_DPC_CTL_INT_EN); } -static void dpc_rp_pio_print_error(struct dpc_dev *dpc, - struct dpc_rp_pio_regs *rp_pio) +static void dpc_process_rp_pio_error(struct dpc_dev *dpc) { struct device *dev = &dpc->dev->device; + struct pci_dev *pdev = dpc->dev->port; + u16 cap = dpc->cap_pos, dpc_status, first_error; + u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix; int i; - u32 status; + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_MASK, &mask); dev_err(dev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n", - rp_pio->status, rp_pio->mask); + status, mask); + + dpc->rp_pio_status = status; + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SEVERITY, &sev); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SYSERROR, &syserr); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_EXCEPTION, &exc); dev_err(dev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n", - rp_pio->severity, rp_pio->syserror, rp_pio->exception); + sev, syserr, exc); - status = (rp_pio->status & ~rp_pio->mask); + /* Get First Error Pointer */ + pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &dpc_status); + first_error = (dpc_status & 0x1f00) >> 8; + status &= ~mask; for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) { - if (!(status & (1 << i))) - continue; - - dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i], - rp_pio->first_error == i ? " (First)" : ""); + if (status & (1 << i)) + dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i], + first_error == i ? " (First)" : ""); } - dpc_rp_pio_print_tlp_header(dev, &rp_pio->header_log); - if (rp_pio->log_size == 4) + if (dpc->rp_log_size < 4) return; - dev_err(dev, "RP PIO ImpSpec Log %#010x\n", rp_pio->impspec_log); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG, + &dw0); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4, + &dw1); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8, + &dw2); + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12, + &dw3); + dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n", + dw0, dw1, dw2, dw3); - for (i = 0; i < rp_pio->log_size - 5; i++) - dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, - rp_pio->tlp_prefix_log[i]); + if (dpc->rp_log_size < 5) + return; + pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log); + dev_err(dev, "RP PIO ImpSpec Log %#010x\n", log); + + for (i = 0; i < dpc->rp_log_size - 5; i++) { + pci_read_config_dword(pdev, + cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix); + dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix); + } } -static void dpc_rp_pio_get_info(struct dpc_dev *dpc, - struct dpc_rp_pio_regs *rp_pio) +static irqreturn_t dpc_irq(int irq, void *context) { + struct dpc_dev *dpc = (struct dpc_dev *)context; struct pci_dev *pdev = dpc->dev->port; struct device *dev = &dpc->dev->device; - int i; - u16 cap; - u16 status; - - pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS, - &rp_pio->status); - pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_MASK, - &rp_pio->mask); - - pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_SEVERITY, - &rp_pio->severity); - pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_SYSERROR, - &rp_pio->syserror); - pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_EXCEPTION, - &rp_pio->exception); + u16 cap = dpc->cap_pos, ctl, status, source, reason, ext_reason; - /* Get First Error Pointer */ - pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); - rp_pio->first_error = (status & 0x1f00) >> 8; + pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl); - pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); - rp_pio->log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; - if (rp_pio->log_size < 4 || rp_pio->log_size > 9) { - dev_err(dev, "RP PIO log size %u is invalid\n", - rp_pio->log_size); - return; - } - - pci_read_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG, - &rp_pio->header_log.dw0); - pci_read_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4, - &rp_pio->header_log.dw1); - pci_read_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8, - &rp_pio->header_log.dw2); - pci_read_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12, - &rp_pio->header_log.dw3); - if (rp_pio->log_size == 4) - return; - - pci_read_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, - &rp_pio->impspec_log); - for (i = 0; i < rp_pio->log_size - 5; i++) - pci_read_config_dword(pdev, - dpc->cap_pos + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, - &rp_pio->tlp_prefix_log[i]); -} + if (!(ctl & PCI_EXP_DPC_CTL_INT_EN) || ctl == (u16)(~0)) + return IRQ_NONE; -static void dpc_process_rp_pio_error(struct dpc_dev *dpc) -{ - struct dpc_rp_pio_regs rp_pio_regs; + pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); - dpc_rp_pio_get_info(dpc, &rp_pio_regs); - dpc_rp_pio_print_error(dpc, &rp_pio_regs); + if (!(status & PCI_EXP_DPC_STATUS_INTERRUPT)) + return IRQ_NONE; - dpc->rp_pio_status = rp_pio_regs.status; -} + if (!(status & PCI_EXP_DPC_STATUS_TRIGGER)) { + pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, + PCI_EXP_DPC_STATUS_INTERRUPT); + return IRQ_HANDLED; + } -static irqreturn_t dpc_irq(int irq, void *context) -{ - struct dpc_dev *dpc = (struct dpc_dev *)context; - struct pci_dev *pdev = dpc->dev->port; - struct device *dev = &dpc->dev->device; - u16 status, source; + pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL, + ctl & ~PCI_EXP_DPC_CTL_INT_EN); - pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); - pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_SOURCE_ID, + pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &source); - if (!status || status == (u16)(~0)) - return IRQ_NONE; dev_info(dev, "DPC containment event, status:%#06x source:%#06x\n", status, source); - if (status & PCI_EXP_DPC_STATUS_TRIGGER) { - u16 reason = (status >> 1) & 0x3; - u16 ext_reason = (status >> 5) & 0x3; - - dev_warn(dev, "DPC %s detected, remove downstream devices\n", - (reason == 0) ? "unmasked uncorrectable error" : - (reason == 1) ? "ERR_NONFATAL" : - (reason == 2) ? "ERR_FATAL" : - (ext_reason == 0) ? "RP PIO error" : - (ext_reason == 1) ? "software trigger" : - "reserved error"); - /* show RP PIO error detail information */ - if (reason == 3 && ext_reason == 0) - dpc_process_rp_pio_error(dpc); - - schedule_work(&dpc->work); - } + reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1; + ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5; + + dev_warn(dev, "DPC %s detected, remove downstream devices\n", + (reason == 0) ? "unmasked uncorrectable error" : + (reason == 1) ? "ERR_NONFATAL" : + (reason == 2) ? "ERR_FATAL" : + (ext_reason == 0) ? "RP PIO error" : + (ext_reason == 1) ? "software trigger" : + "reserved error"); + /* show RP PIO error detail information */ + if (dpc->rp_extensions && reason == 3 && ext_reason == 0) + dpc_process_rp_pio_error(dpc); + + schedule_work(&dpc->work); + return IRQ_HANDLED; } @@ -289,13 +239,16 @@ static int dpc_probe(struct pcie_device *dev) int status; u16 ctl, cap; + if (pcie_aer_get_firmware_first(pdev)) + return -ENOTSUPP; + dpc = devm_kzalloc(device, sizeof(*dpc), GFP_KERNEL); if (!dpc) return -ENOMEM; dpc->cap_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC); dpc->dev = dev; - INIT_WORK(&dpc->work, interrupt_event_handler); + INIT_WORK(&dpc->work, dpc_work); set_service_data(dev, dpc); status = devm_request_irq(device, dev->irq, dpc_irq, IRQF_SHARED, @@ -309,15 +262,23 @@ static int dpc_probe(struct pcie_device *dev) pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); - dpc->rp = (cap & PCI_EXP_DPC_CAP_RP_EXT); + dpc->rp_extensions = (cap & PCI_EXP_DPC_CAP_RP_EXT); + if (dpc->rp_extensions) { + dpc->rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; + if (dpc->rp_log_size < 4 || dpc->rp_log_size > 9) { + dev_err(device, "RP PIO log size %u is invalid\n", + dpc->rp_log_size); + dpc->rp_log_size = 0; + } + } ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN; pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", - cap & 0xf, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), + cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP), - FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf, + FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size, FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); return status; } diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index a59210350c44..ef3bad4ad010 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -216,9 +216,9 @@ static int get_port_device_capability(struct pci_dev *dev) return 0; cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP - | PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_DPC; + | PCIE_PORT_SERVICE_VC; if (pci_aer_available()) - cap_mask |= PCIE_PORT_SERVICE_AER; + cap_mask |= PCIE_PORT_SERVICE_AER | PCIE_PORT_SERVICE_DPC; if (pcie_ports_auto) pcie_port_platform_notify(dev, &cap_mask); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 14e0ea1ff38b..3761b1303529 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1875,6 +1875,38 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev) } } +static void pci_configure_ltr(struct pci_dev *dev) +{ +#ifdef CONFIG_PCIEASPM + u32 cap; + struct pci_dev *bridge; + + if (!pci_is_pcie(dev)) + return; + + pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap); + if (!(cap & PCI_EXP_DEVCAP2_LTR)) + return; + + /* + * Software must not enable LTR in an Endpoint unless the Root + * Complex and all intermediate Switches indicate support for LTR. + * PCIe r3.1, sec 6.18. + */ + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) + dev->ltr_path = 1; + else { + bridge = pci_upstream_bridge(dev); + if (bridge && bridge->ltr_path) + dev->ltr_path = 1; + } + + if (dev->ltr_path) + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_LTR_EN); +#endif +} + static void pci_configure_device(struct pci_dev *dev) { struct hotplug_params hpp; @@ -1883,6 +1915,7 @@ static void pci_configure_device(struct pci_dev *dev) pci_configure_mps(dev); pci_configure_extended_tags(dev, NULL); pci_configure_relaxed_ordering(dev); + pci_configure_ltr(dev); memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 10684b17d0bd..24e9a148e734 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2699,7 +2699,8 @@ static void __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) * HT MSI mapping should be disabled on devices that are below * a non-Hypertransport host bridge. Locate the host bridge... */ - host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); + host_bridge = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), 0, + PCI_DEVFN(0, 0)); if (host_bridge == NULL) { dev_warn(&dev->dev, "nv_msi_ht_cap_quirk didn't locate host bridge\n"); return; diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index 83efa001c2e7..e725f99b5479 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -28,7 +28,7 @@ SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn, return -EPERM; err = -ENODEV; - dev = pci_get_bus_and_slot(bus, dfn); + dev = pci_get_domain_bus_and_slot(0, bus, dfn); if (!dev) goto error; @@ -96,7 +96,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - dev = pci_get_bus_and_slot(bus, dfn); + dev = pci_get_domain_bus_and_slot(0, bus, dfn); if (!dev) return -ENODEV; diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 8fc2e9532575..94b25b552254 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -595,6 +595,7 @@ static pci_ers_result_t pcifront_common_process(int cmd, struct pci_driver *pdrv; int bus = pdev->sh_info->aer_op.bus; int devfn = pdev->sh_info->aer_op.devfn; + int domain = pdev->sh_info->aer_op.domain; struct pci_dev *pcidev; int flag = 0; @@ -603,7 +604,7 @@ static pci_ers_result_t pcifront_common_process(int cmd, cmd, bus, devfn); result = PCI_ERS_RESULT_NONE; - pcidev = pci_get_bus_and_slot(bus, devfn); + pcidev = pci_get_domain_bus_and_slot(domain, bus, devfn); if (!pcidev || !pcidev->driver) { dev_err(&pdev->xdev->dev, "device or AER driver is NULL\n"); pci_dev_put(pcidev); |