Merge branch 'pci/taku-acpi-pci-host-bridge-v3' into next

This commit is contained in:
Bjorn Helgaas
2012-09-24 16:36:10 -06:00
5 changed files with 89 additions and 91 deletions

View File

@@ -27,7 +27,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/spinlock.h> #include <linux/mutex.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pci.h> #include <linux/pci.h>
@@ -71,9 +71,11 @@ static struct acpi_driver acpi_pci_root_driver = {
}, },
}; };
/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
static DEFINE_MUTEX(acpi_pci_root_lock);
static LIST_HEAD(acpi_pci_roots); static LIST_HEAD(acpi_pci_roots);
static LIST_HEAD(acpi_pci_drivers);
static struct acpi_pci_driver *sub_driver;
static DEFINE_MUTEX(osc_lock); static DEFINE_MUTEX(osc_lock);
int acpi_pci_register_driver(struct acpi_pci_driver *driver) int acpi_pci_register_driver(struct acpi_pci_driver *driver)
@@ -81,55 +83,46 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
int n = 0; int n = 0;
struct acpi_pci_root *root; struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver; mutex_lock(&acpi_pci_root_lock);
while (*pptr) list_add_tail(&driver->node, &acpi_pci_drivers);
pptr = &(*pptr)->next; if (driver->add)
*pptr = driver; list_for_each_entry(root, &acpi_pci_roots, node) {
driver->add(root);
if (!driver->add) n++;
return 0; }
mutex_unlock(&acpi_pci_root_lock);
list_for_each_entry(root, &acpi_pci_roots, node) {
driver->add(root->device->handle);
n++;
}
return n; return n;
} }
EXPORT_SYMBOL(acpi_pci_register_driver); EXPORT_SYMBOL(acpi_pci_register_driver);
void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
{ {
struct acpi_pci_root *root; struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver; mutex_lock(&acpi_pci_root_lock);
while (*pptr) { list_del(&driver->node);
if (*pptr == driver) if (driver->remove)
break; list_for_each_entry(root, &acpi_pci_roots, node)
pptr = &(*pptr)->next; driver->remove(root);
} mutex_unlock(&acpi_pci_root_lock);
BUG_ON(!*pptr);
*pptr = (*pptr)->next;
if (!driver->remove)
return;
list_for_each_entry(root, &acpi_pci_roots, node)
driver->remove(root->device->handle);
} }
EXPORT_SYMBOL(acpi_pci_unregister_driver); EXPORT_SYMBOL(acpi_pci_unregister_driver);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
{ {
struct acpi_pci_root *root; struct acpi_pci_root *root;
acpi_handle handle = NULL;
mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(root, &acpi_pci_roots, node) list_for_each_entry(root, &acpi_pci_roots, node)
if ((root->segment == (u16) seg) && if ((root->segment == (u16) seg) &&
(root->secondary.start == (u16) bus)) (root->secondary.start == (u16) bus)) {
return root->device->handle; handle = root->device->handle;
return NULL; break;
}
mutex_unlock(&acpi_pci_root_lock);
return handle;
} }
EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
@@ -277,12 +270,15 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
{ {
struct acpi_pci_root *root; struct acpi_pci_root *root;
struct acpi_device *device;
list_for_each_entry(root, &acpi_pci_roots, node) { if (acpi_bus_get_device(handle, &device) ||
if (root->device->handle == handle) acpi_match_device_ids(device, root_device_ids))
return root; return NULL;
}
return NULL; root = acpi_driver_data(device);
return root;
} }
EXPORT_SYMBOL_GPL(acpi_pci_find_root); EXPORT_SYMBOL_GPL(acpi_pci_find_root);
@@ -518,8 +514,9 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
* TBD: Need PCI interface for enumeration/configuration of roots. * TBD: Need PCI interface for enumeration/configuration of roots.
*/ */
/* TBD: Locking */ mutex_lock(&acpi_pci_root_lock);
list_add_tail(&root->node, &acpi_pci_roots); list_add_tail(&root->node, &acpi_pci_roots);
mutex_unlock(&acpi_pci_root_lock);
printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
acpi_device_name(device), acpi_device_bid(device), acpi_device_name(device), acpi_device_bid(device),
@@ -538,7 +535,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
"Bus %04x:%02x not present in PCI namespace\n", "Bus %04x:%02x not present in PCI namespace\n",
root->segment, (unsigned int)root->secondary.start); root->segment, (unsigned int)root->secondary.start);
result = -ENODEV; result = -ENODEV;
goto end; goto out_del_root;
} }
/* /*
@@ -548,7 +545,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
*/ */
result = acpi_pci_bind_root(device); result = acpi_pci_bind_root(device);
if (result) if (result)
goto end; goto out_del_root;
/* /*
* PCI Routing Table * PCI Routing Table
@@ -633,9 +630,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
return 0; return 0;
out_del_root:
mutex_lock(&acpi_pci_root_lock);
list_del(&root->node);
mutex_unlock(&acpi_pci_root_lock);
end: end:
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root); kfree(root);
return result; return result;
} }
@@ -643,18 +642,34 @@ end:
static int acpi_pci_root_start(struct acpi_device *device) static int acpi_pci_root_start(struct acpi_device *device)
{ {
struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_root *root = acpi_driver_data(device);
struct acpi_pci_driver *driver;
mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(driver, &acpi_pci_drivers, node)
if (driver->add)
driver->add(root);
mutex_unlock(&acpi_pci_root_lock);
pci_bus_add_devices(root->bus); pci_bus_add_devices(root->bus);
return 0; return 0;
} }
static int acpi_pci_root_remove(struct acpi_device *device, int type) static int acpi_pci_root_remove(struct acpi_device *device, int type)
{ {
struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_root *root = acpi_driver_data(device);
struct acpi_pci_driver *driver;
mutex_lock(&acpi_pci_root_lock);
list_for_each_entry(driver, &acpi_pci_drivers, node)
if (driver->remove)
driver->remove(root);
device_set_run_wake(root->bus->bridge, false); device_set_run_wake(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device); pci_acpi_remove_bus_pm_notifier(device);
list_del(&root->node);
mutex_unlock(&acpi_pci_root_lock);
kfree(root); kfree(root);
return 0; return 0;
} }

View File

@@ -67,8 +67,8 @@ struct acpi_pci_slot {
struct list_head list; /* node in the list of slots */ struct list_head list; /* node in the list of slots */
}; };
static int acpi_pci_slot_add(acpi_handle handle); static int acpi_pci_slot_add(struct acpi_pci_root *root);
static void acpi_pci_slot_remove(acpi_handle handle); static void acpi_pci_slot_remove(struct acpi_pci_root *root);
static LIST_HEAD(slot_list); static LIST_HEAD(slot_list);
static DEFINE_MUTEX(slot_list_lock); static DEFINE_MUTEX(slot_list_lock);
@@ -233,45 +233,20 @@ out:
/* /*
* walk_root_bridge - generic root bridge walker * walk_root_bridge - generic root bridge walker
* @handle: points to an acpi_pci_root * @root: poiner of an acpi_pci_root
* @user_function: user callback for slot objects * @user_function: user callback for slot objects
* *
* Call user_function for all objects underneath this root bridge. * Call user_function for all objects underneath this root bridge.
* Walk p2p bridges underneath us and call user_function on those too. * Walk p2p bridges underneath us and call user_function on those too.
*/ */
static int static int
walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
{ {
int seg, bus;
unsigned long long tmp;
acpi_status status; acpi_status status;
acpi_handle dummy_handle; acpi_handle handle = root->device->handle;
struct pci_bus *pci_bus; struct pci_bus *pci_bus = root->bus;
struct callback_args context; struct callback_args context;
/* 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)) {
info("%s: _STA evaluation failure\n", __func__);
return 0;
}
if ((tmp & ACPI_STA_DEVICE_FUNCTIONING) == 0)
/* don't register this object */
return 0;
}
status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
seg = ACPI_SUCCESS(status) ? tmp : 0;
status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
bus = ACPI_SUCCESS(status) ? tmp : 0;
pci_bus = pci_find_bus(seg, bus);
if (!pci_bus)
return 0;
context.pci_bus = pci_bus; context.pci_bus = pci_bus;
context.user_function = user_function; context.user_function = user_function;
context.root_handle = handle; context.root_handle = handle;
@@ -295,11 +270,11 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
* @handle: points to an acpi_pci_root * @handle: points to an acpi_pci_root
*/ */
static int static int
acpi_pci_slot_add(acpi_handle handle) acpi_pci_slot_add(struct acpi_pci_root *root)
{ {
acpi_status status; acpi_status status;
status = walk_root_bridge(handle, register_slot); status = walk_root_bridge(root, register_slot);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
err("%s: register_slot failure - %d\n", __func__, status); err("%s: register_slot failure - %d\n", __func__, status);
@@ -311,10 +286,11 @@ acpi_pci_slot_add(acpi_handle handle)
* @handle: points to an acpi_pci_root * @handle: points to an acpi_pci_root
*/ */
static void static void
acpi_pci_slot_remove(acpi_handle handle) acpi_pci_slot_remove(struct acpi_pci_root *root)
{ {
struct acpi_pci_slot *slot, *tmp; struct acpi_pci_slot *slot, *tmp;
struct pci_bus *pbus; struct pci_bus *pbus;
acpi_handle handle = root->device->handle;
mutex_lock(&slot_list_lock); mutex_lock(&slot_list_lock);
list_for_each_entry_safe(slot, tmp, &slot_list, list) { list_for_each_entry_safe(slot, tmp, &slot_list, list) {

View File

@@ -382,10 +382,10 @@ static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
/* allocate and initialize host bridge data structure */ /* allocate and initialize host bridge data structure */
static void add_host_bridge(acpi_handle *handle) static void add_host_bridge(struct acpi_pci_root *root)
{ {
struct acpiphp_bridge *bridge; struct acpiphp_bridge *bridge;
struct acpi_pci_root *root = acpi_pci_find_root(handle); acpi_handle handle = root->device->handle;
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
if (bridge == NULL) if (bridge == NULL)
@@ -468,11 +468,12 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
/* find hot-pluggable slots, and then find P2P bridge */ /* find hot-pluggable slots, and then find P2P bridge */
static int add_bridge(acpi_handle handle) static int add_bridge(struct acpi_pci_root *root)
{ {
acpi_status status; acpi_status status;
unsigned long long tmp; unsigned long long tmp;
acpi_handle dummy_handle; acpi_handle dummy_handle;
acpi_handle handle = root->device->handle;
/* if the bridge doesn't have _STA, we assume it is always there */ /* if the bridge doesn't have _STA, we assume it is always there */
status = acpi_get_handle(handle, "_STA", &dummy_handle); status = acpi_get_handle(handle, "_STA", &dummy_handle);
@@ -490,7 +491,7 @@ static int add_bridge(acpi_handle handle)
/* check if this bridge has ejectable slots */ /* check if this bridge has ejectable slots */
if (detect_ejectable_slots(handle) > 0) { if (detect_ejectable_slots(handle) > 0) {
dbg("found PCI host-bus bridge with hot-pluggable slots\n"); dbg("found PCI host-bus bridge with hot-pluggable slots\n");
add_host_bridge(handle); add_host_bridge(root);
} }
/* search P2P bridges under this host bridge */ /* search P2P bridges under this host bridge */
@@ -588,9 +589,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK; return AE_OK;
} }
static void remove_bridge(acpi_handle handle) static void remove_bridge(struct acpi_pci_root *root)
{ {
struct acpiphp_bridge *bridge; struct acpiphp_bridge *bridge;
acpi_handle handle = root->device->handle;
/* cleanup p2p bridges under this host bridge /* cleanup p2p bridges under this host bridge
in a depth-first manner */ in a depth-first manner */

View File

@@ -138,9 +138,9 @@ void acpi_penalize_isa_irq(int irq, int active);
void acpi_pci_irq_disable (struct pci_dev *dev); void acpi_pci_irq_disable (struct pci_dev *dev);
struct acpi_pci_driver { struct acpi_pci_driver {
struct acpi_pci_driver *next; struct list_head node;
int (*add)(acpi_handle handle); int (*add)(struct acpi_pci_root *root);
void (*remove)(acpi_handle handle); void (*remove)(struct acpi_pci_root *root);
}; };
int acpi_pci_register_driver(struct acpi_pci_driver *driver); int acpi_pci_register_driver(struct acpi_pci_driver *driver);

View File

@@ -22,19 +22,24 @@ extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
{ {
struct pci_bus *pbus = pdev->bus; struct pci_bus *pbus = pdev->bus;
/* Find a PCI root bus */ /* Find a PCI root bus */
while (!pci_is_root_bus(pbus)) while (!pci_is_root_bus(pbus))
pbus = pbus->parent; pbus = pbus->parent;
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
pbus->number); return DEVICE_ACPI_HANDLE(pbus->bridge);
} }
static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus) static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
{ {
if (!pci_is_root_bus(pbus)) struct device *dev;
return DEVICE_ACPI_HANDLE(&(pbus->self->dev));
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus), if (pci_is_root_bus(pbus))
pbus->number); dev = pbus->bridge;
else
dev = &pbus->self->dev;
return DEVICE_ACPI_HANDLE(dev);
} }
#endif #endif