From 09cc900632400079619e9154604fd299c2cc9a5a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 30 Mar 2023 19:24:30 +0300 Subject: PCI: Introduce pci_dev_for_each_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of open-coding it everywhere introduce a tiny helper that can be used to iterate over each resource of a PCI device, and convert the most obvious users into it. While at it drop doubled empty line before pdev_sort_resources(). No functional changes intended. Suggested-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230330162434.35055-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas Reviewed-by: Krzysztof WilczyƄski --- arch/alpha/kernel/pci.c | 5 ++--- arch/arm/kernel/bios32.c | 16 +++++++--------- arch/arm/mach-dove/pcie.c | 10 +++++----- arch/arm/mach-mv78xx0/pcie.c | 10 +++++----- arch/arm/mach-orion5x/pci.c | 10 +++++----- arch/mips/pci/ops-bcm63xx.c | 8 ++++---- arch/mips/pci/pci-legacy.c | 3 +-- arch/powerpc/kernel/pci-common.c | 21 +++++++++++---------- arch/powerpc/platforms/4xx/pci.c | 8 ++++---- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 5 ++--- arch/powerpc/platforms/pseries/pci.c | 16 ++++++++-------- arch/sh/drivers/pci/pcie-sh7786.c | 10 +++++----- arch/sparc/kernel/leon_pci.c | 5 ++--- arch/sparc/kernel/pci.c | 10 ++++------ arch/sparc/kernel/pcic.c | 5 ++--- 15 files changed, 67 insertions(+), 75 deletions(-) (limited to 'arch') diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 64fbfb0763b2..4458eb7f44f0 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -288,11 +288,10 @@ pcibios_claim_one_bus(struct pci_bus *b) struct pci_bus *child_bus; list_for_each_entry(dev, &b->devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (r->parent || !r->start || !r->flags) continue; if (pci_has_flag(PCI_PROBE_ONLY) || diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index e7ef2b5bea9c..d334c7fb672b 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -142,15 +142,15 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F, */ static void pci_fixup_dec21285(struct pci_dev *dev) { - int i; - if (dev->devfn == 0) { + struct resource *r; + dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } @@ -162,13 +162,11 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_d static void pci_fixup_ide_bases(struct pci_dev *dev) { struct resource *r; - int i; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) return; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - r = dev->resource + i; + pci_dev_for_each_resource(dev, r) { if ((r->start & ~0x80) == 0x374) { r->start |= 2; r->end = r->start; diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 754ca381f600..3044b7e03890 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -142,14 +142,14 @@ static struct pci_ops pcie_ops = { static void rc_pci_fixup(struct pci_dev *dev) { if (dev->bus->parent == NULL && dev->devfn == 0) { - int i; + struct resource *r; dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index 6190f538a124..0ebc909ea273 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -186,14 +186,14 @@ static struct pci_ops pcie_ops = { static void rc_pci_fixup(struct pci_dev *dev) { if (dev->bus->parent == NULL && dev->devfn == 0) { - int i; + struct resource *r; dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 888fdc9099c5..3313bc5a63ea 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -522,14 +522,14 @@ static int __init pci_setup(struct pci_sys_data *sys) static void rc_pci_fixup(struct pci_dev *dev) { if (dev->bus->parent == NULL && dev->devfn == 0) { - int i; + struct resource *r; dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index dc6dc2741272..b0ea023c47c0 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -413,18 +413,18 @@ struct pci_ops bcm63xx_cb_ops = { static void bcm63xx_fixup(struct pci_dev *dev) { static int io_window = -1; - int i, found, new_io_window; + int found, new_io_window; + struct resource *r; u32 val; /* look for any io resource */ found = 0; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (pci_resource_flags(dev, i) & IORESOURCE_IO) { + pci_dev_for_each_resource(dev, r) { + if (resource_type(r) == IORESOURCE_IO) { found = 1; break; } } - if (!found) return; diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c index 468722c8a5c6..ec2567f8efd8 100644 --- a/arch/mips/pci/pci-legacy.c +++ b/arch/mips/pci/pci-legacy.c @@ -249,12 +249,11 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + pci_dev_for_each_resource(dev, r, idx) { /* Only set up the requested stuff */ if (!(mask & (1<resource[idx]; if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) continue; if ((idx == PCI_ROM_RESOURCE) && diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index d67cf79bf5d0..e88d7c9feeec 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -880,6 +880,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) static void pcibios_fixup_resources(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct resource *res; int i; if (!hose) { @@ -891,9 +892,9 @@ static void pcibios_fixup_resources(struct pci_dev *dev) if (dev->is_virtfn) return; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = dev->resource + i; + pci_dev_for_each_resource(dev, res, i) { struct pci_bus_region reg; + if (!res->flags) continue; @@ -1452,11 +1453,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) struct pci_bus *child_bus; list_for_each_entry(dev, &bus->devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (r->parent || !r->start || !r->flags) continue; @@ -1705,19 +1705,20 @@ EXPORT_SYMBOL_GPL(pcibios_scan_phb); static void fixup_hide_host_resource_fsl(struct pci_dev *dev) { - int i, class = dev->class >> 8; + int class = dev->class >> 8; /* When configured as agent, programming interface = 1 */ int prog_if = dev->class & 0xf; + struct resource *r; if ((class == PCI_CLASS_PROCESSOR_POWERPC || class == PCI_CLASS_BRIDGE_OTHER) && (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) && (prog_if == 0) && (dev->bus->parent == NULL)) { - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/powerpc/platforms/4xx/pci.c b/arch/powerpc/platforms/4xx/pci.c index ca5dd7a5842a..07dcc2b8007f 100644 --- a/arch/powerpc/platforms/4xx/pci.c +++ b/arch/powerpc/platforms/4xx/pci.c @@ -57,7 +57,7 @@ static inline int ppc440spe_revA(void) static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) { struct pci_controller *hose; - int i; + struct resource *r; if (dev->devfn != 0 || dev->bus->self != NULL) return; @@ -79,9 +79,9 @@ static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) /* Hide the PCI host BARs from the kernel as their content doesn't * fit well in the resource management */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = r->end = 0; + r->flags = 0; } printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 859e2818c43d..0ca4401ba781 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -327,14 +327,13 @@ mpc52xx_pci_setup(struct pci_controller *hose, static void mpc52xx_pci_fixup_resources(struct pci_dev *dev) { - int i; + struct resource *res; pr_debug("%s() %.4x:%.4x\n", __func__, dev->vendor, dev->device); /* We don't rely on boot loader for PCI and resets all devices */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = &dev->resource[i]; + pci_dev_for_each_resource(dev, res) { if (res->end > res->start) { /* Only valid resources */ res->end -= res->start; res->start = 0; diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 60e0a58928ef..1772ae3d193d 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -240,7 +240,7 @@ void __init pSeries_final_fixup(void) */ static void fixup_winbond_82c105(struct pci_dev* dev) { - int i; + struct resource *r; unsigned int reg; if (!machine_is(pseries)) @@ -251,14 +251,14 @@ static void fixup_winbond_82c105(struct pci_dev* dev) /* Enable LEGIRQ to use INTC instead of ISA interrupts */ pci_write_config_dword(dev, 0x40, reg | (1<<11)); - for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { + pci_dev_for_each_resource(dev, r) { /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - if (dev->resource[i].start == 0 && dev->resource[i].end) { - dev->resource[i].flags = 0; - dev->resource[i].end = 0; + if (dev->bus->number == 0 && dev->devfn == 0x81 && + r->flags & IORESOURCE_IO) + r->flags &= ~IORESOURCE_IO; + if (r->start == 0 && r->end) { + r->flags = 0; + r->end = 0; } } } diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index b0c2a5238d04..4f5e49f10805 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -140,12 +140,12 @@ static void sh7786_pci_fixup(struct pci_dev *dev) * Prevent enumeration of root complex resources. */ if (pci_is_root_bus(dev->bus) && dev->devfn == 0) { - int i; + struct resource *r; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index e5e5ff6b9a5c..b6663a3fbae9 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -62,15 +62,14 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) int pcibios_enable_device(struct pci_dev *dev, int mask) { + struct resource *res; u16 cmd, oldcmd; int i; pci_read_config_word(dev, PCI_COMMAND, &cmd); oldcmd = cmd; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - + pci_dev_for_each_resource(dev, res, i) { /* Only set up the requested stuff */ if (!(mask & (1<devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (r->parent || !r->start || !r->flags) continue; @@ -724,15 +723,14 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm, int pcibios_enable_device(struct pci_dev *dev, int mask) { + struct resource *res; u16 cmd, oldcmd; int i; pci_read_config_word(dev, PCI_COMMAND, &cmd); oldcmd = cmd; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - + pci_dev_for_each_resource(dev, res, i) { /* Only set up the requested stuff */ if (!(mask & (1<resource[i]; - + pci_dev_for_each_resource(dev, res, i) { /* Only set up the requested stuff */ if (!(mask & (1< Date: Wed, 12 Apr 2023 00:02:13 +0800 Subject: PCI: Fix up L1SS capability for Intel Apollo Lake Root Port On Google Coral and Reef family Chromebooks with Intel Apollo Lake SoC, firmware clobbers the header of the L1 PM Substates capability and the previous capability when returning from D3cold to D0. Save those headers at enumeration-time and restore them at resume. [bhelgaas: The main benefit is to make the lspci output after resume correct. Apparently there's little or no effect on power consumption.] Link: https://lore.kernel.org/linux-pci/CAFJ_xbq0cxcH-cgpXLU4Mjk30+muWyWm1aUZGK7iG53yaLBaQg@mail.gmail.com/T/#u Link: https://lore.kernel.org/r/20230411160213.4453-1-ron.lee@intel.com Signed-off-by: Ron Lee Signed-off-by: Bjorn Helgaas --- arch/x86/pci/fixup.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'arch') diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 615a76d70019..c6c46605812b 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -824,3 +824,62 @@ static void rs690_fix_64bit_dma(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7910, rs690_fix_64bit_dma); #endif + +/* + * When returning from D3cold to D0, firmware on some Google Coral and Reef + * family Chromebooks with Intel Apollo Lake SoC clobbers the headers of + * both the L1 PM Substates capability and the previous capability for the + * "Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port B #1". + * + * Save those values at enumeration-time and restore them at resume. + */ + +static u16 prev_cap, l1ss_cap; +static u32 prev_header, l1ss_header; + +static void chromeos_save_apl_pci_l1ss_capability(struct pci_dev *dev) +{ + int pos = PCI_CFG_SPACE_SIZE, prev = 0; + u32 header, pheader = 0; + + while (pos) { + pci_read_config_dword(dev, pos, &header); + if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_L1SS) { + prev_cap = prev; + prev_header = pheader; + l1ss_cap = pos; + l1ss_header = header; + return; + } + + prev = pos; + pheader = header; + pos = PCI_EXT_CAP_NEXT(header); + } +} + +static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev) +{ + u32 header; + + if (!prev_cap || !prev_header || !l1ss_cap || !l1ss_header) + return; + + /* Fixup the header of L1SS Capability if missing */ + pci_read_config_dword(dev, l1ss_cap, &header); + if (header != l1ss_header) { + pci_write_config_dword(dev, l1ss_cap, l1ss_header); + pci_info(dev, "restore L1SS Capability header (was %#010x now %#010x)\n", + header, l1ss_header); + } + + /* Fixup the link to L1SS Capability if missing */ + pci_read_config_dword(dev, prev_cap, &header); + if (header != prev_header) { + pci_write_config_dword(dev, prev_cap, prev_header); + pci_info(dev, "restore previous Capability header (was %#010x now %#010x)\n", + header, prev_header); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability); -- cgit v1.2.3