diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-25 21:18:18 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-25 21:18:18 -0800 | 
| commit | 556f12f602ac0a18a82ca83e9f8e8547688fc633 (patch) | |
| tree | d4051f6dd57968c8e8e660ad117c5bedc2aa7e8e /drivers/acpi/pci_root.c | |
| parent | fffddfd6c8e0c10c42c6e2cc54ba880fcc36ebbb (diff) | |
| parent | 018ba0a6efada61b9bc17500101d81c3d35807c2 (diff) | |
| download | olio-linux-3.10-556f12f602ac0a18a82ca83e9f8e8547688fc633.tar.xz olio-linux-3.10-556f12f602ac0a18a82ca83e9f8e8547688fc633.zip  | |
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
  ...
Diffstat (limited to 'drivers/acpi/pci_root.c')
| -rw-r--r-- | drivers/acpi/pci_root.c | 170 | 
1 files changed, 133 insertions, 37 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index b3cc69c5caf..0ac546d5e53 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -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); +}  |