diff options
Diffstat (limited to 'drivers/pci/hotplug/rpaphp_pci.c')
-rw-r--r-- | drivers/pci/hotplug/rpaphp_pci.c | 299 |
1 files changed, 115 insertions, 184 deletions
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index d8305a935aab..49e4d10a6488 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -30,22 +30,35 @@ #include "rpaphp.h" -struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn) +static struct pci_bus *find_bus_among_children(struct pci_bus *bus, + struct device_node *dn) { - struct pci_dev *dev = NULL; - char bus_id[BUS_ID_SIZE]; + struct pci_bus *child = NULL; + struct list_head *tmp; + struct device_node *busdn; + + busdn = pci_bus_to_OF_node(bus); + if (busdn == dn) + return bus; - sprintf(bus_id, "%04x:%02x:%02x.%d", dn->phb->global_number, - dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn)); - for_each_pci_dev(dev) { - if (!strcmp(pci_name(dev), bus_id)) { + list_for_each(tmp, &bus->children) { + child = find_bus_among_children(pci_bus_b(tmp), dn); + if (child) break; - } } - return dev; + return child; } -EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev); +struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn) +{ + struct pci_dn *pdn = dn->data; + + if (!pdn || !pdn->phb || !pdn->phb->bus) + return NULL; + + return find_bus_among_children(pdn->phb->bus, dn); +} +EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus); int rpaphp_claim_resource(struct pci_dev *dev, int resource) { @@ -69,11 +82,6 @@ int rpaphp_claim_resource(struct pci_dev *dev, int resource) EXPORT_SYMBOL_GPL(rpaphp_claim_resource); -static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot) -{ - return rpaphp_find_pci_dev(slot->dn); -} - static int rpaphp_get_sensor_state(struct slot *slot, int *state) { int rc; @@ -116,39 +124,27 @@ static int rpaphp_get_sensor_state(struct slot *slot, int *state) */ int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) { + struct pci_bus *bus; int state, rc; - struct device_node *child_dn; - struct pci_dev *child_dev = NULL; *value = NOT_VALID; rc = rpaphp_get_sensor_state(slot, &state); if (rc) goto exit; - if ((state == EMPTY) || (slot->type == PHB)) { - dbg("slot is empty\n"); + if (state == EMPTY) *value = EMPTY; - } else if (state == PRESENT) { if (!is_init) { /* at run-time slot->state can be changed by */ /* config/unconfig adapter */ *value = slot->state; } else { - child_dn = slot->dn->child; - if (child_dn) - child_dev = rpaphp_find_pci_dev(child_dn); - - if (child_dev) - *value = CONFIGURED; - else if (!child_dn) - dbg("%s: %s is not valid OFDT node\n", - __FUNCTION__, slot->dn->full_name); - else { - err("%s: can't find pdev of adapter in slot[%s]\n", - __FUNCTION__, slot->dn->full_name); + bus = rpaphp_find_pci_bus(slot->dn); + if (bus && !list_empty(&bus->devices)) + *value = CONFIGURED; + else *value = NOT_CONFIGURED; - } } } exit: @@ -186,39 +182,6 @@ 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) -{ - struct device_node *eads_first_child = dn->child; - struct pci_dev *dev = NULL; - 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; @@ -252,6 +215,42 @@ static int rpaphp_pci_config_bridge(struct pci_dev *dev) return 0; } +/***************************************************************************** + 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 pci_bus *bus) +{ + struct device_node *dn = pci_bus_to_OF_node(bus); + struct pci_dev *dev = NULL; + int slotno; + int num; + + dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); + if (!dn || !dn->child) + return NULL; + + slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); + + /* pci_scan_slot should find all children */ + num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); + if (num) { + rpaphp_fixup_new_pci_devices(bus, 1); + pci_bus_add_devices(bus); + } + if (list_empty(&bus->devices)) { + err("%s: No new device found\n", __FUNCTION__); + return NULL; + } + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + rpaphp_pci_config_bridge(dev); + } + + return dev; +} + static void enable_eeh(struct device_node *dn) { struct device_node *sib; @@ -263,49 +262,44 @@ static void enable_eeh(struct device_node *dn) } -static void print_slot_pci_funcs(struct slot *slot) +static void print_slot_pci_funcs(struct pci_bus *bus) { + struct device_node *dn; struct pci_dev *dev; - if (slot->dev_type == PCI_DEV) { - dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->name); - list_for_each_entry (dev, slot->dev.pci_devs, bus_list) - dbg("\t%s\n", pci_name(dev)); - } + dn = pci_bus_to_OF_node(bus); + if (!dn) + return; + + dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name); + list_for_each_entry (dev, &bus->devices, bus_list) + dbg("\t%s\n", pci_name(dev)); return; } -static int rpaphp_config_pci_adapter(struct slot *slot) +int rpaphp_config_pci_adapter(struct pci_bus *bus) { - struct pci_bus *pci_bus; + struct device_node *dn = pci_bus_to_OF_node(bus); struct pci_dev *dev; int rc = -ENODEV; - dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); - - if (slot->bridge) { + dbg("Entry %s: slot[%s]\n", __FUNCTION__, dn->full_name); + if (!dn) + goto exit; - pci_bus = slot->bridge->subordinate; - if (!pci_bus) { - 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; - } - print_slot_pci_funcs(slot); - rc = 0; - } else { - /* slot is not enabled */ - err("slot doesn't have pci_dev structure\n"); + enable_eeh(dn); + dev = rpaphp_pci_config_slot(bus); + if (!dev) { + err("%s: can't find any devices.\n", __FUNCTION__); + goto exit; } + print_slot_pci_funcs(bus); + rc = 0; exit: dbg("Exit %s: rc=%d\n", __FUNCTION__, rc); return rc; } +EXPORT_SYMBOL_GPL(rpaphp_config_pci_adapter); static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) { @@ -327,13 +321,14 @@ static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) int rpaphp_unconfig_pci_adapter(struct slot *slot) { - struct pci_dev *dev; + struct pci_dev *dev, *tmp; int retval = 0; - list_for_each_entry(dev, slot->dev.pci_devs, bus_list) + list_for_each_entry_safe(dev, tmp, slot->pci_devs, bus_list) { rpaphp_eeh_remove_bus_device(dev); + pci_remove_bus_device(dev); + } - pci_remove_behind_bridge(slot->bridge); slot->state = NOT_CONFIGURED; info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, slot->name); @@ -356,66 +351,41 @@ static int setup_pci_hotplug_slot_info(struct slot *slot) return 0; } -static int set_phb_slot_name(struct slot *slot) +static void set_slot_name(struct slot *slot) { - struct device_node *dn; - struct pci_controller *phb; - struct pci_bus *bus; - - dn = slot->dn; - if (!dn) { - return -EINVAL; - } - phb = dn->phb; - if (!phb) { - return -EINVAL; - } - bus = phb->bus; - if (!bus) { - return -EINVAL; - } + struct pci_bus *bus = slot->bus; + struct pci_dev *bridge; - sprintf(slot->name, "%04x:%02x:%02x.%x", pci_domain_nr(bus), - bus->number, 0, 0); - return 0; + bridge = bus->self; + if (bridge) + strcpy(slot->name, pci_name(bridge)); + else + sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), + bus->number); } static int setup_pci_slot(struct slot *slot) { + struct device_node *dn = slot->dn; struct pci_bus *bus; - int rc; - if (slot->type == PHB) { - rc = set_phb_slot_name(slot); - if (rc < 0) { - err("%s: failed to set phb slot name\n", __FUNCTION__); - goto exit_rc; - } - } else { - 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; - } - - bus = slot->bridge->subordinate; - if (!bus) - goto exit_rc; - slot->dev.pci_devs = &bus->devices; - - dbg("%s set slot->name to %s\n", __FUNCTION__, - pci_name(slot->bridge)); - strcpy(slot->name, pci_name(slot->bridge)); + BUG_ON(!dn); + bus = rpaphp_find_pci_bus(dn); + if (!bus) { + err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); + goto exit_rc; } + slot->bus = bus; + slot->pci_devs = &bus->devices; + set_slot_name(slot); + /* find slot's pci_dev if it's not empty */ if (slot->hotplug_slot->info->adapter_status == EMPTY) { slot->state = EMPTY; /* slot is empty */ } else { /* slot is occupied */ - if (!(slot->dn->child)) { + if (!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); @@ -425,7 +395,7 @@ static int setup_pci_slot(struct slot *slot) if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { dbg("%s CONFIGURING pci adapter in slot[%s]\n", __FUNCTION__, slot->name); - if (rpaphp_config_pci_adapter(slot)) { + if (rpaphp_config_pci_adapter(slot->bus)) { err("%s: CONFIG pci adapter failed\n", __FUNCTION__); goto exit_rc; } @@ -435,8 +405,8 @@ static int setup_pci_slot(struct slot *slot) __FUNCTION__, slot->name); goto exit_rc; } - print_slot_pci_funcs(slot); - if (!list_empty(slot->dev.pci_devs)) { + print_slot_pci_funcs(slot->bus); + if (!list_empty(slot->pci_devs)) { slot->state = CONFIGURED; } else { /* DLPAR add as opposed to @@ -454,11 +424,6 @@ int register_pci_slot(struct slot *slot) { int rc = -EINVAL; - slot->dev_type = PCI_DEV; - if ((slot->type == EMBEDDED) || (slot->type == PHB)) - slot->removable = 0; - else - slot->removable = 1; if (setup_pci_hotplug_slot_info(slot)) goto exit_rc; if (setup_pci_slot(slot)) @@ -479,7 +444,7 @@ int rpaphp_enable_pci_slot(struct slot *slot) /* 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); + retval = rpaphp_config_pci_adapter(slot->bus); if (!retval) { slot->state = CONFIGURED; dbg("%s: PCI devices in slot[%s] has been configured\n", @@ -502,37 +467,3 @@ exit: 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); |