PCI changes for the v3.9 merge window:

Host bridge hotplug
     - Major overhaul of ACPI host bridge add/start (Rafael Wysocki, Yinghai Lu)
     - Major overhaul of PCI/ACPI binding (Rafael Wysocki, Yinghai Lu)
     - Split out ACPI host bridge and ACPI PCI device hotplug (Yinghai Lu)
     - Stop caching _PRT and make independent of bus numbers (Yinghai Lu)
 
   PCI device hotplug
     - Clean up cpqphp dead code (Sasha Levin)
     - Disable ARI unless device and upstream bridge support it (Yijing Wang)
     - Initialize all hot-added devices (not functions 0-7) (Yijing Wang)
 
   Power management
     - Don't touch ASPM if disabled (Joe Lawrence)
     - Fix ASPM link state management (Myron Stowe)
 
   Miscellaneous
     - Fix PCI_EXP_FLAGS accessor (Alex Williamson)
     - Disable Bus Master in pci_device_shutdown (Konstantin Khlebnikov)
     - Document hotplug resource and MPS parameters (Yijing Wang)
     - Add accessor for PCIe capabilities (Myron Stowe)
     - Drop pciehp suspend/resume messages (Paul Bolle)
     - Make pci_slot built-in only (not a module) (Jiang Liu)
     - Remove unused PCI/ACPI bind ops (Jiang Liu)
     - Removed used pci_root_bus (Bjorn Helgaas)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJRKS3hAAoJEFmIoMA60/r8xxoP/j1CS4oCZAnBIVT9fKBkis+/
 CENcfHIUKj6J9iMfJEVvqBELvqaLqtpeNwAGMcGPxV7VuT3K1QumChfaTpRDP0HC
 VDRmrjcmfenEK+YPOG7acsrTyqk2wjpLOyu9MKRxtC5u7tF6376KQpkEFpO4haL4
 eUHTxfE76OkrPBSvx3+PUSf6jqrvrNbjX8K6HdDVVlm3sVAQKmYJU/Wphv2NPOqa
 CAMyCzEGybFjr8hDRwvWgr+06c718GMwQUbnrPdHXAe7lMNMrN/XVBmU9ABN3Aas
 icd3lrDs+yPObgcO/gT8+sAZErCtdJ9zuHGYHdYpRbIQj/5JT4TMk7tw/Bj7vKY9
 Mqmho9GR5YmYTRN9f1r+2n5AQ/KYWXJDrRNOnt5/ys5BOM3vwJ7WJ902zpSwtFQp
 nLX+oD/hLfzpnoIQGDuBAoAXp2Kam3XWRgVvG78buRNrPj+kUzimk14a8qQeY+CB
 El6UKuwi5Uv/qgs1gAqqjmZmsAkon2DnsRZa6Fl8NTkDlis7LY4gp9OU38ySFpB+
 PhCmRyCZmDDqTVtwj6XzR3nPQ5LBSbvsTfgMxYMIUSXHa06tyb2q5p4mEIas0OmU
 RKaP5xQqZuTgD8fbdYrx0xgSrn7JHt/j/X//Qs6unlLCWhlpm3LjJZKxyw2FwBGr
 o4Lci+PiBh3MowCrju9D
 =ER3b
 -----END PGP SIGNATURE-----

Merge tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI changes from Bjorn Helgaas:
 "Host bridge hotplug
    - Major overhaul of ACPI host bridge add/start (Rafael Wysocki, Yinghai Lu)
    - Major overhaul of PCI/ACPI binding (Rafael Wysocki, Yinghai Lu)
    - Split out ACPI host bridge and ACPI PCI device hotplug (Yinghai Lu)
    - Stop caching _PRT and make independent of bus numbers (Yinghai Lu)

  PCI device hotplug
    - Clean up cpqphp dead code (Sasha Levin)
    - Disable ARI unless device and upstream bridge support it (Yijing Wang)
    - Initialize all hot-added devices (not functions 0-7) (Yijing Wang)

  Power management
    - Don't touch ASPM if disabled (Joe Lawrence)
    - Fix ASPM link state management (Myron Stowe)

  Miscellaneous
    - Fix PCI_EXP_FLAGS accessor (Alex Williamson)
    - Disable Bus Master in pci_device_shutdown (Konstantin Khlebnikov)
    - Document hotplug resource and MPS parameters (Yijing Wang)
    - Add accessor for PCIe capabilities (Myron Stowe)
    - Drop pciehp suspend/resume messages (Paul Bolle)
    - Make pci_slot built-in only (not a module) (Jiang Liu)
    - Remove unused PCI/ACPI bind ops (Jiang Liu)
    - Removed used pci_root_bus (Bjorn Helgaas)"

* tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (51 commits)
  PCI/ACPI: Don't cache _PRT, and don't associate them with bus numbers
  PCI: Fix PCI Express Capability accessors for PCI_EXP_FLAGS
  ACPI / PCI: Make pci_slot built-in only, not a module
  PCI/PM: Clear state_saved during suspend
  PCI: Use atomic_inc_return() rather than atomic_add_return()
  PCI: Catch attempts to disable already-disabled devices
  PCI: Disable Bus Master unconditionally in pci_device_shutdown()
  PCI: acpiphp: Remove dead code for PCI host bridge hotplug
  PCI: acpiphp: Create companion ACPI devices before creating PCI devices
  PCI: Remove unused "rc" in virtfn_add_bus()
  PCI: pciehp: Drop suspend/resume ENTRY messages
  PCI/ASPM: Don't touch ASPM if forcibly disabled
  PCI/ASPM: Deallocate upstream link state even if device is not PCIe
  PCI: Document MPS parameters pci=pcie_bus_safe, pci=pcie_bus_perf, etc
  PCI: Document hpiosize= and hpmemsize= resource reservation parameters
  PCI: Use PCI Express Capability accessor
  PCI: Introduce accessor to retrieve PCIe Capabilities Register
  PCI: Put pci_dev in device tree as early as possible
  PCI: Skip attaching driver in device_add()
  PCI: acpiphp: Keep driver loaded even if no slots found
  ...
This commit is contained in:
Linus Torvalds 2013-02-25 21:18:18 -08:00
commit 556f12f602
46 changed files with 680 additions and 792 deletions

View File

@ -2262,6 +2262,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This sorting is done to get a device This sorting is done to get a device
order compatible with older (<= 2.4) kernels. order compatible with older (<= 2.4) kernels.
nobfsort Don't sort PCI devices into breadth-first order. nobfsort Don't sort PCI devices into breadth-first order.
pcie_bus_tune_off Disable PCIe MPS (Max Payload Size)
tuning and use the BIOS-configured MPS defaults.
pcie_bus_safe Set every device's MPS to the largest value
supported by all devices below the root complex.
pcie_bus_perf Set device MPS to the largest allowable MPS
based on its parent bus. Also set MRRS (Max
Read Request Size) to the largest supported
value (no larger than the MPS that the device
or bus can support) for best performance.
pcie_bus_peer2peer Set every device's MPS to 128B, which
every device is guaranteed to support. This
configuration allows peer-to-peer DMA between
any pair of devices, possibly at the cost of
reduced performance. This also guarantees
that hot-added devices will work.
cbiosize=nn[KMG] The fixed amount of bus space which is cbiosize=nn[KMG] The fixed amount of bus space which is
reserved for the CardBus bridge's IO window. reserved for the CardBus bridge's IO window.
The default value is 256 bytes. The default value is 256 bytes.
@ -2283,6 +2298,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
the default. the default.
off: Turn ECRC off off: Turn ECRC off
on: Turn ECRC on. on: Turn ECRC on.
hpiosize=nn[KMG] The fixed amount of bus space which is
reserved for hotplug bridge's IO window.
Default size is 256 bytes.
hpmemsize=nn[KMG] The fixed amount of bus space which is
reserved for hotplug bridge's memory window.
Default size is 2 megabytes.
realloc= Enable/disable reallocating PCI bridge resources realloc= Enable/disable reallocating PCI bridge resources
if allocations done by BIOS are too small to if allocations done by BIOS are too small to
accommodate resources required by all child accommodate resources required by all child

View File

@ -31,7 +31,6 @@ void pcibios_resource_survey(void);
/* pci-vdk.c */ /* pci-vdk.c */
extern int __nongpreldata pcibios_last_bus; extern int __nongpreldata pcibios_last_bus;
extern struct pci_bus *__nongpreldata pci_root_bus;
extern struct pci_ops *__nongpreldata pci_root_ops; extern struct pci_ops *__nongpreldata pci_root_ops;
/* pci-irq.c */ /* pci-irq.c */

View File

@ -26,7 +26,6 @@
unsigned int __nongpreldata pci_probe = 1; unsigned int __nongpreldata pci_probe = 1;
int __nongpreldata pcibios_last_bus = -1; int __nongpreldata pcibios_last_bus = -1;
struct pci_bus *__nongpreldata pci_root_bus;
struct pci_ops *__nongpreldata pci_root_ops; struct pci_ops *__nongpreldata pci_root_ops;
/* /*
@ -416,8 +415,7 @@ int __init pcibios_init(void)
printk("PCI: Probing PCI hardware\n"); printk("PCI: Probing PCI hardware\n");
pci_add_resource(&resources, &pci_ioport_resource); pci_add_resource(&resources, &pci_ioport_resource);
pci_add_resource(&resources, &pci_iomem_resource); pci_add_resource(&resources, &pci_iomem_resource);
pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);
&resources);
pcibios_irq_init(); pcibios_irq_init();
pcibios_fixup_peer_bridges(); pcibios_fixup_peer_bridges();

View File

@ -393,6 +393,14 @@ out1:
return NULL; return NULL;
} }
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_controller *controller = bridge->bus->sysdata;
ACPI_HANDLE_SET(&bridge->dev, controller->acpi_handle);
return 0;
}
static int is_valid_resource(struct pci_dev *dev, int idx) static int is_valid_resource(struct pci_dev *dev, int idx)
{ {
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;

View File

@ -36,7 +36,6 @@ extern void pcibios_resource_survey(void);
/* pci.c */ /* pci.c */
extern int pcibios_last_bus; extern int pcibios_last_bus;
extern struct pci_bus *pci_root_bus;
extern struct pci_ops *pci_root_ops; extern struct pci_ops *pci_root_ops;
extern struct irq_routing_table *pcibios_get_irq_routing_table(void); extern struct irq_routing_table *pcibios_get_irq_routing_table(void);

View File

@ -24,7 +24,6 @@
unsigned int pci_probe = 1; unsigned int pci_probe = 1;
int pcibios_last_bus = -1; int pcibios_last_bus = -1;
struct pci_bus *pci_root_bus;
struct pci_ops *pci_root_ops; struct pci_ops *pci_root_ops;
/* /*
@ -377,8 +376,7 @@ static int __init pcibios_init(void)
pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset); pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset); pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
&resources);
pcibios_irq_init(); pcibios_irq_init();
pcibios_fixup_irqs(); pcibios_fixup_irqs();

View File

@ -14,6 +14,9 @@
struct pci_sysdata { struct pci_sysdata {
int domain; /* PCI domain */ int domain; /* PCI domain */
int node; /* NUMA node */ int node; /* NUMA node */
#ifdef CONFIG_ACPI
void *acpi; /* ACPI-specific data */
#endif
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
void *iommu; /* IOMMU private data */ void *iommu; /* IOMMU private data */
#endif #endif

View File

@ -54,7 +54,6 @@ void pcibios_set_cache_line_size(void);
/* pci-pc.c */ /* pci-pc.c */
extern int pcibios_last_bus; extern int pcibios_last_bus;
extern struct pci_bus *pci_root_bus;
extern struct pci_ops pci_root_ops; extern struct pci_ops pci_root_ops;
void pcibios_scan_specific_bus(int busn); void pcibios_scan_specific_bus(int busn);

View File

@ -521,6 +521,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
sd = &info->sd; sd = &info->sd;
sd->domain = domain; sd->domain = domain;
sd->node = node; sd->node = node;
sd->acpi = device->handle;
/* /*
* Maybe the desired pci bus has been already scanned. In such case * Maybe the desired pci bus has been already scanned. In such case
* it is unnecessary to scan the pci bus with the given domain,busnum. * it is unnecessary to scan the pci bus with the given domain,busnum.
@ -592,6 +593,14 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
return bus; return bus;
} }
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_sysdata *sd = bridge->bus->sysdata;
ACPI_HANDLE_SET(&bridge->dev, sd->acpi);
return 0;
}
int __init pci_acpi_init(void) int __init pci_acpi_init(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;

View File

@ -34,7 +34,6 @@ int noioapicreroute = 1;
#endif #endif
int pcibios_last_bus = -1; int pcibios_last_bus = -1;
unsigned long pirq_table_addr; unsigned long pirq_table_addr;
struct pci_bus *pci_root_bus;
const struct pci_raw_ops *__read_mostly raw_pci_ops; const struct pci_raw_ops *__read_mostly raw_pci_ops;
const struct pci_raw_ops *__read_mostly raw_pci_ext_ops; const struct pci_raw_ops *__read_mostly raw_pci_ext_ops;

View File

@ -51,6 +51,7 @@ struct pcibios_fwaddrmap {
static LIST_HEAD(pcibios_fwaddrmappings); static LIST_HEAD(pcibios_fwaddrmappings);
static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock); static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
static bool pcibios_fw_addr_done;
/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */ /* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev) static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
@ -72,6 +73,9 @@ pcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
unsigned long flags; unsigned long flags;
struct pcibios_fwaddrmap *map; struct pcibios_fwaddrmap *map;
if (pcibios_fw_addr_done)
return;
spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags); spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
map = pcibios_fwaddrmap_lookup(dev); map = pcibios_fwaddrmap_lookup(dev);
if (!map) { if (!map) {
@ -97,6 +101,9 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
struct pcibios_fwaddrmap *map; struct pcibios_fwaddrmap *map;
resource_size_t fw_addr = 0; resource_size_t fw_addr = 0;
if (pcibios_fw_addr_done)
return 0;
spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags); spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
map = pcibios_fwaddrmap_lookup(dev); map = pcibios_fwaddrmap_lookup(dev);
if (map) if (map)
@ -106,7 +113,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
return fw_addr; return fw_addr;
} }
static void pcibios_fw_addr_list_del(void) static void __init pcibios_fw_addr_list_del(void)
{ {
unsigned long flags; unsigned long flags;
struct pcibios_fwaddrmap *entry, *next; struct pcibios_fwaddrmap *entry, *next;
@ -118,6 +125,7 @@ static void pcibios_fw_addr_list_del(void)
kfree(entry); kfree(entry);
} }
spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags); spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
pcibios_fw_addr_done = true;
} }
static int static int
@ -193,46 +201,46 @@ EXPORT_SYMBOL(pcibios_align_resource);
* as well. * as well.
*/ */
static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
{ {
struct pci_bus *bus;
struct pci_dev *dev;
int idx; int idx;
struct resource *r; struct resource *r;
/* Depth-First Search on bus tree */ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
list_for_each_entry(bus, bus_list, node) { r = &dev->resource[idx];
if ((dev = bus->self)) { if (!r->flags)
for (idx = PCI_BRIDGE_RESOURCES; continue;
idx < PCI_NUM_RESOURCES; idx++) { if (!r->start || pci_claim_resource(dev, idx) < 0) {
r = &dev->resource[idx]; /*
if (!r->flags) * Something is wrong with the region.
continue; * Invalidate the resource to prevent
if (!r->start || * child resource allocations in this
pci_claim_resource(dev, idx) < 0) { * range.
/* */
* Something is wrong with the region. r->start = r->end = 0;
* Invalidate the resource to prevent r->flags = 0;
* child resource allocations in this
* range.
*/
r->start = r->end = 0;
r->flags = 0;
}
}
} }
pcibios_allocate_bus_resources(&bus->children);
} }
} }
static void pcibios_allocate_bus_resources(struct pci_bus *bus)
{
struct pci_bus *child;
/* Depth-First Search on bus tree */
if (bus->self)
pcibios_allocate_bridge_resources(bus->self);
list_for_each_entry(child, &bus->children, node)
pcibios_allocate_bus_resources(child);
}
struct pci_check_idx_range { struct pci_check_idx_range {
int start; int start;
int end; int end;
}; };
static void __init pcibios_allocate_resources(int pass) static void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
{ {
struct pci_dev *dev = NULL;
int idx, disabled, i; int idx, disabled, i;
u16 command; u16 command;
struct resource *r; struct resource *r;
@ -244,14 +252,13 @@ static void __init pcibios_allocate_resources(int pass)
#endif #endif
}; };
for_each_pci_dev(dev) { pci_read_config_word(dev, PCI_COMMAND, &command);
pci_read_config_word(dev, PCI_COMMAND, &command); for (i = 0; i < ARRAY_SIZE(idx_range); i++)
for (i = 0; i < ARRAY_SIZE(idx_range); i++)
for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) { for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
r = &dev->resource[idx]; r = &dev->resource[idx];
if (r->parent) /* Already allocated */ if (r->parent) /* Already allocated */
continue; continue;
if (!r->start) /* Address not assigned at all */ if (!r->start) /* Address not assigned at all */
continue; continue;
if (r->flags & IORESOURCE_IO) if (r->flags & IORESOURCE_IO)
disabled = !(command & PCI_COMMAND_IO); disabled = !(command & PCI_COMMAND_IO);
@ -270,44 +277,74 @@ static void __init pcibios_allocate_resources(int pass)
} }
} }
} }
if (!pass) { if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE]; r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & IORESOURCE_ROM_ENABLE) { if (r->flags & IORESOURCE_ROM_ENABLE) {
/* Turn the ROM off, leave the resource region, /* Turn the ROM off, leave the resource region,
* but keep it unregistered. */ * but keep it unregistered. */
u32 reg; u32 reg;
dev_dbg(&dev->dev, "disabling ROM %pR\n", r); dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
r->flags &= ~IORESOURCE_ROM_ENABLE; r->flags &= ~IORESOURCE_ROM_ENABLE;
pci_read_config_dword(dev, pci_read_config_dword(dev, dev->rom_base_reg, &reg);
dev->rom_base_reg, &reg); pci_write_config_dword(dev, dev->rom_base_reg,
pci_write_config_dword(dev, dev->rom_base_reg,
reg & ~PCI_ROM_ADDRESS_ENABLE); reg & ~PCI_ROM_ADDRESS_ENABLE);
}
} }
} }
} }
static void pcibios_allocate_resources(struct pci_bus *bus, int pass)
{
struct pci_dev *dev;
struct pci_bus *child;
list_for_each_entry(dev, &bus->devices, bus_list) {
pcibios_allocate_dev_resources(dev, pass);
child = dev->subordinate;
if (child)
pcibios_allocate_resources(child, pass);
}
}
static void pcibios_allocate_dev_rom_resource(struct pci_dev *dev)
{
struct resource *r;
/*
* Try to use BIOS settings for ROMs, otherwise let
* pci_assign_unassigned_resources() allocate the new
* addresses.
*/
r = &dev->resource[PCI_ROM_RESOURCE];
if (!r->flags || !r->start)
return;
if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
r->end -= r->start;
r->start = 0;
}
}
static void pcibios_allocate_rom_resources(struct pci_bus *bus)
{
struct pci_dev *dev;
struct pci_bus *child;
list_for_each_entry(dev, &bus->devices, bus_list) {
pcibios_allocate_dev_rom_resource(dev);
child = dev->subordinate;
if (child)
pcibios_allocate_rom_resources(child);
}
}
static int __init pcibios_assign_resources(void) static int __init pcibios_assign_resources(void)
{ {
struct pci_dev *dev = NULL; struct pci_bus *bus;
struct resource *r;
if (!(pci_probe & PCI_ASSIGN_ROMS)) { if (!(pci_probe & PCI_ASSIGN_ROMS))
/* list_for_each_entry(bus, &pci_root_buses, node)
* Try to use BIOS settings for ROMs, otherwise let pcibios_allocate_rom_resources(bus);
* pci_assign_unassigned_resources() allocate the new
* addresses.
*/
for_each_pci_dev(dev) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (!r->flags || !r->start)
continue;
if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
r->end -= r->start;
r->start = 0;
}
}
}
pci_assign_unassigned_resources(); pci_assign_unassigned_resources();
pcibios_fw_addr_list_del(); pcibios_fw_addr_list_del();
@ -315,12 +352,32 @@ static int __init pcibios_assign_resources(void)
return 0; return 0;
} }
void pcibios_resource_survey_bus(struct pci_bus *bus)
{
dev_printk(KERN_DEBUG, &bus->dev, "Allocating resources\n");
pcibios_allocate_bus_resources(bus);
pcibios_allocate_resources(bus, 0);
pcibios_allocate_resources(bus, 1);
if (!(pci_probe & PCI_ASSIGN_ROMS))
pcibios_allocate_rom_resources(bus);
}
void __init pcibios_resource_survey(void) void __init pcibios_resource_survey(void)
{ {
struct pci_bus *bus;
DBG("PCI: Allocating resources\n"); DBG("PCI: Allocating resources\n");
pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0); list_for_each_entry(bus, &pci_root_buses, node)
pcibios_allocate_resources(1); pcibios_allocate_bus_resources(bus);
list_for_each_entry(bus, &pci_root_buses, node)
pcibios_allocate_resources(bus, 0);
list_for_each_entry(bus, &pci_root_buses, node)
pcibios_allocate_resources(bus, 1);
e820_reserve_resources_late(); e820_reserve_resources_late();
/* /*

View File

@ -30,7 +30,7 @@ int __init pci_legacy_init(void)
} }
printk("PCI: Probing PCI hardware\n"); printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0); pcibios_scan_root(0);
return 0; return 0;
} }

View File

@ -152,7 +152,7 @@ int __init pci_numaq_init(void)
raw_pci_ops = &pci_direct_conf1_mq; raw_pci_ops = &pci_direct_conf1_mq;
pci_root_bus = pcibios_scan_root(0); pcibios_scan_root(0);
if (num_online_nodes() > 1) if (num_online_nodes() > 1)
for_each_online_node(quad) { for_each_online_node(quad) {
if (quad == 0) if (quad == 0)

View File

@ -306,7 +306,7 @@ config ACPI_DEBUG_FUNC_TRACE
is about half of the penalty and is rarely useful. is about half of the penalty and is rarely useful.
config ACPI_PCI_SLOT config ACPI_PCI_SLOT
tristate "PCI slot detection driver" bool "PCI slot detection driver"
depends on SYSFS depends on SYSFS
default n default n
help help
@ -315,9 +315,6 @@ config ACPI_PCI_SLOT
i.e., segment/bus/device/function tuples, with physical slots in i.e., segment/bus/device/function tuples, with physical slots in
the system. If you are unsure, say N. the system. If you are unsure, say N.
To compile this driver as a module, choose M here:
the module will be called pci_slot.
config X86_PM_TIMER config X86_PM_TIMER
bool "Power Management Timer Support" if EXPERT bool "Power Management Timer Support" if EXPERT
depends on X86 depends on X86

View File

@ -25,8 +25,14 @@
int init_acpi_device_notify(void); int init_acpi_device_notify(void);
int acpi_scan_init(void); int acpi_scan_init(void);
#ifdef CONFIG_ACPI_PCI_SLOT
void acpi_pci_slot_init(void);
#else
static inline void acpi_pci_slot_init(void) { }
#endif
void acpi_pci_root_init(void); void acpi_pci_root_init(void);
void acpi_pci_link_init(void); void acpi_pci_link_init(void);
void acpi_pci_root_hp_init(void);
void acpi_platform_init(void); void acpi_platform_init(void);
int acpi_sysfs_init(void); int acpi_sysfs_init(void);
void acpi_csrt_init(void); void acpi_csrt_init(void);

View File

@ -84,8 +84,7 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context; static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq; static struct workqueue_struct *kacpi_notify_wq;
struct workqueue_struct *kacpi_hotplug_wq; static struct workqueue_struct *kacpi_hotplug_wq;
EXPORT_SYMBOL(kacpi_hotplug_wq);
/* /*
* This list of permanent mappings is for memory that may be accessed from * This list of permanent mappings is for memory that may be accessed from
@ -1778,3 +1777,24 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
{ {
__acpi_os_prepare_sleep = func; __acpi_os_prepare_sleep = func;
} }
void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
void (*func)(struct work_struct *work))
{
struct acpi_hp_work *hp_work;
int ret;
hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
if (!hp_work)
return;
hp_work->handle = handle;
hp_work->type = type;
hp_work->context = context;
INIT_WORK(&hp_work->work, func);
ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
if (!ret)
kfree(hp_work);
}
EXPORT_SYMBOL_GPL(alloc_acpi_hp_work);

View File

@ -53,9 +53,6 @@ struct acpi_prt_entry {
u32 index; /* GSI, or link _CRS index */ u32 index; /* GSI, or link _CRS index */
}; };
static LIST_HEAD(acpi_prt_list);
static DEFINE_SPINLOCK(acpi_prt_lock);
static inline char pin_name(int pin) static inline char pin_name(int pin)
{ {
return 'A' + pin - 1; return 'A' + pin - 1;
@ -65,28 +62,6 @@ static inline char pin_name(int pin)
PCI IRQ Routing Table (PRT) Support PCI IRQ Routing Table (PRT) Support
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
int pin)
{
struct acpi_prt_entry *entry;
int segment = pci_domain_nr(dev->bus);
int bus = dev->bus->number;
int device = PCI_SLOT(dev->devfn);
spin_lock(&acpi_prt_lock);
list_for_each_entry(entry, &acpi_prt_list, list) {
if ((segment == entry->id.segment)
&& (bus == entry->id.bus)
&& (device == entry->id.device)
&& (pin == entry->pin)) {
spin_unlock(&acpi_prt_lock);
return entry;
}
}
spin_unlock(&acpi_prt_lock);
return NULL;
}
/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ /* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */
static const struct dmi_system_id medion_md9580[] = { static const struct dmi_system_id medion_md9580[] = {
{ {
@ -184,11 +159,19 @@ static void do_prt_fixups(struct acpi_prt_entry *entry,
} }
} }
static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
struct acpi_pci_routing_table *prt) int pin, struct acpi_pci_routing_table *prt,
struct acpi_prt_entry **entry_ptr)
{ {
int segment = pci_domain_nr(dev->bus);
int bus = dev->bus->number;
int device = PCI_SLOT(dev->devfn);
struct acpi_prt_entry *entry; struct acpi_prt_entry *entry;
if (((prt->address >> 16) & 0xffff) != device ||
prt->pin + 1 != pin)
return -ENODEV;
entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
if (!entry) if (!entry)
return -ENOMEM; return -ENOMEM;
@ -237,43 +220,37 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
entry->id.device, pin_name(entry->pin), entry->id.device, pin_name(entry->pin),
prt->source, entry->index)); prt->source, entry->index));
spin_lock(&acpi_prt_lock); *entry_ptr = entry;
list_add_tail(&entry->list, &acpi_prt_list);
spin_unlock(&acpi_prt_lock);
return 0; return 0;
} }
int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
int pin, struct acpi_prt_entry **entry_ptr)
{ {
acpi_status status; acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_pci_routing_table *entry; struct acpi_pci_routing_table *entry;
acpi_handle handle = NULL;
/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ if (dev->bus->bridge)
status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); handle = ACPI_HANDLE(dev->bus->bridge);
if (ACPI_FAILURE(status))
if (!handle)
return -ENODEV; return -ENODEV;
printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
(char *) buffer.pointer);
kfree(buffer.pointer);
buffer.length = ACPI_ALLOCATE_BUFFER;
buffer.pointer = NULL;
status = acpi_get_irq_routing_table(handle, &buffer); status = acpi_get_irq_routing_table(handle, &buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
acpi_format_exception(status)));
kfree(buffer.pointer); kfree(buffer.pointer);
return -ENODEV; return -ENODEV;
} }
entry = buffer.pointer; entry = buffer.pointer;
while (entry && (entry->length > 0)) { while (entry && (entry->length > 0)) {
acpi_pci_irq_add_entry(handle, segment, bus, entry); if (!acpi_pci_irq_check_entry(handle, dev, pin,
entry, entry_ptr))
break;
entry = (struct acpi_pci_routing_table *) entry = (struct acpi_pci_routing_table *)
((unsigned long)entry + entry->length); ((unsigned long)entry + entry->length);
} }
@ -282,23 +259,6 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
return 0; return 0;
} }
void acpi_pci_irq_del_prt(int segment, int bus)
{
struct acpi_prt_entry *entry, *tmp;
printk(KERN_DEBUG
"ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
segment, bus);
spin_lock(&acpi_prt_lock);
list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) {
if (segment == entry->id.segment && bus == entry->id.bus) {
list_del(&entry->list);
kfree(entry);
}
}
spin_unlock(&acpi_prt_lock);
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
PCI Interrupt Routing Support PCI Interrupt Routing Support
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
@ -359,12 +319,13 @@ static int acpi_reroute_boot_interrupt(struct pci_dev *dev,
static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
{ {
struct acpi_prt_entry *entry; struct acpi_prt_entry *entry = NULL;
struct pci_dev *bridge; struct pci_dev *bridge;
u8 bridge_pin, orig_pin = pin; u8 bridge_pin, orig_pin = pin;
int ret;
entry = acpi_pci_irq_find_prt_entry(dev, pin); ret = acpi_pci_irq_find_prt_entry(dev, pin, &entry);
if (entry) { if (!ret && entry) {
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
acpi_reroute_boot_interrupt(dev, entry); acpi_reroute_boot_interrupt(dev, entry);
#endif /* CONFIG_X86_IO_APIC */ #endif /* CONFIG_X86_IO_APIC */
@ -373,7 +334,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
return entry; return entry;
} }
/* /*
* Attempt to derive an IRQ for this device from a parent bridge's * Attempt to derive an IRQ for this device from a parent bridge's
* PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge).
*/ */
@ -393,8 +354,8 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
pin = bridge_pin; pin = bridge_pin;
} }
entry = acpi_pci_irq_find_prt_entry(bridge, pin); ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry);
if (entry) { if (!ret && entry) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Derived GSI for %s INT %c from %s\n", "Derived GSI for %s INT %c from %s\n",
pci_name(dev), pin_name(orig_pin), pci_name(dev), pin_name(orig_pin),
@ -470,6 +431,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
dev_warn(&dev->dev, "PCI INT %c: no GSI\n", dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
pin_name(pin)); pin_name(pin));
} }
return 0; return 0;
} }
@ -477,6 +439,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
if (rc < 0) { if (rc < 0) {
dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
pin_name(pin)); pin_name(pin));
kfree(entry);
return rc; return rc;
} }
dev->irq = rc; dev->irq = rc;
@ -491,6 +454,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
(triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
(polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
kfree(entry);
return 0; return 0;
} }
@ -513,6 +477,8 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
else else
gsi = entry->index; gsi = entry->index;
kfree(entry);
/* /*
* TBD: It might be worth clearing dev->irq by magic constant * TBD: It might be worth clearing dev->irq by magic constant
* (e.g. PCI_UNDEFINED_IRQ). * (e.g. PCI_UNDEFINED_IRQ).

View File

@ -103,24 +103,6 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
} }
EXPORT_SYMBOL(acpi_pci_unregister_driver); EXPORT_SYMBOL(acpi_pci_unregister_driver);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
{
struct acpi_pci_root *root;
acpi_handle handle = NULL;
mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(root, &acpi_pci_roots, node)
if ((root->segment == (u16) seg) &&
(root->secondary.start == (u16) bus)) {
handle = root->device->handle;
break;
}
mutex_unlock(&acpi_pci_root_lock);
return handle;
}
EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
/** /**
* acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
* @handle - the ACPI CA node in question. * @handle - the ACPI CA node in question.
@ -431,7 +413,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
acpi_status status; acpi_status status;
int result; int result;
struct acpi_pci_root *root; struct acpi_pci_root *root;
acpi_handle handle;
struct acpi_pci_driver *driver; struct acpi_pci_driver *driver;
u32 flags, base_flags; u32 flags, base_flags;
bool is_osc_granted = false; bool is_osc_granted = false;
@ -486,16 +467,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
acpi_device_name(device), acpi_device_bid(device), acpi_device_name(device), acpi_device_bid(device),
root->segment, &root->secondary); root->segment, &root->secondary);
/*
* PCI Routing Table
* -----------------
* Evaluate and parse _PRT, if exists.
*/
status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status))
result = acpi_pci_irq_add_prt(device->handle, root->segment,
root->secondary.start);
root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle); root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle);
/* /*
@ -597,8 +568,10 @@ static int acpi_pci_root_add(struct acpi_device *device,
if (device->wakeup.flags.run_wake) if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true); device_set_run_wake(root->bus->bridge, true);
if (system_state != SYSTEM_BOOTING) if (system_state != SYSTEM_BOOTING) {
pcibios_resource_survey_bus(root->bus);
pci_assign_unassigned_bus_resources(root->bus); pci_assign_unassigned_bus_resources(root->bus);
}
mutex_lock(&acpi_pci_root_lock); mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(driver, &acpi_pci_drivers, node) list_for_each_entry(driver, &acpi_pci_drivers, node)
@ -618,7 +591,6 @@ out_del_root:
list_del(&root->node); list_del(&root->node);
mutex_unlock(&acpi_pci_root_lock); mutex_unlock(&acpi_pci_root_lock);
acpi_pci_irq_del_prt(root->segment, root->secondary.start);
end: end:
kfree(root); kfree(root);
return result; return result;
@ -626,8 +598,6 @@ end:
static void acpi_pci_root_remove(struct acpi_device *device) static void acpi_pci_root_remove(struct acpi_device *device)
{ {
acpi_status status;
acpi_handle handle;
struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_root *root = acpi_driver_data(device);
struct acpi_pci_driver *driver; struct acpi_pci_driver *driver;
@ -642,10 +612,6 @@ static void acpi_pci_root_remove(struct acpi_device *device)
device_set_run_wake(root->bus->bridge, false); device_set_run_wake(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device); pci_acpi_remove_bus_pm_notifier(device);
status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status))
acpi_pci_irq_del_prt(root->segment, root->secondary.start);
pci_remove_root_bus(root->bus); pci_remove_root_bus(root->bus);
mutex_lock(&acpi_pci_root_lock); mutex_lock(&acpi_pci_root_lock);
@ -663,3 +629,133 @@ void __init acpi_pci_root_init(void)
acpi_scan_add_handler(&pci_root_handler); acpi_scan_add_handler(&pci_root_handler);
} }
} }
/* Support root bridge hotplug */
static void handle_root_bridge_insertion(acpi_handle handle)
{
struct acpi_device *device;
if (!acpi_bus_get_device(handle, &device)) {
printk(KERN_DEBUG "acpi device exists...\n");
return;
}
if (acpi_bus_scan(handle))
printk(KERN_ERR "cannot add bridge to acpi list\n");
}
static void handle_root_bridge_removal(struct acpi_device *device)
{
struct acpi_eject_event *ej_event;
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
/* Inform firmware the hot-remove operation has error */
(void) acpi_evaluate_hotplug_ost(device->handle,
ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
NULL);
return;
}
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
acpi_bus_hot_remove_device(ej_event);
}
static void _handle_hotplug_event_root(struct work_struct *work)
{
struct acpi_pci_root *root;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
struct acpi_hp_work *hp_work;
acpi_handle handle;
u32 type;
hp_work = container_of(work, struct acpi_hp_work, work);
handle = hp_work->handle;
type = hp_work->type;
root = acpi_pci_find_root(handle);
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus enumerate */
printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
(char *)buffer.pointer);
if (!root)
handle_root_bridge_insertion(handle);
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
(char *)buffer.pointer);
if (!root)
handle_root_bridge_insertion(handle);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
(char *)buffer.pointer);
if (root)
handle_root_bridge_removal(root->device);
break;
default:
printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
type, (char *)buffer.pointer);
break;
}
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
kfree(buffer.pointer);
}
static void handle_hotplug_event_root(acpi_handle handle, u32 type,
void *context)
{
alloc_acpi_hp_work(handle, type, context,
_handle_hotplug_event_root);
}
static acpi_status __init
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
int *count = (int *)context;
if (!acpi_is_root_bridge(handle))
return AE_OK;
(*count)++;
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_root, NULL);
if (ACPI_FAILURE(status))
printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n",
objname, (unsigned int)status);
else
printk(KERN_DEBUG "acpi root: %s notify handler is installed\n",
objname);
return AE_OK;
}
void __init acpi_pci_root_hp_init(void)
{
int num = 0;
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
printk(KERN_DEBUG "Found %d acpi root devices\n", num);
}

View File

@ -329,19 +329,8 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
{} {}
}; };
static int __init void __init acpi_pci_slot_init(void)
acpi_pci_slot_init(void)
{ {
dmi_check_system(acpi_pci_slot_dmi_table); dmi_check_system(acpi_pci_slot_dmi_table);
acpi_pci_register_driver(&acpi_pci_slot_driver); acpi_pci_register_driver(&acpi_pci_slot_driver);
return 0;
} }
static void __exit
acpi_pci_slot_exit(void)
{
acpi_pci_unregister_driver(&acpi_pci_slot_driver);
}
module_init(acpi_pci_slot_init);
module_exit(acpi_pci_slot_exit);

View File

@ -1783,6 +1783,7 @@ int __init acpi_scan_init(void)
acpi_platform_init(); acpi_platform_init();
acpi_csrt_init(); acpi_csrt_init();
acpi_container_init(); acpi_container_init();
acpi_pci_slot_init();
mutex_lock(&acpi_scan_lock); mutex_lock(&acpi_scan_lock);
/* /*
@ -1804,6 +1805,8 @@ int __init acpi_scan_init(void)
acpi_update_all_gpes(); acpi_update_all_gpes();
acpi_pci_root_hp_init();
out: out:
mutex_unlock(&acpi_scan_lock); mutex_unlock(&acpi_scan_lock);
return result; return result;

View File

@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
static inline int pcie_cap_version(const struct pci_dev *dev) static inline int pcie_cap_version(const struct pci_dev *dev)
{ {
return dev->pcie_flags_reg & PCI_EXP_FLAGS_VERS; return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
} }
static inline bool pcie_cap_has_devctl(const struct pci_dev *dev) static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
@ -497,7 +497,7 @@ static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
return pcie_cap_version(dev) > 1 || return pcie_cap_version(dev) > 1 ||
type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ROOT_PORT ||
(type == PCI_EXP_TYPE_DOWNSTREAM && (type == PCI_EXP_TYPE_DOWNSTREAM &&
dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT); pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT);
} }
static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev) static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
@ -515,7 +515,7 @@ static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
return false; return false;
switch (pos) { switch (pos) {
case PCI_EXP_FLAGS_TYPE: case PCI_EXP_FLAGS:
return true; return true;
case PCI_EXP_DEVCAP: case PCI_EXP_DEVCAP:
case PCI_EXP_DEVCTL: case PCI_EXP_DEVCTL:

View File

@ -158,69 +158,38 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
return ret; return ret;
} }
void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
/** /**
* pci_bus_add_device - add a single device * pci_bus_add_device - start driver for a single device
* @dev: device to add * @dev: device to add
* *
* This adds a single pci device to the global * This adds add sysfs entries and start device drivers
* device list and adds sysfs and procfs entries
*/ */
int pci_bus_add_device(struct pci_dev *dev) int pci_bus_add_device(struct pci_dev *dev)
{ {
int retval; int retval;
pci_fixup_device(pci_fixup_final, dev); /*
* Can not put in pci_device_add yet because resources
* are not assigned yet for some devices.
*/
pci_create_sysfs_dev_files(dev);
retval = pcibios_add_device(dev); dev->match_driver = true;
if (retval) retval = device_attach(&dev->dev);
return retval; WARN_ON(retval < 0);
retval = device_add(&dev->dev);
if (retval)
return retval;
dev->is_added = 1; dev->is_added = 1;
pci_proc_attach_device(dev);
pci_create_sysfs_dev_files(dev);
return 0; return 0;
} }
/** /**
* pci_bus_add_child - add a child bus * pci_bus_add_devices - start driver for PCI devices
* @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;
/* 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
* @bus: bus to check for new devices * @bus: bus to check for new devices
* *
* Add newly discovered PCI devices (which are on the bus->devices * Start driver for PCI devices and add some sysfs entries.
* list) to the global PCI device list, add the sysfs and procfs
* entries. Where a bridge is found, add the discovered bus to
* the parents list of child buses, and recurse (breadth-first
* to be compatible with 2.4)
*
* Call hotplug for each new devices.
*/ */
void pci_bus_add_devices(const struct pci_bus *bus) void pci_bus_add_devices(const struct pci_bus *bus)
{ {
@ -233,36 +202,20 @@ void pci_bus_add_devices(const struct pci_bus *bus)
if (dev->is_added) if (dev->is_added)
continue; continue;
retval = pci_bus_add_device(dev); retval = pci_bus_add_device(dev);
if (retval)
dev_err(&dev->dev, "Error adding device, continuing\n");
} }
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; child = dev->subordinate;
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
if (!child) if (!child)
continue; continue;
if (list_empty(&child->node)) {
down_write(&pci_bus_sem);
list_add_tail(&child->node, &dev->bus->children);
up_write(&pci_bus_sem);
}
pci_bus_add_devices(child); pci_bus_add_devices(child);
/*
* register the bus with sysfs as the parent is now
* properly registered.
*/
if (child->is_added) if (child->is_added)
continue; continue;
retval = pci_bus_add_child(child); child->is_added = 1;
if (retval)
dev_err(&dev->dev, "Error adding bus, continuing\n");
} }
} }

View File

@ -79,7 +79,6 @@ struct acpiphp_bridge {
/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
struct acpiphp_func *func; struct acpiphp_func *func;
int type;
int nr_slots; int nr_slots;
u32 flags; u32 flags;
@ -146,10 +145,6 @@ struct acpiphp_attention_info
/* PCI bus bridge HID */ /* PCI bus bridge HID */
#define ACPI_PCI_HOST_HID "PNP0A03" #define ACPI_PCI_HOST_HID "PNP0A03"
/* PCI BRIDGE type */
#define BRIDGE_TYPE_HOST 0
#define BRIDGE_TYPE_P2P 1
/* ACPI _STA method value (ignore bit 4; battery present) */ /* ACPI _STA method value (ignore bit 4; battery present) */
#define ACPI_STA_PRESENT (0x00000001) #define ACPI_STA_PRESENT (0x00000001)
#define ACPI_STA_ENABLED (0x00000002) #define ACPI_STA_ENABLED (0x00000002)
@ -158,13 +153,7 @@ struct acpiphp_attention_info
#define ACPI_STA_ALL (0x0000000f) #define ACPI_STA_ALL (0x0000000f)
/* bridge flags */ /* bridge flags */
#define BRIDGE_HAS_STA (0x00000001) #define BRIDGE_HAS_EJ0 (0x00000001)
#define BRIDGE_HAS_EJ0 (0x00000002)
#define BRIDGE_HAS_HPP (0x00000004)
#define BRIDGE_HAS_PS0 (0x00000010)
#define BRIDGE_HAS_PS1 (0x00000020)
#define BRIDGE_HAS_PS2 (0x00000040)
#define BRIDGE_HAS_PS3 (0x00000080)
/* slot flags */ /* slot flags */
@ -193,7 +182,6 @@ extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
/* acpiphp_glue.c */ /* acpiphp_glue.c */
extern int acpiphp_glue_init (void); extern int acpiphp_glue_init (void);
extern void acpiphp_glue_exit (void); extern void acpiphp_glue_exit (void);
extern int acpiphp_get_num_slots (void);
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
extern int acpiphp_enable_slot (struct acpiphp_slot *slot); extern int acpiphp_enable_slot (struct acpiphp_slot *slot);

View File

@ -50,7 +50,6 @@
bool acpiphp_debug; bool acpiphp_debug;
/* local variables */ /* local variables */
static int num_slots;
static struct acpiphp_attention_info *attention_info; static struct acpiphp_attention_info *attention_info;
#define DRIVER_VERSION "0.5" #define DRIVER_VERSION "0.5"
@ -272,25 +271,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0; return 0;
} }
static int __init init_acpi(void)
{
int retval;
/* initialize internal data structure etc. */
retval = acpiphp_glue_init();
/* read initial number of slots */
if (!retval) {
num_slots = acpiphp_get_num_slots();
if (num_slots == 0) {
acpiphp_glue_exit();
retval = -ENODEV;
}
}
return retval;
}
/** /**
* release_slot - free up the memory used by a slot * release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free * @hotplug_slot: slot to free
@ -379,7 +359,8 @@ static int __init acpiphp_init(void)
return 0; return 0;
/* read all the ACPI info from the system */ /* read all the ACPI info from the system */
return init_acpi(); /* initialize internal data structure etc. */
return acpiphp_glue_init();
} }

View File

@ -325,8 +325,8 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
return; return;
} }
/* install notify handler */ /* install notify handler for P2P bridges */
if (bridge->type != BRIDGE_TYPE_HOST) { if (!pci_is_root_bus(bridge->pci_bus)) {
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
status = acpi_remove_notify_handler(bridge->func->handle, status = acpi_remove_notify_handler(bridge->func->handle,
ACPI_SYSTEM_NOTIFY, ACPI_SYSTEM_NOTIFY,
@ -369,27 +369,12 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle
static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
{ {
acpi_handle dummy_handle; acpi_handle dummy_handle;
struct acpiphp_func *func;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_STA", &dummy_handle))) "_EJ0", &dummy_handle))) {
bridge->flags |= BRIDGE_HAS_STA;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_EJ0", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_EJ0; bridge->flags |= BRIDGE_HAS_EJ0;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_PS0", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_PS0;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_PS3", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_PS3;
/* is this ejectable p2p bridge? */
if (bridge->flags & BRIDGE_HAS_EJ0) {
struct acpiphp_func *func;
dbg("found ejectable p2p bridge\n"); dbg("found ejectable p2p bridge\n");
/* make link between PCI bridge and PCI function */ /* make link between PCI bridge and PCI function */
@ -412,7 +397,6 @@ static void add_host_bridge(struct acpi_pci_root *root)
if (bridge == NULL) if (bridge == NULL)
return; return;
bridge->type = BRIDGE_TYPE_HOST;
bridge->handle = handle; bridge->handle = handle;
bridge->pci_bus = root->bus; bridge->pci_bus = root->bus;
@ -432,7 +416,6 @@ static void add_p2p_bridge(acpi_handle *handle)
return; return;
} }
bridge->type = BRIDGE_TYPE_P2P;
bridge->handle = handle; bridge->handle = handle;
config_p2p_bridge_flags(bridge); config_p2p_bridge_flags(bridge);
@ -543,13 +526,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
acpi_status status; acpi_status status;
acpi_handle handle = bridge->handle; acpi_handle handle = bridge->handle;
status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, if (!pci_is_root_bus(bridge->pci_bus)) {
status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge); handle_hotplug_event_bridge);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
err("failed to remove notify handler\n"); err("failed to remove notify handler\n");
}
if ((bridge->type != BRIDGE_TYPE_HOST) && if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
status = acpi_install_notify_handler(bridge->func->handle, status = acpi_install_notify_handler(bridge->func->handle,
ACPI_SYSTEM_NOTIFY, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func, handle_hotplug_event_func,
@ -630,9 +615,6 @@ static void remove_bridge(struct acpi_pci_root *root)
bridge = acpiphp_handle_to_bridge(handle); bridge = acpiphp_handle_to_bridge(handle);
if (bridge) if (bridge)
cleanup_bridge(bridge); cleanup_bridge(bridge);
else
acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge);
} }
static int power_on_slot(struct acpiphp_slot *slot) static int power_on_slot(struct acpiphp_slot *slot)
@ -793,6 +775,29 @@ static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
} }
} }
static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
{
struct acpiphp_func *func;
if (!dev->subordinate)
return;
/* quirk, or pcie could set it already */
if (dev->is_hotplug_bridge)
return;
if (PCI_SLOT(dev->devfn) != slot->device)
return;
list_for_each_entry(func, &slot->funcs, sibling) {
if (PCI_FUNC(dev->devfn) == func->function) {
/* check if this bridge has ejectable slots */
if ((detect_ejectable_slots(func->handle) > 0))
dev->is_hotplug_bridge = 1;
break;
}
}
}
/** /**
* enable_device - enable, configure a slot * enable_device - enable, configure a slot
* @slot: slot to be enabled * @slot: slot to be enabled
@ -812,6 +817,9 @@ static int __ref enable_device(struct acpiphp_slot *slot)
if (slot->flags & SLOT_ENABLED) if (slot->flags & SLOT_ENABLED)
goto err_exit; goto err_exit;
list_for_each_entry(func, &slot->funcs, sibling)
acpiphp_bus_add(func);
num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
if (num == 0) { if (num == 0) {
/* Maybe only part of funcs are added. */ /* Maybe only part of funcs are added. */
@ -827,15 +835,14 @@ static int __ref enable_device(struct acpiphp_slot *slot)
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
max = pci_scan_bridge(bus, dev, max, pass); max = pci_scan_bridge(bus, dev, max, pass);
if (pass && dev->subordinate) if (pass && dev->subordinate) {
check_hotplug_bridge(slot, dev);
pci_bus_size_bridges(dev->subordinate); pci_bus_size_bridges(dev->subordinate);
}
} }
} }
} }
list_for_each_entry(func, &slot->funcs, sibling)
acpiphp_bus_add(func);
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus); acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus); acpiphp_set_hpp_values(bus);
@ -1093,69 +1100,10 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
} }
} }
/* Program resources in newly inserted bridge */
static int acpiphp_configure_bridge (acpi_handle handle)
{
struct pci_bus *bus;
if (acpi_is_root_bridge(handle)) {
struct acpi_pci_root *root = acpi_pci_find_root(handle);
bus = root->bus;
} else {
struct pci_dev *pdev = acpi_get_pci_dev(handle);
bus = pdev->subordinate;
pci_dev_put(pdev);
}
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus);
pci_enable_bridges(bus);
return 0;
}
static void handle_bridge_insertion(acpi_handle handle, u32 type)
{
struct acpi_device *device;
if ((type != ACPI_NOTIFY_BUS_CHECK) &&
(type != ACPI_NOTIFY_DEVICE_CHECK)) {
err("unexpected notification type %d\n", type);
return;
}
if (acpi_bus_scan(handle)) {
err("cannot add bridge to acpi list\n");
return;
}
if (acpi_bus_get_device(handle, &device)) {
err("ACPI device object missing\n");
return;
}
if (!acpiphp_configure_bridge(handle))
add_bridge(handle);
else
err("cannot configure and start bridge\n");
}
/* /*
* ACPI event handlers * ACPI event handlers
*/ */
static acpi_status
count_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int *count = (int *)context;
struct acpiphp_bridge *bridge;
bridge = acpiphp_handle_to_bridge(handle);
if (bridge)
(*count)++;
return AE_OK ;
}
static acpi_status static acpi_status
check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{ {
@ -1174,83 +1122,33 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK ; return AE_OK ;
} }
struct acpiphp_hp_work {
struct work_struct work;
acpi_handle handle;
u32 type;
void *context;
};
static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
void *context,
void (*func)(struct work_struct *work))
{
struct acpiphp_hp_work *hp_work;
int ret;
hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
if (!hp_work)
return;
hp_work->handle = handle;
hp_work->type = type;
hp_work->context = context;
INIT_WORK(&hp_work->work, func);
ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
if (!ret)
kfree(hp_work);
}
static void _handle_hotplug_event_bridge(struct work_struct *work) static void _handle_hotplug_event_bridge(struct work_struct *work)
{ {
struct acpiphp_bridge *bridge; struct acpiphp_bridge *bridge;
char objname[64]; char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname), struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname }; .pointer = objname };
struct acpi_device *device; struct acpi_hp_work *hp_work;
int num_sub_bridges = 0;
struct acpiphp_hp_work *hp_work;
acpi_handle handle; acpi_handle handle;
u32 type; u32 type;
hp_work = container_of(work, struct acpiphp_hp_work, work); hp_work = container_of(work, struct acpi_hp_work, work);
handle = hp_work->handle; handle = hp_work->handle;
type = hp_work->type; type = hp_work->type;
bridge = (struct acpiphp_bridge *)hp_work->context;
acpi_scan_lock_acquire(); acpi_scan_lock_acquire();
if (acpi_bus_get_device(handle, &device)) {
/* This bridge must have just been physically inserted */
handle_bridge_insertion(handle, type);
goto out;
}
bridge = acpiphp_handle_to_bridge(handle);
if (type == ACPI_NOTIFY_BUS_CHECK) {
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
count_sub_bridges, NULL, &num_sub_bridges, NULL);
}
if (!bridge && !num_sub_bridges) {
err("cannot get bridge info\n");
goto out;
}
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */ /* bus re-enumerate */
dbg("%s: Bus check notify on %s\n", __func__, objname); dbg("%s: Bus check notify on %s\n", __func__, objname);
if (bridge) { dbg("%s: re-enumerating slots under %s\n", __func__, objname);
dbg("%s: re-enumerating slots under %s\n", acpiphp_check_bridge(bridge);
__func__, objname); acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
acpiphp_check_bridge(bridge); ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
}
if (num_sub_bridges)
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
break; break;
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
@ -1267,8 +1165,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */ /* request device eject */
dbg("%s: Device eject notify on %s\n", __func__, objname); dbg("%s: Device eject notify on %s\n", __func__, objname);
if ((bridge->type != BRIDGE_TYPE_HOST) && if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
(bridge->flags & BRIDGE_HAS_EJ0)) {
struct acpiphp_slot *slot; struct acpiphp_slot *slot;
slot = bridge->func->slot; slot = bridge->func->slot;
if (!acpiphp_disable_slot(slot)) if (!acpiphp_disable_slot(slot))
@ -1296,7 +1193,6 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
break; break;
} }
out:
acpi_scan_lock_release(); acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
} }
@ -1320,8 +1216,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
* For now just re-add this work to the kacpi_hotplug_wq so we * For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions. * don't deadlock on hotplug actions.
*/ */
alloc_acpiphp_hp_work(handle, type, context, alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
_handle_hotplug_event_bridge);
} }
static void _handle_hotplug_event_func(struct work_struct *work) static void _handle_hotplug_event_func(struct work_struct *work)
@ -1330,22 +1225,19 @@ static void _handle_hotplug_event_func(struct work_struct *work)
char objname[64]; char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname), struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname }; .pointer = objname };
struct acpiphp_hp_work *hp_work; struct acpi_hp_work *hp_work;
acpi_handle handle; acpi_handle handle;
u32 type; u32 type;
void *context;
hp_work = container_of(work, struct acpiphp_hp_work, work); hp_work = container_of(work, struct acpi_hp_work, work);
handle = hp_work->handle; handle = hp_work->handle;
type = hp_work->type; type = hp_work->type;
context = hp_work->context; func = (struct acpiphp_func *)hp_work->context;
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
func = (struct acpiphp_func *)context;
acpi_scan_lock_acquire(); acpi_scan_lock_acquire();
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */ /* bus re-enumerate */
@ -1399,23 +1291,7 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
* For now just re-add this work to the kacpi_hotplug_wq so we * For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions. * don't deadlock on hotplug actions.
*/ */
alloc_acpiphp_hp_work(handle, type, context, alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
_handle_hotplug_event_func);
}
static acpi_status
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int *count = (int *)context;
if (!acpi_is_root_bridge(handle))
return AE_OK;
(*count)++;
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge, NULL);
return AE_OK ;
} }
static struct acpi_pci_driver acpi_pci_hp_driver = { static struct acpi_pci_driver acpi_pci_hp_driver = {
@ -1428,15 +1304,7 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
*/ */
int __init acpiphp_glue_init(void) int __init acpiphp_glue_init(void)
{ {
int num = 0; acpi_pci_register_driver(&acpi_pci_hp_driver);
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
if (num <= 0)
return -1;
else
acpi_pci_register_driver(&acpi_pci_hp_driver);
return 0; return 0;
} }
@ -1452,28 +1320,6 @@ void acpiphp_glue_exit(void)
acpi_pci_unregister_driver(&acpi_pci_hp_driver); acpi_pci_unregister_driver(&acpi_pci_hp_driver);
} }
/**
* acpiphp_get_num_slots - count number of slots in a system
*/
int __init acpiphp_get_num_slots(void)
{
struct acpiphp_bridge *bridge;
int num_slots = 0;
list_for_each_entry(bridge, &bridge_list, list) {
dbg("Bus %04x:%02x has %d slot%s\n",
pci_domain_nr(bridge->pci_bus),
bridge->pci_bus->number, bridge->nr_slots,
bridge->nr_slots == 1 ? "" : "s");
num_slots += bridge->nr_slots;
}
dbg("Total %d slots\n", num_slots);
return num_slots;
}
/** /**
* acpiphp_enable_slot - power on slot * acpiphp_enable_slot - power on slot
* @slot: ACPI PHP slot * @slot: ACPI PHP slot

View File

@ -252,8 +252,8 @@ int cpci_led_off(struct slot* slot)
int __ref cpci_configure_slot(struct slot *slot) int __ref cpci_configure_slot(struct slot *slot)
{ {
struct pci_dev *dev;
struct pci_bus *parent; struct pci_bus *parent;
int fn;
dbg("%s - enter", __func__); dbg("%s - enter", __func__);
@ -282,18 +282,13 @@ int __ref cpci_configure_slot(struct slot *slot)
} }
parent = slot->dev->bus; parent = slot->dev->bus;
for (fn = 0; fn < 8; fn++) { list_for_each_entry(dev, &parent->devices, bus_list)
struct pci_dev *dev; if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
dev = pci_get_slot(parent,
PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
if (!dev)
continue; continue;
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
pci_hp_add_bridge(dev); pci_hp_add_bridge(dev);
pci_dev_put(dev);
}
pci_assign_unassigned_bridge_resources(parent->self); pci_assign_unassigned_bridge_resources(parent->self);
@ -305,8 +300,7 @@ int __ref cpci_configure_slot(struct slot *slot)
int cpci_unconfigure_slot(struct slot* slot) int cpci_unconfigure_slot(struct slot* slot)
{ {
int i; struct pci_dev *dev, *temp;
struct pci_dev *dev;
dbg("%s - enter", __func__); dbg("%s - enter", __func__);
if (!slot->dev) { if (!slot->dev) {
@ -314,13 +308,12 @@ int cpci_unconfigure_slot(struct slot* slot)
return -ENODEV; return -ENODEV;
} }
for (i = 0; i < 8; i++) { list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
dev = pci_get_slot(slot->bus, if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
PCI_DEVFN(PCI_SLOT(slot->devfn), i)); continue;
if (dev) { pci_dev_get(dev);
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev); pci_dev_put(dev);
}
} }
pci_dev_put(slot->dev); pci_dev_put(slot->dev);
slot->dev = NULL; slot->dev = NULL;

View File

@ -1900,8 +1900,7 @@ static void interrupt_event_handler(struct controller *ctrl)
dbg("power fault\n"); dbg("power fault\n");
} else { } else {
/* refresh notification */ /* refresh notification */
if (p_slot) update_slot_info(ctrl, p_slot);
update_slot_info(ctrl, p_slot);
} }
ctrl->event_queue[loop].event_type = 0; ctrl->event_queue[loop].event_type = 0;
@ -2520,44 +2519,28 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
/* If we have IO resources copy them and fill in the bridge's /* If we have IO resources copy them and fill in the bridge's
* IO range registers */ * IO range registers */
if (io_node) { memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); io_node->next = NULL;
io_node->next = NULL;
/* set IO base and Limit registers */ /* set IO base and Limit registers */
temp_byte = io_node->base >> 8; temp_byte = io_node->base >> 8;
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte);
temp_byte = (io_node->base + io_node->length - 1) >> 8; temp_byte = (io_node->base + io_node->length - 1) >> 8;
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
} else {
kfree(hold_IO_node);
hold_IO_node = NULL;
}
/* If we have memory resources copy them and fill in the /* Copy the memory resources and fill in the bridge's memory
* bridge's memory range registers. Otherwise, fill in the * range registers.
* range registers with values that disable them. */ */
if (mem_node) { memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); mem_node->next = NULL;
mem_node->next = NULL;
/* set Mem base and Limit registers */ /* set Mem base and Limit registers */
temp_word = mem_node->base >> 16; temp_word = mem_node->base >> 16;
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
temp_word = (mem_node->base + mem_node->length - 1) >> 16; temp_word = (mem_node->base + mem_node->length - 1) >> 16;
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
} else {
temp_word = 0xFFFF;
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
temp_word = 0x0000;
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
kfree(hold_mem_node);
hold_mem_node = NULL;
}
memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
p_mem_node->next = NULL; p_mem_node->next = NULL;
@ -2627,7 +2610,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
/* Return unused bus resources /* Return unused bus resources
* First use the temporary node to store information for * First use the temporary node to store information for
* the board */ * the board */
if (hold_bus_node && bus_node && temp_resources.bus_head) { if (bus_node && temp_resources.bus_head) {
hold_bus_node->length = bus_node->base - hold_bus_node->base; hold_bus_node->length = bus_node->base - hold_bus_node->base;
hold_bus_node->next = func->bus_head; hold_bus_node->next = func->bus_head;
@ -2751,7 +2734,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
} }
/* If we have prefetchable memory space available and there /* If we have prefetchable memory space available and there
* is some left at the end, return the unused portion */ * is some left at the end, return the unused portion */
if (hold_p_mem_node && temp_resources.p_mem_head) { if (temp_resources.p_mem_head) {
p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
&hold_p_mem_node, 0x100000); &hold_p_mem_node, 0x100000);

View File

@ -293,7 +293,6 @@ static void pciehp_remove(struct pcie_device *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pciehp_suspend (struct pcie_device *dev) static int pciehp_suspend (struct pcie_device *dev)
{ {
dev_info(&dev->device, "%s ENTRY\n", __func__);
return 0; return 0;
} }
@ -303,7 +302,6 @@ static int pciehp_resume (struct pcie_device *dev)
struct slot *slot; struct slot *slot;
u8 status; u8 status;
dev_info(&dev->device, "%s ENTRY\n", __func__);
ctrl = get_service_data(dev); ctrl = get_service_data(dev);
/* reinitialize the chipset's event detection logic */ /* reinitialize the chipset's event detection logic */

View File

@ -39,7 +39,7 @@ int pciehp_configure_device(struct slot *p_slot)
struct pci_dev *dev; struct pci_dev *dev;
struct pci_dev *bridge = p_slot->ctrl->pcie->port; struct pci_dev *bridge = p_slot->ctrl->pcie->port;
struct pci_bus *parent = bridge->subordinate; struct pci_bus *parent = bridge->subordinate;
int num, fn; int num;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
dev = pci_get_slot(parent, PCI_DEVFN(0, 0)); dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
@ -57,28 +57,18 @@ int pciehp_configure_device(struct slot *p_slot)
return -ENODEV; return -ENODEV;
} }
for (fn = 0; fn < 8; fn++) { list_for_each_entry(dev, &parent->devices, bus_list)
dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
if (!dev)
continue;
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
pci_hp_add_bridge(dev); pci_hp_add_bridge(dev);
pci_dev_put(dev);
}
pci_assign_unassigned_bridge_resources(bridge); pci_assign_unassigned_bridge_resources(bridge);
for (fn = 0; fn < 8; fn++) { list_for_each_entry(dev, &parent->devices, bus_list) {
dev = pci_get_slot(parent, PCI_DEVFN(0, fn)); if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
if (!dev)
continue; continue;
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
pci_dev_put(dev);
continue;
}
pci_configure_slot(dev); pci_configure_slot(dev);
pci_dev_put(dev);
} }
pci_bus_add_devices(parent); pci_bus_add_devices(parent);
@ -89,9 +79,9 @@ int pciehp_configure_device(struct slot *p_slot)
int pciehp_unconfigure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot)
{ {
int ret, rc = 0; int ret, rc = 0;
int j;
u8 bctl = 0; u8 bctl = 0;
u8 presence = 0; u8 presence = 0;
struct pci_dev *dev, *temp;
struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate; struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate;
u16 command; u16 command;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
@ -102,33 +92,31 @@ int pciehp_unconfigure_device(struct slot *p_slot)
if (ret) if (ret)
presence = 0; presence = 0;
for (j = 0; j < 8; j++) { list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
struct pci_dev *temp = pci_get_slot(parent, PCI_DEVFN(0, j)); pci_dev_get(dev);
if (!temp) if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
continue; pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
if (bctl & PCI_BRIDGE_CTL_VGA) { if (bctl & PCI_BRIDGE_CTL_VGA) {
ctrl_err(ctrl, ctrl_err(ctrl,
"Cannot remove display device %s\n", "Cannot remove display device %s\n",
pci_name(temp)); pci_name(dev));
pci_dev_put(temp); pci_dev_put(dev);
rc = -EINVAL; rc = -EINVAL;
break; break;
} }
} }
pci_stop_and_remove_bus_device(temp); pci_stop_and_remove_bus_device(dev);
/* /*
* Ensure that no new Requests will be generated from * Ensure that no new Requests will be generated from
* the device. * the device.
*/ */
if (presence) { if (presence) {
pci_read_config_word(temp, PCI_COMMAND, &command); pci_read_config_word(dev, PCI_COMMAND, &command);
command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
command |= PCI_COMMAND_INTX_DISABLE; command |= PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(temp, PCI_COMMAND, command); pci_write_config_word(dev, PCI_COMMAND, command);
} }
pci_dev_put(temp); pci_dev_put(dev);
} }
return rc; return rc;

View File

@ -334,7 +334,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
struct slot *slot = bss_hotplug_slot->private; struct slot *slot = bss_hotplug_slot->private;
struct pci_bus *new_bus = NULL; struct pci_bus *new_bus = NULL;
struct pci_dev *dev; struct pci_dev *dev;
int func, num_funcs; int num_funcs;
int new_ppb = 0; int new_ppb = 0;
int rc; int rc;
char *ssdt = NULL; char *ssdt = NULL;
@ -381,29 +381,26 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* to the Linux PCI interface and tell the drivers * to the Linux PCI interface and tell the drivers
* about them. * about them.
*/ */
for (func = 0; func < num_funcs; func++) { list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) {
dev = pci_get_slot(slot->pci_bus, if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
PCI_DEVFN(slot->device_num + 1, continue;
PCI_FUNC(func)));
if (dev) { /* Need to do slot fixup on PPB before fixup of children
/* Need to do slot fixup on PPB before fixup of children * (PPB's pcidev_info needs to be in pcidev_info list
* (PPB's pcidev_info needs to be in pcidev_info list * before child's SN_PCIDEV_INFO() call to setup
* before child's SN_PCIDEV_INFO() call to setup * pdi_host_pcidev_info).
* pdi_host_pcidev_info). */
*/ pcibios_fixup_device_resources(dev);
pcibios_fixup_device_resources(dev); if (SN_ACPI_BASE_SUPPORT())
if (SN_ACPI_BASE_SUPPORT()) sn_acpi_slot_fixup(dev);
sn_acpi_slot_fixup(dev); else
else sn_io_slot_fixup(dev);
sn_io_slot_fixup(dev); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { pci_hp_add_bridge(dev);
pci_hp_add_bridge(dev); if (dev->subordinate) {
if (dev->subordinate) { new_bus = dev->subordinate;
new_bus = dev->subordinate; new_ppb = 1;
new_ppb = 1;
}
} }
pci_dev_put(dev);
} }
} }
@ -483,8 +480,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
static int disable_slot(struct hotplug_slot *bss_hotplug_slot) static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
{ {
struct slot *slot = bss_hotplug_slot->private; struct slot *slot = bss_hotplug_slot->private;
struct pci_dev *dev; struct pci_dev *dev, *temp;
int func;
int rc; int rc;
acpi_owner_id ssdt_id = 0; acpi_owner_id ssdt_id = 0;
@ -545,15 +541,14 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
} }
/* Free the SN resources assigned to the Linux device.*/ /* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) { list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
dev = pci_get_slot(slot->pci_bus, if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
PCI_DEVFN(slot->device_num + 1, continue;
PCI_FUNC(func)));
if (dev) { pci_dev_get(dev);
sn_bus_free_data(dev); sn_bus_free_data(dev);
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev); pci_dev_put(dev);
}
} }
/* Remove the SSDT for the slot from the ACPI namespace */ /* Remove the SSDT for the slot from the ACPI namespace */

View File

@ -40,7 +40,7 @@ int __ref shpchp_configure_device(struct slot *p_slot)
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
struct pci_dev *bridge = ctrl->pci_dev; struct pci_dev *bridge = ctrl->pci_dev;
struct pci_bus *parent = bridge->subordinate; struct pci_bus *parent = bridge->subordinate;
int num, fn; int num;
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (dev) { if (dev) {
@ -57,24 +57,20 @@ int __ref shpchp_configure_device(struct slot *p_slot)
return -ENODEV; return -ENODEV;
} }
for (fn = 0; fn < 8; fn++) { list_for_each_entry(dev, &parent->devices, bus_list) {
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); if (PCI_SLOT(dev->devfn) != p_slot->device)
if (!dev)
continue; continue;
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
pci_hp_add_bridge(dev); pci_hp_add_bridge(dev);
pci_dev_put(dev);
} }
pci_assign_unassigned_bridge_resources(bridge); pci_assign_unassigned_bridge_resources(bridge);
for (fn = 0; fn < 8; fn++) { list_for_each_entry(dev, &parent->devices, bus_list) {
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); if (PCI_SLOT(dev->devfn) != p_slot->device)
if (!dev)
continue; continue;
pci_configure_slot(dev); pci_configure_slot(dev);
pci_dev_put(dev);
} }
pci_bus_add_devices(parent); pci_bus_add_devices(parent);
@ -85,32 +81,32 @@ int __ref shpchp_configure_device(struct slot *p_slot)
int shpchp_unconfigure_device(struct slot *p_slot) int shpchp_unconfigure_device(struct slot *p_slot)
{ {
int rc = 0; int rc = 0;
int j;
u8 bctl = 0; u8 bctl = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
struct pci_dev *dev, *temp;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n", ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
__func__, pci_domain_nr(parent), p_slot->bus, p_slot->device); __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
for (j = 0; j < 8 ; j++) { list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
struct pci_dev *temp = pci_get_slot(parent, if (PCI_SLOT(dev->devfn) != p_slot->device)
(p_slot->device << 3) | j);
if (!temp)
continue; continue;
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); pci_dev_get(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
if (bctl & PCI_BRIDGE_CTL_VGA) { if (bctl & PCI_BRIDGE_CTL_VGA) {
ctrl_err(ctrl, ctrl_err(ctrl,
"Cannot remove display device %s\n", "Cannot remove display device %s\n",
pci_name(temp)); pci_name(dev));
pci_dev_put(temp); pci_dev_put(dev);
rc = -EINVAL; rc = -EINVAL;
break; break;
} }
} }
pci_stop_and_remove_bus_device(temp); pci_stop_and_remove_bus_device(dev);
pci_dev_put(temp); pci_dev_put(dev);
} }
return rc; return rc;
} }

View File

@ -33,7 +33,6 @@ static inline u8 virtfn_devfn(struct pci_dev *dev, int id)
static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
{ {
int rc;
struct pci_bus *child; struct pci_bus *child;
if (bus->number == busnr) if (bus->number == busnr)
@ -48,12 +47,7 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
return NULL; return NULL;
pci_bus_insert_busn_res(child, busnr, busnr); pci_bus_insert_busn_res(child, busnr, busnr);
child->dev.parent = bus->bridge; bus->is_added = 1;
rc = pci_bus_add_child(child);
if (rc) {
pci_remove_bus(child);
return NULL;
}
return child; return child;
} }
@ -123,8 +117,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
virtfn->is_virtfn = 1; virtfn->is_virtfn = 1;
rc = pci_bus_add_device(virtfn); rc = pci_bus_add_device(virtfn);
if (rc)
goto failed1;
sprintf(buf, "virtfn%u", id); sprintf(buf, "virtfn%u", id);
rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
if (rc) if (rc)

View File

@ -302,48 +302,11 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
return 0; return 0;
} }
static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
{
int num;
unsigned int seg, bus;
/*
* The string should be the same as root bridge's name
* Please look at 'pci_scan_bus_parented'
*/
num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus);
if (num != 2)
return -ENODEV;
*handle = acpi_get_pci_rootbridge_handle(seg, bus);
if (!*handle)
return -ENODEV;
return 0;
}
static void pci_acpi_setup(struct device *dev) static void pci_acpi_setup(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pci_dev = to_pci_dev(dev);
acpi_handle handle = ACPI_HANDLE(dev); acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_device *adev; struct acpi_device *adev;
acpi_status status;
acpi_handle dummy;
/*
* Evaluate and parse _PRT, if exists. This code allows parsing of
* _PRT objects within the scope of non-bridge devices. Note that
* _PRTs within the scope of a PCI bridge assume the bridge's
* subordinate bus number.
*
* TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
*/
status = acpi_get_handle(handle, METHOD_NAME__PRT, &dummy);
if (ACPI_SUCCESS(status)) {
unsigned char bus;
bus = pci_dev->subordinate ?
pci_dev->subordinate->number : pci_dev->bus->number;
acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus);
}
if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid)
return; return;
@ -358,7 +321,6 @@ static void pci_acpi_setup(struct device *dev)
static void pci_acpi_cleanup(struct device *dev) static void pci_acpi_cleanup(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev);
acpi_handle handle = ACPI_HANDLE(dev); acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_device *adev; struct acpi_device *adev;
@ -367,16 +329,11 @@ static void pci_acpi_cleanup(struct device *dev)
device_set_run_wake(dev, false); device_set_run_wake(dev, false);
pci_acpi_remove_pm_notifier(adev); pci_acpi_remove_pm_notifier(adev);
} }
if (pci_dev->subordinate)
acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus),
pci_dev->subordinate->number);
} }
static struct acpi_bus_type acpi_pci_bus = { static struct acpi_bus_type acpi_pci_bus = {
.bus = &pci_bus_type, .bus = &pci_bus_type,
.find_device = acpi_pci_find_device, .find_device = acpi_pci_find_device,
.find_bridge = acpi_pci_find_root_bridge,
.setup = pci_acpi_setup, .setup = pci_acpi_setup,
.cleanup = pci_acpi_cleanup, .cleanup = pci_acpi_cleanup,
}; };

View File

@ -392,7 +392,7 @@ static void pci_device_shutdown(struct device *dev)
* Turn off Bus Master bit on the device to tell it to not * Turn off Bus Master bit on the device to tell it to not
* continue to do DMA * continue to do DMA
*/ */
pci_disable_device(pci_dev); pci_clear_master(pci_dev);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -628,6 +628,7 @@ static int pci_pm_suspend(struct device *dev)
goto Fixup; goto Fixup;
} }
pci_dev->state_saved = false;
if (pm->suspend) { if (pm->suspend) {
pci_power_t prev = pci_dev->current_state; pci_power_t prev = pci_dev->current_state;
int error; int error;
@ -774,6 +775,7 @@ static int pci_pm_freeze(struct device *dev)
return 0; return 0;
} }
pci_dev->state_saved = false;
if (pm->freeze) { if (pm->freeze) {
int error; int error;
@ -862,6 +864,7 @@ static int pci_pm_poweroff(struct device *dev)
goto Fixup; goto Fixup;
} }
pci_dev->state_saved = false;
if (pm->poweroff) { if (pm->poweroff) {
int error; int error;
@ -987,6 +990,7 @@ static int pci_pm_runtime_suspend(struct device *dev)
if (!pm || !pm->runtime_suspend) if (!pm || !pm->runtime_suspend)
return -ENOSYS; return -ENOSYS;
pci_dev->state_saved = false;
pci_dev->no_d3cold = false; pci_dev->no_d3cold = false;
error = pm->runtime_suspend(dev); error = pm->runtime_suspend(dev);
suspend_report_result(pm->runtime_suspend, error); suspend_report_result(pm->runtime_suspend, error);
@ -1186,9 +1190,13 @@ pci_dev_driver(const struct pci_dev *dev)
static int pci_bus_match(struct device *dev, struct device_driver *drv) static int pci_bus_match(struct device *dev, struct device_driver *drv)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *pci_drv = to_pci_driver(drv); struct pci_driver *pci_drv;
const struct pci_device_id *found_id; const struct pci_device_id *found_id;
if (!pci_dev->match_driver)
return 0;
pci_drv = to_pci_driver(drv);
found_id = pci_match_device(pci_drv, pci_dev); found_id = pci_match_device(pci_drv, pci_dev);
if (found_id) if (found_id)
return 1; return 1;

View File

@ -1151,8 +1151,7 @@ int pci_reenable_device(struct pci_dev *dev)
return 0; return 0;
} }
static int __pci_enable_device_flags(struct pci_dev *dev, static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
resource_size_t flags)
{ {
int err; int err;
int i, bars = 0; int i, bars = 0;
@ -1169,7 +1168,7 @@ static int __pci_enable_device_flags(struct pci_dev *dev,
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
} }
if (atomic_add_return(1, &dev->enable_cnt) > 1) if (atomic_inc_return(&dev->enable_cnt) > 1)
return 0; /* already enabled */ return 0; /* already enabled */
/* only skip sriov related */ /* only skip sriov related */
@ -1196,7 +1195,7 @@ static int __pci_enable_device_flags(struct pci_dev *dev,
*/ */
int pci_enable_device_io(struct pci_dev *dev) int pci_enable_device_io(struct pci_dev *dev)
{ {
return __pci_enable_device_flags(dev, IORESOURCE_IO); return pci_enable_device_flags(dev, IORESOURCE_IO);
} }
/** /**
@ -1209,7 +1208,7 @@ int pci_enable_device_io(struct pci_dev *dev)
*/ */
int pci_enable_device_mem(struct pci_dev *dev) int pci_enable_device_mem(struct pci_dev *dev)
{ {
return __pci_enable_device_flags(dev, IORESOURCE_MEM); return pci_enable_device_flags(dev, IORESOURCE_MEM);
} }
/** /**
@ -1225,7 +1224,7 @@ int pci_enable_device_mem(struct pci_dev *dev)
*/ */
int pci_enable_device(struct pci_dev *dev) int pci_enable_device(struct pci_dev *dev)
{ {
return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
} }
/* /*
@ -1396,7 +1395,10 @@ pci_disable_device(struct pci_dev *dev)
if (dr) if (dr)
dr->enabled = 0; dr->enabled = 0;
if (atomic_sub_return(1, &dev->enable_cnt) != 0) dev_WARN_ONCE(&dev->dev, atomic_read(&dev->enable_cnt) <= 0,
"disabling already-disabled device");
if (atomic_dec_return(&dev->enable_cnt) != 0)
return; return;
do_pci_disable_device(dev); do_pci_disable_device(dev);
@ -2043,10 +2045,13 @@ void pci_free_cap_save_buffers(struct pci_dev *dev)
} }
/** /**
* pci_enable_ari - enable ARI forwarding if hardware support it * pci_configure_ari - enable or disable ARI forwarding
* @dev: the PCI device * @dev: the PCI device
*
* If @dev and its upstream bridge both support ARI, enable ARI in the
* bridge. Otherwise, disable ARI in the bridge.
*/ */
void pci_enable_ari(struct pci_dev *dev) void pci_configure_ari(struct pci_dev *dev)
{ {
u32 cap; u32 cap;
struct pci_dev *bridge; struct pci_dev *bridge;
@ -2054,9 +2059,6 @@ void pci_enable_ari(struct pci_dev *dev)
if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn) if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
return; return;
if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI))
return;
bridge = dev->bus->self; bridge = dev->bus->self;
if (!bridge) if (!bridge)
return; return;
@ -2065,8 +2067,15 @@ void pci_enable_ari(struct pci_dev *dev)
if (!(cap & PCI_EXP_DEVCAP2_ARI)) if (!(cap & PCI_EXP_DEVCAP2_ARI))
return; return;
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI); if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) {
bridge->ari_enabled = 1; pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ARI);
bridge->ari_enabled = 1;
} else {
pcie_capability_clear_word(bridge, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ARI);
bridge->ari_enabled = 0;
}
} }
/** /**
@ -3742,18 +3751,6 @@ resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
return align; return align;
} }
/**
* pci_is_reassigndev - check if specified PCI is target device to reassign
* @dev: the PCI device to check
*
* RETURNS: non-zero for PCI device is a target device to reassign,
* or zero is not.
*/
int pci_is_reassigndev(struct pci_dev *dev)
{
return (pci_specified_resource_alignment(dev) != 0);
}
/* /*
* This function disables memory decoding and releases memory resources * This function disables memory decoding and releases memory resources
* of the device specified by kernel's boot parameter 'pci=resource_alignment='. * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
@ -3768,7 +3765,9 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
resource_size_t align, size; resource_size_t align, size;
u16 command; u16 command;
if (!pci_is_reassigndev(dev)) /* check if specified PCI is target device to reassign */
align = pci_specified_resource_alignment(dev);
if (!align)
return; return;
if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL && if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
@ -3784,7 +3783,6 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
command &= ~PCI_COMMAND_MEMORY; command &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, command); pci_write_config_word(dev, PCI_COMMAND, command);
align = pci_specified_resource_alignment(dev);
for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
r = &dev->resource[i]; r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM)) if (!(r->flags & IORESOURCE_MEM))

View File

@ -203,8 +203,8 @@ extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int reg); struct resource *res, unsigned int reg);
extern int pci_resource_bar(struct pci_dev *dev, int resno, extern int pci_resource_bar(struct pci_dev *dev, int resno,
enum pci_bar_type *type); enum pci_bar_type *type);
extern int pci_bus_add_child(struct pci_bus *bus); extern void pci_configure_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
* @bus: the PCI bus * @bus: the PCI bus

View File

@ -556,6 +556,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link; struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev); int blacklist = !!pcie_aspm_sanity_check(pdev);
if (!aspm_support_enabled)
return;
if (!pci_is_pcie(pdev) || pdev->link_state) if (!pci_is_pcie(pdev) || pdev->link_state)
return; return;
if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
@ -634,10 +637,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
struct pci_dev *parent = pdev->bus->self; struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link, *root, *parent_link; struct pcie_link_state *link, *root, *parent_link;
if (!pci_is_pcie(pdev) || !parent || !parent->link_state) if (!parent || !parent->link_state)
return;
if ((pci_pcie_type(parent) != PCI_EXP_TYPE_ROOT_PORT) &&
(pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM))
return; return;
down_read(&pci_bus_sem); down_read(&pci_bus_sem);

View File

@ -272,7 +272,7 @@ static int get_port_device_capability(struct pci_dev *dev)
/* Hot-Plug Capable */ /* Hot-Plug Capable */
if ((cap_mask & PCIE_PORT_SERVICE_HP) && if ((cap_mask & PCIE_PORT_SERVICE_HP) &&
dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT) { pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT) {
pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, &reg32); pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, &reg32);
if (reg32 & PCI_EXP_SLTCAP_HPC) { if (reg32 & PCI_EXP_SLTCAP_HPC) {
services |= PCIE_PORT_SERVICE_HP; services |= PCIE_PORT_SERVICE_HP;

View File

@ -623,6 +623,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
{ {
struct pci_bus *child; struct pci_bus *child;
int i; int i;
int ret;
/* /*
* Allocate a new bus, and inherit stuff from the parent.. * Allocate a new bus, and inherit stuff from the parent..
@ -637,8 +638,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
child->bus_flags = parent->bus_flags; child->bus_flags = parent->bus_flags;
/* initialize some portions of the bus device, but don't register it /* initialize some portions of the bus device, but don't register it
* now as the parent is not properly set up yet. This device will get * now as the parent is not properly set up yet.
* registered later in pci_bus_add_devices()
*/ */
child->dev.class = &pcibus_class; child->dev.class = &pcibus_class;
dev_set_name(&child->dev, "%04x:%02x", pci_domain_nr(child), busnr); dev_set_name(&child->dev, "%04x:%02x", pci_domain_nr(child), busnr);
@ -651,11 +651,14 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
child->primary = parent->busn_res.start; child->primary = parent->busn_res.start;
child->busn_res.end = 0xff; child->busn_res.end = 0xff;
if (!bridge) if (!bridge) {
return child; child->dev.parent = parent->bridge;
goto add_dev;
}
child->self = bridge; child->self = bridge;
child->bridge = get_device(&bridge->dev); child->bridge = get_device(&bridge->dev);
child->dev.parent = child->bridge;
pci_set_bus_of_node(child); pci_set_bus_of_node(child);
pci_set_bus_speed(child); pci_set_bus_speed(child);
@ -666,6 +669,13 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
} }
bridge->subordinate = child; bridge->subordinate = child;
add_dev:
ret = device_register(&child->dev);
WARN_ON(ret < 0);
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(child);
return child; return child;
} }
@ -1285,7 +1295,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_vpd_pci22_init(dev); pci_vpd_pci22_init(dev);
/* Alternative Routing-ID Forwarding */ /* Alternative Routing-ID Forwarding */
pci_enable_ari(dev); pci_configure_ari(dev);
/* Single Root I/O Virtualization */ /* Single Root I/O Virtualization */
pci_iov_init(dev); pci_iov_init(dev);
@ -1296,10 +1306,12 @@ static void pci_init_capabilities(struct pci_dev *dev)
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{ {
int ret;
device_initialize(&dev->dev); device_initialize(&dev->dev);
dev->dev.release = pci_release_dev; dev->dev.release = pci_release_dev;
pci_dev_get(dev);
set_dev_node(&dev->dev, pcibus_to_node(bus));
dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms; dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull; dev->dev.coherent_dma_mask = 0xffffffffull;
@ -1326,6 +1338,17 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
down_write(&pci_bus_sem); down_write(&pci_bus_sem);
list_add_tail(&dev->bus_list, &bus->devices); list_add_tail(&dev->bus_list, &bus->devices);
up_write(&pci_bus_sem); up_write(&pci_bus_sem);
pci_fixup_device(pci_fixup_final, dev);
ret = pcibios_add_device(dev);
WARN_ON(ret < 0);
/* Notifier could use PCI capabilities */
dev->match_driver = false;
ret = device_add(&dev->dev);
WARN_ON(ret < 0);
pci_proc_attach_device(dev);
} }
struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
@ -1348,31 +1371,31 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
} }
EXPORT_SYMBOL(pci_scan_single_device); EXPORT_SYMBOL(pci_scan_single_device);
static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn) static unsigned next_fn(struct pci_bus *bus, struct pci_dev *dev, unsigned fn)
{ {
u16 cap; int pos;
unsigned pos, next_fn; u16 cap = 0;
unsigned next_fn;
if (!dev) if (pci_ari_enabled(bus)) {
return 0; if (!dev)
return 0;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
if (!pos)
return 0;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap);
if (!pos) next_fn = PCI_ARI_CAP_NFN(cap);
return 0; if (next_fn <= fn)
pci_read_config_word(dev, pos + 4, &cap); return 0; /* protect against malformed list */
next_fn = cap >> 8;
if (next_fn <= fn)
return 0;
return next_fn;
}
static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn) return next_fn;
{ }
return (fn + 1) % 8;
} /* dev may be NULL for non-contiguous multifunction devices */
if (!dev || dev->multifunction)
return (fn + 1) % 8;
static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
{
return 0; return 0;
} }
@ -1405,7 +1428,6 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
{ {
unsigned fn, nr = 0; unsigned fn, nr = 0;
struct pci_dev *dev; struct pci_dev *dev;
unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
if (only_one_child(bus) && (devfn > 0)) if (only_one_child(bus) && (devfn > 0))
return 0; /* Already scanned the entire slot */ return 0; /* Already scanned the entire slot */
@ -1416,12 +1438,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
if (!dev->is_added) if (!dev->is_added)
nr++; nr++;
if (pci_ari_enabled(bus)) for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
next_fn = next_ari_fn;
else if (dev->multifunction)
next_fn = next_trad_fn;
for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
dev = pci_scan_single_device(bus, devfn + fn); dev = pci_scan_single_device(bus, devfn + fn);
if (dev) { if (dev) {
if (!dev->is_added) if (!dev->is_added)
@ -1632,6 +1649,18 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
return max; return max;
} }
/**
* pcibios_root_bridge_prepare - Platform-specific host bridge setup.
* @bridge: Host bridge to set up.
*
* Default empty implementation. Replace with an architecture-specific setup
* routine, if necessary.
*/
int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
return 0;
}
struct pci_bus *pci_create_root_bus(struct device *parent, int bus, struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources) struct pci_ops *ops, void *sysdata, struct list_head *resources)
{ {
@ -1644,13 +1673,13 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
char bus_addr[64]; char bus_addr[64];
char *fmt; char *fmt;
b = pci_alloc_bus(); b = pci_alloc_bus();
if (!b) if (!b)
return NULL; return NULL;
b->sysdata = sysdata; b->sysdata = sysdata;
b->ops = ops; b->ops = ops;
b->number = b->busn_res.start = bus;
b2 = pci_find_bus(pci_domain_nr(b), bus); b2 = pci_find_bus(pci_domain_nr(b), bus);
if (b2) { if (b2) {
/* If we already got to this bus through a different bridge, ignore it */ /* If we already got to this bus through a different bridge, ignore it */
@ -1665,6 +1694,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
bridge->dev.parent = parent; bridge->dev.parent = parent;
bridge->dev.release = pci_release_bus_bridge_dev; bridge->dev.release = pci_release_bus_bridge_dev;
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
error = pcibios_root_bridge_prepare(bridge);
if (error)
goto bridge_dev_reg_err;
error = device_register(&bridge->dev); error = device_register(&bridge->dev);
if (error) if (error)
goto bridge_dev_reg_err; goto bridge_dev_reg_err;
@ -1685,8 +1718,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
/* Create legacy_io and legacy_mem files for this bus */ /* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(b); pci_create_legacy_files(b);
b->number = b->busn_res.start = bus;
if (parent) if (parent)
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
else else

View File

@ -24,7 +24,7 @@ static void pci_stop_dev(struct pci_dev *dev)
if (dev->is_added) { if (dev->is_added) {
pci_proc_detach_device(dev); pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev); pci_remove_sysfs_dev_files(dev);
device_unregister(&dev->dev); device_del(&dev->dev);
dev->is_added = 0; dev->is_added = 0;
} }
@ -39,7 +39,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
up_write(&pci_bus_sem); up_write(&pci_bus_sem);
pci_free_resources(dev); pci_free_resources(dev);
pci_dev_put(dev); put_device(&dev->dev);
} }
void pci_remove_bus(struct pci_bus *bus) void pci_remove_bus(struct pci_bus *bus)

View File

@ -319,13 +319,13 @@ int pci_dev_present(const struct pci_device_id *ids)
WARN_ON(in_interrupt()); WARN_ON(in_interrupt());
while (ids->vendor || ids->subvendor || ids->class_mask) { while (ids->vendor || ids->subvendor || ids->class_mask) {
found = pci_get_dev_by_id(ids, NULL); found = pci_get_dev_by_id(ids, NULL);
if (found) if (found) {
goto exit; pci_dev_put(found);
return 1;
}
ids++; ids++;
} }
exit:
if (found)
return 1;
return 0; return 0;
} }
EXPORT_SYMBOL(pci_dev_present); EXPORT_SYMBOL(pci_dev_present);

View File

@ -283,7 +283,7 @@ static void assign_requested_resources_sorted(struct list_head *head,
idx = res - &dev_res->dev->resource[0]; idx = res - &dev_res->dev->resource[0];
if (resource_size(res) && if (resource_size(res) &&
pci_assign_resource(dev_res->dev, idx)) { pci_assign_resource(dev_res->dev, idx)) {
if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) { if (fail_head) {
/* /*
* if the failed res is for ROM BAR, and it will * if the failed res is for ROM BAR, and it will
* be enabled later, don't add it to the list * be enabled later, don't add it to the list

View File

@ -323,6 +323,15 @@ struct acpi_eject_event {
u32 event; u32 event;
}; };
struct acpi_hp_work {
struct work_struct work;
acpi_handle handle;
u32 type;
void *context;
};
void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
void (*func)(struct work_struct *work));
extern struct kobject *acpi_kobj; extern struct kobject *acpi_kobj;
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
void acpi_bus_private_data_handler(acpi_handle, void *); void acpi_bus_private_data_handler(acpi_handle, void *);
@ -454,7 +463,6 @@ struct acpi_pci_root {
/* helper */ /* helper */
acpi_handle acpi_get_child(acpi_handle, u64); acpi_handle acpi_get_child(acpi_handle, u64);
int acpi_is_root_bridge(acpi_handle); int acpi_is_root_bridge(acpi_handle);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev)) #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev))

View File

@ -90,11 +90,6 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
int *polarity, char **name); int *polarity, char **name);
int acpi_pci_link_free_irq(acpi_handle handle); int acpi_pci_link_free_irq(acpi_handle handle);
/* ACPI PCI Interrupt Routing (pci_irq.c) */
int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus);
void acpi_pci_irq_del_prt(int segment, int bus);
/* ACPI PCI Device Binding (pci_bind.c) */ /* ACPI PCI Device Binding (pci_bind.c) */
struct pci_bus; struct pci_bus;

View File

@ -194,8 +194,6 @@ void acpi_os_fixed_event_count(u32 fixed_event_number);
/* /*
* Threads and Scheduling * Threads and Scheduling
*/ */
extern struct workqueue_struct *kacpi_hotplug_wq;
acpi_thread_id acpi_os_get_thread_id(void); acpi_thread_id acpi_os_get_thread_id(void);
acpi_status acpi_status

View File

@ -286,6 +286,7 @@ struct pci_dev {
unsigned int irq; unsigned int irq;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
bool match_driver; /* Skip attaching driver */
/* These fields are used by common fixups */ /* These fields are used by common fixups */
unsigned int transparent:1; /* Transparent PCI bridge */ unsigned int transparent:1; /* Transparent PCI bridge */
unsigned int multifunction:1;/* Part of multi-function device */ unsigned int multifunction:1;/* Part of multi-function device */
@ -378,6 +379,8 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *), void (*release_fn)(struct pci_host_bridge *),
void *release_data); void *release_data);
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge);
/* /*
* The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
* to P2P or CardBus bridge windows) go in a table. Additional ones (for * to P2P or CardBus bridge windows) go in a table. Additional ones (for
@ -674,6 +677,7 @@ extern struct list_head pci_root_buses; /* list of all known PCI buses */
/* Some device drivers need know if pci is initiated */ /* Some device drivers need know if pci is initiated */
extern int no_pci_devices(void); extern int no_pci_devices(void);
void pcibios_resource_survey_bus(struct pci_bus *bus);
void pcibios_fixup_bus(struct pci_bus *); void pcibios_fixup_bus(struct pci_bus *);
int __must_check pcibios_enable_device(struct pci_dev *, int mask); int __must_check pcibios_enable_device(struct pci_dev *, int mask);
/* Architecture specific versions may override this (weak) */ /* Architecture specific versions may override this (weak) */
@ -1699,13 +1703,22 @@ static inline bool pci_is_pcie(struct pci_dev *dev)
return !!pci_pcie_cap(dev); return !!pci_pcie_cap(dev);
} }
/**
* pcie_caps_reg - get the PCIe Capabilities Register
* @dev: PCI device
*/
static inline u16 pcie_caps_reg(const struct pci_dev *dev)
{
return dev->pcie_flags_reg;
}
/** /**
* pci_pcie_type - get the PCIe device/port type * pci_pcie_type - get the PCIe device/port type
* @dev: PCI device * @dev: PCI device
*/ */
static inline int pci_pcie_type(const struct pci_dev *dev) static inline int pci_pcie_type(const struct pci_dev *dev)
{ {
return (dev->pcie_flags_reg & PCI_EXP_FLAGS_TYPE) >> 4; return (pcie_caps_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
} }
void pci_request_acs(void); void pci_request_acs(void);