Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18d63c35 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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

parents 168ae6a0 cd4faf9c
Loading
Loading
Loading
Loading
+58 −43
Original line number Original line Diff line number Diff line
@@ -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;

	if (!driver->add)
		return 0;

		list_for_each_entry(root, &acpi_pci_roots, node) {
		list_for_each_entry(root, &acpi_pci_roots, node) {
		driver->add(root->device->handle);
			driver->add(root);
			n++;
			n++;
		}
		}
	mutex_unlock(&acpi_pci_root_lock);


	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;
		pptr = &(*pptr)->next;
	}
	BUG_ON(!*pptr);
	*pptr = (*pptr)->next;

	if (!driver->remove)
		return;

		list_for_each_entry(root, &acpi_pci_roots, node)
		list_for_each_entry(root, &acpi_pci_roots, node)
		driver->remove(root->device->handle);
			driver->remove(root);
	mutex_unlock(&acpi_pci_root_lock);
}
}

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;


end:
out_del_root:
	if (!list_empty(&root->node))
	mutex_lock(&acpi_pci_root_lock);
	list_del(&root->node);
	list_del(&root->node);
	mutex_unlock(&acpi_pci_root_lock);
end:
	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;
}
}
+10 −34
Original line number Original line Diff line number Diff line
@@ -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) {
+7 −5
Original line number Original line Diff line number Diff line
@@ -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 */
+3 −3
Original line number Original line Diff line number Diff line
@@ -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);
+11 −6
Original line number Original line Diff line number Diff line
@@ -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