From 0f12a4e29368a9476076515881d9ef4e5876c6e2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 13 Jan 2011 19:47:56 +0000 Subject: PCI: sysfs: Fix failure path for addition of "vpd" attribute Commit 280c73d ("PCI: centralize the capabilities code in pci-sysfs.c") changed the initialisation of the "rom" and "vpd" attributes, and made the failure path for the "vpd" attribute incorrect. We must free the new attribute structure (attr), but instead we currently free dev->vpd->attr. That will normally be NULL, resulting in a memory leak, but it might be a stale pointer, resulting in a double-free. Found by inspection; compile-tested only. Cc: stable@kernel.org Signed-off-by: Ben Hutchings Signed-off-by: Jesse Barnes --- drivers/pci/pci-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8ecaac983923..cf2b3654b4a8 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1087,7 +1087,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev) attr->write = write_vpd_attr; retval = sysfs_create_bin_file(&dev->dev.kobj, attr); if (retval) { - kfree(dev->vpd->attr); + kfree(attr); return retval; } dev->vpd->attr = attr; -- cgit v1.2.3 From 7c867c8899e873652ef98a890d2e647c092bec25 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 24 Jan 2011 21:14:33 +0100 Subject: PCI: Avoid potential NULL pointer dereference in pci_scan_bridge pci_add_new_bus() calls pci_alloc_child_bus() which calls pci_alloc_bus() that allocates memory dynamically with kzalloc(). The return value of kzalloc() is the pointer that's eventually returned from pci_add_new_bus(), so since kzalloc() can fail and return NULL so can pci_add_new_bus(). Thus we may end up dereferencing a NULL pointer in drivers/pci/probe.c::pci_scan_bridge(). Seems to me we should test for this and bail out if it happens rather than crashing. Also removed some trailing whitespace that bugged me while looking at this. Signed-off-by: Jesper Juhl Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c84900da3c59..44cbbbaa499d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -764,6 +764,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, if (pci_find_bus(pci_domain_nr(bus), max+1)) goto out; child = pci_add_new_bus(bus, dev, ++max); + if (!child) + goto out; buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) @@ -777,7 +779,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, buses &= ~0xff000000; buses |= CARDBUS_LATENCY_TIMER << 24; } - + /* * We need to blast all three values with a single write. */ -- cgit v1.2.3 From b99af4b002e4908d1a5cdaf424529bdf1dc69768 Mon Sep 17 00:00:00 2001 From: Brandeburg, Jesse Date: Mon, 14 Feb 2011 09:05:02 -0800 Subject: PCI: remove quirk for pre-production systems Revert commit 7eb93b175d4de9438a4b0af3a94a112cb5266944 Author: Yu Zhao Date: Fri Apr 3 15:18:11 2009 +0800 PCI: SR-IOV quirk for Intel 82576 NIC If BIOS doesn't allocate resources for the SR-IOV BARs, zero the Flash BAR and program the SR-IOV BARs to use the old Flash Memory Space. Please refer to Intel 82576 Gigabit Ethernet Controller Datasheet section 7.9.2.14.2 for details. http://download.intel.com/design/network/datashts/82576_Datasheet.pdf Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes This quirk was added before SR-IOV was in production and now all machines that originally had this issue alreayd have bios updates to correct the issue. The quirk itself is no longer needed and in fact causes bugs if run. Remove it. Signed-off-by: Jesse Brandeburg CC: Yu Zhao CC: Jesse Barnes Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 53a786fd0d40..ff01bfb3cc29 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2618,58 +2618,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375, #endif /* CONFIG_PCI_MSI */ -#ifdef CONFIG_PCI_IOV - -/* - * For Intel 82576 SR-IOV NIC, if BIOS doesn't allocate resources for the - * SR-IOV BARs, zero the Flash BAR and program the SR-IOV BARs to use the - * old Flash Memory Space. - */ -static void __devinit quirk_i82576_sriov(struct pci_dev *dev) -{ - int pos, flags; - u32 bar, start, size; - - if (PAGE_SIZE > 0x10000) - return; - - flags = pci_resource_flags(dev, 0); - if ((flags & PCI_BASE_ADDRESS_SPACE) != - PCI_BASE_ADDRESS_SPACE_MEMORY || - (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != - PCI_BASE_ADDRESS_MEM_TYPE_32) - return; - - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); - if (!pos) - return; - - pci_read_config_dword(dev, pos + PCI_SRIOV_BAR, &bar); - if (bar & PCI_BASE_ADDRESS_MEM_MASK) - return; - - start = pci_resource_start(dev, 1); - size = pci_resource_len(dev, 1); - if (!start || size != 0x400000 || start & (size - 1)) - return; - - pci_resource_flags(dev, 1) = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); - pci_write_config_dword(dev, pos + PCI_SRIOV_BAR, start); - pci_write_config_dword(dev, pos + PCI_SRIOV_BAR + 12, start + size / 2); - - dev_info(&dev->dev, "use Flash Memory Space for SR-IOV BARs\n"); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10c9, quirk_i82576_sriov); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e6, quirk_i82576_sriov); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e8, quirk_i82576_sriov); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150a, quirk_i82576_sriov); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150d, quirk_i82576_sriov); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov); - -#endif /* CONFIG_PCI_IOV */ - /* Allow manual resource allocation for PCI hotplug bridges * via pci=hpmemsize=nnM and pci=hpiosize=nnM parameters. For * some PCI-PCI hotplug bridges, like PLX 6254 (former HINT HB6), -- cgit v1.2.3 From db2e2e6ee9ee9ce93b04c6975fdfef304771d6ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 24 Jan 2011 15:43:03 +0100 Subject: xen-pcifront: don't use flush_scheduled_work() flush_scheduled_work() is scheduled for deprecation. Cancel ->op_work directly instead. Signed-off-by: Tejun Heo Cc: Ryan Wilson Cc: Jan Beulich Cc: Jesse Barnes Signed-off-by: Konrad Rzeszutek Wilk --- drivers/pci/xen-pcifront.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 3a5a6fcc0ead..030ce3743439 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -733,8 +733,7 @@ static void free_pdev(struct pcifront_device *pdev) pcifront_free_roots(pdev); - /*For PCIE_AER error handling job*/ - flush_scheduled_work(); + cancel_work_sync(&pdev->op_work); if (pdev->irq >= 0) unbind_from_irqhandler(pdev->irq, pdev); -- cgit v1.2.3 From 1d4610527bc71d3f9eea520fc51a02d54f79dcd0 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 16 Feb 2011 13:43:22 -0500 Subject: xen-pcifront: Sanity check the MSI/MSI-X values Check the returned vector values for any values that are odd or plain incorrect (say vector value zero), and if so print a warning. Also fixup the return values. This patch was precipiated by the Xen PCIBack returning the incorrect values due to how it was retrieving PIRQ values. This has been fixed in the xen-pciback by "xen/pciback: Utilize 'xen_pirq_from_irq' to get PIRQ value" patch. Reviewed-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/pci/xen-pcifront.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 030ce3743439..5c7b6ad68056 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -277,18 +277,24 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, if (likely(!err)) { if (likely(!op.value)) { /* we get the result */ - for (i = 0; i < nvec; i++) + for (i = 0; i < nvec; i++) { + if (op.msix_entries[i].vector <= 0) { + dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n", + i, op.msix_entries[i].vector); + err = -EINVAL; + *(*vector+i) = -1; + continue; + } *(*vector+i) = op.msix_entries[i].vector; - return 0; + } } else { printk(KERN_DEBUG "enable msix get value %x\n", op.value); - return op.value; } } else { dev_err(&dev->dev, "enable msix get err %x\n", err); - return err; } + return err; } static void pci_frontend_disable_msix(struct pci_dev *dev) @@ -325,6 +331,12 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector) err = do_pci_op(pdev, &op); if (likely(!err)) { *(*vector) = op.value; + if (op.value <= 0) { + dev_warn(&dev->dev, "MSI entry is invalid: %d!\n", + op.value); + err = -EINVAL; + *(*vector) = -1; + } } else { dev_err(&dev->dev, "pci frontend enable msi failed for dev " "%x:%x\n", op.bus, op.devfn); -- cgit v1.2.3 From cc0f89c4a426fcd6400a89e9e34e4a8851abef76 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 17 Feb 2011 12:02:23 -0500 Subject: pci/xen: Cleanup: convert int** to int[] Cleanup code. Cosmetic change to make the code look easier to read. Reviewed-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/xen/pci.h | 8 ++++---- arch/x86/pci/xen.c | 4 ++-- drivers/pci/xen-pcifront.c | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/pci') diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h index 2329b3eaf8d3..aa8620989162 100644 --- a/arch/x86/include/asm/xen/pci.h +++ b/arch/x86/include/asm/xen/pci.h @@ -27,16 +27,16 @@ static inline void __init xen_setup_pirqs(void) * its own functions. */ struct xen_pci_frontend_ops { - int (*enable_msi)(struct pci_dev *dev, int **vectors); + int (*enable_msi)(struct pci_dev *dev, int vectors[]); void (*disable_msi)(struct pci_dev *dev); - int (*enable_msix)(struct pci_dev *dev, int **vectors, int nvec); + int (*enable_msix)(struct pci_dev *dev, int vectors[], int nvec); void (*disable_msix)(struct pci_dev *dev); }; extern struct xen_pci_frontend_ops *xen_pci_frontend; static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev, - int **vectors) + int vectors[]) { if (xen_pci_frontend && xen_pci_frontend->enable_msi) return xen_pci_frontend->enable_msi(dev, vectors); @@ -48,7 +48,7 @@ static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev) xen_pci_frontend->disable_msi(dev); } static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev, - int **vectors, int nvec) + int vectors[], int nvec) { if (xen_pci_frontend && xen_pci_frontend->enable_msix) return xen_pci_frontend->enable_msix(dev, vectors, nvec); diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 6432f751ee4f..30fdd09dea05 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -150,9 +150,9 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) return -ENOMEM; if (type == PCI_CAP_ID_MSIX) - ret = xen_pci_frontend_enable_msix(dev, &v, nvec); + ret = xen_pci_frontend_enable_msix(dev, v, nvec); else - ret = xen_pci_frontend_enable_msi(dev, &v); + ret = xen_pci_frontend_enable_msi(dev, v); if (ret) goto error; i = 0; diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 5c7b6ad68056..492b7d807fe8 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -243,7 +243,7 @@ struct pci_ops pcifront_bus_ops = { #ifdef CONFIG_PCI_MSI static int pci_frontend_enable_msix(struct pci_dev *dev, - int **vector, int nvec) + int vector[], int nvec) { int err; int i; @@ -282,10 +282,10 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n", i, op.msix_entries[i].vector); err = -EINVAL; - *(*vector+i) = -1; + vector[i] = -1; continue; } - *(*vector+i) = op.msix_entries[i].vector; + vector[i] = op.msix_entries[i].vector; } } else { printk(KERN_DEBUG "enable msix get value %x\n", @@ -316,7 +316,7 @@ static void pci_frontend_disable_msix(struct pci_dev *dev) dev_err(&dev->dev, "pci_disable_msix get err %x\n", err); } -static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector) +static int pci_frontend_enable_msi(struct pci_dev *dev, int vector[]) { int err; struct xen_pci_op op = { @@ -330,12 +330,12 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector) err = do_pci_op(pdev, &op); if (likely(!err)) { - *(*vector) = op.value; + vector[0] = op.value; if (op.value <= 0) { dev_warn(&dev->dev, "MSI entry is invalid: %d!\n", op.value); err = -EINVAL; - *(*vector) = -1; + vector[0] = -1; } } else { dev_err(&dev->dev, "pci frontend enable msi failed for dev " -- cgit v1.2.3 From 457d9d088b026e26dbab98cad9d299c1faf4c343 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Tue, 11 Jan 2011 15:34:35 -0500 Subject: PCI: aer-inject: Override PCIe AER Mask Registers I have several systems which have the same problem: The PCIe AER corrected and uncorrected masks have all the error bits set. This results in the inablility to test with the aer_inject module & utility on those systems. Add the 'aer_mask_override' module parameter which will override the corrected or uncorrected masks for a PCI device. The mask will have the bit corresponding to the status passed into the aer_inject() function. After this patch it is possible to successfully use the aer_inject utility on those PCI slots. Successfully tested by me on a Dell and Intel whitebox which exhibited the mask problem. Signed-off-by: Prarit Bhargava Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aer/aer_inject.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index b3cf6223f63a..f62079ff06dd 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -27,6 +27,10 @@ #include #include "aerdrv.h" +/* Override the existing corrected and uncorrected error masks */ +static int aer_mask_override; +module_param(aer_mask_override, bool, 0); + struct aer_error_inj { u8 bus; u8 dev; @@ -322,7 +326,7 @@ static int aer_inject(struct aer_error_inj *einj) unsigned long flags; unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); int pos_cap_err, rp_pos_cap_err; - u32 sever, cor_mask, uncor_mask; + u32 sever, cor_mask, uncor_mask, cor_mask_orig, uncor_mask_orig; int ret = 0; dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); @@ -361,6 +365,18 @@ static int aer_inject(struct aer_error_inj *einj) goto out_put; } + if (aer_mask_override) { + cor_mask_orig = cor_mask; + cor_mask &= !(einj->cor_status); + pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, + cor_mask); + + uncor_mask_orig = uncor_mask; + uncor_mask &= !(einj->uncor_status); + pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, + uncor_mask); + } + spin_lock_irqsave(&inject_lock, flags); err = __find_aer_error_by_dev(dev); @@ -378,14 +394,16 @@ static int aer_inject(struct aer_error_inj *einj) err->header_log2 = einj->header_log2; err->header_log3 = einj->header_log3; - if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { + if (!aer_mask_override && einj->cor_status && + !(einj->cor_status & ~cor_mask)) { ret = -EINVAL; printk(KERN_WARNING "The correctable error(s) is masked " "by device\n"); spin_unlock_irqrestore(&inject_lock, flags); goto out_put; } - if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { + if (!aer_mask_override && einj->uncor_status && + !(einj->uncor_status & ~uncor_mask)) { ret = -EINVAL; printk(KERN_WARNING "The uncorrectable error(s) is masked " "by device\n"); @@ -425,6 +443,13 @@ static int aer_inject(struct aer_error_inj *einj) } spin_unlock_irqrestore(&inject_lock, flags); + if (aer_mask_override) { + pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, + cor_mask_orig); + pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, + uncor_mask_orig); + } + ret = pci_bus_set_aer_ops(dev->bus); if (ret) goto out_put; -- cgit v1.2.3 From cdb9755849fbaf2bb9c0a009ba5baa817a0f152d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 28 Feb 2011 10:45:09 +0100 Subject: PCI: add more checking to ICH region quirks Per ICH4 and ICH6 specs, ACPI and GPIO regions are valid iff ACPI_EN and GPIO_EN bits are set to 1. Add checks for these bits into the quirks prior to the region creation. While at it, name the constants by macros. Signed-off-by: Jiri Slaby Cc: Bjorn Helgaas Cc: "David S. Miller" Cc: Thomas Renninger Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ff01bfb3cc29..9e23912c97ac 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -533,6 +533,17 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi); +#define ICH_PMBASE 0x40 +#define ICH_ACPI_CNTL 0x44 +#define ICH4_ACPI_EN 0x10 +#define ICH6_ACPI_EN 0x80 +#define ICH4_GPIOBASE 0x58 +#define ICH4_GPIO_CNTL 0x5c +#define ICH4_GPIO_EN 0x10 +#define ICH6_GPIOBASE 0x48 +#define ICH6_GPIO_CNTL 0x4c +#define ICH6_GPIO_EN 0x10 + /* * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at * 0x40 (128 bytes of ACPI, GPIO & TCO registers) @@ -541,12 +552,21 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, qui static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) { u32 region; + u8 enable; - pci_read_config_dword(dev, 0x40, ®ion); - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH4 ACPI/GPIO/TCO"); + pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable); + if (enable & ICH4_ACPI_EN) { + pci_read_config_dword(dev, ICH_PMBASE, ®ion); + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, + "ICH4 ACPI/GPIO/TCO"); + } - pci_read_config_dword(dev, 0x58, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO"); + pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable); + if (enable & ICH4_GPIO_EN) { + pci_read_config_dword(dev, ICH4_GPIOBASE, ®ion); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES + 1, + "ICH4 GPIO"); + } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi); @@ -562,12 +582,21 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, qui static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev) { u32 region; + u8 enable; - pci_read_config_dword(dev, 0x40, ®ion); - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH6 ACPI/GPIO/TCO"); + pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable); + if (enable & ICH6_ACPI_EN) { + pci_read_config_dword(dev, ICH_PMBASE, ®ion); + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, + "ICH6 ACPI/GPIO/TCO"); + } - pci_read_config_dword(dev, 0x48, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO"); + pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable); + if (enable & ICH4_GPIO_EN) { + pci_read_config_dword(dev, ICH6_GPIOBASE, ®ion); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES + 1, + "ICH6 GPIO"); + } } static void __devinit ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize) -- cgit v1.2.3 From 6058989bad05b82e78baacce69ec14f27a11b5fd Mon Sep 17 00:00:00 2001 From: Narendra_K@Dell.com Date: Wed, 2 Mar 2011 22:34:17 +0530 Subject: PCI: Export ACPI _DSM provided firmware instance number and string name to sysfs This patch exports ACPI _DSM (Device Specific Method) provided firmware instance number and string name of PCI devices as defined by 'PCI Firmware Specification Revision 3.1' section 4.6.7.( DSM for Naming a PCI or PCI Express Device Under Operating Systems) to sysfs. New files created are: /sys/bus/pci/devices/.../label which contains the firmware name for the device in question, and /sys/bus/pci/devices/.../acpi_index which contains the firmware device type instance for the given device. cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/acpi_index 1 cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/label Embedded Broadcom 5709C NIC 1 cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.1/acpi_index 2 cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.1/label Embedded Broadcom 5709C NIC 2 The ACPI _DSM provided firmware 'instance number' and 'string name' will be given priority if the firmware also provides 'SMBIOS type 41 device type instance and string'. Signed-off-by: Matthew Garrett Signed-off-by: Jordan Hargrave Signed-off-by: Narendra K Signed-off-by: Jesse Barnes --- Documentation/ABI/testing/sysfs-bus-pci | 31 +++- drivers/pci/Kconfig | 2 + drivers/pci/Makefile | 3 +- drivers/pci/pci-label.c | 247 +++++++++++++++++++++++++++++++- drivers/pci/pci.h | 2 +- 5 files changed, 270 insertions(+), 15 deletions(-) (limited to 'drivers/pci') diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index f979d825d112..36bf454ba855 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -145,9 +145,11 @@ Date: July 2010 Contact: Narendra K , linux-bugs@dell.com Description: Reading this attribute will provide the firmware - given name(SMBIOS type 41 string) of the PCI device. - The attribute will be created only if the firmware - has given a name to the PCI device. + given name (SMBIOS type 41 string or ACPI _DSM string) of + the PCI device. The attribute will be created only + if the firmware has given a name to the PCI device. + ACPI _DSM string name will be given priority if the + system firmware provides SMBIOS type 41 string also. Users: Userspace applications interested in knowing the firmware assigned name of the PCI device. @@ -157,12 +159,27 @@ Date: July 2010 Contact: Narendra K , linux-bugs@dell.com Description: Reading this attribute will provide the firmware - given instance(SMBIOS type 41 device type instance) - of the PCI device. The attribute will be created - only if the firmware has given a device type instance - to the PCI device. + given instance (SMBIOS type 41 device type instance) of the + PCI device. The attribute will be created only if the firmware + has given an instance number to the PCI device. Users: Userspace applications interested in knowing the firmware assigned device type instance of the PCI device that can help in understanding the firmware intended order of the PCI device. + +What: /sys/bus/pci/devices/.../acpi_index +Date: July 2010 +Contact: Narendra K , linux-bugs@dell.com +Description: + Reading this attribute will provide the firmware + given instance (ACPI _DSM instance number) of the PCI device. + The attribute will be created only if the firmware has given + an instance number to the PCI device. ACPI _DSM instance number + will be given priority if the system firmware provides SMBIOS + type 41 device type instance also. +Users: + Userspace applications interested in knowing the + firmware assigned instance number of the PCI + device that can help in understanding the firmware + intended order of the PCI device. diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index a9523fdc6911..c8ff646c0b05 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -87,3 +87,5 @@ config PCI_IOAPIC depends on ACPI depends on HOTPLUG default y + +select NLS if (DMI || ACPI) diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98e6fdf34d30..bb1d3b2d81ec 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -53,8 +53,9 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o # # ACPI Related PCI FW Functions +# ACPI _DSM provided firmware instance and string name # -obj-$(CONFIG_ACPI) += pci-acpi.o +obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o # SMBIOS provided firmware instance and labels obj-$(CONFIG_DMI) += pci-label.o diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index 90c0a729cd3a..824e247edc58 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -5,6 +5,13 @@ * by Narendra K , * Jordan Hargrave * + * PCI Firmware Specification Revision 3.1 section 4.6.7 (DSM for Naming a + * PCI or PCI Express Device Under Operating Systems) defines an instance + * number and string name. This code retrieves them and exports them to sysfs. + * If the system firmware does not provide the ACPI _DSM (Device Specific + * Method), then the SMBIOS type 41 instance number and string is exported to + * sysfs. + * * SMBIOS defines type 41 for onboard pci devices. This code retrieves * the instance number and string from the type 41 record and exports * it to sysfs. @@ -19,8 +26,30 @@ #include #include #include +#include +#include +#include +#include +#include #include "pci.h" +#define DEVICE_LABEL_DSM 0x07 + +#ifndef CONFIG_DMI + +static inline int +pci_create_smbiosname_file(struct pci_dev *pdev) +{ + return -1; +} + +static inline void +pci_remove_smbiosname_file(struct pci_dev *pdev) +{ +} + +#else + enum smbios_attr_enum { SMBIOS_ATTR_NONE = 0, SMBIOS_ATTR_LABEL_SHOW, @@ -120,9 +149,7 @@ static struct attribute_group smbios_attr_group = { static int pci_create_smbiosname_file(struct pci_dev *pdev) { - if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group)) - return 0; - return -ENODEV; + return sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group); } static void @@ -131,13 +158,221 @@ pci_remove_smbiosname_file(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); } +#endif + +#ifndef CONFIG_ACPI + +static inline int +pci_create_acpi_index_label_files(struct pci_dev *pdev) +{ + return -1; +} + +static inline int +pci_remove_acpi_index_label_files(struct pci_dev *pdev) +{ + return -1; +} + +#else + +static const char device_label_dsm_uuid[] = { + 0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D, + 0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D +}; + +enum acpi_attr_enum { + ACPI_ATTR_NONE = 0, + ACPI_ATTR_LABEL_SHOW, + ACPI_ATTR_INDEX_SHOW, +}; + +static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) +{ + int len; + len = utf16s_to_utf8s((const wchar_t *)obj-> + package.elements[1].string.pointer, + obj->package.elements[1].string.length, + UTF16_LITTLE_ENDIAN, + buf, PAGE_SIZE); + buf[len] = '\n'; +} + +static int +dsm_get_label(acpi_handle handle, int func, + struct acpi_buffer *output, + char *buf, enum acpi_attr_enum attribute) +{ + struct acpi_object_list input; + union acpi_object params[4]; + union acpi_object *obj; + int len = 0; + + int err; + + input.count = 4; + input.pointer = params; + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = sizeof(device_label_dsm_uuid); + params[0].buffer.pointer = (char *)device_label_dsm_uuid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = 0x02; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + + err = acpi_evaluate_object(handle, "_DSM", &input, output); + if (err) + return -1; + + obj = (union acpi_object *)output->pointer; + + switch (obj->type) { + case ACPI_TYPE_PACKAGE: + if (obj->package.count != 2) + break; + len = obj->package.elements[0].integer.value; + if (buf) { + if (attribute == ACPI_ATTR_INDEX_SHOW) + scnprintf(buf, PAGE_SIZE, "%llu\n", + obj->package.elements[0].integer.value); + else if (attribute == ACPI_ATTR_LABEL_SHOW) + dsm_label_utf16s_to_utf8s(obj, buf); + kfree(output->pointer); + return strlen(buf); + } + kfree(output->pointer); + return len; + break; + default: + kfree(output->pointer); + } + return -1; +} + +static bool +device_has_dsm(struct device *dev) +{ + acpi_handle handle; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + + handle = DEVICE_ACPI_HANDLE(dev); + + if (!handle) + return FALSE; + + if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL, + ACPI_ATTR_NONE) > 0) + return TRUE; + + return FALSE; +} + +static mode_t +acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) +{ + struct device *dev; + + dev = container_of(kobj, struct device, kobj); + + if (device_has_dsm(dev)) + return S_IRUGO; + + return 0; +} + +static ssize_t +acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_handle handle; + int length; + + handle = DEVICE_ACPI_HANDLE(dev); + + if (!handle) + return -1; + + length = dsm_get_label(handle, DEVICE_LABEL_DSM, + &output, buf, ACPI_ATTR_LABEL_SHOW); + + if (length < 1) + return -1; + + return length; +} + +static ssize_t +acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_handle handle; + int length; + + handle = DEVICE_ACPI_HANDLE(dev); + + if (!handle) + return -1; + + length = dsm_get_label(handle, DEVICE_LABEL_DSM, + &output, buf, ACPI_ATTR_INDEX_SHOW); + + if (length < 0) + return -1; + + return length; + +} + +static struct device_attribute acpi_attr_label = { + .attr = {.name = "label", .mode = 0444}, + .show = acpilabel_show, +}; + +static struct device_attribute acpi_attr_index = { + .attr = {.name = "acpi_index", .mode = 0444}, + .show = acpiindex_show, +}; + +static struct attribute *acpi_attributes[] = { + &acpi_attr_label.attr, + &acpi_attr_index.attr, + NULL, +}; + +static struct attribute_group acpi_attr_group = { + .attrs = acpi_attributes, + .is_visible = acpi_index_string_exist, +}; + +static int +pci_create_acpi_index_label_files(struct pci_dev *pdev) +{ + return sysfs_create_group(&pdev->dev.kobj, &acpi_attr_group); +} + +static int +pci_remove_acpi_index_label_files(struct pci_dev *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group); + return 0; +} +#endif + void pci_create_firmware_label_files(struct pci_dev *pdev) { - if (!pci_create_smbiosname_file(pdev)) - ; + if (device_has_dsm(&pdev->dev)) + pci_create_acpi_index_label_files(pdev); + else + pci_create_smbiosname_file(pdev); } void pci_remove_firmware_label_files(struct pci_dev *pdev) { - pci_remove_smbiosname_file(pdev); + if (device_has_dsm(&pdev->dev)) + pci_remove_acpi_index_label_files(pdev); + else + pci_remove_smbiosname_file(pdev); } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index f69d6e0fda75..a6ec200fe5ee 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -11,7 +11,7 @@ extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); -#ifndef CONFIG_DMI +#if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI) static inline void pci_create_firmware_label_files(struct pci_dev *pdev) { return; } static inline void pci_remove_firmware_label_files(struct pci_dev *pdev) -- cgit v1.2.3 From 47e9037ac16637cd7f12b8790ea7ce6680e42168 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 28 Feb 2011 16:20:11 +0000 Subject: PCI hotplug: acpiphp: set current_state to D0 in register_slot If a device doesn't support power management (pm_cap == 0) but it is acpi_pci_power_manageable() because there is a _PS0 method declared for it and _EJ0 is also declared for the slot then nobody is going to set current_state = PCI_D0 for this device. This is what I think it is happening: pci_enable_device | __pci_enable_device_flags /* here we do not set current_state because !pm_cap */ | do_pci_enable_device | pci_set_power_state | __pci_start_power_transition | pci_platform_power_transition /* platform_pci_power_manageable() calls acpi_pci_power_manageable that * returns true */ | platform_pci_set_power_state /* acpi_pci_set_power_state gets called and does nothing because the * acpi device has _EJ0, see the comment "If the ACPI device has _EJ0, * ignore the device" */ at this point if we refer to the commit message that introduced the comment above (10b3dcae0f275e2546e55303d64ddbb58cec7599), it is up to the hotplug driver to set the state to D0. However AFAICT the pci hotplug driver never does, in fact drivers/pci/hotplug/acpiphp_glue.c:register_slot sets the slot flags to (SLOT_ENABLED | SLOT_POWEREDON) but it does not set the pci device current state to PCI_D0. So my proposed fix is also to set current_state = PCI_D0 in register_slot. Comments are very welcome. Signed-off-by: Stefano Stabellini Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/acpiphp_glue.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cb23aa2ebf96..e610cfe4f07b 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -212,6 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); if (pdev) { + pdev->current_state = PCI_D0; slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); pci_dev_put(pdev); } -- cgit v1.2.3 From 87e3dc3855430bd254370afc79f2ed92250f5b7c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 28 Feb 2011 10:45:10 +0100 Subject: PCI: do not create quirk I/O regions below PCIBIOS_MIN_IO for ICH Some broken BIOSes on ICH4 chipset report an ACPI region which is in conflict with legacy IDE ports when ACPI is disabled. Even though the regions overlap, IDE ports are working correctly (we cannot find out the decoding rules on chipsets). So the only problem is the reported region itself, if we don't reserve the region in the quirk everything works as expected. This patch avoids reserving any quirk regions below PCIBIOS_MIN_IO which is 0x1000. Some regions might be (and are by a fast google query) below this border, but the only difference is that they won't be reserved anymore. They should still work though the same as before. The conflicts look like (1f.0 is bridge, 1f.1 is IDE ctrl): pci 0000:00:1f.1: address space collision: [io 0x0170-0x0177] conflicts with 0000:00:1f.0 [io 0x0100-0x017f] At 0x0100 a 128 bytes long ACPI region is reported in the quirk for ICH4. ata_piix then fails to find disks because the IDE legacy ports are zeroed: ata_piix 0000:00:1f.1: device not available (can't reserve [io 0x0000-0x0007]) References: https://bugzilla.novell.com/show_bug.cgi?id=558740 Signed-off-by: Jiri Slaby Cc: Bjorn Helgaas Cc: "David S. Miller" Cc: Thomas Renninger Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 9e23912c97ac..bd80f6378463 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -554,18 +554,30 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) u32 region; u8 enable; + /* + * The check for PCIBIOS_MIN_IO is to ensure we won't create a conflict + * with low legacy (and fixed) ports. We don't know the decoding + * priority and can't tell whether the legacy device or the one created + * here is really at that address. This happens on boards with broken + * BIOSes. + */ + pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable); if (enable & ICH4_ACPI_EN) { pci_read_config_dword(dev, ICH_PMBASE, ®ion); - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, - "ICH4 ACPI/GPIO/TCO"); + region &= PCI_BASE_ADDRESS_IO_MASK; + if (region >= PCIBIOS_MIN_IO) + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, + "ICH4 ACPI/GPIO/TCO"); } pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable); if (enable & ICH4_GPIO_EN) { pci_read_config_dword(dev, ICH4_GPIOBASE, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES + 1, - "ICH4 GPIO"); + region &= PCI_BASE_ADDRESS_IO_MASK; + if (region >= PCIBIOS_MIN_IO) + quirk_io_region(dev, region, 64, + PCI_BRIDGE_RESOURCES + 1, "ICH4 GPIO"); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi); @@ -587,15 +599,19 @@ static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev) pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable); if (enable & ICH6_ACPI_EN) { pci_read_config_dword(dev, ICH_PMBASE, ®ion); - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, - "ICH6 ACPI/GPIO/TCO"); + region &= PCI_BASE_ADDRESS_IO_MASK; + if (region >= PCIBIOS_MIN_IO) + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, + "ICH6 ACPI/GPIO/TCO"); } pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable); if (enable & ICH4_GPIO_EN) { pci_read_config_dword(dev, ICH6_GPIOBASE, ®ion); - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES + 1, - "ICH6 GPIO"); + region &= PCI_BASE_ADDRESS_IO_MASK; + if (region >= PCIBIOS_MIN_IO) + quirk_io_region(dev, region, 64, + PCI_BRIDGE_RESOURCES + 1, "ICH6 GPIO"); } } -- cgit v1.2.3 From 13583b16592a9a85093dd9aa3d4e8cd76e4f0cd4 Mon Sep 17 00:00:00 2001 From: Ram Pai Date: Mon, 14 Feb 2011 17:43:17 -0800 Subject: PCI: refactor io size calculation code Refactor code that calculates the io size in pbus_size_io() and pbus_mem_io() into separate functions. Signed-off-by: Ram Pai Signed-off-by: Jesse Barnes --- drivers/pci/setup-bus.c | 66 +++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 24 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 66cb8f4cc5f4..21212155eaba 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -404,6 +404,43 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon return NULL; } +static resource_size_t calculate_iosize(resource_size_t size, + resource_size_t min_size, + resource_size_t size1, + resource_size_t old_size, + resource_size_t align) +{ + if (size < min_size) + size = min_size; + if (old_size == 1 ) + old_size = 0; + /* To be fixed in 2.5: we should have sort of HAVE_ISA + flag in the struct pci_bus. */ +#if defined(CONFIG_ISA) || defined(CONFIG_EISA) + size = (size & 0xff) + ((size & ~0xffUL) << 2); +#endif + size = ALIGN(size + size1, align); + if (size < old_size) + size = old_size; + return size; +} + +static resource_size_t calculate_memsize(resource_size_t size, + resource_size_t min_size, + resource_size_t size1, + resource_size_t old_size, + resource_size_t align) +{ + if (size < min_size) + size = min_size; + if (old_size == 1 ) + old_size = 0; + if (size < old_size) + size = old_size; + size = ALIGN(size + size1, align); + return size; +} + /* Sizing the IO windows of the PCI-PCI bridge is trivial, since these windows have 4K granularity and the IO ranges of non-bridge PCI devices are limited to 256 bytes. @@ -412,7 +449,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) { struct pci_dev *dev; struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); - unsigned long size = 0, size1 = 0, old_size; + unsigned long size = 0, size1 = 0; if (!b_res) return; @@ -435,19 +472,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) size1 += r_size; } } - if (size < min_size) - size = min_size; - old_size = resource_size(b_res); - if (old_size == 1) - old_size = 0; -/* To be fixed in 2.5: we should have sort of HAVE_ISA - flag in the struct pci_bus. */ -#if defined(CONFIG_ISA) || defined(CONFIG_EISA) - size = (size & 0xff) + ((size & ~0xffUL) << 2); -#endif - size = ALIGN(size + size1, 4096); - if (size < old_size) - size = old_size; + size = calculate_iosize(size, min_size, size1, + resource_size(b_res), 4096); if (!size) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " @@ -468,7 +494,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type, resource_size_t min_size) { struct pci_dev *dev; - resource_size_t min_align, align, size, old_size; + resource_size_t min_align, align, size; resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, type); @@ -516,14 +542,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, mem64_mask &= r->flags & IORESOURCE_MEM_64; } } - if (size < min_size) - size = min_size; - old_size = resource_size(b_res); - if (old_size == 1) - old_size = 0; - if (size < old_size) - size = old_size; - align = 0; min_align = 0; for (order = 0; order <= max_order; order++) { @@ -537,7 +555,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = align1 >> 1; align += aligns[order]; } - size = ALIGN(size, min_align); + size = calculate_memsize(size, min_size, 0, resource_size(b_res), align); if (!size) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " -- cgit v1.2.3 From 094732a520caae81ae1532af29da82a4fa953472 Mon Sep 17 00:00:00 2001 From: Ram Pai Date: Mon, 14 Feb 2011 17:43:18 -0800 Subject: PCI: data structure agnostic free list function Replace free_failed_list() with a free_list() call. free_list() can handle 'resource_list_x', 'resource_list' and any linked list linked through ->next Signed-off-by: Ram Pai Signed-off-by: Jesse Barnes --- drivers/pci/setup-bus.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 21212155eaba..bcf5752f6907 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -36,6 +36,16 @@ struct resource_list_x { unsigned long flags; }; +#define free_list(type, head) do { \ + struct type *list, *tmp; \ + for (list = (head)->next; list;) { \ + tmp = list; \ + list = list->next; \ + kfree(tmp); \ + } \ + (head)->next = NULL; \ +} while (0) + static void add_to_failed_list(struct resource_list_x *head, struct pci_dev *dev, struct resource *res) { @@ -58,19 +68,6 @@ static void add_to_failed_list(struct resource_list_x *head, list->next = tmp; } -static void free_failed_list(struct resource_list_x *head) -{ - struct resource_list_x *list, *tmp; - - for (list = head->next; list;) { - tmp = list; - list = list->next; - kfree(tmp); - } - - head->next = NULL; -} - static void __dev_sort_resources(struct pci_dev *dev, struct resource_list *head) { @@ -900,7 +897,7 @@ again: if (tried_times >= 2) { /* still fail, don't need to try more */ - free_failed_list(&head); + free_list(resource_list_x, &head); goto enable_all; } @@ -931,7 +928,7 @@ again: list = list->next; } - free_failed_list(&head); + free_list(resource_list_x, &head); goto again; -- cgit v1.2.3 From fc075e1da1b96ef65c32e83648055606b8204b58 Mon Sep 17 00:00:00 2001 From: Ram Pai Date: Mon, 14 Feb 2011 17:43:19 -0800 Subject: PCI: introduce reset_resource() Introduce reset_resource() which factors out resource reset logic. Signed-off-by: Ram Pai Signed-off-by: Jesse Barnes --- drivers/pci/setup-bus.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index bcf5752f6907..a94ecc161208 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -88,6 +88,13 @@ static void __dev_sort_resources(struct pci_dev *dev, pdev_sort_resources(dev, head); } +static inline void reset_resource(struct resource *res) +{ + res->start = 0; + res->end = 0; + res->flags = 0; +} + static void __assign_resources_sorted(struct resource_list *head, struct resource_list_x *fail_head) { @@ -109,9 +116,7 @@ static void __assign_resources_sorted(struct resource_list *head, (!(res->flags & IORESOURCE_ROM_ENABLE)))) add_to_failed_list(fail_head, list->dev, res); } - res->start = 0; - res->end = 0; - res->flags = 0; + reset_resource(res); } tmp = list; list = list->next; -- cgit v1.2.3 From c8adf9a3e873eddaaec11ac410a99ef6b9656938 Mon Sep 17 00:00:00 2001 From: Ram Pai Date: Mon, 14 Feb 2011 17:43:20 -0800 Subject: PCI: pre-allocate additional resources to devices only after successful allocation of essential resources. Linux tries to pre-allocate minimal resources to hotplug bridges. This works fine as long as there are enough resources to satisfy all other genuine resource requirements. However if enough resources are not available to satisfy any of these nice-to-have pre-allocations, the resource-allocator reports errors and returns failure. This patch distinguishes between must-have resource from nice-to-have resource. Any failure to allocate nice-to-have resources are ignored. This behavior can be particularly useful to trigger automatic reallocation when the OS discovers genuine allocation-conflicts or genuine unallocated-requests caused by buggy allocation behavior of the native BIOS/uEFI. https://bugzilla.kernel.org/show_bug.cgi?id=15960 captures the movitation behind the patch. This patch is verified to resolve the above bug. changelog v2: o fixed a bug where pci_assign_resource() was called on a resource of zero resource size. changelog v3: addressed Bjorn's comment o "Please don't indent and right-justify the changelog". o removed add_size from struct resource. The additional size is now tracked using a linked list. changelog v4: o moved freeing up of elements in head list from assign_requested_resources_sorted() to __assign_resources_sorted(). o removed a wrong reference to 'add_size' in pbus_size_mem(). o some code optimizations in adjust_resources_sorted() and assign_requested_resources_sorted() changelog v5: o moved freeing up of elements in head list from assign_requested_resources_sorted() to __assign_resources_sorted(). o removed a wrong reference to 'add_size' in pbus_size_mem(). o some code optimizations in adjust_resources_sorted() and assign_requested_resources_sorted() changelog v5: o factored out common code and made them into separate independent patches o added comments in kdoc format o added a BUG_ON in pci_assign_unassigned_resources() to catch for memory leak. Signed-off-by: Ram Pai Signed-off-by: Jesse Barnes --- drivers/pci/setup-bus.c | 231 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 184 insertions(+), 47 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a94ecc161208..89d0a6a88df7 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -33,6 +33,7 @@ struct resource_list_x { struct pci_dev *dev; resource_size_t start; resource_size_t end; + resource_size_t add_size; unsigned long flags; }; @@ -46,8 +47,18 @@ struct resource_list_x { (head)->next = NULL; \ } while (0) -static void add_to_failed_list(struct resource_list_x *head, - struct pci_dev *dev, struct resource *res) +/** + * add_to_list() - add a new resource tracker to the list + * @head: Head of the list + * @dev: device corresponding to which the resource + * belongs + * @res: The resource to be tracked + * @add_size: additional size to be optionally added + * to the resource + */ +static void add_to_list(struct resource_list_x *head, + struct pci_dev *dev, struct resource *res, + resource_size_t add_size) { struct resource_list_x *list = head; struct resource_list_x *ln = list->next; @@ -55,7 +66,7 @@ static void add_to_failed_list(struct resource_list_x *head, tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { - pr_warning("add_to_failed_list: kmalloc() failed!\n"); + pr_warning("add_to_list: kmalloc() failed!\n"); return; } @@ -65,9 +76,16 @@ static void add_to_failed_list(struct resource_list_x *head, tmp->start = res->start; tmp->end = res->end; tmp->flags = res->flags; + tmp->add_size = add_size; list->next = tmp; } +static void add_to_failed_list(struct resource_list_x *head, + struct pci_dev *dev, struct resource *res) +{ + add_to_list(head, dev, res, 0); +} + static void __dev_sort_resources(struct pci_dev *dev, struct resource_list *head) { @@ -95,18 +113,81 @@ static inline void reset_resource(struct resource *res) res->flags = 0; } -static void __assign_resources_sorted(struct resource_list *head, - struct resource_list_x *fail_head) +/** + * adjust_resources_sorted() - satisfy any additional resource requests + * + * @add_head : head of the list tracking requests requiring additional + * resources + * @head : head of the list tracking requests with allocated + * resources + * + * Walk through each element of the add_head and try to procure + * additional resources for the element, provided the element + * is in the head list. + */ +static void adjust_resources_sorted(struct resource_list_x *add_head, + struct resource_list *head) { struct resource *res; - struct resource_list *list, *tmp; + struct resource_list_x *list, *tmp, *prev; + struct resource_list *hlist; + resource_size_t add_size; int idx; - for (list = head->next; list;) { + prev = add_head; + for (list = add_head->next; list;) { res = list->res; + /* skip resource that has been reset */ + if (!res->flags) + goto out; + + /* skip this resource if not found in head list */ + for (hlist = head->next; hlist && hlist->res != res; + hlist = hlist->next); + if (!hlist) { /* just skip */ + prev = list; + list = list->next; + continue; + } + idx = res - &list->dev->resource[0]; + add_size=list->add_size; + if (!resource_size(res) && add_size) { + res->end = res->start + add_size - 1; + if(pci_assign_resource(list->dev, idx)) + reset_resource(res); + } else if (add_size) { + adjust_resource(res, res->start, + resource_size(res) + add_size); + } +out: + tmp = list; + prev->next = list = list->next; + kfree(tmp); + } +} + +/** + * assign_requested_resources_sorted() - satisfy resource requests + * + * @head : head of the list tracking requests for resources + * @failed_list : head of the list tracking requests that could + * not be allocated + * + * Satisfy resource requests of each element in the list. Add + * requests that could not satisfied to the failed_list. + */ +static void assign_requested_resources_sorted(struct resource_list *head, + struct resource_list_x *fail_head) +{ + struct resource *res; + struct resource_list *list; + int idx; - if (pci_assign_resource(list->dev, idx)) { + for (list = head->next; list; list = list->next) { + res = list->res; + idx = res - &list->dev->resource[0]; + if (resource_size(res) && pci_assign_resource(list->dev, idx)) { if (fail_head && !pci_is_root_bus(list->dev->bus)) { /* * if the failed res is for ROM BAR, and it will @@ -118,12 +199,23 @@ static void __assign_resources_sorted(struct resource_list *head, } reset_resource(res); } - tmp = list; - list = list->next; - kfree(tmp); } } +static void __assign_resources_sorted(struct resource_list *head, + struct resource_list_x *add_head, + struct resource_list_x *fail_head) +{ + /* Satisfy the must-have resource requests */ + assign_requested_resources_sorted(head, fail_head); + + /* Try to satisfy any additional nice-to-have resource + requests */ + if (add_head) + adjust_resources_sorted(add_head, head); + free_list(resource_list, head); +} + static void pdev_assign_resources_sorted(struct pci_dev *dev, struct resource_list_x *fail_head) { @@ -131,11 +223,12 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev, head.next = NULL; __dev_sort_resources(dev, &head); - __assign_resources_sorted(&head, fail_head); + __assign_resources_sorted(&head, NULL, fail_head); } static void pbus_assign_resources_sorted(const struct pci_bus *bus, + struct resource_list_x *add_head, struct resource_list_x *fail_head) { struct pci_dev *dev; @@ -145,7 +238,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus, list_for_each_entry(dev, &bus->devices, bus_list) __dev_sort_resources(dev, &head); - __assign_resources_sorted(&head, fail_head); + __assign_resources_sorted(&head, add_head, fail_head); } void pci_setup_cardbus(struct pci_bus *bus) @@ -443,15 +536,25 @@ static resource_size_t calculate_memsize(resource_size_t size, return size; } -/* Sizing the IO windows of the PCI-PCI bridge is trivial, - since these windows have 4K granularity and the IO ranges - of non-bridge PCI devices are limited to 256 bytes. - We must be careful with the ISA aliasing though. */ -static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) +/** + * pbus_size_io() - size the io window of a given bus + * + * @bus : the bus + * @min_size : the minimum io window that must to be allocated + * @add_size : additional optional io window + * @add_head : track the additional io window on this list + * + * Sizing the IO windows of the PCI-PCI bridge is trivial, + * since these windows have 4K granularity and the IO ranges + * of non-bridge PCI devices are limited to 256 bytes. + * We must be careful with the ISA aliasing though. + */ +static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, + resource_size_t add_size, struct resource_list_x *add_head) { struct pci_dev *dev; struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); - unsigned long size = 0, size1 = 0; + unsigned long size = 0, size0 = 0, size1 = 0; if (!b_res) return; @@ -474,9 +577,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) size1 += r_size; } } - size = calculate_iosize(size, min_size, size1, + size0 = calculate_iosize(size, min_size, size1, + resource_size(b_res), 4096); + size1 = !add_size? size0: + calculate_iosize(size, min_size+add_size, size1, resource_size(b_res), 4096); - if (!size) { + if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " "%pR to [bus %02x-%02x] (unused)\n", b_res, @@ -486,17 +592,30 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) } /* Alignment of the IO window is always 4K */ b_res->start = 4096; - b_res->end = b_res->start + size - 1; + b_res->end = b_res->start + size0 - 1; b_res->flags |= IORESOURCE_STARTALIGN; + if (size1 > size0 && add_head) + add_to_list(add_head, bus->self, b_res, size1-size0); } -/* Calculate the size of the bus and minimal alignment which - guarantees that all child resources fit in this size. */ +/** + * pbus_size_mem() - size the memory window of a given bus + * + * @bus : the bus + * @min_size : the minimum memory window that must to be allocated + * @add_size : additional optional memory window + * @add_head : track the additional memory window on this list + * + * Calculate the size of the bus and minimal alignment which + * guarantees that all child resources fit in this size. + */ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, - unsigned long type, resource_size_t min_size) + unsigned long type, resource_size_t min_size, + resource_size_t add_size, + struct resource_list_x *add_head) { struct pci_dev *dev; - resource_size_t min_align, align, size; + resource_size_t min_align, align, size, size0, size1; resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, type); @@ -557,8 +676,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = align1 >> 1; align += aligns[order]; } - size = calculate_memsize(size, min_size, 0, resource_size(b_res), align); - if (!size) { + size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), align); + size1 = !add_size ? size : + calculate_memsize(size, min_size+add_size, 0, + resource_size(b_res), align); + if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " "%pR to [bus %02x-%02x] (unused)\n", b_res, @@ -567,9 +689,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, return 1; } b_res->start = min_align; - b_res->end = size + min_align - 1; - b_res->flags |= IORESOURCE_STARTALIGN; - b_res->flags |= mem64_mask; + b_res->end = size0 + min_align - 1; + b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; + if (size1 > size0 && add_head) + add_to_list(add_head, bus->self, b_res, size1-size0); return 1; } @@ -622,11 +745,12 @@ static void pci_bus_size_cardbus(struct pci_bus *bus) } } -void __ref pci_bus_size_bridges(struct pci_bus *bus) +void __ref __pci_bus_size_bridges(struct pci_bus *bus, + struct resource_list_x *add_head) { struct pci_dev *dev; unsigned long mask, prefmask; - resource_size_t min_mem_size = 0, min_io_size = 0; + resource_size_t additional_mem_size = 0, additional_io_size = 0; list_for_each_entry(dev, &bus->devices, bus_list) { struct pci_bus *b = dev->subordinate; @@ -640,7 +764,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) case PCI_CLASS_BRIDGE_PCI: default: - pci_bus_size_bridges(b); + __pci_bus_size_bridges(b, add_head); break; } } @@ -657,11 +781,14 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) case PCI_CLASS_BRIDGE_PCI: pci_bridge_check_ranges(bus); if (bus->self->is_hotplug_bridge) { - min_io_size = pci_hotplug_io_size; - min_mem_size = pci_hotplug_mem_size; + additional_io_size = pci_hotplug_io_size; + additional_mem_size = pci_hotplug_mem_size; } + /* + * Follow thru + */ default: - pbus_size_io(bus, min_io_size); + pbus_size_io(bus, 0, additional_io_size, add_head); /* If the bridge supports prefetchable range, size it separately. If it doesn't, or its prefetchable window has already been allocated by arch code, try @@ -669,30 +796,36 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) resources. */ mask = IORESOURCE_MEM; prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; - if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size)) + if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head)) mask = prefmask; /* Success, size non-prefetch only. */ else - min_mem_size += min_mem_size; - pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size); + additional_mem_size += additional_mem_size; + pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head); break; } } + +void __ref pci_bus_size_bridges(struct pci_bus *bus) +{ + __pci_bus_size_bridges(bus, NULL); +} EXPORT_SYMBOL(pci_bus_size_bridges); static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, + struct resource_list_x *add_head, struct resource_list_x *fail_head) { struct pci_bus *b; struct pci_dev *dev; - pbus_assign_resources_sorted(bus, fail_head); + pbus_assign_resources_sorted(bus, add_head, fail_head); list_for_each_entry(dev, &bus->devices, bus_list) { b = dev->subordinate; if (!b) continue; - __pci_bus_assign_resources(b, fail_head); + __pci_bus_assign_resources(b, add_head, fail_head); switch (dev->class >> 8) { case PCI_CLASS_BRIDGE_PCI: @@ -714,7 +847,7 @@ static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, void __ref pci_bus_assign_resources(const struct pci_bus *bus) { - __pci_bus_assign_resources(bus, NULL); + __pci_bus_assign_resources(bus, NULL, NULL); } EXPORT_SYMBOL(pci_bus_assign_resources); @@ -729,7 +862,7 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, if (!b) return; - __pci_bus_assign_resources(b, fail_head); + __pci_bus_assign_resources(b, NULL, fail_head); switch (bridge->class >> 8) { case PCI_CLASS_BRIDGE_PCI: @@ -862,17 +995,21 @@ void __init pci_assign_unassigned_resources(void) { struct pci_bus *bus; - + struct resource_list_x add_list; /* list of resources that + want additional resources */ + add_list.next = NULL; /* Depth first, calculate sizes and alignments of all subordinate buses. */ list_for_each_entry(bus, &pci_root_buses, node) { - pci_bus_size_bridges(bus); + __pci_bus_size_bridges(bus, &add_list); } + /* Depth last, allocate resources and update the hardware. */ list_for_each_entry(bus, &pci_root_buses, node) { - pci_bus_assign_resources(bus); + __pci_bus_assign_resources(bus, &add_list, NULL); pci_enable_bridges(bus); } + BUG_ON(add_list.next); /* dump the resource on buses */ list_for_each_entry(bus, &pci_root_buses, node) { -- cgit v1.2.3 From aa33860158114d0df3c7997bc1dd41c0168e1c2a Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Fri, 11 Feb 2011 00:06:54 +0100 Subject: PM: Remove CONFIG_PM_OPS After redefining CONFIG_PM to depend on (CONFIG_PM_SLEEP || CONFIG_PM_RUNTIME) the CONFIG_PM_OPS option is redundant and can be replaced with CONFIG_PM. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 4 ++-- drivers/base/power/Makefile | 3 +-- drivers/net/e1000e/netdev.c | 8 ++++---- drivers/net/pch_gbe/pch_gbe_main.c | 2 +- drivers/pci/pci-driver.c | 4 ++-- drivers/scsi/Makefile | 2 +- drivers/scsi/scsi_priv.h | 2 +- drivers/scsi/scsi_sysfs.c | 2 +- drivers/usb/core/hcd-pci.c | 4 ++-- include/acpi/acpi_bus.h | 2 +- include/linux/pm.h | 2 +- kernel/power/Kconfig | 5 ----- 12 files changed, 17 insertions(+), 23 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index d6a8cd14de2e..8ea092fad3f6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -585,7 +585,7 @@ int acpi_suspend(u32 acpi_state) return -EINVAL; } -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM /** * acpi_pm_device_sleep_state - return preferred power state of ACPI device * in the system sleep state given by %acpi_target_sleep_state @@ -671,7 +671,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) *d_min_p = d_min; return d_max; } -#endif /* CONFIG_PM_OPS */ +#endif /* CONFIG_PM */ #ifdef CONFIG_PM_SLEEP /** diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index abe46edfe5b4..118c1b92a511 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,7 +1,6 @@ -obj-$(CONFIG_PM) += sysfs.o +obj-$(CONFIG_PM) += sysfs.o generic_ops.o obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o obj-$(CONFIG_PM_RUNTIME) += runtime.o -obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 2e5022849f18..6d513a383340 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -5338,7 +5338,7 @@ void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) __e1000e_disable_aspm(pdev, state); } -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM static bool e1000e_pm_ready(struct e1000_adapter *adapter) { return !!adapter->tx_ring->buffer_info; @@ -5489,7 +5489,7 @@ static int e1000_runtime_resume(struct device *dev) return __e1000_resume(pdev); } #endif /* CONFIG_PM_RUNTIME */ -#endif /* CONFIG_PM_OPS */ +#endif /* CONFIG_PM */ static void e1000_shutdown(struct pci_dev *pdev) { @@ -6196,7 +6196,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM static const struct dev_pm_ops e1000_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume) SET_RUNTIME_PM_OPS(e1000_runtime_suspend, @@ -6210,7 +6210,7 @@ static struct pci_driver e1000_driver = { .id_table = e1000_pci_tbl, .probe = e1000_probe, .remove = __devexit_p(e1000_remove), -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM .driver.pm = &e1000_pm_ops, #endif .shutdown = e1000_shutdown, diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index b99e90aca37d..8c66e22c3a0a 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -2446,7 +2446,7 @@ static struct pci_driver pch_gbe_pcidev = { .id_table = pch_gbe_pcidev_id, .probe = pch_gbe_probe, .remove = pch_gbe_remove, -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM .driver.pm = &pch_gbe_pm_ops, #endif .shutdown = pch_gbe_shutdown, diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 88246dd46452..d86ea8b01137 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -431,7 +431,7 @@ static void pci_device_shutdown(struct device *dev) pci_msix_shutdown(pci_dev); } -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM /* Auxiliary functions used for system resume and run-time resume. */ @@ -1059,7 +1059,7 @@ static int pci_pm_runtime_idle(struct device *dev) #endif /* !CONFIG_PM_RUNTIME */ -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM const struct dev_pm_ops pci_dev_pm_ops = { .prepare = pci_pm_prepare, diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 2e9a87e8e7d8..ef6de669424b 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -165,7 +165,7 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o scsi_mod-y += scsi_trace.o -scsi_mod-$(CONFIG_PM_OPS) += scsi_pm.o +scsi_mod-$(CONFIG_PM) += scsi_pm.o scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index b4056d14f812..342ee1a9c41d 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -146,7 +146,7 @@ static inline void scsi_netlink_exit(void) {} #endif /* scsi_pm.c */ -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM extern const struct dev_pm_ops scsi_bus_pm_ops; #endif #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 490ce213204e..e44ff64233fd 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -383,7 +383,7 @@ struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .uevent = scsi_bus_uevent, -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif }; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index f71e8e307e0f..64a035ba2eab 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -335,7 +335,7 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM #ifdef CONFIG_PPC_PMAC static void powermac_set_asic(struct pci_dev *pci_dev, int enable) @@ -580,4 +580,4 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = { }; EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); -#endif /* CONFIG_PM_OPS */ +#endif /* CONFIG_PM */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 78ca429929f7..ff103ba96b78 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -381,7 +381,7 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); int acpi_disable_wakeup_device_power(struct acpi_device *dev); -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM int acpi_pm_device_sleep_state(struct device *, int *); #else static inline int acpi_pm_device_sleep_state(struct device *d, int *p) diff --git a/include/linux/pm.h b/include/linux/pm.h index 21415cc91cbb..9279175a4557 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -267,7 +267,7 @@ const struct dev_pm_ops name = { \ * callbacks provided by device drivers supporting both the system sleep PM and * runtime PM, make the pm member point to generic_subsys_pm_ops. */ -#ifdef CONFIG_PM_OPS +#ifdef CONFIG_PM extern struct dev_pm_ops generic_subsys_pm_ops; #define GENERIC_SUBSYS_PM_OPS (&generic_subsys_pm_ops) #else diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 1e4d9238c5da..0710beead05b 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -220,11 +220,6 @@ config APM_EMULATION anything, try disabling/enabling this option (or disabling/enabling APM in your BIOS). -config PM_OPS - bool - depends on PM_SLEEP || PM_RUNTIME - default y - config ARCH_HAS_OPP bool -- cgit v1.2.3 From 07eefe1ca542129c24833c96ceb83b9aaa3b458d Mon Sep 17 00:00:00 2001 From: Narendra_K@Dell.com Date: Mon, 7 Mar 2011 12:55:56 -0800 Subject: PCI: label: Fix compilation error when CONFIG_ACPI is unset This patch fixes compilation error descibed below introduced by the commit 6058989bad05b82e78baacce69ec14f27a11b5fd drivers/pci/pci-label.c: In function ‘pci_create_firmware_label_files’: drivers/pci/pci-label.c:366:2: error: implicit declaration of function ‘device_has_dsm’ Signed-off-by: Narendra K Signed-off-by: Jesse Barnes --- drivers/pci/pci-label.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index 824e247edc58..8c80138bb66f 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -174,6 +174,12 @@ pci_remove_acpi_index_label_files(struct pci_dev *pdev) return -1; } +static inline bool +device_has_dsm(struct device *dev) +{ + return false; +} + #else static const char device_label_dsm_uuid[] = { -- cgit v1.2.3 From 65d8defe2e13fbebd74f96d2b5ca9aad435e6648 Mon Sep 17 00:00:00 2001 From: Shyam_Iyer@Dell.com Date: Fri, 11 Mar 2011 03:35:56 +0530 Subject: PCI: label: remove #include of ACPI header to avoid warnings I found that including acpi/apci_drivers.h is not necessary and introduces these warnings: In file included from drivers/pci/pci-label.c:32: include/acpi/acpi_drivers.h:103: warning: ‘struct acpi_device’ declared inside parameter list include/acpi/acpi_drivers.h:103: warning: its scope is only this definition or declaration, which is probably not what you want include/acpi/acpi_drivers.h:107: warning: ‘struct acpi_pci_root’ declared inside parameter list Signed-off-by: Shyam Iyer Signed-off-by: Jesse Barnes --- drivers/pci/pci-label.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index 8c80138bb66f..77cb2a14c896 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include "pci.h" -- cgit v1.2.3 From 700598cef866011b878f389c30414d31fa5bb87b Mon Sep 17 00:00:00 2001 From: GuanXuetao Date: Sat, 15 Jan 2011 18:25:14 +0800 Subject: unicore32 machine related files: pci bus handling This patch implements arch-specific pci bus driver. Signed-off-by: Guan Xuetao --- arch/unicore32/include/asm/pci.h | 46 +++++ arch/unicore32/kernel/pci.c | 404 +++++++++++++++++++++++++++++++++++++++ drivers/pci/Makefile | 1 + 3 files changed, 451 insertions(+) create mode 100644 arch/unicore32/include/asm/pci.h create mode 100644 arch/unicore32/kernel/pci.c (limited to 'drivers/pci') diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h new file mode 100644 index 000000000000..c5b28b459535 --- /dev/null +++ b/arch/unicore32/include/asm/pci.h @@ -0,0 +1,46 @@ +/* + * linux/arch/unicore32/include/asm/pci.h + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __UNICORE_PCI_H__ +#define __UNICORE_PCI_H__ + +#ifdef __KERNEL__ +#include +#include +#include /* for PCIBIOS_MIN_* */ + +static inline void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + +static inline void pcibios_penalize_isa_irq(int irq, int active) +{ + /* We don't do dynamic PCI IRQ allocation */ +} + +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + +#define HAVE_PCI_MMAP +extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); + +#endif /* __KERNEL__ */ + +#endif diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c new file mode 100644 index 000000000000..d4e55e2d2d29 --- /dev/null +++ b/arch/unicore32/kernel/pci.c @@ -0,0 +1,404 @@ +/* + * linux/arch/unicore32/kernel/pci.c + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * PCI bios-type initialisation for PCI machines + * + */ +#include +#include +#include +#include +#include +#include +#include + +static int debug_pci; +static int use_firmware; + +#define CONFIG_CMD(bus, devfn, where) \ + (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) + +static int +puv3_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + PCICFG_ADDR = CONFIG_CMD(bus, devfn, where); + switch (size) { + case 1: + *value = (PCICFG_DATA >> ((where & 3) * 8)) & 0xFF; + break; + case 2: + *value = (PCICFG_DATA >> ((where & 2) * 8)) & 0xFFFF; + break; + case 4: + *value = PCICFG_DATA; + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int +puv3_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + PCICFG_ADDR = CONFIG_CMD(bus, devfn, where); + switch (size) { + case 1: + PCICFG_DATA = (PCICFG_DATA & ~FMASK(8, (where&3)*8)) + | FIELD(value, 8, (where&3)*8); + break; + case 2: + PCICFG_DATA = (PCICFG_DATA & ~FMASK(16, (where&2)*8)) + | FIELD(value, 16, (where&2)*8); + break; + case 4: + PCICFG_DATA = value; + break; + } + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops pci_puv3_ops = { + .read = puv3_read_config, + .write = puv3_write_config, +}; + +void pci_puv3_preinit(void) +{ + printk(KERN_DEBUG "PCI: PKUnity PCI Controller Initializing ...\n"); + /* config PCI bridge base */ + PCICFG_BRIBASE = PKUNITY_PCIBRI_BASE; + + PCIBRI_AHBCTL0 = 0; + PCIBRI_AHBBAR0 = PKUNITY_PCIBRI_BASE | PCIBRI_BARx_MEM; + PCIBRI_AHBAMR0 = 0xFFFF0000; + PCIBRI_AHBTAR0 = 0; + + PCIBRI_AHBCTL1 = PCIBRI_CTLx_AT; + PCIBRI_AHBBAR1 = PKUNITY_PCILIO_BASE | PCIBRI_BARx_IO; + PCIBRI_AHBAMR1 = 0xFFFF0000; + PCIBRI_AHBTAR1 = 0x00000000; + + PCIBRI_AHBCTL2 = PCIBRI_CTLx_PREF; + PCIBRI_AHBBAR2 = PKUNITY_PCIMEM_BASE | PCIBRI_BARx_MEM; + PCIBRI_AHBAMR2 = 0xF8000000; + PCIBRI_AHBTAR2 = 0; + + PCIBRI_BAR1 = PKUNITY_PCIAHB_BASE | PCIBRI_BARx_MEM; + + PCIBRI_PCICTL0 = PCIBRI_CTLx_AT | PCIBRI_CTLx_PREF; + PCIBRI_PCIBAR0 = PKUNITY_PCIAHB_BASE | PCIBRI_BARx_MEM; + PCIBRI_PCIAMR0 = 0xF8000000; + PCIBRI_PCITAR0 = PKUNITY_SDRAM_BASE; + + PCIBRI_CMD = PCIBRI_CMD | PCIBRI_CMD_IO | PCIBRI_CMD_MEM; +} + +static int __init pci_puv3_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->bus->number == 0) { +#ifdef CONFIG_ARCH_FPGA /* 4 pci slots */ + if (dev->devfn == 0x00) + return IRQ_PCIINTA; + else if (dev->devfn == 0x08) + return IRQ_PCIINTB; + else if (dev->devfn == 0x10) + return IRQ_PCIINTC; + else if (dev->devfn == 0x18) + return IRQ_PCIINTD; +#endif +#ifdef CONFIG_PUV3_DB0913 /* 3 pci slots */ + if (dev->devfn == 0x30) + return IRQ_PCIINTB; + else if (dev->devfn == 0x60) + return IRQ_PCIINTC; + else if (dev->devfn == 0x58) + return IRQ_PCIINTD; +#endif +#if defined(CONFIG_PUV3_NB0916) || defined(CONFIG_PUV3_SMW0919) + /* only support 2 pci devices */ + if (dev->devfn == 0x00) + return IRQ_PCIINTC; /* sata */ +#endif + } + return -1; +} + +/* + * Only first 128MB of memory can be accessed via PCI. + * We use GFP_DMA to allocate safe buffers to do map/unmap. + * This is really ugly and we need a better way of specifying + * DMA-capable regions of memory. + */ +void __init puv3_pci_adjust_zones(unsigned long *zone_size, + unsigned long *zhole_size) +{ + unsigned int sz = SZ_128M >> PAGE_SHIFT; + + /* + * Only adjust if > 128M on current system + */ + if (zone_size[0] <= sz) + return; + + zone_size[1] = zone_size[0] - sz; + zone_size[0] = sz; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + +void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) +{ + if (debug_pci) + printk(KERN_DEBUG "PCI: Assigning IRQ %02d to %s\n", + irq, pci_name(dev)); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +/* + * If the bus contains any of these devices, then we must not turn on + * parity checking of any kind. + */ +static inline int pdev_bad_for_parity(struct pci_dev *dev) +{ + return 0; +} + +/* + * pcibios_fixup_bus - Called after each bus is probed, + * but before its children are examined. + */ +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + u16 features = PCI_COMMAND_SERR + | PCI_COMMAND_PARITY + | PCI_COMMAND_FAST_BACK; + + bus->resource[0] = &ioport_resource; + bus->resource[1] = &iomem_resource; + + /* + * Walk the devices on this bus, working out what we can + * and can't support. + */ + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 status; + + pci_read_config_word(dev, PCI_STATUS, &status); + + /* + * If any device on this bus does not support fast back + * to back transfers, then the bus as a whole is not able + * to support them. Having fast back to back transfers + * on saves us one PCI cycle per transaction. + */ + if (!(status & PCI_STATUS_FAST_BACK)) + features &= ~PCI_COMMAND_FAST_BACK; + + if (pdev_bad_for_parity(dev)) + features &= ~(PCI_COMMAND_SERR + | PCI_COMMAND_PARITY); + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status); + status |= PCI_BRIDGE_CTL_PARITY + | PCI_BRIDGE_CTL_MASTER_ABORT; + status &= ~(PCI_BRIDGE_CTL_BUS_RESET + | PCI_BRIDGE_CTL_FAST_BACK); + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status); + break; + + case PCI_CLASS_BRIDGE_CARDBUS: + pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, + &status); + status |= PCI_CB_BRIDGE_CTL_PARITY + | PCI_CB_BRIDGE_CTL_MASTER_ABORT; + pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, + status); + break; + } + } + + /* + * Now walk the devices again, this time setting them up. + */ + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 cmd; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= features; + pci_write_config_word(dev, PCI_COMMAND, cmd); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + L1_CACHE_BYTES >> 2); + } + + /* + * Propagate the flags to the PCI bridge. + */ + if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + if (features & PCI_COMMAND_FAST_BACK) + bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK; + if (features & PCI_COMMAND_PARITY) + bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY; + } + + /* + * Report what we did for this bus + */ + printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", + bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); +} +#ifdef CONFIG_HOTPLUG +EXPORT_SYMBOL(pcibios_fixup_bus); +#endif + +static int __init pci_common_init(void) +{ + struct pci_bus *puv3_bus; + + pci_puv3_preinit(); + + puv3_bus = pci_scan_bus(0, &pci_puv3_ops, NULL); + + if (!puv3_bus) + panic("PCI: unable to scan bus!"); + + pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq); + + if (!use_firmware) { + /* + * Size the bridge windows. + */ + pci_bus_size_bridges(puv3_bus); + + /* + * Assign resources. + */ + pci_bus_assign_resources(puv3_bus); + } + + /* + * Tell drivers about devices found. + */ + pci_bus_add_devices(puv3_bus); + + return 0; +} +subsys_initcall(pci_common_init); + +char * __devinit pcibios_setup(char *str) +{ + if (!strcmp(str, "debug")) { + debug_pci = 1; + return NULL; + } else if (!strcmp(str, "firmware")) { + use_firmware = 1; + return NULL; + } + return str; +} + +/* + * From arch/i386/kernel/pci-i386.c: + * + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might be mirrored at 0x0100-0x03ff.. + */ +resource_size_t pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + resource_size_t start = res->start; + + if (res->flags & IORESOURCE_IO && start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + + start = (start + align - 1) & ~(align - 1); + + return start; +} + +/** + * pcibios_enable_device - Enable I/O and memory. + * @dev: PCI device to be enabled + */ +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1 << idx))) + continue; + + r = dev->resource + idx; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because" + " of resource collisions\n", pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + + /* + * Bridges (eg, cardbus bridges) need to be fully enabled + */ + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + + if (cmd != old_cmd) { + printk("PCI: enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + unsigned long phys; + + if (mmap_state == pci_mmap_io) + return -EINVAL; + + phys = vma->vm_pgoff; + + /* + * Mark this as IO + */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_pfn_range(vma, vma->vm_start, phys, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98e6fdf34d30..77cf813ba264 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o obj-$(CONFIG_X86) += setup-bus.o obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o +obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_PPC) += setup-bus.o -- cgit v1.2.3