forked from Minki/linux
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:
commit
556f12f602
@ -2262,6 +2262,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
This sorting is done to get a device
|
||||
order compatible with older (<= 2.4) kernels.
|
||||
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
|
||||
reserved for the CardBus bridge's IO window.
|
||||
The default value is 256 bytes.
|
||||
@ -2283,6 +2298,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
the default.
|
||||
off: Turn ECRC off
|
||||
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
|
||||
if allocations done by BIOS are too small to
|
||||
accommodate resources required by all child
|
||||
|
@ -31,7 +31,6 @@ void pcibios_resource_survey(void);
|
||||
/* pci-vdk.c */
|
||||
|
||||
extern int __nongpreldata pcibios_last_bus;
|
||||
extern struct pci_bus *__nongpreldata pci_root_bus;
|
||||
extern struct pci_ops *__nongpreldata pci_root_ops;
|
||||
|
||||
/* pci-irq.c */
|
||||
|
@ -26,7 +26,6 @@
|
||||
unsigned int __nongpreldata pci_probe = 1;
|
||||
|
||||
int __nongpreldata pcibios_last_bus = -1;
|
||||
struct pci_bus *__nongpreldata pci_root_bus;
|
||||
struct pci_ops *__nongpreldata pci_root_ops;
|
||||
|
||||
/*
|
||||
@ -416,8 +415,7 @@ int __init pcibios_init(void)
|
||||
printk("PCI: Probing PCI hardware\n");
|
||||
pci_add_resource(&resources, &pci_ioport_resource);
|
||||
pci_add_resource(&resources, &pci_iomem_resource);
|
||||
pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL,
|
||||
&resources);
|
||||
pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);
|
||||
|
||||
pcibios_irq_init();
|
||||
pcibios_fixup_peer_bridges();
|
||||
|
@ -393,6 +393,14 @@ out1:
|
||||
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)
|
||||
{
|
||||
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
|
||||
|
@ -36,7 +36,6 @@ extern void pcibios_resource_survey(void);
|
||||
/* pci.c */
|
||||
|
||||
extern int pcibios_last_bus;
|
||||
extern struct pci_bus *pci_root_bus;
|
||||
extern struct pci_ops *pci_root_ops;
|
||||
|
||||
extern struct irq_routing_table *pcibios_get_irq_routing_table(void);
|
||||
|
@ -24,7 +24,6 @@
|
||||
unsigned int pci_probe = 1;
|
||||
|
||||
int pcibios_last_bus = -1;
|
||||
struct pci_bus *pci_root_bus;
|
||||
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_iomem_resource, mem_offset);
|
||||
pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
|
||||
&resources);
|
||||
pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
|
||||
|
||||
pcibios_irq_init();
|
||||
pcibios_fixup_irqs();
|
||||
|
@ -14,6 +14,9 @@
|
||||
struct pci_sysdata {
|
||||
int domain; /* PCI domain */
|
||||
int node; /* NUMA node */
|
||||
#ifdef CONFIG_ACPI
|
||||
void *acpi; /* ACPI-specific data */
|
||||
#endif
|
||||
#ifdef CONFIG_X86_64
|
||||
void *iommu; /* IOMMU private data */
|
||||
#endif
|
||||
|
@ -54,7 +54,6 @@ void pcibios_set_cache_line_size(void);
|
||||
/* pci-pc.c */
|
||||
|
||||
extern int pcibios_last_bus;
|
||||
extern struct pci_bus *pci_root_bus;
|
||||
extern struct pci_ops pci_root_ops;
|
||||
|
||||
void pcibios_scan_specific_bus(int busn);
|
||||
|
@ -521,6 +521,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
|
||||
sd = &info->sd;
|
||||
sd->domain = domain;
|
||||
sd->node = node;
|
||||
sd->acpi = device->handle;
|
||||
/*
|
||||
* 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.
|
||||
@ -592,6 +593,14 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
|
||||
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)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
|
@ -34,7 +34,6 @@ int noioapicreroute = 1;
|
||||
#endif
|
||||
int pcibios_last_bus = -1;
|
||||
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_ext_ops;
|
||||
|
||||
|
@ -51,6 +51,7 @@ struct pcibios_fwaddrmap {
|
||||
|
||||
static LIST_HEAD(pcibios_fwaddrmappings);
|
||||
static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
|
||||
static bool pcibios_fw_addr_done;
|
||||
|
||||
/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
|
||||
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;
|
||||
struct pcibios_fwaddrmap *map;
|
||||
|
||||
if (pcibios_fw_addr_done)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
|
||||
map = pcibios_fwaddrmap_lookup(dev);
|
||||
if (!map) {
|
||||
@ -97,6 +101,9 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
|
||||
struct pcibios_fwaddrmap *map;
|
||||
resource_size_t fw_addr = 0;
|
||||
|
||||
if (pcibios_fw_addr_done)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
|
||||
map = pcibios_fwaddrmap_lookup(dev);
|
||||
if (map)
|
||||
@ -106,7 +113,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
|
||||
return fw_addr;
|
||||
}
|
||||
|
||||
static void pcibios_fw_addr_list_del(void)
|
||||
static void __init pcibios_fw_addr_list_del(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct pcibios_fwaddrmap *entry, *next;
|
||||
@ -118,6 +125,7 @@ static void pcibios_fw_addr_list_del(void)
|
||||
kfree(entry);
|
||||
}
|
||||
spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
|
||||
pcibios_fw_addr_done = true;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -193,46 +201,46 @@ EXPORT_SYMBOL(pcibios_align_resource);
|
||||
* 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;
|
||||
struct resource *r;
|
||||
|
||||
/* Depth-First Search on bus tree */
|
||||
list_for_each_entry(bus, bus_list, node) {
|
||||
if ((dev = bus->self)) {
|
||||
for (idx = PCI_BRIDGE_RESOURCES;
|
||||
idx < PCI_NUM_RESOURCES; idx++) {
|
||||
r = &dev->resource[idx];
|
||||
if (!r->flags)
|
||||
continue;
|
||||
if (!r->start ||
|
||||
pci_claim_resource(dev, idx) < 0) {
|
||||
/*
|
||||
* Something is wrong with the region.
|
||||
* Invalidate the resource to prevent
|
||||
* child resource allocations in this
|
||||
* range.
|
||||
*/
|
||||
r->start = r->end = 0;
|
||||
r->flags = 0;
|
||||
}
|
||||
}
|
||||
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
|
||||
r = &dev->resource[idx];
|
||||
if (!r->flags)
|
||||
continue;
|
||||
if (!r->start || pci_claim_resource(dev, idx) < 0) {
|
||||
/*
|
||||
* Something is wrong with the region.
|
||||
* Invalidate the resource to prevent
|
||||
* 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 {
|
||||
int start;
|
||||
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;
|
||||
u16 command;
|
||||
struct resource *r;
|
||||
@ -244,14 +252,13 @@ static void __init pcibios_allocate_resources(int pass)
|
||||
#endif
|
||||
};
|
||||
|
||||
for_each_pci_dev(dev) {
|
||||
pci_read_config_word(dev, PCI_COMMAND, &command);
|
||||
for (i = 0; i < ARRAY_SIZE(idx_range); i++)
|
||||
pci_read_config_word(dev, PCI_COMMAND, &command);
|
||||
for (i = 0; i < ARRAY_SIZE(idx_range); i++)
|
||||
for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
|
||||
r = &dev->resource[idx];
|
||||
if (r->parent) /* Already allocated */
|
||||
if (r->parent) /* Already allocated */
|
||||
continue;
|
||||
if (!r->start) /* Address not assigned at all */
|
||||
if (!r->start) /* Address not assigned at all */
|
||||
continue;
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
disabled = !(command & PCI_COMMAND_IO);
|
||||
@ -270,44 +277,74 @@ static void __init pcibios_allocate_resources(int pass)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!pass) {
|
||||
r = &dev->resource[PCI_ROM_RESOURCE];
|
||||
if (r->flags & IORESOURCE_ROM_ENABLE) {
|
||||
/* Turn the ROM off, leave the resource region,
|
||||
* but keep it unregistered. */
|
||||
u32 reg;
|
||||
dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
|
||||
r->flags &= ~IORESOURCE_ROM_ENABLE;
|
||||
pci_read_config_dword(dev,
|
||||
dev->rom_base_reg, ®);
|
||||
pci_write_config_dword(dev, dev->rom_base_reg,
|
||||
if (!pass) {
|
||||
r = &dev->resource[PCI_ROM_RESOURCE];
|
||||
if (r->flags & IORESOURCE_ROM_ENABLE) {
|
||||
/* Turn the ROM off, leave the resource region,
|
||||
* but keep it unregistered. */
|
||||
u32 reg;
|
||||
dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
|
||||
r->flags &= ~IORESOURCE_ROM_ENABLE;
|
||||
pci_read_config_dword(dev, dev->rom_base_reg, ®);
|
||||
pci_write_config_dword(dev, dev->rom_base_reg,
|
||||
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)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
struct resource *r;
|
||||
struct pci_bus *bus;
|
||||
|
||||
if (!(pci_probe & PCI_ASSIGN_ROMS)) {
|
||||
/*
|
||||
* Try to use BIOS settings for ROMs, otherwise let
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(pci_probe & PCI_ASSIGN_ROMS))
|
||||
list_for_each_entry(bus, &pci_root_buses, node)
|
||||
pcibios_allocate_rom_resources(bus);
|
||||
|
||||
pci_assign_unassigned_resources();
|
||||
pcibios_fw_addr_list_del();
|
||||
@ -315,12 +352,32 @@ static int __init pcibios_assign_resources(void)
|
||||
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)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
|
||||
DBG("PCI: Allocating resources\n");
|
||||
pcibios_allocate_bus_resources(&pci_root_buses);
|
||||
pcibios_allocate_resources(0);
|
||||
pcibios_allocate_resources(1);
|
||||
|
||||
list_for_each_entry(bus, &pci_root_buses, node)
|
||||
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();
|
||||
/*
|
||||
|
@ -30,7 +30,7 @@ int __init pci_legacy_init(void)
|
||||
}
|
||||
|
||||
printk("PCI: Probing PCI hardware\n");
|
||||
pci_root_bus = pcibios_scan_root(0);
|
||||
pcibios_scan_root(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ int __init pci_numaq_init(void)
|
||||
|
||||
raw_pci_ops = &pci_direct_conf1_mq;
|
||||
|
||||
pci_root_bus = pcibios_scan_root(0);
|
||||
pcibios_scan_root(0);
|
||||
if (num_online_nodes() > 1)
|
||||
for_each_online_node(quad) {
|
||||
if (quad == 0)
|
||||
|
@ -306,7 +306,7 @@ config ACPI_DEBUG_FUNC_TRACE
|
||||
is about half of the penalty and is rarely useful.
|
||||
|
||||
config ACPI_PCI_SLOT
|
||||
tristate "PCI slot detection driver"
|
||||
bool "PCI slot detection driver"
|
||||
depends on SYSFS
|
||||
default n
|
||||
help
|
||||
@ -315,9 +315,6 @@ config ACPI_PCI_SLOT
|
||||
i.e., segment/bus/device/function tuples, with physical slots in
|
||||
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
|
||||
bool "Power Management Timer Support" if EXPERT
|
||||
depends on X86
|
||||
|
@ -25,8 +25,14 @@
|
||||
|
||||
int init_acpi_device_notify(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_link_init(void);
|
||||
void acpi_pci_root_hp_init(void);
|
||||
void acpi_platform_init(void);
|
||||
int acpi_sysfs_init(void);
|
||||
void acpi_csrt_init(void);
|
||||
|
@ -84,8 +84,7 @@ static acpi_osd_handler acpi_irq_handler;
|
||||
static void *acpi_irq_context;
|
||||
static struct workqueue_struct *kacpid_wq;
|
||||
static struct workqueue_struct *kacpi_notify_wq;
|
||||
struct workqueue_struct *kacpi_hotplug_wq;
|
||||
EXPORT_SYMBOL(kacpi_hotplug_wq);
|
||||
static struct workqueue_struct *kacpi_hotplug_wq;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -53,9 +53,6 @@ struct acpi_prt_entry {
|
||||
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)
|
||||
{
|
||||
return 'A' + pin - 1;
|
||||
@ -65,28 +62,6 @@ static inline char pin_name(int pin)
|
||||
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 */
|
||||
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,
|
||||
struct acpi_pci_routing_table *prt)
|
||||
static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
|
||||
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;
|
||||
|
||||
if (((prt->address >> 16) & 0xffff) != device ||
|
||||
prt->pin + 1 != pin)
|
||||
return -ENODEV;
|
||||
|
||||
entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
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),
|
||||
prt->source, entry->index));
|
||||
|
||||
spin_lock(&acpi_prt_lock);
|
||||
list_add_tail(&entry->list, &acpi_prt_list);
|
||||
spin_unlock(&acpi_prt_lock);
|
||||
*entry_ptr = entry;
|
||||
|
||||
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;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_pci_routing_table *entry;
|
||||
acpi_handle handle = NULL;
|
||||
|
||||
/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
|
||||
status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
if (dev->bus->bridge)
|
||||
handle = ACPI_HANDLE(dev->bus->bridge);
|
||||
|
||||
if (!handle)
|
||||
return -ENODEV;
|
||||
|
||||
printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
|
||||
(char *) buffer.pointer);
|
||||
|
||||
kfree(buffer.pointer);
|
||||
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
buffer.pointer = NULL;
|
||||
|
||||
/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
|
||||
status = acpi_get_irq_routing_table(handle, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
|
||||
acpi_format_exception(status)));
|
||||
kfree(buffer.pointer);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
entry = buffer.pointer;
|
||||
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 *)
|
||||
((unsigned long)entry + entry->length);
|
||||
}
|
||||
@ -282,23 +259,6 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
|
||||
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
|
||||
-------------------------------------------------------------------------- */
|
||||
@ -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)
|
||||
{
|
||||
struct acpi_prt_entry *entry;
|
||||
struct acpi_prt_entry *entry = NULL;
|
||||
struct pci_dev *bridge;
|
||||
u8 bridge_pin, orig_pin = pin;
|
||||
int ret;
|
||||
|
||||
entry = acpi_pci_irq_find_prt_entry(dev, pin);
|
||||
if (entry) {
|
||||
ret = acpi_pci_irq_find_prt_entry(dev, pin, &entry);
|
||||
if (!ret && entry) {
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
acpi_reroute_boot_interrupt(dev, entry);
|
||||
#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;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
@ -393,8 +354,8 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
||||
pin = bridge_pin;
|
||||
}
|
||||
|
||||
entry = acpi_pci_irq_find_prt_entry(bridge, pin);
|
||||
if (entry) {
|
||||
ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry);
|
||||
if (!ret && entry) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Derived GSI for %s INT %c from %s\n",
|
||||
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",
|
||||
pin_name(pin));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -477,6 +439,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
||||
if (rc < 0) {
|
||||
dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
|
||||
pin_name(pin));
|
||||
kfree(entry);
|
||||
return rc;
|
||||
}
|
||||
dev->irq = rc;
|
||||
@ -491,6 +454,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
||||
(triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
|
||||
(polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
|
||||
|
||||
kfree(entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -513,6 +477,8 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
|
||||
else
|
||||
gsi = entry->index;
|
||||
|
||||
kfree(entry);
|
||||
|
||||
/*
|
||||
* TBD: It might be worth clearing dev->irq by magic constant
|
||||
* (e.g. PCI_UNDEFINED_IRQ).
|
||||
|
@ -103,24 +103,6 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *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
|
||||
* @handle - the ACPI CA node in question.
|
||||
@ -431,7 +413,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
||||
acpi_status status;
|
||||
int result;
|
||||
struct acpi_pci_root *root;
|
||||
acpi_handle handle;
|
||||
struct acpi_pci_driver *driver;
|
||||
u32 flags, base_flags;
|
||||
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),
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -597,8 +568,10 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
||||
if (device->wakeup.flags.run_wake)
|
||||
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);
|
||||
}
|
||||
|
||||
mutex_lock(&acpi_pci_root_lock);
|
||||
list_for_each_entry(driver, &acpi_pci_drivers, node)
|
||||
@ -618,7 +591,6 @@ out_del_root:
|
||||
list_del(&root->node);
|
||||
mutex_unlock(&acpi_pci_root_lock);
|
||||
|
||||
acpi_pci_irq_del_prt(root->segment, root->secondary.start);
|
||||
end:
|
||||
kfree(root);
|
||||
return result;
|
||||
@ -626,8 +598,6 @@ end:
|
||||
|
||||
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_driver *driver;
|
||||
|
||||
@ -642,10 +612,6 @@ static void acpi_pci_root_remove(struct acpi_device *device)
|
||||
device_set_run_wake(root->bus->bridge, false);
|
||||
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);
|
||||
|
||||
mutex_lock(&acpi_pci_root_lock);
|
||||
@ -663,3 +629,133 @@ void __init acpi_pci_root_init(void)
|
||||
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);
|
||||
}
|
||||
|
@ -329,19 +329,8 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
|
||||
{}
|
||||
};
|
||||
|
||||
static int __init
|
||||
acpi_pci_slot_init(void)
|
||||
void __init acpi_pci_slot_init(void)
|
||||
{
|
||||
dmi_check_system(acpi_pci_slot_dmi_table);
|
||||
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);
|
||||
|
@ -1783,6 +1783,7 @@ int __init acpi_scan_init(void)
|
||||
acpi_platform_init();
|
||||
acpi_csrt_init();
|
||||
acpi_container_init();
|
||||
acpi_pci_slot_init();
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
/*
|
||||
@ -1804,6 +1805,8 @@ int __init acpi_scan_init(void)
|
||||
|
||||
acpi_update_all_gpes();
|
||||
|
||||
acpi_pci_root_hp_init();
|
||||
|
||||
out:
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
return result;
|
||||
|
@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
|
||||
|
||||
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)
|
||||
@ -497,7 +497,7 @@ static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
|
||||
return pcie_cap_version(dev) > 1 ||
|
||||
type == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
(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)
|
||||
@ -515,7 +515,7 @@ static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
|
||||
return false;
|
||||
|
||||
switch (pos) {
|
||||
case PCI_EXP_FLAGS_TYPE:
|
||||
case PCI_EXP_FLAGS:
|
||||
return true;
|
||||
case PCI_EXP_DEVCAP:
|
||||
case PCI_EXP_DEVCTL:
|
||||
|
@ -158,69 +158,38 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
|
||||
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
|
||||
*
|
||||
* This adds a single pci device to the global
|
||||
* device list and adds sysfs and procfs entries
|
||||
* This adds add sysfs entries and start device drivers
|
||||
*/
|
||||
int pci_bus_add_device(struct pci_dev *dev)
|
||||
{
|
||||
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);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = device_add(&dev->dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
dev->match_driver = true;
|
||||
retval = device_attach(&dev->dev);
|
||||
WARN_ON(retval < 0);
|
||||
|
||||
dev->is_added = 1;
|
||||
pci_proc_attach_device(dev);
|
||||
pci_create_sysfs_dev_files(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_bus_add_child - add a child bus
|
||||
* @bus: bus to add
|
||||
*
|
||||
* This adds sysfs entries for a single bus
|
||||
*/
|
||||
int pci_bus_add_child(struct pci_bus *bus)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (bus->bridge)
|
||||
bus->dev.parent = bus->bridge;
|
||||
|
||||
retval = device_register(&bus->dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bus->is_added = 1;
|
||||
|
||||
/* Create legacy_io and legacy_mem files for this bus */
|
||||
pci_create_legacy_files(bus);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_bus_add_devices - insert newly discovered PCI devices
|
||||
* pci_bus_add_devices - start driver for PCI devices
|
||||
* @bus: bus to check for new devices
|
||||
*
|
||||
* Add newly discovered PCI devices (which are on the bus->devices
|
||||
* 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.
|
||||
* Start driver for PCI devices and add some sysfs entries.
|
||||
*/
|
||||
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)
|
||||
continue;
|
||||
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) {
|
||||
BUG_ON(!dev->is_added);
|
||||
|
||||
child = dev->subordinate;
|
||||
/*
|
||||
* If there is an unattached subordinate bus, attach
|
||||
* it and then scan for unattached PCI devices.
|
||||
*/
|
||||
|
||||
if (!child)
|
||||
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);
|
||||
|
||||
/*
|
||||
* register the bus with sysfs as the parent is now
|
||||
* properly registered.
|
||||
*/
|
||||
if (child->is_added)
|
||||
continue;
|
||||
retval = pci_bus_add_child(child);
|
||||
if (retval)
|
||||
dev_err(&dev->dev, "Error adding bus, continuing\n");
|
||||
child->is_added = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,6 @@ struct acpiphp_bridge {
|
||||
/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
|
||||
struct acpiphp_func *func;
|
||||
|
||||
int type;
|
||||
int nr_slots;
|
||||
|
||||
u32 flags;
|
||||
@ -146,10 +145,6 @@ struct acpiphp_attention_info
|
||||
/* PCI bus bridge HID */
|
||||
#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) */
|
||||
#define ACPI_STA_PRESENT (0x00000001)
|
||||
#define ACPI_STA_ENABLED (0x00000002)
|
||||
@ -158,13 +153,7 @@ struct acpiphp_attention_info
|
||||
#define ACPI_STA_ALL (0x0000000f)
|
||||
|
||||
/* bridge flags */
|
||||
#define BRIDGE_HAS_STA (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)
|
||||
#define BRIDGE_HAS_EJ0 (0x00000001)
|
||||
|
||||
/* slot flags */
|
||||
|
||||
@ -193,7 +182,6 @@ extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
|
||||
/* acpiphp_glue.c */
|
||||
extern int acpiphp_glue_init (void);
|
||||
extern void acpiphp_glue_exit (void);
|
||||
extern int acpiphp_get_num_slots (void);
|
||||
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
|
||||
|
||||
extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
|
||||
|
@ -50,7 +50,6 @@
|
||||
bool acpiphp_debug;
|
||||
|
||||
/* local variables */
|
||||
static int num_slots;
|
||||
static struct acpiphp_attention_info *attention_info;
|
||||
|
||||
#define DRIVER_VERSION "0.5"
|
||||
@ -272,25 +271,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
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
|
||||
* @hotplug_slot: slot to free
|
||||
@ -379,7 +359,8 @@ static int __init acpiphp_init(void)
|
||||
return 0;
|
||||
|
||||
/* read all the ACPI info from the system */
|
||||
return init_acpi();
|
||||
/* initialize internal data structure etc. */
|
||||
return acpiphp_glue_init();
|
||||
}
|
||||
|
||||
|
||||
|
@ -325,8 +325,8 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
/* install notify handler */
|
||||
if (bridge->type != BRIDGE_TYPE_HOST) {
|
||||
/* install notify handler for P2P bridges */
|
||||
if (!pci_is_root_bus(bridge->pci_bus)) {
|
||||
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
|
||||
status = acpi_remove_notify_handler(bridge->func->handle,
|
||||
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)
|
||||
{
|
||||
acpi_handle dummy_handle;
|
||||
struct acpiphp_func *func;
|
||||
|
||||
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
|
||||
"_STA", &dummy_handle)))
|
||||
bridge->flags |= BRIDGE_HAS_STA;
|
||||
|
||||
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
|
||||
"_EJ0", &dummy_handle)))
|
||||
"_EJ0", &dummy_handle))) {
|
||||
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");
|
||||
|
||||
/* 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)
|
||||
return;
|
||||
|
||||
bridge->type = BRIDGE_TYPE_HOST;
|
||||
bridge->handle = handle;
|
||||
|
||||
bridge->pci_bus = root->bus;
|
||||
@ -432,7 +416,6 @@ static void add_p2p_bridge(acpi_handle *handle)
|
||||
return;
|
||||
}
|
||||
|
||||
bridge->type = BRIDGE_TYPE_P2P;
|
||||
bridge->handle = handle;
|
||||
config_p2p_bridge_flags(bridge);
|
||||
|
||||
@ -543,13 +526,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
|
||||
acpi_status status;
|
||||
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);
|
||||
if (ACPI_FAILURE(status))
|
||||
err("failed to remove notify handler\n");
|
||||
if (ACPI_FAILURE(status))
|
||||
err("failed to remove notify handler\n");
|
||||
}
|
||||
|
||||
if ((bridge->type != BRIDGE_TYPE_HOST) &&
|
||||
((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
|
||||
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
|
||||
status = acpi_install_notify_handler(bridge->func->handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
handle_hotplug_event_func,
|
||||
@ -630,9 +615,6 @@ static void remove_bridge(struct acpi_pci_root *root)
|
||||
bridge = acpiphp_handle_to_bridge(handle);
|
||||
if (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)
|
||||
@ -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
|
||||
* @slot: slot to be enabled
|
||||
@ -812,6 +817,9 @@ static int __ref enable_device(struct acpiphp_slot *slot)
|
||||
if (slot->flags & SLOT_ENABLED)
|
||||
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));
|
||||
if (num == 0) {
|
||||
/* 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 ||
|
||||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(func, &slot->funcs, sibling)
|
||||
acpiphp_bus_add(func);
|
||||
|
||||
pci_bus_assign_resources(bus);
|
||||
acpiphp_sanitize_bus(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
|
||||
*/
|
||||
|
||||
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
|
||||
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 ;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct acpiphp_bridge *bridge;
|
||||
char objname[64];
|
||||
struct acpi_buffer buffer = { .length = sizeof(objname),
|
||||
.pointer = objname };
|
||||
struct acpi_device *device;
|
||||
int num_sub_bridges = 0;
|
||||
struct acpiphp_hp_work *hp_work;
|
||||
struct acpi_hp_work *hp_work;
|
||||
acpi_handle handle;
|
||||
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;
|
||||
type = hp_work->type;
|
||||
bridge = (struct acpiphp_bridge *)hp_work->context;
|
||||
|
||||
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);
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
/* bus re-enumerate */
|
||||
dbg("%s: Bus check notify on %s\n", __func__, objname);
|
||||
if (bridge) {
|
||||
dbg("%s: re-enumerating slots under %s\n",
|
||||
__func__, objname);
|
||||
acpiphp_check_bridge(bridge);
|
||||
}
|
||||
if (num_sub_bridges)
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
|
||||
ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
|
||||
dbg("%s: re-enumerating slots under %s\n", __func__, objname);
|
||||
acpiphp_check_bridge(bridge);
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
|
||||
ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
@ -1267,8 +1165,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
/* request device eject */
|
||||
dbg("%s: Device eject notify on %s\n", __func__, objname);
|
||||
if ((bridge->type != BRIDGE_TYPE_HOST) &&
|
||||
(bridge->flags & BRIDGE_HAS_EJ0)) {
|
||||
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
|
||||
struct acpiphp_slot *slot;
|
||||
slot = bridge->func->slot;
|
||||
if (!acpiphp_disable_slot(slot))
|
||||
@ -1296,7 +1193,6 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
acpi_scan_lock_release();
|
||||
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
|
||||
* don't deadlock on hotplug actions.
|
||||
*/
|
||||
alloc_acpiphp_hp_work(handle, type, context,
|
||||
_handle_hotplug_event_bridge);
|
||||
alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
|
||||
}
|
||||
|
||||
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];
|
||||
struct acpi_buffer buffer = { .length = sizeof(objname),
|
||||
.pointer = objname };
|
||||
struct acpiphp_hp_work *hp_work;
|
||||
struct acpi_hp_work *hp_work;
|
||||
acpi_handle handle;
|
||||
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;
|
||||
type = hp_work->type;
|
||||
context = hp_work->context;
|
||||
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
|
||||
func = (struct acpiphp_func *)context;
|
||||
func = (struct acpiphp_func *)hp_work->context;
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
/* 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
|
||||
* don't deadlock on hotplug actions.
|
||||
*/
|
||||
alloc_acpiphp_hp_work(handle, type, context,
|
||||
_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 ;
|
||||
alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
|
||||
}
|
||||
|
||||
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 num = 0;
|
||||
|
||||
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);
|
||||
acpi_pci_register_driver(&acpi_pci_hp_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1452,28 +1320,6 @@ void acpiphp_glue_exit(void)
|
||||
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
|
||||
* @slot: ACPI PHP slot
|
||||
|
@ -252,8 +252,8 @@ int cpci_led_off(struct slot* slot)
|
||||
|
||||
int __ref cpci_configure_slot(struct slot *slot)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *parent;
|
||||
int fn;
|
||||
|
||||
dbg("%s - enter", __func__);
|
||||
|
||||
@ -282,18 +282,13 @@ int __ref cpci_configure_slot(struct slot *slot)
|
||||
}
|
||||
parent = slot->dev->bus;
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
struct pci_dev *dev;
|
||||
|
||||
dev = pci_get_slot(parent,
|
||||
PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
|
||||
if (!dev)
|
||||
list_for_each_entry(dev, &parent->devices, bus_list)
|
||||
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
|
||||
continue;
|
||||
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
|
||||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
|
||||
pci_hp_add_bridge(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
|
||||
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 i;
|
||||
struct pci_dev *dev;
|
||||
struct pci_dev *dev, *temp;
|
||||
|
||||
dbg("%s - enter", __func__);
|
||||
if (!slot->dev) {
|
||||
@ -314,13 +308,12 @@ int cpci_unconfigure_slot(struct slot* slot)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
dev = pci_get_slot(slot->bus,
|
||||
PCI_DEVFN(PCI_SLOT(slot->devfn), i));
|
||||
if (dev) {
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
|
||||
continue;
|
||||
pci_dev_get(dev);
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
pci_dev_put(slot->dev);
|
||||
slot->dev = NULL;
|
||||
|
@ -1900,8 +1900,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
||||
dbg("power fault\n");
|
||||
} else {
|
||||
/* refresh notification */
|
||||
if (p_slot)
|
||||
update_slot_info(ctrl, p_slot);
|
||||
update_slot_info(ctrl, p_slot);
|
||||
}
|
||||
|
||||
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
|
||||
* IO range registers */
|
||||
if (io_node) {
|
||||
memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
|
||||
io_node->next = NULL;
|
||||
memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
|
||||
io_node->next = NULL;
|
||||
|
||||
/* set IO base and Limit registers */
|
||||
temp_byte = io_node->base >> 8;
|
||||
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte);
|
||||
/* set IO base and Limit registers */
|
||||
temp_byte = io_node->base >> 8;
|
||||
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte);
|
||||
|
||||
temp_byte = (io_node->base + io_node->length - 1) >> 8;
|
||||
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
|
||||
} else {
|
||||
kfree(hold_IO_node);
|
||||
hold_IO_node = NULL;
|
||||
}
|
||||
temp_byte = (io_node->base + io_node->length - 1) >> 8;
|
||||
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
|
||||
|
||||
/* If we have memory resources copy them and fill in the
|
||||
* bridge's memory range registers. Otherwise, fill in the
|
||||
* range registers with values that disable them. */
|
||||
if (mem_node) {
|
||||
memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
|
||||
mem_node->next = NULL;
|
||||
/* Copy the memory resources and fill in the bridge's memory
|
||||
* range registers.
|
||||
*/
|
||||
memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
|
||||
mem_node->next = NULL;
|
||||
|
||||
/* set Mem base and Limit registers */
|
||||
temp_word = mem_node->base >> 16;
|
||||
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
|
||||
/* set Mem base and Limit registers */
|
||||
temp_word = mem_node->base >> 16;
|
||||
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
|
||||
|
||||
temp_word = (mem_node->base + mem_node->length - 1) >> 16;
|
||||
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;
|
||||
}
|
||||
temp_word = (mem_node->base + mem_node->length - 1) >> 16;
|
||||
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
|
||||
|
||||
memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
|
||||
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
|
||||
* First use the temporary node to store information for
|
||||
* 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->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
|
||||
* 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),
|
||||
&hold_p_mem_node, 0x100000);
|
||||
|
||||
|
@ -293,7 +293,6 @@ static void pciehp_remove(struct pcie_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int pciehp_suspend (struct pcie_device *dev)
|
||||
{
|
||||
dev_info(&dev->device, "%s ENTRY\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -303,7 +302,6 @@ static int pciehp_resume (struct pcie_device *dev)
|
||||
struct slot *slot;
|
||||
u8 status;
|
||||
|
||||
dev_info(&dev->device, "%s ENTRY\n", __func__);
|
||||
ctrl = get_service_data(dev);
|
||||
|
||||
/* reinitialize the chipset's event detection logic */
|
||||
|
@ -39,7 +39,7 @@ int pciehp_configure_device(struct slot *p_slot)
|
||||
struct pci_dev *dev;
|
||||
struct pci_dev *bridge = p_slot->ctrl->pcie->port;
|
||||
struct pci_bus *parent = bridge->subordinate;
|
||||
int num, fn;
|
||||
int num;
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
|
||||
@ -57,28 +57,18 @@ int pciehp_configure_device(struct slot *p_slot)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
|
||||
if (!dev)
|
||||
continue;
|
||||
list_for_each_entry(dev, &parent->devices, bus_list)
|
||||
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
|
||||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
|
||||
pci_hp_add_bridge(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
pci_assign_unassigned_bridge_resources(bridge);
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
|
||||
if (!dev)
|
||||
list_for_each_entry(dev, &parent->devices, bus_list) {
|
||||
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
|
||||
continue;
|
||||
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
|
||||
pci_dev_put(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
pci_configure_slot(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
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 ret, rc = 0;
|
||||
int j;
|
||||
u8 bctl = 0;
|
||||
u8 presence = 0;
|
||||
struct pci_dev *dev, *temp;
|
||||
struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate;
|
||||
u16 command;
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
@ -102,33 +92,31 @@ int pciehp_unconfigure_device(struct slot *p_slot)
|
||||
if (ret)
|
||||
presence = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
struct pci_dev *temp = pci_get_slot(parent, PCI_DEVFN(0, j));
|
||||
if (!temp)
|
||||
continue;
|
||||
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
|
||||
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
|
||||
list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
|
||||
pci_dev_get(dev);
|
||||
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
|
||||
pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
|
||||
if (bctl & PCI_BRIDGE_CTL_VGA) {
|
||||
ctrl_err(ctrl,
|
||||
"Cannot remove display device %s\n",
|
||||
pci_name(temp));
|
||||
pci_dev_put(temp);
|
||||
pci_name(dev));
|
||||
pci_dev_put(dev);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pci_stop_and_remove_bus_device(temp);
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
/*
|
||||
* Ensure that no new Requests will be generated from
|
||||
* the device.
|
||||
*/
|
||||
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_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;
|
||||
|
@ -334,7 +334,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
|
||||
struct slot *slot = bss_hotplug_slot->private;
|
||||
struct pci_bus *new_bus = NULL;
|
||||
struct pci_dev *dev;
|
||||
int func, num_funcs;
|
||||
int num_funcs;
|
||||
int new_ppb = 0;
|
||||
int rc;
|
||||
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
|
||||
* about them.
|
||||
*/
|
||||
for (func = 0; func < num_funcs; func++) {
|
||||
dev = pci_get_slot(slot->pci_bus,
|
||||
PCI_DEVFN(slot->device_num + 1,
|
||||
PCI_FUNC(func)));
|
||||
if (dev) {
|
||||
/* Need to do slot fixup on PPB before fixup of children
|
||||
* (PPB's pcidev_info needs to be in pcidev_info list
|
||||
* before child's SN_PCIDEV_INFO() call to setup
|
||||
* pdi_host_pcidev_info).
|
||||
*/
|
||||
pcibios_fixup_device_resources(dev);
|
||||
if (SN_ACPI_BASE_SUPPORT())
|
||||
sn_acpi_slot_fixup(dev);
|
||||
else
|
||||
sn_io_slot_fixup(dev);
|
||||
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
|
||||
pci_hp_add_bridge(dev);
|
||||
if (dev->subordinate) {
|
||||
new_bus = dev->subordinate;
|
||||
new_ppb = 1;
|
||||
}
|
||||
list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
|
||||
continue;
|
||||
|
||||
/* Need to do slot fixup on PPB before fixup of children
|
||||
* (PPB's pcidev_info needs to be in pcidev_info list
|
||||
* before child's SN_PCIDEV_INFO() call to setup
|
||||
* pdi_host_pcidev_info).
|
||||
*/
|
||||
pcibios_fixup_device_resources(dev);
|
||||
if (SN_ACPI_BASE_SUPPORT())
|
||||
sn_acpi_slot_fixup(dev);
|
||||
else
|
||||
sn_io_slot_fixup(dev);
|
||||
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
|
||||
pci_hp_add_bridge(dev);
|
||||
if (dev->subordinate) {
|
||||
new_bus = dev->subordinate;
|
||||
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)
|
||||
{
|
||||
struct slot *slot = bss_hotplug_slot->private;
|
||||
struct pci_dev *dev;
|
||||
int func;
|
||||
struct pci_dev *dev, *temp;
|
||||
int rc;
|
||||
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.*/
|
||||
for (func = 0; func < 8; func++) {
|
||||
dev = pci_get_slot(slot->pci_bus,
|
||||
PCI_DEVFN(slot->device_num + 1,
|
||||
PCI_FUNC(func)));
|
||||
if (dev) {
|
||||
sn_bus_free_data(dev);
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
|
||||
continue;
|
||||
|
||||
pci_dev_get(dev);
|
||||
sn_bus_free_data(dev);
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
/* Remove the SSDT for the slot from the ACPI namespace */
|
||||
|
@ -40,7 +40,7 @@ int __ref shpchp_configure_device(struct slot *p_slot)
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
struct pci_dev *bridge = ctrl->pci_dev;
|
||||
struct pci_bus *parent = bridge->subordinate;
|
||||
int num, fn;
|
||||
int num;
|
||||
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
|
||||
if (dev) {
|
||||
@ -57,24 +57,20 @@ int __ref shpchp_configure_device(struct slot *p_slot)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
|
||||
if (!dev)
|
||||
list_for_each_entry(dev, &parent->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != p_slot->device)
|
||||
continue;
|
||||
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
|
||||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
|
||||
pci_hp_add_bridge(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
pci_assign_unassigned_bridge_resources(bridge);
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
|
||||
if (!dev)
|
||||
list_for_each_entry(dev, &parent->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != p_slot->device)
|
||||
continue;
|
||||
pci_configure_slot(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
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 rc = 0;
|
||||
int j;
|
||||
u8 bctl = 0;
|
||||
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
|
||||
struct pci_dev *dev, *temp;
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
|
||||
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
|
||||
__func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
|
||||
|
||||
for (j = 0; j < 8 ; j++) {
|
||||
struct pci_dev *temp = pci_get_slot(parent,
|
||||
(p_slot->device << 3) | j);
|
||||
if (!temp)
|
||||
list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
|
||||
if (PCI_SLOT(dev->devfn) != p_slot->device)
|
||||
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) {
|
||||
ctrl_err(ctrl,
|
||||
"Cannot remove display device %s\n",
|
||||
pci_name(temp));
|
||||
pci_dev_put(temp);
|
||||
pci_name(dev));
|
||||
pci_dev_put(dev);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pci_stop_and_remove_bus_device(temp);
|
||||
pci_dev_put(temp);
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
int rc;
|
||||
struct pci_bus *child;
|
||||
|
||||
if (bus->number == busnr)
|
||||
@ -48,12 +47,7 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
|
||||
return NULL;
|
||||
|
||||
pci_bus_insert_busn_res(child, busnr, busnr);
|
||||
child->dev.parent = bus->bridge;
|
||||
rc = pci_bus_add_child(child);
|
||||
if (rc) {
|
||||
pci_remove_bus(child);
|
||||
return NULL;
|
||||
}
|
||||
bus->is_added = 1;
|
||||
|
||||
return child;
|
||||
}
|
||||
@ -123,8 +117,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
|
||||
virtfn->is_virtfn = 1;
|
||||
|
||||
rc = pci_bus_add_device(virtfn);
|
||||
if (rc)
|
||||
goto failed1;
|
||||
sprintf(buf, "virtfn%u", id);
|
||||
rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
|
||||
if (rc)
|
||||
|
@ -302,48 +302,11 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
|
||||
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)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
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)
|
||||
return;
|
||||
@ -358,7 +321,6 @@ static void pci_acpi_setup(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);
|
||||
struct acpi_device *adev;
|
||||
|
||||
@ -367,16 +329,11 @@ static void pci_acpi_cleanup(struct device *dev)
|
||||
device_set_run_wake(dev, false);
|
||||
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 = {
|
||||
.bus = &pci_bus_type,
|
||||
.find_device = acpi_pci_find_device,
|
||||
.find_bridge = acpi_pci_find_root_bridge,
|
||||
.setup = pci_acpi_setup,
|
||||
.cleanup = pci_acpi_cleanup,
|
||||
};
|
||||
|
@ -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
|
||||
* continue to do DMA
|
||||
*/
|
||||
pci_disable_device(pci_dev);
|
||||
pci_clear_master(pci_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -628,6 +628,7 @@ static int pci_pm_suspend(struct device *dev)
|
||||
goto Fixup;
|
||||
}
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
if (pm->suspend) {
|
||||
pci_power_t prev = pci_dev->current_state;
|
||||
int error;
|
||||
@ -774,6 +775,7 @@ static int pci_pm_freeze(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
if (pm->freeze) {
|
||||
int error;
|
||||
|
||||
@ -862,6 +864,7 @@ static int pci_pm_poweroff(struct device *dev)
|
||||
goto Fixup;
|
||||
}
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
if (pm->poweroff) {
|
||||
int error;
|
||||
|
||||
@ -987,6 +990,7 @@ static int pci_pm_runtime_suspend(struct device *dev)
|
||||
if (!pm || !pm->runtime_suspend)
|
||||
return -ENOSYS;
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
pci_dev->no_d3cold = false;
|
||||
error = pm->runtime_suspend(dev);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!pci_dev->match_driver)
|
||||
return 0;
|
||||
|
||||
pci_drv = to_pci_driver(drv);
|
||||
found_id = pci_match_device(pci_drv, pci_dev);
|
||||
if (found_id)
|
||||
return 1;
|
||||
|
@ -1151,8 +1151,7 @@ int pci_reenable_device(struct pci_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __pci_enable_device_flags(struct pci_dev *dev,
|
||||
resource_size_t flags)
|
||||
static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
|
||||
{
|
||||
int err;
|
||||
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);
|
||||
}
|
||||
|
||||
if (atomic_add_return(1, &dev->enable_cnt) > 1)
|
||||
if (atomic_inc_return(&dev->enable_cnt) > 1)
|
||||
return 0; /* already enabled */
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
|
||||
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
|
||||
*
|
||||
* 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;
|
||||
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)
|
||||
return;
|
||||
|
||||
if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI))
|
||||
return;
|
||||
|
||||
bridge = dev->bus->self;
|
||||
if (!bridge)
|
||||
return;
|
||||
@ -2065,8 +2067,15 @@ void pci_enable_ari(struct pci_dev *dev)
|
||||
if (!(cap & PCI_EXP_DEVCAP2_ARI))
|
||||
return;
|
||||
|
||||
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
|
||||
bridge->ari_enabled = 1;
|
||||
if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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;
|
||||
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;
|
||||
|
||||
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;
|
||||
pci_write_config_word(dev, PCI_COMMAND, command);
|
||||
|
||||
align = pci_specified_resource_alignment(dev);
|
||||
for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
|
||||
r = &dev->resource[i];
|
||||
if (!(r->flags & IORESOURCE_MEM))
|
||||
|
@ -203,8 +203,8 @@ extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
|
||||
struct resource *res, unsigned int reg);
|
||||
extern int pci_resource_bar(struct pci_dev *dev, int resno,
|
||||
enum pci_bar_type *type);
|
||||
extern int pci_bus_add_child(struct pci_bus *bus);
|
||||
extern void pci_enable_ari(struct pci_dev *dev);
|
||||
extern void pci_configure_ari(struct pci_dev *dev);
|
||||
|
||||
/**
|
||||
* pci_ari_enabled - query ARI forwarding status
|
||||
* @bus: the PCI bus
|
||||
|
@ -556,6 +556,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||||
struct pcie_link_state *link;
|
||||
int blacklist = !!pcie_aspm_sanity_check(pdev);
|
||||
|
||||
if (!aspm_support_enabled)
|
||||
return;
|
||||
|
||||
if (!pci_is_pcie(pdev) || pdev->link_state)
|
||||
return;
|
||||
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 pcie_link_state *link, *root, *parent_link;
|
||||
|
||||
if (!pci_is_pcie(pdev) || !parent || !parent->link_state)
|
||||
return;
|
||||
if ((pci_pcie_type(parent) != PCI_EXP_TYPE_ROOT_PORT) &&
|
||||
(pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM))
|
||||
if (!parent || !parent->link_state)
|
||||
return;
|
||||
|
||||
down_read(&pci_bus_sem);
|
||||
|
@ -272,7 +272,7 @@ static int get_port_device_capability(struct pci_dev *dev)
|
||||
|
||||
/* Hot-Plug Capable */
|
||||
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, ®32);
|
||||
if (reg32 & PCI_EXP_SLTCAP_HPC) {
|
||||
services |= PCIE_PORT_SERVICE_HP;
|
||||
|
@ -623,6 +623,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
|
||||
{
|
||||
struct pci_bus *child;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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
|
||||
* registered later in pci_bus_add_devices()
|
||||
* now as the parent is not properly set up yet.
|
||||
*/
|
||||
child->dev.class = &pcibus_class;
|
||||
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->busn_res.end = 0xff;
|
||||
|
||||
if (!bridge)
|
||||
return child;
|
||||
if (!bridge) {
|
||||
child->dev.parent = parent->bridge;
|
||||
goto add_dev;
|
||||
}
|
||||
|
||||
child->self = bridge;
|
||||
child->bridge = get_device(&bridge->dev);
|
||||
child->dev.parent = child->bridge;
|
||||
pci_set_bus_of_node(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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1285,7 +1295,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
|
||||
pci_vpd_pci22_init(dev);
|
||||
|
||||
/* Alternative Routing-ID Forwarding */
|
||||
pci_enable_ari(dev);
|
||||
pci_configure_ari(dev);
|
||||
|
||||
/* Single Root I/O Virtualization */
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
device_initialize(&dev->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_parms = &dev->dma_parms;
|
||||
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);
|
||||
list_add_tail(&dev->bus_list, &bus->devices);
|
||||
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)
|
||||
@ -1348,31 +1371,31 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
|
||||
}
|
||||
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;
|
||||
unsigned pos, next_fn;
|
||||
int pos;
|
||||
u16 cap = 0;
|
||||
unsigned next_fn;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
if (pci_ari_enabled(bus)) {
|
||||
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);
|
||||
if (!pos)
|
||||
return 0;
|
||||
pci_read_config_word(dev, pos + 4, &cap);
|
||||
next_fn = cap >> 8;
|
||||
if (next_fn <= fn)
|
||||
return 0;
|
||||
return next_fn;
|
||||
}
|
||||
pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap);
|
||||
next_fn = PCI_ARI_CAP_NFN(cap);
|
||||
if (next_fn <= fn)
|
||||
return 0; /* protect against malformed list */
|
||||
|
||||
static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
|
||||
{
|
||||
return (fn + 1) % 8;
|
||||
}
|
||||
return next_fn;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -1405,7 +1428,6 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
|
||||
{
|
||||
unsigned fn, nr = 0;
|
||||
struct pci_dev *dev;
|
||||
unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
|
||||
|
||||
if (only_one_child(bus) && (devfn > 0))
|
||||
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)
|
||||
nr++;
|
||||
|
||||
if (pci_ari_enabled(bus))
|
||||
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)) {
|
||||
for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
|
||||
dev = pci_scan_single_device(bus, devfn + fn);
|
||||
if (dev) {
|
||||
if (!dev->is_added)
|
||||
@ -1632,6 +1649,18 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
|
||||
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_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 *fmt;
|
||||
|
||||
|
||||
b = pci_alloc_bus();
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
b->sysdata = sysdata;
|
||||
b->ops = ops;
|
||||
b->number = b->busn_res.start = bus;
|
||||
b2 = pci_find_bus(pci_domain_nr(b), bus);
|
||||
if (b2) {
|
||||
/* 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.release = pci_release_bus_bridge_dev;
|
||||
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);
|
||||
if (error)
|
||||
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 */
|
||||
pci_create_legacy_files(b);
|
||||
|
||||
b->number = b->busn_res.start = bus;
|
||||
|
||||
if (parent)
|
||||
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
|
||||
else
|
||||
|
@ -24,7 +24,7 @@ static void pci_stop_dev(struct pci_dev *dev)
|
||||
if (dev->is_added) {
|
||||
pci_proc_detach_device(dev);
|
||||
pci_remove_sysfs_dev_files(dev);
|
||||
device_unregister(&dev->dev);
|
||||
device_del(&dev->dev);
|
||||
dev->is_added = 0;
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
|
||||
up_write(&pci_bus_sem);
|
||||
|
||||
pci_free_resources(dev);
|
||||
pci_dev_put(dev);
|
||||
put_device(&dev->dev);
|
||||
}
|
||||
|
||||
void pci_remove_bus(struct pci_bus *bus)
|
||||
|
@ -319,13 +319,13 @@ int pci_dev_present(const struct pci_device_id *ids)
|
||||
WARN_ON(in_interrupt());
|
||||
while (ids->vendor || ids->subvendor || ids->class_mask) {
|
||||
found = pci_get_dev_by_id(ids, NULL);
|
||||
if (found)
|
||||
goto exit;
|
||||
if (found) {
|
||||
pci_dev_put(found);
|
||||
return 1;
|
||||
}
|
||||
ids++;
|
||||
}
|
||||
exit:
|
||||
if (found)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_dev_present);
|
||||
|
@ -283,7 +283,7 @@ static void assign_requested_resources_sorted(struct list_head *head,
|
||||
idx = res - &dev_res->dev->resource[0];
|
||||
if (resource_size(res) &&
|
||||
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
|
||||
* be enabled later, don't add it to the list
|
||||
|
@ -323,6 +323,15 @@ struct acpi_eject_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 int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
|
||||
void acpi_bus_private_data_handler(acpi_handle, void *);
|
||||
@ -454,7 +463,6 @@ struct acpi_pci_root {
|
||||
/* helper */
|
||||
acpi_handle acpi_get_child(acpi_handle, u64);
|
||||
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);
|
||||
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev))
|
||||
|
||||
|
@ -90,11 +90,6 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
|
||||
int *polarity, char **name);
|
||||
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) */
|
||||
|
||||
struct pci_bus;
|
||||
|
@ -194,8 +194,6 @@ void acpi_os_fixed_event_count(u32 fixed_event_number);
|
||||
/*
|
||||
* Threads and Scheduling
|
||||
*/
|
||||
extern struct workqueue_struct *kacpi_hotplug_wq;
|
||||
|
||||
acpi_thread_id acpi_os_get_thread_id(void);
|
||||
|
||||
acpi_status
|
||||
|
@ -286,6 +286,7 @@ struct pci_dev {
|
||||
unsigned int irq;
|
||||
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 */
|
||||
unsigned int transparent:1; /* Transparent PCI bridge */
|
||||
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_data);
|
||||
|
||||
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge);
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -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 */
|
||||
extern int no_pci_devices(void);
|
||||
|
||||
void pcibios_resource_survey_bus(struct pci_bus *bus);
|
||||
void pcibios_fixup_bus(struct pci_bus *);
|
||||
int __must_check pcibios_enable_device(struct pci_dev *, int mask);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @dev: PCI device
|
||||
*/
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user