]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/pci/hotplug/pci_hotplug_core.c
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[linux-2.6-omap-h63xx.git] / drivers / pci / hotplug / pci_hotplug_core.c
index a11021e8ce37bb0cc3e76f182dfbd84027ff8d9f..535fce0f07f964edd1ecebc019a4347ec71cb549 100644 (file)
 #include <linux/init.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <asm/uaccess.h>
+#include "../pci.h"
 
 #define MY_NAME        "pci_hotplug"
 
@@ -60,41 +62,7 @@ static int debug;
 //////////////////////////////////////////////////////////////////
 
 static LIST_HEAD(pci_hotplug_slot_list);
-
-struct kset *pci_hotplug_slots_kset;
-
-static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
-               struct attribute *attr, char *buf)
-{
-       struct hotplug_slot *slot = to_hotplug_slot(kobj);
-       struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
-       return attribute->show ? attribute->show(slot, buf) : -EIO;
-}
-
-static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
-               struct attribute *attr, const char *buf, size_t len)
-{
-       struct hotplug_slot *slot = to_hotplug_slot(kobj);
-       struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
-       return attribute->store ? attribute->store(slot, buf, len) : -EIO;
-}
-
-static struct sysfs_ops hotplug_slot_sysfs_ops = {
-       .show = hotplug_slot_attr_show,
-       .store = hotplug_slot_attr_store,
-};
-
-static void hotplug_slot_release(struct kobject *kobj)
-{
-       struct hotplug_slot *slot = to_hotplug_slot(kobj);
-       if (slot->release)
-               slot->release(slot);
-}
-
-static struct kobj_type hotplug_slot_ktype = {
-       .sysfs_ops = &hotplug_slot_sysfs_ops,
-       .release = &hotplug_slot_release,
-};
+static DEFINE_MUTEX(pci_hp_mutex);
 
 /* these strings match up with the values in pci_bus_speed */
 static char *pci_bus_speed_strings[] = {
@@ -135,13 +103,13 @@ static int get_##name (struct hotplug_slot *slot, type *value)            \
 {                                                                      \
        struct hotplug_slot_ops *ops = slot->ops;                       \
        int retval = 0;                                                 \
-       if (try_module_get(ops->owner)) {                               \
-               if (ops->get_##name)                                    \
-                       retval = ops->get_##name(slot, value);          \
-               else                                                    \
-                       *value = slot->info->name;                      \
-               module_put(ops->owner);                                 \
-       }                                                               \
+       if (!try_module_get(ops->owner))                                \
+               return -ENODEV;                                         \
+       if (ops->get_##name)                                            \
+               retval = ops->get_##name(slot, value);                  \
+       else                                                            \
+               *value = slot->info->name;                              \
+       module_put(ops->owner);                                         \
        return retval;                                                  \
 }
 
@@ -149,16 +117,15 @@ GET_STATUS(power_status, u8)
 GET_STATUS(attention_status, u8)
 GET_STATUS(latch_status, u8)
 GET_STATUS(adapter_status, u8)
-GET_STATUS(address, u32)
 GET_STATUS(max_bus_speed, enum pci_bus_speed)
 GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
-static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t power_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_power_status (slot, &value);
+       retval = get_power_status(slot->hotplug, &value);
        if (retval)
                goto exit;
        retval = sprintf (buf, "%d\n", value);
@@ -166,9 +133,10 @@ exit:
        return retval;
 }
 
-static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
+static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
                size_t count)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        unsigned long lpower;
        u8 power;
        int retval = 0;
@@ -204,29 +172,30 @@ exit:
        return count;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_power = {
+static struct pci_slot_attribute hotplug_slot_attr_power = {
        .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
        .show = power_read_file,
        .store = power_write_file
 };
 
-static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_attention_status (slot, &value);
+       retval = get_attention_status(slot->hotplug, &value);
        if (retval)
                goto exit;
-       retval = sprintf (buf, "%d\n", value);
+       retval = sprintf(buf, "%d\n", value);
 
 exit:
        return retval;
 }
 
-static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
+static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
                size_t count)
 {
+       struct hotplug_slot_ops *ops = slot->hotplug->ops;
        unsigned long lattention;
        u8 attention;
        int retval = 0;
@@ -235,13 +204,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
        attention = (u8)(lattention & 0xff);
        dbg (" - attention = %d\n", attention);
 
-       if (!try_module_get(slot->ops->owner)) {
+       if (!try_module_get(ops->owner)) {
                retval = -ENODEV;
                goto exit;
        }
-       if (slot->ops->set_attention_status)
-               retval = slot->ops->set_attention_status(slot, attention);
-       module_put(slot->ops->owner);
+       if (ops->set_attention_status)
+               retval = ops->set_attention_status(slot->hotplug, attention);
+       module_put(ops->owner);
 
 exit:  
        if (retval)
@@ -249,18 +218,18 @@ exit:
        return count;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
+static struct pci_slot_attribute hotplug_slot_attr_attention = {
        .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
        .show = attention_read_file,
        .store = attention_write_file
 };
 
-static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_latch_status (slot, &value);
+       retval = get_latch_status(slot->hotplug, &value);
        if (retval)
                goto exit;
        retval = sprintf (buf, "%d\n", value);
@@ -269,17 +238,17 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
+static struct pci_slot_attribute hotplug_slot_attr_latch = {
        .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
        .show = latch_read_file,
 };
 
-static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
 {
        int retval;
        u8 value;
 
-       retval = get_adapter_status (slot, &value);
+       retval = get_adapter_status(slot->hotplug, &value);
        if (retval)
                goto exit;
        retval = sprintf (buf, "%d\n", value);
@@ -288,42 +257,20 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
+static struct pci_slot_attribute hotplug_slot_attr_presence = {
        .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
        .show = presence_read_file,
 };
 
-static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
-{
-       int retval;
-       u32 address;
-
-       retval = get_address (slot, &address);
-       if (retval)
-               goto exit;
-       retval = sprintf (buf, "%04x:%02x:%02x\n",
-                         (address >> 16) & 0xffff,
-                         (address >> 8) & 0xff,
-                         address & 0xff);
-
-exit:
-       return retval;
-}
-
-static struct hotplug_slot_attribute hotplug_slot_attr_address = {
-       .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
-       .show = address_read_file,
-};
-
 static char *unknown_speed = "Unknown bus speed";
 
-static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
 {
        char *speed_string;
        int retval;
        enum pci_bus_speed value;
        
-       retval = get_max_bus_speed (slot, &value);
+       retval = get_max_bus_speed(slot->hotplug, &value);
        if (retval)
                goto exit;
 
@@ -338,18 +285,18 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
+static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
        .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
        .show = max_bus_speed_read_file,
 };
 
-static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
+static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
 {
        char *speed_string;
        int retval;
        enum pci_bus_speed value;
 
-       retval = get_cur_bus_speed (slot, &value);
+       retval = get_cur_bus_speed(slot->hotplug, &value);
        if (retval)
                goto exit;
 
@@ -364,14 +311,15 @@ exit:
        return retval;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
+static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
        .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
        .show = cur_bus_speed_read_file,
 };
 
-static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
+static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
                size_t count)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        unsigned long ltest;
        u32 test;
        int retval = 0;
@@ -394,13 +342,14 @@ exit:
        return count;
 }
 
-static struct hotplug_slot_attribute hotplug_slot_attr_test = {
+static struct pci_slot_attribute hotplug_slot_attr_test = {
        .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
        .store = test_write_file
 };
 
-static int has_power_file (struct hotplug_slot *slot)
+static int has_power_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if ((slot->ops->enable_slot) ||
@@ -410,8 +359,9 @@ static int has_power_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int has_attention_file (struct hotplug_slot *slot)
+static int has_attention_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if ((slot->ops->set_attention_status) ||
@@ -420,8 +370,9 @@ static int has_attention_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int has_latch_file (struct hotplug_slot *slot)
+static int has_latch_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if (slot->ops->get_latch_status)
@@ -429,8 +380,9 @@ static int has_latch_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int has_adapter_file (struct hotplug_slot *slot)
+static int has_adapter_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if (slot->ops->get_adapter_status)
@@ -438,17 +390,9 @@ static int has_adapter_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int has_address_file (struct hotplug_slot *slot)
-{
-       if ((!slot) || (!slot->ops))
-               return -ENODEV;
-       if (slot->ops->get_address)
-               return 0;
-       return -ENOENT;
-}
-
-static int has_max_bus_speed_file (struct hotplug_slot *slot)
+static int has_max_bus_speed_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if (slot->ops->get_max_bus_speed)
@@ -456,8 +400,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int has_cur_bus_speed_file (struct hotplug_slot *slot)
+static int has_cur_bus_speed_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if (slot->ops->get_cur_bus_speed)
@@ -465,8 +410,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int has_test_file (struct hotplug_slot *slot)
+static int has_test_file(struct pci_slot *pci_slot)
 {
+       struct hotplug_slot *slot = pci_slot->hotplug;
        if ((!slot) || (!slot->ops))
                return -ENODEV;
        if (slot->ops->hardware_test)
@@ -474,7 +420,7 @@ static int has_test_file (struct hotplug_slot *slot)
        return -ENOENT;
 }
 
-static int fs_add_slot (struct hotplug_slot *slot)
+static int fs_add_slot(struct pci_slot *slot)
 {
        int retval = 0;
 
@@ -505,13 +451,6 @@ static int fs_add_slot (struct hotplug_slot *slot)
                        goto exit_adapter;
        }
 
-       if (has_address_file(slot) == 0) {
-               retval = sysfs_create_file(&slot->kobj,
-                                          &hotplug_slot_attr_address.attr);
-               if (retval)
-                       goto exit_address;
-       }
-
        if (has_max_bus_speed_file(slot) == 0) {
                retval = sysfs_create_file(&slot->kobj,
                                           &hotplug_slot_attr_max_bus_speed.attr);
@@ -544,10 +483,6 @@ exit_cur_speed:
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
 
 exit_max_speed:
-       if (has_address_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
-
-exit_address:
        if (has_adapter_file(slot) == 0)
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
 
@@ -567,7 +502,7 @@ exit:
        return retval;
 }
 
-static void fs_remove_slot (struct hotplug_slot *slot)
+static void fs_remove_slot(struct pci_slot *slot)
 {
        if (has_power_file(slot) == 0)
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
@@ -581,9 +516,6 @@ static void fs_remove_slot (struct hotplug_slot *slot)
        if (has_adapter_file(slot) == 0)
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
 
-       if (has_address_file(slot) == 0)
-               sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
-
        if (has_max_bus_speed_file(slot) == 0)
                sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
 
@@ -601,7 +533,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
 
        list_for_each (tmp, &pci_hotplug_slot_list) {
                slot = list_entry (tmp, struct hotplug_slot, slot_list);
-               if (strcmp(slot->name, name) == 0)
+               if (strcmp(hotplug_slot_name(slot), name) == 0)
                        return slot;
        }
        return NULL;
@@ -609,17 +541,21 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
 
 /**
  * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
+ * @bus: bus this slot is on
  * @slot: pointer to the &struct hotplug_slot to register
+ * @slot_nr: slot number
+ * @name: name registered with kobject core
  *
  * Registers a hotplug slot with the pci hotplug subsystem, which will allow
  * userspace interaction to the slot.
  *
  * Returns 0 if successful, anything else for an error.
  */
-int pci_hp_register (struct hotplug_slot *slot)
+int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
+                       const char *name)
 {
        int result;
-       struct hotplug_slot *tmp;
+       struct pci_slot *pci_slot;
 
        if (slot == NULL)
                return -ENODEV;
@@ -631,58 +567,73 @@ int pci_hp_register (struct hotplug_slot *slot)
                return -EINVAL;
        }
 
-       /* Check if we have already registered a slot with the same name. */
-       tmp = get_slot_from_name(slot->name);
-       if (tmp)
-               return -EEXIST;
-
-       slot->kobj.kset = pci_hotplug_slots_kset;
-       result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
-                                     "%s", slot->name);
-       if (result) {
-               err("Unable to register kobject '%s'", slot->name);
-               return -EINVAL;
+       mutex_lock(&pci_hp_mutex);
+
+       /*
+        * No problems if we call this interface from both ACPI_PCI_SLOT
+        * driver and call it here again. If we've already created the
+        * pci_slot, the interface will simply bump the refcount.
+        */
+       pci_slot = pci_create_slot(bus, slot_nr, name, slot);
+       if (IS_ERR(pci_slot)) {
+               result = PTR_ERR(pci_slot);
+               goto out;
        }
 
-       list_add (&slot->slot_list, &pci_hotplug_slot_list);
+       slot->pci_slot = pci_slot;
+       pci_slot->hotplug = slot;
+
+       list_add(&slot->slot_list, &pci_hotplug_slot_list);
 
-       result = fs_add_slot (slot);
-       kobject_uevent(&slot->kobj, KOBJ_ADD);
-       dbg ("Added slot %s to the list\n", slot->name);
+       result = fs_add_slot(pci_slot);
+       kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
+       dbg("Added slot %s to the list\n", name);
+out:
+       mutex_unlock(&pci_hp_mutex);
        return result;
 }
 
 /**
  * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
- * @slot: pointer to the &struct hotplug_slot to deregister
+ * @hotplug: pointer to the &struct hotplug_slot to deregister
  *
  * The @slot must have been registered with the pci hotplug subsystem
  * previously with a call to pci_hp_register().
  *
  * Returns 0 if successful, anything else for an error.
  */
-int pci_hp_deregister (struct hotplug_slot *slot)
+int pci_hp_deregister(struct hotplug_slot *hotplug)
 {
        struct hotplug_slot *temp;
+       struct pci_slot *slot;
 
-       if (slot == NULL)
+       if (!hotplug)
                return -ENODEV;
 
-       temp = get_slot_from_name (slot->name);
-       if (temp != slot) {
+       mutex_lock(&pci_hp_mutex);
+       temp = get_slot_from_name(hotplug_slot_name(hotplug));
+       if (temp != hotplug) {
+               mutex_unlock(&pci_hp_mutex);
                return -ENODEV;
        }
-       list_del (&slot->slot_list);
 
-       fs_remove_slot (slot);
-       dbg ("Removed slot %s from the list\n", slot->name);
-       kobject_put(&slot->kobj);
+       list_del(&hotplug->slot_list);
+
+       slot = hotplug->pci_slot;
+       fs_remove_slot(slot);
+       dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug));
+
+       hotplug->release(hotplug);
+       slot->hotplug = NULL;
+       pci_destroy_slot(slot);
+       mutex_unlock(&pci_hp_mutex);
+
        return 0;
 }
 
 /**
  * pci_hp_change_slot_info - changes the slot's information structure in the core
- * @slot: pointer to the slot whose info has changed
+ * @hotplug: pointer to the slot whose info has changed
  * @info: pointer to the info copy into the slot's info structure
  *
  * @slot must have been registered with the pci 
@@ -690,13 +641,15 @@ int pci_hp_deregister (struct hotplug_slot *slot)
  *
  * Returns 0 if successful, anything else for an error.
  */
-int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
+int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
                                         struct hotplug_slot_info *info)
 {
-       if ((slot == NULL) || (info == NULL))
+       struct pci_slot *slot;
+       if (!hotplug || !info)
                return -ENODEV;
+       slot = hotplug->pci_slot;
 
-       memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
+       memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));
 
        return 0;
 }
@@ -704,36 +657,22 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
 static int __init pci_hotplug_init (void)
 {
        int result;
-       struct kset *pci_bus_kset;
-
-       pci_bus_kset = bus_get_kset(&pci_bus_type);
 
-       pci_hotplug_slots_kset = kset_create_and_add("slots", NULL,
-                                                    &pci_bus_kset->kobj);
-       if (!pci_hotplug_slots_kset) {
-               result = -ENOMEM;
-               err("Register subsys error\n");
-               goto exit;
-       }
        result = cpci_hotplug_init(debug);
        if (result) {
                err ("cpci_hotplug_init with error %d\n", result);
-               goto err_subsys;
+               goto err_cpci;
        }
 
        info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
-       goto exit;
 
-err_subsys:
-       kset_unregister(pci_hotplug_slots_kset);
-exit:
+err_cpci:
        return result;
 }
 
 static void __exit pci_hotplug_exit (void)
 {
        cpci_hotplug_exit();
-       kset_unregister(pci_hotplug_slots_kset);
 }
 
 module_init(pci_hotplug_init);
@@ -745,7 +684,6 @@ MODULE_LICENSE("GPL");
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
 
-EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset);
 EXPORT_SYMBOL_GPL(pci_hp_register);
 EXPORT_SYMBOL_GPL(pci_hp_deregister);
 EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);