X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fpci%2Fhotplug%2Frpaphp_core.c;h=ef7411c660b99f0352548fb989fb6f5fa7dc158e;hb=3374cd1abd478f767aaedf2c21d109596ff0fe72;hp=353da5b296ef797ce74cf13d69849c7be1c922a5;hpb=d05c7a80cf39ae7d0f8d0c3e47c93d51fcd393d3;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 353da5b..ef7411c 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -27,10 +27,9 @@ #include #include #include -#include #include -#include #include +#include #include /* for eeh_add_device() */ #include /* rtas_call */ #include /* for pci_controller */ @@ -38,10 +37,8 @@ /* and pci_do_scan_bus */ #include "rpaphp.h" -int debug; -static struct semaphore rpaphp_sem; +int rpaphp_debug; LIST_HEAD(rpaphp_slot_head); -int num_slots; #define DRIVER_VERSION "0.1" #define DRIVER_AUTHOR "Linda Xie " @@ -53,95 +50,89 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, 0644); - -static int rpaphp_get_attention_status(struct slot *slot) -{ - return slot->hotplug_slot->info->attention_status; -} +module_param_named(debug, rpaphp_debug, bool, 0644); /** * set_attention_status - set attention LED + * @hotplug_slot: target &hotplug_slot + * @value: LED control value + * * echo 0 > attention -- set LED OFF * echo 1 > attention -- set LED ON * echo 2 > attention -- set LED ID(identify, light is blinking) - * */ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { - int retval = 0; + int rc; struct slot *slot = (struct slot *)hotplug_slot->private; - down(&rpaphp_sem); switch (value) { case 0: - retval = rpaphp_set_attention_status(slot, LED_OFF); - hotplug_slot->info->attention_status = 0; - break; case 1: - default: - retval = rpaphp_set_attention_status(slot, LED_ON); - hotplug_slot->info->attention_status = 1; - break; case 2: - retval = rpaphp_set_attention_status(slot, LED_ID); - hotplug_slot->info->attention_status = 2; + break; + default: + value = 1; break; } - up(&rpaphp_sem); - return retval; + + rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); + if (!rc) + hotplug_slot->info->attention_status = value; + + return rc; } /** * get_power_status - get power status of a slot * @hotplug_slot: slot to get status * @value: pointer to store status - * - * */ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) { - int retval; + int retval, level; struct slot *slot = (struct slot *)hotplug_slot->private; - down(&rpaphp_sem); - retval = rpaphp_get_power_status(slot, value); - up(&rpaphp_sem); + retval = rtas_get_power_level (slot->power_domain, &level); + if (!retval) + *value = level; return retval; } /** * get_attention_status - get attention LED status - * - * + * @hotplug_slot: slot to get status + * @value: pointer to store status */ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) { - int retval = 0; struct slot *slot = (struct slot *)hotplug_slot->private; - - down(&rpaphp_sem); - *value = rpaphp_get_attention_status(slot); - up(&rpaphp_sem); - return retval; + *value = slot->hotplug_slot->info->attention_status; + return 0; } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) { struct slot *slot = (struct slot *)hotplug_slot->private; - int retval = 0; + int rc, state; - down(&rpaphp_sem); - retval = rpaphp_get_pci_adapter_status(slot, 0, value); - up(&rpaphp_sem); - return retval; + rc = rpaphp_get_sensor_state(slot, &state); + + *value = NOT_VALID; + if (rc) + return rc; + + if (state == EMPTY) + *value = EMPTY; + else if (state == PRESENT) + *value = slot->state; + + return 0; } -static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +static enum pci_bus_speed get_max_bus_speed(struct slot *slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; - - down(&rpaphp_sem); + enum pci_bus_speed speed; switch (slot->type) { case 1: case 2: @@ -149,31 +140,30 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe case 4: case 5: case 6: - *value = PCI_SPEED_33MHz; /* speed for case 1-6 */ + speed = PCI_SPEED_33MHz; /* speed for case 1-6 */ break; case 7: case 8: - *value = PCI_SPEED_66MHz; + speed = PCI_SPEED_66MHz; break; case 11: case 14: - *value = PCI_SPEED_66MHz_PCIX; + speed = PCI_SPEED_66MHz_PCIX; break; case 12: case 15: - *value = PCI_SPEED_100MHz_PCIX; + speed = PCI_SPEED_100MHz_PCIX; break; case 13: case 16: - *value = PCI_SPEED_133MHz_PCIX; + speed = PCI_SPEED_133MHz_PCIX; break; default: - *value = PCI_SPEED_UNKNOWN; + speed = PCI_SPEED_UNKNOWN; break; - } - up(&rpaphp_sem); - return 0; + + return speed; } static int get_children_props(struct device_node *dn, const int **drc_indexes, @@ -265,6 +255,19 @@ static int is_php_type(char *drc_type) return 1; } +/** + * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0 + * @dn: target &device_node + * @indexes: passed to get_children_props() + * @names: passed to get_children_props() + * @types: returned from get_children_props() + * @power_domains: + * + * This routine will return true only if the device node is + * a hotpluggable slot. This routine will return false + * for built-in pci slots (even when the built-in slots are + * dlparable.) + */ static int is_php_dn(struct device_node *dn, const int **indexes, const int **names, const int **types, const int **power_domains) { @@ -272,24 +275,31 @@ static int is_php_dn(struct device_node *dn, const int **indexes, int rc; rc = get_children_props(dn, indexes, names, &drc_types, power_domains); - if (rc >= 0) { - if (is_php_type((char *) &drc_types[1])) { - *types = drc_types; - return 1; - } - } + if (rc < 0) + return 0; - return 0; + if (!is_php_type((char *) &drc_types[1])) + return 0; + + *types = drc_types; + return 1; } /** - * rpaphp_add_slot -- add hotplug or dlpar slot + * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem. + * @dn: device node of slot + * + * This subroutine will register a hotplugable slot with the + * PCI hotplug infrastructure. This routine is typicaly called + * during boot time, if the hotplug slots are present at boot time, + * or is called later, by the dlpar add code, if the slot is + * being dynamically added during runtime. * - * rpaphp not only registers PCI hotplug slots(HOTPLUG), - * but also logical DR slots(EMBEDDED). - * HOTPLUG slot: An adapter can be physically added/removed. - * EMBEDDED slot: An adapter can be logically removed/added - * from/to a partition with the slot. + * If the device node points at an embedded (built-in) slot, this + * routine will just return without doing anything, since embedded + * slots cannot be hotplugged. + * + * To remove a slot, it suffices to call rpaphp_deregister_slot(). */ int rpaphp_add_slot(struct device_node *dn) { @@ -299,34 +309,42 @@ int rpaphp_add_slot(struct device_node *dn) const int *indexes, *names, *types, *power_domains; char *name, *type; - dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); + if (!dn->name || strcmp(dn->name, "pci")) + return 0; + + /* If this is not a hotplug slot, return without doing anything. */ + if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) + return 0; + + dbg("Entry %s: dn->full_name=%s\n", __func__, dn->full_name); /* register PCI devices */ - if (dn->name != 0 && strcmp(dn->name, "pci") == 0) { - if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) - goto exit; - - name = (char *) &names[1]; - type = (char *) &types[1]; - for (i = 0; i < indexes[0]; i++, - name += (strlen(name) + 1), type += (strlen(type) + 1)) { - - if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name, - power_domains[i + 1]))) { - retval = -ENOMEM; - goto exit; - } - slot->type = simple_strtoul(type, NULL, 10); + name = (char *) &names[1]; + type = (char *) &types[1]; + for (i = 0; i < indexes[0]; i++) { + + slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]); + if (!slot) + return -ENOMEM; + + slot->type = simple_strtoul(type, NULL, 10); - dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", - indexes[i + 1], name, type); + dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", + indexes[i + 1], name, type); - retval = rpaphp_register_pci_slot(slot); - } + retval = rpaphp_enable_slot(slot); + if (!retval) + retval = rpaphp_register_slot(slot); + + if (retval) + dealloc_slot_struct(slot); + + name += strlen(name) + 1; + type += strlen(type) + 1; } -exit: - dbg("%s - Exit: num_slots=%d rc[%d]\n", - __FUNCTION__, num_slots, retval); + dbg("%s - Exit: rc[%d]\n", __func__, retval); + + /* XXX FIXME: reports a failure only if last entry in loop failed */ return retval; } @@ -354,7 +372,6 @@ static int __init rpaphp_init(void) struct device_node *dn = NULL; info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - init_MUTEX(&rpaphp_sem); while ((dn = of_find_node_by_name(dn, "pci"))) rpaphp_add_slot(dn); @@ -367,8 +384,9 @@ static void __exit rpaphp_exit(void) cleanup_slots(); } -static int __enable_slot(struct slot *slot) +static int enable_slot(struct hotplug_slot *hotplug_slot) { + struct slot *slot = (struct slot *)hotplug_slot->private; int state; int retval; @@ -385,62 +403,35 @@ static int __enable_slot(struct slot *slot) } else if (state == EMPTY) { slot->state = EMPTY; } else { - err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot->name); + err("%s: slot[%s] is in invalid state\n", __func__, slot->name); slot->state = NOT_VALID; return -EINVAL; } + + slot->bus->max_bus_speed = get_max_bus_speed(slot); return 0; } -static int enable_slot(struct hotplug_slot *hotplug_slot) +static int disable_slot(struct hotplug_slot *hotplug_slot) { - int retval; struct slot *slot = (struct slot *)hotplug_slot->private; - - down(&rpaphp_sem); - retval = __enable_slot(slot); - up(&rpaphp_sem); - - return retval; -} - -static int __disable_slot(struct slot *slot) -{ - struct pci_dev *dev, *tmp; - if (slot->state == NOT_CONFIGURED) return -EINVAL; - list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) { - eeh_remove_bus_device(dev); - pci_remove_bus_device(dev); - } + pcibios_remove_pci_devices(slot->bus); + vm_unmap_aliases(); slot->state = NOT_CONFIGURED; return 0; } -static int disable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = (struct slot *)hotplug_slot->private; - int retval; - - down(&rpaphp_sem); - retval = __disable_slot (slot); - up(&rpaphp_sem); - - return retval; -} - struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, .get_power_status = get_power_status, .get_attention_status = get_attention_status, .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, }; module_init(rpaphp_init);