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,6 +12,7 @@ static __init int pci_arch_init(void) ...@@ -12,6 +12,7 @@ static __init int pci_arch_init(void)
type = pci_direct_probe(); type = pci_direct_probe();
#endif #endif
if (!(pci_probe & PCI_PROBE_NOEARLY))
pci_mmcfg_early_init(); pci_mmcfg_early_init();
#ifdef CONFIG_PCI_OLPC #ifdef CONFIG_PCI_OLPC
......
...@@ -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;
if (fatal_signal_pending(current))
return -EINTR;
if (!cond_resched())
udelay(10); 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))
return -EINTR;
ret = pci_vpd_pci22_wait(dev); ret = pci_vpd_pci22_wait(dev);
if (ret < 0) if (ret < 0)
goto out; goto out;
while (pos < end) {
u32 val;
unsigned int i, skip;
ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
pos & ~3); pos & ~3);
if (ret < 0) if (ret < 0)
goto out; break;
vpd->busy = true; vpd->busy = true;
vpd->flag = 1; vpd->flag = PCI_VPD_ADDR_F;
ret = pci_vpd_pci22_wait(dev); ret = pci_vpd_pci22_wait(dev);
if (ret < 0) if (ret < 0)
goto out; break;
ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA,
&val); ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val);
out:
spin_unlock_irq(&vpd->lock);
if (ret < 0) if (ret < 0)
return ret; break;
/* Convert to bytes */ skip = pos & 3;
begin = pos & 3; for (i = 0; i < sizeof(u32); i++) {
end = min(4, begin + size); if (i >= skip) {
for (i = 0; i < end; ++i) {
if (i >= begin)
*buf++ = val; *buf++ = val;
if (++pos == end)
break;
}
val >>= 8; 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); 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) if (ret < 0)
goto out; break;
ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
pos | PCI_VPD_ADDR_F); pos | PCI_VPD_ADDR_F);
if (ret < 0) if (ret < 0)
goto out; break;
vpd->busy = true; vpd->busy = true;
vpd->flag = 0; vpd->flag = 0;
ret = pci_vpd_pci22_wait(dev); ret = pci_vpd_pci22_wait(dev);
out:
spin_unlock_irq(&vpd->lock);
if (ret < 0)
return ret;
return 4; 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;
if (list_empty(&child->node)) {
down_write(&pci_bus_sem); down_write(&pci_bus_sem);
list_add_tail(&dev->subordinate->node, list_add_tail(&child->node, &dev->bus->children);
&dev->bus->children);
up_write(&pci_bus_sem); up_write(&pci_bus_sem);
} }
pci_bus_add_devices(dev->subordinate); pci_bus_add_devices(child);
/* register the bus with sysfs as the parent is now /*
* properly registered. */ * register the bus with sysfs as the parent is now
child_bus = dev->subordinate; * properly registered.
if (child_bus->is_added) */
if (child->is_added)
continue; continue;
child_bus->dev.parent = child_bus->bridge; retval = pci_bus_add_child(child);
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) if (retval)
dev_err(&dev->dev, "Error creating cpuaffinity" dev_err(&dev->dev, "Error adding bus, continuing\n");
" 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");
}
} }
} }
......
...@@ -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");
...@@ -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.
...@@ -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,14 +178,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) ...@@ -178,14 +178,13 @@ 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 * After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been * before taking any action that relies on power having been
* removed from the slot/adapter. * removed from the slot/adapter.
*/ */
msleep(1000); 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,14 +285,13 @@ static int remove_board(struct slot *p_slot) ...@@ -286,14 +285,13 @@ 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 * After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been * before taking any action that relies on power having been
* removed from the slot/adapter. * removed from the slot/adapter.
*/ */
msleep(1000); msleep(1000);
}
if (PWR_LED(ctrl)) if (PWR_LED(ctrl))
/* turn off Green LED */ /* turn off Green LED */
......
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 ((osc_data->control_set & control_req) == control_req)
goto out;
if (!osc_data->is_queried) {
status = __acpi_query_osc(osc_data->support_set, osc_data);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
goto out; goto out;
}
if ((result & ctrlset) != ctrlset) { 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) { return pci_read_vpd(dev, off, count, buf);
ret = dev->vpd->ops->read(dev, off, end - off, buf);
if (ret < 0)
return ret;
buf += ret;
off += ret;
}
return count;
} }
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) { return pci_write_vpd(dev, off, count, buf);
ret = dev->vpd->ops->write(dev, off, end - off, buf);
if (ret < 0)
return ret;
buf += ret;
off += ret;
}
return count;
} }
#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;
if (!blacklist) {
link_state->clk_pm_capable = capable;
pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); 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.
...@@ -41,7 +41,6 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) ...@@ -41,7 +41,6 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
{ {
int retval; int retval;
pci_restore_state(dev);
retval = pci_enable_device(dev); retval = pci_enable_device(dev);
if (retval) if (retval)
return retval; return retval;
...@@ -52,11 +51,18 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) ...@@ -52,11 +51,18 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
{ {
int ret = pcie_port_device_suspend(dev, state); return pcie_port_device_suspend(dev, state);
}
if (!ret) static int pcie_portdrv_suspend_late(struct pci_dev *dev, pm_message_t state)
ret = pcie_portdrv_save_config(dev); {
return ret; return pci_save_state(dev);
}
static int pcie_portdrv_resume_early(struct pci_dev *dev)
{
return pci_restore_state(dev);
} }
static int pcie_portdrv_resume(struct pci_dev *dev) static int pcie_portdrv_resume(struct pci_dev *dev)
...@@ -66,6 +72,8 @@ static int pcie_portdrv_resume(struct pci_dev *dev) ...@@ -66,6 +72,8 @@ static int pcie_portdrv_resume(struct pci_dev *dev)
} }
#else #else
#define pcie_portdrv_suspend NULL #define pcie_portdrv_suspend NULL
#define pcie_portdrv_suspend_late NULL
#define pcie_portdrv_resume_early NULL
#define pcie_portdrv_resume NULL #define pcie_portdrv_resume NULL
#endif #endif
...@@ -221,6 +229,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) ...@@ -221,6 +229,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
/* If fatal, restore cfg space for possible link reset at upstream */ /* If fatal, restore cfg space for possible link reset at upstream */
if (dev->error_state == pci_channel_io_frozen) { if (dev->error_state == pci_channel_io_frozen) {
pci_restore_state(dev);
pcie_portdrv_restore_config(dev); pcie_portdrv_restore_config(dev);
pci_enable_pcie_error_reporting(dev); pci_enable_pcie_error_reporting(dev);
} }
...@@ -283,6 +292,8 @@ static struct pci_driver pcie_portdriver = { ...@@ -283,6 +292,8 @@ static struct pci_driver pcie_portdriver = {
.remove = pcie_portdrv_remove, .remove = pcie_portdrv_remove,
.suspend = pcie_portdrv_suspend, .suspend = pcie_portdrv_suspend,
.suspend_late = pcie_portdrv_suspend_late,
.resume_early = pcie_portdrv_resume_early,
.resume = pcie_portdrv_resume, .resume = pcie_portdrv_resume,
.err_handler = &pcie_portdrv_err_handler, .err_handler = &pcie_portdrv_err_handler,
......
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.
...@@ -49,6 +49,7 @@ struct resource_list { ...@@ -49,6 +49,7 @@ struct resource_list {
#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ #define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ #define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
#define IORESOURCE_DISABLED 0x10000000 #define IORESOURCE_DISABLED 0x10000000
#define IORESOURCE_UNSET 0x20000000 #define IORESOURCE_UNSET 0x20000000
#define IORESOURCE_AUTO 0x40000000 #define IORESOURCE_AUTO 0x40000000
...@@ -133,13 +134,16 @@ static inline unsigned long resource_type(struct resource *res) ...@@ -133,13 +134,16 @@ static inline unsigned long resource_type(struct resource *res)
} }
/* Convenience shorthand with allocation */ /* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) #define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl)
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
#define request_mem_region_exclusive(start,n,name) \
__request_region(&iomem_resource, (start), (n), (name), IORESOURCE_EXCLUSIVE)
#define rename_region(region, newname) do { (region)->name = (newname); } while (0) #define rename_region(region, newname) do { (region)->name = (newname); } while (0)
extern struct resource * __request_region(struct resource *, extern struct resource * __request_region(struct resource *,
resource_size_t start, resource_size_t start,
resource_size_t n, const char *name); resource_size_t n, const char *name, int relaxed);
/* Compatibility cruft */ /* Compatibility cruft */
#define release_region(start,n) __release_region(&ioport_resource, (start), (n)) #define release_region(start,n) __release_region(&ioport_resource, (start), (n))
...@@ -175,6 +179,7 @@ extern struct resource * __devm_request_region(struct device *dev, ...@@ -175,6 +179,7 @@ extern struct resource * __devm_request_region(struct device *dev,
extern void __devm_release_region(struct device *dev, struct resource *parent, extern void __devm_release_region(struct device *dev, struct resource *parent,
resource_size_t start, resource_size_t n); resource_size_t start, resource_size_t n);
extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size); extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size);
extern int iomem_is_exclusive(u64 addr);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _LINUX_IOPORT_H */ #endif /* _LINUX_IOPORT_H */
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