forked from mirrors/linux
		
	PCI: acpiphp: Do not use ACPI PCI subdriver mechanism
Previously the acpiphp driver registered itself as an ACPI PCI subdriver,
so its callbacks were invoked when creating/destroying PCI root
buses to manage ACPI-based PCI hotplug slots.  But it doesn't handle
P2P bridge hotplug events, so it will cause strange behaviour if there
are hotplug slots associated with a hot-removed P2P bridge.
This patch fixes this issue by:
1) Directly hooking into PCI core to update hotplug slot devices when
   creating/destroying PCI buses through:
	pci_{add|remove}_bus() -> acpi_pci_{add|remove}_bus()
2) Getting rid of unused ACPI PCI subdriver-related code
It also cleans up unused code in the acpiphp driver.
[bhelgaas: keep acpi_pci_add_bus() stub for CONFIG_ACPI=n]
Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Yinghai Lu <yinghai@kernel.org>
Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Cc: Toshi Kani <toshi.kani@hp.com>
			
			
This commit is contained in:
		
							parent
							
								
									6037a803b0
								
							
						
					
					
						commit
						3b63aaa70e
					
				
					 5 changed files with 71 additions and 247 deletions
				
			
		|  | @ -119,7 +119,6 @@ struct acpiphp_slot { | ||||||
|  */ |  */ | ||||||
| struct acpiphp_func { | struct acpiphp_func { | ||||||
| 	struct acpiphp_slot *slot;	/* parent */ | 	struct acpiphp_slot *slot;	/* parent */ | ||||||
| 	struct acpiphp_bridge *bridge;	/* Ejectable PCI-to-PCI bridge */ |  | ||||||
| 
 | 
 | ||||||
| 	struct list_head sibling; | 	struct list_head sibling; | ||||||
| 	struct notifier_block nb; | 	struct notifier_block nb; | ||||||
|  | @ -176,8 +175,6 @@ extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot); | ||||||
| extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); | extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); | ||||||
| 
 | 
 | ||||||
| /* acpiphp_glue.c */ | /* acpiphp_glue.c */ | ||||||
| extern int acpiphp_glue_init (void); |  | ||||||
| extern void acpiphp_glue_exit (void); |  | ||||||
| typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); | ||||||
| 
 | 
 | ||||||
| extern int acpiphp_enable_slot (struct acpiphp_slot *slot); | extern int acpiphp_enable_slot (struct acpiphp_slot *slot); | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <linux/pci.h> | #include <linux/pci.h> | ||||||
|  | #include <linux/pci-acpi.h> | ||||||
| #include <linux/pci_hotplug.h> | #include <linux/pci_hotplug.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/smp.h> | #include <linux/smp.h> | ||||||
|  | @ -354,19 +355,9 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static int __init acpiphp_init(void) | void __init acpiphp_init(void) | ||||||
| { | { | ||||||
| 	info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n", | 	info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n", | ||||||
| 		acpiphp_disabled ? ", disabled by user; please report a bug" | 		acpiphp_disabled ? ", disabled by user; please report a bug" | ||||||
| 				 : ""); | 				 : ""); | ||||||
| 
 |  | ||||||
| 	if (acpi_pci_disabled || acpiphp_disabled) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	/* read all the ACPI info from the system */ |  | ||||||
| 	/* initialize internal data structure etc. */ |  | ||||||
| 	return acpiphp_glue_init(); |  | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| module_init(acpiphp_init); |  | ||||||
|  |  | ||||||
|  | @ -157,6 +157,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | ||||||
| 	int device, function, retval; | 	int device, function, retval; | ||||||
| 	struct pci_bus *pbus = bridge->pci_bus; | 	struct pci_bus *pbus = bridge->pci_bus; | ||||||
| 	struct pci_dev *pdev; | 	struct pci_dev *pdev; | ||||||
|  | 	u32 val; | ||||||
| 
 | 
 | ||||||
| 	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) | 	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) | ||||||
| 		return AE_OK; | 		return AE_OK; | ||||||
|  | @ -249,11 +250,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | ||||||
| 	newfunc->slot = slot; | 	newfunc->slot = slot; | ||||||
| 	list_add_tail(&newfunc->sibling, &slot->funcs); | 	list_add_tail(&newfunc->sibling, &slot->funcs); | ||||||
| 
 | 
 | ||||||
| 	pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); | 	if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), | ||||||
| 	if (pdev) { | 				       &val, 60*1000)) | ||||||
| 		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | ||||||
| 		pci_dev_put(pdev); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if (is_dock_device(handle)) { | 	if (is_dock_device(handle)) { | ||||||
| 		/* we don't want to call this device's _EJ0
 | 		/* we don't want to call this device's _EJ0
 | ||||||
|  | @ -366,148 +365,6 @@ 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, |  | ||||||
| 					"_EJ0", &dummy_handle))) { |  | ||||||
| 		bridge->flags |= BRIDGE_HAS_EJ0; |  | ||||||
| 
 |  | ||||||
| 		dbg("found ejectable p2p bridge\n"); |  | ||||||
| 
 |  | ||||||
| 		/* make link between PCI bridge and PCI function */ |  | ||||||
| 		func = acpiphp_bridge_handle_to_function(bridge->handle); |  | ||||||
| 		if (!func) |  | ||||||
| 			return; |  | ||||||
| 		bridge->func = func; |  | ||||||
| 		func->bridge = bridge; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* allocate and initialize host bridge data structure */ |  | ||||||
| static void add_host_bridge(struct acpi_pci_root *root) |  | ||||||
| { |  | ||||||
| 	struct acpiphp_bridge *bridge; |  | ||||||
| 	acpi_handle handle = root->device->handle; |  | ||||||
| 
 |  | ||||||
| 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |  | ||||||
| 	if (bridge == NULL) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	bridge->handle = handle; |  | ||||||
| 
 |  | ||||||
| 	bridge->pci_bus = root->bus; |  | ||||||
| 
 |  | ||||||
| 	init_bridge_misc(bridge); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* allocate and initialize PCI-to-PCI bridge data structure */ |  | ||||||
| static void add_p2p_bridge(acpi_handle *handle) |  | ||||||
| { |  | ||||||
| 	struct acpiphp_bridge *bridge; |  | ||||||
| 
 |  | ||||||
| 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |  | ||||||
| 	if (bridge == NULL) { |  | ||||||
| 		err("out of memory\n"); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	bridge->handle = handle; |  | ||||||
| 	config_p2p_bridge_flags(bridge); |  | ||||||
| 
 |  | ||||||
| 	bridge->pci_dev = acpi_get_pci_dev(handle); |  | ||||||
| 	bridge->pci_bus = bridge->pci_dev->subordinate; |  | ||||||
| 	if (!bridge->pci_bus) { |  | ||||||
| 		err("This is not a PCI-to-PCI bridge!\n"); |  | ||||||
| 		goto err; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * Grab a ref to the subordinate PCI bus in case the bus is |  | ||||||
| 	 * removed via PCI core logical hotplug. The ref pins the bus |  | ||||||
| 	 * (which we access during module unload). |  | ||||||
| 	 */ |  | ||||||
| 	get_device(&bridge->pci_bus->dev); |  | ||||||
| 
 |  | ||||||
| 	init_bridge_misc(bridge); |  | ||||||
| 	return; |  | ||||||
|  err: |  | ||||||
| 	pci_dev_put(bridge->pci_dev); |  | ||||||
| 	kfree(bridge); |  | ||||||
| 	return; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* callback routine to find P2P bridges */ |  | ||||||
| static acpi_status |  | ||||||
| find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) |  | ||||||
| { |  | ||||||
| 	acpi_status status; |  | ||||||
| 	struct pci_dev *dev; |  | ||||||
| 
 |  | ||||||
| 	dev = acpi_get_pci_dev(handle); |  | ||||||
| 	if (!dev || !dev->subordinate) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	/* check if this bridge has ejectable slots */ |  | ||||||
| 	if ((detect_ejectable_slots(handle) > 0)) { |  | ||||||
| 		dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); |  | ||||||
| 		add_p2p_bridge(handle); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* search P2P bridges under this p2p bridge */ |  | ||||||
| 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |  | ||||||
| 				     find_p2p_bridge, NULL, NULL, NULL); |  | ||||||
| 	if (ACPI_FAILURE(status)) |  | ||||||
| 		warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |  | ||||||
| 
 |  | ||||||
|  out: |  | ||||||
| 	pci_dev_put(dev); |  | ||||||
| 	return AE_OK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* find hot-pluggable slots, and then find P2P bridge */ |  | ||||||
| static int add_bridge(struct acpi_pci_root *root) |  | ||||||
| { |  | ||||||
| 	acpi_status status; |  | ||||||
| 	unsigned long long tmp; |  | ||||||
| 	acpi_handle dummy_handle; |  | ||||||
| 	acpi_handle handle = root->device->handle; |  | ||||||
| 
 |  | ||||||
| 	/* if the bridge doesn't have _STA, we assume it is always there */ |  | ||||||
| 	status = acpi_get_handle(handle, "_STA", &dummy_handle); |  | ||||||
| 	if (ACPI_SUCCESS(status)) { |  | ||||||
| 		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); |  | ||||||
| 		if (ACPI_FAILURE(status)) { |  | ||||||
| 			dbg("%s: _STA evaluation failure\n", __func__); |  | ||||||
| 			return 0; |  | ||||||
| 		} |  | ||||||
| 		if ((tmp & ACPI_STA_DEVICE_FUNCTIONING) == 0) |  | ||||||
| 			/* don't register this object */ |  | ||||||
| 			return 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* check if this bridge has ejectable slots */ |  | ||||||
| 	if (detect_ejectable_slots(handle) > 0) { |  | ||||||
| 		dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |  | ||||||
| 		add_host_bridge(root); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* search P2P bridges under this host bridge */ |  | ||||||
| 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |  | ||||||
| 				     find_p2p_bridge, NULL, NULL, NULL); |  | ||||||
| 
 |  | ||||||
| 	if (ACPI_FAILURE(status)) |  | ||||||
| 		warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | ||||||
| { | { | ||||||
| 	struct acpiphp_bridge *bridge; | 	struct acpiphp_bridge *bridge; | ||||||
|  | @ -567,56 +424,12 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | ||||||
| 		slot = next; | 		slot = next; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 |  | ||||||
| 	 * Only P2P bridges have a pci_dev |  | ||||||
| 	 */ |  | ||||||
| 	if (bridge->pci_dev) |  | ||||||
| 	put_device(&bridge->pci_bus->dev); | 	put_device(&bridge->pci_bus->dev); | ||||||
| 
 |  | ||||||
| 	pci_dev_put(bridge->pci_dev); | 	pci_dev_put(bridge->pci_dev); | ||||||
| 	list_del(&bridge->list); | 	list_del(&bridge->list); | ||||||
| 	kfree(bridge); | 	kfree(bridge); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static acpi_status |  | ||||||
| cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) |  | ||||||
| { |  | ||||||
| 	struct acpiphp_bridge *bridge; |  | ||||||
| 
 |  | ||||||
| 	/* cleanup p2p bridges under this P2P bridge
 |  | ||||||
| 	   in a depth-first manner */ |  | ||||||
| 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |  | ||||||
| 				cleanup_p2p_bridge, NULL, NULL, NULL); |  | ||||||
| 
 |  | ||||||
| 	bridge = acpiphp_handle_to_bridge(handle); |  | ||||||
| 	if (bridge) |  | ||||||
| 		cleanup_bridge(bridge); |  | ||||||
| 
 |  | ||||||
| 	return AE_OK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void remove_bridge(struct acpi_pci_root *root) |  | ||||||
| { |  | ||||||
| 	struct acpiphp_bridge *bridge; |  | ||||||
| 	acpi_handle handle = root->device->handle; |  | ||||||
| 
 |  | ||||||
| 	/* cleanup p2p bridges under this host bridge
 |  | ||||||
| 	   in a depth-first manner */ |  | ||||||
| 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, |  | ||||||
| 				(u32)1, cleanup_p2p_bridge, NULL, NULL, NULL); |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * On root bridges with hotplug slots directly underneath (ie, |  | ||||||
| 	 * no p2p bridge between), we call cleanup_bridge().  |  | ||||||
| 	 * |  | ||||||
| 	 * The else clause cleans up root bridges that either had no |  | ||||||
| 	 * hotplug slots at all, or had a p2p bridge underneath. |  | ||||||
| 	 */ |  | ||||||
| 	bridge = acpiphp_handle_to_bridge(handle); |  | ||||||
| 	if (bridge) |  | ||||||
| 		cleanup_bridge(bridge); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int power_on_slot(struct acpiphp_slot *slot) | static int power_on_slot(struct acpiphp_slot *slot) | ||||||
| { | { | ||||||
| 	acpi_status status; | 	acpi_status status; | ||||||
|  | @ -798,6 +611,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * enable_device - enable, configure a slot |  * enable_device - enable, configure a slot | ||||||
|  * @slot: slot to be enabled |  * @slot: slot to be enabled | ||||||
|  | @ -812,7 +626,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) | ||||||
| 	struct acpiphp_func *func; | 	struct acpiphp_func *func; | ||||||
| 	int retval = 0; | 	int retval = 0; | ||||||
| 	int num, max, pass; | 	int num, max, pass; | ||||||
| 	acpi_status status; |  | ||||||
| 
 | 
 | ||||||
| 	if (slot->flags & SLOT_ENABLED) | 	if (slot->flags & SLOT_ENABLED) | ||||||
| 		goto err_exit; | 		goto err_exit; | ||||||
|  | @ -867,18 +680,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) | ||||||
| 			slot->flags &= (~SLOT_ENABLED); | 			slot->flags &= (~SLOT_ENABLED); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && |  | ||||||
| 		    dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) { |  | ||||||
| 			pci_dev_put(dev); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); |  | ||||||
| 		if (ACPI_FAILURE(status)) |  | ||||||
| 			warn("find_p2p_bridge failed (error code = 0x%x)\n", |  | ||||||
| 				status); |  | ||||||
| 		pci_dev_put(dev); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -912,16 +713,6 @@ static int disable_device(struct acpiphp_slot *slot) | ||||||
| { | { | ||||||
| 	struct acpiphp_func *func; | 	struct acpiphp_func *func; | ||||||
| 	struct pci_dev *pdev; | 	struct pci_dev *pdev; | ||||||
| 	struct pci_bus *bus = slot->bridge->pci_bus; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry(func, &slot->funcs, sibling) { |  | ||||||
| 		if (func->bridge) { |  | ||||||
| 			/* cleanup p2p bridges under this P2P bridge */ |  | ||||||
| 			cleanup_p2p_bridge(func->bridge->handle, |  | ||||||
| 						(u32)1, NULL, NULL); |  | ||||||
| 			func->bridge = NULL; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * enable_device() enumerates all functions in this device via | 	 * enable_device() enumerates all functions in this device via | ||||||
|  | @ -940,7 +731,6 @@ static int disable_device(struct acpiphp_slot *slot) | ||||||
| 
 | 
 | ||||||
| 	slot->flags &= (~SLOT_ENABLED); | 	slot->flags &= (~SLOT_ENABLED); | ||||||
| 
 | 
 | ||||||
| err_exit: |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1287,30 +1077,62 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, | ||||||
| 	alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); | 	alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct acpi_pci_driver acpi_pci_hp_driver = { | /*
 | ||||||
| 	.add =		add_bridge, |  * Create hotplug slots for the PCI bus. | ||||||
| 	.remove =	remove_bridge, |  * It should always return 0 to avoid skipping following notifiers. | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures |  | ||||||
|  */ |  */ | ||||||
| int __init acpiphp_glue_init(void) | void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) | ||||||
| { | { | ||||||
| 	acpi_pci_register_driver(&acpi_pci_hp_driver); | 	acpi_handle dummy_handle; | ||||||
|  | 	struct acpiphp_bridge *bridge; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	if (acpiphp_disabled) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (detect_ejectable_slots(handle) <= 0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | ||||||
|  | 	if (bridge == NULL) { | ||||||
|  | 		err("out of memory\n"); | ||||||
|  | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	bridge->handle = handle; | ||||||
|  | 	bridge->pci_dev = pci_dev_get(bus->self); | ||||||
|  | 	bridge->pci_bus = bus; | ||||||
| 
 | 
 | ||||||
| /**
 | 	/*
 | ||||||
|  * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures | 	 * Grab a ref to the subordinate PCI bus in case the bus is | ||||||
|  * | 	 * removed via PCI core logical hotplug. The ref pins the bus | ||||||
|  * This function frees all data allocated in acpiphp_glue_init(). | 	 * (which we access during module unload). | ||||||
| 	 */ | 	 */ | ||||||
| void  acpiphp_glue_exit(void) | 	get_device(&bus->dev); | ||||||
|  | 
 | ||||||
|  | 	if (!pci_is_root_bus(bridge->pci_bus) && | ||||||
|  | 	    ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||||||
|  | 					"_EJ0", &dummy_handle))) { | ||||||
|  | 		dbg("found ejectable p2p bridge\n"); | ||||||
|  | 		bridge->flags |= BRIDGE_HAS_EJ0; | ||||||
|  | 		bridge->func = acpiphp_bridge_handle_to_function(handle); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	init_bridge_misc(bridge); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Destroy hotplug slots associated with the PCI bus */ | ||||||
|  | void acpiphp_remove_slots(struct pci_bus *bus) | ||||||
| { | { | ||||||
| 	acpi_pci_unregister_driver(&acpi_pci_hp_driver); | 	struct acpiphp_bridge *bridge, *tmp; | ||||||
|  | 
 | ||||||
|  | 	if (acpiphp_disabled) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(bridge, tmp, &bridge_list, list) | ||||||
|  | 		if (bridge->pci_bus == bus) { | ||||||
|  | 			cleanup_bridge(bridge); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -297,6 +297,7 @@ void acpi_pci_add_bus(struct pci_bus *bus) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	acpi_pci_slot_enumerate(bus, handle); | 	acpi_pci_slot_enumerate(bus, handle); | ||||||
|  | 	acpiphp_enumerate_slots(bus, handle); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void acpi_pci_remove_bus(struct pci_bus *bus) | void acpi_pci_remove_bus(struct pci_bus *bus) | ||||||
|  | @ -308,6 +309,7 @@ void acpi_pci_remove_bus(struct pci_bus *bus) | ||||||
| 	if (acpi_pci_disabled) | 	if (acpi_pci_disabled) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	acpiphp_remove_slots(bus); | ||||||
| 	acpi_pci_slot_remove(bus); | 	acpi_pci_slot_remove(bus); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -388,6 +390,7 @@ static int __init acpi_pci_init(void) | ||||||
| 
 | 
 | ||||||
| 	pci_set_platform_pm(&acpi_pci_platform_pm); | 	pci_set_platform_pm(&acpi_pci_platform_pm); | ||||||
| 	acpi_pci_slot_init(); | 	acpi_pci_slot_init(); | ||||||
|  | 	acpiphp_init(); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -56,6 +56,17 @@ static inline void acpi_pci_slot_enumerate(struct pci_bus *bus, | ||||||
| static inline void acpi_pci_slot_remove(struct pci_bus *bus) { } | static inline void acpi_pci_slot_remove(struct pci_bus *bus) { } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef	CONFIG_HOTPLUG_PCI_ACPI | ||||||
|  | void acpiphp_init(void); | ||||||
|  | void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle); | ||||||
|  | void acpiphp_remove_slots(struct pci_bus *bus); | ||||||
|  | #else | ||||||
|  | static inline void acpiphp_init(void) { } | ||||||
|  | static inline void acpiphp_enumerate_slots(struct pci_bus *bus, | ||||||
|  | 					   acpi_handle handle) { } | ||||||
|  | static inline void acpiphp_remove_slots(struct pci_bus *bus) { } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #else	/* CONFIG_ACPI */ | #else	/* CONFIG_ACPI */ | ||||||
| static inline void acpi_pci_add_bus(struct pci_bus *bus) { } | static inline void acpi_pci_add_bus(struct pci_bus *bus) { } | ||||||
| static inline void acpi_pci_remove_bus(struct pci_bus *bus) { } | static inline void acpi_pci_remove_bus(struct pci_bus *bus) { } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jiang Liu
						Jiang Liu