Merge branch 'pci/host-designware' into next
* pci/host-designware:
PCI: dwc: Constify dw_pcie_host_ops structures
PCI: host: Mark PCIe/PCI (MSI) cascade ISR as IRQF_NO_THREAD
diff --git a/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_pci.h b/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_pci.h
index 8a7ecb4..bf9dd9e 100644
--- a/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_pci.h
+++ b/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_pci.h
@@ -80,7 +80,6 @@
#define PCI_BAR3_REG 0x1c
#define PCI_BAR4_REG 0x20
#define PCI_BAR5_REG 0x24
-#define PCI_BAR_COUNT 6
#define PCI_BAR_RANGE_MASK 0xFFFFFFFF
/* CARDBUS CIS POINTER */
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 1000c1b..52f551e 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -39,7 +39,6 @@
unsigned long io_offset;
unsigned long io_map_base;
struct resource *busn_resource;
- unsigned long busn_offset;
#ifndef CONFIG_PCI_DOMAINS_GENERIC
unsigned int index;
diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c
index 3a84f6c..174575a 100644
--- a/arch/mips/pci/pci-legacy.c
+++ b/arch/mips/pci/pci-legacy.c
@@ -86,8 +86,7 @@
hose->mem_resource, hose->mem_offset);
pci_add_resource_offset(&resources,
hose->io_resource, hose->io_offset);
- pci_add_resource_offset(&resources,
- hose->busn_resource, hose->busn_offset);
+ pci_add_resource(&resources, hose->busn_resource);
bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
&resources);
hose->bus = bus;
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 190e718..1f9f2ee 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -24,7 +24,6 @@
unsigned int pci_early_dump_regs;
static int pci_bf_sort;
-static int smbios_type_b1_flag;
int pci_routeirq;
int noioapicquirk;
#ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS
@@ -197,34 +196,18 @@
static void __init read_dmi_type_b1(const struct dmi_header *dm,
void *private_data)
{
- u8 *d = (u8 *)dm + 4;
+ u8 *data = (u8 *)dm + 4;
if (dm->type != 0xB1)
return;
- switch (((*(u32 *)d) >> 9) & 0x03) {
- case 0x00:
- printk(KERN_INFO "dmi type 0xB1 record - unknown flag\n");
- break;
- case 0x01: /* set pci=bfsort */
- smbios_type_b1_flag = 1;
- break;
- case 0x02: /* do not set pci=bfsort */
- smbios_type_b1_flag = 2;
- break;
- default:
- break;
- }
+ if ((((*(u32 *)data) >> 9) & 0x03) == 0x01)
+ set_bf_sort((const struct dmi_system_id *)private_data);
}
static int __init find_sort_method(const struct dmi_system_id *d)
{
- dmi_walk(read_dmi_type_b1, NULL);
-
- if (smbios_type_b1_flag == 1) {
- set_bf_sort(d);
- return 0;
- }
- return -1;
+ dmi_walk(read_dmi_type_b1, (void *)d);
+ return 0;
}
/*
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 6d52b94..11e4074 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -571,3 +571,50 @@
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar);
+
+/*
+ * Device [1022:7808]
+ * 23. USB Wake on Connect/Disconnect with Low Speed Devices
+ * https://support.amd.com/TechDocs/46837.pdf
+ * Appendix A2
+ * https://support.amd.com/TechDocs/42413.pdf
+ */
+static void pci_fixup_amd_ehci_pme(struct pci_dev *dev)
+{
+ dev_info(&dev->dev, "PME# does not work under D3, disabling it\n");
+ dev->pme_support &= ~((PCI_PM_CAP_PME_D3 | PCI_PM_CAP_PME_D3cold)
+ >> PCI_PM_CAP_PME_SHIFT);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7808, pci_fixup_amd_ehci_pme);
+
+/*
+ * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff]
+ *
+ * Using the [mem 0x7fa00000-0x7fbfffff] region, e.g., by assigning it to
+ * the 00:1c.0 Root Port, causes a conflict with [io 0x1804], which is used
+ * for soft poweroff and suspend-to-RAM.
+ *
+ * As far as we know, this is related to the address space, not to the Root
+ * Port itself. Attaching the quirk to the Root Port is a convenience, but
+ * it could probably also be a standalone DMI quirk.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=103211
+ */
+static void quirk_apple_mbp_poweroff(struct pci_dev *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ if ((!dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,4") &&
+ !dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,5")) ||
+ pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x1c, 0))
+ return;
+
+ res = request_mem_region(0x7fa00000, 0x200000,
+ "MacBook Pro poweroff workaround");
+ if (res)
+ dev_info(dev, "claimed %s %pR\n", res->name, res);
+ else
+ dev_info(dev, "can't work around MacBook Pro poweroff issue\n");
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff);
diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c
index c1bdb9e..7659540 100644
--- a/arch/x86/pci/pcbios.c
+++ b/arch/x86/pci/pcbios.c
@@ -46,7 +46,7 @@
pcibios_enabled = 1;
set_memory_x(PAGE_OFFSET + BIOS_BEGIN, (BIOS_END - BIOS_BEGIN) >> PAGE_SHIFT);
if (__supported_pte_mask & _PAGE_NX)
- printk(KERN_INFO "PCI : PCI BIOS area is rw and x. Use pci=nobios if you want it NX.\n");
+ printk(KERN_INFO "PCI: PCI BIOS area is rw and x. Use pci=nobios if you want it NX.\n");
}
/*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 43ca16b..bbac5d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1152,16 +1152,12 @@
return;
if (state == VGA_SWITCHEROO_ON) {
- unsigned d3_delay = dev->pdev->d3_delay;
-
pr_info("amdgpu: switched on\n");
/* don't suspend or resume card normally */
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
amdgpu_device_resume(dev, true, true);
- dev->pdev->d3_delay = d3_delay;
-
dev->switch_power_state = DRM_SWITCH_POWER_ON;
drm_kms_helper_poll_enable(dev);
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 6ecf427..aecaafb 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -113,7 +113,6 @@
#endif
#define RADEON_PX_QUIRK_DISABLE_PX (1 << 0)
-#define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1)
struct radeon_px_quirk {
u32 chip_vendor;
@@ -136,8 +135,6 @@
* https://bugzilla.kernel.org/show_bug.cgi?id=51381
*/
{ PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
- /* macbook pro 8.2 */
- { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP },
{ 0, 0, 0, 0, 0 },
};
@@ -1241,25 +1238,17 @@
static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
- struct radeon_device *rdev = dev->dev_private;
if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF)
return;
if (state == VGA_SWITCHEROO_ON) {
- unsigned d3_delay = dev->pdev->d3_delay;
-
pr_info("radeon: switched on\n");
/* don't suspend or resume card normally */
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
- if (d3_delay < 20 && (rdev->px_quirk_flags & RADEON_PX_QUIRK_LONG_WAKEUP))
- dev->pdev->d3_delay = 20;
-
radeon_resume_kms(dev, true, true);
- dev->pdev->d3_delay = d3_delay;
-
dev->switch_power_state = DRM_SWITCH_POWER_ON;
drm_kms_helper_poll_enable(dev);
} else {
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
index 3e26d27..6378457 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -2348,30 +2348,19 @@
netif_device_attach(netdev);
}
-/**
- * fm10k_io_reset_notify - called when PCI function is reset
- * @pdev: Pointer to PCI device
- *
- * This callback is called when the PCI function is reset such as from
- * /sys/class/net/<enpX>/device/reset or similar. When prepare is true, it
- * means we should prepare for a function reset. If prepare is false, it means
- * the function reset just occurred.
- */
-static void fm10k_io_reset_notify(struct pci_dev *pdev, bool prepare)
+static void fm10k_io_reset_prepare(struct pci_dev *pdev)
+{
+ /* warn incase we have any active VF devices */
+ if (pci_num_vf(pdev))
+ dev_warn(&pdev->dev,
+ "PCIe FLR may cause issues for any active VF devices\n");
+ fm10k_prepare_suspend(pci_get_drvdata(pdev));
+}
+
+static void fm10k_io_reset_done(struct pci_dev *pdev)
{
struct fm10k_intfc *interface = pci_get_drvdata(pdev);
- int err = 0;
-
- if (prepare) {
- /* warn incase we have any active VF devices */
- if (pci_num_vf(pdev))
- dev_warn(&pdev->dev,
- "PCIe FLR may cause issues for any active VF devices\n");
-
- fm10k_prepare_suspend(interface);
- } else {
- err = fm10k_handle_resume(interface);
- }
+ int err = fm10k_handle_resume(interface);
if (err) {
dev_warn(&pdev->dev,
@@ -2384,7 +2373,8 @@
.error_detected = fm10k_io_error_detected,
.slot_reset = fm10k_io_slot_reset,
.resume = fm10k_io_resume,
- .reset_notify = fm10k_io_reset_notify,
+ .reset_prepare = fm10k_io_reset_prepare,
+ .reset_done = fm10k_io_reset_done,
};
static struct pci_driver fm10k_driver = {
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index ac62bce..279adf1 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -346,7 +346,37 @@
MODULE_DEVICE_TABLE(pci, mwifiex_ids);
-static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
+/*
+ * Cleanup all software without cleaning anything related to PCIe and HW.
+ */
+static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
+{
+ struct pcie_service_card *card = pci_get_drvdata(pdev);
+ struct mwifiex_adapter *adapter = card->adapter;
+
+ if (!adapter) {
+ dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
+ __func__);
+ return;
+ }
+
+ mwifiex_dbg(adapter, INFO,
+ "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Pre-FLR\n",
+ __func__, pdev->vendor, pdev->device, pdev->revision);
+
+ mwifiex_shutdown_sw(adapter);
+ adapter->surprise_removed = true;
+ clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
+ clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
+ mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+}
+
+/*
+ * Kernel stores and restores PCIe function context before and after performing
+ * FLR respectively. Reconfigure the software and firmware including firmware
+ * redownload.
+ */
+static void mwifiex_pcie_reset_done(struct pci_dev *pdev)
{
struct pcie_service_card *card = pci_get_drvdata(pdev);
struct mwifiex_adapter *adapter = card->adapter;
@@ -359,37 +389,20 @@
}
mwifiex_dbg(adapter, INFO,
- "%s: vendor=0x%4.04x device=0x%4.04x rev=%d %s\n",
- __func__, pdev->vendor, pdev->device,
- pdev->revision,
- prepare ? "Pre-FLR" : "Post-FLR");
+ "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Post-FLR\n",
+ __func__, pdev->vendor, pdev->device, pdev->revision);
- if (prepare) {
- /* Kernel would be performing FLR after this notification.
- * Cleanup all software without cleaning anything related to
- * PCIe and HW.
- */
- mwifiex_shutdown_sw(adapter);
- adapter->surprise_removed = true;
- clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
- clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
- } else {
- /* Kernel stores and restores PCIe function context before and
- * after performing FLR respectively. Reconfigure the software
- * and firmware including firmware redownload
- */
- adapter->surprise_removed = false;
- ret = mwifiex_reinit_sw(adapter);
- if (ret) {
- dev_err(&pdev->dev, "reinit failed: %d\n", ret);
- return;
- }
- }
- mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+ adapter->surprise_removed = false;
+ ret = mwifiex_reinit_sw(adapter);
+ if (ret)
+ dev_err(&pdev->dev, "reinit failed: %d\n", ret);
+ else
+ mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
}
-static const struct pci_error_handlers mwifiex_pcie_err_handler[] = {
- { .reset_notify = mwifiex_pcie_reset_notify, },
+static const struct pci_error_handlers mwifiex_pcie_err_handler = {
+ .reset_prepare = mwifiex_pcie_reset_prepare,
+ .reset_done = mwifiex_pcie_reset_done,
};
#ifdef CONFIG_PM_SLEEP
@@ -410,7 +423,7 @@
},
#endif
.shutdown = mwifiex_pcie_shutdown,
- .err_handler = mwifiex_pcie_err_handler,
+ .err_handler = &mwifiex_pcie_err_handler,
};
/*
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index fed8032..9a3d69b 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2145,14 +2145,14 @@
return result;
}
-static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)
+static void nvme_reset_prepare(struct pci_dev *pdev)
{
- struct nvme_dev *dev = pci_get_drvdata(pdev);
+ nvme_dev_disable(pci_get_drvdata(pdev), false);
+}
- if (prepare)
- nvme_dev_disable(dev, false);
- else
- nvme_reset(dev);
+static void nvme_reset_done(struct pci_dev *pdev)
+{
+ nvme_reset(pci_get_drvdata(pdev));
}
static void nvme_shutdown(struct pci_dev *pdev)
@@ -2275,7 +2275,8 @@
.error_detected = nvme_error_detected,
.slot_reset = nvme_slot_reset,
.resume = nvme_error_resume,
- .reset_notify = nvme_reset_notify,
+ .reset_prepare = nvme_reset_prepare,
+ .reset_done = nvme_reset_done,
};
static const struct pci_device_id nvme_id_table[] = {
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index eeb9fb2..ad8ddbb 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -153,23 +153,27 @@
u32 max_requests;
int pos;
+ if (WARN_ON(pdev->pri_enabled))
+ return -EBUSY;
+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return -EINVAL;
- pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
- if ((control & PCI_PRI_CTRL_ENABLE) ||
- !(status & PCI_PRI_STATUS_STOPPED))
+ if (!(status & PCI_PRI_STATUS_STOPPED))
return -EBUSY;
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
reqs = min(max_requests, reqs);
+ pdev->pri_reqs_alloc = reqs;
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
- control |= PCI_PRI_CTRL_ENABLE;
+ control = PCI_PRI_CTRL_ENABLE;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+ pdev->pri_enabled = 1;
+
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_pri);
@@ -185,6 +189,9 @@
u16 control;
int pos;
+ if (WARN_ON(!pdev->pri_enabled))
+ return;
+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return;
@@ -192,10 +199,34 @@
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
control &= ~PCI_PRI_CTRL_ENABLE;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+
+ pdev->pri_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_pri);
/**
+ * pci_restore_pri_state - Restore PRI
+ * @pdev: PCI device structure
+ */
+void pci_restore_pri_state(struct pci_dev *pdev)
+{
+ u16 control = PCI_PRI_CTRL_ENABLE;
+ u32 reqs = pdev->pri_reqs_alloc;
+ int pos;
+
+ if (!pdev->pri_enabled)
+ return;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
+ if (!pos)
+ return;
+
+ pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
+ pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
+}
+EXPORT_SYMBOL_GPL(pci_restore_pri_state);
+
+/**
* pci_reset_pri - Resets device's PRI state
* @pdev: PCI device structure
*
@@ -207,16 +238,14 @@
u16 control;
int pos;
+ if (WARN_ON(pdev->pri_enabled))
+ return -EBUSY;
+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return -EINVAL;
- pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
- if (control & PCI_PRI_CTRL_ENABLE)
- return -EBUSY;
-
- control |= PCI_PRI_CTRL_RESET;
-
+ control = PCI_PRI_CTRL_RESET;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
return 0;
@@ -239,16 +268,14 @@
u16 control, supported;
int pos;
+ if (WARN_ON(pdev->pasid_enabled))
+ return -EBUSY;
+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
return -EINVAL;
- pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
-
- if (control & PCI_PASID_CTRL_ENABLE)
- return -EINVAL;
-
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
/* User wants to enable anything unsupported? */
@@ -256,9 +283,12 @@
return -EINVAL;
control = PCI_PASID_CTRL_ENABLE | features;
+ pdev->pasid_features = features;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
+ pdev->pasid_enabled = 1;
+
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_pasid);
@@ -266,22 +296,47 @@
/**
* pci_disable_pasid - Disable the PASID capability
* @pdev: PCI device structure
- *
*/
void pci_disable_pasid(struct pci_dev *pdev)
{
u16 control = 0;
int pos;
+ if (WARN_ON(!pdev->pasid_enabled))
+ return;
+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
return;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
+
+ pdev->pasid_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_pasid);
/**
+ * pci_restore_pasid_state - Restore PASID capabilities
+ * @pdev: PCI device structure
+ */
+void pci_restore_pasid_state(struct pci_dev *pdev)
+{
+ u16 control;
+ int pos;
+
+ if (!pdev->pasid_enabled)
+ return;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
+ if (!pos)
+ return;
+
+ control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
+ pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
+}
+EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
+
+/**
* pci_pasid_features - Check which PASID features are supported
* @pdev: PCI device structure
*
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index fb48160..7a8968d 100644
--- a/drivers/pci/dwc/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -252,7 +252,34 @@
static int imx6q_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
- return 0;
+ unsigned long pc = instruction_pointer(regs);
+ unsigned long instr = *(unsigned long *)pc;
+ int reg = (instr >> 12) & 15;
+
+ /*
+ * If the instruction being executed was a read,
+ * make it look like it read all-ones.
+ */
+ if ((instr & 0x0c100000) == 0x04100000) {
+ unsigned long val;
+
+ if (instr & 0x00400000)
+ val = 255;
+ else
+ val = -1;
+
+ regs->uregs[reg] = val;
+ regs->ARM_pc += 4;
+ return 0;
+ }
+
+ if ((instr & 0x0e100090) == 0x00100090) {
+ regs->uregs[reg] = -1;
+ regs->ARM_pc += 4;
+ return 0;
+ }
+
+ return 1;
}
static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
@@ -819,8 +846,8 @@
* we can install the handler here without risking it
* accessing some uninitialized driver state.
*/
- hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
- "imprecise external abort");
+ hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0,
+ "external abort on non-linefetch");
return platform_driver_register(&imx6_pcie_driver);
}
diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index c23f146..c09623c 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -6,6 +6,7 @@
config PCI_ENDPOINT
bool "PCI Endpoint Support"
+ depends on HAS_DMA
help
Enable this configuration option to support configurable PCI
endpoint. This should be enabled if the platform has a PCI
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index d9dc736..120485d 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -461,8 +461,6 @@
else
iov->dev = dev;
- mutex_init(&iov->lock);
-
dev->sriov = iov;
dev->is_physfn = 1;
rc = compute_max_vf_buses(dev);
@@ -491,8 +489,6 @@
if (dev != dev->sriov->dev)
pci_dev_put(dev->sriov->dev);
- mutex_destroy(&dev->sriov->lock);
-
kfree(dev->sriov);
dev->sriov = NULL;
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ba44fdf..9e15691 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -1058,7 +1058,7 @@
for (;;) {
if (affd) {
- nvec = irq_calc_affinity_vectors(nvec, affd);
+ nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
if (nvec < minvec)
return -ENOSPC;
}
@@ -1097,7 +1097,7 @@
for (;;) {
if (affd) {
- nvec = irq_calc_affinity_vectors(nvec, affd);
+ nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
if (nvec < minvec)
return -ENOSPC;
}
@@ -1165,16 +1165,6 @@
if (flags & PCI_IRQ_AFFINITY) {
if (!affd)
affd = &msi_default_affd;
-
- if (affd->pre_vectors + affd->post_vectors > min_vecs)
- return -EINVAL;
-
- /*
- * If there aren't any vectors left after applying the pre/post
- * vectors don't bother with assigning affinity.
- */
- if (affd->pre_vectors + affd->post_vectors == min_vecs)
- affd = NULL;
} else {
if (WARN_ON(affd))
affd = NULL;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 11167c6..50f93a3b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -966,6 +966,7 @@
return pci_legacy_resume_early(dev);
pci_update_current_state(pci_dev, PCI_D0);
+ pci_restore_state(pci_dev);
if (drv && drv->pm && drv->pm->thaw_noirq)
error = drv->pm->thaw_noirq(dev);
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index 5135737..1d828a6 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -43,9 +43,11 @@
{
const struct dmi_device *dmi;
struct dmi_dev_onboard *donboard;
+ int domain_nr;
int bus;
int devfn;
+ domain_nr = pci_domain_nr(pdev->bus);
bus = pdev->bus->number;
devfn = pdev->devfn;
@@ -53,8 +55,9 @@
while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD,
NULL, dmi)) != NULL) {
donboard = dmi->device_data;
- if (donboard && donboard->bus == bus &&
- donboard->devfn == devfn) {
+ if (donboard && donboard->segment == domain_nr &&
+ donboard->bus == bus &&
+ donboard->devfn == devfn) {
if (buf) {
if (attribute == SMBIOS_ATTR_INSTANCE_SHOW)
return scnprintf(buf, PAGE_SIZE,
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 31e9961..2f3780b 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -154,6 +154,129 @@
}
static DEVICE_ATTR_RO(resource);
+static ssize_t max_link_speed_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u32 linkcap;
+ int err;
+ const char *speed;
+
+ err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap);
+ if (err)
+ return -EINVAL;
+
+ switch (linkcap & PCI_EXP_LNKCAP_SLS) {
+ case PCI_EXP_LNKCAP_SLS_8_0GB:
+ speed = "8 GT/s";
+ break;
+ case PCI_EXP_LNKCAP_SLS_5_0GB:
+ speed = "5 GT/s";
+ break;
+ case PCI_EXP_LNKCAP_SLS_2_5GB:
+ speed = "2.5 GT/s";
+ break;
+ default:
+ speed = "Unknown speed";
+ }
+
+ return sprintf(buf, "%s\n", speed);
+}
+static DEVICE_ATTR_RO(max_link_speed);
+
+static ssize_t max_link_width_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u32 linkcap;
+ int err;
+
+ err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap);
+ if (err)
+ return -EINVAL;
+
+ return sprintf(buf, "%u\n", (linkcap & PCI_EXP_LNKCAP_MLW) >> 4);
+}
+static DEVICE_ATTR_RO(max_link_width);
+
+static ssize_t current_link_speed_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u16 linkstat;
+ int err;
+ const char *speed;
+
+ err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
+ if (err)
+ return -EINVAL;
+
+ switch (linkstat & PCI_EXP_LNKSTA_CLS) {
+ case PCI_EXP_LNKSTA_CLS_8_0GB:
+ speed = "8 GT/s";
+ break;
+ case PCI_EXP_LNKSTA_CLS_5_0GB:
+ speed = "5 GT/s";
+ break;
+ case PCI_EXP_LNKSTA_CLS_2_5GB:
+ speed = "2.5 GT/s";
+ break;
+ default:
+ speed = "Unknown speed";
+ }
+
+ return sprintf(buf, "%s\n", speed);
+}
+static DEVICE_ATTR_RO(current_link_speed);
+
+static ssize_t current_link_width_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u16 linkstat;
+ int err;
+
+ err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
+ if (err)
+ return -EINVAL;
+
+ return sprintf(buf, "%u\n",
+ (linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT);
+}
+static DEVICE_ATTR_RO(current_link_width);
+
+static ssize_t secondary_bus_number_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u8 sec_bus;
+ int err;
+
+ err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
+ if (err)
+ return -EINVAL;
+
+ return sprintf(buf, "%u\n", sec_bus);
+}
+static DEVICE_ATTR_RO(secondary_bus_number);
+
+static ssize_t subordinate_bus_number_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u8 sub_bus;
+ int err;
+
+ err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
+ if (err)
+ return -EINVAL;
+
+ return sprintf(buf, "%u\n", sub_bus);
+}
+static DEVICE_ATTR_RO(subordinate_bus_number);
+
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -472,7 +595,6 @@
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct pci_sriov *iov = pdev->sriov;
int ret;
u16 num_vfs;
@@ -483,7 +605,7 @@
if (num_vfs > pci_sriov_get_totalvfs(pdev))
return -ERANGE;
- mutex_lock(&iov->dev->sriov->lock);
+ device_lock(&pdev->dev);
if (num_vfs == pdev->sriov->num_VFs)
goto exit;
@@ -518,7 +640,7 @@
num_vfs, ret);
exit:
- mutex_unlock(&iov->dev->sriov->lock);
+ device_unlock(&pdev->dev);
if (ret < 0)
return ret;
@@ -629,12 +751,17 @@
NULL,
};
-static const struct attribute_group pci_dev_group = {
- .attrs = pci_dev_attrs,
+static struct attribute *pci_bridge_attrs[] = {
+ &dev_attr_subordinate_bus_number.attr,
+ &dev_attr_secondary_bus_number.attr,
+ NULL,
};
-const struct attribute_group *pci_dev_groups[] = {
- &pci_dev_group,
+static struct attribute *pcie_dev_attrs[] = {
+ &dev_attr_current_link_speed.attr,
+ &dev_attr_current_link_width.attr,
+ &dev_attr_max_link_width.attr,
+ &dev_attr_max_link_speed.attr,
NULL,
};
@@ -1557,6 +1684,57 @@
return a->mode;
}
+static umode_t pci_bridge_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (pci_is_bridge(pdev))
+ return a->mode;
+
+ return 0;
+}
+
+static umode_t pcie_dev_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (pci_is_pcie(pdev))
+ return a->mode;
+
+ return 0;
+}
+
+static const struct attribute_group pci_dev_group = {
+ .attrs = pci_dev_attrs,
+};
+
+const struct attribute_group *pci_dev_groups[] = {
+ &pci_dev_group,
+ NULL,
+};
+
+static const struct attribute_group pci_bridge_group = {
+ .attrs = pci_bridge_attrs,
+};
+
+const struct attribute_group *pci_bridge_groups[] = {
+ &pci_bridge_group,
+ NULL,
+};
+
+static const struct attribute_group pcie_dev_group = {
+ .attrs = pcie_dev_attrs,
+};
+
+const struct attribute_group *pcie_dev_groups[] = {
+ &pcie_dev_group,
+ NULL,
+};
+
static struct attribute_group pci_dev_hp_attr_group = {
.attrs = pci_dev_hp_attrs,
.is_visible = pci_dev_hp_attrs_are_visible,
@@ -1592,12 +1770,24 @@
.is_visible = pci_dev_attrs_are_visible,
};
+static struct attribute_group pci_bridge_attr_group = {
+ .attrs = pci_bridge_attrs,
+ .is_visible = pci_bridge_attrs_are_visible,
+};
+
+static struct attribute_group pcie_dev_attr_group = {
+ .attrs = pcie_dev_attrs,
+ .is_visible = pcie_dev_attrs_are_visible,
+};
+
static const struct attribute_group *pci_dev_attr_groups[] = {
&pci_dev_attr_group,
&pci_dev_hp_attr_group,
#ifdef CONFIG_PCI_IOV
&sriov_dev_attr_group,
#endif
+ &pci_bridge_attr_group,
+ &pcie_dev_attr_group,
NULL,
};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b01bd5b..34b5fe0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -28,6 +28,7 @@
#include <linux/pm_runtime.h>
#include <linux/pci_hotplug.h>
#include <linux/vmalloc.h>
+#include <linux/pci-ats.h>
#include <asm/setup.h>
#include <asm/dma.h>
#include <linux/aer.h>
@@ -455,7 +456,7 @@
pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
- if (res->start && resource_contains(r, res)) {
+ if (resource_contains(r, res)) {
/*
* If the window is prefetchable but the BAR is
@@ -1173,6 +1174,8 @@
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
+ pci_restore_pasid_state(dev);
+ pci_restore_pri_state(dev);
pci_restore_ats_state(dev);
pci_restore_vc_state(dev);
@@ -1960,12 +1963,13 @@
/**
* pci_target_state - find an appropriate low power state for a given PCI dev
* @dev: PCI device
+ * @wakeup: Whether or not wakeup functionality will be enabled for the device.
*
* Use underlying platform code to find a supported low power state for @dev.
* If the platform can't manage @dev, return the deepest state from which it
* can generate wake events, based on any available PME info.
*/
-static pci_power_t pci_target_state(struct pci_dev *dev)
+static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
{
pci_power_t target_state = PCI_D3hot;
@@ -2002,7 +2006,7 @@
if (dev->current_state == PCI_D3cold)
target_state = PCI_D3cold;
- if (device_may_wakeup(&dev->dev)) {
+ if (wakeup) {
/*
* Find the deepest state from which the device can generate
* wake-up events, make it the target state and enable device
@@ -2028,13 +2032,14 @@
*/
int pci_prepare_to_sleep(struct pci_dev *dev)
{
- pci_power_t target_state = pci_target_state(dev);
+ bool wakeup = device_may_wakeup(&dev->dev);
+ pci_power_t target_state = pci_target_state(dev, wakeup);
int error;
if (target_state == PCI_POWER_ERROR)
return -EIO;
- pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
+ pci_enable_wake(dev, target_state, wakeup);
error = pci_set_power_state(dev, target_state);
@@ -2067,9 +2072,10 @@
*/
int pci_finish_runtime_suspend(struct pci_dev *dev)
{
- pci_power_t target_state = pci_target_state(dev);
+ pci_power_t target_state;
int error;
+ target_state = pci_target_state(dev, device_can_wakeup(&dev->dev));
if (target_state == PCI_POWER_ERROR)
return -EIO;
@@ -2105,8 +2111,8 @@
if (!dev->pme_support)
return false;
- /* PME-capable in principle, but not from the intended sleep state */
- if (!pci_pme_capable(dev, pci_target_state(dev)))
+ /* PME-capable in principle, but not from the target power state */
+ if (!pci_pme_capable(dev, pci_target_state(dev, false)))
return false;
while (bus->parent) {
@@ -2141,10 +2147,12 @@
bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
{
struct device *dev = &pci_dev->dev;
+ bool wakeup = device_may_wakeup(dev);
if (!pm_runtime_suspended(dev)
- || pci_target_state(pci_dev) != pci_dev->current_state
- || platform_pci_need_resume(pci_dev))
+ || pci_target_state(pci_dev, wakeup) != pci_dev->current_state
+ || platform_pci_need_resume(pci_dev)
+ || (pci_dev->dev_flags & PCI_DEV_FLAGS_NEEDS_RESUME))
return false;
/*
@@ -2160,7 +2168,7 @@
spin_lock_irq(&dev->power.lock);
if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold &&
- !device_may_wakeup(dev))
+ !wakeup)
__pci_pme_active(pci_dev, false);
spin_unlock_irq(&dev->power.lock);
@@ -3708,46 +3716,6 @@
}
EXPORT_SYMBOL_GPL(pci_intx);
-/**
- * pci_intx_mask_supported - probe for INTx masking support
- * @dev: the PCI device to operate on
- *
- * Check if the device dev support INTx masking via the config space
- * command word.
- */
-bool pci_intx_mask_supported(struct pci_dev *dev)
-{
- bool mask_supported = false;
- u16 orig, new;
-
- if (dev->broken_intx_masking)
- return false;
-
- pci_cfg_access_lock(dev);
-
- pci_read_config_word(dev, PCI_COMMAND, &orig);
- pci_write_config_word(dev, PCI_COMMAND,
- orig ^ PCI_COMMAND_INTX_DISABLE);
- pci_read_config_word(dev, PCI_COMMAND, &new);
-
- /*
- * There's no way to protect against hardware bugs or detect them
- * reliably, but as long as we know what the value should be, let's
- * go ahead and check it.
- */
- if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) {
- dev_err(&dev->dev, "Command register changed from 0x%x to 0x%x: driver or hardware bug?\n",
- orig, new);
- } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) {
- mask_supported = true;
- pci_write_config_word(dev, PCI_COMMAND, orig);
- }
-
- pci_cfg_access_unlock(dev);
- return mask_supported;
-}
-EXPORT_SYMBOL_GPL(pci_intx_mask_supported);
-
static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
{
struct pci_bus *bus = dev->bus;
@@ -3798,7 +3766,7 @@
* @dev: the PCI device to operate on
*
* Check if the device dev has its INTx line asserted, mask it and
- * return true in that case. False is returned if not interrupt was
+ * return true in that case. False is returned if no interrupt was
* pending.
*/
bool pci_check_and_mask_intx(struct pci_dev *dev)
@@ -4068,40 +4036,6 @@
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
}
-static int __pci_dev_reset(struct pci_dev *dev, int probe)
-{
- int rc;
-
- might_sleep();
-
- rc = pci_dev_specific_reset(dev, probe);
- if (rc != -ENOTTY)
- goto done;
-
- if (pcie_has_flr(dev)) {
- if (!probe)
- pcie_flr(dev);
- rc = 0;
- goto done;
- }
-
- rc = pci_af_flr(dev, probe);
- if (rc != -ENOTTY)
- goto done;
-
- rc = pci_pm_reset(dev, probe);
- if (rc != -ENOTTY)
- goto done;
-
- rc = pci_dev_reset_slot_function(dev, probe);
- if (rc != -ENOTTY)
- goto done;
-
- rc = pci_parent_bus_reset(dev, probe);
-done:
- return rc;
-}
-
static void pci_dev_lock(struct pci_dev *dev)
{
pci_cfg_access_lock(dev);
@@ -4127,26 +4061,18 @@
pci_cfg_access_unlock(dev);
}
-/**
- * pci_reset_notify - notify device driver of reset
- * @dev: device to be notified of reset
- * @prepare: 'true' if device is about to be reset; 'false' if reset attempt
- * completed
- *
- * Must be called prior to device access being disabled and after device
- * access is restored.
- */
-static void pci_reset_notify(struct pci_dev *dev, bool prepare)
+static void pci_dev_save_and_disable(struct pci_dev *dev)
{
const struct pci_error_handlers *err_handler =
dev->driver ? dev->driver->err_handler : NULL;
- if (err_handler && err_handler->reset_notify)
- err_handler->reset_notify(dev, prepare);
-}
-static void pci_dev_save_and_disable(struct pci_dev *dev)
-{
- pci_reset_notify(dev, true);
+ /*
+ * dev->driver->err_handler->reset_prepare() is protected against
+ * races with ->remove() by the device lock, which must be held by
+ * the caller.
+ */
+ if (err_handler && err_handler->reset_prepare)
+ err_handler->reset_prepare(dev);
/*
* Wake-up device prior to save. PM registers default to D0 after
@@ -4168,23 +4094,18 @@
static void pci_dev_restore(struct pci_dev *dev)
{
+ const struct pci_error_handlers *err_handler =
+ dev->driver ? dev->driver->err_handler : NULL;
+
pci_restore_state(dev);
- pci_reset_notify(dev, false);
-}
-static int pci_dev_reset(struct pci_dev *dev, int probe)
-{
- int rc;
-
- if (!probe)
- pci_dev_lock(dev);
-
- rc = __pci_dev_reset(dev, probe);
-
- if (!probe)
- pci_dev_unlock(dev);
-
- return rc;
+ /*
+ * dev->driver->err_handler->reset_done() is protected against
+ * races with ->remove() by the device lock, which must be held by
+ * the caller.
+ */
+ if (err_handler && err_handler->reset_done)
+ err_handler->reset_done(dev);
}
/**
@@ -4206,7 +4127,13 @@
*/
int __pci_reset_function(struct pci_dev *dev)
{
- return pci_dev_reset(dev, 0);
+ int ret;
+
+ pci_dev_lock(dev);
+ ret = __pci_reset_function_locked(dev);
+ pci_dev_unlock(dev);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(__pci_reset_function);
@@ -4231,7 +4158,27 @@
*/
int __pci_reset_function_locked(struct pci_dev *dev)
{
- return __pci_dev_reset(dev, 0);
+ int rc;
+
+ might_sleep();
+
+ rc = pci_dev_specific_reset(dev, 0);
+ if (rc != -ENOTTY)
+ return rc;
+ if (pcie_has_flr(dev)) {
+ pcie_flr(dev);
+ return 0;
+ }
+ rc = pci_af_flr(dev, 0);
+ if (rc != -ENOTTY)
+ return rc;
+ rc = pci_pm_reset(dev, 0);
+ if (rc != -ENOTTY)
+ return rc;
+ rc = pci_dev_reset_slot_function(dev, 0);
+ if (rc != -ENOTTY)
+ return rc;
+ return pci_parent_bus_reset(dev, 0);
}
EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
@@ -4248,7 +4195,26 @@
*/
int pci_probe_reset_function(struct pci_dev *dev)
{
- return pci_dev_reset(dev, 1);
+ int rc;
+
+ might_sleep();
+
+ rc = pci_dev_specific_reset(dev, 1);
+ if (rc != -ENOTTY)
+ return rc;
+ if (pcie_has_flr(dev))
+ return 0;
+ rc = pci_af_flr(dev, 1);
+ if (rc != -ENOTTY)
+ return rc;
+ rc = pci_pm_reset(dev, 1);
+ if (rc != -ENOTTY)
+ return rc;
+ rc = pci_dev_reset_slot_function(dev, 1);
+ if (rc != -ENOTTY)
+ return rc;
+
+ return pci_parent_bus_reset(dev, 1);
}
/**
@@ -4271,15 +4237,17 @@
{
int rc;
- rc = pci_dev_reset(dev, 1);
+ rc = pci_probe_reset_function(dev);
if (rc)
return rc;
+ pci_dev_lock(dev);
pci_dev_save_and_disable(dev);
- rc = pci_dev_reset(dev, 0);
+ rc = __pci_reset_function_locked(dev);
pci_dev_restore(dev);
+ pci_dev_unlock(dev);
return rc;
}
@@ -4295,20 +4263,18 @@
{
int rc;
- rc = pci_dev_reset(dev, 1);
+ rc = pci_probe_reset_function(dev);
if (rc)
return rc;
- pci_dev_save_and_disable(dev);
+ if (!pci_dev_trylock(dev))
+ return -EAGAIN;
- if (pci_dev_trylock(dev)) {
- rc = __pci_dev_reset(dev, 0);
- pci_dev_unlock(dev);
- } else
- rc = -EAGAIN;
+ pci_dev_save_and_disable(dev);
+ rc = __pci_reset_function_locked(dev);
+ pci_dev_unlock(dev);
pci_dev_restore(dev);
-
return rc;
}
EXPORT_SYMBOL_GPL(pci_try_reset_function);
@@ -4458,7 +4424,9 @@
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
+ pci_dev_lock(dev);
pci_dev_save_and_disable(dev);
+ pci_dev_unlock(dev);
if (dev->subordinate)
pci_bus_save_and_disable(dev->subordinate);
}
@@ -4473,7 +4441,9 @@
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
+ pci_dev_lock(dev);
pci_dev_restore(dev);
+ pci_dev_unlock(dev);
if (dev->subordinate)
pci_bus_restore(dev->subordinate);
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f8113e5..93f4044 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -272,7 +272,6 @@
u16 driver_max_VFs; /* max num VFs driver supports */
struct pci_dev *dev; /* lowest numbered PF */
struct pci_dev *self; /* this PF */
- struct mutex lock; /* lock for setting sriov_numvfs in sysfs */
resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
bool drivers_autoprobe; /* auto probing of VFs by driver */
};
diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c
index 77d2ca9..c39f32e 100644
--- a/drivers/pci/pcie/pcie-dpc.c
+++ b/drivers/pci/pcie/pcie-dpc.c
@@ -92,7 +92,7 @@
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,
&source);
- if (!status)
+ if (!status || status == (u16)(~0))
return IRQ_NONE;
dev_info(&dpc->dev->device, "DPC containment event, status:%#06x source:%#06x\n",
@@ -144,7 +144,7 @@
dpc->rp = (cap & PCI_EXP_DPC_CAP_RP_EXT);
- ctl |= PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN;
+ 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(&dev->device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 587aef3..4334fd5 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -13,10 +13,11 @@
#define PCIE_PORT_DEVICE_MAXSERVICES 5
/*
- * According to the PCI Express Base Specification 2.0, the indices of
- * the MSI-X table entries used by port services must not exceed 31
+ * The PCIe Capability Interrupt Message Number (PCIe r3.1, sec 7.8.2) must
+ * be one of the first 32 MSI-X entries. Per PCI r3.0, sec 6.8.3.1, MSI
+ * supports a maximum of 32 vectors per function.
*/
-#define PCIE_PORT_MAX_MSIX_ENTRIES 32
+#define PCIE_PORT_MAX_MSI_ENTRIES 32
#define get_descriptor_id(type, service) (((type - 4) << 8) | service)
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index cea504f..313a21d 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -44,14 +44,15 @@
}
/**
- * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port
+ * pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode
+ * for given port
* @dev: PCI Express port to handle
* @irqs: Array of interrupt vectors to populate
* @mask: Bitmask of port capabilities returned by get_port_device_capability()
*
* Return value: 0 on success, error code on failure
*/
-static int pcie_port_enable_msix(struct pci_dev *dev, int *irqs, int mask)
+static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
{
int nr_entries, entry, nvec = 0;
@@ -61,8 +62,8 @@
* equal to the number of entries this port actually uses, we'll happily
* go through without any tricks.
*/
- nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSIX_ENTRIES,
- PCI_IRQ_MSIX);
+ nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSI_ENTRIES,
+ PCI_IRQ_MSIX | PCI_IRQ_MSI);
if (nr_entries < 0)
return nr_entries;
@@ -70,14 +71,19 @@
u16 reg16;
/*
- * The code below follows the PCI Express Base Specification 2.0
- * stating in Section 6.1.6 that "PME and Hot-Plug Event
- * interrupts (when both are implemented) always share the same
- * MSI or MSI-X vector, as indicated by the Interrupt Message
- * Number field in the PCI Express Capabilities register", where
- * according to Section 7.8.2 of the specification "For MSI-X,
- * the value in this field indicates which MSI-X Table entry is
- * used to generate the interrupt message."
+ * Per PCIe r3.1, sec 6.1.6, "PME and Hot-Plug Event
+ * interrupts (when both are implemented) always share the
+ * same MSI or MSI-X vector, as indicated by the Interrupt
+ * Message Number field in the PCI Express Capabilities
+ * register".
+ *
+ * Per sec 7.8.2, "For MSI, the [Interrupt Message Number]
+ * indicates the offset between the base Message Data and
+ * the interrupt message that is generated."
+ *
+ * "For MSI-X, the [Interrupt Message Number] indicates
+ * which MSI-X Table entry is used to generate the
+ * interrupt message."
*/
pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16);
entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
@@ -94,13 +100,17 @@
u32 reg32, pos;
/*
- * The code below follows Section 7.10.10 of the PCI Express
- * Base Specification 2.0 stating that bits 31-27 of the Root
- * Error Status Register contain a value indicating which of the
- * MSI/MSI-X vectors assigned to the port is going to be used
- * for AER, where "For MSI-X, the value in this register
- * indicates which MSI-X Table entry is used to generate the
- * interrupt message."
+ * Per PCIe r3.1, sec 7.10.10, the Advanced Error Interrupt
+ * Message Number in the Root Error Status register
+ * indicates which MSI/MSI-X vector is used for AER.
+ *
+ * "For MSI, the [Advanced Error Interrupt Message Number]
+ * indicates the offset between the base Message Data and
+ * the interrupt message that is generated."
+ *
+ * "For MSI-X, the [Advanced Error Interrupt Message
+ * Number] indicates which MSI-X Table entry is used to
+ * generate the interrupt message."
*/
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32);
@@ -113,6 +123,33 @@
nvec = max(nvec, entry + 1);
}
+ if (mask & PCIE_PORT_SERVICE_DPC) {
+ u16 reg16, pos;
+
+ /*
+ * Per PCIe r4.0 (v0.9), sec 7.9.15.2, the DPC Interrupt
+ * Message Number in the DPC Capability register indicates
+ * which MSI/MSI-X vector is used for DPC.
+ *
+ * "For MSI, the [DPC Interrupt Message Number] indicates
+ * the offset between the base Message Data and the
+ * interrupt message that is generated."
+ *
+ * "For MSI-X, the [DPC Interrupt Message Number] indicates
+ * which MSI-X Table entry is used to generate the
+ * interrupt message."
+ */
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC);
+ pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP, ®16);
+ entry = reg16 & 0x1f;
+ if (entry >= nr_entries)
+ goto out_free_irqs;
+
+ irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, entry);
+
+ nvec = max(nvec, entry + 1);
+ }
+
/*
* If nvec is equal to the allocated number of entries, we can just use
* what we have. Otherwise, the port has some extra entries not for the
@@ -124,7 +161,7 @@
/* Now allocate the MSI-X vectors for real */
nr_entries = pci_alloc_irq_vectors(dev, nvec, nvec,
- PCI_IRQ_MSIX);
+ PCI_IRQ_MSIX | PCI_IRQ_MSI);
if (nr_entries < 0)
return nr_entries;
}
@@ -146,26 +183,29 @@
*/
static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
{
- unsigned flags = PCI_IRQ_LEGACY | PCI_IRQ_MSI;
int ret, i;
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
irqs[i] = -1;
/*
- * If MSI cannot be used for PCIe PME or hotplug, we have to use
- * INTx or other interrupts, e.g. system shared interrupt.
+ * If we support PME or hotplug, but we can't use MSI/MSI-X for
+ * them, we have to fall back to INTx or other interrupts, e.g., a
+ * system shared interrupt.
*/
- if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) ||
- ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) {
- flags &= ~PCI_IRQ_MSI;
- } else {
- /* Try to use MSI-X if supported */
- if (!pcie_port_enable_msix(dev, irqs, mask))
- return 0;
- }
+ if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi())
+ goto legacy_irq;
- ret = pci_alloc_irq_vectors(dev, 1, 1, flags);
+ if ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())
+ goto legacy_irq;
+
+ /* Try to use MSI-X or MSI if supported */
+ if (pcie_port_enable_irq_vec(dev, irqs, mask) == 0)
+ return 0;
+
+legacy_irq:
+ /* fall back to legacy IRQ */
+ ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY);
if (ret < 0)
return -ENODEV;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bd42ed4..c31310d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1356,6 +1356,34 @@
}
/**
+ * pci_intx_mask_broken - test PCI_COMMAND_INTX_DISABLE writability
+ * @dev: PCI device
+ *
+ * Test whether PCI_COMMAND_INTX_DISABLE is writable for @dev. Check this
+ * at enumeration-time to avoid modifying PCI_COMMAND at run-time.
+ */
+static int pci_intx_mask_broken(struct pci_dev *dev)
+{
+ u16 orig, toggle, new;
+
+ pci_read_config_word(dev, PCI_COMMAND, &orig);
+ toggle = orig ^ PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(dev, PCI_COMMAND, toggle);
+ pci_read_config_word(dev, PCI_COMMAND, &new);
+
+ pci_write_config_word(dev, PCI_COMMAND, orig);
+
+ /*
+ * PCI_COMMAND_INTX_DISABLE was reserved and read-only prior to PCI
+ * r2.3, so strictly speaking, a device is not *broken* if it's not
+ * writable. But we'll live with the misnomer for now.
+ */
+ if (new != toggle)
+ return 1;
+ return 0;
+}
+
+/**
* pci_setup_device - fill in class and map information of a device
* @dev: the device structure to fill
*
@@ -1425,6 +1453,8 @@
}
}
+ dev->broken_intx_masking = pci_intx_mask_broken(dev);
+
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
@@ -1700,6 +1730,11 @@
/* Initialize Advanced Error Capabilities and Control Register */
pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32);
reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or;
+ /* Don't enable ECRC generation or checking if unsupported */
+ if (!(reg32 & PCI_ERR_CAP_ECRC_GENC))
+ reg32 &= ~PCI_ERR_CAP_ECRC_GENE;
+ if (!(reg32 & PCI_ERR_CAP_ECRC_CHKC))
+ reg32 &= ~PCI_ERR_CAP_ECRC_CHKE;
pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
/*
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 085fb78..6967c6b 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -304,7 +304,7 @@
{
int i;
- for (i = 0; i < PCI_STD_RESOURCE_END; i++) {
+ for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
struct resource *r = &dev->resource[i];
if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) {
@@ -1684,6 +1684,19 @@
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
+static void quirk_radeon_pm(struct pci_dev *dev)
+{
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
+ dev->subsystem_device == 0x00e2) {
+ if (dev->d3_delay < 20) {
+ dev->d3_delay = 20;
+ dev_info(&dev->dev, "extending delay after power-on from D3 to %d msec\n",
+ dev->d3_delay);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6741, quirk_radeon_pm);
+
#ifdef CONFIG_X86_IO_APIC
static int dmi_disable_ioapicreroute(const struct dmi_system_id *d)
{
@@ -3236,6 +3249,10 @@
quirk_broken_intx_masking);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1589,
quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x158a,
+ quirk_broken_intx_masking);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x158b,
+ quirk_broken_intx_masking);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d0,
quirk_broken_intx_masking);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d1,
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index cc6e085..af81b2d 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -120,6 +120,13 @@
u32 reserved16[4];
} __packed;
+enum {
+ SWITCHTEC_CFG0_RUNNING = 0x04,
+ SWITCHTEC_CFG1_RUNNING = 0x05,
+ SWITCHTEC_IMG0_RUNNING = 0x03,
+ SWITCHTEC_IMG1_RUNNING = 0x07,
+};
+
struct sys_info_regs {
u32 device_id;
u32 device_version;
@@ -129,7 +136,9 @@
u32 table_format_version;
u32 partition_id;
u32 cfg_file_fmt_version;
- u32 reserved2[58];
+ u16 cfg_running;
+ u16 img_running;
+ u32 reserved2[57];
char vendor_id[8];
char product_id[16];
char product_revision[4];
@@ -807,6 +816,7 @@
{
struct switchtec_ioctl_flash_part_info info = {0};
struct flash_info_regs __iomem *fi = stdev->mmio_flash_info;
+ struct sys_info_regs __iomem *si = stdev->mmio_sys_info;
u32 active_addr = -1;
if (copy_from_user(&info, uinfo, sizeof(info)))
@@ -816,18 +826,26 @@
case SWITCHTEC_IOCTL_PART_CFG0:
active_addr = ioread32(&fi->active_cfg);
set_fw_info_part(&info, &fi->cfg0);
+ if (ioread16(&si->cfg_running) == SWITCHTEC_CFG0_RUNNING)
+ info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
break;
case SWITCHTEC_IOCTL_PART_CFG1:
active_addr = ioread32(&fi->active_cfg);
set_fw_info_part(&info, &fi->cfg1);
+ if (ioread16(&si->cfg_running) == SWITCHTEC_CFG1_RUNNING)
+ info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
break;
case SWITCHTEC_IOCTL_PART_IMG0:
active_addr = ioread32(&fi->active_img);
set_fw_info_part(&info, &fi->img0);
+ if (ioread16(&si->img_running) == SWITCHTEC_IMG0_RUNNING)
+ info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
break;
case SWITCHTEC_IOCTL_PART_IMG1:
active_addr = ioread32(&fi->active_img);
set_fw_info_part(&info, &fi->img1);
+ if (ioread16(&si->img_running) == SWITCHTEC_IMG1_RUNNING)
+ info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
break;
case SWITCHTEC_IOCTL_PART_NVLOG:
set_fw_info_part(&info, &fi->nvlog);
@@ -861,7 +879,7 @@
}
if (info.address == active_addr)
- info.active = 1;
+ info.active |= SWITCHTEC_IOCTL_PART_ACTIVE;
if (copy_to_user(uinfo, &info, sizeof(info)))
return -EFAULT;
@@ -1291,7 +1309,6 @@
cdev = &stdev->cdev;
cdev_init(cdev, &switchtec_fops);
cdev->owner = THIS_MODULE;
- cdev->kobj.parent = &dev->kobj;
return stdev;
@@ -1442,12 +1459,15 @@
stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET;
stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET;
stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET;
- stdev->partition = ioread8(&stdev->mmio_ntb->partition_id);
+ stdev->partition = ioread8(&stdev->mmio_sys_info->partition_id);
stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count);
stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET;
stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition];
stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET;
+ if (stdev->partition_count < 1)
+ stdev->partition_count = 1;
+
init_pff(stdev);
pci_set_drvdata(pdev, stdev);
@@ -1479,11 +1499,7 @@
SWITCHTEC_EVENT_EN_IRQ,
&stdev->mmio_part_cfg->mrpc_comp_hdr);
- rc = cdev_add(&stdev->cdev, stdev->dev.devt, 1);
- if (rc)
- goto err_put;
-
- rc = device_add(&stdev->dev);
+ rc = cdev_device_add(&stdev->cdev, &stdev->dev);
if (rc)
goto err_devadd;
@@ -1492,7 +1508,6 @@
return 0;
err_devadd:
- cdev_del(&stdev->cdev);
stdev_kill(stdev);
err_put:
ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt));
@@ -1506,8 +1521,7 @@
pci_set_drvdata(pdev, NULL);
- device_del(&stdev->dev);
- cdev_del(&stdev->cdev);
+ cdev_device_del(&stdev->cdev, &stdev->dev);
ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt));
dev_info(&stdev->dev, "unregistered.\n");
@@ -1544,6 +1558,24 @@
SWITCHTEC_PCI_DEVICE(0x8544), //PSX 64xG3
SWITCHTEC_PCI_DEVICE(0x8545), //PSX 80xG3
SWITCHTEC_PCI_DEVICE(0x8546), //PSX 96xG3
+ SWITCHTEC_PCI_DEVICE(0x8551), //PAX 24XG3
+ SWITCHTEC_PCI_DEVICE(0x8552), //PAX 32XG3
+ SWITCHTEC_PCI_DEVICE(0x8553), //PAX 48XG3
+ SWITCHTEC_PCI_DEVICE(0x8554), //PAX 64XG3
+ SWITCHTEC_PCI_DEVICE(0x8555), //PAX 80XG3
+ SWITCHTEC_PCI_DEVICE(0x8556), //PAX 96XG3
+ SWITCHTEC_PCI_DEVICE(0x8561), //PFXL 24XG3
+ SWITCHTEC_PCI_DEVICE(0x8562), //PFXL 32XG3
+ SWITCHTEC_PCI_DEVICE(0x8563), //PFXL 48XG3
+ SWITCHTEC_PCI_DEVICE(0x8564), //PFXL 64XG3
+ SWITCHTEC_PCI_DEVICE(0x8565), //PFXL 80XG3
+ SWITCHTEC_PCI_DEVICE(0x8566), //PFXL 96XG3
+ SWITCHTEC_PCI_DEVICE(0x8571), //PFXI 24XG3
+ SWITCHTEC_PCI_DEVICE(0x8572), //PFXI 32XG3
+ SWITCHTEC_PCI_DEVICE(0x8573), //PFXI 48XG3
+ SWITCHTEC_PCI_DEVICE(0x8574), //PFXI 64XG3
+ SWITCHTEC_PCI_DEVICE(0x8575), //PFXI 80XG3
+ SWITCHTEC_PCI_DEVICE(0x8576), //PFXI 96XG3
{0}
};
MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl);
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index b827a81..ff01bed 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -408,7 +408,7 @@
if (!base)
return;
- for (i = 0; i < PCI_STD_RESOURCE_END; i++) {
+ for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
struct resource *res = &dev->resource[i];
if (!(res->flags & IORESOURCE_MEM))
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a6fba48..0991f97 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -291,7 +291,7 @@
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
struct cpumask *irq_create_affinity_masks(int nvec, const struct irq_affinity *affd);
-int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd);
+int irq_calc_affinity_vectors(int minvec, int maxvec, const struct irq_affinity *affd);
#else /* CONFIG_SMP */
@@ -331,7 +331,7 @@
}
static inline int
-irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd)
+irq_calc_affinity_vectors(int minvec, int maxvec, const struct irq_affinity *affd)
{
return maxvec;
}
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 57e0b82..782fb8e 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -7,6 +7,7 @@
int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
void pci_disable_pri(struct pci_dev *pdev);
+void pci_restore_pri_state(struct pci_dev *pdev);
int pci_reset_pri(struct pci_dev *pdev);
#else /* CONFIG_PCI_PRI */
@@ -20,6 +21,10 @@
{
}
+static inline void pci_restore_pri_state(struct pci_dev *pdev)
+{
+}
+
static inline int pci_reset_pri(struct pci_dev *pdev)
{
return -ENODEV;
@@ -31,6 +36,7 @@
int pci_enable_pasid(struct pci_dev *pdev, int features);
void pci_disable_pasid(struct pci_dev *pdev);
+void pci_restore_pasid_state(struct pci_dev *pdev);
int pci_pasid_features(struct pci_dev *pdev);
int pci_max_pasids(struct pci_dev *pdev);
@@ -45,6 +51,10 @@
{
}
+static inline void pci_restore_pasid_state(struct pci_dev *pdev)
+{
+}
+
static inline int pci_pasid_features(struct pci_dev *pdev)
{
return -EINVAL;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 5c1c0ae..bd68ed1 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -183,6 +183,11 @@
PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = (__force pci_dev_flags_t) (1 << 9),
/* Do not use FLR even if device advertises PCI_AF_CAP */
PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
+ /*
+ * Resume before calling the driver's system suspend hooks, disabling
+ * the direct_complete optimization.
+ */
+ PCI_DEV_FLAGS_NEEDS_RESUME = (__force pci_dev_flags_t) (1 << 11),
};
enum pci_irq_reroute_variant {
@@ -356,6 +361,8 @@
unsigned int msix_enabled:1;
unsigned int ari_enabled:1; /* ARI forwarding */
unsigned int ats_enabled:1; /* Address Translation Service */
+ unsigned int pasid_enabled:1; /* Process Address Space ID */
+ unsigned int pri_enabled:1; /* Page Request Interface */
unsigned int is_managed:1;
unsigned int needs_freset:1; /* Dev requires fundamental reset */
unsigned int state_saved:1;
@@ -366,7 +373,7 @@
unsigned int is_thunderbolt:1; /* Thunderbolt controller */
unsigned int __aer_firmware_first_valid:1;
unsigned int __aer_firmware_first:1;
- unsigned int broken_intx_masking:1;
+ unsigned int broken_intx_masking:1; /* INTx masking can't be used */
unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */
unsigned int irq_managed:1;
unsigned int has_secondary_link:1;
@@ -399,6 +406,12 @@
u8 ats_stu; /* ATS Smallest Translation Unit */
atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */
#endif
+#ifdef CONFIG_PCI_PRI
+ u32 pri_reqs_alloc; /* Number of PRI requests allocated */
+#endif
+#ifdef CONFIG_PCI_PASID
+ u16 pasid_features;
+#endif
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
size_t romlen; /* Length of ROM if it's not from the BAR */
char *driver_override; /* Driver name to force a match */
@@ -694,7 +707,8 @@
pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
/* PCI function reset prepare or completed */
- void (*reset_notify)(struct pci_dev *dev, bool prepare);
+ void (*reset_prepare)(struct pci_dev *dev);
+ void (*reset_done)(struct pci_dev *dev);
/* Device driver may resume normal operations */
void (*resume)(struct pci_dev *dev);
@@ -1004,6 +1018,15 @@
int __must_check pcim_enable_device(struct pci_dev *pdev);
void pcim_pin_device(struct pci_dev *pdev);
+static inline bool pci_intx_mask_supported(struct pci_dev *pdev)
+{
+ /*
+ * INTx masking is supported if PCI_COMMAND_INTX_DISABLE is
+ * writable and no quirk has marked the feature broken.
+ */
+ return !pdev->broken_intx_masking;
+}
+
static inline int pci_is_enabled(struct pci_dev *pdev)
{
return (atomic_read(&pdev->enable_cnt) > 0);
@@ -1027,7 +1050,6 @@
int pci_try_set_mwi(struct pci_dev *dev);
void pci_clear_mwi(struct pci_dev *dev);
void pci_intx(struct pci_dev *dev, int enable);
-bool pci_intx_mask_supported(struct pci_dev *dev);
bool pci_check_and_mask_intx(struct pci_dev *dev);
bool pci_check_and_unmask_intx(struct pci_dev *dev);
int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask);
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index d56bb00..c22d3eb 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -517,6 +517,7 @@
#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */
#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
+#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
diff --git a/include/uapi/linux/switchtec_ioctl.h b/include/uapi/linux/switchtec_ioctl.h
index 3e824e1..5e392968 100644
--- a/include/uapi/linux/switchtec_ioctl.h
+++ b/include/uapi/linux/switchtec_ioctl.h
@@ -39,6 +39,9 @@
__u32 padding;
};
+#define SWITCHTEC_IOCTL_PART_ACTIVE 1
+#define SWITCHTEC_IOCTL_PART_RUNNING 2
+
struct switchtec_ioctl_flash_part_info {
__u32 flash_partition;
__u32 address;
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
index e2d356d..9b71406 100644
--- a/kernel/irq/affinity.c
+++ b/kernel/irq/affinity.c
@@ -66,6 +66,13 @@
struct cpumask *masks;
cpumask_var_t nmsk;
+ /*
+ * If there aren't any vectors left after applying the pre/post
+ * vectors don't bother with assigning affinity.
+ */
+ if (!affv)
+ return NULL;
+
if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
return NULL;
@@ -140,15 +147,19 @@
/**
* irq_calc_affinity_vectors - Calculate the optimal number of vectors
+ * @minvec: The minimum number of vectors available
* @maxvec: The maximum number of vectors available
* @affd: Description of the affinity requirements
*/
-int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd)
+int irq_calc_affinity_vectors(int minvec, int maxvec, const struct irq_affinity *affd)
{
int resv = affd->pre_vectors + affd->post_vectors;
int vecs = maxvec - resv;
int cpus;
+ if (resv > minvec)
+ return 0;
+
/* Stabilize the cpumasks */
get_online_cpus();
cpus = cpumask_weight(cpu_online_mask);