X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fpci%2Fhotplug%2Frpaphp_pci.c;h=6f5b61b7c61a3ac3157f6c0ebda8ea9a82ec2f2e;hb=f9296eb00ed30209424102d3c920e69617eea853;hp=0dd2d23699e53438a8cb7f907552f6e9612e09d3;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 0dd2d2369..6f5b61b7c 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -24,25 +24,30 @@ */ #include #include -#include #include "../pci.h" /* for pci_add_new_bus */ #include "rpaphp.h" struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn) { - struct pci_dev *retval_dev = NULL, *dev = NULL; + struct pci_dev *retval_dev = NULL, *dev; char bus_id[BUS_ID_SIZE]; sprintf(bus_id, "%04x:%02x:%02x.%d",dn->phb->global_number, dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn)); + + dbg("Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s\n", + dn->full_name, bus_id); + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (!strcmp(pci_name(dev), bus_id)) { + if (!strcmp(pci_name(dev), bus_id)) { retval_dev = dev; + dbg("rpaphp_find_pci_dev(): found dev=%p\n\n", dev); break; } } return retval_dev; + } EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev); @@ -74,6 +79,11 @@ static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot) return rpaphp_find_pci_dev(slot->dn); } +static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot) +{ + return rpaphp_find_pci_dev(slot->dn->child); +} + static int rpaphp_get_sensor_state(struct slot *slot, int *state) { int rc; @@ -134,8 +144,7 @@ int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) else if (rpaphp_find_pci_dev(slot->dn->child)) *value = CONFIGURED; else { - err("%s: can't find pdev of adapter in slot[%s]\n", - __FUNCTION__, slot->dn->full_name); + dbg("%s: can't find pdev of adapter in slot[%s]\n", __FUNCTION__, slot->name); *value = NOT_CONFIGURED; } } @@ -149,8 +158,7 @@ exit: } /* Must be called before pci_bus_add_devices */ -static void -rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) +static void rpaphp_fixup_new_pci_devices(struct pci_bus *bus) { struct pci_dev *dev; @@ -161,9 +169,8 @@ rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) */ if (list_empty(&dev->global_list)) { int i; - - if(fix_bus) - pcibios_fixup_device_resources(dev, bus); + + pcibios_fixup_device_resources(dev, bus); pci_read_irq_line(dev); for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; @@ -176,139 +183,69 @@ rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) } } -static int rpaphp_pci_config_bridge(struct pci_dev *dev); - -/***************************************************************************** - rpaphp_pci_config_slot() will configure all devices under the - given slot->dn and return the the first pci_dev. - *****************************************************************************/ -static struct pci_dev * -rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus) +static void +rpaphp_pci_config_device(struct pci_bus *pci_bus, struct device_node *dn) { - struct device_node *eads_first_child = dn->child; - struct pci_dev *dev; int num; - - dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); - - if (eads_first_child) { - /* pci_scan_slot should find all children of EADs */ - num = pci_scan_slot(bus, PCI_DEVFN(PCI_SLOT(eads_first_child->devfn), 0)); - if (num) { - rpaphp_fixup_new_pci_devices(bus, 1); - pci_bus_add_devices(bus); - } - dev = rpaphp_find_pci_dev(eads_first_child); - if (!dev) { - err("No new device found\n"); - return NULL; - } - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - rpaphp_pci_config_bridge(dev); - } - return dev; -} - -static int rpaphp_pci_config_bridge(struct pci_dev *dev) -{ - u8 sec_busno; - struct pci_bus *child_bus; - struct pci_dev *child_dev; - - dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev)); - /* get busno of downstream bus */ - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); - - /* add to children of PCI bridge dev->bus */ - child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); - if (!child_bus) { - err("%s: could not add second bus\n", __FUNCTION__); - return -EIO; - } - sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); - /* do pci_scan_child_bus */ - pci_scan_child_bus(child_bus); - - list_for_each_entry(child_dev, &child_bus->devices, bus_list) { - eeh_add_device_late(child_dev); + num = pci_scan_slot(pci_bus, PCI_DEVFN(PCI_SLOT(dn->devfn), 0)); + if (num) { + rpaphp_fixup_new_pci_devices(pci_bus); + pci_bus_add_devices(pci_bus); } - - /* fixup new pci devices without touching bus struct */ - rpaphp_fixup_new_pci_devices(child_bus, 0); - - /* Make the discovered devices available */ - pci_bus_add_devices(child_bus); - return 0; } -static void enable_eeh(struct device_node *dn) -{ - struct device_node *sib; +static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn); - for (sib = dn->child; sib; sib = sib->sibling) - enable_eeh(sib); - eeh_add_device_early(dn); - return; - -} - -#ifdef DEBUG -static void print_slot_pci_funcs(struct slot *slot) +/***************************************************************************** + rpaphp_pci_config_dn() will recursively configure all devices under the + given slot->dn and return the dn's pci_dev. + *****************************************************************************/ +static struct pci_dev * +rpaphp_pci_config_dn(struct device_node *dn, struct pci_bus *bus) { - struct list_head *l; - - if (slot->dev_type == PCI_DEV) { - printk("pci_funcs of slot[%s]\n", slot->name); - if (list_empty(&slot->dev.pci_funcs)) - printk(" pci_funcs is EMPTY\n"); + struct device_node *local; + struct pci_dev *dev; - list_for_each (l, &slot->dev.pci_funcs) { - struct rpaphp_pci_func *func = - list_entry(l, struct rpaphp_pci_func, sibling); - printk(" FOUND dev=%s\n", pci_name(func->pci_dev)); - } + for (local = dn->child; local; local = local->sibling) { + rpaphp_pci_config_device(bus, local); + dev = rpaphp_find_pci_dev(local); + if (!rpaphp_pci_config_bridge(dev, local)) + return NULL; } - return; -} -#else -static void print_slot_pci_funcs(struct slot *slot) -{ - return; + + return dev; } -#endif -static int init_slot_pci_funcs(struct slot *slot) +static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn) { - struct device_node *child; - - for (child = slot->dn->child; child != NULL; child = child->sibling) { - struct pci_dev *pdev = rpaphp_find_pci_dev(child); - - if (pdev) { - struct rpaphp_pci_func *func; - func = kmalloc(sizeof(struct rpaphp_pci_func), GFP_KERNEL); - if (!func) - return -ENOMEM; - memset(func, 0, sizeof(struct rpaphp_pci_func)); - INIT_LIST_HEAD(&func->sibling); - func->pci_dev = pdev; - list_add_tail(&func->sibling, &slot->dev.pci_funcs); - print_slot_pci_funcs(slot); - } else { - err("%s: dn=%s has no pci_dev\n", - __FUNCTION__, child->full_name); - return -EIO; + if (dev && dn->child) { /* dn is a PCI bridge node */ + struct pci_bus *child; + u8 sec_busno; + + /* get busno of downstream bus */ + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); + + /* add to children of PCI bridge dev->bus */ + child = pci_add_new_bus(dev->bus, dev, sec_busno); + if (!child) { + err("%s: could not add second bus\n", __FUNCTION__); + return 0; } + sprintf(child->name, "PCI Bus #%02x", child->number); + /* Fixup subordinate bridge bases and resureces */ + pcibios_fixup_bus(child); + + /* may need do more stuff here */ + rpaphp_pci_config_dn(dn, dev->subordinate); } - return 0; + return 1; } -static int rpaphp_config_pci_adapter(struct slot *slot) +static struct pci_dev *rpaphp_config_pci_adapter(struct slot *slot) { struct pci_bus *pci_bus; - struct pci_dev *dev; - int rc = -ENODEV; + struct pci_dev *dev = NULL; dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); @@ -319,74 +256,38 @@ static int rpaphp_config_pci_adapter(struct slot *slot) err("%s: can't find bus structure\n", __FUNCTION__); goto exit; } - enable_eeh(slot->dn); - dev = rpaphp_pci_config_slot(slot->dn, pci_bus); - if (!dev) { - err("%s: can't find any devices.\n", __FUNCTION__); - goto exit; - } - /* associate corresponding pci_dev */ - rc = init_slot_pci_funcs(slot); - if (rc) - goto exit; - print_slot_pci_funcs(slot); - if (!list_empty(&slot->dev.pci_funcs)) - rc = 0; + + eeh_add_device_early(slot->dn->child); + dev = rpaphp_pci_config_dn(slot->dn, pci_bus); + eeh_add_device_late(dev); } else { /* slot is not enabled */ err("slot doesn't have pci_dev structure\n"); + dev = NULL; } -exit: - dbg("Exit %s: rc=%d\n", __FUNCTION__, rc); - return rc; -} - -static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) -{ - eeh_remove_device(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *bus = dev->subordinate; - struct list_head *ln; - if (!bus) - return; - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *pdev = pci_dev_b(ln); - if (pdev) - rpaphp_eeh_remove_bus_device(pdev); - } - - } - return; +exit: + dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev ? "found" : "not found"); + return dev; } int rpaphp_unconfig_pci_adapter(struct slot *slot) { int retval = 0; - struct list_head *ln; dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); - if (list_empty(&slot->dev.pci_funcs)) { - err("%s: slot[%s] doesn't have any devices.\n", __FUNCTION__, - slot->name); + if (!slot->dev.pci_dev) { + info("%s: no card in slot[%s]\n", __FUNCTION__, slot->name); retval = -EINVAL; goto exit; } - /* remove the devices from the pci core */ - list_for_each (ln, &slot->dev.pci_funcs) { - struct rpaphp_pci_func *func; - - func = list_entry(ln, struct rpaphp_pci_func, sibling); - if (func->pci_dev) { - pci_remove_bus_device(func->pci_dev); - rpaphp_eeh_remove_bus_device(func->pci_dev); - } - kfree(func); - } - INIT_LIST_HEAD(&slot->dev.pci_funcs); + /* remove the device from the pci core */ + eeh_remove_device(slot->dev.pci_dev); + pci_remove_bus_device(slot->dev.pci_dev); + slot->state = NOT_CONFIGURED; - info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, + info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name); exit: dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval); @@ -402,7 +303,7 @@ static int setup_pci_hotplug_slot_info(struct slot *slot) &slot->hotplug_slot->info-> adapter_status); if (slot->hotplug_slot->info->adapter_status == NOT_VALID) { - err("%s: NOT_VALID: skip dn->full_name=%s\n", + dbg("%s: NOT_VALID: skip dn->full_name=%s\n", __FUNCTION__, slot->dn->full_name); return -1; } @@ -413,41 +314,35 @@ static int setup_pci_slot(struct slot *slot) { slot->bridge = rpaphp_find_bridge_pdev(slot); if (!slot->bridge) { /* slot being added doesn't have pci_dev yet */ - err("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name); - goto exit_rc; + dbg("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name); + dealloc_slot_struct(slot); + return 1; } - dbg("%s set slot->name to %s\n", __FUNCTION__, pci_name(slot->bridge)); + strcpy(slot->name, pci_name(slot->bridge)); - /* find slot's pci_dev if it's not empty */ if (slot->hotplug_slot->info->adapter_status == EMPTY) { slot->state = EMPTY; /* slot is empty */ + slot->dev.pci_dev = NULL; } else { /* slot is occupied */ if (!(slot->dn->child)) { /* non-empty slot has to have child */ - err("%s: slot[%s]'s device_node doesn't have child for adapter\n", - __FUNCTION__, slot->name); - goto exit_rc; + err("%s: slot[%s]'s device_node doesn't have child for adapter\n", __FUNCTION__, slot->name); + dealloc_slot_struct(slot); + return 1; } - if (init_slot_pci_funcs(slot)) { - err("%s: init_slot_pci_funcs failed\n", __FUNCTION__); - goto exit_rc; - } - print_slot_pci_funcs(slot); - if (!list_empty(&slot->dev.pci_funcs)) { + slot->dev.pci_dev = rpaphp_find_adapter_pdev(slot); + if (slot->dev.pci_dev) { slot->state = CONFIGURED; - + } else { /* DLPAR add as opposed to - * boot time */ + * boot time */ slot->state = NOT_CONFIGURED; } } return 0; -exit_rc: - dealloc_slot_struct(slot); - return 1; } int register_pci_slot(struct slot *slot) @@ -455,17 +350,14 @@ int register_pci_slot(struct slot *slot) int rc = 1; slot->dev_type = PCI_DEV; - if (slot->type == EMBEDDED) - slot->removable = EMBEDDED; - else - slot->removable = HOTPLUG; - INIT_LIST_HEAD(&slot->dev.pci_funcs); if (setup_pci_hotplug_slot_info(slot)) goto exit_rc; if (setup_pci_slot(slot)) goto exit_rc; rc = register_slot(slot); exit_rc: + if (rc) + dealloc_slot_struct(slot); return rc; } @@ -479,12 +371,12 @@ int rpaphp_enable_pci_slot(struct slot *slot) dbg("%s: sensor state[%d]\n", __FUNCTION__, state); /* if slot is not empty, enable the adapter */ if (state == PRESENT) { - dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name); - retval = rpaphp_config_pci_adapter(slot); - if (!retval) { + dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot->name); + if ((slot->dev.pci_dev = + rpaphp_config_pci_adapter(slot)) != NULL) { slot->state = CONFIGURED; - dbg("%s: PCI devices in slot[%s] has been configured\n", - __FUNCTION__, slot->name); + dbg("%s: PCI adapter %s in slot[%s] has been configured\n", + __FUNCTION__, pci_name(slot->dev.pci_dev), slot->name); } else { slot->state = NOT_CONFIGURED; dbg("%s: no pci_dev struct for adapter in slot[%s]\n", @@ -500,40 +392,10 @@ int rpaphp_enable_pci_slot(struct slot *slot) retval = -EINVAL; } exit: + if (slot->state != NOT_VALID) + rpaphp_set_attention_status(slot, LED_ON); + else + rpaphp_set_attention_status(slot, LED_ID); dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; } - -struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev) -{ - struct list_head *tmp, *n; - struct slot *slot; - - list_for_each_safe(tmp, n, &rpaphp_slot_head) { - struct pci_bus *bus; - struct list_head *ln; - - slot = list_entry(tmp, struct slot, rpaphp_slot_list); - if (slot->bridge == NULL) { - if (slot->dev_type == PCI_DEV) { - printk(KERN_WARNING "PCI slot missing bridge %s %s \n", - slot->name, slot->location); - } - continue; - } - - bus = slot->bridge->subordinate; - if (!bus) { - continue; /* should never happen? */ - } - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *pdev = pci_dev_b(ln); - if (pdev == dev) - return slot->hotplug_slot; - } - } - - return NULL; -} - -EXPORT_SYMBOL_GPL(rpaphp_find_hotplug_slot);