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