From 04846b5b8112e53b588038349b3e92b8485c1807 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Mon, 20 Apr 2009 10:54:52 +0900 Subject: [PATCH 01/74] PCI MSI: Remove unused/obsolete macros and definitions Impact: cleanup, spec compliance This patch does: - Remove unused msi/msix_enable/disable macros. User should use msi/msix_set_enable() functions instead. - Remove unused msix_mask/unmask/pending macros. These macros are useless because they are not based on any of the PCI Local Bus Specifications properly. It seems that they were written based on a draft of PCI spec, and that the draft was the MSI-X ECN that underwent membership review in September 2002. (* In the draft, the size of a entry in MSI-X table was 64bit, containing 32bit message data and DWORD aligned lower address plus a pending bit and a mask bit.(30+1+1bit) The higher address was placed in MSI-X capability structure and shared by all entries.) - Remove PCI_MSIX_FLAGS_BITMASK. This definition also come from the draft ECN. Signed-off-by: Hidetoshi Seto Reviewed-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/pci/msi.h | 8 +------- include/linux/pci_regs.h | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 71f4df2ef654..4fed59261952 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -19,18 +19,12 @@ ( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 ) #define msi_mask_bits_reg(base, is64bit) \ ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4) -#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE #define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) #define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) #define msix_table_offset_reg(base) (base + 0x04) #define msix_pba_offset_reg(base) (base + 0x08) -#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE -#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE #define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1) -#define multi_msix_capable msix_table_size -#define msix_unmask(address) (address & ~PCI_MSIX_FLAGS_BITMASK) -#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) -#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) +#define multi_msix_capable(control) msix_table_size((control)) #endif /* MSI_H */ diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 616bf8b3c8b5..dcba7668e0cd 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -304,7 +304,6 @@ #define PCI_MSIX_FLAGS_ENABLE (1 << 15) #define PCI_MSIX_FLAGS_MASKALL (1 << 14) #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) -#define PCI_MSIX_FLAGS_BITMASK (1 << 0) /* CompactPCI Hotswap Register */ From ad4efa359dcded8f76c94768f9deb1f79f950090 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Apr 2009 15:20:11 -0700 Subject: [PATCH 02/74] PCIE: remove driver_data direct access of struct device In the near future, the driver core is going to not allow direct access to the driver_data pointer in struct device. Instead, the functions dev_get_drvdata() and dev_set_drvdata() should be used. These functions have been around since the beginning, so are backwards compatible with all older kernel versions. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Jesse Barnes --- drivers/pci/pcie/portdrv_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index e39982503863..13ffdc35ea0e 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -275,7 +275,7 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, memset(device, 0, sizeof(struct device)); device->bus = &pcie_port_bus_type; device->driver = NULL; - device->driver_data = NULL; + dev_set_drvdata(device, NULL); device->release = release_pcie_device; /* callback to free pcie dev */ dev_set_name(device, "%s:pcie%02x", pci_name(parent), get_descriptor_id(port_type, service_type)); From 64f039d3d7f574943165b1afb72ee25caa1a9a91 Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Wed, 15 Apr 2009 14:24:08 -0700 Subject: [PATCH 03/74] PCI: ibmphp_core.c: fix warning due to missing module_exit() drivers/pci/hotplug/ibmphp_core.c:1414: warning: `ibmphp_exit' defined but not used Signed-off-by: Zhenwen Xu Signed-off-by: Andrew Morton Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/ibmphp_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index dd18f857dfb0..29ccb8a6da8a 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -1419,3 +1419,4 @@ static void __exit ibmphp_exit(void) } module_init(ibmphp_init); +module_exit(ibmphp_exit); From 67b5db6502ddd27d65dea43bf036abbd82d0dfc9 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Mon, 20 Apr 2009 10:54:59 +0900 Subject: [PATCH 04/74] PCI MSI: Define PCI_MSI_MASK_32/64 Impact: cleanup, improve readability Define PCI_MSI_MASK_32/64 for 32/64bit devices, instead of using implicit offset (-4), "PCI_MSI_MASK_BIT - 4" and "PCI_MSI_MASK_BIT". Signed-off-by: Hidetoshi Seto Reviewed-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 2 +- drivers/pci/msi.h | 6 +++--- include/linux/pci_regs.h | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 362773247fbf..7ffac27d5d4a 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -381,7 +381,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.pos = pos; - entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); + entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64); /* All MSIs are unmasked by default, Mask them all */ if (entry->msi_attrib.maskbit) pci_read_config_dword(dev, entry->mask_pos, &entry->masked); diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4fed59261952..a0662842550b 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -16,9 +16,9 @@ #define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) #define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI) #define msi_data_reg(base, is64bit) \ - ( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 ) -#define msi_mask_bits_reg(base, is64bit) \ - ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4) + (base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32)) +#define msi_mask_reg(base, is64bit) \ + (base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32)) #define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) #define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index dcba7668e0cd..83b02f5a25b2 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -295,8 +295,9 @@ #define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ #define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ #define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ +#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ #define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ -#define PCI_MSI_MASK_BIT 16 /* Mask bits register */ +#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ /* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */ #define PCI_MSIX_FLAGS 2 From 1f82de10d6b1d845155363c895c552e61b36b51a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 23 Apr 2009 20:48:32 -0700 Subject: [PATCH 05/74] PCI/x86: don't assume prefetchable ranges are 64bit We should not assign 64bit ranges to PCI devices that only take 32bit prefetchable addresses. Try to set IORESOURCE_MEM_64 in 64bit resource of pci_device/pci_bridge and make the bus resource only have that bit set when all devices under it support 64bit prefetchable memory. Use that flag to allocate resources from that range. Reported-by: Yannick Reviewed-by: Ivan Kokshaysky Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes --- arch/x86/include/asm/pci.h | 1 + drivers/pci/bus.c | 7 ++++- drivers/pci/probe.c | 9 +++++-- drivers/pci/setup-bus.c | 52 ++++++++++++++++++++++++++++++-------- include/linux/ioport.h | 2 ++ include/linux/pci.h | 4 +++ 6 files changed, 62 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index b51a1e8b0baf..927958d13c19 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -130,6 +130,7 @@ extern void pci_iommu_alloc(void); /* generic pci stuff */ #include +#define PCIBIOS_MAX_MEM_32 0xffffffff #ifdef CONFIG_NUMA /* Returns the node based on pci bus */ diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 97a8194063b5..40af27f31043 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -41,9 +41,14 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void *alignf_data) { int i, ret = -ENOMEM; + resource_size_t max = -1; type_mask |= IORESOURCE_IO | IORESOURCE_MEM; + /* don't allocate too high if the pref mem doesn't support 64bit*/ + if (!(res->flags & IORESOURCE_MEM_64)) + max = PCIBIOS_MAX_MEM_32; + for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { struct resource *r = bus->resource[i]; if (!r) @@ -62,7 +67,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, /* Ok, try it out.. */ ret = allocate_resource(r, res, size, r->start ? : min, - -1, align, + max, align, alignf, alignf_data); if (ret == 0) break; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f1ae2475ffff..b962326e3d95 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -193,7 +193,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; if (type == pci_bar_io) { l &= PCI_BASE_ADDRESS_IO_MASK; - mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff; + mask = PCI_BASE_ADDRESS_IO_MASK & IO_SPACE_LIMIT; } else { l &= PCI_BASE_ADDRESS_MEM_MASK; mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; @@ -237,6 +237,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, dev_printk(KERN_DEBUG, &dev->dev, "reg %x 64bit mmio: %pR\n", pos, res); } + + res->flags |= IORESOURCE_MEM_64; } else { sz = pci_size(l, sz, mask); @@ -362,7 +364,10 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) } } if (base <= limit) { - res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; + res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | + IORESOURCE_MEM | IORESOURCE_PREFETCH; + if (res->flags & PCI_PREF_RANGE_TYPE_64) + res->flags |= IORESOURCE_MEM_64; res->start = base; res->end = limit + 0xfffff; dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n", diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a00f85471b6e..e1c360a5b0db 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -143,6 +143,7 @@ static void pci_setup_bridge(struct pci_bus *bus) struct pci_dev *bridge = bus->self; struct pci_bus_region region; u32 l, bu, lu, io_upper16; + int pref_mem64; if (pci_is_enabled(bridge)) return; @@ -198,16 +199,22 @@ static void pci_setup_bridge(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ + pref_mem64 = 0; bu = lu = 0; pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { + int width = 8; l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - bu = upper_32_bits(region.start); - lu = upper_32_bits(region.end); - dev_info(&bridge->dev, " PREFETCH window: %#016llx-%#016llx\n", - (unsigned long long)region.start, - (unsigned long long)region.end); + if (bus->resource[2]->flags & IORESOURCE_MEM_64) { + pref_mem64 = 1; + bu = upper_32_bits(region.start); + lu = upper_32_bits(region.end); + width = 16; + } + dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", + width, (unsigned long long)region.start, + width, (unsigned long long)region.end); } else { l = 0x0000fff0; @@ -215,9 +222,11 @@ static void pci_setup_bridge(struct pci_bus *bus) } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - /* Set the upper 32 bits of PREF base & limit. */ - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); - pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); + if (pref_mem64) { + /* Set the upper 32 bits of PREF base & limit. */ + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); + } pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -255,8 +264,25 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); } - if (pmem) + if (pmem) { b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; + if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) + b_res[2].flags |= IORESOURCE_MEM_64; + } + + /* double check if bridge does support 64 bit pref */ + if (b_res[2].flags & IORESOURCE_MEM_64) { + u32 mem_base_hi, tmp; + pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, + &mem_base_hi); + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, + 0xffffffff); + pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp); + if (!tmp) + b_res[2].flags &= ~IORESOURCE_MEM_64; + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, + mem_base_hi); + } } /* Helper function for sizing routines: find first available @@ -336,6 +362,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, type); + unsigned int mem64_mask = 0; if (!b_res) return 0; @@ -344,9 +371,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long max_order = 0; size = 0; + mem64_mask = b_res->flags & IORESOURCE_MEM_64; + b_res->flags &= ~IORESOURCE_MEM_64; + list_for_each_entry(dev, &bus->devices, bus_list) { int i; - + for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; resource_size_t r_size; @@ -372,6 +402,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long aligns[order] += align; if (order > max_order) max_order = order; + mem64_mask &= r->flags & IORESOURCE_MEM_64; } } @@ -396,6 +427,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long b_res->start = min_align; b_res->end = size + min_align - 1; b_res->flags |= IORESOURCE_STARTALIGN; + b_res->flags |= mem64_mask; return 1; } diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 32e4b2f72294..786e7b8cece9 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -49,6 +49,8 @@ struct resource_list { #define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ #define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ +#define IORESOURCE_MEM_64 0x00100000 + #define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ #define IORESOURCE_DISABLED 0x10000000 #define IORESOURCE_UNSET 0x20000000 diff --git a/include/linux/pci.h b/include/linux/pci.h index 72698d89e767..6dfa47d25ba4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1097,6 +1097,10 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, #include +#ifndef PCIBIOS_MAX_MEM_32 +#define PCIBIOS_MAX_MEM_32 (-1) +#endif + /* these helpers provide future and backwards compatibility * for accessing popular PCI BAR info */ #define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) From d09ee9687e027fc7d2c6b95daf05a8ef3ff06340 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 23 Apr 2009 20:49:25 -0700 Subject: [PATCH 06/74] PCI: improve resource allocation under transparent bridges We could run out of space under under 4g, but devices under transparent bridges can use 64bit resources, so keep trying on the parent bus until we hit a non-transparent bridge. Impact: better support for assigning unassigned resources Reviewed-by: Ivan Kokshaysky Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes --- drivers/pci/setup-bus.c | 1 - drivers/pci/setup-res.c | 49 ++++++++++++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index e1c360a5b0db..b636e245445d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -58,7 +58,6 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus) res = list->res; idx = res - &list->dev->resource[0]; if (pci_assign_resource(list->dev, idx)) { - /* FIXME: get rid of this */ res->start = 0; res->end = 0; res->flags = 0; diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 3039fcb86afc..0b6908b48935 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -135,23 +135,16 @@ void pci_disable_bridge_window(struct pci_dev *dev) } #endif /* CONFIG_PCI_QUIRKS */ -int pci_assign_resource(struct pci_dev *dev, int resno) +static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, + int resno) { - struct pci_bus *bus = dev->bus; struct resource *res = dev->resource + resno; resource_size_t size, min, align; int ret; size = resource_size(res); min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; - align = resource_alignment(res); - if (!align) { - dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " - "alignment) %pR flags %#lx\n", - resno, res, res->flags); - return -EINVAL; - } /* First, try exact prefetching match.. */ ret = pci_bus_alloc_resource(bus, res, size, align, min, @@ -169,10 +162,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) pcibios_align_resource, dev); } - if (ret) { - dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", - resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); - } else { + if (!ret) { res->flags &= ~IORESOURCE_STARTALIGN; if (resno < PCI_BRIDGE_RESOURCES) pci_update_resource(dev, resno); @@ -181,6 +171,39 @@ int pci_assign_resource(struct pci_dev *dev, int resno) return ret; } +int pci_assign_resource(struct pci_dev *dev, int resno) +{ + struct resource *res = dev->resource + resno; + resource_size_t align; + struct pci_bus *bus; + int ret; + + align = resource_alignment(res); + if (!align) { + dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " + "alignment) %pR flags %#lx\n", + resno, res, res->flags); + return -EINVAL; + } + + bus = dev->bus; + while ((ret = __pci_assign_resource(bus, dev, resno))) { + if (bus->parent && bus->self->transparent) + bus = bus->parent; + else + bus = NULL; + if (bus) + continue; + break; + } + + if (ret) + dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", + resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); + + return ret; +} + #if 0 int pci_assign_resource_fixed(struct pci_dev *dev, int resno) { From 861fefbf550d41e7a4f44584f3ec35977fa08bf1 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:11 -0600 Subject: [PATCH 07/74] PCI Hotplug: cpqphp: stray whitespace cleanups Clean up all stray whitespace issues, such as trailing whitespace, spaces before tabs, etc. and whatever else vim's c_space_errors highlights in red. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp.h | 58 ++++++++++---------- drivers/pci/hotplug/cpqphp_core.c | 56 ++++++++----------- drivers/pci/hotplug/cpqphp_ctrl.c | 86 +++++++++++++++--------------- drivers/pci/hotplug/cpqphp_nvram.c | 18 +++---- drivers/pci/hotplug/cpqphp_pci.c | 14 ++--- 5 files changed, 110 insertions(+), 122 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index afaf8f69f73e..b627dfd74500 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -150,25 +150,25 @@ struct ctrl_reg { /* offset */ /* offsets to the controller registers based on the above structure layout */ enum ctrl_offsets { - SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), MISC = offsetof(struct ctrl_reg, misc), LED_CONTROL = offsetof(struct ctrl_reg, led_control), INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), - INT_MASK = offsetof(struct ctrl_reg, int_mask), - CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), - GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), - NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), - SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), - CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), @@ -220,15 +220,15 @@ struct slot_rt { /* offsets to the hotplug slot resource table registers based on the above structure layout */ enum slot_rt_offsets { DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), }; struct pci_func { @@ -471,7 +471,7 @@ static inline void return_resource(struct pci_resource **head, struct pci_resour static inline void set_SOGO(struct controller *ctrl) { u16 misc; - + misc = readw(ctrl->hpc_reg + MISC); misc = (misc | 0x0001) & 0xFFFB; writew(misc, ctrl->hpc_reg + MISC); @@ -481,7 +481,7 @@ static inline void set_SOGO(struct controller *ctrl) static inline void amber_LED_on(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control |= (0x01010000L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -491,7 +491,7 @@ static inline void amber_LED_on(struct controller *ctrl, u8 slot) static inline void amber_LED_off(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x01010000L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -504,7 +504,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot) led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= (0x01010000L << slot); - + return led_control ? 1 : 0; } @@ -512,7 +512,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot) static inline void green_LED_on(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control |= 0x0101L << slot; writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -521,7 +521,7 @@ static inline void green_LED_on(struct controller *ctrl, u8 slot) static inline void green_LED_off(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x0101L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -531,7 +531,7 @@ static inline void green_LED_off(struct controller *ctrl, u8 slot) static inline void green_LED_blink(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x0101L << slot); led_control |= (0x0001L << slot); @@ -586,11 +586,11 @@ static inline u8 read_slot_enable(struct controller *ctrl) static inline u8 get_controller_speed(struct controller *ctrl) { u8 curr_freq; - u16 misc; - + u16 misc; + if (ctrl->pcix_support) { curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); - if ((curr_freq & 0xB0) == 0xB0) + if ((curr_freq & 0xB0) == 0xB0) return PCI_SPEED_133MHz_PCIX; if ((curr_freq & 0xA0) == 0xA0) return PCI_SPEED_100MHz_PCIX; @@ -602,10 +602,10 @@ static inline u8 get_controller_speed(struct controller *ctrl) return PCI_SPEED_33MHz; } - misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; } - + /* * get_adapter_speed - find the max supported frequency/mode of adapter. diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index c2e1bcbb28a7..55eae4c233c9 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -25,7 +25,7 @@ * Send feedback to * * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, - * Torben Mathiasen + * Torben Mathiasen * */ @@ -100,8 +100,8 @@ static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, }; @@ -144,7 +144,7 @@ static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *e break; } } - + if (!status) fp = NULL; @@ -292,7 +292,7 @@ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, if (!smbios_table) return NULL; - if (!previous) { + if (!previous) { previous = smbios_start; } else { previous = get_subsequent_smbios_entry(smbios_start, @@ -300,7 +300,7 @@ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, } while (previous) { - if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); } else { @@ -426,7 +426,7 @@ static int ctrl_slot_setup(struct controller *ctrl, cpq_get_latch_status(ctrl, slot); hotplug_slot_info->adapter_status = get_presence_status(ctrl, slot); - + dbg("registering bus %d, dev %d, number %d, " "ctrl->slot_device_offset %d, slot %d\n", slot->bus, slot->device, @@ -440,7 +440,7 @@ static int ctrl_slot_setup(struct controller *ctrl, err("pci_hp_register failed with error %d\n", result); goto error_info; } - + slot->next = ctrl->slot; ctrl->slot = slot; @@ -563,9 +563,9 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) } - // If we got here, we didn't find an entry in the IRQ mapping table - // for the target PCI device. If we did determine that the target - // device is on the other side of a PCI-to-PCI bridge, return the + // If we got here, we didn't find an entry in the IRQ mapping table + // for the target PCI device. If we did determine that the target + // device is on the other side of a PCI-to-PCI bridge, return the // slot number for the bridge. if (bridgeSlot != 0xFF) { *slot = bridgeSlot; @@ -719,7 +719,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); - return cpqhp_hardware_test(ctrl, value); + return cpqhp_hardware_test(ctrl, value); } @@ -738,7 +738,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_attention_status(ctrl, slot); @@ -832,7 +832,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Check for the proper subsytem ID's - * Intel uses a different SSID programming model than Compaq. + * Intel uses a different SSID programming model than Compaq. * For Intel, each SSID bit identifies a PHP capability. * Also Intel HPC's may have RID=0. */ @@ -1087,7 +1087,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { goto err_free_bus; } - + dbg("pdev = %p\n", pdev); dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0)); dbg("pci resource len %llx\n", (unsigned long long)pci_resource_len(pdev, 0)); @@ -1182,7 +1182,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) __func__, rc); goto err_iounmap; } - + /* Mask all general input interrupts */ writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); @@ -1291,7 +1291,6 @@ err_disable_device: return rc; } - static int one_time_init(void) { int loop; @@ -1328,10 +1327,10 @@ static int one_time_init(void) retval = -EIO; goto error; } - + /* Now, map the int15 entry point if we are on compaq specific hardware */ compaq_nvram_init(cpqhp_rom_start); - + /* Map smbios table entry point structure */ smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); @@ -1361,7 +1360,6 @@ error: return retval; } - static void __exit unload_cpqphpd(void) { struct pci_func *next; @@ -1381,10 +1379,10 @@ static void __exit unload_cpqphpd(void) if (ctrl->hpc_reg) { u16 misc; rc = read_slot_enable (ctrl); - + writeb(0, ctrl->hpc_reg + SLOT_SERR); writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); - + misc = readw(ctrl->hpc_reg + MISC); misc &= 0xFFFD; writew(misc, ctrl->hpc_reg + MISC); @@ -1475,27 +1473,23 @@ static void __exit unload_cpqphpd(void) iounmap(smbios_start); } - - static struct pci_device_id hpcd_pci_tbl[] = { { /* handle any PCI Hotplug controller */ .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), .class_mask = ~0, - + /* no matter who makes it */ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - + }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); - - static struct pci_driver cpqhpc_driver = { .name = "compaq_pci_hotplug", .id_table = hpcd_pci_tbl, @@ -1503,8 +1497,6 @@ static struct pci_driver cpqhpc_driver = { /* remove: cpqhpc_remove_one, */ }; - - static int __init cpqhpc_init(void) { int result; @@ -1518,7 +1510,6 @@ static int __init cpqhpc_init(void) return result; } - static void __exit cpqhpc_cleanup(void) { dbg("unload_cpqphpd()\n"); @@ -1529,8 +1520,5 @@ static void __exit cpqhpc_cleanup(void) cpqhp_shutdown_debugfs(); } - module_init(cpqhpc_init); module_exit(cpqhpc_cleanup); - - diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index cc227a8c4b11..ec3a76519af2 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -642,7 +642,7 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz return NULL; for (max = *head; max; max = max->next) { - /* If not big enough we could probably just bail, + /* If not big enough we could probably just bail, * instead we'll continue to the next. */ if (max->length < size) continue; @@ -886,7 +886,7 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) u32 Diff; u32 temp_dword; - + misc = readw(ctrl->hpc_reg + MISC); /*************************************** * Check to see if it was our interrupt @@ -1130,33 +1130,33 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); u16 reg16; u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); - + if (ctrl->speed == adapter_speed) return 0; - + /* We don't allow freq/mode changes if we find another adapter running * in another slot on this controller */ for(slot = ctrl->slot; slot; slot = slot->next) { - if (slot->device == (hp_slot + ctrl->slot_device_offset)) + if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; if (!slot->hotplug_slot || !slot->hotplug_slot->info) continue; - if (slot->hotplug_slot->info->adapter_status == 0) + if (slot->hotplug_slot->info->adapter_status == 0) continue; /* If another adapter is running on the same segment but at a * lower speed/mode, we allow the new adapter to function at * this rate if supported */ - if (ctrl->speed < adapter_speed) + if (ctrl->speed < adapter_speed) return 0; return 1; } - + /* If the controller doesn't support freq/mode changes and the * controller is running at a higher mode, we bail */ if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) return 1; - + /* But we allow the adapter to run at a lower rate if possible */ if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) return 0; @@ -1171,22 +1171,22 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ writel(0x0L, ctrl->hpc_reg + LED_CONTROL); writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); + + set_SOGO(ctrl); wait_for_ctrl_irq(ctrl); - + if (adapter_speed != PCI_SPEED_133MHz_PCIX) reg = 0xF5; else - reg = 0xF4; + reg = 0xF4; pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - + reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); reg16 &= ~0x000F; switch(adapter_speed) { - case(PCI_SPEED_133MHz_PCIX): + case(PCI_SPEED_133MHz_PCIX): reg = 0x75; - reg16 |= 0xB; + reg16 |= 0xB; break; case(PCI_SPEED_100MHz_PCIX): reg = 0x74; @@ -1203,47 +1203,47 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ default: /* 33MHz PCI 2.2 */ reg = 0x71; break; - + } reg16 |= 0xB << 12; writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); - - mdelay(5); - + + mdelay(5); + /* Reenable interrupts */ writel(0, ctrl->hpc_reg + INT_MASK); - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + /* Restart state machine */ reg = ~0xF; pci_read_config_byte(ctrl->pci_dev, 0x43, ®); pci_write_config_byte(ctrl->pci_dev, 0x43, reg); - + /* Only if mode change...*/ if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) set_SOGO(ctrl); - + wait_for_ctrl_irq(ctrl); mdelay(1100); - + /* Restore LED/Slot state */ writel(leds, ctrl->hpc_reg + LED_CONTROL); writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); - + set_SOGO(ctrl); wait_for_ctrl_irq(ctrl); ctrl->speed = adapter_speed; slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - info("Successfully changed frequency/mode for adapter in slot %d\n", + info("Successfully changed frequency/mode for adapter in slot %d\n", slot->number); return 0; } -/* the following routines constitute the bulk of the +/* the following routines constitute the bulk of the hotplug controller logic */ @@ -1299,7 +1299,7 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - + adapter_speed = get_adapter_speed(ctrl, hp_slot); if (ctrl->speed != adapter_speed) if (set_controller_speed(ctrl, adapter_speed, hp_slot)) @@ -1443,12 +1443,12 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - + adapter_speed = get_adapter_speed(ctrl, hp_slot); if (ctrl->speed != adapter_speed) if (set_controller_speed(ctrl, adapter_speed, hp_slot)) rc = WRONG_BUS_FREQUENCY; - + /* turn off board without attaching to the bus */ disable_slot_power (ctrl, hp_slot); @@ -1461,7 +1461,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) if (rc) return rc; - + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); /* turn on board and blink green LED */ @@ -1859,12 +1859,12 @@ static void interrupt_event_handler(struct controller *ctrl) info(msg_button_on, p_slot->number); } mutex_lock(&ctrl->crit_sect); - + dbg("blink green LED and turn off amber\n"); - + amber_LED_off (ctrl, hp_slot); green_LED_blink (ctrl, hp_slot); - + set_SOGO(ctrl); /* Wait for SOBS to be unset */ @@ -1958,7 +1958,7 @@ void cpqhp_pushbutton_thread(unsigned long slot) if (cpqhp_process_SI(ctrl, func) != 0) { amber_LED_on(ctrl, hp_slot); green_LED_off(ctrl, hp_slot); - + set_SOGO(ctrl); /* Wait for SOBS to be unset */ @@ -2079,7 +2079,7 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) struct pci_bus *pci_bus = ctrl->pci_bus; int physical_slot=0; - device = func->device; + device = func->device; func = cpqhp_slot_find(ctrl->bus, device, index++); p_slot = cpqhp_find_slot(ctrl, device); if (p_slot) { @@ -2216,7 +2216,7 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num) long_delay((3*HZ)/10); work_LED = work_LED >> 16; writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - + set_SOGO(ctrl); /* Wait for SOGO interrupt */ @@ -2339,7 +2339,7 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func /* - Configuration logic that involves the hotplug data structures and + Configuration logic that involves the hotplug data structures and their bookkeeping */ @@ -2917,17 +2917,17 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func } /* End of base register loop */ if (cpqhp_legacy_mode) { /* Figure out which interrupt pin this function uses */ - rc = pci_bus_read_config_byte (pci_bus, devfn, + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); /* If this function needs an interrupt and we are behind * a bridge and the pin is tied to something that's * alread mapped, set this one the same */ - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { /* We have to share with something already set up */ - IRQ = resources->irqs->interrupt[(temp_byte + + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; } else { /* Program IRQ based on card type */ diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index cb174888002b..76e110f0e3a6 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -113,7 +113,7 @@ static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) if ((*used + 1) > *avail) return(1); - + *((u8*)*p_buffer) = value; tByte = (u8**)p_buffer; (*tByte)++; @@ -170,10 +170,10 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) unsigned long flags; int op = operation; int ret_val; - + if (!compaq_int15_entry_point) return -ENODEV; - + spin_lock_irqsave(&int15_lock, flags); __asm__ ( "xorl %%ebx,%%ebx\n" \ @@ -187,7 +187,7 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) "D" (buffer), "m" (compaq_int15_entry_point) : "%ebx", "%edx"); spin_unlock_irqrestore(&int15_lock, flags); - + return((ret_val & 0xFF00) >> 8); } @@ -263,7 +263,7 @@ static u32 store_HRT (void __iomem *rom_start) p_EV_header = (struct ev_hrt_header *) pFill; ctrl = cpqhp_ctrl_list; - + // The revision of this structure rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); if (rc) @@ -401,7 +401,7 @@ static u32 store_HRT (void __iomem *rom_start) ctrl = ctrl->next; } - + p_EV_header->num_of_ctrl = numCtrl; // Now store the EV @@ -479,7 +479,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) function = p_ev_ctrl->function; while ((bus != ctrl->bus) || - (device != PCI_SLOT(ctrl->pci_dev->devfn)) || + (device != PCI_SLOT(ctrl->pci_dev->devfn)) || (function != PCI_FUNC(ctrl->pci_dev->devfn))) { nummem = p_ev_ctrl->mem_avail; numpmem = p_ev_ctrl->p_mem_avail; @@ -640,14 +640,14 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) if (rc) return(rc); } else { - if ((evbuffer[0] != 0) && (!ctrl->push_flag)) + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) return 1; } return 0; } - + int compaq_nvram_store (void __iomem *rom_start) { int rc = 1; diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 6c0ed0fcb8ee..573a2702fb6a 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -82,7 +82,7 @@ static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iom } -int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) { unsigned char bus; struct pci_bus *child; @@ -116,10 +116,10 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) } -int cpqhp_unconfigure_device(struct pci_func* func) +int cpqhp_unconfigure_device(struct pci_func* func) { int j; - + dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); for (j=0; j<8 ; j++) { @@ -195,8 +195,8 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) /* - * WTF??? This function isn't in the code, yet a function calls it, but the - * compiler optimizes it away? strange. Here as a placeholder to keep the + * WTF??? This function isn't in the code, yet a function calls it, but the + * compiler optimizes it away? strange. Here as a placeholder to keep the * compiler happy. */ static int PCI_ScanBusNonBridge (u8 bus, u8 device) @@ -398,7 +398,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) index = 0; new_slot = cpqhp_slot_find(busnumber, device, index++); - while (new_slot && + while (new_slot && (new_slot->function != (u8) function)) new_slot = cpqhp_slot_find(busnumber, device, index++); @@ -1168,7 +1168,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) * this function is for hot plug ADD! * * returns 0 if success - */ + */ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start) { u8 temp; From 427438c61b0083a60bb953cb36cfdc5841f0bb03 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:16 -0600 Subject: [PATCH 08/74] PCI Hotplug: cpqphp: fix comment style Fix up comments from C++ to C-style, wrapping if necessary, etc. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp.h | 22 +- drivers/pci/hotplug/cpqphp_core.c | 157 ++++++++------- drivers/pci/hotplug/cpqphp_ctrl.c | 131 +++++++----- drivers/pci/hotplug/cpqphp_nvram.c | 79 ++++---- drivers/pci/hotplug/cpqphp_pci.c | 313 ++++++++++++++++------------- 5 files changed, 387 insertions(+), 315 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index b627dfd74500..e15d657368f0 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -190,7 +190,9 @@ struct hrt { u32 reserved2; } __attribute__ ((packed)); -/* offsets to the hotplug resource table registers based on the above structure layout */ +/* offsets to the hotplug resource table registers based on the above + * structure layout + */ enum hrt_offsets { SIG0 = offsetof(struct hrt, sig0), SIG1 = offsetof(struct hrt, sig1), @@ -217,7 +219,9 @@ struct slot_rt { u16 pre_mem_length; } __attribute__ ((packed)); -/* offsets to the hotplug slot resource table registers based on the above structure layout */ +/* offsets to the hotplug slot resource table registers based on the above + * structure layout + */ enum slot_rt_offsets { DEV_FUNC = offsetof(struct slot_rt, dev_func), PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), @@ -286,8 +290,8 @@ struct event_info { struct controller { struct controller *next; u32 ctrl_int_comp; - struct mutex crit_sect; /* critical section mutex */ - void __iomem *hpc_reg; /* cookie for our pci controller location */ + struct mutex crit_sect; /* critical section mutex */ + void __iomem *hpc_reg; /* cookie for our pci controller location */ struct pci_resource *mem_head; struct pci_resource *p_mem_head; struct pci_resource *io_head; @@ -299,7 +303,7 @@ struct controller { u8 next_event; u8 interrupt; u8 cfgspc_irq; - u8 bus; /* bus number for the pci hotplug controller */ + u8 bus; /* bus number for the pci hotplug controller */ u8 rev; u8 slot_device_offset; u8 first_slot; @@ -458,7 +462,6 @@ static inline char *slot_name(struct slot *slot) * return_resource * * Puts node back in the resource list pointed to by head - * */ static inline void return_resource(struct pci_resource **head, struct pci_resource *node) { @@ -575,13 +578,12 @@ static inline u8 read_slot_enable(struct controller *ctrl) } -/* +/** * get_controller_speed - find the current frequency/mode of controller. * * @ctrl: controller to get frequency/mode for. * * Returns controller speed. - * */ static inline u8 get_controller_speed(struct controller *ctrl) { @@ -607,14 +609,13 @@ static inline u8 get_controller_speed(struct controller *ctrl) } -/* +/** * get_adapter_speed - find the max supported frequency/mode of adapter. * * @ctrl: hotplug controller. * @hp_slot: hotplug slot where adapter is installed. * * Returns adapter speed. - * */ static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot) { @@ -719,4 +720,3 @@ static inline int wait_for_ctrl_irq(struct controller *ctrl) } #endif - diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 55eae4c233c9..91dc95850cce 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -26,7 +26,6 @@ * * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, * Torben Mathiasen - * */ #include @@ -171,7 +170,7 @@ static int init_SERR(struct controller * ctrl) tempdword = ctrl->first_slot; number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // Loop through slots + /* Loop through slots */ while (number_of_slots) { physical_slot = tempdword; writeb(0, ctrl->hpc_reg + SLOT_SERR); @@ -200,7 +199,7 @@ static int pci_print_IRQ_route (void) len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry + /* Make sure I got at least one entry */ if (len == 0) { kfree(routing_table); return -1; @@ -244,7 +243,7 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, if (!smbios_table || !curr) return(NULL); - // set p_max to the end of the table + /* set p_max to the end of the table */ p_max = smbios_start + readw(smbios_table + ST_LENGTH); p_temp = curr; @@ -253,7 +252,8 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, while ((p_temp < p_max) && !bail) { /* Look for the double NULL terminator * The first condition is the previous byte - * and the second is the curr */ + * and the second is the curr + */ if (!previous_byte && !(readb(p_temp))) { bail = 1; } @@ -387,8 +387,9 @@ static int ctrl_slot_setup(struct controller *ctrl, slot->task_event.expires = jiffies + 5 * HZ; slot->task_event.function = cpqhp_pushbutton_thread; - //FIXME: these capabilities aren't used but if they are - // they need to be correctly implemented + /*FIXME: these capabilities aren't used but if they are + * they need to be correctly implemented + */ slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; @@ -402,14 +403,14 @@ static int ctrl_slot_setup(struct controller *ctrl, ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); - // Check presence + /* Check presence */ slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; - // Check the switch state + /* Check the switch state */ slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; - // Check the slot enable + /* Check the slot enable */ slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; @@ -476,11 +477,11 @@ static int ctrl_slot_cleanup (struct controller * ctrl) cpqhp_remove_debugfs_files(ctrl); - //Free IRQ associated with hot plug device + /* Free IRQ associated with hot plug device */ free_irq(ctrl->interrupt, ctrl); - //Unmap the memory + /* Unmap the memory */ iounmap(ctrl->hpc_reg); - //Finally reclaim PCI mem + /* Finally reclaim PCI mem */ release_mem_region(pci_resource_start(ctrl->pci_dev, 0), pci_resource_len(ctrl->pci_dev, 0)); @@ -488,20 +489,17 @@ static int ctrl_slot_cleanup (struct controller * ctrl) } -//============================================================================ -// function: get_slot_mapping -// -// Description: Attempts to determine a logical slot mapping for a PCI -// device. Won't work for more than one PCI-PCI bridge -// in a slot. -// -// Input: u8 bus_num - bus number of PCI device -// u8 dev_num - device number of PCI device -// u8 *slot - Pointer to u8 where slot number will -// be returned -// -// Output: SUCCESS or FAILURE -//============================================================================= +/** + * get_slot_mapping - determine logical slot mapping for PCI device + * + * Won't work for more than one PCI-PCI bridge in a slot. + * + * @bus_num - bus number of PCI device + * @dev_num - device number of PCI device + * @slot - Pointer to u8 where slot number will be returned + * + * Output: SUCCESS or FAILURE + */ static int get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) { @@ -522,7 +520,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) len = (PCIIRQRoutingInfoLength->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry + /* Make sure I got at least one entry */ if (len == 0) { kfree(PCIIRQRoutingInfoLength); return -1; @@ -539,13 +537,14 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) return 0; } else { /* Did not get a match on the target PCI device. Check - * if the current IRQ table entry is a PCI-to-PCI bridge - * device. If so, and it's secondary bus matches the - * bus number for the target device, I need to save the - * bridge's slot number. If I can not find an entry for - * the target device, I will have to assume it's on the - * other side of the bridge, and assign it the bridge's - * slot. */ + * if the current IRQ table entry is a PCI-to-PCI + * bridge device. If so, and it's secondary bus + * matches the bus number for the target device, I need + * to save the bridge's slot number. If I can not find + * an entry for the target device, I will have to + * assume it's on the other side of the bridge, and + * assign it the bridge's slot. + */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_CLASS_REVISION, &work); @@ -563,17 +562,18 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) } - // If we got here, we didn't find an entry in the IRQ mapping table - // for the target PCI device. If we did determine that the target - // device is on the other side of a PCI-to-PCI bridge, return the - // slot number for the bridge. + /* If we got here, we didn't find an entry in the IRQ mapping table for + * the target PCI device. If we did determine that the target device + * is on the other side of a PCI-to-PCI bridge, return the slot number + * for the bridge. + */ if (bridgeSlot != 0xFF) { *slot = bridgeSlot; kfree(PCIIRQRoutingInfoLength); return 0; } kfree(PCIIRQRoutingInfoLength); - // Couldn't find an entry in the routing table for this PCI device + /* Couldn't find an entry in the routing table for this PCI device */ return -1; } @@ -595,7 +595,7 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, hp_slot = func->device - ctrl->slot_device_offset; - // Wait for exclusive access to hardware + /* Wait for exclusive access to hardware */ mutex_lock(&ctrl->crit_sect); if (status == 1) { @@ -603,17 +603,17 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, } else if (status == 0) { amber_LED_off (ctrl, hp_slot); } else { - // Done with exclusive hardware access + /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); return(1); } set_SOGO(ctrl); - // Wait for SOBS to be unset + /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - // Done with exclusive hardware access + /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); return(0); @@ -815,7 +815,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } - // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery + /* Need to read VID early b/c it's used to differentiate CPQ and INTC + * discovery + */ rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { err(msg_HPC_non_compaq_or_intel); @@ -837,7 +839,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * Also Intel HPC's may have RID=0. */ if ((pdev->revision > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { - // TODO: This code can be made to support non-Compaq or Intel subsystem IDs + /* TODO: This code can be made to support non-Compaq or Intel + * subsystem IDs + */ rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); if (rc) { err("%s : pci_read_config_word failed\n", __func__); @@ -865,7 +869,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); - /* Set Vendor ID, so it can be accessed later from other functions */ + /* Set Vendor ID, so it can be accessed later from other + * functions + */ ctrl->vendor_id = vendor_id; switch (subsystem_vid) { @@ -992,23 +998,23 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* PHP Status (0=De-feature PHP, 1=Normal operation) */ if (subsystem_deviceid & 0x0008) { - ctrl->defeature_PHP = 1; // PHP supported + ctrl->defeature_PHP = 1; /* PHP supported */ } else { - ctrl->defeature_PHP = 0; // PHP not supported + ctrl->defeature_PHP = 0; /* PHP not supported */ } /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ if (subsystem_deviceid & 0x0010) { - ctrl->alternate_base_address = 1; // supported + ctrl->alternate_base_address = 1; /* supported */ } else { - ctrl->alternate_base_address = 0; // not supported + ctrl->alternate_base_address = 0; /* not supported */ } /* PCI Config Space Index (0=not supported, 1=supported) */ if (subsystem_deviceid & 0x0020) { - ctrl->pci_config_space = 1; // supported + ctrl->pci_config_space = 1; /* supported */ } else { - ctrl->pci_config_space = 0; // not supported + ctrl->pci_config_space = 0; /* not supported */ } /* PCI-X support */ @@ -1042,7 +1048,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } - // Tell the user that we found one. + /* Tell the user that we found one. */ info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); @@ -1120,7 +1126,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * ********************************************************/ - // find the physical slot number of the first hot plug slot + /* find the physical slot number of the first hot plug slot */ /* Get slot won't work for devices behind bridges, but * in this case it will always be called for the "base" @@ -1137,7 +1143,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_iounmap; } - // Store PCI Config Space for all devices on this bus + /* Store PCI Config Space for all devices on this bus */ rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); if (rc) { err("%s: unable to save PCI configuration data, error %d\n", @@ -1148,7 +1154,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* * Get IO, memory, and IRQ resources for new devices */ - // The next line is required for cpqhp_find_available_resources + /* The next line is required for cpqhp_find_available_resources */ ctrl->interrupt = pdev->irq; if (ctrl->interrupt < 0x10) { cpqhp_legacy_mode = 1; @@ -1196,12 +1202,14 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_iounmap; } - /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + /* Enable Shift Out interrupt and clear it, also enable SERR on power + * fault + */ temp_word = readw(ctrl->hpc_reg + MISC); temp_word |= 0x4006; writew(temp_word, ctrl->hpc_reg + MISC); - // Changed 05/05/97 to clear all interrupts at start + /* Changed 05/05/97 to clear all interrupts at start */ writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); @@ -1216,13 +1224,14 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) cpqhp_ctrl_list = ctrl; } - // turn off empty slots here unless command line option "ON" set - // Wait for exclusive access to hardware + /* turn off empty slots here unless command line option "ON" set + * Wait for exclusive access to hardware + */ mutex_lock(&ctrl->crit_sect); num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // find first device number for the ctrl + /* find first device number for the ctrl */ device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; while (num_of_slots) { @@ -1234,7 +1243,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hp_slot = func->device - ctrl->slot_device_offset; dbg("hp_slot: %d\n", hp_slot); - // We have to save the presence info for these slots + /* We have to save the presence info for these slots */ temp_word = ctrl->ctrl_int_comp >> 16; func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; @@ -1258,7 +1267,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!power_mode) { set_SOGO(ctrl); - // Wait for SOBS to be unset + /* Wait for SOBS to be unset */ wait_for_ctrl_irq(ctrl); } @@ -1269,7 +1278,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_irq; } - // Done with exclusive hardware access + /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); cpqhp_create_debugfs_files(ctrl); @@ -1316,11 +1325,11 @@ static int one_time_init(void) cpqhp_slot_list[loop] = NULL; } - // FIXME: We also need to hook the NMI handler eventually. - // this also needs to be worked with Christoph - // register_NMI_handler(); - - // Map rom address + /* FIXME: We also need to hook the NMI handler eventually. + * this also needs to be worked with Christoph + * register_NMI_handler(); + */ + /* Map rom address */ cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); if (!cpqhp_rom_start) { err ("Could not ioremap memory region for ROM\n"); @@ -1328,7 +1337,9 @@ static int one_time_init(void) goto error; } - /* Now, map the int15 entry point if we are on compaq specific hardware */ + /* Now, map the int15 entry point if we are on compaq specific + * hardware + */ compaq_nvram_init(cpqhp_rom_start); /* Map smbios table entry point structure */ @@ -1462,11 +1473,11 @@ static void __exit unload_cpqphpd(void) } } - // Stop the notification mechanism + /* Stop the notification mechanism */ if (initialized) cpqhp_event_stop_thread(); - //unmap the rom address + /* unmap the rom address */ if (cpqhp_rom_start) iounmap(cpqhp_rom_start); if (smbios_start) diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index ec3a76519af2..b02b8dddcf9f 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -81,14 +81,15 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x1L << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); /* this is the structure that tells the worker thread - *what to do */ + * what to do + */ taskInfo = &(ctrl->event_queue[ctrl->next_event]); ctrl->next_event = (ctrl->next_event + 1) % 10; taskInfo->hp_slot = hp_slot; @@ -100,17 +101,17 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - /********************************** + /* * Switch opened - **********************************/ + */ func->switch_save = 0; taskInfo->event_type = INT_SWITCH_OPEN; } else { - /********************************** + /* * Switch closed - **********************************/ + */ func->switch_save = 0x10; @@ -152,17 +153,17 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) if (!change) return 0; - /********************************** + /* * Presence Change - **********************************/ + */ dbg("cpqsbd: Presence/Notify input change.\n"); dbg(" Changed bits are 0x%4.4x\n", change ); for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x0101 << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); @@ -177,22 +178,23 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) return 0; /* If the switch closed, must be a button - * If not in button mode, nevermind */ + * If not in button mode, nevermind + */ if (func->switch_save && (ctrl->push_button == 1)) { temp_word = ctrl->ctrl_int_comp >> 16; temp_byte = (temp_word >> hp_slot) & 0x01; temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; if (temp_byte != func->presence_save) { - /************************************** + /* * button Pressed (doesn't do anything) - **************************************/ + */ dbg("hp_slot %d button pressed\n", hp_slot); taskInfo->event_type = INT_BUTTON_PRESS; } else { - /********************************** + /* * button Released - TAKE ACTION!!!! - **********************************/ + */ dbg("hp_slot %d button released\n", hp_slot); taskInfo->event_type = INT_BUTTON_RELEASE; @@ -210,7 +212,8 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) } } else { /* Switch is open, assume a presence change - * Save the presence state */ + * Save the presence state + */ temp_word = ctrl->ctrl_int_comp >> 16; func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; @@ -241,17 +244,17 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) if (!change) return 0; - /********************************** + /* * power fault - **********************************/ + */ info("power fault interrupt\n"); for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x01 << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); @@ -262,16 +265,16 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) rc++; if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { - /********************************** + /* * power fault Cleared - **********************************/ + */ func->status = 0x00; taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { - /********************************** + /* * power fault - **********************************/ + */ taskInfo->event_type = INT_POWER_FAULT; if (ctrl->rev < 4) { @@ -432,13 +435,15 @@ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **h /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front */ + * we may be able to split some off of the front + */ node = *head; if (node->length & (alignment -1)) { /* this one isn't an aligned length, so we'll make a new entry - * and split it up. */ + * and split it up. + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -556,7 +561,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size if (node->base & (size - 1)) { /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -581,7 +587,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size /* Don't need to check if too small since we already did */ if (node->length > size) { /* this one is longer than we need - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -601,7 +608,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size continue; /* If we got here, then it is the right size - * Now take it out of the list and break */ + * Now take it out of the list and break + */ if (*head == node) { *head = node->next; } else { @@ -643,13 +651,15 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz for (max = *head; max; max = max->next) { /* If not big enough we could probably just bail, - * instead we'll continue to the next. */ + * instead we'll continue to the next. + */ if (max->length < size) continue; if (max->base & (size - 1)) { /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (max->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -672,7 +682,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz if ((max->base + max->length) & (size - 1)) { /* this one isn't end aligned properly at the top - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -744,7 +755,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) if (node->base & (size - 1)) { dbg("%s: not aligned\n", __func__); /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -769,7 +781,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) if (node->length > size) { dbg("%s: too big\n", __func__); /* this one is longer than we need - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -888,17 +901,17 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) misc = readw(ctrl->hpc_reg + MISC); - /*************************************** + /* * Check to see if it was our interrupt - ***************************************/ + */ if (!(misc & 0x000C)) { return IRQ_NONE; } if (misc & 0x0004) { - /********************************** + /* * Serial Output interrupt Pending - **********************************/ + */ /* Clear the interrupt */ misc |= 0x0004; @@ -963,7 +976,8 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); if (new_slot == NULL) { /* I'm not dead yet! - * You will be. */ + * You will be. + */ return new_slot; } @@ -1135,7 +1149,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ return 0; /* We don't allow freq/mode changes if we find another adapter running - * in another slot on this controller */ + * in another slot on this controller + */ for(slot = ctrl->slot; slot; slot = slot->next) { if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; @@ -1145,7 +1160,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ continue; /* If another adapter is running on the same segment but at a * lower speed/mode, we allow the new adapter to function at - * this rate if supported */ + * this rate if supported + */ if (ctrl->speed < adapter_speed) return 0; @@ -1153,7 +1169,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ } /* If the controller doesn't support freq/mode changes and the - * controller is running at a higher mode, we bail */ + * controller is running at a higher mode, we bail + */ if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) return 1; @@ -1162,7 +1179,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ return 0; /* We try to set the max speed supported by both the adapter and - * controller */ + * controller + */ if (ctrl->speed_capability < adapter_speed) { if (ctrl->speed == ctrl->speed_capability) return 0; @@ -1244,7 +1262,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ } /* the following routines constitute the bulk of the - hotplug controller logic + * hotplug controller logic */ @@ -1269,14 +1287,14 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) hp_slot = func->device - ctrl->slot_device_offset; if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { - /********************************** + /* * The switch is open. - **********************************/ + */ rc = INTERLOCK_OPEN; } else if (is_slot_enabled (ctrl, hp_slot)) { - /********************************** + /* * The board is already on - **********************************/ + */ rc = CARD_FUNCTIONING; } else { mutex_lock(&ctrl->crit_sect); @@ -1352,7 +1370,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) * Get slot won't work for devices behind * bridges, but in this case it will always be * called for the "base" bus/dev/func of an - * adapter. */ + * adapter. + */ mutex_lock(&ctrl->crit_sect); @@ -1377,7 +1396,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) * Get slot won't work for devices behind bridges, but * in this case it will always be called for the "base" - * bus/dev/func of an adapter. */ + * bus/dev/func of an adapter. + */ mutex_lock(&ctrl->crit_sect); @@ -1434,7 +1454,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) wait_for_ctrl_irq (ctrl); /* Change bits in slot power register to force another shift out - * NOTE: this is to work around the timer bug */ + * NOTE: this is to work around the timer bug + */ temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); writeb(0x00, ctrl->hpc_reg + SLOT_POWER); writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); @@ -2484,7 +2505,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func temp_resources.irqs = &irqs; /* Make copies of the nodes we are going to pass down so that - * if there is a problem,we can just use these to free resources */ + * if there is a problem,we can just use these to free resources + */ hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL); hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL); hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL); @@ -2556,7 +2578,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - /* Adjust this to compensate for extra adjustment in first loop */ + /* Adjust this to compensate for extra adjustment in first loop + */ irqs.barber_pole--; rc = 0; diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index 76e110f0e3a6..76ba8a1c774d 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -94,12 +94,13 @@ static u8 evbuffer[1024]; static void __iomem *compaq_int15_entry_point; -static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ +/* lock for ordering int15_bios_call() */ +static spinlock_t int15_lock; /* This is a series of function that deals with - setting & getting the hotplug resource table in some environment variable. -*/ + * setting & getting the hotplug resource table in some environment variable. + */ /* * We really shouldn't be doing this unless there is a _very_ good reason to!!! @@ -210,14 +211,16 @@ static int load_HRT (void __iomem *rom_start) available = 1024; - // Now load the EV + /* Now load the EV */ temp_dword = available; rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); evbuffer_length = temp_dword; - // We're maintaining the resource lists so write FF to invalidate old info + /* We're maintaining the resource lists so write FF to invalidate old + * info + */ temp_dword = 1; rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); @@ -264,12 +267,12 @@ static u32 store_HRT (void __iomem *rom_start) ctrl = cpqhp_ctrl_list; - // The revision of this structure + /* The revision of this structure */ rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); if (rc) return(rc); - // The number of controllers + /* The number of controllers */ rc = add_byte( &pFill, 1, &usedbytes, &available); if (rc) return(rc); @@ -279,27 +282,27 @@ static u32 store_HRT (void __iomem *rom_start) numCtrl++; - // The bus number + /* The bus number */ rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); if (rc) return(rc); - // The device Number + /* The device Number */ rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); - // The function Number + /* The function Number */ rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); - // Skip the number of available entries + /* Skip the number of available entries */ rc = add_dword( &pFill, 0, &usedbytes, &available); if (rc) return(rc); - // Figure out memory Available + /* Figure out memory Available */ resNode = ctrl->mem_head; @@ -308,12 +311,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -321,10 +324,10 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->mem_avail = loop; - // Figure out prefetchable memory Available + /* Figure out prefetchable memory Available */ resNode = ctrl->p_mem_head; @@ -333,12 +336,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -346,10 +349,10 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->p_mem_avail = loop; - // Figure out IO Available + /* Figure out IO Available */ resNode = ctrl->io_head; @@ -358,12 +361,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -371,10 +374,10 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->io_avail = loop; - // Figure out bus Available + /* Figure out bus Available */ resNode = ctrl->bus_head; @@ -383,12 +386,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -396,7 +399,7 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->bus_avail = loop; ctrl = ctrl->next; @@ -404,7 +407,7 @@ static u32 store_HRT (void __iomem *rom_start) p_EV_header->num_of_ctrl = numCtrl; - // Now store the EV + /* Now store the EV */ temp_dword = usedbytes; @@ -449,20 +452,21 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) struct ev_hrt_header *p_EV_header; if (!evbuffer_init) { - // Read the resource list information in from NVRAM + /* Read the resource list information in from NVRAM */ if (load_HRT(rom_start)) memset (evbuffer, 0, 1024); evbuffer_init = 1; } - // If we saved information in NVRAM, use it now + /* If we saved information in NVRAM, use it now */ p_EV_header = (struct ev_hrt_header *) evbuffer; - // The following code is for systems where version 1.0 of this - // driver has been loaded, but doesn't support the hardware. - // In that case, the driver would incorrectly store something - // in NVRAM. + /* The following code is for systems where version 1.0 of this + * driver has been loaded, but doesn't support the hardware. + * In that case, the driver would incorrectly store something + * in NVRAM. + */ if ((p_EV_header->Version == 2) || ((p_EV_header->Version == 1) && !ctrl->push_flag)) { p_byte = &(p_EV_header->next); @@ -491,7 +495,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) if (p_byte > ((u8*)p_EV_header + evbuffer_length)) return 2; - // Skip forward to the next entry + /* Skip forward to the next entry */ p_byte += (nummem + numpmem + numio + numbus) * 8; if (p_byte > ((u8*)p_EV_header + evbuffer_length)) @@ -629,8 +633,9 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) ctrl->bus_head = bus_node; } - // If all of the following fail, we don't have any resources for - // hot plug add + /* If all of the following fail, we don't have any resources for + * hot plug add + */ rc = 1; rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 573a2702fb6a..2e96bae3c82a 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -178,17 +178,17 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) if (!rc) return !rc; - // set the Edge Level Control Register (ELCR) + /* set the Edge Level Control Register (ELCR) */ temp_word = inb(0x4d0); temp_word |= inb(0x4d1) << 8; temp_word |= 0x01 << irq_num; - // This should only be for x86 as it sets the Edge Level Control Register - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); - rc = 0; - } + /* This should only be for x86 as it sets the Edge Level + * Control Register + */ + outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word & + 0xFF00) >> 8), 0x4d1); rc = 0; } return rc; } @@ -213,11 +213,11 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev ctrl->pci_bus->number = bus_num; for (tdevice = 0; tdevice < 0xFF; tdevice++) { - //Scan for access first + /* Scan for access first */ if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) continue; dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. Not a bridge ? + /* Yep we got one. Not a bridge ? */ if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { *dev_num = tdevice; dbg("found it !\n"); @@ -225,11 +225,11 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev } } for (tdevice = 0; tdevice < 0xFF; tdevice++) { - //Scan for access first + /* Scan for access first */ if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) continue; dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. bridge ? + /* Yep we got one. bridge ? */ if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); @@ -257,7 +257,7 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num len = (PCIIRQRoutingInfoLength->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry + /* Make sure I got at least one entry */ if (len == 0) { kfree(PCIIRQRoutingInfoLength ); return -1; @@ -304,11 +304,14 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) { - return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) + /* plain (bridges allowed) */ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); } -/* More PCI configuration routines; this time centered around hotplug controller */ +/* More PCI configuration routines; this time centered around hotplug + * controller + */ /* @@ -339,12 +342,12 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) int stop_it; int index; - // Decide which slots are supported + /* Decide which slots are supported */ if (is_hot_plug) { - //********************************* - // is_hot_plug is the slot mask - //********************************* + /* + * is_hot_plug is the slot mask + */ FirstSupported = is_hot_plug >> 4; LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; } else { @@ -352,13 +355,13 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) LastSupported = 0x1F; } - // Save PCI configuration space for all devices in supported slots + /* Save PCI configuration space for all devices in supported slots */ ctrl->pci_bus->number = busnumber; for (device = FirstSupported; device <= LastSupported; device++) { ID = 0xFFFFFFFF; rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { // device in slot + if (ID != 0xFFFFFFFF) { /* device in slot */ rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); if (rc) return rc; @@ -367,7 +370,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) if (rc) return rc; - // If multi-function device, set max_functions to 8 + /* If multi-function device, set max_functions to 8 */ if (header_type & 0x80) max_functions = 8; else @@ -377,18 +380,19 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) do { DevError = 0; - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge - // Recurse the subordinate bus - // get the subordinate bus number + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus + * get the subordinate bus number + */ rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); if (rc) { return rc; } else { sub_bus = (int) secondary_bus; - // Save secondary bus cfg spc - // with this recursive call. + /* Save secondary bus cfg spc + * with this recursive call. + */ rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return rc; @@ -403,7 +407,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) new_slot = cpqhp_slot_find(busnumber, device, index++); if (!new_slot) { - // Setup slot structure. + /* Setup slot structure. */ new_slot = cpqhp_slot_create(busnumber); if (new_slot == NULL) @@ -415,7 +419,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) new_slot->function = (u8) function; new_slot->is_a_board = 1; new_slot->switch_save = 0x10; - // In case of unsupported board + /* In case of unsupported board */ new_slot->status = DevError; new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); @@ -429,14 +433,15 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) stop_it = 0; - // this loop skips to the next present function - // reading in Class Code and Header type. + /* this loop skips to the next present function + * reading in Class Code and Header type. + */ while ((function < max_functions)&&(!stop_it)) { rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { // nothing there. + if (ID == 0xFFFFFFFF) { /* nothing there. */ function++; - } else { // Something there + } else { /* Something there */ rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); if (rc) return rc; @@ -450,9 +455,9 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) } } while (function < max_functions); - } // End of IF (device in slot?) + } /* End of IF (device in slot?) */ else if (is_hot_plug) { - // Setup slot structure with entry for empty slot + /* Setup slot structure with entry for empty slot */ new_slot = cpqhp_slot_create(busnumber); if (new_slot == NULL) { @@ -466,7 +471,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) new_slot->presence_save = 0; new_slot->switch_save = 0; } - } // End of FOR loop + } /* End of FOR loop */ return(0); } @@ -498,11 +503,11 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) ctrl->pci_bus->number = new_slot->bus; pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { // device in slot + if (ID != 0xFFFFFFFF) { /* device in slot */ pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - if (header_type & 0x80) // Multi-function device + if (header_type & 0x80) /* Multi-function device */ max_functions = 8; else max_functions = 1; @@ -510,19 +515,21 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) function = 0; do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Recurse the subordinate bus + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus */ pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; - // Save the config headers for the secondary bus. + /* Save the config headers for the secondary + * bus. + */ rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return(rc); ctrl->pci_bus->number = new_slot->bus; - } // End of IF + } /* End of IF */ new_slot->status = 0; @@ -534,15 +541,15 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) stop_it = 0; - // this loop skips to the next present function - // reading in the Class Code and the Header type. - + /* this loop skips to the next present function + * reading in the Class Code and the Header type. + */ while ((function < max_functions) && (!stop_it)) { pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { // nothing there. + if (ID == 0xFFFFFFFF) { /* nothing there. */ function++; - } else { // Something there + } else { /* Something there */ pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); @@ -552,7 +559,7 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) } } while (function < max_functions); - } // End of IF (device in slot?) + } /* End of IF (device in slot?) */ else { return 2; } @@ -590,11 +597,10 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - // PCI-PCI Bridge pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -610,23 +616,27 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) } pci_bus->number = func->bus; - //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together - // Figure out IO and memory base lengths + /* FIXME: this loop is duplicated in the non-bridge + * case. The two could be rolled together Figure out + * IO and memory base lengths + */ for (cloop = 0x10; cloop <= 0x14; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // set base = amount of IO space requested + /* IO base + * set base = amount of IO space + * requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base + /* memory base */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -637,32 +647,36 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) type = 0; } - // Save information in slot structure + /* Save information in slot structure */ func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; - } // End of base register loop + } /* End of base register loop */ - - } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge - // Figure out IO and memory base lengths + } else if ((header_type & 0x7F) == 0x00) { + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // base = amount of IO space requested + /* IO base + * base = amount of IO space + * requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base - // base = amount of memory space requested + /* memory base + * base = amount of memory + * space requested + */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -673,16 +687,16 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) type = 0; } - // Save information in slot structure + /* Save information in slot structure */ func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; - } // End of base register loop + } /* End of base register loop */ - } else { // Some other unknown header type + } else { /* Some other unknown header type */ } - // find the next device in this slot + /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -728,18 +742,18 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Save the command register + /* Save the command register */ pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); - // disable card + /* disable card */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Clear Bridge Control Register + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Clear Bridge Control Register */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); @@ -755,7 +769,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) bus_node->next = func->bus_head; func->bus_head = bus_node; - // Save IO base and Limit registers + /* Save IO base and Limit registers */ pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base); pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length); @@ -771,7 +785,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) func->io_head = io_node; } - // Save memory base and Limit registers + /* Save memory base and Limit registers */ pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); @@ -787,7 +801,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) func->mem_head = mem_node; } - // Save prefetchable memory base and Limit registers + /* Save prefetchable memory base and Limit registers */ pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); @@ -802,7 +816,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) p_mem_node->next = func->p_mem_head; func->p_mem_head = p_mem_node; } - // Figure out IO and memory base lengths + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x14; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); @@ -812,11 +826,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) temp_register = base; - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested + /* IO base + * set temp_register = amount + * of IO space requested + */ temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; @@ -834,7 +851,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -851,7 +868,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -868,9 +885,10 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else return(1); } - } // End of base register loop - } else if ((header_type & 0x7F) == 0x00) { // Standard header - // Figure out IO and memory base lengths + } /* End of base register loop */ + /* Standard header */ + } else if ((header_type & 0x7F) == 0x00) { + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); @@ -880,11 +898,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) temp_register = base; - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested + /* IO base + * set temp_register = amount + * of IO space requested + */ temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; @@ -901,7 +922,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -918,7 +939,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -935,11 +956,12 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else return(1); } - } // End of base register loop - } else { // Some other unknown header type + } /* End of base register loop */ + /* Some other unknown header type */ + } else { } - // find the next device in this slot + /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -975,16 +997,17 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Start at the top of config space so that the control - // registers are programmed last + /* Start at the top of config space so that the control + * registers are programmed last + */ for (cloop = 0x3C; cloop > 0; cloop -= 4) { pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); } pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - // If this is a bridge device, restore subordinate devices - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + /* If this is a bridge device, restore subordinate devices */ + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -1000,8 +1023,9 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) } } else { - // Check all the base Address Registers to make sure - // they are the same. If not, the board is different. + /* Check all the base Address Registers to make sure + * they are the same. If not, the board is different. + */ for (cloop = 16; cloop < 40; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); @@ -1058,27 +1082,28 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); - // No adapter present + /* No adapter present */ if (temp_register == 0xFFFFFFFF) return(NO_ADAPTER_PRESENT); if (temp_register != func->config_space[0]) return(ADAPTER_NOT_SAME); - // Check for same revision number and class code + /* Check for same revision number and class code */ pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); - // Adapter not the same + /* Adapter not the same */ if (temp_register != func->config_space[0x08 >> 2]) return(ADAPTER_NOT_SAME); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // In order to continue checking, we must program the - // bus registers in the bridge to respond to accesses - // for it's subordinate bus(es) + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* In order to continue checking, we must program the + * bus registers in the bridge to respond to accesses + * for its subordinate bus(es) + */ temp_register = func->config_space[0x18 >> 2]; pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); @@ -1096,35 +1121,39 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) } } - // Check to see if it is a standard config header + /* Check to see if it is a standard config header */ else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Check subsystem vendor and ID + /* Check subsystem vendor and ID */ pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); if (temp_register != func->config_space[0x2C >> 2]) { - // If it's a SMART-2 and the register isn't filled - // in, ignore the difference because - // they just have an old rev of the firmware - + /* If it's a SMART-2 and the register isn't + * filled in, ignore the difference because + * they just have an old rev of the firmware + */ if (!((func->config_space[0] == 0xAE100E11) && (temp_register == 0x00L))) return(ADAPTER_NOT_SAME); } - // Figure out IO and memory base lengths + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented + + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // set base = amount of IO space requested + /* IO base + * set base = amount of IO + * space requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base + /* memory base */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -1135,23 +1164,24 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) type = 0; } - // Check information in slot structure + /* Check information in slot structure */ if (func->base_length[(cloop - 0x10) >> 2] != base) return(ADAPTER_NOT_SAME); if (func->base_type[(cloop - 0x10) >> 2] != type) return(ADAPTER_NOT_SAME); - } // End of base register loop + } /* End of base register loop */ - } // End of (type 0 config space) else + } /* End of (type 0 config space) else */ else { - // this is not a type 0 or 1 config space header so - // we don't know how to do it + /* this is not a type 0 or 1 config space header so + * we don't know how to do it + */ return(DEVICE_TYPE_NOT_SUPPORTED); } - // Get the next function + /* Get the next function */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -1190,7 +1220,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st if (rom_resource_table == NULL) { return -ENODEV; } - // Sum all resources and setup resource maps + /* Sum all resources and setup resource maps */ unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); dbg("unused_IRQ = %x\n", unused_IRQ); @@ -1262,13 +1292,13 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, primary_bus, secondary_bus, max_bus); - // If this entry isn't for our controller's bus, ignore it + /* If this entry isn't for our controller's bus, ignore it */ if (primary_bus != ctrl->bus) { i--; one_slot += sizeof (struct slot_rt); continue; } - // find out if this entry is for an occupied slot + /* find out if this entry is for an occupied slot */ ctrl->pci_bus->number = primary_bus; pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); dbg("temp_D_word = %x\n", temp_dword); @@ -1282,13 +1312,13 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); } - // If we can't find a match, skip this table entry + /* If we can't find a match, skip this table entry */ if (!func) { i--; one_slot += sizeof (struct slot_rt); continue; } - // this may not work and shouldn't be used + /* this may not work and shouldn't be used */ if (secondary_bus != primary_bus) bridged_slot = 1; else @@ -1301,7 +1331,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } - // If we've got a valid IO base, use it + /* If we've got a valid IO base, use it */ temp_dword = io_base + io_length; @@ -1325,7 +1355,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid memory base, use it + /* If we've got a valid memory base, use it */ temp_dword = mem_base + mem_length; if ((mem_base) && (temp_dword < 0x10000)) { mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); @@ -1348,8 +1378,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid prefetchable memory base, and - // the base + length isn't greater than 0xFFFF + /* If we've got a valid prefetchable memory base, and + * the base + length isn't greater than 0xFFFF + */ temp_dword = pre_mem_base + pre_mem_length; if ((pre_mem_base) && (temp_dword < 0x10000)) { p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); @@ -1372,9 +1403,10 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid bus number, use it - // The second condition is to ignore bus numbers on - // populated slots that don't have PCI-PCI bridges + /* If we've got a valid bus number, use it + * The second condition is to ignore bus numbers on + * populated slots that don't have PCI-PCI bridges + */ if (secondary_bus && (secondary_bus != primary_bus)) { bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); if (!bus_node) @@ -1398,8 +1430,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st one_slot += sizeof (struct slot_rt); } - // If all of the following fail, we don't have any resources for - // hot plug add + /* If all of the following fail, we don't have any resources for + * hot plug add + */ rc = 1; rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); From 86a58023e4078a843f8ca8a9b6fa23542d881f99 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:21 -0600 Subject: [PATCH 09/74] PCI Hotplug: cpqphp: obey 80 column convention in cpqphp.h Clean up cpqphp.h to follow 80 column convention. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp.h | 76 +++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index e15d657368f0..308f82b1fc9a 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -405,40 +405,50 @@ struct resource_lists { /* debugfs functions for the hotplug controller info */ -extern void cpqhp_initialize_debugfs (void); -extern void cpqhp_shutdown_debugfs (void); -extern void cpqhp_create_debugfs_files (struct controller *ctrl); -extern void cpqhp_remove_debugfs_files (struct controller *ctrl); +extern void cpqhp_initialize_debugfs(void); +extern void cpqhp_shutdown_debugfs(void); +extern void cpqhp_create_debugfs_files(struct controller *ctrl); +extern void cpqhp_remove_debugfs_files(struct controller *ctrl); /* controller functions */ -extern void cpqhp_pushbutton_thread (unsigned long event_pointer); -extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data); -extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start); -extern int cpqhp_event_start_thread (void); -extern void cpqhp_event_stop_thread (void); -extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); -extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); -extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); +extern void cpqhp_pushbutton_thread(unsigned long event_pointer); +extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data); +extern int cpqhp_find_available_resources(struct controller *ctrl, + void __iomem *rom_start); +extern int cpqhp_event_start_thread(void); +extern void cpqhp_event_stop_thread(void); +extern struct pci_func *cpqhp_slot_create(unsigned char busnumber); +extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device, + unsigned char index); +extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func); +extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func); +extern int cpqhp_hardware_test(struct controller *ctrl, int test_num); /* resource functions */ extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); /* pci functions */ -extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); -extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); -extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); -extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); -extern void cpqhp_destroy_board_resources (struct pci_func * func); -extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); -extern void cpqhp_destroy_resource_list (struct resource_lists * resources); -extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); -extern int cpqhp_unconfigure_device (struct pci_func* func); +extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, + u8 slot); +extern int cpqhp_save_config(struct controller *ctrl, int busnumber, + int is_hot_plug); +extern int cpqhp_save_base_addr_length(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_save_used_resources(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_configure_board(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_save_slot_config(struct controller *ctrl, + struct pci_func *new_slot); +extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func); +extern void cpqhp_destroy_board_resources(struct pci_func *func); +extern int cpqhp_return_board_resources (struct pci_func *func, + struct resource_lists *resources); +extern void cpqhp_destroy_resource_list(struct resource_lists *resources); +extern int cpqhp_configure_device(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_unconfigure_device(struct pci_func *func); /* Global variables */ extern int cpqhp_debug; @@ -463,7 +473,8 @@ static inline char *slot_name(struct slot *slot) * * Puts node back in the resource list pointed to by head */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) +static inline void return_resource(struct pci_resource **head, + struct pci_resource *node) { if (!node || !head) return; @@ -673,7 +684,8 @@ static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot) } -static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slot) +static inline int cpq_get_latch_status(struct controller *ctrl, + struct slot *slot) { u32 status; u8 hp_slot; @@ -688,7 +700,8 @@ static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slo } -static inline int get_presence_status(struct controller *ctrl, struct slot *slot) +static inline int get_presence_status(struct controller *ctrl, + struct slot *slot) { int presence_save = 0; u8 hp_slot; @@ -697,7 +710,8 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot hp_slot = slot->device - ctrl->slot_device_offset; tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) + >> hp_slot) & 0x02; return presence_save; } From b4d897a48d451db0ab6a4ebf8c28eb314eba0280 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:26 -0600 Subject: [PATCH 10/74] PCI Hotplug: cpqphp: remove useless prototypes in cpqphp_core.c Impact: refactor Refactor code to follow convention more closely and eliminate the need for some useless prototypes. No functional change. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_core.c | 461 +++++++++++++++--------------- 1 file changed, 224 insertions(+), 237 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 91dc95850cce..f05ea7a5606b 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -77,33 +77,6 @@ MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); #define CPQHPC_MODULE_MINOR 208 -static int one_time_init (void); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int process_SI (struct hotplug_slot *slot); -static int process_SS (struct hotplug_slot *slot); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); -static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); - -static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = process_SI, - .disable_slot = process_SS, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - static inline int is_slot64bit(struct slot *slot) { return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0; @@ -322,145 +295,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) kfree(slot); } -#define SLOT_NAME_SIZE 10 - -static int ctrl_slot_setup(struct controller *ctrl, - void __iomem *smbios_start, - void __iomem *smbios_table) -{ - struct slot *slot; - struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *hotplug_slot_info; - u8 number_of_slots; - u8 slot_device; - u8 slot_number; - u8 ctrl_slot; - u32 tempdword; - char name[SLOT_NAME_SIZE]; - void __iomem *slot_entry= NULL; - int result = -ENOMEM; - - dbg("%s\n", __func__); - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) - goto error; - - slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)), - GFP_KERNEL); - if (!slot->hotplug_slot) - goto error_slot; - hotplug_slot = slot->hotplug_slot; - - hotplug_slot->info = - kzalloc(sizeof(*(hotplug_slot->info)), - GFP_KERNEL); - if (!hotplug_slot->info) - goto error_hpslot; - hotplug_slot_info = hotplug_slot->info; - - slot->ctrl = ctrl; - slot->bus = ctrl->bus; - slot->device = slot_device; - slot->number = slot_number; - dbg("slot->number = %u\n", slot->number); - - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, - slot_entry); - - while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != - slot->number)) { - slot_entry = get_SMBIOS_entry(smbios_start, - smbios_table, 9, slot_entry); - } - - slot->p_sm_slot = slot_entry; - - init_timer(&slot->task_event); - slot->task_event.expires = jiffies + 5 * HZ; - slot->task_event.function = cpqhp_pushbutton_thread; - - /*FIXME: these capabilities aren't used but if they are - * they need to be correctly implemented - */ - slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; - slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; - - if (is_slot64bit(slot)) - slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; - if (is_slot66mhz(slot)) - slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; - if (ctrl->speed == PCI_SPEED_66MHz) - slot->capabilities |= PCISLOT_66_MHZ_OPERATION; - - ctrl_slot = - slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); - - /* Check presence */ - slot->capabilities |= - ((((~tempdword) >> 23) | - ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; - /* Check the switch state */ - slot->capabilities |= - ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; - /* Check the slot enable */ - slot->capabilities |= - ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; - - /* register this slot with the hotplug pci core */ - hotplug_slot->release = &release_slot; - hotplug_slot->private = slot; - snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); - hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - - hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); - hotplug_slot_info->attention_status = - cpq_get_attention_status(ctrl, slot); - hotplug_slot_info->latch_status = - cpq_get_latch_status(ctrl, slot); - hotplug_slot_info->adapter_status = - get_presence_status(ctrl, slot); - - dbg("registering bus %d, dev %d, number %d, " - "ctrl->slot_device_offset %d, slot %d\n", - slot->bus, slot->device, - slot->number, ctrl->slot_device_offset, - slot_number); - result = pci_hp_register(hotplug_slot, - ctrl->pci_dev->bus, - slot->device, - name); - if (result) { - err("pci_hp_register failed with error %d\n", result); - goto error_info; - } - - slot->next = ctrl->slot; - ctrl->slot = slot; - - number_of_slots--; - slot_device++; - slot_number++; - } - - return 0; -error_info: - kfree(hotplug_slot_info); -error_hpslot: - kfree(hotplug_slot); -error_slot: - kfree(slot); -error: - return result; -} - static int ctrl_slot_cleanup (struct controller * ctrl) { struct slot *old_slot, *next_slot; @@ -793,6 +627,230 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp return 0; } +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .set_attention_status = set_attention_status, + .enable_slot = process_SI, + .disable_slot = process_SS, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + +#define SLOT_NAME_SIZE 10 + +static int ctrl_slot_setup(struct controller *ctrl, + void __iomem *smbios_start, + void __iomem *smbios_table) +{ + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *hotplug_slot_info; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + char name[SLOT_NAME_SIZE]; + void __iomem *slot_entry= NULL; + int result = -ENOMEM; + + dbg("%s\n", __func__); + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + goto error; + + slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)), + GFP_KERNEL); + if (!slot->hotplug_slot) + goto error_slot; + hotplug_slot = slot->hotplug_slot; + + hotplug_slot->info = + kzalloc(sizeof(*(hotplug_slot->info)), + GFP_KERNEL); + if (!hotplug_slot->info) + goto error_hpslot; + hotplug_slot_info = hotplug_slot->info; + + slot->ctrl = ctrl; + slot->bus = ctrl->bus; + slot->device = slot_device; + slot->number = slot_number; + dbg("slot->number = %u\n", slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, + slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != + slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, + smbios_table, 9, slot_entry); + } + + slot->p_sm_slot = slot_entry; + + init_timer(&slot->task_event); + slot->task_event.expires = jiffies + 5 * HZ; + slot->task_event.function = cpqhp_pushbutton_thread; + + /*FIXME: these capabilities aren't used but if they are + * they need to be correctly implemented + */ + slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(slot)) + slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(slot)) + slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (ctrl->speed == PCI_SPEED_66MHz) + slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = + slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + /* Check presence */ + slot->capabilities |= + ((((~tempdword) >> 23) | + ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + /* Check the switch state */ + slot->capabilities |= + ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + /* Check the slot enable */ + slot->capabilities |= + ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + hotplug_slot->release = &release_slot; + hotplug_slot->private = slot; + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); + hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); + hotplug_slot_info->attention_status = + cpq_get_attention_status(ctrl, slot); + hotplug_slot_info->latch_status = + cpq_get_latch_status(ctrl, slot); + hotplug_slot_info->adapter_status = + get_presence_status(ctrl, slot); + + dbg("registering bus %d, dev %d, number %d, " + "ctrl->slot_device_offset %d, slot %d\n", + slot->bus, slot->device, + slot->number, ctrl->slot_device_offset, + slot_number); + result = pci_hp_register(hotplug_slot, + ctrl->pci_dev->bus, + slot->device, + name); + if (result) { + err("pci_hp_register failed with error %d\n", result); + goto error_info; + } + + slot->next = ctrl->slot; + ctrl->slot = slot; + + number_of_slots--; + slot_device++; + slot_number++; + } + + return 0; +error_info: + kfree(hotplug_slot_info); +error_hpslot: + kfree(hotplug_slot); +error_slot: + kfree(slot); +error: + return result; +} + +static int one_time_init(void) +{ + int loop; + int retval = 0; + + if (initialized) + return 0; + + power_mode = 0; + + retval = pci_print_IRQ_route(); + if (retval) + goto error; + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) { + cpqhp_slot_list[loop] = NULL; + } + + /* FIXME: We also need to hook the NMI handler eventually. + * this also needs to be worked with Christoph + * register_NMI_handler(); + */ + /* Map rom address */ + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific + * hardware + */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, + cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO; + goto error_rom_start; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), + readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO; + goto error_smbios_start; + } + + initialized = 1; + + return retval; + +error_smbios_start: + iounmap(smbios_start); +error_rom_start: + iounmap(cpqhp_rom_start); +error: + return retval; +} + static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u8 num_of_slots = 0; @@ -1300,77 +1358,6 @@ err_disable_device: return rc; } -static int one_time_init(void) -{ - int loop; - int retval = 0; - - if (initialized) - return 0; - - power_mode = 0; - - retval = pci_print_IRQ_route(); - if (retval) - goto error; - - dbg("Initialize + Start the notification mechanism \n"); - - retval = cpqhp_event_start_thread(); - if (retval) - goto error; - - dbg("Initialize slot lists\n"); - for (loop = 0; loop < 256; loop++) { - cpqhp_slot_list[loop] = NULL; - } - - /* FIXME: We also need to hook the NMI handler eventually. - * this also needs to be worked with Christoph - * register_NMI_handler(); - */ - /* Map rom address */ - cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!cpqhp_rom_start) { - err ("Could not ioremap memory region for ROM\n"); - retval = -EIO; - goto error; - } - - /* Now, map the int15 entry point if we are on compaq specific - * hardware - */ - compaq_nvram_init(cpqhp_rom_start); - - /* Map smbios table entry point structure */ - smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, - cpqhp_rom_start + ROM_PHY_LEN); - if (!smbios_table) { - err ("Could not find the SMBIOS pointer in memory\n"); - retval = -EIO; - goto error_rom_start; - } - - smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), - readw(smbios_table + ST_LENGTH)); - if (!smbios_start) { - err ("Could not ioremap memory region taken from SMBIOS values\n"); - retval = -EIO; - goto error_smbios_start; - } - - initialized = 1; - - return retval; - -error_smbios_start: - iounmap(smbios_start); -error_rom_start: - iounmap(cpqhp_rom_start); -error: - return retval; -} - static void __exit unload_cpqphpd(void) { struct pci_func *next; From 04225fe7e6877493765b9cfa3092524e21e020d7 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:31 -0600 Subject: [PATCH 11/74] PCI Hotplug: cpqphp: eliminate stray braces Clean up style and eliminate superfluous braces and parens. No functional change. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_core.c | 55 +++++++++++++------------------ 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index f05ea7a5606b..195c8c9b33e0 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -154,7 +154,6 @@ static int init_SERR(struct controller * ctrl) return 0; } - /* nice debugging output */ static int pci_print_IRQ_route (void) { @@ -214,7 +213,7 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, void __iomem *p_max; if (!smbios_table || !curr) - return(NULL); + return NULL; /* set p_max to the end of the table */ p_max = smbios_start + readw(smbios_table + ST_LENGTH); @@ -227,19 +226,17 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, * The first condition is the previous byte * and the second is the curr */ - if (!previous_byte && !(readb(p_temp))) { + if (!previous_byte && !(readb(p_temp))) bail = 1; - } previous_byte = readb(p_temp); p_temp++; } - if (p_temp < p_max) { + if (p_temp < p_max) return p_temp; - } else { + else return NULL; - } } @@ -265,21 +262,18 @@ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, if (!smbios_table) return NULL; - if (!previous) { + if (!previous) previous = smbios_start; - } else { + else previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } - while (previous) { - if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + while (previous) + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } else { + else break; - } - } return previous; } @@ -319,7 +313,7 @@ static int ctrl_slot_cleanup (struct controller * ctrl) release_mem_region(pci_resource_start(ctrl->pci_dev, 0), pci_resource_len(ctrl->pci_dev, 0)); - return(0); + return 0; } @@ -388,9 +382,8 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); // See if bridge's secondary bus matches target bus. - if (((work >> 8) & 0x000000FF) == (long) bus_num) { + if (((work >> 8) & 0x000000FF) == (long) bus_num) bridgeSlot = tslot; - } } } @@ -425,21 +418,21 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, u8 hp_slot; if (func == NULL) - return(1); + return 1; hp_slot = func->device - ctrl->slot_device_offset; /* Wait for exclusive access to hardware */ mutex_lock(&ctrl->crit_sect); - if (status == 1) { + if (status == 1) amber_LED_on (ctrl, hp_slot); - } else if (status == 0) { + else if (status == 0) amber_LED_off (ctrl, hp_slot); - } else { + else { /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); - return(1); + return 1; } set_SOGO(ctrl); @@ -450,7 +443,7 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); - return(0); + return 0; } @@ -678,8 +671,7 @@ static int ctrl_slot_setup(struct controller *ctrl, goto error_slot; hotplug_slot = slot->hotplug_slot; - hotplug_slot->info = - kzalloc(sizeof(*(hotplug_slot->info)), + hotplug_slot->info = kzalloc(sizeof(*(hotplug_slot->info)), GFP_KERNEL); if (!hotplug_slot->info) goto error_hpslot; @@ -801,9 +793,8 @@ static int one_time_init(void) goto error; dbg("Initialize slot lists\n"); - for (loop = 0; loop < 256; loop++) { + for (loop = 0; loop < 256; loop++) cpqhp_slot_list[loop] = NULL; - } /* FIXME: We also need to hook the NMI handler eventually. * this also needs to be worked with Christoph @@ -1306,18 +1297,16 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) func->switch_save = 0; - } else { + else func->switch_save = 0x10; - } - if (!power_mode) { + if (!power_mode) if (!func->is_a_board) { green_LED_off(ctrl, hp_slot); slot_disable(ctrl, hp_slot); } - } device++; num_of_slots--; From 867556fe740d0d29a05fce99d2d960625077ed45 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:36 -0600 Subject: [PATCH 12/74] PCI Hotplug: cpqphp: refactor cpqhp_probe Apply DeMorgan's theorem: if ((pdev->revision > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) turns into if ((pdev->revision <= 2) && (vendor_id != PCI_VENDOR_ID_INTEL)) Now we can bail out early from the function if the controller is not supported. This allows us to un-indent the remainder of the function quite a bit and make it much more readable. Fix up some extra braces, and un-indent the 'case' labels in the switch statement as per CodingStyle. No functional change. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_core.c | 402 +++++++++++++++--------------- 1 file changed, 195 insertions(+), 207 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 195c8c9b33e0..857e466df71d 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -887,216 +887,204 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * For Intel, each SSID bit identifies a PHP capability. * Also Intel HPC's may have RID=0. */ - if ((pdev->revision > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { - /* TODO: This code can be made to support non-Compaq or Intel - * subsystem IDs - */ - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); - if (rc) { - err("%s : pci_read_config_word failed\n", __func__); - goto err_disable_device; - } - dbg("Subsystem Vendor ID: %x\n", subsystem_vid); - if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { - err(msg_HPC_non_compaq_or_intel); - rc = -ENODEV; - goto err_disable_device; - } - - ctrl = kzalloc(sizeof(struct controller), GFP_KERNEL); - if (!ctrl) { - err("%s : out of memory\n", __func__); - rc = -ENOMEM; - goto err_disable_device; - } - - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); - if (rc) { - err("%s : pci_read_config_word failed\n", __func__); - goto err_free_ctrl; - } - - info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); - - /* Set Vendor ID, so it can be accessed later from other - * functions - */ - ctrl->vendor_id = vendor_id; - - switch (subsystem_vid) { - case PCI_VENDOR_ID_COMPAQ: - if (pdev->revision >= 0x13) { /* CIOBX */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 1; - ctrl->pcix_speed_capability = 1; - pci_read_config_byte(pdev, 0x41, &bus_cap); - if (bus_cap & 0x80) { - dbg("bus max supports 133MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; - break; - } - if (bus_cap & 0x40) { - dbg("bus max supports 100MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - break; - } - if (bus_cap & 20) { - dbg("bus max supports 66MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; - break; - } - if (bus_cap & 10) { - dbg("bus max supports 66MHz PCI\n"); - ctrl->speed_capability = PCI_SPEED_66MHz; - break; - } - - break; - } - - switch (subsystem_deviceid) { - case PCI_SUB_HPC_ID: - /* Original 6500/7000 implementation */ - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID2: - /* First Pushbutton implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID_INTC: - /* Third party (6500/7000) */ - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID3: - /* First 66 Mhz implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_66MHz; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID4: - /* First PCI-X implementation, 100MHz */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 1; - ctrl->pcix_speed_capability = 0; - break; - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - break; - - case PCI_VENDOR_ID_INTEL: - /* Check for speed capability (0=33, 1=66) */ - if (subsystem_deviceid & 0x0001) { - ctrl->speed_capability = PCI_SPEED_66MHz; - } else { - ctrl->speed_capability = PCI_SPEED_33MHz; - } - - /* Check for push button */ - if (subsystem_deviceid & 0x0002) { - /* no push button */ - ctrl->push_button = 0; - } else { - /* push button supported */ - ctrl->push_button = 1; - } - - /* Check for slot switch type (0=mechanical, 1=not mechanical) */ - if (subsystem_deviceid & 0x0004) { - /* no switch */ - ctrl->slot_switch_type = 0; - } else { - /* switch */ - ctrl->slot_switch_type = 1; - } - - /* PHP Status (0=De-feature PHP, 1=Normal operation) */ - if (subsystem_deviceid & 0x0008) { - ctrl->defeature_PHP = 1; /* PHP supported */ - } else { - ctrl->defeature_PHP = 0; /* PHP not supported */ - } - - /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0010) { - ctrl->alternate_base_address = 1; /* supported */ - } else { - ctrl->alternate_base_address = 0; /* not supported */ - } - - /* PCI Config Space Index (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0020) { - ctrl->pci_config_space = 1; /* supported */ - } else { - ctrl->pci_config_space = 0; /* not supported */ - } - - /* PCI-X support */ - if (subsystem_deviceid & 0x0080) { - /* PCI-X capable */ - ctrl->pcix_support = 1; - /* Frequency of operation in PCI-X mode */ - if (subsystem_deviceid & 0x0040) { - /* 133MHz PCI-X if bit 7 is 1 */ - ctrl->pcix_speed_capability = 1; - } else { - /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ - /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ - ctrl->pcix_speed_capability = 0; - } - } else { - /* Conventional PCI */ - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - } - break; - - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - - } else { + if ((pdev->revision <= 2) && (vendor_id != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_not_supported); return -ENODEV; } + /* TODO: This code can be made to support non-Compaq or Intel + * subsystem IDs + */ + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); + if (rc) { + err("%s : pci_read_config_word failed\n", __func__); + goto err_disable_device; + } + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + rc = -ENODEV; + goto err_disable_device; + } + + ctrl = kzalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __func__); + rc = -ENOMEM; + goto err_disable_device; + } + + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); + if (rc) { + err("%s : pci_read_config_word failed\n", __func__); + goto err_free_ctrl; + } + + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other + * functions + */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + if (pdev->revision >= 0x13) { /* CIOBX */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 1; + ctrl->pcix_speed_capability = 1; + pci_read_config_byte(pdev, 0x41, &bus_cap); + if (bus_cap & 0x80) { + dbg("bus max supports 133MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; + break; + } + if (bus_cap & 0x40) { + dbg("bus max supports 100MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + break; + } + if (bus_cap & 20) { + dbg("bus max supports 66MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; + break; + } + if (bus_cap & 10) { + dbg("bus max supports 66MHz PCI\n"); + ctrl->speed_capability = PCI_SPEED_66MHz; + break; + } + + break; + } + + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_66MHz; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID4: + /* First PCI-X implementation, 100MHz */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 1; + ctrl->pcix_speed_capability = 0; + break; + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) + ctrl->speed_capability = PCI_SPEED_66MHz; + else + ctrl->speed_capability = PCI_SPEED_33MHz; + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) + ctrl->push_button = 0; + else + ctrl->push_button = 1; + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) + ctrl->slot_switch_type = 0; + else + ctrl->slot_switch_type = 1; + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) + ctrl->defeature_PHP = 1; /* PHP supported */ + else + ctrl->defeature_PHP = 0; /* PHP not supported */ + + /* Alternate Base Address Register Interface + * (0=not supported, 1=supported) + */ + if (subsystem_deviceid & 0x0010) + ctrl->alternate_base_address = 1; + else + ctrl->alternate_base_address = 0; + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) + ctrl->pci_config_space = 1; + else + ctrl->pci_config_space = 0; + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + ctrl->pcix_support = 1; + if (subsystem_deviceid & 0x0040) + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + else + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + /* Tell the user that we found one. */ info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); @@ -1164,7 +1152,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_mem_region; } - // Check for 66Mhz operation + /* Check for 66Mhz operation */ ctrl->speed = get_controller_speed(ctrl); From 1d3ecf1376bf22be57c6138e7cdf425c6027b115 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:41 -0600 Subject: [PATCH 13/74] PCI Hotplug: cpqphp: clean up cpqphp_ctrl.c Style and whitespace cleanups, no functional change. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_ctrl.c | 172 ++++++++++++++---------------- 1 file changed, 80 insertions(+), 92 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index b02b8dddcf9f..2fa47af992a8 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -132,9 +132,8 @@ static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot = ctrl->slot; - while (slot && (slot->device != device)) { + while (slot && (slot->device != device)) slot = slot->next; - } return slot; } @@ -549,10 +548,10 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size if (!(*head)) return NULL; - if ( cpqhp_resource_sort_and_combine(head) ) + if (cpqhp_resource_sort_and_combine(head)) return NULL; - if ( sort_by_size(head) ) + if (sort_by_size(head)) return NULL; for (node = *head; node; node = node->next) { @@ -974,12 +973,8 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) struct pci_func *next; new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); - if (new_slot == NULL) { - /* I'm not dead yet! - * You will be. - */ + if (new_slot == NULL) return new_slot; - } new_slot->next = NULL; new_slot->configured = 1; @@ -1010,10 +1005,8 @@ static int slot_remove(struct pci_func * old_slot) return 1; next = cpqhp_slot_list[old_slot->bus]; - - if (next == NULL) { + if (next == NULL) return 1; - } if (next == old_slot) { cpqhp_slot_list[old_slot->bus] = old_slot->next; @@ -1022,9 +1015,8 @@ static int slot_remove(struct pci_func * old_slot) return 0; } - while ((next->next != old_slot) && (next->next != NULL)) { + while ((next->next != old_slot) && (next->next != NULL)) next = next->next; - } if (next->next == old_slot) { next->next = old_slot->next; @@ -1054,9 +1046,8 @@ static int bridge_slot_remove(struct pci_func *bridge) for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { next = cpqhp_slot_list[tempBus]; - while (!slot_remove(next)) { + while (!slot_remove(next)) next = cpqhp_slot_list[tempBus]; - } } next = cpqhp_slot_list[bridge->bus]; @@ -1286,17 +1277,17 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) hp_slot = func->device - ctrl->slot_device_offset; - if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { - /* - * The switch is open. - */ + /* + * The switch is open. + */ + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) rc = INTERLOCK_OPEN; - } else if (is_slot_enabled (ctrl, hp_slot)) { - /* - * The board is already on - */ + /* + * The board is already on + */ + else if (is_slot_enabled (ctrl, hp_slot)) rc = CARD_FUNCTIONING; - } else { + else { mutex_lock(&ctrl->crit_sect); /* turn on board without attaching to the bus */ @@ -1542,7 +1533,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) } /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ + if (temp_register != 0xFFFFFFFF) { res_lists.io_head = ctrl->io_head; res_lists.mem_head = ctrl->mem_head; res_lists.p_mem_head = ctrl->p_mem_head; @@ -1591,9 +1582,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) index = 0; do { new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); - if (new_slot && !new_slot->pci_dev) { + if (new_slot && !new_slot->pci_dev) cpqhp_configure_device(ctrl, new_slot); - } } while (new_slot); mutex_lock(&ctrl->crit_sect); @@ -2134,9 +2124,8 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) /* If the VGA Enable bit is set, remove isn't * supported */ - if (BCR & PCI_BRIDGE_CTL_VGA) { + if (BCR & PCI_BRIDGE_CTL_VGA) rc = REMOVE_NOT_SUPPORTED; - } } } @@ -2204,67 +2193,67 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num) num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; switch (test_num) { - case 1: - /* Do stuff here! */ + case 1: + /* Do stuff here! */ - /* Do that funky LED thing */ - /* so we can restore them later */ - save_LED = readl(ctrl->hpc_reg + LED_CONTROL); - work_LED = 0x01010101; - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); + /* Do that funky LED thing */ + /* so we can restore them later */ + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); + work_LED = 0x01010101; + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); - work_LED = 0x01010000; + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + /* Wait for SOGO interrupt */ + wait_for_ctrl_irq (ctrl); + + /* Get ready for next iteration */ + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - work_LED = 0x00000101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - /* Wait for SOGO interrupt */ - wait_for_ctrl_irq (ctrl); - - /* Get ready for next iteration */ - long_delay((3*HZ)/10); - work_LED = work_LED >> 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - /* Wait for SOGO interrupt */ - wait_for_ctrl_irq (ctrl); - - /* Get ready for next iteration */ - long_delay((3*HZ)/10); - work_LED = work_LED << 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - } - - /* put it back the way it was */ - writel(save_LED, ctrl->hpc_reg + LED_CONTROL); set_SOGO(ctrl); - /* Wait for SOBS to be unset */ + /* Wait for SOGO interrupt */ wait_for_ctrl_irq (ctrl); - break; - case 2: - /* Do other stuff here! */ - break; - case 3: - /* and more... */ - break; + + /* Get ready for next iteration */ + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } + + /* put it back the way it was */ + writel(save_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + /* Wait for SOBS to be unset */ + wait_for_ctrl_irq (ctrl); + break; + case 2: + /* Do other stuff here! */ + break; + case 3: + /* and more... */ + break; } return 0; } @@ -2333,9 +2322,9 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func while ((function < max_functions) && (!stop_it)) { pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - if (ID == 0xFFFFFFFF) { /* There's nothing there. */ + if (ID == 0xFFFFFFFF) { function++; - } else { /* There's something there */ + } else { /* Setup slot structure. */ new_slot = cpqhp_slot_create(func->bus); @@ -2360,8 +2349,8 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func /* - Configuration logic that involves the hotplug data structures and - their bookkeeping + * Configuration logic that involves the hotplug data structures and + * their bookkeeping */ @@ -2414,7 +2403,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func if (rc) return rc; - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* set Primary bus */ dbg("set Primary bus = %d\n", func->bus); rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); @@ -2956,11 +2945,10 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func /* Program IRQ based on card type */ rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (class_code == PCI_BASE_CLASS_STORAGE) { + if (class_code == PCI_BASE_CLASS_STORAGE) IRQ = cpqhp_disk_irq; - } else { + else IRQ = cpqhp_nic_irq; - } } /* IRQ Line */ From de86ae16d55a23315cdf1dae68df9de55312cf25 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:46 -0600 Subject: [PATCH 14/74] PCI Hotplug: cpqphp: refactor cpqphp_save_slot_config Check for an empty slot, and return early if so. This allows us to un-indent the rest of the function by one level. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_pci.c | 111 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 59 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 2e96bae3c82a..1f1c90dd791d 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -494,7 +494,7 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) u8 secondary_bus; int sub_bus; int max_functions; - int function; + int function = 0; int cloop = 0; int stop_it; @@ -503,65 +503,58 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) ctrl->pci_bus->number = new_slot->bus; pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { /* device in slot */ - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - /* Recurse the subordinate bus */ - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - /* Save the config headers for the secondary - * bus. - */ - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return(rc); - ctrl->pci_bus->number = new_slot->bus; - - } /* End of IF */ - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in the Class Code and the Header type. - */ - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - } else { /* Something there */ - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); - - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); - - stop_it++; - } - } - - } while (function < max_functions); - } /* End of IF (device in slot?) */ - else { + if (ID == 0xFFFFFFFF) return 2; + + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; + + while (function < max_functions) { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus */ + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + /* Save the config headers for the secondary + * bus. + */ + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return(rc); + ctrl->pci_bus->number = new_slot->bus; + + } + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + + function++; + + stop_it = 0; + + /* this loop skips to the next present function + * reading in the Class Code and the Header type. + */ + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) + function++; + else { + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + stop_it++; + } + } + } return 0; From 4aabb58e1f544e97dbb97d0ce29bdfc9108f2f2c Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:52 -0600 Subject: [PATCH 15/74] PCI Hotplug: cpqphp: style cleanups Clean up style, whitespace in cpqphp_pci.c Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_pci.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 1f1c90dd791d..bd384e94f212 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -950,15 +950,13 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) return(1); } } /* End of base register loop */ - /* Some other unknown header type */ - } else { } /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } - return(0); + return 0; } @@ -993,9 +991,8 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) /* Start at the top of config space so that the control * registers are programmed last */ - for (cloop = 0x3C; cloop > 0; cloop -= 4) { + for (cloop = 0x3C; cloop > 0; cloop -= 4) pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); - } pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); @@ -1210,9 +1207,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); dbg("rom_resource_table = %p\n", rom_resource_table); - if (rom_resource_table == NULL) { + if (rom_resource_table == NULL) return -ENODEV; - } + /* Sum all resources and setup resource maps */ unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); dbg("unused_IRQ = %x\n", unused_IRQ); @@ -1245,13 +1242,11 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st temp = 0; - if (!cpqhp_nic_irq) { + if (!cpqhp_nic_irq) cpqhp_nic_irq = ctrl->cfgspc_irq; - } - if (!cpqhp_disk_irq) { + if (!cpqhp_disk_irq) cpqhp_disk_irq = ctrl->cfgspc_irq; - } dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); From 1d2e8b1c58ef96b8834b139caf4357effedcb5ab Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:23:57 -0600 Subject: [PATCH 16/74] PCI Hotplug: cpqphp: refactor cpqhp_save_config Handle an empty slot at the top of the loop, and continue early. This allows us to un-indent the rest of the function by one level. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_pci.c | 198 +++++++++++++++---------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index bd384e94f212..2909e3f6caa7 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -359,121 +359,121 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) ctrl->pci_bus->number = busnumber; for (device = FirstSupported; device <= LastSupported; device++) { ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { /* device in slot */ - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - /* If multi-function device, set max_functions to 8 */ - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - /* Recurse the subordinate bus - * get the subordinate bus number - */ - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - /* Save secondary bus cfg spc - * with this recursive call. - */ - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return rc; - ctrl->pci_bus->number = busnumber; - } - } - - index = 0; - new_slot = cpqhp_slot_find(busnumber, device, index++); - while (new_slot && - (new_slot->function != (u8) function)) - new_slot = cpqhp_slot_find(busnumber, device, index++); - - if (!new_slot) { - /* Setup slot structure. */ - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) - return(1); - } + if (ID == 0xFFFFFFFF) { + if (is_hot_plug) { + /* Setup slot structure with entry for empty + * slot + */ + new_slot = cpqhp_slot_create(busnumber); + if (new_slot == NULL) + return 1; new_slot->bus = (u8) busnumber; new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - /* In case of unsupported board */ - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + continue; + } - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + /* If multi-function device, set max_functions to 8 */ + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus + * get the subordinate bus number + */ + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + /* Save secondary bus cfg spc + * with this recursive call. + */ + rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return rc; + ctrl->pci_bus->number = busnumber; } + } - function++; + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) + new_slot = cpqhp_slot_find(busnumber, device, index++); - stop_it = 0; - - /* this loop skips to the next present function - * reading in Class Code and Header type. - */ - - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - } else { /* Something there */ - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - stop_it++; - } - } - - } while (function < max_functions); - } /* End of IF (device in slot?) */ - else if (is_hot_plug) { - /* Setup slot structure with entry for empty slot */ - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); + if (!new_slot) { + /* Setup slot structure. */ + new_slot = cpqhp_slot_create(busnumber); + if (new_slot == NULL) + return 1; } new_slot->bus = (u8) busnumber; new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + /* In case of unsupported board */ + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + /* this loop skips to the next present function + * reading in Class Code and Header type. + */ + while ((function < max_functions) && (!stop_it)) { + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { + function++; + continue; + } + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + stop_it++; + } + + } while (function < max_functions); } /* End of FOR loop */ - return(0); + return 0; } From b019ee679afde950f2d01b1af0530453aa60af3f Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:24:02 -0600 Subject: [PATCH 17/74] PCI Hotplug: cpqphp: clean up accesses to pcibios_get_irq_routing_table() Instead of making multiple calls to pcibios_get_irq_routing_table, let's just do it once and save the answer. The reason we were making multiple calls is because we liked to calculate its length and perform some loop over it. Instead of open-coding the length calculation every time, provide it in an inline helper function. Finally, since pci_print_IRQ_route() is used only for debug, let's only do it when cpqhp_debug is set. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp.h | 9 ++++ drivers/pci/hotplug/cpqphp_core.c | 72 +++++++++++++------------------ drivers/pci/hotplug/cpqphp_pci.c | 36 +++------------- 3 files changed, 47 insertions(+), 70 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index 308f82b1fc9a..1d5561c6bad4 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -455,6 +455,7 @@ extern int cpqhp_debug; extern int cpqhp_legacy_mode; extern struct controller *cpqhp_ctrl_list; extern struct pci_func *cpqhp_slot_list[256]; +extern struct irq_routing_table *cpqhp_routing_table; /* these can be gotten rid of, but for debugging they are purty */ extern u8 cpqhp_nic_irq; @@ -733,4 +734,12 @@ static inline int wait_for_ctrl_irq(struct controller *ctrl) return retval; } +#include +static inline int cpqhp_routing_table_length(void) +{ + BUG_ON(cpqhp_routing_table == NULL); + return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) / + sizeof(struct irq_info)); +} + #endif diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 857e466df71d..7888b37c6c8e 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -44,7 +44,6 @@ #include "cpqphp.h" #include "cpqphp_nvram.h" -#include /* Global variables */ @@ -52,6 +51,7 @@ int cpqhp_debug; int cpqhp_legacy_mode; struct controller *cpqhp_ctrl_list; /* = NULL */ struct pci_func *cpqhp_slot_list[256]; +struct irq_routing_table *cpqhp_routing_table; /* local variables */ static void __iomem *smbios_table; @@ -154,40 +154,42 @@ static int init_SERR(struct controller * ctrl) return 0; } -/* nice debugging output */ -static int pci_print_IRQ_route (void) +static int init_cpqhp_routing_table(void) { - struct irq_routing_table *routing_table; int len; - int loop; - u8 tbus, tdevice, tslot; - - routing_table = pcibios_get_irq_routing_table(); - if (routing_table == NULL) { - err("No BIOS Routing Table??? Not good\n"); + cpqhp_routing_table = pcibios_get_irq_routing_table(); + if (cpqhp_routing_table == NULL) return -ENOMEM; - } - len = (routing_table->size - sizeof(struct irq_routing_table)) / - sizeof(struct irq_info); - /* Make sure I got at least one entry */ + len = cpqhp_routing_table_length(); if (len == 0) { - kfree(routing_table); + kfree(cpqhp_routing_table); + cpqhp_routing_table = NULL; return -1; } - dbg("bus dev func slot\n"); + return 0; +} +/* nice debugging output */ +static void pci_print_IRQ_route(void) +{ + int len; + int loop; + u8 tbus, tdevice, tslot; + + len = cpqhp_routing_table_length(); + + dbg("bus dev func slot\n"); for (loop = 0; loop < len; ++loop) { - tbus = routing_table->slots[loop].bus; - tdevice = routing_table->slots[loop].devfn; - tslot = routing_table->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn; + tslot = cpqhp_routing_table->slots[loop].slot; dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); } - kfree(routing_table); - return 0; + return; } @@ -331,7 +333,6 @@ static int ctrl_slot_cleanup (struct controller * ctrl) static int get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) { - struct irq_routing_table *PCIIRQRoutingInfoLength; u32 work; long len; long loop; @@ -342,26 +343,14 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) bridgeSlot = 0xFF; - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - /* Make sure I got at least one entry */ - if (len == 0) { - kfree(PCIIRQRoutingInfoLength); - return -1; - } - + len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn >> 3; + tslot = cpqhp_routing_table->slots[loop].slot; if ((tbus == bus_num) && (tdevice == dev_num)) { *slot = tslot; - kfree(PCIIRQRoutingInfoLength); return 0; } else { /* Did not get a match on the target PCI device. Check @@ -396,10 +385,8 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) */ if (bridgeSlot != 0xFF) { *slot = bridgeSlot; - kfree(PCIIRQRoutingInfoLength); return 0; } - kfree(PCIIRQRoutingInfoLength); /* Couldn't find an entry in the routing table for this PCI device */ return -1; } @@ -782,10 +769,13 @@ static int one_time_init(void) power_mode = 0; - retval = pci_print_IRQ_route(); + retval = init_cpqhp_routing_table(); if (retval) goto error; + if (cpqhp_debug) + pci_print_IRQ_route(); + dbg("Initialize + Start the notification mechanism \n"); retval = cpqhp_event_start_thread(); diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 2909e3f6caa7..6201281b9dab 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -37,7 +37,6 @@ #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" -#include u8 cpqhp_nic_irq; @@ -244,39 +243,23 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) { - struct irq_routing_table *PCIIRQRoutingInfoLength; - long len; - long loop; + int loop, len; u32 work; - u8 tbus, tdevice, tslot; - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - /* Make sure I got at least one entry */ - if (len == 0) { - kfree(PCIIRQRoutingInfoLength ); - return -1; - } - + len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn; + tslot = cpqhp_routing_table->slots[loop].slot; if (tslot == slot) { *bus_num = tbus; *dev_num = tdevice; ctrl->pci_bus->number = tbus; pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); - if (!nobridge || (work == 0xffffffff)) { - kfree(PCIIRQRoutingInfoLength ); + if (!nobridge || (work == 0xffffffff)) return 0; - } dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); @@ -287,17 +270,12 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num dbg("Scan bus for Non Bridge: bus %d\n", tbus); if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { *bus_num = tbus; - kfree(PCIIRQRoutingInfoLength ); return 0; } - } else { - kfree(PCIIRQRoutingInfoLength ); + } else return 0; - } - } } - kfree(PCIIRQRoutingInfoLength ); return -1; } From e3265ea364c7ed5accc9955f8b805c380149870f Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:24:07 -0600 Subject: [PATCH 18/74] PCI Hotplug: cpqphp: eliminate dead code - PCI_ScanBusNonBridge I have no clue what the original intent here was, but the code as written is useless. The old dbg() statement above the old callsite might lead one to think that at one point, there was supposed to be some recursion, but any sense of sanity here has been lost to the ravages of time. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp_pci.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 6201281b9dab..3e3acc7e7461 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -193,16 +193,6 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) } -/* - * WTF??? This function isn't in the code, yet a function calls it, but the - * compiler optimizes it away? strange. Here as a placeholder to keep the - * compiler happy. - */ -static int PCI_ScanBusNonBridge (u8 bus, u8 device) -{ - return 0; -} - static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) { u16 tdevice; @@ -231,9 +221,9 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev /* Yep we got one. bridge ? */ if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); + /* XXX: no recursion, wtf? */ dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); - if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) - return 0; + return 0; } } From 6d1e87daeeba864a18535b7f3aed0e65f5f52275 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:24:12 -0600 Subject: [PATCH 19/74] PCI Hotplug: cpqphp: constify slot_name() Eliminate this warning: warning: return discards qualifiers from pointer target type Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/cpqphp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index 1d5561c6bad4..53836001d511 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -464,7 +464,7 @@ extern u8 cpqhp_disk_irq; /* inline functions */ -static inline char *slot_name(struct slot *slot) +static inline const char *slot_name(struct slot *slot) { return hotplug_slot_name(slot->hotplug_slot); } From 12a9da0fcb147b46de33bb919b1de2bb92c9e2a9 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:24:17 -0600 Subject: [PATCH 20/74] PCI Hotplug: cpqphp: don't use pci_find_slot() Convert uses of pci_find_slot to modern API. In the conversion sites, we end up calling pci_dev_put() right away. This may seem like it misses the entire point of doing something like pci_get_bus_and_slot(), since we drop the reference so soon, but it turns out we don't actually do much with the returned pci_dev. I plan on untangling cpqphp further, but clearly cpqphp never worried too much about a properly refcounted pci_dev anyway. For now, this conversion seems reasonable, as it gets rid of the last in-tree caller of pci_find_slot. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/Kconfig | 2 +- drivers/pci/hotplug/cpqphp_pci.c | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 9aa4fe100a0d..ac888ccfa161 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -41,7 +41,7 @@ config HOTPLUG_PCI_FAKE config HOTPLUG_PCI_COMPAQ tristate "Compaq PCI Hotplug driver" - depends on X86 && PCI_BIOS && PCI_LEGACY + depends on X86 && PCI_BIOS help Say Y here if you have a motherboard with a Compaq PCI Hotplug controller. diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 3e3acc7e7461..6173b9a4544e 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -88,7 +88,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) int num; if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function)); /* No pci device, we need to create it then */ if (func->pci_dev == NULL) { @@ -98,7 +98,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) if (num) pci_bus_add_devices(ctrl->pci_dev->bus); - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); if (func->pci_dev == NULL) { dbg("ERROR: pci_dev still null\n"); return 0; @@ -111,6 +111,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) pci_do_scan_bus(child); } + pci_dev_put(func->pci_dev); + return 0; } @@ -122,9 +124,11 @@ int cpqhp_unconfigure_device(struct pci_func* func) dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, PCI_DEVFN(func->device, j)); - if (temp) + struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); + if (temp) { + pci_dev_put(temp); pci_remove_bus_device(temp); + } } return 0; } @@ -406,7 +410,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) new_slot->switch_save = 0x10; /* In case of unsupported board */ new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); for (cloop = 0; cloop < 0x20; cloop++) { rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); @@ -414,6 +418,8 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) return rc; } + pci_dev_put(new_slot->pci_dev); + function++; stop_it = 0; From 3b073eda9557975a87a27b08a46a545fe8da66fb Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 31 Mar 2009 09:24:22 -0600 Subject: [PATCH 21/74] PCI: remove deprecated pci_find_slot() interface The last in-tree caller of pci_find_slot has been converted, so let's get rid of this deprecated interface. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/search.c | 30 ------------------------------ include/linux/pci.h | 8 -------- 2 files changed, 38 deletions(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 710d4ea69568..650bc0a538dc 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -114,36 +114,6 @@ pci_find_next_bus(const struct pci_bus *from) } #ifdef CONFIG_PCI_LEGACY -/** - * pci_find_slot - locate PCI device from a given PCI slot - * @bus: number of PCI bus on which desired PCI device resides - * @devfn: encodes number of PCI slot in which the desired PCI - * device resides and the logical device number within that slot - * in case of multi-function devices. - * - * Given a PCI bus and slot/function number, the desired PCI device - * is located in system global list of PCI devices. If the device - * is found, a pointer to its data structure is returned. If no - * device is found, %NULL is returned. - * - * NOTE: Do not use this function any more; use pci_get_slot() instead, as - * the PCI device returned by this function can disappear at any moment in - * time. - */ -struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) -{ - struct pci_dev *dev = NULL; - - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (dev->bus->number == bus && dev->devfn == devfn) { - pci_dev_put(dev); - return dev; - } - } - return NULL; -} -EXPORT_SYMBOL(pci_find_slot); - /** * pci_find_device - begin or continue searching for a PCI device by vendor/device id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids diff --git a/include/linux/pci.h b/include/linux/pci.h index 6dfa47d25ba4..19ee92c53ef7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -599,8 +599,6 @@ extern void pci_sort_breadthfirst(void); struct pci_dev __deprecated *pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from); -struct pci_dev __deprecated *pci_find_slot(unsigned int bus, - unsigned int devfn); #endif /* CONFIG_PCI_LEGACY */ enum pci_lost_interrupt_reason { @@ -936,12 +934,6 @@ static inline struct pci_dev *pci_find_device(unsigned int vendor, return NULL; } -static inline struct pci_dev *pci_find_slot(unsigned int bus, - unsigned int devfn) -{ - return NULL; -} - static inline struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) From 9e9f46c44e487af0a82eb61b624553e2f7118f5b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 11 Jun 2009 10:58:28 -0700 Subject: [PATCH 22/74] PCI: use ACPI _CRS data by default At this point, it seems to solve more problems than it causes, so let's try using it by default. It's an easy revert if it ends up causing trouble. Reviewed-by: Yinghai Lu Acked-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 2 +- arch/x86/include/asm/pci_x86.h | 2 +- arch/x86/pci/acpi.c | 2 +- arch/x86/pci/amd_bus.c | 2 +- arch/x86/pci/common.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fd5cac013037..7bdaf5080408 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1787,7 +1787,7 @@ and is between 256 and 4096 characters. It is defined in the file IRQ routing is enabled. noacpi [X86] Do not use ACPI for IRQ routing or for PCI scanning. - use_crs [X86] Use _CRS for PCI resource + nocrs [X86] Don't use _CRS for PCI resource allocation. routeirq Do IRQ routing for all PCI devices. This is normally done in pci_enable_device(), diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index e60fd3e14bdf..cb739cc0a080 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -25,7 +25,7 @@ #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 #define PCI_CAN_SKIP_ISA_ALIGN 0x8000 -#define PCI_USE__CRS 0x10000 +#define PCI_NO_ROOT_CRS 0x10000 #define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000 #define PCI_HAS_IO_ECS 0x40000 #define PCI_NOASSIGN_ROMS 0x80000 diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index c0ecf250fe51..8d898e0d3609 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -217,7 +217,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do #endif } - if (bus && (pci_probe & PCI_USE__CRS)) + if (bus && !(pci_probe & PCI_NO_ROOT_CRS)) get_current_resources(device, busnum, domain, bus); return bus; } diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index f893d6a6e803..2255f880678b 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c @@ -101,7 +101,7 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b) struct pci_root_info *info; /* don't go for it if _CRS is used */ - if (pci_probe & PCI_USE__CRS) + if (!(pci_probe & PCI_NO_ROOT_CRS)) return; /* if only one root bus, don't need to anything */ diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 2202b6257b82..4740119e4bb7 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -515,8 +515,8 @@ char * __devinit pcibios_setup(char *str) } else if (!strcmp(str, "assign-busses")) { pci_probe |= PCI_ASSIGN_ALL_BUSSES; return NULL; - } else if (!strcmp(str, "use_crs")) { - pci_probe |= PCI_USE__CRS; + } else if (!strcmp(str, "nocrs")) { + pci_probe |= PCI_NO_ROOT_CRS; return NULL; } else if (!strcmp(str, "earlydump")) { pci_early_dump_regs = 1; From 8e822df700694ca6850d1e0c122fd7004b2778d8 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 8 Jun 2009 09:27:25 +0800 Subject: [PATCH 23/74] PCI: disable ASPM on VIA root-port-under-bridge configurations VIA has a strange chipset, it has root port under a bridge. Disable ASPM for such strange chipset. Cc: stable@kernel.org Tested-by: Wolfgang Denk Signed-off-by: Shaohua Li Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b0367f168af4..777b2c76caf5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -638,6 +638,10 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; + /* VIA has a strange chipset, root port is under a bridge */ + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && + pdev->bus->self) + return; down_read(&pci_bus_sem); if (list_empty(&pdev->subordinate->devices)) goto out; From 57fbf52c86addd8e25d1975fac0d59d982d1f6ec Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 7 May 2009 11:28:41 +0300 Subject: [PATCH 24/74] PCI MSI: let drivers retry when not enough vectors pci_enable_msix currently returns -EINVAL if you ask for more vectors than supported by the device, which would typically cause fallback to regular interrupts. It's better to return the table size, making the driver retry MSI-X with less vectors. Reviewed-by: Matthew Wilcox Signed-off-by: Michael S. Tsirkin Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 7ffac27d5d4a..f2725710593a 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -691,8 +691,8 @@ int pci_msix_table_size(struct pci_dev *dev) * indicates the successful configuration of MSI-X capability structure * with new allocated MSI-X irqs. A return of < 0 indicates a failure. * Or a return of > 0 indicates that driver request is exceeding the number - * of irqs available. Driver should use the returned value to re-send - * its request. + * of irqs or MSI-X vectors available. Driver should use the returned value to + * re-send its request. **/ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { @@ -708,7 +708,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) nr_entries = pci_msix_table_size(dev); if (nvec > nr_entries) - return -EINVAL; + return nr_entries; /* Check for any invalid entries */ for (i = 0; i < nvec; i++) { From af4c5f985afd8d4cfdf402aaa03677f2cb96e37c Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Mon, 18 May 2009 19:02:38 -0600 Subject: [PATCH 25/74] PCI: eliminate redundant pci_stop_dev() call from pci_destroy_dev() We always call pci_stop_bus_device before calling pci_destroy_dev. Since pci_stop_bus_device calls pci_stop_dev, there is no need for pci_destroy_dev to repeat the call. Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/remove.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 86503c14ce7e..176615e7231f 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -32,8 +32,6 @@ static void pci_stop_dev(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev) { - pci_stop_dev(dev); - /* Remove the device from the device lists, and prevent any further * list accesses from this device */ down_write(&pci_bus_sem); From 4d135dbee7b0a89e946f7ba284f2b957505a2c3a Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 20 May 2009 17:11:57 +0800 Subject: [PATCH 26/74] PCI: fix SR-IOV function dependency link problem PCIe root complex integrated endpoint does not implement ARI, so this kind of endpoint uses 3-bit function number. The function dependency link of the integrated endpoint should be calculated using the device number plus the value from function dependency link register. Normal endpoint always implements ARI and the function dependency link register contains 8-bit function number (i.e. `devfn' from software's perspective). Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes --- drivers/pci/iov.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b497daab3d4a..e87fe95da814 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -487,6 +487,8 @@ found: iov->self = dev; pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); + if (dev->pcie_type == PCI_EXP_TYPE_RC_END) + iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link); if (pdev) iov->dev = pci_dev_get(pdev); From f62795f1e892ca9269849fa83de97621da7e02c0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 18 May 2009 22:51:12 +0200 Subject: [PATCH 27/74] PCI PM: Follow PCI_PM_CTRL_NO_SOFT_RESET during transitions from D3 According to the PCI PM specification (PCI Bus Power Management Interface Specification, Rev. 1.2, Section 5.4.1) we are supposed to reinitialize devices that have PCI_PM_CTRL_NO_SOFT_RESET clear during all transitions from PCI_D3hot to PCI_D0, but we only do it if the device's current_state field is equal to PCI_UNKNOWN. This may lead to problems if a device with PCI_PM_CTRL_NO_SOFT_RESET unset is put into PCI_D3hot at run time by its driver and pci_set_power_state() is used to put it back into PCI_D0, because in that case the device will remain uninitialized after pci_set_power_state() has returned. Prevent that from happening by modifying pci_raw_set_power_state() to reinitialize devices with PCI_PM_CTRL_NO_SOFT_RESET unset during all transitions from D3 to D0. Cc: stable@kernel.org Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1a91bf9687af..761557688b18 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -480,6 +480,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= state; break; + case PCI_D3hot: + case PCI_D3cold: case PCI_UNKNOWN: /* Boot-up */ if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) From 43c16408842b0eeb367c23a6fa540ce69f99e347 Mon Sep 17 00:00:00 2001 From: Andrew Patterson Date: Wed, 22 Apr 2009 16:52:09 -0600 Subject: [PATCH 28/74] PCI: Add support for turning PCIe ECRC on or off Adds support for PCI Express transaction layer end-to-end CRC checking (ECRC). This patch will enable/disable ECRC checking by setting/clearing the ECRC Check Enable and/or ECRC Generation Enable bits for devices that support ECRC. The ECRC setting is controlled by the "pci=ecrc=" command-line option. If this option is not set or is set to 'bios", the enable and generation bits are left in whatever state that firmware/BIOS set them to. The "off" setting turns them off, and the "on" option turns them on (if the device supports it). Turning ECRC on or off can be a data integrity versus performance tradeoff. In theory, turning it on will catch more data errors, turning it off means possibly better performance since CRC does not need to be calculated by the PCIe hardware and packet sizes are reduced. Signed-off-by: Andrew Patterson Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 6 ++ drivers/pci/pci.c | 2 + drivers/pci/pcie/aer/Kconfig | 13 +++ drivers/pci/pcie/aer/Makefile | 2 + drivers/pci/pcie/aer/aerdrv_core.c | 16 ++-- drivers/pci/pcie/aer/ecrc.c | 131 ++++++++++++++++++++++++++++ include/linux/pci.h | 11 +++ 7 files changed, 174 insertions(+), 7 deletions(-) create mode 100644 drivers/pci/pcie/aer/ecrc.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7bdaf5080408..395d1a013ebb 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1824,6 +1824,12 @@ and is between 256 and 4096 characters. It is defined in the file PAGE_SIZE is used as alignment. PCI-PCI bridge can be specified, if resource windows need to be expanded. + ecrc= Enable/disable PCIe ECRC (transaction layer + end-to-end CRC checking). + bios: Use BIOS/firmware settings. This is the + the default. + off: Turn ECRC off + on: Turn ECRC on. pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 761557688b18..56fb18d2cb52 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2588,6 +2588,8 @@ static int __init pci_setup(char *str) } else if (!strncmp(str, "resource_alignment=", 19)) { pci_set_resource_alignment_param(str + 19, strlen(str + 19)); + } else if (!strncmp(str, "ecrc=", 5)) { + pcie_ecrc_get_policy(str + 5); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig index c3bde588aa13..db4cb950933a 100644 --- a/drivers/pci/pcie/aer/Kconfig +++ b/drivers/pci/pcie/aer/Kconfig @@ -10,3 +10,16 @@ config PCIEAER This enables PCI Express Root Port Advanced Error Reporting (AER) driver support. Error reporting messages sent to Root Port will be handled by PCI Express AER driver. + + +# +# PCI Express ECRC +# +config PCIE_ECRC + bool "PCI Express ECRC settings control" + depends on PCIEAER + help + Used to override firmware/bios settings for PCI Express ECRC + (transaction layer end-to-end CRC checking). + + When in doubt, say N. diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile index 8da3bd8455a8..7f93411c56e5 100644 --- a/drivers/pci/pcie/aer/Makefile +++ b/drivers/pci/pcie/aer/Makefile @@ -4,6 +4,8 @@ obj-$(CONFIG_PCIEAER) += aerdriver.o +obj-$(CONFIG_PCIE_ECRC) += ecrc.o + aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 307452f30035..dd3829e68e3f 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -113,15 +113,17 @@ static void set_device_error_reporting(struct pci_dev *dev, void *data) { bool enable = *((bool *)data); - if (dev->pcie_type != PCIE_RC_PORT && - dev->pcie_type != PCIE_SW_UPSTREAM_PORT && - dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT) - return; + if (dev->pcie_type == PCIE_RC_PORT || + dev->pcie_type == PCIE_SW_UPSTREAM_PORT || + dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) { + if (enable) + pci_enable_pcie_error_reporting(dev); + else + pci_disable_pcie_error_reporting(dev); + } if (enable) - pci_enable_pcie_error_reporting(dev); - else - pci_disable_pcie_error_reporting(dev); + pcie_set_ecrc_checking(dev); } /** diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c new file mode 100644 index 000000000000..ece97df4df6d --- /dev/null +++ b/drivers/pci/pcie/aer/ecrc.c @@ -0,0 +1,131 @@ +/* + * Enables/disables PCIe ECRC checking. + * + * (C) Copyright 2009 Hewlett-Packard Development Company, L.P. + * Andrew Patterson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include "../../pci.h" + +#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */ +#define ECRC_POLICY_OFF 1 /* ECRC off for performance */ +#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */ + +static int ecrc_policy = ECRC_POLICY_DEFAULT; + +static const char *ecrc_policy_str[] = { + [ECRC_POLICY_DEFAULT] = "bios", + [ECRC_POLICY_OFF] = "off", + [ECRC_POLICY_ON] = "on" +}; + +/** + * enable_ercr_checking - enable PCIe ECRC checking for a device + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +static int enable_ecrc_checking(struct pci_dev *dev) +{ + int pos; + u32 reg32; + + if (!dev->is_pcie) + return -ENODEV; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return -ENODEV; + + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + if (reg32 & PCI_ERR_CAP_ECRC_GENC) + reg32 |= PCI_ERR_CAP_ECRC_GENE; + if (reg32 & PCI_ERR_CAP_ECRC_CHKC) + reg32 |= PCI_ERR_CAP_ECRC_CHKE; + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + return 0; +} + +/** + * disable_ercr_checking - disables PCIe ECRC checking for a device + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +static int disable_ecrc_checking(struct pci_dev *dev) +{ + int pos; + u32 reg32; + + if (!dev->is_pcie) + return -ENODEV; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return -ENODEV; + + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + return 0; +} + +/** + * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy + * @dev: the PCI device + */ +void pcie_set_ecrc_checking(struct pci_dev *dev) +{ + switch (ecrc_policy) { + case ECRC_POLICY_DEFAULT: + return; + case ECRC_POLICY_OFF: + disable_ecrc_checking(dev); + break; + case ECRC_POLICY_ON: + enable_ecrc_checking(dev);; + break; + default: + return; + } +} + +/** + * pcie_ecrc_get_policy - parse kernel command-line ecrc option + */ +void pcie_ecrc_get_policy(char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++) + if (!strncmp(str, ecrc_policy_str[i], + strlen(ecrc_policy_str[i]))) + break; + if (i >= ARRAY_SIZE(ecrc_policy_str)) + return; + + ecrc_policy = i; +} diff --git a/include/linux/pci.h b/include/linux/pci.h index 19ee92c53ef7..ec03b90d3510 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -878,6 +878,17 @@ static inline int pcie_aspm_enabled(void) extern int pcie_aspm_enabled(void); #endif +#ifndef CONFIG_PCIE_ECRC +static inline void pcie_set_ecrc_checking(struct pci_dev *dev) +{ + return; +} +static inline void pcie_ecrc_get_policy(char *str) {}; +#else +extern void pcie_set_ecrc_checking(struct pci_dev *dev); +extern void pcie_ecrc_get_policy(char *str); +#endif + #define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1) #ifdef CONFIG_HT_IRQ From 4096ed0fc7c6ed83da44ab27ab7d1c7cd6e8e175 Mon Sep 17 00:00:00 2001 From: Mats Erik Andersson Date: Tue, 12 May 2009 12:05:23 +0200 Subject: [PATCH 29/74] PCI: expose SMBus on Asus notebook A6L Addition of one unknown subsystem identifier to the quirks handler for chipset i82855GM_HB on notebook Asus A6L. This exposes the otherwise hidden SMBus controller within the south bridge ICH4-M. Signed-off-by: Mats Erik Andersson Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3067673d54f6..a778c84d04a9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1133,6 +1133,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ case 0x1821: /* M5N notebook */ + case 0x1897: /* A6L notebook */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) From 26c56dc0c4fbdf3af12ebc48278f09ef65ddb4dd Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Tue, 12 May 2009 13:49:26 -0700 Subject: [PATCH 30/74] PCI quirk: unhide 'Overflow' device on i828{6,7}5P/PE chipsets Some BIOSes hide 'overflow' device (dev #6) for i82875P/PE chipsets. The same happens for i82865P/PE. Add a quirk to enable this device. This allows i82875 EDAC driver to bind to chipset's dev #6 and not dev #0 as the latter is used by AGP driver. On my laptop (i82865P based) ACPI code is disabling this device again in \_SB.PCI0._CRS method (called at least at PNP init time). This can be easily worked around by patching DSDT. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Michal Miroslaw Acked-by: Doug Thompson Signed-off-by: Andrew Morton Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a778c84d04a9..15a8ab7ea911 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2017,6 +2017,28 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, quirk_brcm_570x_limit_vpd); +/* Originally in EDAC sources for i82875P: + * Intel tells BIOS developers to hide device 6 which + * configures the overflow device access containing + * the DRBs - this is where we expose device 6. + * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm + */ +static void __devinit quirk_unhide_mch_dev6(struct pci_dev *dev) +{ + u8 reg; + + if (pci_read_config_byte(dev, 0xF4, ®) == 0 && !(reg & 0x02)) { + dev_info(&dev->dev, "Enabling MCH 'Overflow' Device\n"); + pci_write_config_byte(dev, 0xF4, reg | 0x02); + } +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, + quirk_unhide_mch_dev6); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, + quirk_unhide_mch_dev6); + + #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually From 74c57428971d28863ec1804b1dd453930bbe1306 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Tue, 12 May 2009 13:49:25 -0700 Subject: [PATCH 31/74] PCI quirk: HP hides SMBus controller in Compaq nx9500 laptops I found no references to SMBus in ACPI DSDT disassembly on my laptop so this should be safe. Signed-off-by: Michal Miroslaw Signed-off-by: Andrew Morton Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 15a8ab7ea911..47d62084d5b7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1164,6 +1164,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ case 0x12bd: /* HP D530 */ + case 0x006a: /* HP Compaq nx9500 */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB) From 84845c070ce3ac4d3bd2c148fa20ba8ce5409167 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 26 May 2009 16:05:06 +0900 Subject: [PATCH 32/74] PCI: use pci_is_root_bus() in acpi_pci_get_bridge_handle() Use pci_is_root_bus() in acpi_pci_get_bridge_handle() to check if the pci bus is root, for code consistency. Reviewed-by: Grant Grundler Reviewed-by: Alex Chiang Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- include/linux/pci-acpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 092e82e0048c..df67c78dfe24 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -23,7 +23,7 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus) { - if (pbus->parent) + if (!pci_is_root_bus(pbus)) return DEVICE_ACPI_HANDLE(&(pbus->self->dev)); return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus), pbus->number); From a222b8f83b995e9c6fe2aff2a8125facb49f658e Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 26 May 2009 16:05:33 +0900 Subject: [PATCH 33/74] PCI: use pci_is_root_bus() in acpi_find_root_bridge_handle() Use pci_is_root_bus() in acpi_find_root_bridge_handle() to check if the pci bus is root, for code consistency. Reviewed-by: Alex Chiang Reviewed-by: Grant Grundler Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- include/linux/pci-acpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index df67c78dfe24..93a7c08f869d 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -15,7 +15,7 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) { struct pci_bus *pbus = pdev->bus; /* Find a PCI root bus */ - while (pbus->parent) + while (!pci_is_root_bus(pbus)) pbus = pbus->parent; return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus), pbus->number); From 6e3f36df0ffa433e273c89f1447c94382a9db49e Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 26 May 2009 16:06:10 +0900 Subject: [PATCH 34/74] PCI: use pci_is_root_bus() in pci_find_upstream_pcie_bridge() Use pci_is_root_bus() in pci_find_upstream_pcie_bridge() to check if the pci bus is root, for code consistency. Reviewed-by: Alex Chiang Reviewed-by: Grant Grundler Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 650bc0a538dc..e8cb5051c311 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) if (pdev->is_pcie) return NULL; while (1) { - if (!pdev->bus->parent) + if (pci_is_root_bus(pdev->bus)) break; pdev = pdev->bus->self; /* a p2p bridge */ From 9fc39256508c18d2861de11622183dfb6e79de87 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 26 May 2009 16:06:48 +0900 Subject: [PATCH 35/74] PCI: use pci_is_root_bus() in pci_read_bridge_bases() Use pci_is_root_bus() in pci_read_bridge_bases() to check if the pci bus is root, for code consistency. Reviewed-by: Alex Chiang Reviewed-by: Grant Grundler Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b962326e3d95..40e75f6a5056 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -289,7 +289,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) struct resource *res; int i; - if (!child->parent) /* It's a host bus, nothing to read */ + if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ return; if (dev->transparent) { From 8784fd4d497171882319e4b513f5a5949fc8ab43 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 26 May 2009 16:07:33 +0900 Subject: [PATCH 36/74] PCI: use pci_is_root_bus() in pci_get_interrupt_pin() Use pci_is_root_bus() in pci_get_interrupt_pin() for checking if the pci bus is root, for code consistency. Reviewed-by: Alex Chiang Reviewed-by: Grant Grundler Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 56fb18d2cb52..70b3b44a8b6c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1529,7 +1529,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) if (!pin) return -1; - while (dev->bus->parent) { + while (!pci_is_root_bus(dev->bus)) { pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; } From 1eb3948716f68bdb71509d0175765295f1aca23d Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 26 May 2009 16:08:36 +0900 Subject: [PATCH 37/74] PCI: use pci_is_root_bus() in pci_common_swizzle() Use pci_is_root_bus() in pci_common_swizzle() for checking if the pci bus is root, for code consistency. Reviewed-by: Alex Chiang Reviewed-by: Grant Grundler Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 70b3b44a8b6c..8ea911e55722 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1549,7 +1549,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) { u8 pin = *pinp; - while (dev->bus->parent) { + while (!pci_is_root_bus(dev->bus)) { pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; } From a72b46c3849cdb05993015991bde548ab8b6d7ac Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Fri, 24 Apr 2009 10:45:17 +0800 Subject: [PATCH 38/74] PCI: Add pci_bus_set_ops pci_bus_set_ops changes pci_ops associated with a pci_bus. This can be used by debug tools such as PCIE AER error injection to fake some PCI configuration registers. Acked-by: Kenji Kaneshige Signed-off-by: Huang Ying Signed-off-by: Jesse Barnes --- drivers/pci/access.c | 19 +++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 0f3706512686..db23200c4874 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -66,6 +66,25 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); +/** + * pci_bus_set_ops - Set raw operations of pci bus + * @bus: pci bus struct + * @ops: new raw operations + * + * Return previous raw operations + */ +struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops) +{ + struct pci_ops *old_ops; + unsigned long flags; + + spin_lock_irqsave(&pci_lock, flags); + old_ops = bus->ops; + bus->ops = ops; + spin_unlock_irqrestore(&pci_lock, flags); + return old_ops; +} +EXPORT_SYMBOL(pci_bus_set_ops); /** * pci_read_vpd - Read one entry from Vital Product Data diff --git a/include/linux/pci.h b/include/linux/pci.h index ec03b90d3510..ea2a153a9126 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -637,6 +637,7 @@ int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val); int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val); +struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops); static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) { From 634deb028c9188b4144863ea87dde5457fb93e92 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Fri, 24 Apr 2009 10:45:23 +0800 Subject: [PATCH 39/74] PCI: PCIE AER: export aer_irq This is used by PCIE AER error injection to fake an PCI AER interrupt. Signed-off-by: Huang Ying Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aer/aerdrv.c | 3 ++- drivers/pci/pcie/aer/aerdrv.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 32ade5af927e..4770f13b3ca1 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -77,7 +77,7 @@ void pci_no_aer(void) * * Invoked when Root Port detects AER messages. **/ -static irqreturn_t aer_irq(int irq, void *context) +irqreturn_t aer_irq(int irq, void *context) { unsigned int status, id; struct pcie_device *pdev = (struct pcie_device *)context; @@ -126,6 +126,7 @@ static irqreturn_t aer_irq(int irq, void *context) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(aer_irq); /** * aer_alloc_rpc - allocate Root Port data structure diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index aa14482a4779..3a69ddefe361 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -11,6 +11,7 @@ #include #include #include +#include #define AER_NONFATAL 0 #define AER_FATAL 1 @@ -120,6 +121,7 @@ extern void aer_delete_rootport(struct aer_rpc *rpc); extern int aer_init(struct pcie_device *dev); extern void aer_isr(struct work_struct *work); extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); +extern irqreturn_t aer_irq(int irq, void *context); #ifdef CONFIG_ACPI extern int aer_osc_setup(struct pcie_device *pciedev); From bfe5a7401785f864a4f30b4f066bfa045a28b9f6 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Fri, 24 Apr 2009 10:45:31 +0800 Subject: [PATCH 40/74] PCI: PCIE AER: Document for PCIE AER software error injection This patch adds a minimal HOWTO for PCIE AER software error injection in Documentation/PCI/pcieaer-howto.txt. Signed-off-by: Huang Ying Signed-off-by: Jesse Barnes --- Documentation/PCI/pcieaer-howto.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt index ddeb14beacc8..f6b1ba7464dc 100644 --- a/Documentation/PCI/pcieaer-howto.txt +++ b/Documentation/PCI/pcieaer-howto.txt @@ -246,3 +246,24 @@ with the PCI Express AER Root driver? A: It could call the helper functions to enable AER in devices and cleanup uncorrectable status register. Pls. refer to section 3.3. + +4. Software error injection + +Debugging PCIE AER error recovery code is quite difficult because it +is hard to trigger real hardware errors. Software based error +injection can be used to fake various kinds of PCIE errors. + +First you should enable PCIE AER software error injection in kernel +configuration, that is, following item should be in your .config. + +CONFIG_PCIEAER_INJECT=y or CONFIG_PCIEAER_INJECT=m + +After reboot with new kernel or insert the module, a device file named +/dev/aer_inject should be created. + +Then, you need a user space tool named aer-inject, which can be gotten +from: + http://www.kernel.org/pub/linux/kernel/people/yhuang/ + +More information about aer-inject can be found in the document comes +with its source code. From 1298307736a5882352418b4dc7c65442ab3b8bd4 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Sun, 7 Jun 2009 16:15:16 +0200 Subject: [PATCH 41/74] x86/PCI: add description for check_enable_amd_mmconf boot parameter Describe check_enable_amd_mmconf. Signed-off-by: Andreas Herrmann Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 395d1a013ebb..8a82489d9a81 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1735,6 +1735,9 @@ and is between 256 and 4096 characters. It is defined in the file root domains (aka PCI segments, in ACPI-speak). nommconf [X86] Disable use of MMCONFIG for PCI Configuration + check_enable_amd_mmconf [X86] check for and enable + properly configured MMIO access to PCI + config space on AMD family 10h CPU nomsi [MSI] If the PCI_MSI kernel config parameter is enabled, this kernel boot option can be used to disable the use of MSI interrupts system-wide. From bd3d99c17039fd05a29587db3f4a180c48da115a Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 2 Jun 2009 13:52:26 +0900 Subject: [PATCH 42/74] PCI: Remove untested Electromechanical Interlock (EMI) support in pciehp. The EMI support in pciehp is obviously broken. It is implemented using struct hotplug_slot_attribute, but sysfs_ops for pci_slot_ktype is NOT for struct hotplug_slot_attribute, but for struct pci_slot_attribute. This bug had been there for a long time, maybe it was introduced when PCI slot framework was introduced. The reason why this bug didn't cause any problem is maybe the EMI support is not tested at all because of lack of test environment. As described above, the EMI support in pciehp seems not to be tested at all. So this patch removes EMI support from pciehp, instead of fixing the bug. Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/pciehp.h | 3 - drivers/pci/hotplug/pciehp_core.c | 111 +----------------------------- drivers/pci/hotplug/pciehp_hpc.c | 31 --------- include/linux/pci_hotplug.h | 8 --- 4 files changed, 1 insertion(+), 152 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 0a368547e633..e6cf096498be 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -81,7 +81,6 @@ struct slot { struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; - unsigned long last_emi_toggle; struct delayed_work work; /* work for button event */ struct mutex lock; }; @@ -203,8 +202,6 @@ struct hpc_ops { int (*set_attention_status)(struct slot *slot, u8 status); int (*get_latch_status)(struct slot *slot, u8 *status); int (*get_adapter_status)(struct slot *slot, u8 *status); - int (*get_emi_status)(struct slot *slot, u8 *status); - int (*toggle_emi)(struct slot *slot); int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index fb254b2454de..eb183d1d0912 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -85,99 +85,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; -/* - * Check the status of the Electro Mechanical Interlock (EMI) - */ -static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = hotplug_slot->private; - return (slot->hpc_ops->get_emi_status(slot, value)); -} - -/* - * sysfs interface for the Electro Mechanical Interlock (EMI) - * 1 == locked, 0 == unlocked - */ -static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_lock_status(slot, &value); - if (retval) - goto lock_read_exit; - retval = sprintf (buf, "%d\n", value); - -lock_read_exit: - return retval; -} - -/* - * Change the status of the Electro Mechanical Interlock (EMI) - * This is a toggle - in addition there must be at least 1 second - * in between toggles. - */ -static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status) -{ - struct slot *slot = hotplug_slot->private; - int retval; - u8 value; - - mutex_lock(&slot->ctrl->crit_sect); - - /* has it been >1 sec since our last toggle? */ - if ((get_seconds() - slot->last_emi_toggle) < 1) { - mutex_unlock(&slot->ctrl->crit_sect); - return -EINVAL; - } - - /* see what our current state is */ - retval = get_lock_status(hotplug_slot, &value); - if (retval || (value == status)) - goto set_lock_exit; - - slot->hpc_ops->toggle_emi(slot); -set_lock_exit: - mutex_unlock(&slot->ctrl->crit_sect); - return 0; -} - -/* - * sysfs interface which allows the user to toggle the Electro Mechanical - * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock - */ -static ssize_t lock_write_file(struct hotplug_slot *hotplug_slot, - const char *buf, size_t count) -{ - struct slot *slot = hotplug_slot->private; - unsigned long llock; - u8 lock; - int retval = 0; - - llock = simple_strtoul(buf, NULL, 10); - lock = (u8)(llock & 0xff); - - switch (lock) { - case 0: - case 1: - retval = set_lock_status(hotplug_slot, lock); - break; - default: - ctrl_err(slot->ctrl, "%d is an invalid lock value\n", - lock); - retval = -EINVAL; - } - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_lock = { - .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = lock_read_file, - .store = lock_write_file -}; - /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -236,17 +143,6 @@ static int init_slots(struct controller *ctrl) get_attention_status(hotplug_slot, &info->attention_status); get_latch_status(hotplug_slot, &info->latch_status); get_adapter_status(hotplug_slot, &info->adapter_status); - /* create additional sysfs entries */ - if (EMI(ctrl)) { - retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, - &hotplug_slot_attr_lock.attr); - if (retval) { - pci_hp_deregister(hotplug_slot); - ctrl_err(ctrl, "Cannot create additional sysfs " - "entries\n"); - goto error_info; - } - } } return 0; @@ -261,13 +157,8 @@ error: static void cleanup_slots(struct controller *ctrl) { struct slot *slot; - - list_for_each_entry(slot, &ctrl->slot_list, slot_list) { - if (EMI(ctrl)) - sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, - &hotplug_slot_attr_lock.attr); + list_for_each_entry(slot, &ctrl->slot_list, slot_list) pci_hp_deregister(slot->hotplug_slot); - } } /* diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 07bd32151146..52813257e5bf 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -422,35 +422,6 @@ static int hpc_query_power_fault(struct slot *slot) return !!(slot_status & PCI_EXP_SLTSTA_PFD); } -static int hpc_get_emi_status(struct slot *slot, u8 *status) -{ - struct controller *ctrl = slot->ctrl; - u16 slot_status; - int retval; - - retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); - if (retval) { - ctrl_err(ctrl, "Cannot check EMI status\n"); - return retval; - } - *status = !!(slot_status & PCI_EXP_SLTSTA_EIS); - return retval; -} - -static int hpc_toggle_emi(struct slot *slot) -{ - u16 slot_cmd; - u16 cmd_mask; - int rc; - - slot_cmd = PCI_EXP_SLTCTL_EIC; - cmd_mask = PCI_EXP_SLTCTL_EIC; - rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask); - slot->last_emi_toggle = get_seconds(); - - return rc; -} - static int hpc_set_attention_status(struct slot *slot, u8 value) { struct controller *ctrl = slot->ctrl; @@ -874,8 +845,6 @@ static struct hpc_ops pciehp_hpc_ops = { .get_attention_status = hpc_get_attention_status, .get_latch_status = hpc_get_latch_status, .get_adapter_status = hpc_get_adapter_status, - .get_emi_status = hpc_get_emi_status, - .toggle_emi = hpc_toggle_emi, .get_max_bus_speed = hpc_get_max_lnk_speed, .get_cur_bus_speed = hpc_get_cur_lnk_speed, diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 20998746518e..11936fd0b56d 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -66,14 +66,6 @@ enum pcie_link_speed { PCIE_LNK_SPEED_UNKNOWN = 0xFF, }; -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr); - /** * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use * @owner: The module owner of this structure From 498a8faf2c7eb974f70b7c5a60a31f0d48c35d44 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 16 Jun 2009 11:00:47 +0900 Subject: [PATCH 43/74] PCI hotplug: fix return value of has_foo() functions Current has_foo() functions in pci_hotplug_core.c returns 0 if the "foo" property is true. It would cause misunderstanding. In addition, the error code of those functions is never checked, so this patch changes those functions' error code to 'bool' and return true if the property "foo" is true. Signed-off-by: Kenji Kaneshige Reviewed-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/pci_hotplug_core.c | 132 +++++++++++++------------ 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 535fce0f07f9..ff32c6b4ae13 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -347,125 +347,126 @@ static struct pci_slot_attribute hotplug_slot_attr_test = { .store = test_write_file }; -static int has_power_file(struct pci_slot *pci_slot) +static bool has_power_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if ((slot->ops->enable_slot) || (slot->ops->disable_slot) || (slot->ops->get_power_status)) - return 0; - return -ENOENT; + return true; + return false; } -static int has_attention_file(struct pci_slot *pci_slot) +static bool has_attention_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if ((slot->ops->set_attention_status) || (slot->ops->get_attention_status)) - return 0; - return -ENOENT; + return true; + return false; } -static int has_latch_file(struct pci_slot *pci_slot) +static bool has_latch_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_latch_status) - return 0; - return -ENOENT; + return true; + return false; } -static int has_adapter_file(struct pci_slot *pci_slot) +static bool has_adapter_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_adapter_status) - return 0; - return -ENOENT; + return true; + return false; } -static int has_max_bus_speed_file(struct pci_slot *pci_slot) +static bool has_max_bus_speed_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_max_bus_speed) - return 0; - return -ENOENT; + return true; + return false; } -static int has_cur_bus_speed_file(struct pci_slot *pci_slot) +static bool has_cur_bus_speed_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_cur_bus_speed) - return 0; - return -ENOENT; + return true; + return false; } -static int has_test_file(struct pci_slot *pci_slot) +static bool has_test_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->hardware_test) - return 0; - return -ENOENT; + return true; + return false; } static int fs_add_slot(struct pci_slot *slot) { int retval = 0; - if (has_power_file(slot) == 0) { - retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); + if (has_power_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_power.attr); if (retval) goto exit_power; } - if (has_attention_file(slot) == 0) { + if (has_attention_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); if (retval) goto exit_attention; } - if (has_latch_file(slot) == 0) { + if (has_latch_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); if (retval) goto exit_latch; } - if (has_adapter_file(slot) == 0) { + if (has_adapter_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); if (retval) goto exit_adapter; } - if (has_max_bus_speed_file(slot) == 0) { + if (has_max_bus_speed_file(slot)) { retval = sysfs_create_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); + &hotplug_slot_attr_max_bus_speed.attr); if (retval) goto exit_max_speed; } - if (has_cur_bus_speed_file(slot) == 0) { + if (has_cur_bus_speed_file(slot)) { retval = sysfs_create_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); + &hotplug_slot_attr_cur_bus_speed.attr); if (retval) goto exit_cur_speed; } - if (has_test_file(slot) == 0) { + if (has_test_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); if (retval) @@ -475,27 +476,26 @@ static int fs_add_slot(struct pci_slot *slot) goto exit; exit_test: - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - + if (has_cur_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_cur_bus_speed.attr); exit_cur_speed: - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - + if (has_max_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_max_bus_speed.attr); exit_max_speed: - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - + if (has_adapter_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); exit_adapter: - if (has_latch_file(slot) == 0) + if (has_latch_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - exit_latch: - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - + if (has_attention_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); exit_attention: - if (has_power_file(slot) == 0) + if (has_power_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); exit_power: exit: @@ -504,25 +504,29 @@ exit: static void fs_remove_slot(struct pci_slot *slot) { - if (has_power_file(slot) == 0) + if (has_power_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + if (has_attention_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); - if (has_latch_file(slot) == 0) + if (has_latch_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + if (has_adapter_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + if (has_max_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_max_bus_speed.attr); - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + if (has_cur_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_cur_bus_speed.attr); - if (has_test_file(slot) == 0) + if (has_test_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); } From c825bc94c8c1908750ab20413eb639c6be029e2d Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 16 Jun 2009 11:01:25 +0900 Subject: [PATCH 44/74] PCI hotplug: create symlink to hotplug driver module Create symbolic link to hotplug driver module in the PCI slot directory (/sys/bus/pci/slots/). In the past, we need to load hotplug drivers one by one to identify the hotplug driver that handles the slot, and it was very inconvenient especially for trouble shooting. With this change, we can easily identify the hotplug driver. Signed-off-by: Taku Izumi Signed-off-by: Kenji Kaneshige Reviewed-by: Alex Chiang Signed-off-by: Jesse Barnes --- Documentation/ABI/testing/sysfs-bus-pci | 7 +++++ drivers/pci/hotplug/pci_hotplug_core.c | 23 ++++++++++----- drivers/pci/slot.c | 39 +++++++++++++++++++++++++ include/linux/pci.h | 5 ++++ include/linux/pci_hotplug.h | 15 ++++++++-- 5 files changed, 80 insertions(+), 9 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 97ad190e13af..6bf68053e4b8 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -122,3 +122,10 @@ Description: This symbolic link appears when a device is a Virtual Function. The symbolic link points to the PCI device sysfs entry of the Physical Function this device associates with. + +What: /sys/bus/pci/slots/.../module +Date: June 2009 +Contact: linux-pci@vger.kernel.org +Description: + This symbolic link points to the PCI hotplug controller driver + module that manages the hotplug slot. diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index ff32c6b4ae13..844580489d4d 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -424,6 +424,9 @@ static int fs_add_slot(struct pci_slot *slot) { int retval = 0; + /* Create symbolic link to the hotplug driver module */ + pci_hp_create_module_link(slot); + if (has_power_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); @@ -498,6 +501,7 @@ exit_attention: if (has_power_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); exit_power: + pci_hp_remove_module_link(slot); exit: return retval; } @@ -528,6 +532,8 @@ static void fs_remove_slot(struct pci_slot *slot) if (has_test_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); + + pci_hp_remove_module_link(slot); } static struct hotplug_slot *get_slot_from_name (const char *name) @@ -544,10 +550,10 @@ static struct hotplug_slot *get_slot_from_name (const char *name) } /** - * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem * @bus: bus this slot is on * @slot: pointer to the &struct hotplug_slot to register - * @slot_nr: slot number + * @devnr: device number * @name: name registered with kobject core * * Registers a hotplug slot with the pci hotplug subsystem, which will allow @@ -555,8 +561,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name) * * Returns 0 if successful, anything else for an error. */ -int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, - const char *name) +int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, + int devnr, const char *name, + struct module *owner, const char *mod_name) { int result; struct pci_slot *pci_slot; @@ -571,14 +578,16 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, return -EINVAL; } - mutex_lock(&pci_hp_mutex); + slot->ops->owner = owner; + slot->ops->mod_name = mod_name; + mutex_lock(&pci_hp_mutex); /* * No problems if we call this interface from both ACPI_PCI_SLOT * driver and call it here again. If we've already created the * pci_slot, the interface will simply bump the refcount. */ - pci_slot = pci_create_slot(bus, slot_nr, name, slot); + pci_slot = pci_create_slot(bus, devnr, name, slot); if (IS_ERR(pci_slot)) { result = PTR_ERR(pci_slot); goto out; @@ -688,6 +697,6 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -EXPORT_SYMBOL_GPL(pci_hp_register); +EXPORT_SYMBOL_GPL(__pci_hp_register); EXPORT_SYMBOL_GPL(pci_hp_deregister); EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index fe95ce20bcbd..eddb0748b0ea 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -307,6 +307,45 @@ void pci_destroy_slot(struct pci_slot *slot) } EXPORT_SYMBOL_GPL(pci_destroy_slot); +#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) +#include +/** + * pci_hp_create_link - create symbolic link to the hotplug driver module. + * @slot: struct pci_slot + * + * Helper function for pci_hotplug_core.c to create symbolic link to + * the hotplug driver module. + */ +void pci_hp_create_module_link(struct pci_slot *pci_slot) +{ + struct hotplug_slot *slot = pci_slot->hotplug; + struct kobject *kobj = NULL; + int no_warn; + + if (!slot || !slot->ops) + return; + kobj = kset_find_obj(module_kset, slot->ops->mod_name); + if (!kobj) + return; + no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module"); + kobject_put(kobj); +} +EXPORT_SYMBOL_GPL(pci_hp_create_module_link); + +/** + * pci_hp_remove_link - remove symbolic link to the hotplug driver module. + * @slot: struct pci_slot + * + * Helper function for pci_hotplug_core.c to remove symbolic link to + * the hotplug driver module. + */ +void pci_hp_remove_module_link(struct pci_slot *pci_slot) +{ + sysfs_remove_link(&pci_slot->kobj, "module"); +} +EXPORT_SYMBOL_GPL(pci_hp_remove_module_link); +#endif + static int pci_slot_init(void) { struct kset *pci_bus_kset; diff --git a/include/linux/pci.h b/include/linux/pci.h index ea2a153a9126..6a1800ecd95d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1261,5 +1261,10 @@ static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev) } #endif +#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) +extern void pci_hp_create_module_link(struct pci_slot *pci_slot); +extern void pci_hp_remove_module_link(struct pci_slot *pci_slot); +#endif + #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 11936fd0b56d..b3646cd7fd5a 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -69,6 +69,7 @@ enum pcie_link_speed { /** * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use * @owner: The module owner of this structure + * @mod_name: The module name (KBUILD_MODNAME) of this structure * @enable_slot: Called when the user wants to enable a specific pci slot * @disable_slot: Called when the user wants to disable a specific pci slot * @set_attention_status: Called to set the specific slot's attention LED to @@ -101,6 +102,7 @@ enum pcie_link_speed { */ struct hotplug_slot_ops { struct module *owner; + const char *mod_name; int (*enable_slot) (struct hotplug_slot *slot); int (*disable_slot) (struct hotplug_slot *slot); int (*set_attention_status) (struct hotplug_slot *slot, u8 value); @@ -159,12 +161,21 @@ static inline const char *hotplug_slot_name(const struct hotplug_slot *slot) return pci_slot_name(slot->pci_slot); } -extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr, - const char *name); +extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus, + int nr, const char *name, + struct module *owner, const char *mod_name); extern int pci_hp_deregister(struct hotplug_slot *slot); extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info); +static inline int pci_hp_register(struct hotplug_slot *slot, + struct pci_bus *pbus, + int devnr, const char *name) +{ + return __pci_hp_register(slot, pbus, devnr, name, + THIS_MODULE, KBUILD_MODNAME); +} + /* PCI Setting Record (Type 0) */ struct hpp_type0 { u32 revision; From a6c0d5c6ebb3d988b1f18a1612b5188f3f555637 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 16 Jun 2009 11:02:02 +0900 Subject: [PATCH 45/74] PCI hotplug: remove redundant .owner initializations The "owner" field in struct hotplug_slot_ops is initialized by PCI hotplug core. So each hotplug controller driver doesn't need to initialize it. Signed-off-by: Kenji Kaneshige Reviewed-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/acpiphp_core.c | 1 - drivers/pci/hotplug/cpci_hotplug_core.c | 1 - drivers/pci/hotplug/cpqphp_core.c | 1 - drivers/pci/hotplug/ibmphp_core.c | 1 - drivers/pci/hotplug/pciehp_core.c | 1 - drivers/pci/hotplug/pcihp_skeleton.c | 1 - drivers/pci/hotplug/rpaphp_core.c | 1 - drivers/pci/hotplug/sgi_hotplug.c | 1 - drivers/pci/hotplug/shpchp_core.c | 1 - 9 files changed, 9 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 43c10bd261b4..4dd7114964ac 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -77,7 +77,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops acpi_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index de94f4feef8c..a5b9f6ae507b 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -72,7 +72,6 @@ static int get_adapter_status(struct hotplug_slot *slot, u8 * value); static int get_latch_status(struct hotplug_slot *slot, u8 * value); static struct hotplug_slot_ops cpci_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 7888b37c6c8e..075b4f4b6e0d 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -608,7 +608,6 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp } static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = process_SI, .disable_slot = process_SS, diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 29ccb8a6da8a..b3d5d47e6980 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -1316,7 +1316,6 @@ error: } struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = ibmphp_disable_slot, diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index eb183d1d0912..2317557fdee6 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -73,7 +73,6 @@ static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *val static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = disable_slot, diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index e3dd6cf9e89f..5175d9b26f0b 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -82,7 +82,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops skel_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 95d02a08fdc7..c159223389ec 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -423,7 +423,6 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) } struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 3eee70928d45..25a48b9f625e 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -83,7 +83,6 @@ static int disable_slot(struct hotplug_slot *slot); static inline int get_power_status(struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops sn_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .get_power_status = get_power_status, diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index fe8d149c2293..8a520a3d0f59 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -69,7 +69,6 @@ static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *val static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = disable_slot, From 70298c6e6c1ba68346336b4ea54bd5c0abbf73c8 Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Tue, 16 Jun 2009 13:34:38 +0800 Subject: [PATCH 46/74] PCI AER: support Multiple Error Received and no error source id Based on PCI Express AER specs, a root port might receive multiple TLP errors while it could only save a correctable error source id and an uncorrectable error source id at the same time. In addition, some root port hardware might be unable to provide a correct source id, i.e., the source id, or the bus id part of the source id provided by root port might be equal to 0. The patchset implements the support in kernel by searching the device tree under the root port. Patch 1 changes parameter cb of function pci_walk_bus to return a value. When cb return non-zero, pci_walk_bus stops more searching on the device tree. Reviewed-by: Andrew Patterson Signed-off-by: Zhang Yanmin Signed-off-by: Jesse Barnes --- arch/powerpc/platforms/pseries/eeh_driver.c | 38 +++++++++++++-------- drivers/pci/bus.c | 11 ++++-- drivers/pci/pcie/aer/aerdrv_core.c | 30 ++++++++-------- include/linux/pci.h | 2 +- 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 9a2a6e32f00f..0e8db6771252 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -122,7 +122,7 @@ static void eeh_enable_irq(struct pci_dev *dev) * passed back in "userdata". */ -static void eeh_report_error(struct pci_dev *dev, void *userdata) +static int eeh_report_error(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; struct pci_driver *driver = dev->driver; @@ -130,19 +130,21 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata) dev->error_state = pci_channel_io_frozen; if (!driver) - return; + return 0; eeh_disable_irq(dev); if (!driver->err_handler || !driver->err_handler->error_detected) - return; + return 0; rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); /* A driver that needs a reset trumps all others */ if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; + + return 0; } /** @@ -153,7 +155,7 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata) * Cumulative response passed back in "userdata". */ -static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) +static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; struct pci_driver *driver = dev->driver; @@ -161,26 +163,28 @@ static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) if (!driver || !driver->err_handler || !driver->err_handler->mmio_enabled) - return; + return 0; rc = driver->err_handler->mmio_enabled (dev); /* A driver that needs a reset trumps all others */ if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; + + return 0; } /** * eeh_report_reset - tell device that slot has been reset */ -static void eeh_report_reset(struct pci_dev *dev, void *userdata) +static int eeh_report_reset(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; struct pci_driver *driver = dev->driver; if (!driver) - return; + return 0; dev->error_state = pci_channel_io_normal; @@ -188,35 +192,39 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata) if (!driver->err_handler || !driver->err_handler->slot_reset) - return; + return 0; rc = driver->err_handler->slot_reset(dev); if ((*res == PCI_ERS_RESULT_NONE) || (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc; if (*res == PCI_ERS_RESULT_DISCONNECT && rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; + + return 0; } /** * eeh_report_resume - tell device to resume normal operations */ -static void eeh_report_resume(struct pci_dev *dev, void *userdata) +static int eeh_report_resume(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; dev->error_state = pci_channel_io_normal; if (!driver) - return; + return 0; eeh_enable_irq(dev); if (!driver->err_handler || !driver->err_handler->resume) - return; + return 0; driver->err_handler->resume(dev); + + return 0; } /** @@ -226,22 +234,24 @@ static void eeh_report_resume(struct pci_dev *dev, void *userdata) * dead, and that no further recovery attempts will be made on it. */ -static void eeh_report_failure(struct pci_dev *dev, void *userdata) +static int eeh_report_failure(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; dev->error_state = pci_channel_io_perm_failure; if (!driver) - return; + return 0; eeh_disable_irq(dev); if (!driver->err_handler || !driver->err_handler->error_detected) - return; + return 0; driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); + + return 0; } /* ------------------------------------------------------- */ diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 40af27f31043..cef28a79103f 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -206,13 +206,18 @@ void pci_enable_bridges(struct pci_bus *bus) * Walk the given bus, including any bridged devices * on buses under this bus. Call the provided callback * on each device found. + * + * We check the return of @cb each time. If it returns anything + * other than 0, we break out. + * */ -void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), +void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata) { struct pci_dev *dev; struct pci_bus *bus; struct list_head *next; + int retval; bus = top; down_read(&pci_bus_sem); @@ -236,8 +241,10 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), /* Run device routines with the device locked */ down(&dev->dev.sem); - cb(dev, userdata); + retval = cb(dev, userdata); up(&dev->dev.sem); + if (retval) + break; } up_read(&pci_bus_sem); } diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index dd3829e68e3f..a7a3919904bb 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -109,7 +109,7 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) #endif /* 0 */ -static void set_device_error_reporting(struct pci_dev *dev, void *data) +static int set_device_error_reporting(struct pci_dev *dev, void *data) { bool enable = *((bool *)data); @@ -124,6 +124,8 @@ static void set_device_error_reporting(struct pci_dev *dev, void *data) if (enable) pcie_set_ecrc_checking(dev); + + return 0; } /** @@ -207,7 +209,7 @@ static struct device* find_source_device(struct pci_dev *parent, u16 id) return NULL; } -static void report_error_detected(struct pci_dev *dev, void *data) +static int report_error_detected(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -232,16 +234,16 @@ static void report_error_detected(struct pci_dev *dev, void *data) dev->driver ? "no AER-aware driver" : "no driver"); } - return; + return 0; } err_handler = dev->driver->err_handler; vote = err_handler->error_detected(dev, result_data->state); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_mmio_enabled(struct pci_dev *dev, void *data) +static int report_mmio_enabled(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -251,15 +253,15 @@ static void report_mmio_enabled(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->mmio_enabled) - return; + return 0; err_handler = dev->driver->err_handler; vote = err_handler->mmio_enabled(dev); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_slot_reset(struct pci_dev *dev, void *data) +static int report_slot_reset(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -269,15 +271,15 @@ static void report_slot_reset(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->slot_reset) - return; + return 0; err_handler = dev->driver->err_handler; vote = err_handler->slot_reset(dev); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_resume(struct pci_dev *dev, void *data) +static int report_resume(struct pci_dev *dev, void *data) { struct pci_error_handlers *err_handler; @@ -286,11 +288,11 @@ static void report_resume(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->resume) - return; + return 0; err_handler = dev->driver->err_handler; err_handler->resume(dev); - return; + return 0; } /** @@ -307,7 +309,7 @@ static void report_resume(struct pci_dev *dev, void *data) static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, enum pci_channel_state state, char *error_mesg, - void (*cb)(struct pci_dev *, void *)) + int (*cb)(struct pci_dev *, void *)) { struct aer_broadcast_data result_data; diff --git a/include/linux/pci.h b/include/linux/pci.h index 6a1800ecd95d..61d9b790d21c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -789,7 +789,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass); -void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), +void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata); int pci_cfg_space_size_ext(struct pci_dev *dev); int pci_cfg_space_size(struct pci_dev *dev); From 28eb27cf0839a30948335f9b2edda739f48b7a2e Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Tue, 16 Jun 2009 13:35:11 +0800 Subject: [PATCH 47/74] PCI AER: support invalid error source IDs When the bus id part of error source id is equal to 0 or nosourceid=1, make the kernel probe the AER status registers of all devices under the root port to find the initial error reporter. Reviewed-by: Andrew Patterson Signed-off-by: Zhang Yanmin Signed-off-by: Jesse Barnes --- Documentation/PCI/pcieaer-howto.txt | 4 + drivers/pci/pcie/aer/aerdrv.h | 2 + drivers/pci/pcie/aer/aerdrv_core.c | 176 ++++++++++++++++++---------- 3 files changed, 122 insertions(+), 60 deletions(-) diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt index f6b1ba7464dc..5408b9b39d89 100644 --- a/Documentation/PCI/pcieaer-howto.txt +++ b/Documentation/PCI/pcieaer-howto.txt @@ -61,6 +61,10 @@ be initiated although firmwares have no _OSC support. To enable the walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line when booting kernel. Note that forceload=n by default. +nosourceid, another parameter of type bool, can be used when broken +hardware (mostly chipsets) has root ports that cannot obtain the reporting +source ID. nosourceid=n by default. + 2.3 AER error output When a PCI-E AER error is captured, an error message will be outputed to console. If it's a correctable error, it is outputed as a warning. diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 3a69ddefe361..dadf492e9ce9 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -58,6 +58,8 @@ struct header_log_regs { }; struct aer_err_info { + struct pci_dev *dev; + u16 id; int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ int flags; unsigned int status; /* COR/UNCOR Error Status */ diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index a7a3919904bb..2750e7b266b4 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -26,7 +26,9 @@ #include "aerdrv.h" static int forceload; +static int nosourceid; module_param(forceload, bool, 0); +module_param(nosourceid, bool, 0); int pci_enable_pcie_error_reporting(struct pci_dev *dev) { @@ -143,34 +145,87 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev, pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); } -static int find_device_iter(struct device *device, void *data) +static inline int compare_device_id(struct pci_dev *dev, + struct aer_err_info *e_info) { - struct pci_dev *dev; - u16 id = *(unsigned long *)data; - u8 secondary, subordinate, d_bus = id >> 8; + if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) { + /* + * Device ID match + */ + return 1; + } - if (device->bus == &pci_bus_type) { - dev = to_pci_dev(device); - if (id == ((dev->bus->number << 8) | dev->devfn)) { - /* - * Device ID match - */ - *(unsigned long*)data = (unsigned long)device; + return 0; +} + +#define PCI_BUS(x) (((x) >> 8) & 0xff) + +static int find_device_iter(struct pci_dev *dev, void *data) +{ + int pos; + u32 status; + u32 mask; + u16 reg16; + int result; + struct aer_err_info *e_info = (struct aer_err_info *)data; + + /* + * When bus id is equal to 0, it might be a bad id + * reported by root port. + */ + if (!nosourceid && (PCI_BUS(e_info->id) != 0)) { + result = compare_device_id(dev, e_info); + if (result) + e_info->dev = dev; + return result; + } + + /* + * Next is to check when bus id is equal to 0 or + * nosourceid==y. Some ports might lose the bus + * id of error source id. We check AER status + * registers to find the initial reporter. + */ + if (atomic_read(&dev->enable_cnt) == 0) + return 0; + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return 0; + /* Check if AER is enabled */ + pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16); + if (!(reg16 & ( + PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE))) + return 0; + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return 0; + + status = 0; + mask = 0; + if (e_info->severity == AER_CORRECTABLE) { + pci_read_config_dword(dev, + pos + PCI_ERR_COR_STATUS, + &status); + pci_read_config_dword(dev, + pos + PCI_ERR_COR_MASK, + &mask); + if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) { + e_info->dev = dev; return 1; } - - /* - * If device is P2P, check if it is an upstream? - */ - if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_SECONDARY_BUS, - &secondary); - pci_read_config_byte(dev, PCI_SUBORDINATE_BUS, - &subordinate); - if (d_bus >= secondary && d_bus <= subordinate) { - *(unsigned long*)data = (unsigned long)device; - return 1; - } + } else { + pci_read_config_dword(dev, + pos + PCI_ERR_UNCOR_STATUS, + &status); + pci_read_config_dword(dev, + pos + PCI_ERR_UNCOR_MASK, + &mask); + if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) { + e_info->dev = dev; + return 1; } } @@ -180,33 +235,22 @@ static int find_device_iter(struct device *device, void *data) /** * find_source_device - search through device hierarchy for source device * @parent: pointer to Root Port pci_dev data structure - * @id: device ID of agent who sends an error message to this Root Port + * @err_info: including detailed error information such like id * * Invoked when error is detected at the Root Port. */ -static struct device* find_source_device(struct pci_dev *parent, u16 id) +static void find_source_device(struct pci_dev *parent, + struct aer_err_info *e_info) { struct pci_dev *dev = parent; - struct device *device; - unsigned long device_addr; - int status; + int result; /* Is Root Port an agent that sends error message? */ - if (id == ((dev->bus->number << 8) | dev->devfn)) - return &dev->dev; + result = find_device_iter(dev, e_info); + if (result) + return; - do { - device_addr = id; - if ((status = device_for_each_child(&dev->dev, - &device_addr, find_device_iter))) { - device = (struct device*)device_addr; - dev = to_pci_dev(device); - if (id == ((dev->bus->number << 8) | dev->devfn)) - return device; - } - }while (status); - - return NULL; + pci_walk_bus(parent->subordinate, find_device_iter, e_info); } static int report_error_detected(struct pci_dev *dev, void *data) @@ -501,12 +545,12 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev, */ static void handle_error_source(struct pcie_device * aerdev, struct pci_dev *dev, - struct aer_err_info info) + struct aer_err_info *info) { pci_ers_result_t status = 0; int pos; - if (info.severity == AER_CORRECTABLE) { + if (info->severity == AER_CORRECTABLE) { /* * Correctable error does not need software intevention. * No need to go through error recovery process. @@ -514,9 +558,9 @@ static void handle_error_source(struct pcie_device * aerdev, pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (pos) pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, - info.status); + info->status); } else { - status = do_recovery(aerdev, dev, info.severity); + status = do_recovery(aerdev, dev, info->severity); if (status == PCI_ERS_RESULT_RECOVERED) { dev_printk(KERN_DEBUG, &dev->dev, "AER driver " "successfully recovered\n"); @@ -673,10 +717,16 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) static void aer_isr_one_error(struct pcie_device *p_device, struct aer_err_source *e_src) { - struct device *s_device; - struct aer_err_info e_info = {0, 0, 0,}; + struct aer_err_info *e_info; int i; - u16 id; + + /* struct aer_err_info might be big, so we allocate it with slab */ + e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL); + if (e_info == NULL) { + dev_printk(KERN_DEBUG, &p_device->port->dev, + "Can't allocate mem when processing AER errors\n"); + return; + } /* * There is a possibility that both correctable error and @@ -688,31 +738,37 @@ static void aer_isr_one_error(struct pcie_device *p_device, if (!(e_src->status & i)) continue; + memset(e_info, 0, sizeof(struct aer_err_info)); + /* Init comprehensive error information */ if (i & PCI_ERR_ROOT_COR_RCV) { - id = ERR_COR_ID(e_src->id); - e_info.severity = AER_CORRECTABLE; + e_info->id = ERR_COR_ID(e_src->id); + e_info->severity = AER_CORRECTABLE; } else { - id = ERR_UNCOR_ID(e_src->id); - e_info.severity = ((e_src->status >> 6) & 1); + e_info->id = ERR_UNCOR_ID(e_src->id); + e_info->severity = ((e_src->status >> 6) & 1); } if (e_src->status & (PCI_ERR_ROOT_MULTI_COR_RCV | PCI_ERR_ROOT_MULTI_UNCOR_RCV)) - e_info.flags |= AER_MULTI_ERROR_VALID_FLAG; - if (!(s_device = find_source_device(p_device->port, id))) { + e_info->flags |= AER_MULTI_ERROR_VALID_FLAG; + + find_source_device(p_device->port, e_info); + if (e_info->dev == NULL) { printk(KERN_DEBUG "%s->can't find device of ID%04x\n", - __func__, id); + __func__, e_info->id); continue; } - if (get_device_error_info(to_pci_dev(s_device), &e_info) == + if (get_device_error_info(e_info->dev, e_info) == AER_SUCCESS) { - aer_print_error(to_pci_dev(s_device), &e_info); + aer_print_error(e_info->dev, e_info); handle_error_source(p_device, - to_pci_dev(s_device), + e_info->dev, e_info); } } + + kfree(e_info); } /** From 3d5505c56db5c8d1eeca45c325b19e95115afdea Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Tue, 16 Jun 2009 13:35:16 +0800 Subject: [PATCH 48/74] PCI AER: multiple error support When a root port receives the same errors more than once before the kernel process them, the Multiple Error Messages Received flags are set by hardware. Because the root port could only save one kind of correctable error source id and another uncorrectable error source id at the same time, the second message sender id is lost if the 2 messages are sent from 2 different devices. This patch makes the kernel search all devices under the root port when multiple messages are received. Reviewed-by: Andrew Patterson Signed-off-by: Zhang Yanmin Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aer/aerdrv.h | 4 +- drivers/pci/pcie/aer/aerdrv_core.c | 88 ++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index dadf492e9ce9..bbd7428ca2d0 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -57,8 +57,10 @@ struct header_log_regs { unsigned int dw3; }; +#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ struct aer_err_info { - struct pci_dev *dev; + struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; + int error_dev_num; u16 id; int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ int flags; diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 2750e7b266b4..3d8872704a58 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -158,6 +158,17 @@ static inline int compare_device_id(struct pci_dev *dev, return 0; } +static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) +{ + if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { + e_info->dev[e_info->error_dev_num] = dev; + e_info->error_dev_num++; + return 1; + } else + return 0; +} + + #define PCI_BUS(x) (((x) >> 8) & 0xff) static int find_device_iter(struct pci_dev *dev, void *data) @@ -176,15 +187,31 @@ static int find_device_iter(struct pci_dev *dev, void *data) if (!nosourceid && (PCI_BUS(e_info->id) != 0)) { result = compare_device_id(dev, e_info); if (result) - e_info->dev = dev; - return result; + add_error_device(e_info, dev); + + /* + * If there is no multiple error, we stop + * or continue based on the id comparing. + */ + if (!(e_info->flags & AER_MULTI_ERROR_VALID_FLAG)) + return result; + + /* + * If there are multiple errors and id does match, + * We need continue to search other devices under + * the root port. Return 0 means that. + */ + if (result) + return 0; } /* - * Next is to check when bus id is equal to 0 or - * nosourceid==y. Some ports might lose the bus - * id of error source id. We check AER status - * registers to find the initial reporter. + * When either + * 1) nosourceid==y; + * 2) bus id is equal to 0. Some ports might lose the bus + * id of error source id; + * 3) There are multiple errors and prior id comparing fails; + * We check AER status registers to find the initial reporter. */ if (atomic_read(&dev->enable_cnt) == 0) return 0; @@ -213,8 +240,8 @@ static int find_device_iter(struct pci_dev *dev, void *data) pos + PCI_ERR_COR_MASK, &mask); if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) { - e_info->dev = dev; - return 1; + add_error_device(e_info, dev); + goto added; } } else { pci_read_config_dword(dev, @@ -224,12 +251,18 @@ static int find_device_iter(struct pci_dev *dev, void *data) pos + PCI_ERR_UNCOR_MASK, &mask); if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) { - e_info->dev = dev; - return 1; + add_error_device(e_info, dev); + goto added; } } return 0; + +added: + if (e_info->flags & AER_MULTI_ERROR_VALID_FLAG) + return 0; + else + return 1; } /** @@ -709,6 +742,28 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) return AER_SUCCESS; } +static inline void aer_process_err_devices(struct pcie_device *p_device, + struct aer_err_info *e_info) +{ + int i; + + if (!e_info->dev[0]) { + dev_printk(KERN_DEBUG, &p_device->port->dev, + "can't find device of ID%04x\n", + e_info->id); + } + + for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { + if (get_device_error_info(e_info->dev[i], e_info) == + AER_SUCCESS) { + aer_print_error(e_info->dev[i], e_info); + handle_error_source(p_device, + e_info->dev[i], + e_info); + } + } +} + /** * aer_isr_one_error - consume an error detected by root port * @p_device: pointer to error root port service device @@ -754,18 +809,7 @@ static void aer_isr_one_error(struct pcie_device *p_device, e_info->flags |= AER_MULTI_ERROR_VALID_FLAG; find_source_device(p_device->port, e_info); - if (e_info->dev == NULL) { - printk(KERN_DEBUG "%s->can't find device of ID%04x\n", - __func__, e_info->id); - continue; - } - if (get_device_error_info(e_info->dev, e_info) == - AER_SUCCESS) { - aer_print_error(e_info->dev, e_info); - handle_error_source(p_device, - e_info->dev, - e_info); - } + aer_process_err_devices(p_device, e_info); } kfree(e_info); From c465def6bfe834b62623caa9b98f2d4f4739875a Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Mon, 15 Jun 2009 10:42:57 +0800 Subject: [PATCH 49/74] PCI AER: software error injection Debugging PCIE AER code can be very difficult because it is hard to trigger various real hardware errors. This patch provide a software based error injection tool, which can fake various PCIE errors with a user space helper tool named "aer-inject". Which can be gotten from: http://www.kernel.org/pub/linux/kernel/people/yhuang/ The patch fakes AER error by faking some PCIE AER related registers and an AER interrupt for specified the PCIE device. Signed-off-by: Huang Ying Signed-off-by: Jesse Barnes --- Documentation/PCI/pcieaer-howto.txt | 2 +- drivers/pci/pcie/aer/Kconfig | 2 + drivers/pci/pcie/aer/Kconfig.debug | 18 ++ drivers/pci/pcie/aer/Makefile | 1 + drivers/pci/pcie/aer/aer_inject.c | 473 ++++++++++++++++++++++++++++ 5 files changed, 495 insertions(+), 1 deletion(-) create mode 100644 drivers/pci/pcie/aer/Kconfig.debug create mode 100644 drivers/pci/pcie/aer/aer_inject.c diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt index 5408b9b39d89..be21001ab144 100644 --- a/Documentation/PCI/pcieaer-howto.txt +++ b/Documentation/PCI/pcieaer-howto.txt @@ -267,7 +267,7 @@ After reboot with new kernel or insert the module, a device file named Then, you need a user space tool named aer-inject, which can be gotten from: - http://www.kernel.org/pub/linux/kernel/people/yhuang/ + http://www.kernel.org/pub/linux/utils/pci/aer-inject/ More information about aer-inject can be found in the document comes with its source code. diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig index db4cb950933a..50e94e02378a 100644 --- a/drivers/pci/pcie/aer/Kconfig +++ b/drivers/pci/pcie/aer/Kconfig @@ -23,3 +23,5 @@ config PCIE_ECRC (transaction layer end-to-end CRC checking). When in doubt, say N. + +source "drivers/pci/pcie/aer/Kconfig.debug" diff --git a/drivers/pci/pcie/aer/Kconfig.debug b/drivers/pci/pcie/aer/Kconfig.debug new file mode 100644 index 000000000000..b8c925c1f6aa --- /dev/null +++ b/drivers/pci/pcie/aer/Kconfig.debug @@ -0,0 +1,18 @@ +# +# PCI Express Root Port Device AER Debug Configuration +# + +config PCIEAER_INJECT + tristate "PCIE AER error injector support" + depends on PCIEAER + default n + help + This enables PCI Express Root Port Advanced Error Reporting + (AER) software error injector. + + Debuging PCIE AER code is quite difficult because it is hard + to trigger various real hardware errors. Software based + error injection can fake almost all kinds of errors with the + help of a user space helper tool aer-inject, which can be + gotten from: + http://www.kernel.org/pub/linux/utils/pci/aer-inject/ diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile index 7f93411c56e5..2cba67510dc8 100644 --- a/drivers/pci/pcie/aer/Makefile +++ b/drivers/pci/pcie/aer/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_PCIE_ECRC) += ecrc.o aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o +obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c new file mode 100644 index 000000000000..d92ae21a59d8 --- /dev/null +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -0,0 +1,473 @@ +/* + * PCIE AER software error injection support. + * + * Debuging PCIE AER code is quite difficult because it is hard to + * trigger various real hardware errors. Software based error + * injection can fake almost all kinds of errors with the help of a + * user space helper tool aer-inject, which can be gotten from: + * http://www.kernel.org/pub/linux/utils/pci/aer-inject/ + * + * Copyright 2009 Intel Corporation. + * Huang Ying + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include "aerdrv.h" + +struct aer_error_inj +{ + u8 bus; + u8 dev; + u8 fn; + u32 uncor_status; + u32 cor_status; + u32 header_log0; + u32 header_log1; + u32 header_log2; + u32 header_log3; +}; + +struct aer_error +{ + struct list_head list; + unsigned int bus; + unsigned int devfn; + int pos_cap_err; + + u32 uncor_status; + u32 cor_status; + u32 header_log0; + u32 header_log1; + u32 header_log2; + u32 header_log3; + u32 root_status; + u32 source_id; +}; + +struct pci_bus_ops +{ + struct list_head list; + struct pci_bus *bus; + struct pci_ops *ops; +}; + +static LIST_HEAD(einjected); + +static LIST_HEAD(pci_bus_ops_list); + +/* Protect einjected and pci_bus_ops_list */ +static DEFINE_SPINLOCK(inject_lock); + +static void aer_error_init(struct aer_error *err, unsigned int bus, + unsigned int devfn, int pos_cap_err) +{ + INIT_LIST_HEAD(&err->list); + err->bus = bus; + err->devfn = devfn; + err->pos_cap_err = pos_cap_err; +} + +/* inject_lock must be held before calling */ +static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) +{ + struct aer_error *err; + + list_for_each_entry(err, &einjected, list) { + if (bus == err->bus && devfn == err->devfn) + return err; + } + return NULL; +} + +/* inject_lock must be held before calling */ +static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) +{ + return __find_aer_error(dev->bus->number, dev->devfn); +} + +/* inject_lock must be held before calling */ +static struct pci_ops *__find_pci_bus_ops(struct pci_bus *bus) +{ + struct pci_bus_ops *bus_ops; + + list_for_each_entry(bus_ops, &pci_bus_ops_list, list) { + if (bus_ops->bus == bus) + return bus_ops->ops; + } + return NULL; +} + +static struct pci_bus_ops *pci_bus_ops_pop(void) +{ + unsigned long flags; + struct pci_bus_ops *bus_ops = NULL; + + spin_lock_irqsave(&inject_lock, flags); + if (list_empty(&pci_bus_ops_list)) + bus_ops = NULL; + else { + struct list_head *lh = pci_bus_ops_list.next; + list_del(lh); + bus_ops = list_entry(lh, struct pci_bus_ops, list); + } + spin_unlock_irqrestore(&inject_lock, flags); + return bus_ops; +} + +static u32 *find_pci_config_dword(struct aer_error *err, int where, + int *prw1cs) +{ + int rw1cs = 0; + u32 *target = NULL; + + if (err->pos_cap_err == -1) + return NULL; + + switch (where - err->pos_cap_err) { + case PCI_ERR_UNCOR_STATUS: + target = &err->uncor_status; + rw1cs = 1; + break; + case PCI_ERR_COR_STATUS: + target = &err->cor_status; + rw1cs = 1; + break; + case PCI_ERR_HEADER_LOG: + target = &err->header_log0; + break; + case PCI_ERR_HEADER_LOG+4: + target = &err->header_log1; + break; + case PCI_ERR_HEADER_LOG+8: + target = &err->header_log2; + break; + case PCI_ERR_HEADER_LOG+12: + target = &err->header_log3; + break; + case PCI_ERR_ROOT_STATUS: + target = &err->root_status; + rw1cs = 1; + break; + case PCI_ERR_ROOT_COR_SRC: + target = &err->source_id; + break; + } + if (prw1cs) + *prw1cs = rw1cs; + return target; +} + +static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + u32 *sim; + struct aer_error *err; + unsigned long flags; + struct pci_ops *ops; + + spin_lock_irqsave(&inject_lock, flags); + if (size != sizeof(u32)) + goto out; + err = __find_aer_error(bus->number, devfn); + if (!err) + goto out; + + sim = find_pci_config_dword(err, where, NULL); + if (sim) { + *val = *sim; + spin_unlock_irqrestore(&inject_lock, flags); + return 0; + } +out: + ops = __find_pci_bus_ops(bus); + spin_unlock_irqrestore(&inject_lock, flags); + return ops->read(bus, devfn, where, size, val); +} + +int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size, + u32 val) +{ + u32 *sim; + struct aer_error *err; + unsigned long flags; + int rw1cs; + struct pci_ops *ops; + + spin_lock_irqsave(&inject_lock, flags); + if (size != sizeof(u32)) + goto out; + err = __find_aer_error(bus->number, devfn); + if (!err) + goto out; + + sim = find_pci_config_dword(err, where, &rw1cs); + if (sim) { + if (rw1cs) + *sim ^= val; + else + *sim = val; + spin_unlock_irqrestore(&inject_lock, flags); + return 0; + } +out: + ops = __find_pci_bus_ops(bus); + spin_unlock_irqrestore(&inject_lock, flags); + return ops->write(bus, devfn, where, size, val); +} + +static struct pci_ops pci_ops_aer = { + .read = pci_read_aer, + .write = pci_write_aer, +}; + +static void pci_bus_ops_init(struct pci_bus_ops *bus_ops, + struct pci_bus *bus, + struct pci_ops *ops) +{ + INIT_LIST_HEAD(&bus_ops->list); + bus_ops->bus = bus; + bus_ops->ops = ops; +} + +static int pci_bus_set_aer_ops(struct pci_bus *bus) +{ + struct pci_ops *ops; + struct pci_bus_ops *bus_ops; + unsigned long flags; + + bus_ops = kmalloc(sizeof(*bus_ops), GFP_KERNEL); + if (!bus_ops) + return -ENOMEM; + ops = pci_bus_set_ops(bus, &pci_ops_aer); + spin_lock_irqsave(&inject_lock, flags); + if (ops == &pci_ops_aer) + goto out; + pci_bus_ops_init(bus_ops, bus, ops); + list_add(&bus_ops->list, &pci_bus_ops_list); + bus_ops = NULL; +out: + spin_unlock_irqrestore(&inject_lock, flags); + if (bus_ops) + kfree(bus_ops); + return 0; +} + +static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) +{ + while (1) { + if (!dev->is_pcie) + break; + if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + return dev; + if (!dev->bus->self) + break; + dev = dev->bus->self; + } + return NULL; +} + +static int find_aer_device_iter(struct device *device, void *data) +{ + struct pcie_device **result = data; + struct pcie_device *pcie_dev; + + if (device->bus == &pcie_port_bus_type) { + pcie_dev = to_pcie_device(device); + if (pcie_dev->service & PCIE_PORT_SERVICE_AER) { + *result = pcie_dev; + return 1; + } + } + return 0; +} + +static int find_aer_device(struct pci_dev *dev, struct pcie_device **result) +{ + return device_for_each_child(&dev->dev, result, find_aer_device_iter); +} + +static int aer_inject(struct aer_error_inj *einj) +{ + struct aer_error *err, *rperr; + struct aer_error *err_alloc = NULL, *rperr_alloc = NULL; + struct pci_dev *dev, *rpdev; + struct pcie_device *edev; + unsigned long flags; + unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); + int pos_cap_err, rp_pos_cap_err; + u32 sever; + int ret = 0; + + dev = pci_get_bus_and_slot(einj->bus, devfn); + if (!dev) + return -EINVAL; + rpdev = pcie_find_root_port(dev); + if (!rpdev) { + ret = -EINVAL; + goto out_put; + } + + pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos_cap_err) { + ret = -EIO; + goto out_put; + } + pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); + + rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); + if (!rp_pos_cap_err) { + ret = -EIO; + goto out_put; + } + + err_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL); + if (!err_alloc) { + ret = -ENOMEM; + goto out_put; + } + rperr_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL); + if (!rperr_alloc) { + ret = -ENOMEM; + goto out_put; + } + + spin_lock_irqsave(&inject_lock, flags); + + err = __find_aer_error_by_dev(dev); + if (!err) { + err = err_alloc; + err_alloc = NULL; + aer_error_init(err, einj->bus, devfn, pos_cap_err); + list_add(&err->list, &einjected); + } + err->uncor_status |= einj->uncor_status; + err->cor_status |= einj->cor_status; + err->header_log0 = einj->header_log0; + err->header_log1 = einj->header_log1; + err->header_log2 = einj->header_log2; + err->header_log3 = einj->header_log3; + + rperr = __find_aer_error_by_dev(rpdev); + if (!rperr) { + rperr = rperr_alloc; + rperr_alloc = NULL; + aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, + rp_pos_cap_err); + list_add(&rperr->list, &einjected); + } + if (einj->cor_status) { + if (rperr->root_status & PCI_ERR_ROOT_COR_RCV) + rperr->root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; + else + rperr->root_status |= PCI_ERR_ROOT_COR_RCV; + rperr->source_id &= 0xffff0000; + rperr->source_id |= (einj->bus << 8) | devfn; + } + if (einj->uncor_status) { + if (rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV) + rperr->root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; + if (sever & einj->uncor_status) { + rperr->root_status |= PCI_ERR_ROOT_FATAL_RCV; + if (!(rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV)) + rperr->root_status |= PCI_ERR_ROOT_FIRST_FATAL; + } else + rperr->root_status |= PCI_ERR_ROOT_NONFATAL_RCV; + rperr->root_status |= PCI_ERR_ROOT_UNCOR_RCV; + rperr->source_id &= 0x0000ffff; + rperr->source_id |= ((einj->bus << 8) | devfn) << 16; + } + spin_unlock_irqrestore(&inject_lock, flags); + + ret = pci_bus_set_aer_ops(dev->bus); + if (ret) + goto out_put; + ret = pci_bus_set_aer_ops(rpdev->bus); + if (ret) + goto out_put; + + if (find_aer_device(rpdev, &edev)) + aer_irq(-1, edev); + else + ret = -EINVAL; +out_put: + if (err_alloc) + kfree(err_alloc); + if (rperr_alloc) + kfree(rperr_alloc); + pci_dev_put(dev); + return ret; +} + +static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, + size_t usize, loff_t *off) +{ + struct aer_error_inj einj; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (usize != sizeof(struct aer_error_inj)) + return -EINVAL; + + if (copy_from_user(&einj, ubuf, usize)) + return -EFAULT; + + ret = aer_inject(&einj); + return ret ? ret : usize; +} + +static const struct file_operations aer_inject_fops = { + .write = aer_inject_write, + .owner = THIS_MODULE, +}; + +static struct miscdevice aer_inject_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "aer_inject", + .fops = &aer_inject_fops, +}; + +static int __init aer_inject_init(void) +{ + return misc_register(&aer_inject_device); +} + +static void __exit aer_inject_exit(void) +{ + struct aer_error *err, *err_next; + unsigned long flags; + struct pci_bus_ops *bus_ops; + + misc_deregister(&aer_inject_device); + + while ((bus_ops = pci_bus_ops_pop())) { + pci_bus_set_ops(bus_ops->bus, bus_ops->ops); + kfree(bus_ops); + } + + spin_lock_irqsave(&inject_lock, flags); + list_for_each_entry_safe(err, err_next, + &pci_bus_ops_list, list) { + list_del(&err->list); + kfree(err); + } + spin_unlock_irqrestore(&inject_lock, flags); +} + +module_init(aer_inject_init); +module_exit(aer_inject_exit); + +MODULE_DESCRIPTION("PCIE AER software error injector"); +MODULE_LICENSE("GPL"); From 8c1c699fec9e9021bf6ff0285dee086bb27aec90 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Sat, 13 Jun 2009 15:52:13 +0800 Subject: [PATCH 50/74] PCI: cleanup Function Level Reset This patch enhances the FLR functions: 1) remove disable_irq() so the shared IRQ won't be disabled. 2) replace the 1s wait with 100, 200 and 400ms wait intervals for the Pending Transaction. 3) replace mdelay() with msleep(). 4) add might_sleep(). 5) lock the device to prevent PM suspend from accessing the CSRs during the reset. 6) coding style fixes. Reviewed-by: Kenji Kaneshige Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes --- drivers/pci/iov.c | 4 +- drivers/pci/pci.c | 160 ++++++++++++++++++++++---------------------- include/linux/pci.h | 2 +- 3 files changed, 84 insertions(+), 82 deletions(-) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index e87fe95da814..03c7706c0a09 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -110,7 +110,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) } if (reset) - pci_execute_reset_function(virtfn); + __pci_reset_function(virtfn); pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); @@ -164,7 +164,7 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) if (reset) { device_release_driver(&virtfn->dev); - pci_execute_reset_function(virtfn); + __pci_reset_function(virtfn); } sprintf(buf, "virtfn%u", id); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8ea911e55722..6a052ada3fe8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2055,111 +2055,112 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask) EXPORT_SYMBOL(pci_set_dma_seg_boundary); #endif -static int __pcie_flr(struct pci_dev *dev, int probe) +static int pcie_flr(struct pci_dev *dev, int probe) { - u16 status; + int i; + int pos; u32 cap; - int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); + u16 status; - if (!exppos) + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) return -ENOTTY; - pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); + + pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap); if (!(cap & PCI_EXP_DEVCAP_FLR)) return -ENOTTY; if (probe) return 0; - pci_block_user_cfg_access(dev); - /* Wait for Transaction Pending bit clean */ - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (!(status & PCI_EXP_DEVSTA_TRPND)) - goto transaction_done; + for (i = 0; i < 4; i++) { + if (i) + msleep((1 << (i - 1)) * 100); - msleep(100); - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (!(status & PCI_EXP_DEVSTA_TRPND)) - goto transaction_done; + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status); + if (!(status & PCI_EXP_DEVSTA_TRPND)) + goto clear; + } - dev_info(&dev->dev, "Busy after 100ms while trying to reset; " - "sleeping for 1 second\n"); - ssleep(1); - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (status & PCI_EXP_DEVSTA_TRPND) - dev_info(&dev->dev, "Still busy after 1s; " - "proceeding with reset anyway\n"); + dev_err(&dev->dev, "transaction is not cleared; " + "proceeding with reset anyway\n"); -transaction_done: - pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, +clear: + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); - mdelay(100); + msleep(100); - pci_unblock_user_cfg_access(dev); return 0; } -static int __pci_af_flr(struct pci_dev *dev, int probe) +static int pci_af_flr(struct pci_dev *dev, int probe) { - int cappos = pci_find_capability(dev, PCI_CAP_ID_AF); - u8 status; + int i; + int pos; u8 cap; + u8 status; - if (!cappos) + pos = pci_find_capability(dev, PCI_CAP_ID_AF); + if (!pos) return -ENOTTY; - pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap); + + pci_read_config_byte(dev, pos + PCI_AF_CAP, &cap); if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR)) return -ENOTTY; if (probe) return 0; - pci_block_user_cfg_access(dev); - /* Wait for Transaction Pending bit clean */ - pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (!(status & PCI_AF_STATUS_TP)) - goto transaction_done; + for (i = 0; i < 4; i++) { + if (i) + msleep((1 << (i - 1)) * 100); + pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status); + if (!(status & PCI_AF_STATUS_TP)) + goto clear; + } + + dev_err(&dev->dev, "transaction is not cleared; " + "proceeding with reset anyway\n"); + +clear: + pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); msleep(100); - pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (!(status & PCI_AF_STATUS_TP)) - goto transaction_done; - dev_info(&dev->dev, "Busy after 100ms while trying to" - " reset; sleeping for 1 second\n"); - ssleep(1); - pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (status & PCI_AF_STATUS_TP) - dev_info(&dev->dev, "Still busy after 1s; " - "proceeding with reset anyway\n"); - -transaction_done: - pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); - mdelay(100); - - pci_unblock_user_cfg_access(dev); return 0; } -static int __pci_reset_function(struct pci_dev *pdev, int probe) +static int pci_dev_reset(struct pci_dev *dev, int probe) { - int res; + int rc; - res = __pcie_flr(pdev, probe); - if (res != -ENOTTY) - return res; + might_sleep(); - res = __pci_af_flr(pdev, probe); - if (res != -ENOTTY) - return res; + if (!probe) { + pci_block_user_cfg_access(dev); + /* block PM suspend, driver probe, etc. */ + down(&dev->dev.sem); + } - return res; + rc = pcie_flr(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_af_flr(dev, probe); +done: + if (!probe) { + up(&dev->dev.sem); + pci_unblock_user_cfg_access(dev); + } + + return rc; } /** - * pci_execute_reset_function() - Reset a PCI device function - * @dev: Device function to reset + * __pci_reset_function - reset a PCI device function + * @dev: PCI device to reset * * Some devices allow an individual function to be reset without affecting * other functions in the same device. The PCI device must be responsive @@ -2171,18 +2172,18 @@ static int __pci_reset_function(struct pci_dev *pdev, int probe) * device including MSI, bus mastering, BARs, decoding IO and memory spaces, * etc. * - * Returns 0 if the device function was successfully reset or -ENOTTY if the + * Returns 0 if the device function was successfully reset or negative if the * device doesn't support resetting a single function. */ -int pci_execute_reset_function(struct pci_dev *dev) +int __pci_reset_function(struct pci_dev *dev) { - return __pci_reset_function(dev, 0); + return pci_dev_reset(dev, 0); } -EXPORT_SYMBOL_GPL(pci_execute_reset_function); +EXPORT_SYMBOL_GPL(__pci_reset_function); /** - * pci_reset_function() - quiesce and reset a PCI device function - * @dev: Device function to reset + * pci_reset_function - quiesce and reset a PCI device function + * @dev: PCI device to reset * * Some devices allow an individual function to be reset without affecting * other functions in the same device. The PCI device must be responsive @@ -2190,32 +2191,33 @@ EXPORT_SYMBOL_GPL(pci_execute_reset_function); * * This function does not just reset the PCI portion of a device, but * clears all the state associated with the device. This function differs - * from pci_execute_reset_function in that it saves and restores device state + * from __pci_reset_function in that it saves and restores device state * over the reset. * - * Returns 0 if the device function was successfully reset or -ENOTTY if the + * Returns 0 if the device function was successfully reset or negative if the * device doesn't support resetting a single function. */ int pci_reset_function(struct pci_dev *dev) { - int r = __pci_reset_function(dev, 1); + int rc; - if (r < 0) - return r; + rc = pci_dev_reset(dev, 1); + if (rc) + return rc; - if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) - disable_irq(dev->irq); pci_save_state(dev); + /* + * both INTx and MSI are disabled after the Interrupt Disable bit + * is set and the Bus Master bit is cleared. + */ pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); - r = pci_execute_reset_function(dev); + rc = pci_dev_reset(dev, 0); pci_restore_state(dev); - if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) - enable_irq(dev->irq); - return r; + return rc; } EXPORT_SYMBOL_GPL(pci_reset_function); diff --git a/include/linux/pci.h b/include/linux/pci.h index 61d9b790d21c..91b06be2f01e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -702,8 +702,8 @@ int pcix_get_mmrbc(struct pci_dev *dev); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); int pcie_get_readrq(struct pci_dev *dev); int pcie_set_readrq(struct pci_dev *dev, int rq); +int __pci_reset_function(struct pci_dev *dev); int pci_reset_function(struct pci_dev *dev); -int pci_execute_reset_function(struct pci_dev *dev); void pci_update_resource(struct pci_dev *dev, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int pci_select_bars(struct pci_dev *dev, unsigned long flags); From f85876ba82281f15bc4da11e41b94243a8b2b5b4 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Sat, 13 Jun 2009 15:52:14 +0800 Subject: [PATCH 51/74] PCI: support PM D0hot->D3 transition reset PCI PM 1.2 specifies that the device will perform an internal reset upon transitioning from D3hot to D0 when the NO_SOFT_RESET bit is clear. This method can be used to reset a function if neither PCIe FLR nor PCI AF FLR are supported. Reviewed-by: Kenji Kaneshige Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6a052ada3fe8..2e58acc66a8c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2132,6 +2132,36 @@ clear: return 0; } +static int pci_pm_reset(struct pci_dev *dev, int probe) +{ + u16 csr; + + if (!dev->pm_cap) + return -ENOTTY; + + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr); + if (csr & PCI_PM_CTRL_NO_SOFT_RESET) + return -ENOTTY; + + if (probe) + return 0; + + if (dev->current_state != PCI_D0) + return -EINVAL; + + csr &= ~PCI_PM_CTRL_STATE_MASK; + csr |= PCI_D3hot; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); + msleep(pci_pm_d3_delay); + + csr &= ~PCI_PM_CTRL_STATE_MASK; + csr |= PCI_D0; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); + msleep(pci_pm_d3_delay); + + return 0; +} + static int pci_dev_reset(struct pci_dev *dev, int probe) { int rc; @@ -2149,6 +2179,10 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) goto done; rc = pci_af_flr(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_pm_reset(dev, probe); done: if (!probe) { up(&dev->dev.sem); From c12ff1df5f114484e3d8abd028769a624cc3399f Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Sat, 13 Jun 2009 15:52:15 +0800 Subject: [PATCH 52/74] PCI: support Secondary Bus Reset PCI-to-PCI Bridge 1.2 specifies that the Secondary Bus Reset bit can force the assertion of RST# on the secondary interface, which can be used to reset all devices including subordinates under this bus. This can be used to reset a function if this function is the only device under this bus. Reviewed-by: Kenji Kaneshige Signed-off-by: Yu Zhao Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2e58acc66a8c..c56a4a0355a8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2162,6 +2162,33 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) return 0; } +static int pci_parent_bus_reset(struct pci_dev *dev, int probe) +{ + u16 ctrl; + struct pci_dev *pdev; + + if (dev->subordinate) + return -ENOTTY; + + list_for_each_entry(pdev, &dev->bus->devices, bus_list) + if (pdev != dev) + return -ENOTTY; + + if (probe) + return 0; + + pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl); + ctrl |= PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); + msleep(100); + + ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); + msleep(100); + + return 0; +} + static int pci_dev_reset(struct pci_dev *dev, int probe) { int rc; @@ -2183,6 +2210,10 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) goto done; rc = pci_pm_reset(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_parent_bus_reset(dev, probe); done: if (!probe) { up(&dev->dev.sem); From d2abdf62882d982c58e7a6b09ecdcfcc28075e2e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 14 Jun 2009 21:25:02 +0200 Subject: [PATCH 53/74] PCI PM: Fix handling of devices without PM support by pci_target_state() If a PCI device is not power-manageable either by the platform, or with the help of the native PCI PM interface, pci_target_state() will return either PCI_D3hot, or PCI_POWER_ERROR for it, depending on whether or not the device is configured to wake up the system. Alas, none of these return values is correct, because each of them causes pci_prepare_to_sleep() to return error code, although it should complete successfully in such a case. Fix this problem by making pci_target_state() always return PCI_D0 for devices that cannot be power managed. Cc: stable@kernel.org Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c56a4a0355a8..7b59fd7c9575 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1284,15 +1284,14 @@ pci_power_t pci_target_state(struct pci_dev *dev) default: target_state = state; } + } else if (!dev->pm_cap) { + target_state = PCI_D0; } else if (device_may_wakeup(&dev->dev)) { /* * Find the deepest state from which the device can generate * wake-up events, make it the target state and enable device * to generate PME#. */ - if (!dev->pm_cap) - return PCI_POWER_ERROR; - if (dev->pme_support) { while (target_state && !(dev->pme_support & (1 << target_state))) From ab7de999a2c771482698efa6fe7c7b7fcb1d482a Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Tue, 16 Jun 2009 16:25:40 +0900 Subject: [PATCH 54/74] PCI: remove invalid comment of msi_mask_irq() Remove invalid comment of msi_mask_irq(). Reviewed-by: Matthew Wilcox Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f2725710593a..f48f7550b4a7 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -131,9 +131,6 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control) * mask all MSI interrupts by clearing the MSI enable bit does not work * reliably as devices without an INTx disable bit will then generate a * level IRQ which will never be cleared. - * - * Returns 1 if it succeeded in masking the interrupt and 0 if the device - * doesn't support MSI masking. */ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) { From f9cde5ffed17bf74f6bef042d99edb0622f58576 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 27 May 2009 12:41:44 -0700 Subject: [PATCH 55/74] x86/ACPI: Correct maximum allowed _CRS returned resources and warn if exceeded Issue a warning if _CRS returns too many resource descriptors to be accommodated by the fixed size resource array instances. If there is no transparent bridge on the root bus "too many" is the PCI_BUS_NUM_RESOURCES size of the resource array. Otherwise, the last 3 slots of the resource array must be excluded making the maximum (PCI_BUS_NUM_RESOURCES - 3). The current code: - is silent when _CRS returns too many resource descriptors and - incorrectly allows use of the last 3 slots of the resource array for a root bus with a transparent bridge Signed-off-by: Gary Hade Signed-off-by: Jesse Barnes --- arch/x86/pci/acpi.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 8d898e0d3609..16c3fda85bba 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; - if (info->res_num >= PCI_BUS_NUM_RESOURCES) - return AE_OK; - status = resource_to_addr(acpi_res, &addr); if (ACPI_SUCCESS(status)) info->res_num++; return AE_OK; } +static int +bus_has_transparent_bridge(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 class = dev->class >> 8; + + if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) + return true; + } + return false; +} + static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) { @@ -56,9 +67,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) acpi_status status; unsigned long flags; struct resource *root; - - if (info->res_num >= PCI_BUS_NUM_RESOURCES) - return AE_OK; + int max_root_bus_resources = PCI_BUS_NUM_RESOURCES; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data) res->end = res->start + addr.address_length - 1; res->child = NULL; + if (bus_has_transparent_bridge(info->bus)) + max_root_bus_resources -= 3; + if (info->res_num >= max_root_bus_resources) { + printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx " + "from %s for %s due to _CRS returning more than " + "%d resource descriptors\n", (unsigned long) res->start, + (unsigned long) res->end, root->name, info->name, + max_root_bus_resources); + info->res_num++; + return AE_OK; + } + if (insert_resource(root, res)) { printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " "from %s for %s\n", (unsigned long) res->start, From 7d9a73f6dcf4390d256bf19330c81e91523a26d5 Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Wed, 17 Jun 2009 00:16:15 +0200 Subject: [PATCH 56/74] PCI PM: consistently use type bool for wake enable variable Other functions use type bool, so use that for pci_enable_wake as well. Signed-off-by: Frans Pop Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 2 +- include/linux/pci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7b59fd7c9575..ccc0a0ccbef9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1205,7 +1205,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) * Error code depending on the platform is returned if both the platform and * the native mechanism fail to enable the generation of wake-up events */ -int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) +int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) { int error = 0; bool pme_done = false; diff --git a/include/linux/pci.h b/include/linux/pci.h index 91b06be2f01e..62e8452c2ec6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -723,7 +723,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state); pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); bool pci_pme_capable(struct pci_dev *dev, pci_power_t state); void pci_pme_active(struct pci_dev *dev, bool enable); -int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); +int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable); int pci_wake_from_d3(struct pci_dev *dev, bool enable); pci_power_t pci_target_state(struct pci_dev *dev); int pci_prepare_to_sleep(struct pci_dev *dev); From 110828c9cdce6e8ec68479ced4ca0bdc1135bb91 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 16 Jun 2009 06:31:45 -0600 Subject: [PATCH 57/74] PCI: remove redundant __msi_set_enable() We have the 'pos' of the MSI capability at all locations which call msi_set_enable(), so pass it to msi_set_enable() instead of making it find the capability every time. Reviewed-by: Kenji Kaneshige Signed-off-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f48f7550b4a7..79e56906c7f1 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -75,22 +75,17 @@ void arch_teardown_msi_irqs(struct pci_dev *dev) } #endif -static void __msi_set_enable(struct pci_dev *dev, int pos, int enable) +static void msi_set_enable(struct pci_dev *dev, int pos, int enable) { u16 control; - if (pos) { - pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); - control &= ~PCI_MSI_FLAGS_ENABLE; - if (enable) - control |= PCI_MSI_FLAGS_ENABLE; - pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); - } -} + BUG_ON(!pos); -static void msi_set_enable(struct pci_dev *dev, int enable) -{ - __msi_set_enable(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), enable); + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + control &= ~PCI_MSI_FLAGS_ENABLE; + if (enable) + control |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); } static void msix_set_enable(struct pci_dev *dev, int enable) @@ -300,7 +295,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) pos = entry->msi_attrib.pos; pci_intx_for_msi(dev, 0); - msi_set_enable(dev, 0); + msi_set_enable(dev, pos, 0); write_msi_msg(dev->irq, &entry->msg); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); @@ -362,9 +357,9 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) u16 control; unsigned mask; - msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + msi_set_enable(dev, pos, 0); /* Disable MSI during set up */ + pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ entry = alloc_msi_entry(dev); @@ -396,7 +391,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) /* Set MSI enabled bits */ pci_intx_for_msi(dev, 0); - msi_set_enable(dev, 1); + msi_set_enable(dev, pos, 1); dev->msi_enabled = 1; dev->irq = entry->irq; @@ -593,17 +588,20 @@ void pci_msi_shutdown(struct pci_dev *dev) struct msi_desc *desc; u32 mask; u16 ctrl; + unsigned pos; if (!pci_msi_enable || !dev || !dev->msi_enabled) return; - msi_set_enable(dev, 0); + BUG_ON(list_empty(&dev->msi_list)); + desc = list_first_entry(&dev->msi_list, struct msi_desc, list); + pos = desc->msi_attrib.pos; + + msi_set_enable(dev, pos, 0); pci_intx_for_msi(dev, 1); dev->msi_enabled = 0; - BUG_ON(list_empty(&dev->msi_list)); - desc = list_first_entry(&dev->msi_list, struct msi_desc, list); - pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl); + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl); mask = msi_capable_mask(ctrl); msi_mask_irq(desc, mask, ~mask); From 268a03a42d3377d5fb41e6e7cbdec4e0b65cab2e Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Wed, 17 Jun 2009 19:03:57 -0600 Subject: [PATCH 58/74] PCI: drivers/pci/slot.c should depend on CONFIG_SYSFS There is no way to interact with a physical PCI slot without sysfs, so encode the dependency and prevent this build error: drivers/pci/slot.c: In function 'pci_hp_create_module_link': drivers/pci/slot.c:327: error: 'module_kset' undeclared This patch _should_ make pci-sysfs.o depend on CONFIG_SYSFS too, but we cannot (yet) because the PCI core merrily assumes the existence of sysfs: drivers/built-in.o: In function `pci_bus_add_device': drivers/pci/bus.c:89: undefined reference to `pci_create_sysfs_dev_files' drivers/built-in.o: In function `pci_stop_dev': drivers/pci/remove.c:24: undefined reference to `pci_remove_sysfs_dev_files' So do the minimal bit for now and figure out how to untangle it later. Reported-by: Randy Dunlap Acked-by: Randy Dunlap Reported-by: Stephen Rothwell Fix-suggested-by: Matthew Wilcox Signed-off-by: Alex Chiang Signed-off-by: Jesse Barnes --- drivers/acpi/Kconfig | 1 + drivers/pci/Makefile | 3 ++- drivers/pci/hotplug/Kconfig | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 431f8b439553..7ec7d88c5999 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -266,6 +266,7 @@ config ACPI_DEBUG_FUNC_TRACE config ACPI_PCI_SLOT tristate "PCI slot detection driver" + depends on SYSFS default n help This driver creates entries in /sys/bus/pci/slots/ for all PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index ba6af162fd39..ed32f678247a 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -2,10 +2,11 @@ # Makefile for the PCI bus specific drivers. # -obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \ +obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ irq.o obj-$(CONFIG_PROC_FS) += proc.o +obj-$(CONFIG_SYSFS) += slot.o # Build PCI Express stuff if needed obj-$(CONFIG_PCIEPORTBUS) += pcie/ diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index ac888ccfa161..66f29bc00be4 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -4,7 +4,7 @@ menuconfig HOTPLUG_PCI tristate "Support for PCI Hotplug" - depends on PCI && HOTPLUG + depends on PCI && HOTPLUG && SYSFS ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is From dc64cd1131a3b5762e26bd8b01dc79030dd0c555 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:11:33 +0900 Subject: [PATCH 59/74] PCI ASPM: fix typo in struct pcie_link_state Fix a typo in struct pcie_link_state. The "sibiling" field in the struct pcie_link_state should be "sibling". Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 777b2c76caf5..419f1f3697c0 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -32,7 +32,7 @@ struct endpoint_state { }; struct pcie_link_state { - struct list_head sibiling; + struct list_head sibling; struct pci_dev *pdev; bool downstream_has_switch; @@ -541,7 +541,7 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; /* check all links who have specific root port link */ - list_for_each_entry(leaf, &link_list, sibiling) { + list_for_each_entry(leaf, &link_list, sibling) { if (!list_empty(&leaf->children) || get_root_port_link(leaf) != root_port_link) continue; @@ -558,12 +558,12 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, * __pcie_aspm_config_link for the order **/ if (state & PCIE_LINK_STATE_L1) { - list_for_each_entry(leaf, &link_list, sibiling) { + list_for_each_entry(leaf, &link_list, sibling) { if (get_root_port_link(leaf) == root_port_link) __pcie_aspm_config_link(leaf->pdev, state); } } else { - list_for_each_entry_reverse(leaf, &link_list, sibiling) { + list_for_each_entry_reverse(leaf, &link_list, sibling) { if (get_root_port_link(leaf) == root_port_link) __pcie_aspm_config_link(leaf->pdev, state); } @@ -682,7 +682,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) } link_state->pdev = pdev; - list_add(&link_state->sibiling, &link_list); + list_add(&link_state->sibling, &link_list); if (link_state->downstream_has_switch) { /* @@ -729,7 +729,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) /* All functions are removed, so just disable ASPM for the link */ __pcie_aspm_config_one_dev(parent, 0); - list_del(&link_state->sibiling); + list_del(&link_state->sibling); list_del(&link_state->link); /* Clock PM is for endpoint device */ @@ -806,7 +806,7 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); aspm_policy = i; - list_for_each_entry(link_state, &link_list, sibiling) { + list_for_each_entry(link_state, &link_list, sibling) { pdev = link_state->pdev; __pcie_aspm_configure_link_state(pdev, policy_to_aspm_state(pdev)); From 80bfdbe370d56a1448c7078cd6d286b89241a72e Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:12:43 +0900 Subject: [PATCH 60/74] PCI ASPM: cleanup aspm state field in struct pcie_link_state The "support_state", "enabled_state" and "bios_aspm_state" fields in the struct pcie_link_state take 2-bit value. So those fields don't need to be defined as unsigned int. This patch makes those fields 2-bit, and cleans up some related code. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 71 ++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 419f1f3697c0..fdb3b7da7383 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -41,9 +41,10 @@ struct pcie_link_state { struct list_head link; /* ASPM state */ - unsigned int support_state; - unsigned int enabled_state; - unsigned int bios_aspm_state; + u32 aspm_support:2; /* Supported ASPM state */ + u32 aspm_enabled:2; /* Enabled ASPM state */ + u32 aspm_default:2; /* Default ASPM state by BIOS */ + /* upstream component */ unsigned int l0s_upper_latency; unsigned int l1_upper_latency; @@ -88,9 +89,9 @@ static int policy_to_aspm_state(struct pci_dev *pdev) return 0; case POLICY_POWERSAVE: /* Enable ASPM L0s/L1 */ - return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; case POLICY_DEFAULT: - return link_state->bios_aspm_state; + return link_state->aspm_default; } return 0; } @@ -311,6 +312,7 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, u32 reg32; unsigned int latency; + *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; @@ -333,26 +335,29 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, static void pcie_aspm_cap_init(struct pci_dev *pdev) { struct pci_dev *child_dev; - u32 state, tmp; + u32 support, l0s, l1, enabled; struct pcie_link_state *link_state = pdev->link_state; /* upstream component states */ - pcie_aspm_get_cap_device(pdev, &link_state->support_state, - &link_state->l0s_upper_latency, - &link_state->l1_upper_latency, - &link_state->enabled_state); + pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled); + link_state->aspm_support = support; + link_state->l0s_upper_latency = l0s; + link_state->l1_upper_latency = l1; + link_state->aspm_enabled = enabled; + /* downstream component states, all functions have the same setting */ child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, bus_list); - pcie_aspm_get_cap_device(child_dev, &state, - &link_state->l0s_down_latency, - &link_state->l1_down_latency, - &tmp); - link_state->support_state &= state; - if (!link_state->support_state) + pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled); + link_state->aspm_support &= support; + link_state->l0s_down_latency = l0s; + link_state->l1_down_latency = l1; + + if (!link_state->aspm_support) return; - link_state->enabled_state &= link_state->support_state; - link_state->bios_aspm_state = link_state->enabled_state; + + link_state->aspm_enabled &= link_state->aspm_support; + link_state->aspm_default = link_state->aspm_enabled; /* ENDPOINT states*/ list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { @@ -371,7 +376,7 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; latency = calc_L0S_latency(latency, 1); ep_state->l0s_acceptable_latency = latency; - if (link_state->support_state & PCIE_LINK_STATE_L1) { + if (link_state->aspm_support & PCIE_LINK_STATE_L1) { latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; latency = calc_L1_latency(latency, 1); ep_state->l1_acceptable_latency = latency; @@ -389,7 +394,7 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, parent_dev = pdev->bus->self; link_state = parent_dev->link_state; - state &= link_state->support_state; + state &= link_state->aspm_support; if (state == 0) return 0; ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; @@ -519,7 +524,7 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) if (!(state & PCIE_LINK_STATE_L1)) __pcie_aspm_config_one_dev(pdev, state); - link_state->enabled_state = state; + link_state->aspm_enabled = state; } static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) @@ -550,7 +555,7 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, /* check root port link too in case it hasn't children */ state = pcie_aspm_check_state(root_port_link->pdev, state); - if (link_state->enabled_state == state) + if (link_state->aspm_enabled == state) return; /* @@ -675,10 +680,11 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) pcie_aspm_configure_common_clock(pdev); pcie_aspm_cap_init(pdev); } else { - link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; - link_state->bios_aspm_state = 0; + link_state->aspm_enabled = + (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + link_state->aspm_default = 0; /* Set support state to 0, so we will disable ASPM later */ - link_state->support_state = 0; + link_state->aspm_support = 0; } link_state->pdev = pdev; @@ -690,7 +696,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * initialization will config the whole hierarchy. but we must * make sure BIOS doesn't set unsupported link state **/ - state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state); + state = pcie_aspm_check_state(pdev, link_state->aspm_default); __pcie_aspm_config_link(pdev, state); } else __pcie_aspm_configure_link_state(pdev, @@ -753,7 +759,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) * devices changed PM state, we should recheck if latency meets all * functions' requirement */ - pcie_aspm_configure_link_state(pdev, link_state->enabled_state); + pcie_aspm_configure_link_state(pdev, link_state->aspm_enabled); } /* @@ -776,12 +782,11 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); link_state = parent->link_state; - link_state->support_state &= - ~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1)); + link_state->aspm_support &= ~state; if (state & PCIE_LINK_STATE_CLKPM) link_state->clk_pm_capable = 0; - __pcie_aspm_configure_link_state(parent, link_state->enabled_state); + __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled); if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) pcie_set_clock_pm(parent, 0); mutex_unlock(&aspm_lock); @@ -842,7 +847,7 @@ static ssize_t link_state_show(struct device *dev, struct pci_dev *pci_device = to_pci_dev(dev); struct pcie_link_state *link_state = pci_device->link_state; - return sprintf(buf, "%d\n", link_state->enabled_state); + return sprintf(buf, "%d\n", link_state->aspm_enabled); } static ssize_t link_state_store(struct device *dev, @@ -908,7 +913,7 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; - if (link_state->support_state) + if (link_state->aspm_support) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); if (link_state->clk_pm_capable) @@ -924,7 +929,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; - if (link_state->support_state) + if (link_state->aspm_support) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); if (link_state->clk_pm_capable) From b6c2e54d3ea27719b920faf15db92dfe0260f0d2 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:14:58 +0900 Subject: [PATCH 61/74] PCI ASPM: cleanup latency field in struct pcie_link_state Clean up latency related data structures for ASPM. - Introduce struct acpi_latency for exit latency and acceptable latency management. With this change, struct endpoint_state is no longer needed. - We don't need to hold both upstream latency and downstream latency in the current implementation. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 66 +++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index fdb3b7da7383..88351c242a48 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -26,9 +26,9 @@ #endif #define MODULE_PARAM_PREFIX "pcie_aspm." -struct endpoint_state { - unsigned int l0s_acceptable_latency; - unsigned int l1_acceptable_latency; +struct aspm_latency { + u32 l0s; /* L0s latency (nsec) */ + u32 l1; /* L1 latency (nsec) */ }; struct pcie_link_state { @@ -45,22 +45,19 @@ struct pcie_link_state { u32 aspm_enabled:2; /* Enabled ASPM state */ u32 aspm_default:2; /* Default ASPM state by BIOS */ - /* upstream component */ - unsigned int l0s_upper_latency; - unsigned int l1_upper_latency; - /* downstream component */ - unsigned int l0s_down_latency; - unsigned int l1_down_latency; + /* Latencies */ + struct aspm_latency latency; /* Exit latency */ + /* Clock PM state*/ unsigned int clk_pm_capable; unsigned int clk_pm_enabled; unsigned int bios_clk_state; /* - * A pcie downstream port only has one slot under it, so at most there - * are 8 functions + * Endpoint acceptable latencies. A pcie downstream port only + * has one slot under it, so at most there are 8 functions. */ - struct endpoint_state endpoints[8]; + struct aspm_latency acceptable[8]; }; static int aspm_disabled, aspm_force; @@ -341,8 +338,8 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) /* upstream component states */ pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled); link_state->aspm_support = support; - link_state->l0s_upper_latency = l0s; - link_state->l1_upper_latency = l1; + link_state->latency.l0s = l0s; + link_state->latency.l1 = l1; link_state->aspm_enabled = enabled; /* downstream component states, all functions have the same setting */ @@ -350,8 +347,8 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) bus_list); pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled); link_state->aspm_support &= support; - link_state->l0s_down_latency = l0s; - link_state->l1_down_latency = l1; + link_state->latency.l0s = max_t(u32, link_state->latency.l0s, l0s); + link_state->latency.l1 = max_t(u32, link_state->latency.l1, l1); if (!link_state->aspm_support) return; @@ -364,8 +361,8 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) int pos; u32 reg32; unsigned int latency; - struct endpoint_state *ep_state = - &link_state->endpoints[PCI_FUNC(child_dev->devfn)]; + struct aspm_latency *acceptable = + &link_state->acceptable[PCI_FUNC(child_dev->devfn)]; if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) @@ -375,11 +372,11 @@ static void pcie_aspm_cap_init(struct pci_dev *pdev) pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; latency = calc_L0S_latency(latency, 1); - ep_state->l0s_acceptable_latency = latency; + acceptable->l0s = latency; if (link_state->aspm_support & PCIE_LINK_STATE_L1) { latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; latency = calc_L1_latency(latency, 1); - ep_state->l1_acceptable_latency = latency; + acceptable->l1 = latency; } } } @@ -388,16 +385,16 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, unsigned int state) { struct pci_dev *parent_dev, *tmp_dev; - unsigned int latency, l1_latency = 0; + unsigned int l1_latency = 0; struct pcie_link_state *link_state; - struct endpoint_state *ep_state; + struct aspm_latency *acceptable; parent_dev = pdev->bus->self; link_state = parent_dev->link_state; state &= link_state->aspm_support; if (state == 0) return 0; - ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; + acceptable = &link_state->acceptable[PCI_FUNC(pdev->devfn)]; /* * Check latency for endpoint device. @@ -411,21 +408,14 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { parent_dev = tmp_dev->bus->self; link_state = parent_dev->link_state; - if (state & PCIE_LINK_STATE_L0S) { - latency = max_t(unsigned int, - link_state->l0s_upper_latency, - link_state->l0s_down_latency); - if (latency > ep_state->l0s_acceptable_latency) - state &= ~PCIE_LINK_STATE_L0S; - } - if (state & PCIE_LINK_STATE_L1) { - latency = max_t(unsigned int, - link_state->l1_upper_latency, - link_state->l1_down_latency); - if (latency + l1_latency > - ep_state->l1_acceptable_latency) - state &= ~PCIE_LINK_STATE_L1; - } + if ((state & PCIE_LINK_STATE_L0S) && + (link_state->latency.l0s > acceptable->l0s)) + state &= ~PCIE_LINK_STATE_L0S; + + if ((state & PCIE_LINK_STATE_L1) && + (link_state->latency.l1 + l1_latency > acceptable->l1)) + state &= ~PCIE_LINK_STATE_L1; + if (!parent_dev->bus->self) /* parent_dev is a root port */ break; else { From 4d246e458918d469ad645fd5f937ac22982e0466 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:15:38 +0900 Subject: [PATCH 62/74] PCI ASPM: cleanup clkpm state in struct pcie_link_state The "clk_pm_capable", "clk_pm_enable" and "bios_clk_state" fields in the struct pcie_link_state only take 1-bit value. So those fields don't need to be defined as unsigned int. This patch makes those fields 1-bit, and cleans up some related code. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 88351c242a48..2d7e695b7589 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -45,14 +45,13 @@ struct pcie_link_state { u32 aspm_enabled:2; /* Enabled ASPM state */ u32 aspm_default:2; /* Default ASPM state by BIOS */ + /* Clock PM state */ + u32 clkpm_capable:1; /* Clock PM capable? */ + u32 clkpm_enabled:1; /* Current Clock PM state */ + u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + /* Latencies */ struct aspm_latency latency; /* Exit latency */ - - /* Clock PM state*/ - unsigned int clk_pm_capable; - unsigned int clk_pm_enabled; - unsigned int bios_clk_state; - /* * Endpoint acceptable latencies. A pcie downstream port only * has one slot under it, so at most there are 8 functions. @@ -105,7 +104,7 @@ static int policy_to_clkpm_state(struct pci_dev *pdev) /* Disable Clock PM */ return 1; case POLICY_DEFAULT: - return link_state->bios_clk_state; + return link_state->clkpm_default; } return 0; } @@ -128,7 +127,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); } - link_state->clk_pm_enabled = !!enable; + link_state->clkpm_enabled = !!enable; } static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) @@ -155,13 +154,13 @@ static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) enabled = 0; } - link_state->clk_pm_enabled = enabled; - link_state->bios_clk_state = enabled; + link_state->clkpm_enabled = enabled; + link_state->clkpm_default = enabled; if (!blacklist) { - link_state->clk_pm_capable = capable; + link_state->clkpm_capable = capable; pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); } else { - link_state->clk_pm_capable = 0; + link_state->clkpm_capable = 0; pcie_set_clock_pm(pdev, 0); } } @@ -774,10 +773,10 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) link_state = parent->link_state; link_state->aspm_support &= ~state; if (state & PCIE_LINK_STATE_CLKPM) - link_state->clk_pm_capable = 0; + link_state->clkpm_capable = 0; __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled); - if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) + if (!link_state->clkpm_capable && link_state->clkpm_enabled) pcie_set_clock_pm(parent, 0); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -805,8 +804,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) pdev = link_state->pdev; __pcie_aspm_configure_link_state(pdev, policy_to_aspm_state(pdev)); - if (link_state->clk_pm_capable && - link_state->clk_pm_enabled != policy_to_clkpm_state(pdev)) + if (link_state->clkpm_capable && + link_state->clkpm_enabled != policy_to_clkpm_state(pdev)) pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); } @@ -867,7 +866,7 @@ static ssize_t clk_ctl_show(struct device *dev, struct pci_dev *pci_device = to_pci_dev(dev); struct pcie_link_state *link_state = pci_device->link_state; - return sprintf(buf, "%d\n", link_state->clk_pm_enabled); + return sprintf(buf, "%d\n", link_state->clkpm_enabled); } static ssize_t clk_ctl_store(struct device *dev, @@ -906,7 +905,7 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) if (link_state->aspm_support) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); - if (link_state->clk_pm_capable) + if (link_state->clkpm_capable) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_clk_ctl.attr, power_group); } @@ -922,7 +921,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) if (link_state->aspm_support) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); - if (link_state->clk_pm_capable) + if (link_state->clkpm_capable) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_clk_ctl.attr, power_group); } From 5cde89d80172a393e49077d2450545b97ac8d972 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:17:04 +0900 Subject: [PATCH 63/74] PCI ASPM: cleanup misc in struct pcie_link_state Cleanup for some fields in pcie_link_state. - Add comments. - make "downstream_has_switch" field 1-bit. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 2d7e695b7589..a1ae9b6f3995 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -32,13 +32,11 @@ struct aspm_latency { }; struct pcie_link_state { - struct list_head sibling; - struct pci_dev *pdev; - bool downstream_has_switch; - - struct pcie_link_state *parent; - struct list_head children; - struct list_head link; + struct pci_dev *pdev; /* Upstream component of the Link */ + struct pcie_link_state *parent; /* pointer to the parent Link state */ + struct list_head sibling; /* node in link_list */ + struct list_head children; /* list of child link states */ + struct list_head link; /* node in parent's children list */ /* ASPM state */ u32 aspm_support:2; /* Supported ASPM state */ @@ -50,6 +48,8 @@ struct pcie_link_state { u32 clkpm_enabled:1; /* Current Clock PM state */ u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + u32 has_switch:1; /* Downstream has switches? */ + /* Latencies */ struct aspm_latency latency; /* Exit latency */ /* @@ -648,7 +648,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (!link_state) goto unlock_out; - link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev); + link_state->has_switch = pcie_aspm_downstream_has_switch(pdev); INIT_LIST_HEAD(&link_state->children); INIT_LIST_HEAD(&link_state->link); if (pdev->bus->self) {/* this is a switch */ @@ -679,7 +679,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) link_state->pdev = pdev; list_add(&link_state->sibling, &link_list); - if (link_state->downstream_has_switch) { + if (link_state->has_switch) { /* * If link has switch, delay the link config. The leaf link * initialization will config the whole hierarchy. but we must From 5aa63583cbec27482c6f1d761a0509f59b7969a8 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:17:44 +0900 Subject: [PATCH 64/74] PCI ASPM: cleanup change input argument of aspm functions In the current ASPM implementation, there are many functions that take a pointer to struct pci_dev corresponding to the upstream component of the link as a parameter. But, since those functions handle PCI express link state, a pointer to struct pcie_link_state is more suitable than a pointer to struct pci_dev. Changing a parameter to a pointer to struct pcie_link_state makes ASPM code much simpler and easier to read. This patch also contains some minor cleanups. This patch doesn't have any functional change. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 370 +++++++++++++++++++--------------------- 1 file changed, 172 insertions(+), 198 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index a1ae9b6f3995..9eaaf95f65a2 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -75,10 +75,8 @@ static const char *policy_str[] = { #define LINK_RETRAIN_TIMEOUT HZ -static int policy_to_aspm_state(struct pci_dev *pdev) +static int policy_to_aspm_state(struct pcie_link_state *link) { - struct pcie_link_state *link_state = pdev->link_state; - switch (aspm_policy) { case POLICY_PERFORMANCE: /* Disable ASPM and Clock PM */ @@ -87,15 +85,13 @@ static int policy_to_aspm_state(struct pci_dev *pdev) /* Enable ASPM L0s/L1 */ return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; case POLICY_DEFAULT: - return link_state->aspm_default; + return link->aspm_default; } return 0; } -static int policy_to_clkpm_state(struct pci_dev *pdev) +static int policy_to_clkpm_state(struct pcie_link_state *link) { - struct pcie_link_state *link_state = pdev->link_state; - switch (aspm_policy) { case POLICY_PERFORMANCE: /* Disable ASPM and Clock PM */ @@ -104,73 +100,73 @@ static int policy_to_clkpm_state(struct pci_dev *pdev) /* Disable Clock PM */ return 1; case POLICY_DEFAULT: - return link_state->clkpm_default; + return link->clkpm_default; } return 0; } -static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) +static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) { - struct pci_dev *child_dev; int pos; u16 reg16; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + list_for_each_entry(child, &linkbus->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); if (!pos) return; - pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); if (enable) reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN; else reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; - pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(child, pos + PCI_EXP_LNKCTL, reg16); } - link_state->clkpm_enabled = !!enable; + link->clkpm_enabled = !!enable; } -static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) +static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) { - int pos; + int pos, capable = 1, enabled = 1; u32 reg32; u16 reg16; - int capable = 1, enabled = 1; - struct pci_dev *child_dev; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; /* All functions should have the same cap and state, take the worst */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + list_for_each_entry(child, &linkbus->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); if (!pos) return; - pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, ®32); + pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32); if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { capable = 0; enabled = 0; break; } - pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) enabled = 0; } - link_state->clkpm_enabled = enabled; - link_state->clkpm_default = enabled; + link->clkpm_enabled = enabled; + link->clkpm_default = enabled; if (!blacklist) { - link_state->clkpm_capable = capable; - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + link->clkpm_capable = capable; + pcie_set_clock_pm(link, policy_to_clkpm_state(link)); } else { - link_state->clkpm_capable = 0; - pcie_set_clock_pm(pdev, 0); + link->clkpm_capable = 0; + pcie_set_clock_pm(link, 0); } } -static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) +static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) { - struct pci_dev *child_dev; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) + list_for_each_entry(child, &linkbus->devices, bus_list) { + if (child->pcie_type == PCI_EXP_TYPE_UPSTREAM) return true; } return false; @@ -181,89 +177,79 @@ static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) * could use common clock. If they are, configure them to use the * common clock. That will reduce the ASPM state exit latency. */ -static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) +static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) { - int pos, child_pos, i = 0; - u16 reg16 = 0; - struct pci_dev *child_dev; - int same_clock = 1; + int ppos, cpos, same_clock = 1; + u16 reg16, parent_reg, child_reg[8]; unsigned long start_jiffies; - u16 child_regs[8], parent_reg; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* - * all functions of a slot should have the same Slot Clock + * All functions of a slot should have the same Slot Clock * Configuration, so just check one function - * */ - child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, - bus_list); - BUG_ON(!child_dev->is_pcie); + */ + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + BUG_ON(!child->is_pcie); /* Check downstream component if bit Slot Clock Configuration is 1 */ - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, ®16); + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Check upstream component if bit Slot Clock Configuration is 1 */ - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); - pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); + pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Configure downstream component, all functions */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, - ®16); - child_regs[i] = reg16; + list_for_each_entry(child, &linkbus->devices, bus_list) { + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16); + child_reg[PCI_FUNC(child->devfn)] = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; - pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, - reg16); - i++; + pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, reg16); } /* Configure upstream component */ - pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(parent, ppos + PCI_EXP_LNKCTL, ®16); parent_reg = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16); - /* retrain link */ + /* Retrain link */ reg16 |= PCI_EXP_LNKCTL_RL; - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16); - /* Wait for link training end */ - /* break out after waiting for timeout */ + /* Wait for link training end. Break out after waiting for timeout */ start_jiffies = jiffies; for (;;) { - pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_LT)) break; if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) break; msleep(1); } - /* training failed -> recover */ - if (reg16 & PCI_EXP_LNKSTA_LT) { - dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" - " common clock\n"); - i = 0; - list_for_each_entry(child_dev, &pdev->subordinate->devices, - bus_list) { - child_pos = pci_find_capability(child_dev, - PCI_CAP_ID_EXP); - pci_write_config_word(child_dev, - child_pos + PCI_EXP_LNKCTL, - child_regs[i]); - i++; - } - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + return; + + /* Training failed. Restore common clock configurations */ + dev_printk(KERN_ERR, &parent->dev, + "ASPM: Could not configure common clock\n"); + list_for_each_entry(child, &linkbus->devices, bus_list) { + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, + child_reg[PCI_FUNC(child->devfn)]); } + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg); } /* @@ -328,51 +314,50 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); } -static void pcie_aspm_cap_init(struct pci_dev *pdev) +static void pcie_aspm_cap_init(struct pcie_link_state *link) { - struct pci_dev *child_dev; u32 support, l0s, l1, enabled; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* upstream component states */ - pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled); - link_state->aspm_support = support; - link_state->latency.l0s = l0s; - link_state->latency.l1 = l1; - link_state->aspm_enabled = enabled; + pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); + link->aspm_support = support; + link->latency.l0s = l0s; + link->latency.l1 = l1; + link->aspm_enabled = enabled; /* downstream component states, all functions have the same setting */ - child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, - bus_list); - pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled); - link_state->aspm_support &= support; - link_state->latency.l0s = max_t(u32, link_state->latency.l0s, l0s); - link_state->latency.l1 = max_t(u32, link_state->latency.l1, l1); + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + pcie_aspm_get_cap_device(child, &support, &l0s, &l1, &enabled); + link->aspm_support &= support; + link->latency.l0s = max_t(u32, link->latency.l0s, l0s); + link->latency.l1 = max_t(u32, link->latency.l1, l1); - if (!link_state->aspm_support) + if (!link->aspm_support) return; - link_state->aspm_enabled &= link_state->aspm_support; - link_state->aspm_default = link_state->aspm_enabled; + link->aspm_enabled &= link->aspm_support; + link->aspm_default = link->aspm_enabled; /* ENDPOINT states*/ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + list_for_each_entry(child, &linkbus->devices, bus_list) { int pos; u32 reg32; unsigned int latency; struct aspm_latency *acceptable = - &link_state->acceptable[PCI_FUNC(child_dev->devfn)]; + &link->acceptable[PCI_FUNC(child->devfn)]; - if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && - child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) + if (child->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child->pcie_type != PCI_EXP_TYPE_LEG_END) continue; - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); + pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; latency = calc_L0S_latency(latency, 1); acceptable->l0s = latency; - if (link_state->aspm_support & PCIE_LINK_STATE_L1) { + if (link->aspm_support & PCIE_LINK_STATE_L1) { latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; latency = calc_L1_latency(latency, 1); acceptable->l1 = latency; @@ -434,33 +419,33 @@ static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, return state; } -static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, - unsigned int state) +static u32 pcie_aspm_check_state(struct pcie_link_state *link, u32 state) { - struct pci_dev *child_dev; + pci_power_t power_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; /* If no child, ignore the link */ - if (list_empty(&pdev->subordinate->devices)) + if (list_empty(&linkbus->devices)) return state; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - /* - * If downstream component of a link is pci bridge, we - * disable ASPM for now for the link - * */ - state = 0; - break; - } - if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && - child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)) + + list_for_each_entry(child, &linkbus->devices, bus_list) { + /* + * If downstream component of a link is pci bridge, we + * disable ASPM for now for the link + */ + if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return 0; + + if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child->pcie_type != PCI_EXP_TYPE_LEG_END)) continue; /* Device not in D0 doesn't need check latency */ - if (child_dev->current_state == PCI_D1 || - child_dev->current_state == PCI_D2 || - child_dev->current_state == PCI_D3hot || - child_dev->current_state == PCI_D3cold) + power_state = child->current_state; + if (power_state == PCI_D1 || power_state == PCI_D2 || + power_state == PCI_D3hot || power_state == PCI_D3cold) continue; - state = __pcie_aspm_check_state_one(child_dev, state); + state = __pcie_aspm_check_state_one(child, state); } return state; } @@ -476,44 +461,38 @@ static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); } -static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) +static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) { - struct pci_dev *child_dev; - int valid = 1; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* If no child, disable the link */ - if (list_empty(&pdev->subordinate->devices)) + if (list_empty(&linkbus->devices)) state = 0; /* - * if the downstream component has pci bridge function, don't do ASPM - * now + * If the downstream component has pci bridge function, don't + * do ASPM now. */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - valid = 0; - break; - } + list_for_each_entry(child, &linkbus->devices, bus_list) { + if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return; } - if (!valid) - return; - /* - * spec 2.0 suggests all functions should be configured the same - * setting for ASPM. Enabling ASPM L1 should be done in upstream - * component first and then downstream, and vice versa for disabling - * ASPM L1. Spec doesn't mention L0S. + * Spec 2.0 suggests all functions should be configured the + * same setting for ASPM. Enabling ASPM L1 should be done in + * upstream component first and then downstream, and vice + * versa for disabling ASPM L1. Spec doesn't mention L0S. */ if (state & PCIE_LINK_STATE_L1) - __pcie_aspm_config_one_dev(pdev, state); + __pcie_aspm_config_one_dev(parent, state); - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) - __pcie_aspm_config_one_dev(child_dev, state); + list_for_each_entry(child, &linkbus->devices, bus_list) + __pcie_aspm_config_one_dev(child, state); if (!(state & PCIE_LINK_STATE_L1)) - __pcie_aspm_config_one_dev(pdev, state); + __pcie_aspm_config_one_dev(parent, state); - link_state->aspm_enabled = state; + link->aspm_enabled = state; } static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) @@ -524,42 +503,38 @@ static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) return root_port_link; } -/* check the whole hierarchy, and configure each link in the hierarchy */ -static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, - unsigned int state) +/* Check the whole hierarchy, and configure each link in the hierarchy */ +static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, + u32 state) { - struct pcie_link_state *link_state = pdev->link_state; - struct pcie_link_state *root_port_link = get_root_port_link(link_state); - struct pcie_link_state *leaf; + struct pcie_link_state *leaf, *root = get_root_port_link(link); - state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); - /* check all links who have specific root port link */ + /* Check all links who have specific root port link */ list_for_each_entry(leaf, &link_list, sibling) { if (!list_empty(&leaf->children) || - get_root_port_link(leaf) != root_port_link) + get_root_port_link(leaf) != root) continue; - state = pcie_aspm_check_state(leaf->pdev, state); + state = pcie_aspm_check_state(leaf, state); } - /* check root port link too in case it hasn't children */ - state = pcie_aspm_check_state(root_port_link->pdev, state); - - if (link_state->aspm_enabled == state) + /* Check root port link too in case it hasn't children */ + state = pcie_aspm_check_state(root, state); + if (link->aspm_enabled == state) return; - /* - * we must change the hierarchy. See comments in + * We must change the hierarchy. See comments in * __pcie_aspm_config_link for the order **/ if (state & PCIE_LINK_STATE_L1) { list_for_each_entry(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root_port_link) - __pcie_aspm_config_link(leaf->pdev, state); + if (get_root_port_link(leaf) == root) + __pcie_aspm_config_link(leaf, state); } } else { list_for_each_entry_reverse(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root_port_link) - __pcie_aspm_config_link(leaf->pdev, state); + if (get_root_port_link(leaf) == root) + __pcie_aspm_config_link(leaf, state); } } } @@ -568,20 +543,20 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, * pcie_aspm_configure_link_state: enable/disable PCI express link state * @pdev: the root port or switch downstream port */ -static void pcie_aspm_configure_link_state(struct pci_dev *pdev, - unsigned int state) +static void pcie_aspm_configure_link_state(struct pcie_link_state *link, + u32 state) { down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - __pcie_aspm_configure_link_state(pdev, state); + __pcie_aspm_configure_link_state(link, state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } -static void free_link_state(struct pci_dev *pdev) +static void free_link_state(struct pcie_link_state *link) { - kfree(pdev->link_state); - pdev->link_state = NULL; + link->pdev->link_state = NULL; + kfree(link); } static int pcie_aspm_sanity_check(struct pci_dev *pdev) @@ -648,7 +623,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (!link_state) goto unlock_out; - link_state->has_switch = pcie_aspm_downstream_has_switch(pdev); INIT_LIST_HEAD(&link_state->children); INIT_LIST_HEAD(&link_state->link); if (pdev->bus->self) {/* this is a switch */ @@ -662,12 +636,13 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) list_add(&link_state->link, &parent_link_state->children); link_state->parent = parent_link_state; } - + link_state->pdev = pdev; + link_state->has_switch = pcie_aspm_downstream_has_switch(link_state); pdev->link_state = link_state; if (!blacklist) { - pcie_aspm_configure_common_clock(pdev); - pcie_aspm_cap_init(pdev); + pcie_aspm_configure_common_clock(link_state); + pcie_aspm_cap_init(link_state); } else { link_state->aspm_enabled = (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); @@ -676,7 +651,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) link_state->aspm_support = 0; } - link_state->pdev = pdev; list_add(&link_state->sibling, &link_list); if (link_state->has_switch) { @@ -685,17 +659,18 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * initialization will config the whole hierarchy. but we must * make sure BIOS doesn't set unsupported link state **/ - state = pcie_aspm_check_state(pdev, link_state->aspm_default); - __pcie_aspm_config_link(pdev, state); + state = pcie_aspm_check_state(link_state, + link_state->aspm_default); + __pcie_aspm_config_link(link_state, state); } else - __pcie_aspm_configure_link_state(pdev, - policy_to_aspm_state(pdev)); + __pcie_aspm_configure_link_state(link_state, + policy_to_aspm_state(link_state)); - pcie_check_clock_pm(pdev, blacklist); + pcie_check_clock_pm(link_state, blacklist); unlock_out: if (error) - free_link_state(pdev); + free_link_state(link_state); mutex_unlock(&aspm_lock); out: up_read(&pci_bus_sem); @@ -728,7 +703,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) list_del(&link_state->link); /* Clock PM is for endpoint device */ - free_link_state(parent); + free_link_state(link_state); out: mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -748,7 +723,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) * devices changed PM state, we should recheck if latency meets all * functions' requirement */ - pcie_aspm_configure_link_state(pdev, link_state->aspm_enabled); + pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); } /* @@ -775,9 +750,9 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) if (state & PCIE_LINK_STATE_CLKPM) link_state->clkpm_capable = 0; - __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled); + __pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); if (!link_state->clkpm_capable && link_state->clkpm_enabled) - pcie_set_clock_pm(parent, 0); + pcie_set_clock_pm(link_state, 0); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } @@ -786,7 +761,6 @@ EXPORT_SYMBOL(pci_disable_link_state); static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) { int i; - struct pci_dev *pdev; struct pcie_link_state *link_state; for (i = 0; i < ARRAY_SIZE(policy_str); i++) @@ -801,12 +775,12 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) mutex_lock(&aspm_lock); aspm_policy = i; list_for_each_entry(link_state, &link_list, sibling) { - pdev = link_state->pdev; - __pcie_aspm_configure_link_state(pdev, - policy_to_aspm_state(pdev)); + __pcie_aspm_configure_link_state(link_state, + policy_to_aspm_state(link_state)); if (link_state->clkpm_capable && - link_state->clkpm_enabled != policy_to_clkpm_state(pdev)) - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + link_state->clkpm_enabled != policy_to_clkpm_state(link_state)) + pcie_set_clock_pm(link_state, + policy_to_clkpm_state(link_state)); } mutex_unlock(&aspm_lock); @@ -844,7 +818,7 @@ static ssize_t link_state_store(struct device *dev, const char *buf, size_t n) { - struct pci_dev *pci_device = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); int state; if (n < 1) @@ -852,7 +826,7 @@ static ssize_t link_state_store(struct device *dev, state = buf[0]-'0'; if (state >= 0 && state <= 3) { /* setup link aspm state */ - pcie_aspm_configure_link_state(pci_device, state); + pcie_aspm_configure_link_state(pdev->link_state, state); return n; } @@ -883,7 +857,7 @@ static ssize_t clk_ctl_store(struct device *dev, down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clock_pm(pci_device, !!state); + pcie_set_clock_pm(pci_device->link_state, !!state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); From 8d349ace9a5c2a8404bcf4a371fe170480ffbebb Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:18:22 +0900 Subject: [PATCH 65/74] PCI ASPM: cleanup initialization Clean up ASPM initialization by refactoring some functionality, renaming functions, and moving things around. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 142 +++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 67 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 9eaaf95f65a2..68a4d4b15f9f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -126,7 +126,7 @@ static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) link->clkpm_enabled = !!enable; } -static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) +static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) { int pos, capable = 1, enabled = 1; u32 reg32; @@ -151,13 +151,7 @@ static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) } link->clkpm_enabled = enabled; link->clkpm_default = enabled; - if (!blacklist) { - link->clkpm_capable = capable; - pcie_set_clock_pm(link, policy_to_clkpm_state(link)); - } else { - link->clkpm_capable = 0; - pcie_set_clock_pm(link, 0); - } + link->clkpm_capable = (blacklist) ? 0 : capable; } static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) @@ -314,12 +308,23 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); } -static void pcie_aspm_cap_init(struct pcie_link_state *link) +static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) { u32 support, l0s, l1, enabled; struct pci_dev *child, *parent = link->pdev; struct pci_bus *linkbus = parent->subordinate; + if (blacklist) { + /* Set support state to 0, so we will disable ASPM later */ + link->aspm_support = 0; + link->aspm_default = 0; + link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; + return; + } + + /* Configure common clock before checking latencies */ + pcie_aspm_configure_common_clock(link); + /* upstream component states */ pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); link->aspm_support = support; @@ -590,6 +595,42 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) return 0; } +static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link; + int blacklist = !!pcie_aspm_sanity_check(pdev); + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return NULL; + INIT_LIST_HEAD(&link->sibling); + INIT_LIST_HEAD(&link->children); + INIT_LIST_HEAD(&link->link); + link->pdev = pdev; + link->has_switch = pcie_aspm_downstream_has_switch(link); + if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) { + struct pcie_link_state *parent; + parent = pdev->bus->parent->self->link_state; + if (!parent) { + kfree(link); + return NULL; + } + link->parent = parent; + list_add(&link->link, &parent->children); + } + list_add(&link->sibling, &link_list); + + pdev->link_state = link; + + /* Check ASPM capability */ + pcie_aspm_cap_init(link, blacklist); + + /* Check Clock PM capability */ + pcie_clkpm_cap_init(link, blacklist); + + return link; +} + /* * pcie_aspm_init_link_state: Initiate PCI express link state. * It is called after the pcie and its children devices are scaned. @@ -597,80 +638,47 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) */ void pcie_aspm_init_link_state(struct pci_dev *pdev) { - unsigned int state; - struct pcie_link_state *link_state; - int error = 0; - int blacklist; + u32 state; + struct pcie_link_state *link; if (aspm_disabled || !pdev->is_pcie || pdev->link_state) return; if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && - pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; + /* VIA has a strange chipset, root port is under a bridge */ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && - pdev->bus->self) + pdev->bus->self) return; + down_read(&pci_bus_sem); if (list_empty(&pdev->subordinate->devices)) goto out; - blacklist = !!pcie_aspm_sanity_check(pdev); - mutex_lock(&aspm_lock); - - link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); - if (!link_state) - goto unlock_out; - - INIT_LIST_HEAD(&link_state->children); - INIT_LIST_HEAD(&link_state->link); - if (pdev->bus->self) {/* this is a switch */ - struct pcie_link_state *parent_link_state; - - parent_link_state = pdev->bus->parent->self->link_state; - if (!parent_link_state) { - kfree(link_state); - goto unlock_out; - } - list_add(&link_state->link, &parent_link_state->children); - link_state->parent = parent_link_state; - } - link_state->pdev = pdev; - link_state->has_switch = pcie_aspm_downstream_has_switch(link_state); - pdev->link_state = link_state; - - if (!blacklist) { - pcie_aspm_configure_common_clock(link_state); - pcie_aspm_cap_init(link_state); + link = pcie_aspm_setup_link_state(pdev); + if (!link) + goto unlock; + /* + * Setup initial ASPM state + * + * If link has switch, delay the link config. The leaf link + * initialization will config the whole hierarchy. But we must + * make sure BIOS doesn't set unsupported link state. + */ + if (link->has_switch) { + state = pcie_aspm_check_state(link, link->aspm_default); + __pcie_aspm_config_link(link, state); } else { - link_state->aspm_enabled = - (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); - link_state->aspm_default = 0; - /* Set support state to 0, so we will disable ASPM later */ - link_state->aspm_support = 0; + state = policy_to_aspm_state(link); + __pcie_aspm_configure_link_state(link, state); } - list_add(&link_state->sibling, &link_list); - - if (link_state->has_switch) { - /* - * If link has switch, delay the link config. The leaf link - * initialization will config the whole hierarchy. but we must - * make sure BIOS doesn't set unsupported link state - **/ - state = pcie_aspm_check_state(link_state, - link_state->aspm_default); - __pcie_aspm_config_link(link_state, state); - } else - __pcie_aspm_configure_link_state(link_state, - policy_to_aspm_state(link_state)); - - pcie_check_clock_pm(link_state, blacklist); - -unlock_out: - if (error) - free_link_state(link_state); + /* Setup initial Clock PM state */ + state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; + pcie_set_clock_pm(link, state); +unlock: mutex_unlock(&aspm_lock); out: up_read(&pci_bus_sem); From f7ea3d7fc03753b08e267fece19c56383e6b856f Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:19:00 +0900 Subject: [PATCH 66/74] PCI ASPM: cleanup __pcie_aspm_check_state_one Clean up and simplify __pcie_aspm_check_state_one(). Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 67 +++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 68a4d4b15f9f..694ba5657758 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -370,56 +370,39 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) } } -static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, - unsigned int state) +/** + * __pcie_aspm_check_state_one - check latency for endpoint device. + * @endpoint: pointer to the struct pci_dev of endpoint device + * + * TBD: The latency from the endpoint to root complex vary per switch's + * upstream link state above the device. Here we just do a simple check + * which assumes all links above the device can be in L1 state, that + * is we just consider the worst case. If switch's upstream link can't + * be put into L0S/L1, then our check is too strictly. + */ +static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state) { - struct pci_dev *parent_dev, *tmp_dev; - unsigned int l1_latency = 0; - struct pcie_link_state *link_state; + u32 l1_switch_latency = 0; struct aspm_latency *acceptable; + struct pcie_link_state *link; - parent_dev = pdev->bus->self; - link_state = parent_dev->link_state; - state &= link_state->aspm_support; - if (state == 0) - return 0; - acceptable = &link_state->acceptable[PCI_FUNC(pdev->devfn)]; + link = endpoint->bus->self->link_state; + state &= link->aspm_support; + acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)]; - /* - * Check latency for endpoint device. - * TBD: The latency from the endpoint to root complex vary per - * switch's upstream link state above the device. Here we just do a - * simple check which assumes all links above the device can be in L1 - * state, that is we just consider the worst case. If switch's upstream - * link can't be put into L0S/L1, then our check is too strictly. - */ - tmp_dev = pdev; - while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { - parent_dev = tmp_dev->bus->self; - link_state = parent_dev->link_state; + while (link && state) { if ((state & PCIE_LINK_STATE_L0S) && - (link_state->latency.l0s > acceptable->l0s)) + (link->latency.l0s > acceptable->l0s)) state &= ~PCIE_LINK_STATE_L0S; - if ((state & PCIE_LINK_STATE_L1) && - (link_state->latency.l1 + l1_latency > acceptable->l1)) + (link->latency.l1 + l1_switch_latency > acceptable->l1)) state &= ~PCIE_LINK_STATE_L1; - - if (!parent_dev->bus->self) /* parent_dev is a root port */ - break; - else { - /* - * parent_dev is the downstream port of a switch, make - * tmp_dev the upstream port of the switch - */ - tmp_dev = parent_dev->bus->self; - /* - * every switch on the path to root complex need 1 more - * microsecond for L1. Spec doesn't mention L0S. - */ - if (state & PCIE_LINK_STATE_L1) - l1_latency += 1000; - } + link = link->parent; + /* + * Every switch on the path to root complex need 1 + * more microsecond for L1. Spec doesn't mention L0s. + */ + l1_switch_latency += 1000; } return state; } From 430842e29d396928989c0a45e05025e988004d79 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:20:10 +0900 Subject: [PATCH 67/74] PCI ASPM: cleanup clkpm checks In the current ASPM implementation, callers of pcie_set_clock_pm() check Clock PM capability of the link or current Clock PM state of the link. This check should be done in pcie_set_clock_pm() itself. This patch moves those checks into pcie_set_clock_pm(). It also introduces pcie_set_clkpm_nocheck() that is equivalent to old pcie_set_clock_pm(), for the caller who wants to change Clocl PM state regardless of the Clock PM capability or current Clock PM state. In addition, this patch changes the function name from pcie_set_clock_pm() to pcie_set_clkpm() for consistency. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 694ba5657758..0d0d3e630925 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -105,7 +105,7 @@ static int policy_to_clkpm_state(struct pcie_link_state *link) return 0; } -static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) +static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) { int pos; u16 reg16; @@ -126,6 +126,17 @@ static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) link->clkpm_enabled = !!enable; } +static void pcie_set_clkpm(struct pcie_link_state *link, int enable) +{ + /* Don't enable Clock PM if the link is not Clock PM capable */ + if (!link->clkpm_capable && enable) + return; + /* Need nothing if the specified equals to current state */ + if (link->clkpm_enabled == enable) + return; + pcie_set_clkpm_nocheck(link, enable); +} + static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) { int pos, capable = 1, enabled = 1; @@ -660,7 +671,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) /* Setup initial Clock PM state */ state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; - pcie_set_clock_pm(link, state); + pcie_set_clkpm(link, state); unlock: mutex_unlock(&aspm_lock); out: @@ -738,12 +749,11 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) mutex_lock(&aspm_lock); link_state = parent->link_state; link_state->aspm_support &= ~state; - if (state & PCIE_LINK_STATE_CLKPM) - link_state->clkpm_capable = 0; - __pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); - if (!link_state->clkpm_capable && link_state->clkpm_enabled) - pcie_set_clock_pm(link_state, 0); + if (state & PCIE_LINK_STATE_CLKPM) { + link_state->clkpm_capable = 0; + pcie_set_clkpm(link_state, 0); + } mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } @@ -768,11 +778,7 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) list_for_each_entry(link_state, &link_list, sibling) { __pcie_aspm_configure_link_state(link_state, policy_to_aspm_state(link_state)); - if (link_state->clkpm_capable && - link_state->clkpm_enabled != policy_to_clkpm_state(link_state)) - pcie_set_clock_pm(link_state, - policy_to_clkpm_state(link_state)); - + pcie_set_clkpm(link_state, policy_to_clkpm_state(link_state)); } mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -839,7 +845,7 @@ static ssize_t clk_ctl_store(struct device *dev, const char *buf, size_t n) { - struct pci_dev *pci_device = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); int state; if (n < 1) @@ -848,7 +854,7 @@ static ssize_t clk_ctl_store(struct device *dev, down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clock_pm(pci_device->link_state, !!state); + pcie_set_clkpm_nocheck(pdev->link_state, !!state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); From 7ab709910323a8af20722c066267516b3e7680a2 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:20:48 +0900 Subject: [PATCH 68/74] PCI ASPM: cleanup pcie_aspm_get_cap_device Minor cleanup for pcie_aspm_get_cap_device(). Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 0d0d3e630925..d85f77ff150c 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -292,19 +292,18 @@ static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) } static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, - unsigned int *l0s, unsigned int *l1, unsigned int *enabled) + u32 *l0s, u32 *l1, u32 *enabled) { int pos; u16 reg16; - u32 reg32; - unsigned int latency; + u32 reg32, latency; *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; if (*state != PCIE_LINK_STATE_L0S && - *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S)) + *state != (PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S)) *state = 0; if (*state == 0) return; @@ -316,7 +315,7 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, *l1 = calc_L1_latency(latency, 0); } pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); - *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); + *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); } static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) From 5e0eaa7d3679c3ef8618803bc9311270e5816641 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:21:48 +0900 Subject: [PATCH 69/74] PCI ASPM: cleanup calc_Lx_latency Cleanup for calc_L0S_latency() and calc_L1_latency(). - Separate exit latency and acceptable latency calculation. - Some minor cleanups. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 75 +++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index d85f77ff150c..23fabb303e82 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -257,38 +257,36 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg); } -/* - * calc_L0S_latency: Convert L0s latency encoding to ns - */ -static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac) +/* Convert L0s latency encoding to ns */ +static u32 calc_l0s_latency(u32 encoding) { - unsigned int ns = 64; - - if (latency_encoding == 0x7) { - if (ac) - ns = -1U; - else - ns = 5*1000; /* > 4us */ - } else - ns *= (1 << latency_encoding); - return ns; + if (encoding == 0x7) + return (5 * 1000); /* > 4us */ + return (64 << encoding); } -/* - * calc_L1_latency: Convert L1 latency encoding to ns - */ -static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) +/* Convert L0s acceptable latency encoding to ns */ +static u32 calc_l0s_acceptable(u32 encoding) { - unsigned int ns = 1000; + if (encoding == 0x7) + return -1U; + return (64 << encoding); +} - if (latency_encoding == 0x7) { - if (ac) - ns = -1U; - else - ns = 65*1000; /* > 64us */ - } else - ns *= (1 << latency_encoding); - return ns; +/* Convert L1 latency encoding to ns */ +static u32 calc_l1_latency(u32 encoding) +{ + if (encoding == 0x7) + return (65 * 1000); /* > 64us */ + return (1000 << encoding); +} + +/* Convert L1 acceptable latency encoding to ns */ +static u32 calc_l1_acceptable(u32 encoding) +{ + if (encoding == 0x7) + return -1U; + return (1000 << encoding); } static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, @@ -296,7 +294,7 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, { int pos; u16 reg16; - u32 reg32, latency; + u32 reg32, encoding; *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); @@ -308,11 +306,11 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, if (*state == 0) return; - latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; - *l0s = calc_L0S_latency(latency, 0); + encoding = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; + *l0s = calc_l0s_latency(encoding); if (*state & PCIE_LINK_STATE_L1) { - latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; - *l1 = calc_L1_latency(latency, 0); + encoding = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; + *l1 = calc_l1_latency(encoding); } pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); @@ -358,8 +356,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) /* ENDPOINT states*/ list_for_each_entry(child, &linkbus->devices, bus_list) { int pos; - u32 reg32; - unsigned int latency; + u32 reg32, encoding; struct aspm_latency *acceptable = &link->acceptable[PCI_FUNC(child->devfn)]; @@ -369,13 +366,11 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) pos = pci_find_capability(child, PCI_CAP_ID_EXP); pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); - latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; - latency = calc_L0S_latency(latency, 1); - acceptable->l0s = latency; + encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; + acceptable->l0s = calc_l0s_acceptable(encoding); if (link->aspm_support & PCIE_LINK_STATE_L1) { - latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; - latency = calc_L1_latency(latency, 1); - acceptable->l1 = latency; + encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; + acceptable->l1 = calc_l1_acceptable(encoding); } } } From efdf8288819df67d608a186f9d17a7d4051f3c1f Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:22:26 +0900 Subject: [PATCH 70/74] PCI ASPM: remove has_switch field We don't need the 'has_switch' field in the struct pcie_link_state. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 23fabb303e82..26fd39caebc5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -48,8 +48,6 @@ struct pcie_link_state { u32 clkpm_enabled:1; /* Current Clock PM state */ u32 clkpm_default:1; /* Default Clock PM state by BIOS */ - u32 has_switch:1; /* Downstream has switches? */ - /* Latencies */ struct aspm_latency latency; /* Exit latency */ /* @@ -595,7 +593,6 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) INIT_LIST_HEAD(&link->children); INIT_LIST_HEAD(&link->link); link->pdev = pdev; - link->has_switch = pcie_aspm_downstream_has_switch(link); if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) { struct pcie_link_state *parent; parent = pdev->bus->parent->self->link_state; @@ -655,7 +652,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * initialization will config the whole hierarchy. But we must * make sure BIOS doesn't set unsupported link state. */ - if (link->has_switch) { + if (pcie_aspm_downstream_has_switch(link)) { state = pcie_aspm_check_state(link, link->aspm_default); __pcie_aspm_config_link(link, state); } else { From 3647584d9ef35c9ec4abefdbea29959c26c54f13 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:23:09 +0900 Subject: [PATCH 71/74] PCI ASPM: cleanup pcie_aspm_sanity_check Minor cleanup for pcie_aspm_sanity_check(). Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 26fd39caebc5..04b6a3098505 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -552,27 +552,24 @@ static void free_link_state(struct pcie_link_state *link) static int pcie_aspm_sanity_check(struct pci_dev *pdev) { - struct pci_dev *child_dev; - int child_pos; + struct pci_dev *child; + int pos; u32 reg32; - /* - * Some functions in a slot might not all be PCIE functions, very - * strange. Disable ASPM for the whole slot + * Some functions in a slot might not all be PCIE functions, + * very strange. Disable ASPM for the whole slot */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - if (!child_pos) + list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); + if (!pos) return -EINVAL; - /* * Disable ASPM for pre-1.1 PCIe device, we follow MS to use * RBER bit to determine if a function is 1.1 version device */ - pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, - ®32); + pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) { - dev_printk(KERN_INFO, &child_dev->dev, "disabling ASPM" + dev_printk(KERN_INFO, &child->dev, "disabling ASPM" " on pre-1.1 PCIe device. You can enable it" " with 'pcie_aspm=force'\n"); return -EINVAL; From 5c92ffb1ecc7f13267cdef5dda8a838937912c93 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Wed, 13 May 2009 12:23:57 +0900 Subject: [PATCH 72/74] PCI ASPM: remove get_root_port_link By having a pointer to the root port link, we can remove loops in get_root_port_link() to search the root port link. Acked-by: Shaohua Li Signed-off-by: Kenji Kaneshige Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 04b6a3098505..3d27c97e0486 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -33,6 +33,7 @@ struct aspm_latency { struct pcie_link_state { struct pci_dev *pdev; /* Upstream component of the Link */ + struct pcie_link_state *root; /* pointer to the root port link */ struct pcie_link_state *parent; /* pointer to the parent Link state */ struct list_head sibling; /* node in link_list */ struct list_head children; /* list of child link states */ @@ -486,26 +487,17 @@ static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) link->aspm_enabled = state; } -static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) -{ - struct pcie_link_state *root_port_link = link; - while (root_port_link->parent) - root_port_link = root_port_link->parent; - return root_port_link; -} - /* Check the whole hierarchy, and configure each link in the hierarchy */ static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, u32 state) { - struct pcie_link_state *leaf, *root = get_root_port_link(link); + struct pcie_link_state *leaf, *root = link->root; state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); /* Check all links who have specific root port link */ list_for_each_entry(leaf, &link_list, sibling) { - if (!list_empty(&leaf->children) || - get_root_port_link(leaf) != root) + if (!list_empty(&leaf->children) || (leaf->root != root)) continue; state = pcie_aspm_check_state(leaf, state); } @@ -519,12 +511,12 @@ static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, **/ if (state & PCIE_LINK_STATE_L1) { list_for_each_entry(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root) + if (leaf->root == root) __pcie_aspm_config_link(leaf, state); } } else { list_for_each_entry_reverse(leaf, &link_list, sibling) { - if (get_root_port_link(leaf) == root) + if (leaf->root == root) __pcie_aspm_config_link(leaf, state); } } @@ -600,6 +592,12 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) link->parent = parent; list_add(&link->link, &parent->children); } + /* Setup a pointer to the root port link */ + if (!link->parent) + link->root = link; + else + link->root = link->parent->root; + list_add(&link->sibling, &link_list); pdev->link_state = link; From f598282f5145036312d90875d0ed5c14b49fd8a7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Thu, 18 Jun 2009 19:15:59 -0700 Subject: [PATCH 73/74] PCI: Fix the NIU MSI-X problem in a better way The previous MSI-X fix (8d181018532dd709ec1f789e374cda92d7b01ce1) had three bugs. First, it didn't move the write that disabled the vector. This led to writing garbage to the MSI-X vector (spotted by Michael Ellerman). It didn't fix the PCI resume case, and it had a race window where the device could generate an interrupt before the MSI-X registers were programmed (leading to a DMA to random addresses). Fortunately, the MSI-X capability has a bit to mask all the vectors. By setting this bit instead of clearing the enable bit, we can ensure the device will not generate spurious interrupts. Since the capability is now enabled, the NIU device will not have a problem with the reads and writes to the MSI-X registers being in the original order in the code. Signed-off-by: Matthew Wilcox Reviewed-by: Hidetoshi Seto Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 79e56906c7f1..944e45e4a84f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -313,22 +313,22 @@ static void __pci_restore_msix_state(struct pci_dev *dev) if (!dev->msix_enabled) return; + BUG_ON(list_empty(&dev->msi_list)); + entry = list_entry(dev->msi_list.next, struct msi_desc, list); + pos = entry->msi_attrib.pos; + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); /* route the table */ pci_intx_for_msi(dev, 0); - msix_set_enable(dev, 0); + control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); list_for_each_entry(entry, &dev->msi_list, list) { write_msi_msg(entry->irq, &entry->msg); msix_mask_irq(entry, entry->masked); } - BUG_ON(list_empty(&dev->msi_list)); - entry = list_entry(dev->msi_list.next, struct msi_desc, list); - pos = entry->msi_attrib.pos; - pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); control &= ~PCI_MSIX_FLAGS_MASKALL; - control |= PCI_MSIX_FLAGS_ENABLE; pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); } @@ -419,11 +419,14 @@ static int msix_capability_init(struct pci_dev *dev, u8 bir; void __iomem *base; - msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); + + /* Ensure MSI-X is disabled while it is set up */ + control &= ~PCI_MSIX_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); + /* Request & Map MSI-X table region */ - pci_read_config_word(dev, msi_control_reg(pos), &control); nr_entries = multi_msix_capable(control); pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset); @@ -434,7 +437,6 @@ static int msix_capability_init(struct pci_dev *dev, if (base == NULL) return -ENOMEM; - /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { entry = alloc_msi_entry(dev); if (!entry) @@ -447,7 +449,6 @@ static int msix_capability_init(struct pci_dev *dev, entry->msi_attrib.default_irq = dev->irq; entry->msi_attrib.pos = pos; entry->mask_base = base; - msix_mask_irq(entry, 1); list_add_tail(&entry->list, &dev->msi_list); } @@ -472,22 +473,31 @@ static int msix_capability_init(struct pci_dev *dev, return ret; } + /* + * Some devices require MSI-X to be enabled before we can touch the + * MSI-X registers. We need to mask all the vectors to prevent + * interrupts coming in before they're fully set up. + */ + control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); + i = 0; list_for_each_entry(entry, &dev->msi_list, list) { entries[i].vector = entry->irq; set_irq_msi(entry->irq, entry); + j = entries[i].entry; + entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + msix_mask_irq(entry, 1); i++; } - /* Set MSI-X enabled bits */ + + /* Set MSI-X enabled bits and unmask the function */ pci_intx_for_msi(dev, 0); - msix_set_enable(dev, 1); dev->msix_enabled = 1; - list_for_each_entry(entry, &dev->msi_list, list) { - int vector = entry->msi_attrib.entry_nr; - entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - } + control &= ~PCI_MSIX_FLAGS_MASKALL; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); return 0; } From 2af5066f664cb011cf17d2e4414491fe24597e07 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Thu, 18 Jun 2009 19:20:26 -0700 Subject: [PATCH 74/74] PCI: make msi_free_irqs() to use msix_mask_irq() instead of open coded write Use msix_mask_irq() instead of direct use of writel, so as not to clear preserved bits in the Vector Control register [31:1]. Signed-off-by: Hidetoshi Seto Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 944e45e4a84f..d9f06fbfa0bf 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -653,10 +653,7 @@ static int msi_free_irqs(struct pci_dev* dev) list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { if (entry->msi_attrib.is_msix) { - writel(1, entry->mask_base + entry->msi_attrib.entry_nr - * PCI_MSIX_ENTRY_SIZE - + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - + msix_mask_irq(entry, 1); if (list_is_last(&entry->list, &dev->msi_list)) iounmap(entry->mask_base); }