linux/drivers/pci/hotplug/rpadlpar_core.c
<<
>>
Prefs
   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
  32static 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
  40static 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;
  44        int rc;
  45
  46        if (!parent)
  47                return NULL;
  48
  49        for_each_child_of_node(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 */
  60static struct device_node *find_php_slot_pci_node(char *drc_name,
  61                                                  char *drc_type)
  62{
  63        struct device_node *np;
  64        int rc;
  65
  66        for_each_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 */
  76static 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 */
 110static 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
 123static 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
 137static 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        pseries_eeh_init_edev_recursive(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
 168static 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
 204static 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
 232static 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
 253static 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 */
 284int 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);
 314exit:
 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 */
 329static 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 */
 355static 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 */
 419int 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);
 449exit:
 450        mutex_unlock(&rpadlpar_mutex);
 451        return rc;
 452}
 453
 454static 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
 461static 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
 473static void __exit rpadlpar_io_exit(void)
 474{
 475        dlpar_sysfs_exit();
 476}
 477
 478module_init(rpadlpar_io_init);
 479module_exit(rpadlpar_io_exit);
 480MODULE_LICENSE("GPL");
 481