root/drivers/pci/hotplug/rpaphp_core.c

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

DEFINITIONS

This source file includes following definitions.
  1. set_attention_status
  2. get_power_status
  3. get_attention_status
  4. get_adapter_status
  5. get_max_bus_speed
  6. get_children_props
  7. rpaphp_check_drc_props_v1
  8. rpaphp_check_drc_props_v2
  9. rpaphp_check_drc_props
  10. is_php_type
  11. is_php_dn
  12. rpaphp_add_slot
  13. cleanup_slots
  14. rpaphp_init
  15. rpaphp_exit
  16. enable_slot
  17. disable_slot

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
   4  * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
   5  *
   6  * All rights reserved.
   7  *
   8  * Send feedback to <lxie@us.ibm.com>
   9  *
  10  */
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/moduleparam.h>
  14 #include <linux/pci.h>
  15 #include <linux/pci_hotplug.h>
  16 #include <linux/smp.h>
  17 #include <linux/init.h>
  18 #include <linux/vmalloc.h>
  19 #include <asm/firmware.h>
  20 #include <asm/eeh.h>       /* for eeh_add_device() */
  21 #include <asm/rtas.h>           /* rtas_call */
  22 #include <asm/pci-bridge.h>     /* for pci_controller */
  23 #include "../pci.h"             /* for pci_add_new_bus */
  24                                 /* and pci_do_scan_bus */
  25 #include "rpaphp.h"
  26 
  27 bool rpaphp_debug;
  28 LIST_HEAD(rpaphp_slot_head);
  29 EXPORT_SYMBOL_GPL(rpaphp_slot_head);
  30 
  31 #define DRIVER_VERSION  "0.1"
  32 #define DRIVER_AUTHOR   "Linda Xie <lxie@us.ibm.com>"
  33 #define DRIVER_DESC     "RPA HOT Plug PCI Controller Driver"
  34 
  35 #define MAX_LOC_CODE 128
  36 
  37 MODULE_AUTHOR(DRIVER_AUTHOR);
  38 MODULE_DESCRIPTION(DRIVER_DESC);
  39 MODULE_LICENSE("GPL");
  40 
  41 module_param_named(debug, rpaphp_debug, bool, 0644);
  42 
  43 /**
  44  * set_attention_status - set attention LED
  45  * @hotplug_slot: target &hotplug_slot
  46  * @value: LED control value
  47  *
  48  * echo 0 > attention -- set LED OFF
  49  * echo 1 > attention -- set LED ON
  50  * echo 2 > attention -- set LED ID(identify, light is blinking)
  51  */
  52 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
  53 {
  54         int rc;
  55         struct slot *slot = to_slot(hotplug_slot);
  56 
  57         switch (value) {
  58         case 0:
  59         case 1:
  60         case 2:
  61                 break;
  62         default:
  63                 value = 1;
  64                 break;
  65         }
  66 
  67         rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
  68         if (!rc)
  69                 slot->attention_status = value;
  70 
  71         return rc;
  72 }
  73 
  74 /**
  75  * get_power_status - get power status of a slot
  76  * @hotplug_slot: slot to get status
  77  * @value: pointer to store status
  78  */
  79 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
  80 {
  81         int retval, level;
  82         struct slot *slot = to_slot(hotplug_slot);
  83 
  84         retval = rtas_get_power_level(slot->power_domain, &level);
  85         if (!retval)
  86                 *value = level;
  87         return retval;
  88 }
  89 
  90 /**
  91  * get_attention_status - get attention LED status
  92  * @hotplug_slot: slot to get status
  93  * @value: pointer to store status
  94  */
  95 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
  96 {
  97         struct slot *slot = to_slot(hotplug_slot);
  98         *value = slot->attention_status;
  99         return 0;
 100 }
 101 
 102 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 103 {
 104         struct slot *slot = to_slot(hotplug_slot);
 105         int rc, state;
 106 
 107         rc = rpaphp_get_sensor_state(slot, &state);
 108 
 109         *value = NOT_VALID;
 110         if (rc)
 111                 return rc;
 112 
 113         if (state == EMPTY)
 114                 *value = EMPTY;
 115         else if (state == PRESENT)
 116                 *value = slot->state;
 117 
 118         return 0;
 119 }
 120 
 121 static enum pci_bus_speed get_max_bus_speed(struct slot *slot)
 122 {
 123         enum pci_bus_speed speed;
 124         switch (slot->type) {
 125         case 1:
 126         case 2:
 127         case 3:
 128         case 4:
 129         case 5:
 130         case 6:
 131                 speed = PCI_SPEED_33MHz;        /* speed for case 1-6 */
 132                 break;
 133         case 7:
 134         case 8:
 135                 speed = PCI_SPEED_66MHz;
 136                 break;
 137         case 11:
 138         case 14:
 139                 speed = PCI_SPEED_66MHz_PCIX;
 140                 break;
 141         case 12:
 142         case 15:
 143                 speed = PCI_SPEED_100MHz_PCIX;
 144                 break;
 145         case 13:
 146         case 16:
 147                 speed = PCI_SPEED_133MHz_PCIX;
 148                 break;
 149         default:
 150                 speed = PCI_SPEED_UNKNOWN;
 151                 break;
 152         }
 153 
 154         return speed;
 155 }
 156 
 157 static int get_children_props(struct device_node *dn, const __be32 **drc_indexes,
 158                               const __be32 **drc_names, const __be32 **drc_types,
 159                               const __be32 **drc_power_domains)
 160 {
 161         const __be32 *indexes, *names, *types, *domains;
 162 
 163         indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
 164         names = of_get_property(dn, "ibm,drc-names", NULL);
 165         types = of_get_property(dn, "ibm,drc-types", NULL);
 166         domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
 167 
 168         if (!indexes || !names || !types || !domains) {
 169                 /* Slot does not have dynamically-removable children */
 170                 return -EINVAL;
 171         }
 172         if (drc_indexes)
 173                 *drc_indexes = indexes;
 174         if (drc_names)
 175                 /* &drc_names[1] contains NULL terminated slot names */
 176                 *drc_names = names;
 177         if (drc_types)
 178                 /* &drc_types[1] contains NULL terminated slot types */
 179                 *drc_types = types;
 180         if (drc_power_domains)
 181                 *drc_power_domains = domains;
 182 
 183         return 0;
 184 }
 185 
 186 
 187 /* Verify the existence of 'drc_name' and/or 'drc_type' within the
 188  * current node.  First obtain it's my-drc-index property.  Next,
 189  * obtain the DRC info from it's parent.  Use the my-drc-index for
 190  * correlation, and obtain/validate the requested properties.
 191  */
 192 
 193 static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name,
 194                                 char *drc_type, unsigned int my_index)
 195 {
 196         char *name_tmp, *type_tmp;
 197         const __be32 *indexes, *names;
 198         const __be32 *types, *domains;
 199         int i, rc;
 200 
 201         rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
 202         if (rc < 0) {
 203                 return -EINVAL;
 204         }
 205 
 206         name_tmp = (char *) &names[1];
 207         type_tmp = (char *) &types[1];
 208 
 209         /* Iterate through parent properties, looking for my-drc-index */
 210         for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
 211                 if (be32_to_cpu(indexes[i + 1]) == my_index)
 212                         break;
 213 
 214                 name_tmp += (strlen(name_tmp) + 1);
 215                 type_tmp += (strlen(type_tmp) + 1);
 216         }
 217 
 218         if (((drc_name == NULL) || (drc_name && !strcmp(drc_name, name_tmp))) &&
 219             ((drc_type == NULL) || (drc_type && !strcmp(drc_type, type_tmp))))
 220                 return 0;
 221 
 222         return -EINVAL;
 223 }
 224 
 225 static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
 226                                 char *drc_type, unsigned int my_index)
 227 {
 228         struct property *info;
 229         unsigned int entries;
 230         struct of_drc_info drc;
 231         const __be32 *value;
 232         char cell_drc_name[MAX_DRC_NAME_LEN];
 233         int j;
 234 
 235         info = of_find_property(dn->parent, "ibm,drc-info", NULL);
 236         if (info == NULL)
 237                 return -EINVAL;
 238 
 239         value = of_prop_next_u32(info, NULL, &entries);
 240         if (!value)
 241                 return -EINVAL;
 242         else
 243                 value++;
 244 
 245         for (j = 0; j < entries; j++) {
 246                 of_read_drc_info_cell(&info, &value, &drc);
 247 
 248                 /* Should now know end of current entry */
 249 
 250                 /* Found it */
 251                 if (my_index >= drc.drc_index_start && my_index <= drc.last_drc_index) {
 252                         int index = my_index - drc.drc_index_start;
 253                         sprintf(cell_drc_name, "%s%d", drc.drc_name_prefix,
 254                                 drc.drc_name_suffix_start + index);
 255                         break;
 256                 }
 257         }
 258 
 259         if (((drc_name == NULL) ||
 260              (drc_name && !strcmp(drc_name, cell_drc_name))) &&
 261             ((drc_type == NULL) ||
 262              (drc_type && !strcmp(drc_type, drc.drc_type))))
 263                 return 0;
 264 
 265         return -EINVAL;
 266 }
 267 
 268 int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
 269                         char *drc_type)
 270 {
 271         const __be32 *my_index;
 272 
 273         my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
 274         if (!my_index) {
 275                 /* Node isn't DLPAR/hotplug capable */
 276                 return -EINVAL;
 277         }
 278 
 279         if (of_find_property(dn->parent, "ibm,drc-info", NULL))
 280                 return rpaphp_check_drc_props_v2(dn, drc_name, drc_type,
 281                                                 be32_to_cpu(*my_index));
 282         else
 283                 return rpaphp_check_drc_props_v1(dn, drc_name, drc_type,
 284                                                 be32_to_cpu(*my_index));
 285 }
 286 EXPORT_SYMBOL_GPL(rpaphp_check_drc_props);
 287 
 288 
 289 static int is_php_type(char *drc_type)
 290 {
 291         unsigned long value;
 292         char *endptr;
 293 
 294         /* PCI Hotplug nodes have an integer for drc_type */
 295         value = simple_strtoul(drc_type, &endptr, 10);
 296         if (endptr == drc_type)
 297                 return 0;
 298 
 299         return 1;
 300 }
 301 
 302 /**
 303  * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
 304  * @dn: target &device_node
 305  * @indexes: passed to get_children_props()
 306  * @names: passed to get_children_props()
 307  * @types: returned from get_children_props()
 308  * @power_domains:
 309  *
 310  * This routine will return true only if the device node is
 311  * a hotpluggable slot. This routine will return false
 312  * for built-in pci slots (even when the built-in slots are
 313  * dlparable.)
 314  */
 315 static int is_php_dn(struct device_node *dn, const __be32 **indexes,
 316                      const __be32 **names, const __be32 **types,
 317                      const __be32 **power_domains)
 318 {
 319         const __be32 *drc_types;
 320         int rc;
 321 
 322         rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
 323         if (rc < 0)
 324                 return 0;
 325 
 326         if (!is_php_type((char *) &drc_types[1]))
 327                 return 0;
 328 
 329         *types = drc_types;
 330         return 1;
 331 }
 332 
 333 /**
 334  * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
 335  * @dn: device node of slot
 336  *
 337  * This subroutine will register a hotpluggable slot with the
 338  * PCI hotplug infrastructure. This routine is typically called
 339  * during boot time, if the hotplug slots are present at boot time,
 340  * or is called later, by the dlpar add code, if the slot is
 341  * being dynamically added during runtime.
 342  *
 343  * If the device node points at an embedded (built-in) slot, this
 344  * routine will just return without doing anything, since embedded
 345  * slots cannot be hotplugged.
 346  *
 347  * To remove a slot, it suffices to call rpaphp_deregister_slot().
 348  */
 349 int rpaphp_add_slot(struct device_node *dn)
 350 {
 351         struct slot *slot;
 352         int retval = 0;
 353         int i;
 354         const __be32 *indexes, *names, *types, *power_domains;
 355         char *name, *type;
 356 
 357         if (!dn->name || strcmp(dn->name, "pci"))
 358                 return 0;
 359 
 360         /* If this is not a hotplug slot, return without doing anything. */
 361         if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
 362                 return 0;
 363 
 364         dbg("Entry %s: dn=%pOF\n", __func__, dn);
 365 
 366         /* register PCI devices */
 367         name = (char *) &names[1];
 368         type = (char *) &types[1];
 369         for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
 370                 int index;
 371 
 372                 index = be32_to_cpu(indexes[i + 1]);
 373                 slot = alloc_slot_struct(dn, index, name,
 374                                          be32_to_cpu(power_domains[i + 1]));
 375                 if (!slot)
 376                         return -ENOMEM;
 377 
 378                 slot->type = simple_strtoul(type, NULL, 10);
 379 
 380                 dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
 381                                 index, name, type);
 382 
 383                 retval = rpaphp_enable_slot(slot);
 384                 if (!retval)
 385                         retval = rpaphp_register_slot(slot);
 386 
 387                 if (retval)
 388                         dealloc_slot_struct(slot);
 389 
 390                 name += strlen(name) + 1;
 391                 type += strlen(type) + 1;
 392         }
 393         dbg("%s - Exit: rc[%d]\n", __func__, retval);
 394 
 395         /* XXX FIXME: reports a failure only if last entry in loop failed */
 396         return retval;
 397 }
 398 EXPORT_SYMBOL_GPL(rpaphp_add_slot);
 399 
 400 static void __exit cleanup_slots(void)
 401 {
 402         struct slot *slot, *next;
 403 
 404         /*
 405          * Unregister all of our slots with the pci_hotplug subsystem,
 406          * and free up all memory that we had allocated.
 407          */
 408 
 409         list_for_each_entry_safe(slot, next, &rpaphp_slot_head,
 410                                  rpaphp_slot_list) {
 411                 list_del(&slot->rpaphp_slot_list);
 412                 pci_hp_deregister(&slot->hotplug_slot);
 413                 dealloc_slot_struct(slot);
 414         }
 415 }
 416 
 417 static int __init rpaphp_init(void)
 418 {
 419         struct device_node *dn;
 420 
 421         info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
 422 
 423         for_each_node_by_name(dn, "pci")
 424                 rpaphp_add_slot(dn);
 425 
 426         return 0;
 427 }
 428 
 429 static void __exit rpaphp_exit(void)
 430 {
 431         cleanup_slots();
 432 }
 433 
 434 static int enable_slot(struct hotplug_slot *hotplug_slot)
 435 {
 436         struct slot *slot = to_slot(hotplug_slot);
 437         int state;
 438         int retval;
 439 
 440         if (slot->state == CONFIGURED)
 441                 return 0;
 442 
 443         retval = rpaphp_get_sensor_state(slot, &state);
 444         if (retval)
 445                 return retval;
 446 
 447         if (state == PRESENT) {
 448                 pci_lock_rescan_remove();
 449                 pci_hp_add_devices(slot->bus);
 450                 pci_unlock_rescan_remove();
 451                 slot->state = CONFIGURED;
 452         } else if (state == EMPTY) {
 453                 slot->state = EMPTY;
 454         } else {
 455                 err("%s: slot[%s] is in invalid state\n", __func__, slot->name);
 456                 slot->state = NOT_VALID;
 457                 return -EINVAL;
 458         }
 459 
 460         slot->bus->max_bus_speed = get_max_bus_speed(slot);
 461         return 0;
 462 }
 463 
 464 static int disable_slot(struct hotplug_slot *hotplug_slot)
 465 {
 466         struct slot *slot = to_slot(hotplug_slot);
 467         if (slot->state == NOT_CONFIGURED)
 468                 return -EINVAL;
 469 
 470         pci_lock_rescan_remove();
 471         pci_hp_remove_devices(slot->bus);
 472         pci_unlock_rescan_remove();
 473         vm_unmap_aliases();
 474 
 475         slot->state = NOT_CONFIGURED;
 476         return 0;
 477 }
 478 
 479 const struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
 480         .enable_slot = enable_slot,
 481         .disable_slot = disable_slot,
 482         .set_attention_status = set_attention_status,
 483         .get_power_status = get_power_status,
 484         .get_attention_status = get_attention_status,
 485         .get_adapter_status = get_adapter_status,
 486 };
 487 
 488 module_init(rpaphp_init);
 489 module_exit(rpaphp_exit);

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