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