Merge branch 'pci/yinghai-root-bus-hotplug' into next
* pci/yinghai-root-bus-hotplug: 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 PCI/ACPI: Print info if host bridge notify handler installation fails PCI: acpiphp: Move host bridge hotplug to pci_root.c PCI/ACPI: acpiphp: Rename alloc_acpiphp_hp_work() to alloc_acpi_hp_work() PCI: Make device create/destroy logic symmetric PCI: Fix reference count leak in pci_dev_present() PCI: Set pci_dev dev_node early so IOAPIC irq_descs are allocated locally PCI: Add root bus children dev's res to fail list PCI: acpiphp: Add is_hotplug_bridge detection Conflicts: drivers/pci/pci.h
This commit is contained in:
Коммит
939de1d69c
|
@ -68,6 +68,7 @@ struct acpi_ec {
|
|||
extern struct acpi_ec *first_ec;
|
||||
|
||||
int acpi_pci_root_init(void);
|
||||
void acpi_pci_root_hp_init(void);
|
||||
int acpi_ec_init(void);
|
||||
int acpi_ec_ecdt_probe(void);
|
||||
int acpi_boot_ec_enable(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);
|
||||
|
|
|
@ -655,3 +655,133 @@ int __init acpi_pci_root_init(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -1706,5 +1706,8 @@ int __init acpi_scan_init(void)
|
|||
}
|
||||
|
||||
acpi_update_all_gpes();
|
||||
|
||||
acpi_pci_root_hp_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -161,68 +161,35 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
|
|||
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)
|
||||
{
|
||||
|
@ -235,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -543,10 +543,13 @@ 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 (bridge->type != BRIDGE_TYPE_HOST) {
|
||||
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)) {
|
||||
|
@ -630,9 +633,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)
|
||||
|
@ -797,6 +797,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
|
||||
|
@ -831,8 +854,10 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1098,18 +1123,12 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
|
|||
}
|
||||
|
||||
/* Program resources in newly inserted bridge */
|
||||
static int acpiphp_configure_bridge (acpi_handle handle)
|
||||
static int acpiphp_configure_p2p_bridge(acpi_handle handle)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
struct pci_dev *pdev = acpi_get_pci_dev(handle);
|
||||
struct pci_bus *bus = pdev->subordinate;
|
||||
|
||||
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_dev_put(pdev);
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
|
@ -1119,7 +1138,7 @@ static int acpiphp_configure_bridge (acpi_handle handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void handle_bridge_insertion(acpi_handle handle, u32 type)
|
||||
static void handle_p2p_bridge_insertion(acpi_handle handle, u32 type)
|
||||
{
|
||||
struct acpi_device *device;
|
||||
|
||||
|
@ -1137,8 +1156,8 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type)
|
|||
err("ACPI device object missing\n");
|
||||
return;
|
||||
}
|
||||
if (!acpiphp_configure_bridge(handle))
|
||||
add_bridge(handle);
|
||||
if (!acpiphp_configure_p2p_bridge(handle))
|
||||
add_p2p_bridge(handle);
|
||||
else
|
||||
err("cannot configure and start bridge\n");
|
||||
|
||||
|
@ -1178,34 +1197,6 @@ 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;
|
||||
|
@ -1214,17 +1205,17 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
|
|||
.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;
|
||||
|
||||
if (acpi_bus_get_device(handle, &device)) {
|
||||
/* This bridge must have just been physically inserted */
|
||||
handle_bridge_insertion(handle, type);
|
||||
handle_p2p_bridge_insertion(handle, type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1321,8 +1312,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)
|
||||
|
@ -1331,12 +1321,12 @@ 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;
|
||||
|
@ -1397,23 +1387,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 = {
|
||||
|
@ -1426,15 +1400,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;
|
||||
}
|
||||
|
@ -1450,28 +1416,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
|
||||
|
|
|
@ -48,12 +48,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 +118,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)
|
||||
|
|
|
@ -1186,9 +1186,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;
|
||||
|
|
|
@ -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_configure_ari(struct pci_dev *dev);
|
||||
|
||||
/**
|
||||
* pci_ari_enabled - query ARI forwarding status
|
||||
* @bus: the PCI bus
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1650,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 */
|
||||
|
@ -1695,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
|
||||
|
|
|
@ -22,7 +22,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;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,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
|
||||
|
|
|
@ -310,6 +310,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 *);
|
||||
|
|
|
@ -193,8 +193,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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче