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