You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -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;
|
||||
|
||||
|
||||
+85
-28
@@ -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,23 +201,16 @@ 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++) {
|
||||
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) {
|
||||
if (!r->start || pci_claim_resource(dev, idx) < 0) {
|
||||
/*
|
||||
* Something is wrong with the region.
|
||||
* Invalidate the resource to prevent
|
||||
@@ -220,9 +221,17 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
|
||||
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 {
|
||||
@@ -230,9 +239,8 @@ struct pci_check_idx_range {
|
||||
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,7 +252,6 @@ 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++)
|
||||
for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
|
||||
@@ -278,36 +285,66 @@ static void __init pcibios_allocate_resources(int pass)
|
||||
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_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 int __init pcibios_assign_resources(void)
|
||||
static void pcibios_allocate_dev_rom_resource(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
struct resource *r;
|
||||
|
||||
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;
|
||||
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_bus *bus;
|
||||
|
||||
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);
|
||||
|
||||
+22
-2
@@ -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);
|
||||
|
||||
+33
-67
@@ -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 */
|
||||
@@ -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).
|
||||
|
||||
+133
-37
@@ -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);
|
||||
}
|
||||
|
||||
+1
-12
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user