diff options
| -rw-r--r-- | drivers/pci/hotplug/rpadlpar_core.c | 79 | ||||
| -rw-r--r-- | drivers/pci/hotplug/rpaphp.h | 2 | ||||
| -rw-r--r-- | drivers/pci/hotplug/rpaphp_pci.c | 76 |
3 files changed, 81 insertions, 76 deletions
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index e8593a60ee89..cc03609f45d0 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c | |||
| @@ -134,43 +134,6 @@ static void rpadlpar_claim_one_bus(struct pci_bus *b) | |||
| 134 | rpadlpar_claim_one_bus(child_bus); | 134 | rpadlpar_claim_one_bus(child_bus); |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | static int pci_add_secondary_bus(struct device_node *dn, | ||
| 138 | struct pci_dev *bridge_dev) | ||
| 139 | { | ||
| 140 | struct pci_dn *pdn = dn->data; | ||
| 141 | struct pci_controller *hose = pdn->phb; | ||
| 142 | struct pci_bus *child; | ||
| 143 | u8 sec_busno; | ||
| 144 | |||
| 145 | /* Get busno of downstream bus */ | ||
| 146 | pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno); | ||
| 147 | |||
| 148 | /* Allocate and add to children of bridge_dev->bus */ | ||
| 149 | child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno); | ||
| 150 | if (!child) { | ||
| 151 | printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__); | ||
| 152 | return -ENOMEM; | ||
| 153 | } | ||
| 154 | |||
| 155 | sprintf(child->name, "PCI Bus #%02x", child->number); | ||
| 156 | |||
| 157 | /* Fixup subordinate bridge bases and resources */ | ||
| 158 | pcibios_fixup_bus(child); | ||
| 159 | |||
| 160 | /* Claim new bus resources */ | ||
| 161 | rpadlpar_claim_one_bus(bridge_dev->bus); | ||
| 162 | |||
| 163 | if (hose->last_busno < child->number) | ||
| 164 | hose->last_busno = child->number; | ||
| 165 | |||
| 166 | pdn->bussubno = child->number; | ||
| 167 | |||
| 168 | /* ioremap() for child bus, which may or may not succeed */ | ||
| 169 | remap_bus_range(child); | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, | 137 | static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, |
| 175 | struct device_node *dev_dn) | 138 | struct device_node *dev_dn) |
| 176 | { | 139 | { |
| @@ -188,29 +151,41 @@ static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, | |||
| 188 | static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) | 151 | static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) |
| 189 | { | 152 | { |
| 190 | struct pci_dn *pdn = dn->data; | 153 | struct pci_dn *pdn = dn->data; |
| 191 | struct pci_controller *hose = pdn->phb; | 154 | struct pci_controller *phb = pdn->phb; |
| 192 | struct pci_dev *dev = NULL; | 155 | struct pci_dev *dev = NULL; |
| 193 | 156 | ||
| 194 | /* Scan phb bus for EADS device, adding new one to bus->devices */ | 157 | rpaphp_eeh_init_nodes(dn); |
| 195 | if (!pci_scan_single_device(hose->bus, pdn->devfn)) { | 158 | /* Add EADS device to PHB bus, adding new entry to bus->devices */ |
| 196 | printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__); | 159 | dev = of_create_pci_dev(dn, phb->bus, pdn->devfn); |
| 160 | if (!dev) { | ||
| 161 | printk(KERN_ERR "%s: failed to create pci dev for %s\n", | ||
| 162 | __FUNCTION__, dn->full_name); | ||
| 197 | return NULL; | 163 | return NULL; |
| 198 | } | 164 | } |
| 199 | 165 | ||
| 166 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | ||
| 167 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | ||
| 168 | of_scan_pci_bridge(dn, dev); | ||
| 169 | |||
| 170 | rpaphp_init_new_devs(dev->subordinate); | ||
| 171 | |||
| 172 | /* Claim new bus resources */ | ||
| 173 | rpadlpar_claim_one_bus(dev->bus); | ||
| 174 | |||
| 175 | /* ioremap() for child bus, which may or may not succeed */ | ||
| 176 | (void) remap_bus_range(dev->bus); | ||
| 177 | |||
| 200 | /* Add new devices to global lists. Register in proc, sysfs. */ | 178 | /* Add new devices to global lists. Register in proc, sysfs. */ |
| 201 | pci_bus_add_devices(hose->bus); | 179 | pci_bus_add_devices(phb->bus); |
| 202 | 180 | ||
| 203 | /* Confirm new bridge dev was created */ | 181 | /* Confirm new bridge dev was created */ |
| 204 | dev = dlpar_find_new_dev(hose->bus, dn); | 182 | dev = dlpar_find_new_dev(phb->bus, dn); |
| 205 | if (dev) { | 183 | if (dev) { |
| 206 | if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { | 184 | if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { |
| 207 | printk(KERN_ERR "%s: unexpected header type %d\n", | 185 | printk(KERN_ERR "%s: unexpected header type %d\n", |
| 208 | __FUNCTION__, dev->hdr_type); | 186 | __FUNCTION__, dev->hdr_type); |
| 209 | return NULL; | 187 | return NULL; |
| 210 | } | 188 | } |
| 211 | |||
| 212 | if (pci_add_secondary_bus(dn, dev)) | ||
| 213 | return NULL; | ||
| 214 | } | 189 | } |
| 215 | 190 | ||
| 216 | return dev; | 191 | return dev; |
| @@ -219,7 +194,6 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) | |||
| 219 | static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) | 194 | static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) |
| 220 | { | 195 | { |
| 221 | struct pci_dev *dev; | 196 | struct pci_dev *dev; |
| 222 | int rc; | ||
| 223 | 197 | ||
| 224 | if (rpaphp_find_pci_bus(dn)) | 198 | if (rpaphp_find_pci_bus(dn)) |
| 225 | return -EINVAL; | 199 | return -EINVAL; |
| @@ -232,15 +206,6 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) | |||
| 232 | return -EIO; | 206 | return -EIO; |
| 233 | } | 207 | } |
| 234 | 208 | ||
| 235 | if (dn->child) { | ||
| 236 | rc = rpaphp_config_pci_adapter(dev->subordinate); | ||
| 237 | if (rc < 0) { | ||
| 238 | printk(KERN_ERR "%s: unable to enable slot %s\n", | ||
| 239 | __FUNCTION__, drc_name); | ||
| 240 | return -EIO; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | /* Add hotplug slot */ | 209 | /* Add hotplug slot */ |
| 245 | if (rpaphp_add_slot(dn)) { | 210 | if (rpaphp_add_slot(dn)) { |
| 246 | printk(KERN_ERR "%s: unable to add hotplug slot %s\n", | 211 | printk(KERN_ERR "%s: unable to add hotplug slot %s\n", |
| @@ -435,6 +400,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) | |||
| 435 | __FUNCTION__, drc_name); | 400 | __FUNCTION__, drc_name); |
| 436 | return -EIO; | 401 | return -EIO; |
| 437 | } | 402 | } |
| 403 | } else { | ||
| 404 | rpaphp_unconfig_pci_adapter(bus); | ||
| 438 | } | 405 | } |
| 439 | 406 | ||
| 440 | if (unmap_bus_range(bus)) { | 407 | if (unmap_bus_range(bus)) { |
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 71ea5f9bb284..57ea71a7bda5 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h | |||
| @@ -93,6 +93,8 @@ extern int rpaphp_claim_resource(struct pci_dev *dev, int resource); | |||
| 93 | extern int rpaphp_enable_pci_slot(struct slot *slot); | 93 | extern int rpaphp_enable_pci_slot(struct slot *slot); |
| 94 | extern int register_pci_slot(struct slot *slot); | 94 | extern int register_pci_slot(struct slot *slot); |
| 95 | extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); | 95 | extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); |
| 96 | extern void rpaphp_init_new_devs(struct pci_bus *bus); | ||
| 97 | extern void rpaphp_eeh_init_nodes(struct device_node *dn); | ||
| 96 | 98 | ||
| 97 | extern int rpaphp_config_pci_adapter(struct pci_bus *bus); | 99 | extern int rpaphp_config_pci_adapter(struct pci_bus *bus); |
| 98 | extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); | 100 | extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); |
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index f7c12d7dfcfc..a7859a84d1ae 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c | |||
| @@ -154,8 +154,7 @@ exit: | |||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | /* Must be called before pci_bus_add_devices */ | 156 | /* Must be called before pci_bus_add_devices */ |
| 157 | static void | 157 | void rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) |
| 158 | rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | ||
| 159 | { | 158 | { |
| 160 | struct pci_dev *dev; | 159 | struct pci_dev *dev; |
| 161 | 160 | ||
| @@ -184,6 +183,20 @@ rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | |||
| 184 | } | 183 | } |
| 185 | } | 184 | } |
| 186 | 185 | ||
| 186 | static void rpaphp_eeh_add_bus_device(struct pci_bus *bus) | ||
| 187 | { | ||
| 188 | struct pci_dev *dev; | ||
| 189 | |||
| 190 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
| 191 | eeh_add_device_late(dev); | ||
| 192 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
| 193 | struct pci_bus *subbus = dev->subordinate; | ||
| 194 | if (subbus) | ||
| 195 | rpaphp_eeh_add_bus_device (subbus); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 187 | static int rpaphp_pci_config_bridge(struct pci_dev *dev) | 200 | static int rpaphp_pci_config_bridge(struct pci_dev *dev) |
| 188 | { | 201 | { |
| 189 | u8 sec_busno; | 202 | u8 sec_busno; |
| @@ -217,6 +230,13 @@ static int rpaphp_pci_config_bridge(struct pci_dev *dev) | |||
| 217 | return 0; | 230 | return 0; |
| 218 | } | 231 | } |
| 219 | 232 | ||
| 233 | void rpaphp_init_new_devs(struct pci_bus *bus) | ||
| 234 | { | ||
| 235 | rpaphp_fixup_new_pci_devices(bus, 0); | ||
| 236 | rpaphp_eeh_add_bus_device(bus); | ||
| 237 | } | ||
| 238 | EXPORT_SYMBOL_GPL(rpaphp_init_new_devs); | ||
| 239 | |||
| 220 | /***************************************************************************** | 240 | /***************************************************************************** |
| 221 | rpaphp_pci_config_slot() will configure all devices under the | 241 | rpaphp_pci_config_slot() will configure all devices under the |
| 222 | given slot->dn and return the the first pci_dev. | 242 | given slot->dn and return the the first pci_dev. |
| @@ -233,36 +253,51 @@ rpaphp_pci_config_slot(struct pci_bus *bus) | |||
| 233 | if (!dn || !dn->child) | 253 | if (!dn || !dn->child) |
| 234 | return NULL; | 254 | return NULL; |
| 235 | 255 | ||
| 236 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); | 256 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { |
| 257 | of_scan_bus(dn, bus); | ||
| 258 | if (list_empty(&bus->devices)) { | ||
| 259 | err("%s: No new device found\n", __FUNCTION__); | ||
| 260 | return NULL; | ||
| 261 | } | ||
| 237 | 262 | ||
| 238 | /* pci_scan_slot should find all children */ | 263 | rpaphp_init_new_devs(bus); |
| 239 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | ||
| 240 | if (num) { | ||
| 241 | rpaphp_fixup_new_pci_devices(bus, 1); | ||
| 242 | pci_bus_add_devices(bus); | 264 | pci_bus_add_devices(bus); |
| 243 | } | 265 | dev = list_entry(&bus->devices, struct pci_dev, bus_list); |
| 244 | if (list_empty(&bus->devices)) { | 266 | } else { |
| 245 | err("%s: No new device found\n", __FUNCTION__); | 267 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); |
| 246 | return NULL; | 268 | |
| 247 | } | 269 | /* pci_scan_slot should find all children */ |
| 248 | list_for_each_entry(dev, &bus->devices, bus_list) { | 270 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); |
| 249 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) | 271 | if (num) { |
| 250 | rpaphp_pci_config_bridge(dev); | 272 | rpaphp_fixup_new_pci_devices(bus, 1); |
| 273 | pci_bus_add_devices(bus); | ||
| 274 | } | ||
| 275 | if (list_empty(&bus->devices)) { | ||
| 276 | err("%s: No new device found\n", __FUNCTION__); | ||
| 277 | return NULL; | ||
| 278 | } | ||
| 279 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
| 280 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) | ||
| 281 | rpaphp_pci_config_bridge(dev); | ||
| 282 | |||
| 283 | rpaphp_eeh_add_bus_device(bus); | ||
| 284 | } | ||
| 251 | } | 285 | } |
| 252 | 286 | ||
| 253 | return dev; | 287 | return dev; |
| 254 | } | 288 | } |
| 255 | 289 | ||
| 256 | static void enable_eeh(struct device_node *dn) | 290 | void rpaphp_eeh_init_nodes(struct device_node *dn) |
| 257 | { | 291 | { |
| 258 | struct device_node *sib; | 292 | struct device_node *sib; |
| 259 | 293 | ||
| 260 | for (sib = dn->child; sib; sib = sib->sibling) | 294 | for (sib = dn->child; sib; sib = sib->sibling) |
| 261 | enable_eeh(sib); | 295 | rpaphp_eeh_init_nodes(sib); |
| 262 | eeh_add_device_early(dn); | 296 | eeh_add_device_early(dn); |
| 263 | return; | 297 | return; |
| 264 | 298 | ||
| 265 | } | 299 | } |
| 300 | EXPORT_SYMBOL_GPL(rpaphp_eeh_init_nodes); | ||
| 266 | 301 | ||
| 267 | static void print_slot_pci_funcs(struct pci_bus *bus) | 302 | static void print_slot_pci_funcs(struct pci_bus *bus) |
| 268 | { | 303 | { |
| @@ -289,7 +324,7 @@ int rpaphp_config_pci_adapter(struct pci_bus *bus) | |||
| 289 | if (!dn) | 324 | if (!dn) |
| 290 | goto exit; | 325 | goto exit; |
| 291 | 326 | ||
| 292 | enable_eeh(dn); | 327 | rpaphp_eeh_init_nodes(dn); |
| 293 | dev = rpaphp_pci_config_slot(bus); | 328 | dev = rpaphp_pci_config_slot(bus); |
| 294 | if (!dev) { | 329 | if (!dev) { |
| 295 | err("%s: can't find any devices.\n", __FUNCTION__); | 330 | err("%s: can't find any devices.\n", __FUNCTION__); |
| @@ -331,6 +366,7 @@ int rpaphp_unconfig_pci_adapter(struct pci_bus *bus) | |||
| 331 | } | 366 | } |
| 332 | return 0; | 367 | return 0; |
| 333 | } | 368 | } |
| 369 | EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter); | ||
| 334 | 370 | ||
| 335 | static int setup_pci_hotplug_slot_info(struct slot *slot) | 371 | static int setup_pci_hotplug_slot_info(struct slot *slot) |
| 336 | { | 372 | { |
| @@ -444,8 +480,8 @@ int rpaphp_enable_pci_slot(struct slot *slot) | |||
| 444 | retval = rpaphp_config_pci_adapter(slot->bus); | 480 | retval = rpaphp_config_pci_adapter(slot->bus); |
| 445 | if (!retval) { | 481 | if (!retval) { |
| 446 | slot->state = CONFIGURED; | 482 | slot->state = CONFIGURED; |
| 447 | dbg("%s: PCI devices in slot[%s] has been configured\n", | 483 | info("%s: devices in slot[%s] configured\n", |
| 448 | __FUNCTION__, slot->name); | 484 | __FUNCTION__, slot->name); |
| 449 | } else { | 485 | } else { |
| 450 | slot->state = NOT_CONFIGURED; | 486 | slot->state = NOT_CONFIGURED; |
| 451 | dbg("%s: no pci_dev struct for adapter in slot[%s]\n", | 487 | dbg("%s: no pci_dev struct for adapter in slot[%s]\n", |
