root/drivers/pci/hotplug/rpadlpar_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_vio_slot_node
  2. find_php_slot_pci_node
  3. find_dlpar_node
  4. find_php_slot
  5. dlpar_find_new_dev
  6. dlpar_pci_add_bus
  7. dlpar_add_pci_slot
  8. dlpar_remove_phb
  9. dlpar_add_phb
  10. dlpar_add_vio_slot
  11. dlpar_add_slot
  12. dlpar_remove_vio_slot
  13. dlpar_remove_pci_slot
  14. dlpar_remove_slot
  15. is_dlpar_capable
  16. rpadlpar_io_init
  17. rpadlpar_io_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Interface for Dynamic Logical Partitioning of I/O Slots on
   4  * RPA-compliant PPC64 platform.
   5  *
   6  * John Rose <johnrose@austin.ibm.com>
   7  * Linda Xie <lxie@us.ibm.com>
   8  *
   9  * October 2003
  10  *
  11  * Copyright (C) 2003 IBM.
  12  */
  13 
  14 #undef DEBUG
  15 
  16 #include <linux/init.h>
  17 #include <linux/module.h>
  18 #include <linux/pci.h>
  19 #include <linux/string.h>
  20 #include <linux/vmalloc.h>
  21 
  22 #include <asm/pci-bridge.h>
  23 #include <linux/mutex.h>
  24 #include <asm/rtas.h>
  25 #include <asm/vio.h>
  26 #include <linux/firmware.h>
  27 
  28 #include "../pci.h"
  29 #include "rpaphp.h"
  30 #include "rpadlpar.h"
  31 
  32 static DEFINE_MUTEX(rpadlpar_mutex);
  33 
  34 #define DLPAR_MODULE_NAME "rpadlpar_io"
  35 
  36 #define NODE_TYPE_VIO  1
  37 #define NODE_TYPE_SLOT 2
  38 #define NODE_TYPE_PHB  3
  39 
  40 static struct device_node *find_vio_slot_node(char *drc_name)
  41 {
  42         struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
  43         struct device_node *dn = NULL;
  44         int rc;
  45 
  46         if (!parent)
  47                 return NULL;
  48 
  49         while ((dn = of_get_next_child(parent, dn))) {
  50                 rc = rpaphp_check_drc_props(dn, drc_name, NULL);
  51                 if (rc == 0)
  52                         break;
  53         }
  54         of_node_put(parent);
  55 
  56         return dn;
  57 }
  58 
  59 /* Find dlpar-capable pci node that contains the specified name and type */
  60 static struct device_node *find_php_slot_pci_node(char *drc_name,
  61                                                   char *drc_type)
  62 {
  63         struct device_node *np = NULL;
  64         int rc;
  65 
  66         while ((np = of_find_node_by_name(np, "pci"))) {
  67                 rc = rpaphp_check_drc_props(np, drc_name, drc_type);
  68                 if (rc == 0)
  69                         break;
  70         }
  71 
  72         return np;
  73 }
  74 
  75 /* Returns a device_node with its reference count incremented */
  76 static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
  77 {
  78         struct device_node *dn;
  79 
  80         dn = find_php_slot_pci_node(drc_name, "SLOT");
  81         if (dn) {
  82                 *node_type = NODE_TYPE_SLOT;
  83                 return dn;
  84         }
  85 
  86         dn = find_php_slot_pci_node(drc_name, "PHB");
  87         if (dn) {
  88                 *node_type = NODE_TYPE_PHB;
  89                 return dn;
  90         }
  91 
  92         dn = find_vio_slot_node(drc_name);
  93         if (dn) {
  94                 *node_type = NODE_TYPE_VIO;
  95                 return dn;
  96         }
  97 
  98         return NULL;
  99 }
 100 
 101 /**
 102  * find_php_slot - return hotplug slot structure for device node
 103  * @dn: target &device_node
 104  *
 105  * This routine will return the hotplug slot structure
 106  * for a given device node. Note that built-in PCI slots
 107  * may be dlpar-able, but not hot-pluggable, so this routine
 108  * will return NULL for built-in PCI slots.
 109  */
 110 static struct slot *find_php_slot(struct device_node *dn)
 111 {
 112         struct slot *slot, *next;
 113 
 114         list_for_each_entry_safe(slot, next, &rpaphp_slot_head,
 115                                  rpaphp_slot_list) {
 116                 if (slot->dn == dn)
 117                         return slot;
 118         }
 119 
 120         return NULL;
 121 }
 122 
 123 static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
 124                                         struct device_node *dev_dn)
 125 {
 126         struct pci_dev *tmp = NULL;
 127         struct device_node *child_dn;
 128 
 129         list_for_each_entry(tmp, &parent->devices, bus_list) {
 130                 child_dn = pci_device_to_OF_node(tmp);
 131                 if (child_dn == dev_dn)
 132                         return tmp;
 133         }
 134         return NULL;
 135 }
 136 
 137 static void dlpar_pci_add_bus(struct device_node *dn)
 138 {
 139         struct pci_dn *pdn = PCI_DN(dn);
 140         struct pci_controller *phb = pdn->phb;
 141         struct pci_dev *dev = NULL;
 142 
 143         eeh_add_device_tree_early(pdn);
 144 
 145         /* Add EADS device to PHB bus, adding new entry to bus->devices */
 146         dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
 147         if (!dev) {
 148                 printk(KERN_ERR "%s: failed to create pci dev for %pOF\n",
 149                                 __func__, dn);
 150                 return;
 151         }
 152 
 153         /* Scan below the new bridge */
 154         if (pci_is_bridge(dev))
 155                 of_scan_pci_bridge(dev);
 156 
 157         /* Map IO space for child bus, which may or may not succeed */
 158         pcibios_map_io_space(dev->subordinate);
 159 
 160         /* Finish adding it : resource allocation, adding devices, etc...
 161          * Note that we need to perform the finish pass on the -parent-
 162          * bus of the EADS bridge so the bridge device itself gets
 163          * properly added
 164          */
 165         pcibios_finish_adding_to_bus(phb->bus);
 166 }
 167 
 168 static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
 169 {
 170         struct pci_dev *dev;
 171         struct pci_controller *phb;
 172 
 173         if (pci_find_bus_by_node(dn))
 174                 return -EINVAL;
 175 
 176         /* Add pci bus */
 177         dlpar_pci_add_bus(dn);
 178 
 179         /* Confirm new bridge dev was created */
 180         phb = PCI_DN(dn)->phb;
 181         dev = dlpar_find_new_dev(phb->bus, dn);
 182 
 183         if (!dev) {
 184                 printk(KERN_ERR "%s: unable to add bus %s\n", __func__,
 185                         drc_name);
 186                 return -EIO;
 187         }
 188 
 189         if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
 190                 printk(KERN_ERR "%s: unexpected header type %d, unable to add bus %s\n",
 191                         __func__, dev->hdr_type, drc_name);
 192                 return -EIO;
 193         }
 194 
 195         /* Add hotplug slot */
 196         if (rpaphp_add_slot(dn)) {
 197                 printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
 198                         __func__, drc_name);
 199                 return -EIO;
 200         }
 201         return 0;
 202 }
 203 
 204 static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
 205 {
 206         struct slot *slot;
 207         struct pci_dn *pdn;
 208         int rc = 0;
 209 
 210         if (!pci_find_bus_by_node(dn))
 211                 return -EINVAL;
 212 
 213         /* If pci slot is hotpluggable, use hotplug to remove it */
 214         slot = find_php_slot(dn);
 215         if (slot && rpaphp_deregister_slot(slot)) {
 216                 printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
 217                        __func__, drc_name);
 218                 return -EIO;
 219         }
 220 
 221         pdn = dn->data;
 222         BUG_ON(!pdn || !pdn->phb);
 223         rc = remove_phb_dynamic(pdn->phb);
 224         if (rc < 0)
 225                 return rc;
 226 
 227         pdn->phb = NULL;
 228 
 229         return 0;
 230 }
 231 
 232 static int dlpar_add_phb(char *drc_name, struct device_node *dn)
 233 {
 234         struct pci_controller *phb;
 235 
 236         if (PCI_DN(dn) && PCI_DN(dn)->phb) {
 237                 /* PHB already exists */
 238                 return -EINVAL;
 239         }
 240 
 241         phb = init_phb_dynamic(dn);
 242         if (!phb)
 243                 return -EIO;
 244 
 245         if (rpaphp_add_slot(dn)) {
 246                 printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
 247                         __func__, drc_name);
 248                 return -EIO;
 249         }
 250         return 0;
 251 }
 252 
 253 static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
 254 {
 255         struct vio_dev *vio_dev;
 256 
 257         vio_dev = vio_find_node(dn);
 258         if (vio_dev) {
 259                 put_device(&vio_dev->dev);
 260                 return -EINVAL;
 261         }
 262 
 263         if (!vio_register_device_node(dn)) {
 264                 printk(KERN_ERR
 265                         "%s: failed to register vio node %s\n",
 266                         __func__, drc_name);
 267                 return -EIO;
 268         }
 269         return 0;
 270 }
 271 
 272 /**
 273  * dlpar_add_slot - DLPAR add an I/O Slot
 274  * @drc_name: drc-name of newly added slot
 275  *
 276  * Make the hotplug module and the kernel aware of a newly added I/O Slot.
 277  * Return Codes:
 278  * 0                    Success
 279  * -ENODEV              Not a valid drc_name
 280  * -EINVAL              Slot already added
 281  * -ERESTARTSYS         Signalled before obtaining lock
 282  * -EIO                 Internal PCI Error
 283  */
 284 int dlpar_add_slot(char *drc_name)
 285 {
 286         struct device_node *dn = NULL;
 287         int node_type;
 288         int rc = -EIO;
 289 
 290         if (mutex_lock_interruptible(&rpadlpar_mutex))
 291                 return -ERESTARTSYS;
 292 
 293         /* Find newly added node */
 294         dn = find_dlpar_node(drc_name, &node_type);
 295         if (!dn) {
 296                 rc = -ENODEV;
 297                 goto exit;
 298         }
 299 
 300         switch (node_type) {
 301                 case NODE_TYPE_VIO:
 302                         rc = dlpar_add_vio_slot(drc_name, dn);
 303                         break;
 304                 case NODE_TYPE_SLOT:
 305                         rc = dlpar_add_pci_slot(drc_name, dn);
 306                         break;
 307                 case NODE_TYPE_PHB:
 308                         rc = dlpar_add_phb(drc_name, dn);
 309                         break;
 310         }
 311         of_node_put(dn);
 312 
 313         printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
 314 exit:
 315         mutex_unlock(&rpadlpar_mutex);
 316         return rc;
 317 }
 318 
 319 /**
 320  * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
 321  * @drc_name: drc-name of newly added slot
 322  * @dn: &device_node
 323  *
 324  * Remove the kernel and hotplug representations of an I/O Slot.
 325  * Return Codes:
 326  * 0                    Success
 327  * -EINVAL              Vio dev doesn't exist
 328  */
 329 static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
 330 {
 331         struct vio_dev *vio_dev;
 332 
 333         vio_dev = vio_find_node(dn);
 334         if (!vio_dev)
 335                 return -EINVAL;
 336 
 337         vio_unregister_device(vio_dev);
 338 
 339         put_device(&vio_dev->dev);
 340 
 341         return 0;
 342 }
 343 
 344 /**
 345  * dlpar_remove_pci_slot - DLPAR remove a PCI I/O Slot
 346  * @drc_name: drc-name of newly added slot
 347  * @dn: &device_node
 348  *
 349  * Remove the kernel and hotplug representations of a PCI I/O Slot.
 350  * Return Codes:
 351  * 0                    Success
 352  * -ENODEV              Not a valid drc_name
 353  * -EIO                 Internal PCI Error
 354  */
 355 int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
 356 {
 357         struct pci_bus *bus;
 358         struct slot *slot;
 359         int ret = 0;
 360 
 361         pci_lock_rescan_remove();
 362 
 363         bus = pci_find_bus_by_node(dn);
 364         if (!bus) {
 365                 ret = -EINVAL;
 366                 goto out;
 367         }
 368 
 369         pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
 370                  bus->self ? pci_name(bus->self) : "<!PHB!>");
 371 
 372         slot = find_php_slot(dn);
 373         if (slot) {
 374                 pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
 375                          pci_domain_nr(bus), bus->number);
 376 
 377                 if (rpaphp_deregister_slot(slot)) {
 378                         printk(KERN_ERR
 379                                 "%s: unable to remove hotplug slot %s\n",
 380                                 __func__, drc_name);
 381                         ret = -EIO;
 382                         goto out;
 383                 }
 384         }
 385 
 386         /* Remove all devices below slot */
 387         pci_hp_remove_devices(bus);
 388 
 389         /* Unmap PCI IO space */
 390         if (pcibios_unmap_io_space(bus)) {
 391                 printk(KERN_ERR "%s: failed to unmap bus range\n",
 392                         __func__);
 393                 ret = -ERANGE;
 394                 goto out;
 395         }
 396 
 397         /* Remove the EADS bridge device itself */
 398         BUG_ON(!bus->self);
 399         pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
 400         pci_stop_and_remove_bus_device(bus->self);
 401 
 402  out:
 403         pci_unlock_rescan_remove();
 404         return ret;
 405 }
 406 
 407 /**
 408  * dlpar_remove_slot - DLPAR remove an I/O Slot
 409  * @drc_name: drc-name of newly added slot
 410  *
 411  * Remove the kernel and hotplug representations of an I/O Slot.
 412  * Return Codes:
 413  * 0                    Success
 414  * -ENODEV              Not a valid drc_name
 415  * -EINVAL              Slot already removed
 416  * -ERESTARTSYS         Signalled before obtaining lock
 417  * -EIO                 Internal Error
 418  */
 419 int dlpar_remove_slot(char *drc_name)
 420 {
 421         struct device_node *dn;
 422         int node_type;
 423         int rc = 0;
 424 
 425         if (mutex_lock_interruptible(&rpadlpar_mutex))
 426                 return -ERESTARTSYS;
 427 
 428         dn = find_dlpar_node(drc_name, &node_type);
 429         if (!dn) {
 430                 rc = -ENODEV;
 431                 goto exit;
 432         }
 433 
 434         switch (node_type) {
 435                 case NODE_TYPE_VIO:
 436                         rc = dlpar_remove_vio_slot(drc_name, dn);
 437                         break;
 438                 case NODE_TYPE_PHB:
 439                         rc = dlpar_remove_phb(drc_name, dn);
 440                         break;
 441                 case NODE_TYPE_SLOT:
 442                         rc = dlpar_remove_pci_slot(drc_name, dn);
 443                         break;
 444         }
 445         of_node_put(dn);
 446         vm_unmap_aliases();
 447 
 448         printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
 449 exit:
 450         mutex_unlock(&rpadlpar_mutex);
 451         return rc;
 452 }
 453 
 454 static inline int is_dlpar_capable(void)
 455 {
 456         int rc = rtas_token("ibm,configure-connector");
 457 
 458         return (int) (rc != RTAS_UNKNOWN_SERVICE);
 459 }
 460 
 461 int __init rpadlpar_io_init(void)
 462 {
 463 
 464         if (!is_dlpar_capable()) {
 465                 printk(KERN_WARNING "%s: partition not DLPAR capable\n",
 466                         __func__);
 467                 return -EPERM;
 468         }
 469 
 470         return dlpar_sysfs_init();
 471 }
 472 
 473 void rpadlpar_io_exit(void)
 474 {
 475         dlpar_sysfs_exit();
 476 }
 477 
 478 module_init(rpadlpar_io_init);
 479 module_exit(rpadlpar_io_exit);
 480 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */