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