Commit b424e8d3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (98 commits)
  PCI PM: Put PM callbacks in the order of execution
  PCI PM: Run default PM callbacks for all devices using new framework
  PCI PM: Register power state of devices during initialization
  PCI PM: Call pci_fixup_device from legacy routines
  PCI PM: Rearrange code in pci-driver.c
  PCI PM: Avoid touching devices behind bridges in unknown state
  PCI PM: Move pci_has_legacy_pm_support
  PCI PM: Power-manage devices without drivers during suspend-resume
  PCI PM: Add suspend counterpart of pci_reenable_device
  PCI PM: Fix poweroff and restore callbacks
  PCI: Use msleep instead of cpu_relax during ASPM link retraining
  PCI: PCIe portdrv: Add kerneldoc comments to remining core funtions
  PCI: PCIe portdrv: Rearrange code so that related things are together
  PCI: PCIe portdrv: Fix suspend and resume of PCI Express port services
  PCI: PCIe portdrv: Add kerneldoc comments to some core functions
  x86/PCI: Do not use interrupt links for devices using MSI-X
  net: sfc: Use pci_clear_master() to disable bus mastering
  PCI: Add pci_clear_master() as opposite of pci_set_master()
  PCI hotplug: remove redundant test in cpq hotplug
  PCI: pciehp: cleanup register and field definitions
  ...
parents 7c7758f9 f6dc1e5e
...@@ -294,7 +294,8 @@ NOTE: pci_enable_device() can fail! Check the return value. ...@@ -294,7 +294,8 @@ NOTE: pci_enable_device() can fail! Check the return value.
pci_set_master() will enable DMA by setting the bus master bit pci_set_master() will enable DMA by setting the bus master bit
in the PCI_COMMAND register. It also fixes the latency timer value if in the PCI_COMMAND register. It also fixes the latency timer value if
it's set to something bogus by the BIOS. it's set to something bogus by the BIOS. pci_clear_master() will
disable DMA by clearing the bus master bit.
If the PCI device can use the PCI Memory-Write-Invalidate transaction, If the PCI device can use the PCI Memory-Write-Invalidate transaction,
call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval
......
...@@ -919,6 +919,10 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -919,6 +919,10 @@ and is between 256 and 4096 characters. It is defined in the file
inttest= [IA64] inttest= [IA64]
iomem= Disable strict checking of access to MMIO memory
strict regions from userspace.
relaxed
iommu= [x86] iommu= [x86]
off off
force force
......
...@@ -320,24 +320,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq) ...@@ -320,24 +320,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
} }
/* Most Alphas have straight-forward swizzling needs. */
u8 __init
common_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (dev->bus->parent) {
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
/* Move up the chain of bridges. */
dev = dev->bus->self;
}
*pinp = pin;
/* The slot is the slot of the last bridge. */
return PCI_SLOT(dev->devfn);
}
void void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res) struct resource *res)
......
...@@ -106,16 +106,11 @@ struct pci_iommu_arena; ...@@ -106,16 +106,11 @@ struct pci_iommu_arena;
* Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
* Thus, each swizzle is ((pin-1) + (device#-4)) % 4 * Thus, each swizzle is ((pin-1) + (device#-4)) % 4
* *
* The following code swizzles for exactly one bridge. The routine * pci_swizzle_interrupt_pin() swizzles for exactly one bridge. The routine
* common_swizzle below handles multiple bridges. But there are a * pci_common_swizzle() handles multiple bridges. But there are a
* couple boards that do strange things, so we define this here. * couple boards that do strange things.
*/ */
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin-1) + slot) % 4) + 1;
}
/* The following macro is used to implement the table-based irq mapping /* The following macro is used to implement the table-based irq mapping
function for all single-bus Alphas. */ function for all single-bus Alphas. */
...@@ -184,7 +179,7 @@ extern int pci_probe_only; ...@@ -184,7 +179,7 @@ extern int pci_probe_only;
extern unsigned long alpha_agpgart_size; extern unsigned long alpha_agpgart_size;
extern void common_init_pci(void); extern void common_init_pci(void);
extern u8 common_swizzle(struct pci_dev *, u8 *); #define common_swizzle pci_common_swizzle
extern struct pci_controller *alloc_pci_controller(void); extern struct pci_controller *alloc_pci_controller(void);
extern struct resource *alloc_resource(void); extern struct resource *alloc_resource(void);
......
...@@ -481,7 +481,7 @@ monet_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -481,7 +481,7 @@ monet_swizzle(struct pci_dev *dev, u8 *pinp)
slot = PCI_SLOT(dev->devfn); slot = PCI_SLOT(dev->devfn);
break; break;
} }
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ; pin = pci_swizzle_interrupt_pin(dev, pin);
/* Move up the chain of bridges. */ /* Move up the chain of bridges. */
dev = dev->bus->self; dev = dev->bus->self;
......
...@@ -204,7 +204,7 @@ eiger_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -204,7 +204,7 @@ eiger_swizzle(struct pci_dev *dev, u8 *pinp)
break; break;
} }
/* Must be a card-based bridge. */ /* Must be a card-based bridge. */
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); pin = pci_swizzle_interrupt_pin(dev, pin);
/* Move up the chain of bridges. */ /* Move up the chain of bridges. */
dev = dev->bus->self; dev = dev->bus->self;
......
...@@ -219,7 +219,7 @@ miata_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -219,7 +219,7 @@ miata_swizzle(struct pci_dev *dev, u8 *pinp)
slot = PCI_SLOT(dev->devfn) + 9; slot = PCI_SLOT(dev->devfn) + 9;
break; break;
} }
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); pin = pci_swizzle_interrupt_pin(dev, pin);
/* Move up the chain of bridges. */ /* Move up the chain of bridges. */
dev = dev->bus->self; dev = dev->bus->self;
......
...@@ -257,7 +257,7 @@ noritake_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -257,7 +257,7 @@ noritake_swizzle(struct pci_dev *dev, u8 *pinp)
slot = PCI_SLOT(dev->devfn) + 15; slot = PCI_SLOT(dev->devfn) + 15;
break; break;
} }
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ; pin = pci_swizzle_interrupt_pin(dev, pin);
/* Move up the chain of bridges. */ /* Move up the chain of bridges. */
dev = dev->bus->self; dev = dev->bus->self;
......
...@@ -160,7 +160,7 @@ ruffian_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -160,7 +160,7 @@ ruffian_swizzle(struct pci_dev *dev, u8 *pinp)
slot = PCI_SLOT(dev->devfn) + 10; slot = PCI_SLOT(dev->devfn) + 10;
break; break;
} }
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); pin = pci_swizzle_interrupt_pin(dev, pin);
/* Move up the chain of bridges. */ /* Move up the chain of bridges. */
dev = dev->bus->self; dev = dev->bus->self;
......
...@@ -425,7 +425,7 @@ lynx_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -425,7 +425,7 @@ lynx_swizzle(struct pci_dev *dev, u8 *pinp)
slot = PCI_SLOT(dev->devfn) + 11; slot = PCI_SLOT(dev->devfn) + 11;
break; break;
} }
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ; pin = pci_swizzle_interrupt_pin(dev, pin);
/* Move up the chain of bridges. */ /* Move up the chain of bridges. */
dev = dev->bus->self; dev = dev->bus->self;
......
...@@ -42,7 +42,7 @@ struct pci_sys_data { ...@@ -42,7 +42,7 @@ struct pci_sys_data {
/* /*
* This is the standard PCI-PCI bridge swizzling algorithm. * This is the standard PCI-PCI bridge swizzling algorithm.
*/ */
u8 pci_std_swizzle(struct pci_dev *dev, u8 *pinp); #define pci_std_swizzle pci_common_swizzle
/* /*
* Call this with your hw_pci struct to initialise the PCI system. * Call this with your hw_pci struct to initialise the PCI system.
......
...@@ -479,33 +479,6 @@ EXPORT_SYMBOL(pcibios_resource_to_bus); ...@@ -479,33 +479,6 @@ EXPORT_SYMBOL(pcibios_resource_to_bus);
EXPORT_SYMBOL(pcibios_bus_to_resource); EXPORT_SYMBOL(pcibios_bus_to_resource);
#endif #endif
/*
* This is the standard PCI-PCI bridge swizzling algorithm:
*
* Dev: 0 1 2 3
* A A B C D
* B B C D A
* C C D A B
* D D A B C
* ^^^^^^^^^^ irq pin on bridge
*/
u8 __devinit pci_std_swizzle(struct pci_dev *dev, u8 *pinp)
{
int pin = *pinp - 1;
while (dev->bus->self) {
pin = (pin + PCI_SLOT(dev->devfn)) & 3;
/*
* move up the chain of bridges,
* swizzling as we go.
*/
dev = dev->bus->self;
}
*pinp = pin + 1;
return PCI_SLOT(dev->devfn);
}
/* /*
* Swizzle the device pin each time we cross a bridge. * Swizzle the device pin each time we cross a bridge.
* This might update pin and returns the slot number. * This might update pin and returns the slot number.
......
...@@ -63,13 +63,7 @@ ...@@ -63,13 +63,7 @@
* *
* Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
* Thus, each swizzle is ((pin-1) + (device#-4)) % 4 * Thus, each swizzle is ((pin-1) + (device#-4)) % 4
*
* The following code swizzles for exactly one bridge.
*/ */
static inline int bridge_swizzle(int pin, unsigned int slot)
{
return (pin + slot) & 3;
}
/* /*
* This routine handles multiple bridges. * This routine handles multiple bridges.
...@@ -81,15 +75,14 @@ static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -81,15 +75,14 @@ static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp)
if (pin == 0) if (pin == 0)
pin = 1; pin = 1;
pin -= 1;
while (dev->bus->self) { while (dev->bus->self) {
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); pin = pci_swizzle_interrupt_pin(dev, pin);
/* /*
* move up the chain of bridges, swizzling as we go. * move up the chain of bridges, swizzling as we go.
*/ */
dev = dev->bus->self; dev = dev->bus->self;
} }
*pinp = pin + 1; *pinp = pin;
return PCI_SLOT(dev->devfn); return PCI_SLOT(dev->devfn);
} }
......
...@@ -146,12 +146,6 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ...@@ -146,12 +146,6 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return 0; return 0;
} }
/* Most MIPS systems have straight-forward swizzling needs. */
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev) static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev)
{ {
while (dev->bus->parent) { while (dev->bus->parent) {
......
...@@ -149,28 +149,6 @@ void __devinit register_pci_controller(struct pci_controller *hose) ...@@ -149,28 +149,6 @@ void __devinit register_pci_controller(struct pci_controller *hose)
"Skipping PCI bus scan due to resource conflict\n"); "Skipping PCI bus scan due to resource conflict\n");
} }
/* Most MIPS systems have straight-forward swizzling needs. */
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (dev->bus->parent) {
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
/* Move up the chain of bridges. */
dev = dev->bus->self;
}
*pinp = pin;
/* The slot is the slot of the last bridge. */
return PCI_SLOT(dev->devfn);
}
static int __init pcibios_init(void) static int __init pcibios_init(void)
{ {
struct pci_controller *hose; struct pci_controller *hose;
...@@ -179,7 +157,7 @@ static int __init pcibios_init(void) ...@@ -179,7 +157,7 @@ static int __init pcibios_init(void)
for (hose = hose_head; hose; hose = hose->next) for (hose = hose_head; hose; hose = hose->next)
pcibios_scanbus(hose); pcibios_scanbus(hose);
pci_fixup_irqs(common_swizzle, pcibios_map_irq); pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
pci_initialized = 1; pci_initialized = 1;
......
...@@ -232,11 +232,6 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, ...@@ -232,11 +232,6 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
} }
EXPORT_SYMBOL_GPL(of_pci_address_to_resource); EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
{
return (((pin - 1) + slot) % 4) + 1;
}
int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
{ {
struct device_node *dn, *ppnode; struct device_node *dn, *ppnode;
...@@ -306,7 +301,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) ...@@ -306,7 +301,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
/* We can only get here if we hit a P2P bridge with no node, /* We can only get here if we hit a P2P bridge with no node,
* let's do standard swizzling and try again * let's do standard swizzling and try again
*/ */
lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); lspec = pci_swizzle_interrupt_pin(pdev, lspec);
pdev = ppdev; pdev = ppdev;
} }
......
...@@ -5,11 +5,6 @@ ...@@ -5,11 +5,6 @@
#include <cpu/irq.h> #include <cpu/irq.h>
#include "pci-sh5.h" #include "pci-sh5.h"
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
{ {
int result = -1; int result = -1;
...@@ -42,7 +37,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) ...@@ -42,7 +37,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
while (dev->bus->number > 0) { while (dev->bus->number > 0) {
slot = path[i].slot = PCI_SLOT(dev->devfn); slot = path[i].slot = PCI_SLOT(dev->devfn);
pin = path[i].pin = bridge_swizzle(pin, slot); pin = path[i].pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self; dev = dev->bus->self;
i++; i++;
if (i > 3) panic("PCI path to root bus too long!\n"); if (i > 3) panic("PCI path to root bus too long!\n");
...@@ -56,7 +51,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) ...@@ -56,7 +51,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
if ((slot < 3) || (i == 0)) { if ((slot < 3) || (i == 0)) {
/* Bus 0 (incl. PCI-PCI bridge itself) : perform the final /* Bus 0 (incl. PCI-PCI bridge itself) : perform the final
swizzle now. */ swizzle now. */
result = IRQ_INTA + bridge_swizzle(pin, slot) - 1; result = IRQ_INTA + pci_swizzle_interrupt_pin(dev, pin) - 1;
} else { } else {
i--; i--;
slot = path[i].slot; slot = path[i].slot;
......
...@@ -21,26 +21,6 @@ ...@@ -21,26 +21,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/io.h> #include <asm/io.h>
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (dev->bus->parent) {
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
/* Move up the chain of bridges. */
dev = dev->bus->self;
}
*pinp = pin;
/* The slot is the slot of the last bridge. */
return PCI_SLOT(dev->devfn);
}
static int __init pcibios_init(void) static int __init pcibios_init(void)
{ {
struct pci_channel *p; struct pci_channel *p;
...@@ -61,7 +41,7 @@ static int __init pcibios_init(void) ...@@ -61,7 +41,7 @@ static int __init pcibios_init(void)
busno = bus->subordinate + 1; busno = bus->subordinate + 1;
} }
pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq); pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
return 0; return 0;
} }
......
...@@ -38,7 +38,7 @@ EXPORT_SYMBOL(bad_dma_address); ...@@ -38,7 +38,7 @@ EXPORT_SYMBOL(bad_dma_address);
be probably a smaller DMA mask, but this is bug-to-bug compatible be probably a smaller DMA mask, but this is bug-to-bug compatible
to older i386. */ to older i386. */
struct device x86_dma_fallback_dev = { struct device x86_dma_fallback_dev = {
.bus_id = "fallback device", .init_name = "fallback device",
.coherent_dma_mask = DMA_32BIT_MASK, .coherent_dma_mask = DMA_32BIT_MASK,
.dma_mask = &x86_dma_fallback_dev.coherent_dma_mask, .dma_mask = &x86_dma_fallback_dev.coherent_dma_mask,
}; };
......
...@@ -328,6 +328,8 @@ int devmem_is_allowed(unsigned long pagenr) ...@@ -328,6 +328,8 @@ int devmem_is_allowed(unsigned long pagenr)
{ {
if (pagenr <= 256) if (pagenr <= 256)
return 1; return 1;
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
return 0;
if (!page_is_ram(pagenr)) if (!page_is_ram(pagenr))
return 1; return 1;
return 0; return 0;
......
...@@ -888,6 +888,8 @@ int devmem_is_allowed(unsigned long pagenr) ...@@ -888,6 +888,8 @@ int devmem_is_allowed(unsigned long pagenr)
{ {
if (pagenr <= 256) if (pagenr <= 256)
return 1; return 1;
if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
return 0;
if (!page_is_ram(pagenr)) if (!page_is_ram(pagenr))
return 1; return 1;
return 0; return 0;
......
...@@ -210,11 +210,10 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do ...@@ -210,11 +210,10 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
if (bus && node != -1) { if (bus && node != -1) {
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
if (pxm >= 0) if (pxm >= 0)
printk(KERN_DEBUG "bus %02x -> pxm %d -> node %d\n", dev_printk(KERN_DEBUG, &bus->dev,
busnum, pxm, node); "on NUMA node %d (pxm %d)\n", node, pxm);
#else #else
printk(KERN_DEBUG "bus %02x -> node %d\n", dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
busnum, node);
#endif #endif
} }
......
...@@ -551,17 +551,25 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) ...@@ -551,17 +551,25 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
if ((err = pci_enable_resources(dev, mask)) < 0) if ((err = pci_enable_resources(dev, mask)) < 0)
return err; return err;
if (!dev->msi_enabled) if (!pci_dev_msi_enabled(dev))
return pcibios_enable_irq(dev); return pcibios_enable_irq(dev);
return 0; return 0;
} }
void pcibios_disable_device (struct pci_dev *dev) void pcibios_disable_device (struct pci_dev *dev)
{ {
if (!dev->msi_enabled && pcibios_disable_irq) if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
pcibios_disable_irq(dev); pcibios_disable_irq(dev);
} }
int pci_ext_cfg_avail(struct pci_dev *dev)
{
if (raw_pci_ext_ops)
return 1;
else
return 0;
}
struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
{ {
struct pci_bus *bus = NULL; struct pci_bus *bus = NULL;
......
...@@ -129,7 +129,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) ...@@ -129,7 +129,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
pr = pci_find_parent_resource(dev, r); pr = pci_find_parent_resource(dev, r);
if (!r->start || !pr || if (!r->start || !pr ||
request_resource(pr, r) < 0) { request_resource(pr, r) < 0) {
dev_err(&dev->dev, "BAR %d: can't allocate resource\n", idx); dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx);
/* /*
* Something is wrong with the region. * Something is wrong with the region.
* Invalidate the resource to prevent * Invalidate the resource to prevent
...@@ -170,7 +170,7 @@ static void __init pcibios_allocate_resources(int pass) ...@@ -170,7 +170,7 @@ static void __init pcibios_allocate_resources(int pass)
r->flags, disabled, pass); r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r); pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) { if (!pr || request_resource(pr, r) < 0) {
dev_err(&dev->dev, "BAR %d: can't allocate resource\n", idx); dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx);
/* We'll assign a new address later */ /* We'll assign a new address later */
r->end -= r->start; r->end -= r->start;
r->start = 0; r->start = 0;
......
...@@ -12,7 +12,8 @@ static __init int pci_arch_init(void) ...@@ -12,7 +12,8 @@ static __init int pci_arch_init(void)
type = pci_direct_probe(); type = pci_direct_probe();
#endif #endif
pci_mmcfg_early_init(); if (!(pci_probe & PCI_PROBE_NOEARLY))
pci_mmcfg_early_init();
#ifdef CONFIG_PCI_OLPC #ifdef CONFIG_PCI_OLPC
if (!pci_olpc_init()) if (!pci_olpc_init())
......
...@@ -533,7 +533,7 @@ static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, ...@@ -533,7 +533,7 @@ static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
{ {
struct pci_dev *bridge; struct pci_dev *bridge;
int pin = pci_get_interrupt_pin(dev, &bridge); int pin = pci_get_interrupt_pin(dev, &bridge);
return pcibios_set_irq_routing(bridge, pin, irq); return pcibios_set_irq_routing(bridge, pin - 1, irq);
} }
#endif #endif
...@@ -887,7 +887,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -887,7 +887,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
dev_dbg(&dev->dev, "no interrupt pin\n"); dev_dbg(&dev->dev, "no interrupt pin\n");
return 0; return 0;
} }
pin = pin - 1;
/* Find IRQ routing entry */ /* Find IRQ routing entry */
...@@ -897,17 +896,17 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -897,17 +896,17 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
info = pirq_get_info(dev); info = pirq_get_info(dev);
if (!info) { if (!info) {
dev_dbg(&dev->dev, "PCI INT %c not found in routing table\n", dev_dbg(&dev->dev, "PCI INT %c not found in routing table\n",
'A' + pin); 'A' + pin - 1);
return 0; return 0;
} }
pirq = info->irq[pin].link; pirq = info->irq[pin - 1].link;
mask = info->irq[pin].bitmap; mask = info->irq[pin - 1].bitmap;
if (!pirq) { if (!pirq) {
dev_dbg(&dev->dev, "PCI INT %c not routed\n", 'A' + pin); dev_dbg(&dev->dev, "PCI INT %c not routed\n", 'A' + pin - 1);
return 0; return 0;
} }
dev_dbg(&dev->dev, "PCI INT %c -> PIRQ %02x, mask %04x, excl %04x", dev_dbg(&dev->dev, "PCI INT %c -> PIRQ %02x, mask %04x, excl %04x",
'A' + pin, pirq, mask, pirq_table->exclusive_irqs); 'A' + pin - 1, pirq, mask, pirq_table->exclusive_irqs);
mask &= pcibios_irq_mask; mask &= pcibios_irq_mask;
/* Work around broken HP Pavilion Notebooks which assign USB to /* Work around broken HP Pavilion Notebooks which assign USB to
...@@ -949,7 +948,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -949,7 +948,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
newirq = i; newirq = i;
} }
} }
dev_dbg(&dev->dev, "PCI INT %c -> newirq %d", 'A' + pin, newirq); dev_dbg(&dev->dev, "PCI INT %c -> newirq %d", 'A' + pin - 1, newirq);
/* Check if it is hardcoded */ /* Check if it is hardcoded */
if ((pirq & 0xf0) == 0xf0) { if ((pirq & 0xf0) == 0xf0) {
...@@ -977,18 +976,18 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -977,18 +976,18 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
return 0; return 0;
} }
} }
dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin, irq); dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin - 1, irq);
/* Update IRQ for all devices with the same pirq value */ /* Update IRQ for all devices with the same pirq value */
while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
if (!pin) if (!pin)
continue; continue;
pin--;
info = pirq_get_info(dev2); info = pirq_get_info(dev2);
if (!info) if (!info)
continue; continue;
if (info->irq[pin].link == pirq) { if (info->irq[pin - 1].link == pirq) {
/* /*
* We refuse to override the dev->irq * We refuse to override the dev->irq
* information. Give a warning! * information. Give a warning!
...@@ -1042,6 +1041,9 @@ static void __init pcibios_fixup_irqs(void) ...@@ -1042,6 +1041,9 @@ static void __init pcibios_fixup_irqs(void)
dev = NULL; dev = NULL;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin)
continue;
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
/* /*
* Recalculate IRQ numbers if we use the I/O APIC. * Recalculate IRQ numbers if we use the I/O APIC.
...@@ -1049,15 +1051,11 @@ static void __init pcibios_fixup_irqs(void) ...@@ -1049,15 +1051,11 @@ static void __init pcibios_fixup_irqs(void)
if (io_apic_assign_pci_irqs) { if (io_apic_assign_pci_irqs) {
int irq; int irq;
if (!pin)
continue;
/* /*
* interrupt pins are numbered starting from 1 * interrupt pins are numbered starting from 1
*/ */
pin--;
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
PCI_SLOT(dev->devfn), pin); PCI_SLOT(dev->devfn), pin - 1);
/* /*
* Busses behind bridges are typically not listed in the * Busses behind bridges are typically not listed in the
* MP-table. In this case we have to look up the IRQ * MP-table. In this case we have to look up the IRQ
...@@ -1070,22 +1068,22 @@ static void __init pcibios_fixup_irqs(void) ...@@ -1070,22 +1068,22 @@ static void __init pcibios_fixup_irqs(void)
struct pci_dev *bridge = dev->bus->self; struct pci_dev *bridge = dev->bus->self;
int bus; int bus;
pin = (pin + PCI_SLOT(dev->devfn)) % 4; pin = pci_swizzle_interrupt_pin(dev, pin);
bus = bridge->bus->number; bus = bridge->bus->number;
irq = IO_APIC_get_PCI_irq_vector(bus, irq = IO_APIC_get_PCI_irq_vector(bus,
PCI_SLOT(bridge->devfn), pin); PCI_SLOT(bridge->devfn), pin - 1);
if (irq >= 0) if (irq >= 0)
dev_warn(&dev->dev, dev_warn(&dev->dev,
"using bridge %s INT %c to " "using bridge %s INT %c to "
"get IRQ %d\n", "get IRQ %d\n",
pci_name(bridge), pci_name(bridge),
'A' + pin, irq); 'A' + pin - 1, irq);
} }
if (irq >= 0) { if (irq >= 0) {
dev_info(&dev->dev, dev_info(&dev->dev,
"PCI->APIC IRQ transform: INT %c " "PCI->APIC IRQ transform: INT %c "
"-> IRQ %d\n", "-> IRQ %d\n",
'A' + pin, irq); 'A' + pin - 1, irq);
dev->irq = irq; dev->irq = irq;
} }
} }
...@@ -1093,7 +1091,7 @@ static void __init pcibios_fixup_irqs(void) ...@@ -1093,7 +1091,7 @@ static void __init pcibios_fixup_irqs(void)
/* /*
* Still no IRQ? Try to lookup one... * Still no IRQ? Try to lookup one...
*/ */
if (pin && !dev->irq) if (!dev->irq)
pcibios_lookup_irq(dev, 0); pcibios_lookup_irq(dev, 0);
} }
} }
...@@ -1220,12 +1218,10 @@ static int pirq_enable_irq(struct pci_dev *dev) ...@@ -1220,12 +1218,10 @@ static int pirq_enable_irq(struct pci_dev *dev)
if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
char *msg = ""; char *msg = "";
pin--; /* interrupt pins are numbered starting from 1 */
if (io_apic_assign_pci_irqs) { if (io_apic_assign_pci_irqs) {
int irq; int irq;
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin - 1);
/* /*
* Busses behind bridges are typically not listed in the MP-table. * Busses behind bridges are typically not listed in the MP-table.
* In this case we have to look up the IRQ based on the parent bus, * In this case we have to look up the IRQ based on the parent bus,
...@@ -1236,20 +1232,20 @@ static int pirq_enable_irq(struct pci_dev *dev) ...@@ -1236,20 +1232,20 @@ static int pirq_enable_irq(struct pci_dev *dev)
while (irq < 0 && dev->bus->parent) { /* go back to the bridge */ while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
struct pci_dev *bridge = dev->bus->self; struct pci_dev *bridge = dev->bus->self;
pin = (pin + PCI_SLOT(dev->devfn)) % 4; pin = pci_swizzle_interrupt_pin(dev, pin);
irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
PCI_SLOT(bridge->devfn), pin); PCI_SLOT(bridge->devfn), pin - 1);
if (irq >= 0) if (irq >= 0)
dev_warn(&dev->dev, "using bridge %s " dev_warn(&dev->dev, "using bridge %s "
"INT %c to get IRQ %d\n", "INT %c to get IRQ %d\n",
pci_name(bridge), 'A' + pin, pci_name(bridge), 'A' + pin - 1,
irq); irq);
dev = bridge; dev = bridge;
} }
dev = temp_dev; dev = temp_dev;
if (irq >= 0) { if (irq >= 0) {
dev_info(&dev->dev, "PCI->APIC IRQ transform: " dev_info(&dev->dev, "PCI->APIC IRQ transform: "
"INT %c -> IRQ %d\n", 'A' + pin, irq); "INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
dev->irq = irq; dev->irq = irq;
return 0; return 0;
} else } else
...@@ -1268,7 +1264,7 @@ static int pirq_enable_irq(struct pci_dev *dev) ...@@ -1268,7 +1264,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
return 0; return 0;
dev_warn(&dev->dev, "can't find IRQ for PCI INT %c%s\n", dev_warn(&dev->dev, "can't find IRQ for PCI INT %c%s\n",
'A' + pin, msg); 'A' + pin - 1, msg);
} }
return 0; return 0;
} }
...@@ -24,24 +24,6 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { } ...@@ -24,24 +24,6 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { }
unsigned int pci_bus0, pci_bus1; unsigned int pci_bus0, pci_bus1;
static inline u8 bridge_swizzle(u8 pin, u8 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
static u8 __init visws_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (dev->bus->self) { /* Move up the chain of bridges. */
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
dev = dev->bus->self;
}
*pinp = pin;
return PCI_SLOT(dev->devfn);
}
static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin) static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{ {
int irq, bus = dev->bus->number; int irq, bus = dev->bus->number;
...@@ -106,7 +88,7 @@ int __init pci_visws_init(void) ...@@ -106,7 +88,7 @@ int __init pci_visws_init(void)
raw_pci_ops = &pci_direct_conf1; raw_pci_ops = &pci_direct_conf1;
pci_scan_bus_with_sysdata(pci_bus0); pci_scan_bus_with_sysdata(pci_bus0);
pci_scan_bus_with_sysdata(pci_bus1); pci_scan_bus_with_sysdata(pci_bus1);
pci_fixup_irqs(visws_swizzle, visws_map_irq); pci_fixup_irqs(pci_common_swizzle, visws_map_irq);
pcibios_resource_survey(); pcibios_resource_survey();
return 0; return 0;
} }
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
...@@ -193,6 +194,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -193,6 +194,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
unsigned long long value = 0; unsigned long long value = 0;
acpi_handle handle = NULL; acpi_handle handle = NULL;
struct acpi_device *child; struct acpi_device *child;
u32 flags, base_flags;
if (!device) if (!device)
...@@ -210,6 +212,13 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -210,6 +212,13 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
device->ops.bind = acpi_pci_bind; device->ops.bind = acpi_pci_bind;
/*
* All supported architectures that use ACPI have support for
* PCI domains, so we indicate this in _OSC support capabilities.
*/
flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
pci_acpi_osc_support(device->handle, flags);
/* /*
* Segment * Segment
* ------- * -------
...@@ -335,6 +344,17 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -335,6 +344,17 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
list_for_each_entry(child, &device->children, node) list_for_each_entry(child, &device->children, node)
acpi_pci_bridge_scan(child); acpi_pci_bridge_scan(child);
/* Indicate support for various _OSC capabilities. */
if (pci_ext_cfg_avail(root->bus->self))
flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
if (pcie_aspm_enabled())
flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
if (pci_msi_enabled())
flags |= OSC_MSI_SUPPORT;
if (flags != base_flags)
pci_acpi_osc_support(device->handle, flags);
end: end:
if (result) { if (result) {
if (!list_empty(&root->node)) if (!list_empty(&root->node))
......
...@@ -4807,7 +4807,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, ...@@ -4807,7 +4807,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
} }
} }
err = pci_request_selected_regions(pdev, err = pci_request_selected_regions_exclusive(pdev,
pci_select_bars(pdev, IORESOURCE_MEM), pci_select_bars(pdev, IORESOURCE_MEM),
e1000e_driver_name); e1000e_driver_name);
if (err) if (err)
......
...@@ -1403,9 +1403,9 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) ...@@ -1403,9 +1403,9 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
} }
/* Disable both devices */ /* Disable both devices */
pci_disable_device(efx->pci_dev); pci_clear_master(efx->pci_dev);
if (FALCON_IS_DUAL_FUNC(efx)) if (FALCON_IS_DUAL_FUNC(efx))
pci_disable_device(nic_data->pci_dev2); pci_clear_master(nic_data->pci_dev2);
falcon_disable_interrupts(efx); falcon_disable_interrupts(efx);
if (++n_int_errors < FALCON_MAX_INT_ERRORS) { if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
......
...@@ -547,7 +547,7 @@ dino_card_fixup(struct pci_dev *dev) ...@@ -547,7 +547,7 @@ dino_card_fixup(struct pci_dev *dev)
** The additional "-1" adjusts for skewing the IRQ<->slot. ** The additional "-1" adjusts for skewing the IRQ<->slot.
*/ */
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin); dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ; dev->irq = pci_swizzle_interrupt_pin(dev, irq_pin) - 1;
/* Shouldn't really need to do this but it's in case someone tries /* Shouldn't really need to do this but it's in case someone tries
** to bypass PCI services and look at the card themselves. ** to bypass PCI services and look at the card themselves.
...@@ -672,7 +672,7 @@ dino_fixup_bus(struct pci_bus *bus) ...@@ -672,7 +672,7 @@ dino_fixup_bus(struct pci_bus *bus)
dino_cfg_read(dev->bus, dev->devfn, dino_cfg_read(dev->bus, dev->devfn,
PCI_INTERRUPT_PIN, 1, &irq_pin); PCI_INTERRUPT_PIN, 1, &irq_pin);
irq_pin = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ; irq_pin = pci_swizzle_interrupt_pin(dev, irq_pin) - 1;
printk(KERN_WARNING "Device %s has undefined IRQ, " printk(KERN_WARNING "Device %s has undefined IRQ, "
"setting to %d\n", pci_name(dev), irq_pin); "setting to %d\n", pci_name(dev), irq_pin);
dino_cfg_write(dev->bus, dev->devfn, dino_cfg_write(dev->bus, dev->devfn,
......
...@@ -519,8 +519,7 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev) ...@@ -519,8 +519,7 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
** **
** Advantage is it's really easy to implement. ** Advantage is it's really easy to implement.
*/ */
intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4; intr_pin = pci_swizzle_interrupt_pin(pcidev, intr_pin);
intr_pin++; /* convert back to INTA-D (1-4) */
#endif /* PCI_BRIDGE_FUNCS */ #endif /* PCI_BRIDGE_FUNCS */
/* /*
......
...@@ -42,6 +42,15 @@ config PCI_DEBUG ...@@ -42,6 +42,15 @@ config PCI_DEBUG
When in doubt, say N. When in doubt, say N.
config PCI_STUB
tristate "PCI Stub driver"
depends on PCI
help
Say Y or M here if you want be able to reserve a PCI device
when it is going to be assigned to a guest operating system.
When in doubt, say N.
config HT_IRQ config HT_IRQ
bool "Interrupts on hypertransport devices" bool "Interrupts on hypertransport devices"
default y default y
......
...@@ -53,6 +53,8 @@ obj-$(CONFIG_HOTPLUG) += setup-bus.o ...@@ -53,6 +53,8 @@ obj-$(CONFIG_HOTPLUG) += setup-bus.o
obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_SYSCALL) += syscall.o
obj-$(CONFIG_PCI_STUB) += pci-stub.o
ifeq ($(CONFIG_PCI_DEBUG),y) ifeq ($(CONFIG_PCI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
endif endif
...@@ -66,6 +66,39 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); ...@@ -66,6 +66,39 @@ EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword); EXPORT_SYMBOL(pci_bus_write_config_dword);
/**
* pci_read_vpd - Read one entry from Vital Product Data
* @dev: pci device struct
* @pos: offset in vpd space
* @count: number of bytes to read
* @buf: pointer to where to store result
*
*/
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
{
if (!dev->vpd || !dev->vpd->ops)
return -ENODEV;
return dev->vpd->ops->read(dev, pos, count, buf);
}
EXPORT_SYMBOL(pci_read_vpd);
/**
* pci_write_vpd - Write entry to Vital Product Data
* @dev: pci device struct
* @pos: offset in vpd space
* @count: number of bytes to read
* @val: value to write
*
*/
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
{
if (!dev->vpd || !dev->vpd->ops)
return -ENODEV;
return dev->vpd->ops->write(dev, pos, count, buf);
}
EXPORT_SYMBOL(pci_write_vpd);
/* /*
* The following routines are to prevent the user from accessing PCI config * The following routines are to prevent the user from accessing PCI config
* space when it's unsafe to do so. Some devices require this during BIST and * space when it's unsafe to do so. Some devices require this during BIST and
...@@ -133,125 +166,145 @@ PCI_USER_WRITE_CONFIG(dword, u32) ...@@ -133,125 +166,145 @@ PCI_USER_WRITE_CONFIG(dword, u32)
struct pci_vpd_pci22 { struct pci_vpd_pci22 {
struct pci_vpd base; struct pci_vpd base;
spinlock_t lock; /* controls access to hardware and the flags */ struct mutex lock;
u8 cap; u16 flag;
bool busy; bool busy;
bool flag; /* value of F bit to wait for */ u8 cap;
}; };
/* Wait for last operation to complete */ /*
* Wait for last operation to complete.
* This code has to spin since there is no other notification from the PCI
* hardware. Since the VPD is often implemented by serial attachment to an
* EEPROM, it may take many milliseconds to complete.
*/
static int pci_vpd_pci22_wait(struct pci_dev *dev) static int pci_vpd_pci22_wait(struct pci_dev *dev)
{ {
struct pci_vpd_pci22 *vpd = struct pci_vpd_pci22 *vpd =
container_of(dev->vpd, struct pci_vpd_pci22, base); container_of(dev->vpd, struct pci_vpd_pci22, base);
u16 flag, status; unsigned long timeout = jiffies + HZ/20 + 2;
int wait; u16 status;
int ret; int ret;
if (!vpd->busy) if (!vpd->busy)
return 0; return 0;
flag = vpd->flag ? PCI_VPD_ADDR_F : 0;
wait = vpd->flag ? 10 : 1000; /* read: 100 us; write: 10 ms */
for (;;) { for (;;) {
ret = pci_user_read_config_word(dev, ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
vpd->cap + PCI_VPD_ADDR,
&status); &status);
if (ret < 0) if (ret)
return ret; return ret;
if ((status & PCI_VPD_ADDR_F) == flag) {
if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
vpd->busy = false; vpd->busy = false;
return 0; return 0;
} }
if (wait-- == 0)
if (time_after(jiffies, timeout))
return -ETIMEDOUT; return -ETIMEDOUT;
udelay(10); if (fatal_signal_pending(current))
return -EINTR;
if (!cond_resched())
udelay(10);
} }
} }
static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
char *buf) void *arg)
{ {
struct pci_vpd_pci22 *vpd = struct pci_vpd_pci22 *vpd =
container_of(dev->vpd, struct pci_vpd_pci22, base); container_of(dev->vpd, struct pci_vpd_pci22, base);
u32 val;
int ret; int ret;
int begin, end, i; loff_t end = pos + count;
u8 *buf = arg;
if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
return -EINVAL; return -EINVAL;
if (size == 0)
return 0;
spin_lock_irq(&vpd->lock); if (mutex_lock_killable(&vpd->lock))
ret = pci_vpd_pci22_wait(dev); return -EINTR;
if (ret < 0)
goto out;
ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
pos & ~3);
if (ret < 0)
goto out;
vpd->busy = true;
vpd->flag = 1;
ret = pci_vpd_pci22_wait(dev); ret = pci_vpd_pci22_wait(dev);
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA,
&val); while (pos < end) {
out: u32 val;
spin_unlock_irq(&vpd->lock); unsigned int i, skip;
if (ret < 0)
return ret; ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
pos & ~3);
/* Convert to bytes */ if (ret < 0)
begin = pos & 3; break;
end = min(4, begin + size); vpd->busy = true;
for (i = 0; i < end; ++i) { vpd->flag = PCI_VPD_ADDR_F;
if (i >= begin) ret = pci_vpd_pci22_wait(dev);
*buf++ = val; if (ret < 0)
val >>= 8; break;
ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val);
if (ret < 0)
break;
skip = pos & 3;
for (i = 0; i < sizeof(u32); i++) {
if (i >= skip) {
*buf++ = val;
if (++pos == end)
break;
}
val >>= 8;
}
} }
return end - begin; out:
mutex_unlock(&vpd->lock);
return ret ? ret : count;
} }
static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count,
const char *buf) const void *arg)
{ {
struct pci_vpd_pci22 *vpd = struct pci_vpd_pci22 *vpd =
container_of(dev->vpd, struct pci_vpd_pci22, base); container_of(dev->vpd, struct pci_vpd_pci22, base);
u32 val; const u8 *buf = arg;
int ret; loff_t end = pos + count;
int ret = 0;
if (pos < 0 || pos > vpd->base.len || pos & 3 || if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
size > vpd->base.len - pos || size < 4)
return -EINVAL; return -EINVAL;
val = (u8) *buf++; if (mutex_lock_killable(&vpd->lock))
val |= ((u8) *buf++) << 8; return -EINTR;
val |= ((u8) *buf++) << 16;
val |= ((u32)(u8) *buf++) << 24;
spin_lock_irq(&vpd->lock);
ret = pci_vpd_pci22_wait(dev); ret = pci_vpd_pci22_wait(dev);
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA,
val);
if (ret < 0)
goto out;
ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
pos | PCI_VPD_ADDR_F);
if (ret < 0)
goto out;
vpd->busy = true;
vpd->flag = 0;
ret = pci_vpd_pci22_wait(dev);
out:
spin_unlock_irq(&vpd->lock);
if (ret < 0)
return ret;
return 4; while (pos < end) {
u32 val;
val = *buf++;
val |= *buf++ << 8;
val |= *buf++ << 16;
val |= *buf++ << 24;
ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val);
if (ret < 0)
break;
ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
pos | PCI_VPD_ADDR_F);
if (ret < 0)
break;
vpd->busy = true;
vpd->flag = 0;
ret = pci_vpd_pci22_wait(dev);
pos += sizeof(u32);
}
out:
mutex_unlock(&vpd->lock);
return ret ? ret : count;
} }
static void pci_vpd_pci22_release(struct pci_dev *dev) static void pci_vpd_pci22_release(struct pci_dev *dev)
...@@ -259,7 +312,7 @@ static void pci_vpd_pci22_release(struct pci_dev *dev) ...@@ -259,7 +312,7 @@ static void pci_vpd_pci22_release(struct pci_dev *dev)
kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
} }
static struct pci_vpd_ops pci_vpd_pci22_ops = { static const struct pci_vpd_ops pci_vpd_pci22_ops = {
.read = pci_vpd_pci22_read, .read = pci_vpd_pci22_read,
.write = pci_vpd_pci22_write, .write = pci_vpd_pci22_write,
.release = pci_vpd_pci22_release, .release = pci_vpd_pci22_release,
...@@ -279,13 +332,36 @@ int pci_vpd_pci22_init(struct pci_dev *dev) ...@@ -279,13 +332,36 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
vpd->base.len = PCI_VPD_PCI22_SIZE; vpd->base.len = PCI_VPD_PCI22_SIZE;
vpd->base.ops = &pci_vpd_pci22_ops; vpd->base.ops = &pci_vpd_pci22_ops;
spin_lock_init(&vpd->lock); mutex_init(&vpd->lock);
vpd->cap = cap; vpd->cap = cap;
vpd->busy = false; vpd->busy = false;
dev->vpd = &vpd->base; dev->vpd = &vpd->base;
return 0; return 0;
} }
/**
* pci_vpd_truncate - Set available Vital Product Data size
* @dev: pci device struct
* @size: available memory in bytes
*
* Adjust size of available VPD area.
*/
int pci_vpd_truncate(struct pci_dev *dev, size_t size)
{
if (!dev->vpd)
return -EINVAL;
/* limited by the access method */
if (size > dev->vpd->len)
return -EINVAL;
dev->vpd->len = size;
dev->vpd->attr->size = size;
return 0;
}
EXPORT_SYMBOL(pci_vpd_truncate);
/** /**
* pci_block_user_cfg_access - Block userspace PCI config reads/writes * pci_block_user_cfg_access - Block userspace PCI config reads/writes
* @dev: pci device struct * @dev: pci device struct
......
...@@ -71,7 +71,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, ...@@ -71,7 +71,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
} }
/** /**
* add a single device * pci_bus_add_device - add a single device
* @dev: device to add * @dev: device to add
* *
* This adds a single pci device to the global * This adds a single pci device to the global
...@@ -90,6 +90,37 @@ int pci_bus_add_device(struct pci_dev *dev) ...@@ -90,6 +90,37 @@ int pci_bus_add_device(struct pci_dev *dev)
return 0; return 0;
} }
/**
* pci_bus_add_child - add a child bus
* @bus: bus to add
*
* This adds sysfs entries for a single bus
*/
int pci_bus_add_child(struct pci_bus *bus)
{
int retval;
if (bus->bridge)
bus->dev.parent = bus->bridge;
retval = device_register(&bus->dev);
if (retval)
return retval;
bus->is_added = 1;
retval = device_create_file(&bus->dev, &dev_attr_cpuaffinity);
if (retval)
return retval;
retval = device_create_file(&bus->dev, &dev_attr_cpulistaffinity);
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(bus);
return retval;
}
/** /**
* pci_bus_add_devices - insert newly discovered PCI devices * pci_bus_add_devices - insert newly discovered PCI devices
* @bus: bus to check for new devices * @bus: bus to check for new devices
...@@ -105,7 +136,7 @@ int pci_bus_add_device(struct pci_dev *dev) ...@@ -105,7 +136,7 @@ int pci_bus_add_device(struct pci_dev *dev)
void pci_bus_add_devices(struct pci_bus *bus) void pci_bus_add_devices(struct pci_bus *bus)
{ {
struct pci_dev *dev; struct pci_dev *dev;
struct pci_bus *child_bus; struct pci_bus *child;
int retval; int retval;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
...@@ -120,45 +151,29 @@ void pci_bus_add_devices(struct pci_bus *bus) ...@@ -120,45 +151,29 @@ void pci_bus_add_devices(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
BUG_ON(!dev->is_added); BUG_ON(!dev->is_added);
child = dev->subordinate;
/* /*
* If there is an unattached subordinate bus, attach * If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices. * it and then scan for unattached PCI devices.
*/ */
if (dev->subordinate) { if (!child)
if (list_empty(&dev->subordinate->node)) { continue;
down_write(&pci_bus_sem); if (list_empty(&child->node)) {
list_add_tail(&dev->subordinate->node, down_write(&pci_bus_sem);
&dev->bus->children); list_add_tail(&child->node, &dev->bus->children);
up_write(&pci_bus_sem); up_write(&pci_bus_sem);
}
pci_bus_add_devices(dev->subordinate);
/* register the bus with sysfs as the parent is now
* properly registered. */
child_bus = dev->subordinate;
if (child_bus->is_added)
continue;
child_bus->dev.parent = child_bus->bridge;
retval = device_register(&child_bus->dev);
if (retval)
dev_err(&dev->dev, "Error registering pci_bus,"
" continuing...\n");
else {
child_bus->is_added = 1;
retval = device_create_file(&child_bus->dev,
&dev_attr_cpuaffinity);
}
if (retval)
dev_err(&dev->dev, "Error creating cpuaffinity"
" file, continuing...\n");
retval = device_create_file(&child_bus->dev,
&dev_attr_cpulistaffinity);
if (retval)
dev_err(&dev->dev,
"Error creating cpulistaffinity"
" file, continuing...\n");
} }
pci_bus_add_devices(child);
/*
* register the bus with sysfs as the parent is now
* properly registered.
*/
if (child->is_added)
continue;
retval = pci_bus_add_child(child);
if (retval)
dev_err(&dev->dev, "Error adding bus, continuing\n");
} }
} }
......
...@@ -55,6 +55,9 @@ pciehp-objs := pciehp_core.o \ ...@@ -55,6 +55,9 @@ pciehp-objs := pciehp_core.o \
pciehp_ctrl.o \ pciehp_ctrl.o \
pciehp_pci.o \ pciehp_pci.o \
pciehp_hpc.o pciehp_hpc.o
ifdef CONFIG_ACPI
pciehp-objs += pciehp_acpi.o
endif
shpchp-objs := shpchp_core.o \ shpchp-objs := shpchp_core.o \
shpchp_ctrl.o \ shpchp_ctrl.o \
......
...@@ -501,5 +501,74 @@ int acpi_root_bridge(acpi_handle handle) ...@@ -501,5 +501,74 @@ int acpi_root_bridge(acpi_handle handle)
} }
EXPORT_SYMBOL_GPL(acpi_root_bridge); EXPORT_SYMBOL_GPL(acpi_root_bridge);
static int is_ejectable(acpi_handle handle)
{
acpi_status status;
acpi_handle tmp;
unsigned long long removable;
status = acpi_get_handle(handle, "_ADR", &tmp);
if (ACPI_FAILURE(status))
return 0;
status = acpi_get_handle(handle, "_EJ0", &tmp);
if (ACPI_SUCCESS(status))
return 1;
status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable);
if (ACPI_SUCCESS(status) && removable)
return 1;
return 0;
}
/**
* acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot
* @pbus: the PCI bus of the PCI slot corresponding to 'handle'
* @handle: ACPI handle to check
*
* Return 1 if handle is ejectable PCI slot, 0 otherwise.
*/
int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
{
acpi_handle bridge_handle, parent_handle;
if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus)))
return 0;
if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))))
return 0;
if (bridge_handle != parent_handle)
return 0;
return is_ejectable(handle);
}
EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable);
static acpi_status
check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int *found = (int *)context;
if (is_ejectable(handle)) {
*found = 1;
return AE_CTRL_TERMINATE;
}
return AE_OK;
}
/**
* acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots
* @pbus - PCI bus to scan
*
* Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise.
*/
int acpi_pci_detect_ejectable(struct pci_bus *pbus)
{
acpi_handle handle;
int found = 0;
if (!(handle = acpi_pci_get_bridge_handle(pbus)))
return 0;
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
check_hotplug, (void *)&found, NULL);
return found;
}
EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable);
module_param(debug_acpi, bool, 0644); module_param(debug_acpi, bool, 0644);
MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
do { \ do { \
if (acpiphp_debug) \ if (acpiphp_debug) \
printk(KERN_DEBUG "%s: " format, \ printk(KERN_DEBUG "%s: " format, \
MY_NAME , ## arg); \ MY_NAME , ## arg); \
} while (0) } while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) #define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci_hotplug.h> #include <linux/pci_hotplug.h>
#include <linux/pci-acpi.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include "../pci.h" #include "../pci.h"
...@@ -62,61 +63,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus); ...@@ -62,61 +63,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
/*
* initialization & terminatation routines
*/
/**
* is_ejectable - determine if a slot is ejectable
* @handle: handle to acpi namespace
*
* Ejectable slot should satisfy at least these conditions:
*
* 1. has _ADR method
* 2. has _EJ0 method
*
* optionally
*
* 1. has _STA method
* 2. has _PS0 method
* 3. has _PS3 method
* 4. ..
*/
static int is_ejectable(acpi_handle handle)
{
acpi_status status;
acpi_handle tmp;
status = acpi_get_handle(handle, "_ADR", &tmp);
if (ACPI_FAILURE(status)) {
return 0;
}
status = acpi_get_handle(handle, "_EJ0", &tmp);
if (ACPI_FAILURE(status)) {
return 0;
}
return 1;
}
/* callback routine to check for the existence of ejectable slots */
static acpi_status
is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int *count = (int *)context;
if (is_ejectable(handle)) {
(*count)++;
/* only one ejectable slot is enough */
return AE_CTRL_TERMINATE;
} else {
return AE_OK;
}
}
/* callback routine to check for the existence of a pci dock device */ /* callback routine to check for the existence of a pci dock device */
static acpi_status static acpi_status
is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
...@@ -131,9 +77,6 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -131,9 +77,6 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
} }
} }
/* /*
* the _DCK method can do funny things... and sometimes not * the _DCK method can do funny things... and sometimes not
* hah-hah funny. * hah-hah funny.
...@@ -160,9 +103,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, ...@@ -160,9 +103,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
if (((buses >> 8) & 0xff) != bus->secondary) { if (((buses >> 8) & 0xff) != bus->secondary) {
buses = (buses & 0xff000000) buses = (buses & 0xff000000)
| ((unsigned int)(bus->primary) << 0) | ((unsigned int)(bus->primary) << 0)
| ((unsigned int)(bus->secondary) << 8) | ((unsigned int)(bus->secondary) << 8)
| ((unsigned int)(bus->subordinate) << 16); | ((unsigned int)(bus->subordinate) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
} }
return NOTIFY_OK; return NOTIFY_OK;
...@@ -184,17 +127,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -184,17 +127,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_status status = AE_OK; acpi_status status = AE_OK;
unsigned long long adr, sun; unsigned long long adr, sun;
int device, function, retval; int device, function, retval;
struct pci_bus *pbus = bridge->pci_bus;
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
if (ACPI_FAILURE(status))
return AE_OK;
status = acpi_get_handle(handle, "_EJ0", &tmp);
if (ACPI_FAILURE(status) && !(is_dock_device(handle)))
return AE_OK; return AE_OK;
acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
device = (adr >> 16) & 0xffff; device = (adr >> 16) & 0xffff;
function = adr & 0xffff; function = adr & 0xffff;
...@@ -205,7 +143,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -205,7 +143,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
INIT_LIST_HEAD(&newfunc->sibling); INIT_LIST_HEAD(&newfunc->sibling);
newfunc->handle = handle; newfunc->handle = handle;
newfunc->function = function; newfunc->function = function;
if (ACPI_SUCCESS(status))
if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
newfunc->flags = FUNC_HAS_EJ0; newfunc->flags = FUNC_HAS_EJ0;
if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
...@@ -256,8 +195,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -256,8 +195,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
bridge->nr_slots++; bridge->nr_slots++;
dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
slot->sun, pci_domain_nr(bridge->pci_bus), slot->sun, pci_domain_nr(pbus), pbus->number, device);
bridge->pci_bus->number, slot->device);
retval = acpiphp_register_hotplug_slot(slot); retval = acpiphp_register_hotplug_slot(slot);
if (retval) { if (retval) {
if (retval == -EBUSY) if (retval == -EBUSY)
...@@ -274,8 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -274,8 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
list_add_tail(&newfunc->sibling, &slot->funcs); list_add_tail(&newfunc->sibling, &slot->funcs);
/* associate corresponding pci_dev */ /* associate corresponding pci_dev */
newfunc->pci_dev = pci_get_slot(bridge->pci_bus, newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function));
PCI_DEVFN(device, function));
if (newfunc->pci_dev) { if (newfunc->pci_dev) {
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
} }
...@@ -324,27 +261,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -324,27 +261,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
/* see if it's worth looking at this bridge */ /* see if it's worth looking at this bridge */
static int detect_ejectable_slots(acpi_handle *bridge_handle) static int detect_ejectable_slots(struct pci_bus *pbus)
{ {
acpi_status status; int found = acpi_pci_detect_ejectable(pbus);
int count; if (!found) {
acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus);
count = 0; acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
is_pci_dock_device, (void *)&found, NULL);
/* only check slots defined directly below bridge object */ }
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, return found;
is_ejectable_slot, (void *)&count, NULL);
/*
* we also need to add this bridge if there is a dock bridge or
* other pci device on a dock station (removable)
*/
if (!count)
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
(u32)1, is_pci_dock_device, (void *)&count,
NULL);
return count;
} }
...@@ -554,7 +479,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -554,7 +479,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
goto out; goto out;
/* check if this bridge has ejectable slots */ /* check if this bridge has ejectable slots */
if ((detect_ejectable_slots(handle) > 0)) { if ((detect_ejectable_slots(dev->subordinate) > 0)) {
dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
add_p2p_bridge(handle, dev); add_p2p_bridge(handle, dev);
} }
...@@ -615,7 +540,7 @@ static int add_bridge(acpi_handle handle) ...@@ -615,7 +540,7 @@ static int add_bridge(acpi_handle handle)
} }
/* check if this bridge has ejectable slots */ /* check if this bridge has ejectable slots */
if (detect_ejectable_slots(handle) > 0) { if (detect_ejectable_slots(pci_bus) > 0) {
dbg("found PCI host-bus bridge with hot-pluggable slots\n"); dbg("found PCI host-bus bridge with hot-pluggable slots\n");
add_host_bridge(handle, pci_bus); add_host_bridge(handle, pci_bus);
} }
......
...@@ -271,7 +271,7 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context) ...@@ -271,7 +271,7 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
dbg("%s: generationg bus event\n", __func__); dbg("%s: generationg bus event\n", __func__);
acpi_bus_generate_proc_event(note->device, note->event, detail); acpi_bus_generate_proc_event(note->device, note->event, detail);
acpi_bus_generate_netlink_event(note->device->pnp.device_class, acpi_bus_generate_netlink_event(note->device->pnp.device_class,
note->device->dev.bus_id, dev_name(&note->device->dev),
note->event, detail); note->event, detail);
} else } else
note->event = event; note->event = event;
......
...@@ -1954,7 +1954,7 @@ void cpqhp_pushbutton_thread(unsigned long slot) ...@@ -1954,7 +1954,7 @@ void cpqhp_pushbutton_thread(unsigned long slot)
return ; return ;
} }
if (func != NULL && ctrl != NULL) { if (ctrl != NULL) {
if (cpqhp_process_SI(ctrl, func) != 0) { if (cpqhp_process_SI(ctrl, func) != 0) {
amber_LED_on(ctrl, hp_slot); amber_LED_on(ctrl, hp_slot);
green_LED_off(ctrl, hp_slot); green_LED_off(ctrl, hp_slot);
...@@ -2604,7 +2604,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func ...@@ -2604,7 +2604,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
for (cloop = 0; cloop < 4; cloop++) { for (cloop = 0; cloop < 4; cloop++) {
if (irqs.valid_INT & (0x01 << cloop)) { if (irqs.valid_INT & (0x01 << cloop)) {
rc = cpqhp_set_irq(func->bus, func->device, rc = cpqhp_set_irq(func->bus, func->device,
0x0A + cloop, irqs.interrupt[cloop]); cloop + 1, irqs.interrupt[cloop]);
if (rc) if (rc)
goto free_and_out; goto free_and_out;
} }
...@@ -2945,7 +2945,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func ...@@ -2945,7 +2945,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
} }
if (!behind_bridge) { if (!behind_bridge) {
rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); rc = cpqhp_set_irq(func->bus, func->device, temp_byte, IRQ);
if (rc) if (rc)
return 1; return 1;
} else { } else {
......
...@@ -171,7 +171,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) ...@@ -171,7 +171,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
fakebus->number = bus_num; fakebus->number = bus_num;
dbg("%s: dev %d, bus %d, pin %d, num %d\n", dbg("%s: dev %d, bus %d, pin %d, num %d\n",
__func__, dev_num, bus_num, int_pin, irq_num); __func__, dev_num, bus_num, int_pin, irq_num);
rc = pcibios_set_irq_routing(fakedev, int_pin - 0x0a, irq_num); rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num);
kfree(fakedev); kfree(fakedev);
kfree(fakebus); kfree(fakebus);
dbg("%s: rc %d\n", __func__, rc); dbg("%s: rc %d\n", __func__, rc);
......
...@@ -324,6 +324,7 @@ static int disable_slot(struct hotplug_slot *slot) ...@@ -324,6 +324,7 @@ static int disable_slot(struct hotplug_slot *slot)
if (test_and_set_bit(0, &dslot->removed)) { if (test_and_set_bit(0, &dslot->removed)) {
dbg("Slot already scheduled for removal\n"); dbg("Slot already scheduled for removal\n");
pci_dev_put(dev);
return -ENODEV; return -ENODEV;
} }
......
...@@ -220,11 +220,23 @@ struct hpc_ops { ...@@ -220,11 +220,23 @@ struct hpc_ops {
#include <acpi/actypes.h> #include <acpi/actypes.h>
#include <linux/pci-acpi.h> #include <linux/pci-acpi.h>
extern void __init pciehp_acpi_slot_detection_init(void);
extern int pciehp_acpi_slot_detection_check(struct pci_dev *dev);
static inline void pciehp_firmware_init(void)
{
pciehp_acpi_slot_detection_init();
}
static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
{ {
int retval;
u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
return acpi_get_hp_hw_control_from_firmware(dev, flags); retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
if (retval)
return retval;
return pciehp_acpi_slot_detection_check(dev);
} }
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
...@@ -235,6 +247,7 @@ static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, ...@@ -235,6 +247,7 @@ static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
return 0; return 0;
} }
#else #else
#define pciehp_firmware_init() do {} while (0)
#define pciehp_get_hp_hw_control_from_firmware(dev) 0 #define pciehp_get_hp_hw_control_from_firmware(dev) 0
#define pciehp_get_hp_params_from_firmware(dev, hpp) (-ENODEV) #define pciehp_get_hp_params_from_firmware(dev, hpp) (-ENODEV)
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
......
/*
* ACPI related functions for PCI Express Hot Plug driver.
*
* Copyright (C) 2008 Kenji Kaneshige
* Copyright (C) 2008 Fujitsu Limited.
*
* All rights reserved.
*
* 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; either version 2 of the License, or (at
* your option) any later version.
*
* 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, GOOD TITLE or
* NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include "pciehp.h"
#define PCIEHP_DETECT_PCIE (0)
#define PCIEHP_DETECT_ACPI (1)
#define PCIEHP_DETECT_AUTO (2)
#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO
static int slot_detection_mode;
static char *pciehp_detect_mode;
module_param(pciehp_detect_mode, charp, 0444);
MODULE_PARM_DESC(pciehp_detect_mode,
"Slot detection mode: pcie, acpi, auto\n"
" pcie - Use PCIe based slot detection\n"
" acpi - Use ACPI for slot detection\n"
" auto(default) - Auto select mode. Use acpi option if duplicate\n"
" slot ids are found. Otherwise, use pcie option\n");
int pciehp_acpi_slot_detection_check(struct pci_dev *dev)
{
if (slot_detection_mode != PCIEHP_DETECT_ACPI)
return 0;
if (acpi_pci_detect_ejectable(dev->subordinate))
return 0;
return -ENODEV;
}
static int __init parse_detect_mode(void)
{
if (!pciehp_detect_mode)
return PCIEHP_DETECT_DEFAULT;
if (!strcmp(pciehp_detect_mode, "pcie"))
return PCIEHP_DETECT_PCIE;
if (!strcmp(pciehp_detect_mode, "acpi"))
return PCIEHP_DETECT_ACPI;
if (!strcmp(pciehp_detect_mode, "auto"))
return PCIEHP_DETECT_AUTO;
warn("bad specifier '%s' for pciehp_detect_mode. Use default\n",
pciehp_detect_mode);
return PCIEHP_DETECT_DEFAULT;
}
static struct pcie_port_service_id __initdata port_pci_ids[] = {
{
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.port_type = PCIE_ANY_PORT,
.service_type = PCIE_PORT_SERVICE_HP,
.driver_data = 0,
}, { /* end: all zeroes */ }
};
static int __initdata dup_slot_id;
static int __initdata acpi_slot_detected;
static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots);
/* Dummy driver for dumplicate name detection */
static int __init dummy_probe(struct pcie_device *dev,
const struct pcie_port_service_id *id)
{
int pos;
u32 slot_cap;
struct slot *slot, *tmp;
struct pci_dev *pdev = dev->port;
struct pci_bus *pbus = pdev->subordinate;
if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL)))
return -ENOMEM;
/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
if (pciehp_get_hp_hw_control_from_firmware(pdev))
return -ENODEV;
if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP)))
return -ENODEV;
pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
slot->number = slot_cap >> 19;
list_for_each_entry(tmp, &dummy_slots, slot_list) {
if (tmp->number == slot->number)
dup_slot_id++;
}
list_add_tail(&slot->slot_list, &dummy_slots);
if (!acpi_slot_detected && acpi_pci_detect_ejectable(pbus))
acpi_slot_detected = 1;
return -ENODEV; /* dummy driver always returns error */
}
static struct pcie_port_service_driver __initdata dummy_driver = {
.name = "pciehp_dummy",
.id_table = port_pci_ids,
.probe = dummy_probe,
};
static int __init select_detection_mode(void)
{
struct slot *slot, *tmp;
pcie_port_service_register(&dummy_driver);
pcie_port_service_unregister(&dummy_driver);
list_for_each_entry_safe(slot, tmp, &dummy_slots, slot_list) {
list_del(&slot->slot_list);
kfree(slot);
}
if (acpi_slot_detected && dup_slot_id)
return PCIEHP_DETECT_ACPI;
return PCIEHP_DETECT_PCIE;
}
void __init pciehp_acpi_slot_detection_init(void)
{
slot_detection_mode = parse_detect_mode();
if (slot_detection_mode != PCIEHP_DETECT_AUTO)
goto out;
slot_detection_mode = select_detection_mode();
out:
if (slot_detection_mode == PCIEHP_DETECT_ACPI)
info("Using ACPI for slot detection.\n");
}
...@@ -522,6 +522,7 @@ static int __init pcied_init(void) ...@@ -522,6 +522,7 @@ static int __init pcied_init(void)
{ {
int retval = 0; int retval = 0;
pciehp_firmware_init();
retval = pcie_port_service_register(&hpdriver_portdrv); retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval); dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
......
...@@ -178,15 +178,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) ...@@ -178,15 +178,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
"Issue of Slot Power Off command failed\n"); "Issue of Slot Power Off command failed\n");
return; return;
} }
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
} }
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
if (PWR_LED(ctrl)) if (PWR_LED(ctrl))
pslot->hpc_ops->green_led_off(pslot); pslot->hpc_ops->green_led_off(pslot);
...@@ -286,15 +285,14 @@ static int remove_board(struct slot *p_slot) ...@@ -286,15 +285,14 @@ static int remove_board(struct slot *p_slot)
"Issue of Slot Disable command failed\n"); "Issue of Slot Disable command failed\n");
return retval; return retval;
} }
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
} }
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
if (PWR_LED(ctrl)) if (PWR_LED(ctrl))
/* turn off Green LED */ /* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->green_led_off(p_slot);
......
This diff is collapsed.
...@@ -15,7 +15,7 @@ static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason) ...@@ -15,7 +15,7 @@ static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason)
dev_printk(KERN_ERR, &pdev->dev, dev_printk(KERN_ERR, &pdev->dev,
"Potentially misrouted IRQ (Bridge %s %04x:%04x)\n", "Potentially misrouted IRQ (Bridge %s %04x:%04x)\n",
parent->dev.bus_id, parent->vendor, parent->device); dev_name(&parent->dev), parent->vendor, parent->device);
dev_printk(KERN_ERR, &pdev->dev, "%s\n", reason); dev_printk(KERN_ERR, &pdev->dev, "%s\n", reason);
dev_printk(KERN_ERR, &pdev->dev, "Please report to linux-kernel@vger.kernel.org\n"); dev_printk(KERN_ERR, &pdev->dev, "Please report to linux-kernel@vger.kernel.org\n");
WARN_ON(1); WARN_ON(1);
......
...@@ -776,28 +776,19 @@ void pci_no_msi(void) ...@@ -776,28 +776,19 @@ void pci_no_msi(void)
pci_msi_enable = 0; pci_msi_enable = 0;
} }
void pci_msi_init_pci_dev(struct pci_dev *dev) /**
{ * pci_msi_enabled - is MSI enabled?
INIT_LIST_HEAD(&dev->msi_list); *
} * Returns true if MSI has not been disabled by the command-line option
* pci=nomsi.
#ifdef CONFIG_ACPI **/
#include <linux/acpi.h> int pci_msi_enabled(void)
#include <linux/pci-acpi.h>
static void __devinit msi_acpi_init(void)
{ {
if (acpi_pci_disabled) return pci_msi_enable;
return;
pci_osc_support_set(OSC_MSI_SUPPORT);
pcie_osc_support_set(OSC_MSI_SUPPORT);
} }
#else EXPORT_SYMBOL(pci_msi_enabled);
static inline void msi_acpi_init(void) { }
#endif /* CONFIG_ACPI */
void __devinit msi_init(void) void pci_msi_init_pci_dev(struct pci_dev *dev)
{ {
if (!pci_msi_enable) INIT_LIST_HEAD(&dev->msi_list);
return;
msi_acpi_init();
} }
...@@ -24,13 +24,14 @@ struct acpi_osc_data { ...@@ -24,13 +24,14 @@ struct acpi_osc_data {
acpi_handle handle; acpi_handle handle;
u32 support_set; u32 support_set;
u32 control_set; u32 control_set;
u32 control_query;
int is_queried;
struct list_head sibiling; struct list_head sibiling;
}; };
static LIST_HEAD(acpi_osc_data_list); static LIST_HEAD(acpi_osc_data_list);
struct acpi_osc_args { struct acpi_osc_args {
u32 capbuf[3]; u32 capbuf[3];
u32 ctrl_result;
}; };
static DEFINE_MUTEX(pci_acpi_lock); static DEFINE_MUTEX(pci_acpi_lock);
...@@ -56,7 +57,7 @@ static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, ...@@ -56,7 +57,7 @@ static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
static acpi_status acpi_run_osc(acpi_handle handle, static acpi_status acpi_run_osc(acpi_handle handle,
struct acpi_osc_args *osc_args) struct acpi_osc_args *osc_args, u32 *retval)
{ {
acpi_status status; acpi_status status;
struct acpi_object_list input; struct acpi_object_list input;
...@@ -112,8 +113,7 @@ static acpi_status acpi_run_osc(acpi_handle handle, ...@@ -112,8 +113,7 @@ static acpi_status acpi_run_osc(acpi_handle handle,
goto out_kfree; goto out_kfree;
} }
out_success: out_success:
osc_args->ctrl_result = *retval = *((u32 *)(out_obj->buffer.pointer + 8));
*((u32 *)(out_obj->buffer.pointer + 8));
status = AE_OK; status = AE_OK;
out_kfree: out_kfree:
...@@ -121,11 +121,10 @@ static acpi_status acpi_run_osc(acpi_handle handle, ...@@ -121,11 +121,10 @@ static acpi_status acpi_run_osc(acpi_handle handle,
return status; return status;
} }
static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data, static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data)
u32 *result)
{ {
acpi_status status; acpi_status status;
u32 support_set; u32 support_set, result;
struct acpi_osc_args osc_args; struct acpi_osc_args osc_args;
/* do _OSC query for all possible controls */ /* do _OSC query for all possible controls */
...@@ -134,56 +133,45 @@ static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data, ...@@ -134,56 +133,45 @@ static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data,
osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set;
osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
status = acpi_run_osc(osc_data->handle, &osc_args); status = acpi_run_osc(osc_data->handle, &osc_args, &result);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
osc_data->support_set = support_set; osc_data->support_set = support_set;
*result = osc_args.ctrl_result; osc_data->control_query = result;
osc_data->is_queried = 1;
} }
return status; return status;
} }
static acpi_status acpi_query_osc(acpi_handle handle, /*
u32 level, void *context, void **retval) * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature
* @flags: Bitmask of flags to support
*
* See the ACPI spec for the definition of the flags
*/
int pci_acpi_osc_support(acpi_handle handle, u32 flags)
{ {
acpi_status status; acpi_status status;
struct acpi_osc_data *osc_data;
u32 flags = (unsigned long)context, dummy;
acpi_handle tmp; acpi_handle tmp;
struct acpi_osc_data *osc_data;
int rc = 0;
status = acpi_get_handle(handle, "_OSC", &tmp); status = acpi_get_handle(handle, "_OSC", &tmp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return AE_OK; return -ENOTTY;
mutex_lock(&pci_acpi_lock); mutex_lock(&pci_acpi_lock);
osc_data = acpi_get_osc_data(handle); osc_data = acpi_get_osc_data(handle);
if (!osc_data) { if (!osc_data) {
printk(KERN_ERR "acpi osc data array is full\n"); printk(KERN_ERR "acpi osc data array is full\n");
rc = -ENOMEM;
goto out; goto out;
} }
__acpi_query_osc(flags, osc_data, &dummy); __acpi_query_osc(flags, osc_data);
out: out:
mutex_unlock(&pci_acpi_lock); mutex_unlock(&pci_acpi_lock);
return AE_OK; return rc;
}
/**
* __pci_osc_support_set - register OS support to Firmware
* @flags: OS support bits
* @hid: hardware ID
*
* Update OS support fields and doing a _OSC Query to obtain an update
* from Firmware on supported control bits.
**/
acpi_status __pci_osc_support_set(u32 flags, const char *hid)
{
if (!(flags & OSC_SUPPORT_MASKS))
return AE_TYPE;
acpi_get_devices(hid, acpi_query_osc,
(void *)(unsigned long)flags, NULL);
return AE_OK;
} }
/** /**
...@@ -196,7 +184,7 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid) ...@@ -196,7 +184,7 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid)
acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
{ {
acpi_status status; acpi_status status;
u32 ctrlset, control_set, result; u32 control_req, control_set, result;
acpi_handle tmp; acpi_handle tmp;
struct acpi_osc_data *osc_data; struct acpi_osc_data *osc_data;
struct acpi_osc_args osc_args; struct acpi_osc_args osc_args;
...@@ -213,28 +201,34 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) ...@@ -213,28 +201,34 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
goto out; goto out;
} }
ctrlset = (flags & OSC_CONTROL_MASKS); control_req = (flags & OSC_CONTROL_MASKS);
if (!ctrlset) { if (!control_req) {
status = AE_TYPE; status = AE_TYPE;
goto out; goto out;
} }
status = __acpi_query_osc(osc_data->support_set, osc_data, &result); /* No need to evaluate _OSC if the control was already granted. */
if (ACPI_FAILURE(status)) if ((osc_data->control_set & control_req) == control_req)
goto out; goto out;
if ((result & ctrlset) != ctrlset) { if (!osc_data->is_queried) {
status = __acpi_query_osc(osc_data->support_set, osc_data);
if (ACPI_FAILURE(status))
goto out;
}
if ((osc_data->control_query & control_req) != control_req) {
status = AE_SUPPORT; status = AE_SUPPORT;
goto out; goto out;
} }
control_set = osc_data->control_set | ctrlset; control_set = osc_data->control_set | control_req;
osc_args.capbuf[OSC_QUERY_TYPE] = 0; osc_args.capbuf[OSC_QUERY_TYPE] = 0;
osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set; osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set;
osc_args.capbuf[OSC_CONTROL_TYPE] = control_set; osc_args.capbuf[OSC_CONTROL_TYPE] = control_set;
status = acpi_run_osc(handle, &osc_args); status = acpi_run_osc(handle, &osc_args, &result);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
osc_data->control_set = control_set; osc_data->control_set = result;
out: out:
mutex_unlock(&pci_acpi_lock); mutex_unlock(&pci_acpi_lock);
return status; return status;
...@@ -375,7 +369,7 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) ...@@ -375,7 +369,7 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
* The string should be the same as root bridge's name * The string should be the same as root bridge's name
* Please look at 'pci_scan_bus_parented' * Please look at 'pci_scan_bus_parented'
*/ */
num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus);
if (num != 2) if (num != 2)
return -ENODEV; return -ENODEV;
*handle = acpi_get_pci_rootbridge_handle(seg, bus); *handle = acpi_get_pci_rootbridge_handle(seg, bus);
......
This diff is collapsed.
/* pci-stub - simple stub driver to reserve a pci device
*
* Copyright (C) 2008 Red Hat, Inc.
* Author:
* Chris Wright
*
* This work is licensed under the terms of the GNU GPL, version 2.
*
* Usage is simple, allocate a new id to the stub driver and bind the
* device to it. For example:
*
* # echo "8086 10f5" > /sys/bus/pci/drivers/pci-stub/new_id
* # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
* # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/pci-stub/bind
* # ls -l /sys/bus/pci/devices/0000:00:19.0/driver
* .../0000:00:19.0/driver -> ../../../bus/pci/drivers/pci-stub
*/
#include <linux/module.h>
#include <linux/pci.h>
static int pci_stub_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
return 0;
}
static struct pci_driver stub_driver = {
.name = "pci-stub",
.id_table = NULL, /* only dynamic id's */
.probe = pci_stub_probe,
};
static int __init pci_stub_init(void)
{
return pci_register_driver(&stub_driver);
}
static void __exit pci_stub_exit(void)
{
pci_unregister_driver(&stub_driver);
}
module_init(pci_stub_init);
module_exit(pci_stub_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris Wright <chrisw@sous-sol.org>");
...@@ -58,13 +58,14 @@ static ssize_t broken_parity_status_store(struct device *dev, ...@@ -58,13 +58,14 @@ static ssize_t broken_parity_status_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
ssize_t consumed = -EINVAL; unsigned long val;
if ((count > 0) && (*buf == '0' || *buf == '1')) { if (strict_strtoul(buf, 0, &val) < 0)
pdev->broken_parity_status = *buf == '1' ? 1 : 0; return -EINVAL;
consumed = count;
} pdev->broken_parity_status = !!val;
return consumed;
return count;
} }
static ssize_t local_cpus_show(struct device *dev, static ssize_t local_cpus_show(struct device *dev,
...@@ -101,11 +102,13 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) ...@@ -101,11 +102,13 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_dev * pci_dev = to_pci_dev(dev);
char * str = buf; char * str = buf;
int i; int i;
int max = 7; int max;
resource_size_t start, end; resource_size_t start, end;
if (pci_dev->subordinate) if (pci_dev->subordinate)
max = DEVICE_COUNT_RESOURCE; max = DEVICE_COUNT_RESOURCE;
else
max = PCI_BRIDGE_RESOURCES;
for (i = 0; i < max; i++) { for (i = 0; i < max; i++) {
struct resource *res = &pci_dev->resource[i]; struct resource *res = &pci_dev->resource[i];
...@@ -133,19 +136,23 @@ static ssize_t is_enabled_store(struct device *dev, ...@@ -133,19 +136,23 @@ static ssize_t is_enabled_store(struct device *dev,
struct device_attribute *attr, const char *buf, struct device_attribute *attr, const char *buf,
size_t count) size_t count)
{ {
ssize_t result = -EINVAL;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
unsigned long val;
ssize_t result = strict_strtoul(buf, 0, &val);
if (result < 0)
return result;
/* this can crash the machine when done on the "wrong" device */ /* this can crash the machine when done on the "wrong" device */
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return count; return -EPERM;
if (*buf == '0') { if (!val) {
if (atomic_read(&pdev->enable_cnt) != 0) if (atomic_read(&pdev->enable_cnt) != 0)
pci_disable_device(pdev); pci_disable_device(pdev);
else else
result = -EIO; result = -EIO;
} else if (*buf == '1') } else
result = pci_enable_device(pdev); result = pci_enable_device(pdev);
return result < 0 ? result : count; return result < 0 ? result : count;
...@@ -185,25 +192,28 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, ...@@ -185,25 +192,28 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
unsigned long val;
if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL;
/* bad things may happen if the no_msi flag is changed /* bad things may happen if the no_msi flag is changed
* while some drivers are loaded */ * while some drivers are loaded */
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return count; return -EPERM;
/* Maybe pci devices without subordinate busses shouldn't even have this
* attribute in the first place? */
if (!pdev->subordinate) if (!pdev->subordinate)
return count; return count;
if (*buf == '0') { /* Is the flag going to change, or keep the value it already had? */
pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^
dev_warn(&pdev->dev, "forced subordinate bus to not support MSI," !!val) {
" bad things could happen.\n"); pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI;
}
if (*buf == '1') { dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI,"
pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI; " bad things could happen\n", val ? "" : " not");
dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
" bad things could happen.\n");
} }
return count; return count;
...@@ -361,55 +371,33 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr, ...@@ -361,55 +371,33 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
} }
static ssize_t static ssize_t
pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count) char *buf, loff_t off, size_t count)
{ {
struct pci_dev *dev = struct pci_dev *dev =
to_pci_dev(container_of(kobj, struct device, kobj)); to_pci_dev(container_of(kobj, struct device, kobj));
int end;
int ret;
if (off > bin_attr->size) if (off > bin_attr->size)
count = 0; count = 0;
else if (count > bin_attr->size - off) else if (count > bin_attr->size - off)
count = bin_attr->size - off; count = bin_attr->size - off;
end = off + count;
while (off < end) {
ret = dev->vpd->ops->read(dev, off, end - off, buf);
if (ret < 0)
return ret;
buf += ret;
off += ret;
}
return count; return pci_read_vpd(dev, off, count, buf);
} }
static ssize_t static ssize_t
pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count) char *buf, loff_t off, size_t count)
{ {
struct pci_dev *dev = struct pci_dev *dev =
to_pci_dev(container_of(kobj, struct device, kobj)); to_pci_dev(container_of(kobj, struct device, kobj));
int end;
int ret;
if (off > bin_attr->size) if (off > bin_attr->size)
count = 0; count = 0;
else if (count > bin_attr->size - off) else if (count > bin_attr->size - off)
count = bin_attr->size - off; count = bin_attr->size - off;
end = off + count;
while (off < end) {
ret = dev->vpd->ops->write(dev, off, end - off, buf);
if (ret < 0)
return ret;
buf += ret;
off += ret;
}
return count; return pci_write_vpd(dev, off, count, buf);
} }
#ifdef HAVE_PCI_LEGACY #ifdef HAVE_PCI_LEGACY
...@@ -569,7 +557,7 @@ void pci_remove_legacy_files(struct pci_bus *b) ...@@ -569,7 +557,7 @@ void pci_remove_legacy_files(struct pci_bus *b)
#ifdef HAVE_PCI_MMAP #ifdef HAVE_PCI_MMAP
static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
{ {
unsigned long nr, start, size; unsigned long nr, start, size;
...@@ -620,6 +608,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, ...@@ -620,6 +608,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
vma->vm_pgoff += start >> PAGE_SHIFT; vma->vm_pgoff += start >> PAGE_SHIFT;
mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start))
return -EINVAL;
return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
} }
...@@ -832,8 +823,8 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev) ...@@ -832,8 +823,8 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
attr->size = dev->vpd->len; attr->size = dev->vpd->len;
attr->attr.name = "vpd"; attr->attr.name = "vpd";
attr->attr.mode = S_IRUSR | S_IWUSR; attr->attr.mode = S_IRUSR | S_IWUSR;
attr->read = pci_read_vpd; attr->read = read_vpd_attr;
attr->write = pci_write_vpd; attr->write = write_vpd_attr;
retval = sysfs_create_bin_file(&dev->dev.kobj, attr); retval = sysfs_create_bin_file(&dev->dev.kobj, attr);
if (retval) { if (retval) {
kfree(dev->vpd->attr); kfree(dev->vpd->attr);
......
This diff is collapsed.
...@@ -10,6 +10,10 @@ extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); ...@@ -10,6 +10,10 @@ extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev); extern void pci_cleanup_rom(struct pci_dev *dev);
#ifdef HAVE_PCI_MMAP
extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
struct vm_area_struct *vma);
#endif
/** /**
* Firmware PM callbacks * Firmware PM callbacks
...@@ -40,7 +44,11 @@ struct pci_platform_pm_ops { ...@@ -40,7 +44,11 @@ struct pci_platform_pm_ops {
}; };
extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
extern void pci_disable_enabled_device(struct pci_dev *dev);
extern void pci_pm_init(struct pci_dev *dev); extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
...@@ -50,14 +58,14 @@ extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); ...@@ -50,14 +58,14 @@ extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val);
extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
struct pci_vpd_ops { struct pci_vpd_ops {
int (*read)(struct pci_dev *dev, int pos, int size, char *buf); ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
int (*write)(struct pci_dev *dev, int pos, int size, const char *buf); ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
void (*release)(struct pci_dev *dev); void (*release)(struct pci_dev *dev);
}; };
struct pci_vpd { struct pci_vpd {
unsigned int len; unsigned int len;
struct pci_vpd_ops *ops; const struct pci_vpd_ops *ops;
struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
}; };
...@@ -98,11 +106,9 @@ extern unsigned int pci_pm_d3_delay; ...@@ -98,11 +106,9 @@ extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
void pci_no_msi(void); void pci_no_msi(void);
extern void pci_msi_init_pci_dev(struct pci_dev *dev); extern void pci_msi_init_pci_dev(struct pci_dev *dev);
extern void __devinit msi_init(void);
#else #else
static inline void pci_no_msi(void) { } static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
static inline void msi_init(void) { }
#endif #endif
#ifdef CONFIG_PCIEAER #ifdef CONFIG_PCIEAER
...@@ -159,16 +165,28 @@ struct pci_slot_attribute { ...@@ -159,16 +165,28 @@ struct pci_slot_attribute {
}; };
#define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr) #define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
enum pci_bar_type {
pci_bar_unknown, /* Standard PCI BAR probe */
pci_bar_io, /* An io port BAR */
pci_bar_mem32, /* A 32-bit memory BAR */
pci_bar_mem64, /* A 64-bit memory BAR */
};
extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int reg);
extern int pci_resource_bar(struct pci_dev *dev, int resno,
enum pci_bar_type *type);
extern int pci_bus_add_child(struct pci_bus *bus);
extern void pci_enable_ari(struct pci_dev *dev); extern void pci_enable_ari(struct pci_dev *dev);
/** /**
* pci_ari_enabled - query ARI forwarding status * pci_ari_enabled - query ARI forwarding status
* @dev: the PCI device * @bus: the PCI bus
* *
* Returns 1 if ARI forwarding is enabled, or 0 if not enabled; * Returns 1 if ARI forwarding is enabled, or 0 if not enabled;
*/ */
static inline int pci_ari_enabled(struct pci_dev *dev) static inline int pci_ari_enabled(struct pci_bus *bus)
{ {
return dev->ari_enabled; return bus->self && bus->self->ari_enabled;
} }
#endif /* DRIVERS_PCI_H */ #endif /* DRIVERS_PCI_H */
...@@ -38,7 +38,6 @@ int aer_osc_setup(struct pcie_device *pciedev) ...@@ -38,7 +38,6 @@ int aer_osc_setup(struct pcie_device *pciedev)
handle = acpi_find_root_bridge_handle(pdev); handle = acpi_find_root_bridge_handle(pdev);
if (handle) { if (handle) {
pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
status = pci_osc_control_set(handle, status = pci_osc_control_set(handle,
OSC_PCI_EXPRESS_AER_CONTROL | OSC_PCI_EXPRESS_AER_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
......
...@@ -233,7 +233,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) ...@@ -233,7 +233,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
if (info->flags & AER_TLP_HEADER_VALID_FLAG) { if (info->flags & AER_TLP_HEADER_VALID_FLAG) {
unsigned char *tlp = (unsigned char *) &info->tlp; unsigned char *tlp = (unsigned char *) &info->tlp;
printk("%sTLB Header:\n", loglevel); printk("%sTLP Header:\n", loglevel);
printk("%s%02x%02x%02x%02x %02x%02x%02x%02x" printk("%s%02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n", " %02x%02x%02x%02x %02x%02x%02x%02x\n",
loglevel, loglevel,
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include "../pci.h" #include "../pci.h"
...@@ -33,6 +34,11 @@ struct endpoint_state { ...@@ -33,6 +34,11 @@ struct endpoint_state {
struct pcie_link_state { struct pcie_link_state {
struct list_head sibiling; struct list_head sibiling;
struct pci_dev *pdev; struct pci_dev *pdev;
bool downstream_has_switch;
struct pcie_link_state *parent;
struct list_head children;
struct list_head link;
/* ASPM state */ /* ASPM state */
unsigned int support_state; unsigned int support_state;
...@@ -70,6 +76,8 @@ static const char *policy_str[] = { ...@@ -70,6 +76,8 @@ static const char *policy_str[] = {
[POLICY_POWERSAVE] = "powersave" [POLICY_POWERSAVE] = "powersave"
}; };
#define LINK_RETRAIN_TIMEOUT HZ
static int policy_to_aspm_state(struct pci_dev *pdev) static int policy_to_aspm_state(struct pci_dev *pdev)
{ {
struct pcie_link_state *link_state = pdev->link_state; struct pcie_link_state *link_state = pdev->link_state;
...@@ -125,7 +133,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) ...@@ -125,7 +133,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable)
link_state->clk_pm_enabled = !!enable; link_state->clk_pm_enabled = !!enable;
} }
static void pcie_check_clock_pm(struct pci_dev *pdev) static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist)
{ {
int pos; int pos;
u32 reg32; u32 reg32;
...@@ -149,10 +157,26 @@ static void pcie_check_clock_pm(struct pci_dev *pdev) ...@@ -149,10 +157,26 @@ static void pcie_check_clock_pm(struct pci_dev *pdev)
if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
enabled = 0; enabled = 0;
} }
link_state->clk_pm_capable = capable;
link_state->clk_pm_enabled = enabled; link_state->clk_pm_enabled = enabled;
link_state->bios_clk_state = enabled; link_state->bios_clk_state = enabled;
pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); if (!blacklist) {
link_state->clk_pm_capable = capable;
pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
} else {
link_state->clk_pm_capable = 0;
pcie_set_clock_pm(pdev, 0);
}
}
static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev)
{
struct pci_dev *child_dev;
list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM)
return true;
}
return false;
} }
/* /*
...@@ -217,16 +241,18 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) ...@@ -217,16 +241,18 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev)
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
/* Wait for link training end */ /* Wait for link training end */
/* break out after waiting for 1 second */ /* break out after waiting for timeout */
start_jiffies = jiffies; start_jiffies = jiffies;
while ((jiffies - start_jiffies) < HZ) { for (;;) {
pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16); pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16);
if (!(reg16 & PCI_EXP_LNKSTA_LT)) if (!(reg16 & PCI_EXP_LNKSTA_LT))
break; break;
cpu_relax(); if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
break;
msleep(1);
} }
/* training failed -> recover */ /* training failed -> recover */
if ((jiffies - start_jiffies) >= HZ) { if (reg16 & PCI_EXP_LNKSTA_LT) {
dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure"
" common clock\n"); " common clock\n");
i = 0; i = 0;
...@@ -419,9 +445,9 @@ static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, ...@@ -419,9 +445,9 @@ static unsigned int pcie_aspm_check_state(struct pci_dev *pdev,
{ {
struct pci_dev *child_dev; struct pci_dev *child_dev;
/* If no child, disable the link */ /* If no child, ignore the link */
if (list_empty(&pdev->subordinate->devices)) if (list_empty(&pdev->subordinate->devices))
return 0; return state;
list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
/* /*
...@@ -462,6 +488,9 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) ...@@ -462,6 +488,9 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
int valid = 1; int valid = 1;
struct pcie_link_state *link_state = pdev->link_state; struct pcie_link_state *link_state = pdev->link_state;
/* If no child, disable the link */
if (list_empty(&pdev->subordinate->devices))
state = 0;
/* /*
* if the downstream component has pci bridge function, don't do ASPM * if the downstream component has pci bridge function, don't do ASPM
* now * now
...@@ -493,20 +522,52 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) ...@@ -493,20 +522,52 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
link_state->enabled_state = state; link_state->enabled_state = 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 pci_dev *pdev, static void __pcie_aspm_configure_link_state(struct pci_dev *pdev,
unsigned int state) unsigned int state)
{ {
struct pcie_link_state *link_state = pdev->link_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;
if (link_state->support_state == 0)
return;
state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
/* state 0 means disabling aspm */ /* check all links who have specific root port link */
state = pcie_aspm_check_state(pdev, state); list_for_each_entry(leaf, &link_list, sibiling) {
if (!list_empty(&leaf->children) ||
get_root_port_link(leaf) != root_port_link)
continue;
state = pcie_aspm_check_state(leaf->pdev, 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->enabled_state == state) if (link_state->enabled_state == state)
return; return;
__pcie_aspm_config_link(pdev, state);
/*
* 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, sibiling) {
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) {
if (get_root_port_link(leaf) == root_port_link)
__pcie_aspm_config_link(leaf->pdev, state);
}
}
} }
/* /*
...@@ -570,6 +631,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) ...@@ -570,6 +631,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
unsigned int state; unsigned int state;
struct pcie_link_state *link_state; struct pcie_link_state *link_state;
int error = 0; int error = 0;
int blacklist;
if (aspm_disabled || !pdev->is_pcie || pdev->link_state) if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
return; return;
...@@ -580,29 +642,58 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) ...@@ -580,29 +642,58 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
if (list_empty(&pdev->subordinate->devices)) if (list_empty(&pdev->subordinate->devices))
goto out; goto out;
if (pcie_aspm_sanity_check(pdev)) blacklist = !!pcie_aspm_sanity_check(pdev);
goto out;
mutex_lock(&aspm_lock); mutex_lock(&aspm_lock);
link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
if (!link_state) if (!link_state)
goto unlock_out; goto unlock_out;
pdev->link_state = link_state;
pcie_aspm_configure_common_clock(pdev); link_state->downstream_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 */
struct pcie_link_state *parent_link_state;
pcie_aspm_cap_init(pdev); 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;
}
/* config link state to avoid BIOS error */ pdev->link_state = link_state;
state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev));
__pcie_aspm_config_link(pdev, state);
pcie_check_clock_pm(pdev); if (!blacklist) {
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;
/* Set support state to 0, so we will disable ASPM later */
link_state->support_state = 0;
}
link_state->pdev = pdev; link_state->pdev = pdev;
list_add(&link_state->sibiling, &link_list); list_add(&link_state->sibiling, &link_list);
if (link_state->downstream_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(pdev, link_state->bios_aspm_state);
__pcie_aspm_config_link(pdev, state);
} else
__pcie_aspm_configure_link_state(pdev,
policy_to_aspm_state(pdev));
pcie_check_clock_pm(pdev, blacklist);
unlock_out: unlock_out:
if (error) if (error)
free_link_state(pdev); free_link_state(pdev);
...@@ -635,6 +726,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) ...@@ -635,6 +726,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
/* All functions are removed, so just disable ASPM for the link */ /* All functions are removed, so just disable ASPM for the link */
__pcie_aspm_config_one_dev(parent, 0); __pcie_aspm_config_one_dev(parent, 0);
list_del(&link_state->sibiling); list_del(&link_state->sibiling);
list_del(&link_state->link);
/* Clock PM is for endpoint device */ /* Clock PM is for endpoint device */
free_link_state(parent); free_link_state(parent);
...@@ -857,24 +949,15 @@ void pcie_no_aspm(void) ...@@ -857,24 +949,15 @@ void pcie_no_aspm(void)
aspm_disabled = 1; aspm_disabled = 1;
} }
#ifdef CONFIG_ACPI /**
#include <acpi/acpi_bus.h> * pcie_aspm_enabled - is PCIe ASPM enabled?
#include <linux/pci-acpi.h> *
static void pcie_aspm_platform_init(void) * Returns true if ASPM has not been disabled by the command-line option
{ * pcie_aspm=off.
pcie_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT| **/
OSC_CLOCK_PWR_CAPABILITY_SUPPORT); int pcie_aspm_enabled(void)
}
#else
static inline void pcie_aspm_platform_init(void) { }
#endif
static int __init pcie_aspm_init(void)
{ {
if (aspm_disabled) return !aspm_disabled;
return 0;
pcie_aspm_platform_init();
return 0;
} }
EXPORT_SYMBOL(pcie_aspm_enabled);
fs_initcall(pcie_aspm_init);
...@@ -16,14 +16,10 @@ ...@@ -16,14 +16,10 @@
#include "portdrv.h" #include "portdrv.h"
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv); static int pcie_port_bus_match(struct device *dev, struct device_driver *drv);
static int pcie_port_bus_suspend(struct device *dev, pm_message_t state);
static int pcie_port_bus_resume(struct device *dev);
struct bus_type pcie_port_bus_type = { struct bus_type pcie_port_bus_type = {
.name = "pci_express", .name = "pci_express",
.match = pcie_port_bus_match, .match = pcie_port_bus_match,
.suspend = pcie_port_bus_suspend,
.resume = pcie_port_bus_resume,
}; };
EXPORT_SYMBOL_GPL(pcie_port_bus_type); EXPORT_SYMBOL_GPL(pcie_port_bus_type);
...@@ -49,32 +45,12 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) ...@@ -49,32 +45,12 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
return 1; return 1;
} }
static int pcie_port_bus_suspend(struct device *dev, pm_message_t state) int pcie_port_bus_register(void)
{ {
struct pcie_device *pciedev; return bus_register(&pcie_port_bus_type);
struct pcie_port_service_driver *driver;
if (!dev || !dev->driver)
return 0;
pciedev = to_pcie_device(dev);
driver = to_service_driver(dev->driver);
if (driver && driver->suspend)
driver->suspend(pciedev, state);
return 0;
} }
static int pcie_port_bus_resume(struct device *dev) void pcie_port_bus_unregister(void)
{ {
struct pcie_device *pciedev; bus_unregister(&pcie_port_bus_type);
struct pcie_port_service_driver *driver;
if (!dev || !dev->driver)
return 0;
pciedev = to_pcie_device(dev);
driver = to_service_driver(dev->driver);
if (driver && driver->resume)
driver->resume(pciedev);
return 0;
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -252,11 +252,20 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -252,11 +252,20 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
const struct proc_dir_entry *dp = PDE(inode); const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data; struct pci_dev *dev = dp->data;
struct pci_filp_private *fpriv = file->private_data; struct pci_filp_private *fpriv = file->private_data;
int ret; int i, ret;
if (!capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_RAWIO))
return -EPERM; return -EPERM;
/* Make sure the caller is mapping a real resource for this device */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
if (pci_mmap_fits(dev, i, vma))
break;
}
if (i >= PCI_ROM_RESOURCE)
return -ENODEV;
ret = pci_mmap_page_range(dev, vma, ret = pci_mmap_page_range(dev, vma,
fpriv->mmap_state, fpriv->mmap_state,
fpriv->write_combine); fpriv->write_combine);
...@@ -352,15 +361,16 @@ static int show_device(struct seq_file *m, void *v) ...@@ -352,15 +361,16 @@ static int show_device(struct seq_file *m, void *v)
dev->vendor, dev->vendor,
dev->device, dev->device,
dev->irq); dev->irq);
/* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
for (i=0; i<7; i++) { /* only print standard and ROM resources to preserve compatibility */
for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
resource_size_t start, end; resource_size_t start, end;
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, "\t%16llx", seq_printf(m, "\t%16llx",
(unsigned long long)(start | (unsigned long long)(start |
(dev->resource[i].flags & PCI_REGION_FLAG_MASK))); (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
} }
for (i=0; i<7; i++) { for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
resource_size_t start, end; resource_size_t start, end;
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, "\t%16llx", seq_printf(m, "\t%16llx",
......
This diff is collapsed.
...@@ -536,9 +536,8 @@ static void pci_bus_dump_res(struct pci_bus *bus) ...@@ -536,9 +536,8 @@ static void pci_bus_dump_res(struct pci_bus *bus)
if (!res) if (!res)
continue; continue;
printk(KERN_INFO "bus: %02x index %x %s: %pR\n", dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i,
bus->number, i, (res->flags & IORESOURCE_IO) ? "io: " : "mem:", res);
(res->flags & IORESOURCE_IO) ? "io port" : "mmio", res);
} }
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment