diff options
Diffstat (limited to 'drivers/acpi/pci_slot.c')
| -rw-r--r-- | drivers/acpi/pci_slot.c | 217 | 
1 files changed, 32 insertions, 185 deletions
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 07f7fea8a4e..139d9e47937 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -9,6 +9,9 @@   *  Copyright (C) 2007-2008 Hewlett-Packard Development Company, L.P.   *  	Alex Chiang <achiang@hp.com>   * + *  Copyright (C) 2013 Huawei Tech. Co., Ltd. + *	Jiang Liu <jiang.liu@huawei.com> + *   *  This program is free software; you can redistribute it and/or modify it   *  under the terms and conditions of the GNU General Public License,   *  version 2, as published by the Free Software Foundation. @@ -28,13 +31,13 @@  #include <linux/init.h>  #include <linux/slab.h>  #include <linux/types.h> +#include <linux/list.h>  #include <linux/pci.h>  #include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h>  #include <linux/dmi.h> +#include <linux/pci-acpi.h> -static int debug; +static bool debug;  static int check_sta_before_sun;  #define DRIVER_VERSION 	"0.1" @@ -50,32 +53,23 @@ module_param(debug, bool, 0644);  ACPI_MODULE_NAME("pci_slot");  #define MY_NAME "pci_slot" -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define err(format, arg...) pr_err("%s: " format , MY_NAME , ## arg) +#define info(format, arg...) pr_info("%s: " format , MY_NAME , ## arg)  #define dbg(format, arg...)					\  	do {							\  		if (debug)					\ -			printk(KERN_DEBUG "%s: " format,	\ -				MY_NAME , ## arg);		\ +			pr_debug("%s: " format,	MY_NAME , ## arg); \  	} while (0)  #define SLOT_NAME_SIZE 21		/* Inspired by #define in acpiphp.h */  struct acpi_pci_slot { -	acpi_handle root_handle;	/* handle of the root bridge */  	struct pci_slot *pci_slot;	/* corresponding pci_slot */  	struct list_head list;		/* node in the list of slots */  }; -static int acpi_pci_slot_add(acpi_handle handle); -static void acpi_pci_slot_remove(acpi_handle handle); -  static LIST_HEAD(slot_list);  static DEFINE_MUTEX(slot_list_lock); -static struct acpi_pci_driver acpi_pci_slot_driver = { -	.add = acpi_pci_slot_add, -	.remove = acpi_pci_slot_remove, -};  static int  check_slot(acpi_handle handle, unsigned long long *sun) @@ -114,21 +108,8 @@ out:  	return device;  } -struct callback_args { -	acpi_walk_callback	user_function;	/* only for walk_p2p_bridge */ -	struct pci_bus		*pci_bus; -	acpi_handle		root_handle; -}; -  /* - * register_slot - * - * Called once for each SxFy object in the namespace. Don't worry about - * calling pci_create_slot multiple times for the same pci_bus:device, - * since each subsequent call simply bumps the refcount on the pci_slot. - * - * The number of calls to pci_destroy_slot from unregister_slot is - * symmetrical. + * Check whether handle has an associated slot and create PCI slot if it has.   */  static acpi_status  register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) @@ -138,13 +119,22 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)  	char name[SLOT_NAME_SIZE];  	struct acpi_pci_slot *slot;  	struct pci_slot *pci_slot; -	struct callback_args *parent_context = context; -	struct pci_bus *pci_bus = parent_context->pci_bus; +	struct pci_bus *pci_bus = context;  	device = check_slot(handle, &sun);  	if (device < 0)  		return AE_OK; +	/* +	 * There may be multiple PCI functions associated with the same slot. +	 * Check whether PCI slot has already been created for this PCI device. +	 */ +	list_for_each_entry(slot, &slot_list, list) { +		pci_slot = slot->pci_slot; +		if (pci_slot->bus == pci_bus && pci_slot->number == device) +			return AE_OK; +	} +  	slot = kmalloc(sizeof(*slot), GFP_KERNEL);  	if (!slot) {  		err("%s: cannot allocate memory\n", __func__); @@ -159,12 +149,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)  		return AE_OK;  	} -	slot->root_handle = parent_context->root_handle;  	slot->pci_slot = pci_slot; -	INIT_LIST_HEAD(&slot->list); -	mutex_lock(&slot_list_lock);  	list_add(&slot->list, &slot_list); -	mutex_unlock(&slot_list_lock);  	get_device(&pci_bus->dev); @@ -174,155 +160,28 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)  	return AE_OK;  } -/* - * walk_p2p_bridge - discover and walk p2p bridges - * @handle: points to an acpi_pci_root - * @context: p2p_bridge_context pointer - * - * Note that when we call ourselves recursively, we pass a different - * value of pci_bus in the child_context. - */ -static acpi_status -walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) +void acpi_pci_slot_enumerate(struct pci_bus *bus)  { -	int device, function; -	unsigned long long adr; -	acpi_status status; -	acpi_handle dummy_handle; -	acpi_walk_callback user_function; - -	struct pci_dev *dev; -	struct pci_bus *pci_bus; -	struct callback_args child_context; -	struct callback_args *parent_context = context; - -	pci_bus = parent_context->pci_bus; -	user_function = parent_context->user_function; - -	status = acpi_get_handle(handle, "_ADR", &dummy_handle); -	if (ACPI_FAILURE(status)) -		return AE_OK; +	acpi_handle handle = ACPI_HANDLE(bus->bridge); -	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); -	if (ACPI_FAILURE(status)) -		return AE_OK; - -	device = (adr >> 16) & 0xffff; -	function = adr & 0xffff; - -	dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); -	if (!dev || !dev->subordinate) -		goto out; - -	child_context.pci_bus = dev->subordinate; -	child_context.user_function = user_function; -	child_context.root_handle = parent_context->root_handle; - -	dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number); -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, -				     user_function, NULL, &child_context, NULL); -	if (ACPI_FAILURE(status)) -		goto out; - -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, -				     walk_p2p_bridge, NULL, &child_context, NULL); -out: -	pci_dev_put(dev); -	return AE_OK; -} - -/* - * walk_root_bridge - generic root bridge walker - * @handle: points to an acpi_pci_root - * @user_function: user callback for slot objects - * - * Call user_function for all objects underneath this root bridge. - * Walk p2p bridges underneath us and call user_function on those too. - */ -static int -walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) -{ -	int seg, bus; -	unsigned long long tmp; -	acpi_status status; -	acpi_handle dummy_handle; -	struct pci_bus *pci_bus; -	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; +	if (handle) { +		mutex_lock(&slot_list_lock); +		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, +				    register_slot, NULL, bus, NULL); +		mutex_unlock(&slot_list_lock);  	} - -	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.user_function = user_function; -	context.root_handle = handle; - -	dbg("root bridge walk, pci_bus = %x\n", pci_bus->number); -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, -				     user_function, NULL, &context, NULL); -	if (ACPI_FAILURE(status)) -		return status; - -	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, -				     walk_p2p_bridge, NULL, &context, NULL); -	if (ACPI_FAILURE(status)) -		err("%s: walk_p2p_bridge failure - %d\n", __func__, status); - -	return status;  } -/* - * acpi_pci_slot_add - * @handle: points to an acpi_pci_root - */ -static int -acpi_pci_slot_add(acpi_handle handle) -{ -	acpi_status status; - -	status = walk_root_bridge(handle, register_slot); -	if (ACPI_FAILURE(status)) -		err("%s: register_slot failure - %d\n", __func__, status); - -	return status; -} - -/* - * acpi_pci_slot_remove - * @handle: points to an acpi_pci_root - */ -static void -acpi_pci_slot_remove(acpi_handle handle) +void acpi_pci_slot_remove(struct pci_bus *bus)  {  	struct acpi_pci_slot *slot, *tmp; -	struct pci_bus *pbus;  	mutex_lock(&slot_list_lock);  	list_for_each_entry_safe(slot, tmp, &slot_list, list) { -		if (slot->root_handle == handle) { +		if (slot->pci_slot->bus == bus) {  			list_del(&slot->list); -			pbus = slot->pci_slot->bus;  			pci_destroy_slot(slot->pci_slot); -			put_device(&pbus->dev); +			put_device(&bus->dev);  			kfree(slot);  		}  	} @@ -354,19 +213,7 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {  	{}  }; -static int __init -acpi_pci_slot_init(void) +void __init acpi_pci_slot_init(void)  {  	dmi_check_system(acpi_pci_slot_dmi_table); -	acpi_pci_register_driver(&acpi_pci_slot_driver); -	return 0;  } - -static void __exit -acpi_pci_slot_exit(void) -{ -	acpi_pci_unregister_driver(&acpi_pci_slot_driver); -} - -module_init(acpi_pci_slot_init); -module_exit(acpi_pci_slot_exit);  | 
