diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie/aer.c | 45 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 76 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 35 |
3 files changed, 98 insertions, 58 deletions
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index e85ff946e8c8..5706019ea908 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1213,6 +1213,28 @@ static irqreturn_t aer_irq(int irq, void *context) return IRQ_WAKE_THREAD; } +static void aer_enable_irq(struct pci_dev *pdev) +{ + int aer = pdev->aer_cap; + u32 reg32; + + /* Enable Root Port's interrupt in response to error messages */ + pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32); + reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; + pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); +} + +static void aer_disable_irq(struct pci_dev *pdev) +{ + int aer = pdev->aer_cap; + u32 reg32; + + /* Disable Root's interrupt in response to error messages */ + pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32); + reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; + pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); +} + /** * aer_enable_rootport - enable Root Port's interrupts when receiving messages * @rpc: pointer to a Root Port data structure @@ -1242,10 +1264,7 @@ static void aer_enable_rootport(struct aer_rpc *rpc) pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, ®32); pci_write_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, reg32); - /* Enable Root Port's interrupt in response to error messages */ - pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32); - reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); + aer_enable_irq(pdev); } /** @@ -1260,10 +1279,7 @@ static void aer_disable_rootport(struct aer_rpc *rpc) int aer = pdev->aer_cap; u32 reg32; - /* Disable Root's interrupt in response to error messages */ - pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32); - reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); + aer_disable_irq(pdev); /* Clear Root's error status reg */ pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, ®32); @@ -1358,12 +1374,8 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) */ aer = root ? root->aer_cap : 0; - if ((host->native_aer || pcie_ports_native) && aer) { - /* Disable Root's interrupt in response to error messages */ - pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32); - reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32); - } + if ((host->native_aer || pcie_ports_native) && aer) + aer_disable_irq(root); if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) { rc = pcie_reset_flr(dev, PCI_RESET_DO_RESET); @@ -1382,10 +1394,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, ®32); pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32); - /* Enable Root Port's interrupt in response to error messages */ - pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32); - reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32); + aer_enable_irq(root); } return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 1bf630059264..99656d669f00 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -7,7 +7,9 @@ * Copyright (C) Shaohua Li (shaohua.li@intel.com) */ +#include <linux/bitfield.h> #include <linux/kernel.h> +#include <linux/limits.h> #include <linux/math.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -16,9 +18,10 @@ #include <linux/errno.h> #include <linux/pm.h> #include <linux/init.h> +#include <linux/printk.h> #include <linux/slab.h> -#include <linux/jiffies.h> -#include <linux/delay.h> +#include <linux/time.h> + #include "../pci.h" #ifdef MODULE_PARAM_PREFIX @@ -267,10 +270,10 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) /* Convert L0s latency encoding to ns */ static u32 calc_l0s_latency(u32 lnkcap) { - u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12; + u32 encoding = FIELD_GET(PCI_EXP_LNKCAP_L0SEL, lnkcap); if (encoding == 0x7) - return (5 * 1000); /* > 4us */ + return 5 * NSEC_PER_USEC; /* > 4us */ return (64 << encoding); } @@ -278,26 +281,26 @@ static u32 calc_l0s_latency(u32 lnkcap) static u32 calc_l0s_acceptable(u32 encoding) { if (encoding == 0x7) - return -1U; + return U32_MAX; return (64 << encoding); } /* Convert L1 latency encoding to ns */ static u32 calc_l1_latency(u32 lnkcap) { - u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15; + u32 encoding = FIELD_GET(PCI_EXP_LNKCAP_L1EL, lnkcap); if (encoding == 0x7) - return (65 * 1000); /* > 64us */ - return (1000 << encoding); + return 65 * NSEC_PER_USEC; /* > 64us */ + return NSEC_PER_USEC << encoding; } /* Convert L1 acceptable latency encoding to ns */ static u32 calc_l1_acceptable(u32 encoding) { if (encoding == 0x7) - return -1U; - return (1000 << encoding); + return U32_MAX; + return NSEC_PER_USEC << encoding; } /* Convert L1SS T_pwr encoding to usec */ @@ -325,33 +328,33 @@ static u32 calc_l12_pwron(struct pci_dev *pdev, u32 scale, u32 val) */ static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value) { - u64 threshold_ns = (u64) threshold_us * 1000; + u64 threshold_ns = (u64)threshold_us * NSEC_PER_USEC; /* * LTR_L1.2_THRESHOLD_Value ("value") is a 10-bit field with max * value of 0x3ff. */ - if (threshold_ns <= 0x3ff * 1) { + if (threshold_ns <= 1 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) { *scale = 0; /* Value times 1ns */ *value = threshold_ns; - } else if (threshold_ns <= 0x3ff * 32) { + } else if (threshold_ns <= 32 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) { *scale = 1; /* Value times 32ns */ *value = roundup(threshold_ns, 32) / 32; - } else if (threshold_ns <= 0x3ff * 1024) { + } else if (threshold_ns <= 1024 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) { *scale = 2; /* Value times 1024ns */ *value = roundup(threshold_ns, 1024) / 1024; - } else if (threshold_ns <= 0x3ff * 32768) { + } else if (threshold_ns <= 32768 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) { *scale = 3; /* Value times 32768ns */ *value = roundup(threshold_ns, 32768) / 32768; - } else if (threshold_ns <= 0x3ff * 1048576) { + } else if (threshold_ns <= 1048576 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) { *scale = 4; /* Value times 1048576ns */ *value = roundup(threshold_ns, 1048576) / 1048576; - } else if (threshold_ns <= 0x3ff * (u64) 33554432) { + } else if (threshold_ns <= (u64)33554432 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) { *scale = 5; /* Value times 33554432ns */ *value = roundup(threshold_ns, 33554432) / 33554432; } else { *scale = 5; - *value = 0x3ff; /* Max representable value */ + *value = FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE); } } @@ -371,11 +374,11 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint) link = endpoint->bus->self->link_state; /* Calculate endpoint L0s acceptable latency */ - encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L0S) >> 6; + encoding = FIELD_GET(PCI_EXP_DEVCAP_L0S, endpoint->devcap); acceptable_l0s = calc_l0s_acceptable(encoding); /* Calculate endpoint L1 acceptable latency */ - encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L1) >> 9; + encoding = FIELD_GET(PCI_EXP_DEVCAP_L1, endpoint->devcap); acceptable_l1 = calc_l1_acceptable(encoding); while (link) { @@ -417,7 +420,7 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint) if ((link->aspm_capable & ASPM_STATE_L1) && (latency + l1_switch_latency > acceptable_l1)) link->aspm_capable &= ~ASPM_STATE_L1; - l1_switch_latency += 1000; + l1_switch_latency += NSEC_PER_USEC; link = link->parent; } @@ -446,22 +449,24 @@ static void aspm_calc_l12_info(struct pcie_link_state *link, u32 pl1_2_enables, cl1_2_enables; /* Choose the greater of the two Port Common_Mode_Restore_Times */ - val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8; - val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8; + val1 = FIELD_GET(PCI_L1SS_CAP_CM_RESTORE_TIME, parent_l1ss_cap); + val2 = FIELD_GET(PCI_L1SS_CAP_CM_RESTORE_TIME, child_l1ss_cap); t_common_mode = max(val1, val2); /* Choose the greater of the two Port T_POWER_ON times */ - val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19; - scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16; - val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19; - scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16; + val1 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_VALUE, parent_l1ss_cap); + scale1 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_SCALE, parent_l1ss_cap); + val2 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_VALUE, child_l1ss_cap); + scale2 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_SCALE, child_l1ss_cap); if (calc_l12_pwron(parent, scale1, val1) > calc_l12_pwron(child, scale2, val2)) { - ctl2 |= scale1 | (val1 << 3); + ctl2 |= FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_SCALE, scale1) | + FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_VALUE, val1); t_power_on = calc_l12_pwron(parent, scale1, val1); } else { - ctl2 |= scale2 | (val2 << 3); + ctl2 |= FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_SCALE, scale2) | + FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_VALUE, val2); t_power_on = calc_l12_pwron(child, scale2, val2); } @@ -477,7 +482,9 @@ static void aspm_calc_l12_info(struct pcie_link_state *link, */ l1_2_threshold = 2 + 4 + t_common_mode + t_power_on; encode_l12_threshold(l1_2_threshold, &scale, &value); - ctl1 |= t_common_mode << 8 | scale << 29 | value << 16; + ctl1 |= FIELD_PREP(PCI_L1SS_CTL1_CM_RESTORE_TIME, t_common_mode) | + FIELD_PREP(PCI_L1SS_CTL1_LTR_L12_TH_VALUE, value) | + FIELD_PREP(PCI_L1SS_CTL1_LTR_L12_TH_SCALE, scale); /* Some broken devices only support dword access to L1 SS */ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1); @@ -1059,7 +1066,8 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) if (state & PCIE_LINK_STATE_L0S) link->aspm_disable |= ASPM_STATE_L0S; if (state & PCIE_LINK_STATE_L1) - link->aspm_disable |= ASPM_STATE_L1; + /* L1 PM substates require L1 */ + link->aspm_disable |= ASPM_STATE_L1 | ASPM_STATE_L1SS; if (state & PCIE_LINK_STATE_L1_1) link->aspm_disable |= ASPM_STATE_L1_1; if (state & PCIE_LINK_STATE_L1_2) @@ -1247,6 +1255,8 @@ static ssize_t aspm_attr_store_common(struct device *dev, link->aspm_disable &= ~ASPM_STATE_L1; } else { link->aspm_disable |= state; + if (state & ASPM_STATE_L1) + link->aspm_disable |= ASPM_STATE_L1SS; } pcie_config_aspm_link(link, policy_to_aspm_state(link)); @@ -1361,10 +1371,10 @@ static int __init pcie_aspm_disable(char *str) aspm_policy = POLICY_DEFAULT; aspm_disabled = 1; aspm_support_enabled = false; - printk(KERN_INFO "PCIe ASPM is disabled\n"); + pr_info("PCIe ASPM is disabled\n"); } else if (!strcmp(str, "force")) { aspm_force = 1; - printk(KERN_INFO "PCIe ASPM is forcibly enabled\n"); + pr_info("PCIe ASPM is forcibly enabled\n"); } return 1; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index eeec1d6f9023..8246074ea530 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5507,6 +5507,12 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0420, quirk_no_ext_tags); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags); #ifdef CONFIG_PCI_ATS +static void quirk_no_ats(struct pci_dev *pdev) +{ + pci_info(pdev, "disabling ATS\n"); + pdev->ats_cap = 0; +} + /* * Some devices require additional driver setup to enable ATS. Don't use * ATS for those devices as ATS will be enabled before the driver has had a @@ -5520,14 +5526,10 @@ static void quirk_amd_harvest_no_ats(struct pci_dev *pdev) (pdev->subsystem_device == 0xce19 || pdev->subsystem_device == 0xcc10 || pdev->subsystem_device == 0xcc08)) - goto no_ats; - else - return; + quirk_no_ats(pdev); + } else { + quirk_no_ats(pdev); } - -no_ats: - pci_info(pdev, "disabling ATS\n"); - pdev->ats_cap = 0; } /* AMD Stoney platform GPU */ @@ -5550,6 +5552,25 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7347, quirk_amd_harvest_no_ats); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x734f, quirk_amd_harvest_no_ats); /* AMD Raven platform iGPU */ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats); + +/* + * Intel IPU E2000 revisions before C0 implement incorrect endianness + * in ATS Invalidate Request message body. Disable ATS for those devices. + */ +static void quirk_intel_e2000_no_ats(struct pci_dev *pdev) +{ + if (pdev->revision < 0x20) + quirk_no_ats(pdev); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1451, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1452, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1453, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1454, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1455, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1457, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1459, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145a, quirk_intel_e2000_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145c, quirk_intel_e2000_no_ats); #endif /* CONFIG_PCI_ATS */ /* Freescale PCIe doesn't support MSI in RC mode */ |