Merge tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
[linux-3.10.git] / drivers / acpi / pci_slot.c
index dd376f7..cd1434e 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <linux/dmi.h>
 
-static int debug;
+static bool debug;
 static int check_sta_before_sun;
 
 #define DRIVER_VERSION         "0.1"
@@ -48,16 +50,15 @@ 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 20              /* Inspired by #define in acpiphp.h */
+#define SLOT_NAME_SIZE 21              /* Inspired by #define in acpiphp.h */
 
 struct acpi_pci_slot {
        acpi_handle root_handle;        /* handle of the root bridge */
@@ -65,8 +66,8 @@ struct acpi_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 int acpi_pci_slot_add(struct acpi_pci_root *root);
+static void acpi_pci_slot_remove(struct acpi_pci_root *root);
 
 static LIST_HEAD(slot_list);
 static DEFINE_MUTEX(slot_list_lock);
@@ -76,10 +77,10 @@ static struct acpi_pci_driver acpi_pci_slot_driver = {
 };
 
 static int
-check_slot(acpi_handle handle, int *device, unsigned long *sun)
+check_slot(acpi_handle handle, unsigned long long *sun)
 {
-       int retval = 0;
-       unsigned long adr, sta;
+       int device = -1;
+       unsigned long long adr, sta;
        acpi_status status;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
@@ -89,32 +90,27 @@ check_slot(acpi_handle handle, int *device, unsigned long *sun)
        if (check_sta_before_sun) {
                /* If SxFy doesn't have _STA, we just assume it's there */
                status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-               if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) {
-                       retval = -1;
+               if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT))
                        goto out;
-               }
        }
 
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
        if (ACPI_FAILURE(status)) {
                dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer);
-               retval = -1;
                goto out;
        }
 
-       *device = (adr >> 16) & 0xffff;
-
        /* No _SUN == not a slot == bail */
        status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
        if (ACPI_FAILURE(status)) {
                dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer);
-               retval = -1;
                goto out;
        }
 
+       device = (adr >> 16) & 0xffff;
 out:
        kfree(buffer.pointer);
-       return retval;
+       return device;
 }
 
 struct callback_args {
@@ -137,14 +133,15 @@ static acpi_status
 register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int device;
-       unsigned long sun;
+       unsigned long long sun;
        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;
 
-       if (check_slot(handle, &device, &sun))
+       device = check_slot(handle, &sun);
+       if (device < 0)
                return AE_OK;
 
        slot = kmalloc(sizeof(*slot), GFP_KERNEL);
@@ -153,8 +150,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                return AE_OK;
        }
 
-       snprintf(name, sizeof(name), "%u", (u32)sun);
-       pci_slot = pci_create_slot(pci_bus, device, name);
+       snprintf(name, sizeof(name), "%llu", sun);
+       pci_slot = pci_create_slot(pci_bus, device, name, NULL);
        if (IS_ERR(pci_slot)) {
                err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
                kfree(slot);
@@ -168,6 +165,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        list_add(&slot->list, &slot_list);
        mutex_unlock(&slot_list_lock);
 
+       get_device(&pci_bus->dev);
+
        dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n",
                pci_slot, pci_bus->number, device, name);
 
@@ -186,7 +185,7 @@ static acpi_status
 walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int device, function;
-       unsigned long adr;
+       unsigned long long adr;
        acpi_status status;
        acpi_handle dummy_handle;
        acpi_walk_callback user_function;
@@ -220,12 +219,12 @@ walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 
        dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    user_function, &child_context, NULL);
+                                    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, &child_context, NULL);
+                                    walk_p2p_bridge, NULL, &child_context, NULL);
 out:
        pci_dev_put(dev);
        return AE_OK;
@@ -233,57 +232,32 @@ out:
 
 /*
  * 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
  *
  * 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)
+walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
 {
-       int seg, bus;
-       unsigned long tmp;
        acpi_status status;
-       acpi_handle dummy_handle;
-       struct pci_bus *pci_bus;
+       acpi_handle handle = root->device->handle;
+       struct pci_bus *pci_bus = root->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;
-       }
-
-       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, &context, NULL);
+                                    user_function, NULL, &context, NULL);
        if (ACPI_FAILURE(status))
                return status;
 
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    walk_p2p_bridge, &context, NULL);
+                                    walk_p2p_bridge, NULL, &context, NULL);
        if (ACPI_FAILURE(status))
                err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
 
@@ -295,11 +269,11 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
  * @handle: points to an acpi_pci_root
  */
 static int
-acpi_pci_slot_add(acpi_handle handle)
+acpi_pci_slot_add(struct acpi_pci_root *root)
 {
        acpi_status status;
 
-       status = walk_root_bridge(handle, register_slot);
+       status = walk_root_bridge(root, register_slot);
        if (ACPI_FAILURE(status))
                err("%s: register_slot failure - %d\n", __func__, status);
 
@@ -311,15 +285,19 @@ acpi_pci_slot_add(acpi_handle handle)
  * @handle: points to an acpi_pci_root
  */
 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 pci_bus *pbus;
+       acpi_handle handle = root->device->handle;
 
        mutex_lock(&slot_list_lock);
        list_for_each_entry_safe(slot, tmp, &slot_list, list) {
                if (slot->root_handle == handle) {
                        list_del(&slot->list);
+                       pbus = slot->pci_slot->bus;
                        pci_destroy_slot(slot->pci_slot);
+                       put_device(&pbus->dev);
                        kfree(slot);
                }
        }
@@ -351,19 +329,8 @@ 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);