Merge branch 'pci/taku-acpi-pci-host-bridge-v3' into next
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user