1 /* 2 * Interface for Dynamic Logical Partitioning of I/O Slots on 3 * RPA-compliant PPC64 platform. 4 * 5 * John Rose <johnrose@austin.ibm.com> 6 * Linda Xie <lxie@us.ibm.com> 7 * 8 * October 2003 9 * 10 * Copyright (C) 2003 IBM. 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 15 * 2 of the License, or (at your option) any later version. 16 */ 17 #include <linux/init.h> 18 #include <linux/pci.h> 19 #include <asm/pci-bridge.h> 20 #include <asm/semaphore.h> 21 #include <asm/rtas.h> 22 #include "../pci.h" 23 #include "rpaphp.h" 24 #include "rpadlpar.h" 25 26 static DECLARE_MUTEX(rpadlpar_sem); 27 28 #define NODE_TYPE_VIO 1 29 #define NODE_TYPE_SLOT 2 30 #define NODE_TYPE_PHB 3 31 32 static struct device_node *find_php_slot_vio_node(char *drc_name) 33 { 34 struct device_node *child; 35 struct device_node *parent = of_find_node_by_name(NULL, "vdevice"); 36 char *loc_code; 37 38 if (!parent) 39 return NULL; 40 41 for (child = of_get_next_child(parent, NULL); 42 child; child = of_get_next_child(parent, child)) { 43 loc_code = get_property(child, "ibm,loc-code", NULL); 44 if (loc_code && !strncmp(loc_code, drc_name, strlen(drc_name))) 45 return child; 46 } 47 48 return NULL; 49 } 50 51 /* Find dlpar-capable pci node that contains the specified name and type */ 52 static struct device_node *find_php_slot_pci_node(char *drc_name, 53 char *drc_type) 54 { 55 struct device_node *np = NULL; 56 char *name; 57 char *type; 58 int rc; 59 60 while ((np = of_find_node_by_type(np, "pci"))) { 61 rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL); 62 if (rc == 0) 63 if (!strcmp(drc_name, name) && !strcmp(drc_type, type)) 64 break; 65 } 66 67 return np; 68 } 69 70 static struct device_node *find_newly_added_node(char *drc_name, int *node_type) 71 { 72 struct device_node *dn; 73 74 dn = find_php_slot_pci_node(drc_name, "SLOT"); 75 if (dn) { 76 *node_type = NODE_TYPE_SLOT; 77 return dn; 78 } 79 80 dn = find_php_slot_pci_node(drc_name, "PHB"); 81 if (dn) { 82 *node_type = NODE_TYPE_PHB; 83 return dn; 84 } 85 86 dn = find_php_slot_vio_node(drc_name); 87 if (dn) { 88 *node_type = NODE_TYPE_VIO; 89 return dn; 90 } 91 92 return NULL; 93 } 94 95 static struct slot *find_slot(char *drc_name) 96 { 97 struct list_head *tmp, *n; 98 struct slot *slot; 99 100 list_for_each_safe(tmp, n, &rpaphp_slot_head) { 101 slot = list_entry(tmp, struct slot, rpaphp_slot_list); 102 if (strcmp(slot->location, drc_name) == 0) 103 return slot; 104 } 105 106 return NULL; 107 } 108 109 static void rpadlpar_claim_one_bus(struct pci_bus *b) 110 { 111 struct list_head *ld; 112 struct pci_bus *child_bus; 113 114 for (ld = b->devices.next; ld != &b->devices; ld = ld->next) { 115 struct pci_dev *dev = pci_dev_b(ld); 116 int i; 117 118 for (i = 0; i < PCI_NUM_RESOURCES; i++) { 119 struct resource *r = &dev->resource[i]; 120 121 if (r->parent || !r->start || !r->flags) 122 continue; 123 rpaphp_claim_resource(dev, i); 124 } 125 } 126 127 list_for_each_entry(child_bus, &b->children, node) 128 rpadlpar_claim_one_bus(child_bus); 129 } 130 131 static int pci_add_secondary_bus(struct device_node *dn, 132 struct pci_dev *bridge_dev) 133 { 134 struct pci_controller *hose = dn->phb; 135 struct pci_bus *child; 136 u8 sec_busno; 137 138 /* Get busno of downstream bus */ 139 pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno); 140 141 /* Allocate and add to children of bridge_dev->bus */ 142 child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno); 143 if (!child) { 144 printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__); 145 return -ENOMEM; 146 } 147 148 sprintf(child->name, "PCI Bus #%02x", child->number); 149 150 /* Fixup subordinate bridge bases and resources */ 151 pcibios_fixup_bus(child); 152 153 /* Claim new bus resources */ 154 rpadlpar_claim_one_bus(bridge_dev->bus); 155 156 if (hose->last_busno < child->number) 157 hose->last_busno = child->number; 158 159 dn->bussubno = child->number; 160 161 /* ioremap() for child bus, which may or may not succeed */ 162 remap_bus_range(child); 163 164 return 0; 165 } 166 167 static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) 168 { 169 struct pci_controller *hose = dn->phb; 170 struct pci_dev *dev = NULL; 171 172 /* Scan phb bus for EADS device, adding new one to bus->devices */ 173 if (!pci_scan_single_device(hose->bus, dn->devfn)) { 174 printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__); 175 return NULL; 176 } 177 178 /* Add new devices to global lists. Register in proc, sysfs. */ 179 pci_bus_add_devices(hose->bus); 180 181 /* Confirm new bridge dev was created */ 182 dev = rpaphp_find_pci_dev(dn); 183 if (!dev) { 184 printk(KERN_ERR "%s: failed to add pci device\n", __FUNCTION__); 185 return NULL; 186 } 187 188 if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { 189 printk(KERN_ERR "%s: unexpected header type %d\n", 190 __FUNCTION__, dev->hdr_type); 191 return NULL; 192 } 193 194 if (pci_add_secondary_bus(dn, dev)) 195 return NULL; 196 197 return dev; 198 } 199 200 static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev) 201 { 202 struct pci_bus *secondary_bus; 203 204 if (!bridge_dev) { 205 printk(KERN_ERR "%s: unexpected null device\n", 206 __FUNCTION__); 207 return -EINVAL; 208 } 209 210 secondary_bus = bridge_dev->subordinate; 211 212 if (unmap_bus_range(secondary_bus)) { 213 printk(KERN_ERR "%s: failed to unmap bus range\n", 214 __FUNCTION__); 215 return -ERANGE; 216 } 217 218 pci_remove_bus_device(bridge_dev); 219 return 0; 220 } 221 222 static inline int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) 223 { 224 struct pci_dev *dev; 225 226 /* Add pci bus */ 227 dev = dlpar_pci_add_bus(dn); 228 if (!dev) { 229 printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__, 230 drc_name); 231 return -EIO; 232 } 233 234 return 0; 235 } 236 237 static int dlpar_remove_root_bus(struct pci_controller *phb) 238 { 239 struct pci_bus *phb_bus; 240 int rc; 241 242 phb_bus = phb->bus; 243 if (!(list_empty(&phb_bus->children) && 244 list_empty(&phb_bus->devices))) { 245 return -EBUSY; 246 } 247 248 rc = pcibios_remove_root_bus(phb); 249 if (rc) 250 return -EIO; 251 252 device_unregister(phb_bus->bridge); 253 pci_remove_bus(phb_bus); 254 255 return 0; 256 } 257 258 static int dlpar_remove_phb(struct slot *slot) 259 { 260 struct pci_controller *phb; 261 struct device_node *dn; 262 int rc = 0; 263 264 dn = slot->dn; 265 if (!dn) { 266 printk(KERN_ERR "%s: unexpected NULL slot device node\n", 267 __FUNCTION__); 268 return -EIO; 269 } 270 271 phb = dn->phb; 272 if (!phb) { 273 printk(KERN_ERR "%s: unexpected NULL phb pointer\n", 274 __FUNCTION__); 275 return -EIO; 276 } 277 278 if (rpaphp_remove_slot(slot)) { 279 printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", 280 __FUNCTION__, slot->location); 281 return -EIO; 282 } 283 284 rc = dlpar_remove_root_bus(phb); 285 if (rc < 0) 286 return rc; 287 288 return 0; 289 } 290 291 static int dlpar_add_phb(struct device_node *dn) 292 { 293 struct pci_controller *phb; 294 295 phb = init_phb_dynamic(dn); 296 if (!phb) 297 return -EINVAL; 298 299 return 0; 300 } 301 302 /** 303 * dlpar_add_slot - DLPAR add an I/O Slot 304 * @drc_name: drc-name of newly added slot 305 * 306 * Make the hotplug module and the kernel aware 307 * of a newly added I/O Slot. 308 * Return Codes - 309 * 0 Success 310 * -ENODEV Not a valid drc_name 311 * -EINVAL Slot already added 312 * -ERESTARTSYS Signalled before obtaining lock 313 * -EIO Internal PCI Error 314 */ 315 int dlpar_add_slot(char *drc_name) 316 { 317 struct device_node *dn = NULL; 318 int node_type; 319 int rc = 0; 320 321 if (down_interruptible(&rpadlpar_sem)) 322 return -ERESTARTSYS; 323 324 /* Check for existing hotplug slot */ 325 if (find_slot(drc_name)) { 326 rc = -EINVAL; 327 goto exit; 328 } 329 330 dn = find_newly_added_node(drc_name, &node_type); 331 if (!dn) { 332 rc = -ENODEV; 333 goto exit; 334 } 335 336 switch (node_type) { 337 case NODE_TYPE_VIO: 338 /* Just add hotplug slot */ 339 break; 340 case NODE_TYPE_SLOT: 341 rc = dlpar_add_pci_slot(drc_name, dn); 342 break; 343 case NODE_TYPE_PHB: 344 rc = dlpar_add_phb(dn); 345 break; 346 default: 347 printk("%s: unexpected node type\n", __FUNCTION__); 348 return -EIO; 349 } 350 351 if (!rc && rpaphp_add_slot(dn)) { 352 printk(KERN_ERR "%s: unable to add hotplug slot %s\n", 353 __FUNCTION__, drc_name); 354 rc = -EIO; 355 } 356 exit: 357 up(&rpadlpar_sem); 358 return rc; 359 } 360 361 /** 362 * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot 363 * @drc_name: drc-name of newly added slot 364 * 365 * Remove the kernel and hotplug representations 366 * of an I/O Slot. 367 * Return Codes: 368 * 0 Success 369 * -EIO Internal Error 370 */ 371 int dlpar_remove_vio_slot(struct slot *slot, char *drc_name) 372 { 373 /* Remove hotplug slot */ 374 375 if (rpaphp_remove_slot(slot)) { 376 printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", 377 __FUNCTION__, drc_name); 378 return -EIO; 379 } 380 return 0; 381 } 382 383 /** 384 * dlpar_remove_slot - DLPAR remove a PCI I/O Slot 385 * @drc_name: drc-name of newly added slot 386 * 387 * Remove the kernel and hotplug representations 388 * of a PCI I/O Slot. 389 * Return Codes: 390 * 0 Success 391 * -ENODEV Not a valid drc_name 392 * -EIO Internal PCI Error 393 */ 394 int dlpar_remove_pci_slot(struct slot *slot, char *drc_name) 395 { 396 struct pci_dev *bridge_dev; 397 398 bridge_dev = slot->bridge; 399 if (!bridge_dev) { 400 printk(KERN_ERR "%s: unexpected null bridge device\n", 401 __FUNCTION__); 402 return -EIO; 403 } 404 405 /* Remove hotplug slot */ 406 if (rpaphp_remove_slot(slot)) { 407 printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", 408 __FUNCTION__, drc_name); 409 return -EIO; 410 } 411 412 /* Remove pci bus */ 413 414 if (dlpar_pci_remove_bus(bridge_dev)) { 415 printk(KERN_ERR "%s: unable to remove pci bus %s\n", 416 __FUNCTION__, drc_name); 417 return -EIO; 418 } 419 return 0; 420 } 421 422 /** 423 * dlpar_remove_slot - DLPAR remove an I/O Slot 424 * @drc_name: drc-name of newly added slot 425 * 426 * Remove the kernel and hotplug representations 427 * of an I/O Slot. 428 * Return Codes: 429 * 0 Success 430 * -ENODEV Not a valid drc_name 431 * -EINVAL Slot already removed 432 * -ERESTARTSYS Signalled before obtaining lock 433 * -EIO Internal Error 434 */ 435 int dlpar_remove_slot(char *drc_name) 436 { 437 struct slot *slot; 438 int rc = 0; 439 440 if (down_interruptible(&rpadlpar_sem)) 441 return -ERESTARTSYS; 442 443 if (!find_php_slot_vio_node(drc_name) && 444 !find_php_slot_pci_node(drc_name, "SLOT") && 445 !find_php_slot_pci_node(drc_name, "PHB")) { 446 rc = -ENODEV; 447 goto exit; 448 } 449 450 slot = find_slot(drc_name); 451 if (!slot) { 452 rc = -EINVAL; 453 goto exit; 454 } 455 456 if (slot->type == PHB) { 457 rc = dlpar_remove_phb(slot); 458 } else { 459 switch (slot->dev_type) { 460 case PCI_DEV: 461 rc = dlpar_remove_pci_slot(slot, drc_name); 462 break; 463 464 case VIO_DEV: 465 rc = dlpar_remove_vio_slot(slot, drc_name); 466 break; 467 } 468 } 469 exit: 470 up(&rpadlpar_sem); 471 return rc; 472 } 473 474 static inline int is_dlpar_capable(void) 475 { 476 int rc = rtas_token("ibm,configure-connector"); 477 478 return (int) (rc != RTAS_UNKNOWN_SERVICE); 479 } 480 481 int __init rpadlpar_io_init(void) 482 { 483 int rc = 0; 484 485 if (!is_dlpar_capable()) { 486 printk(KERN_WARNING "%s: partition not DLPAR capable\n", 487 __FUNCTION__); 488 return -EPERM; 489 } 490 491 rc = dlpar_sysfs_init(); 492 return rc; 493 } 494 495 void rpadlpar_io_exit(void) 496 { 497 dlpar_sysfs_exit(); 498 return; 499 } 500 501 module_init(rpadlpar_io_init); 502 module_exit(rpadlpar_io_exit); 503 MODULE_LICENSE("GPL"); 504