1 /* 2 * PCI Express Hot Plug Controller Driver 3 * 4 * Copyright (C) 1995,2001 Compaq Computer Corporation 5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) 6 * Copyright (C) 2001 IBM Corp. 7 * Copyright (C) 2003-2004 Intel Corporation 8 * 9 * All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or (at 14 * your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 19 * NON INFRINGEMENT. See the GNU General Public License for more 20 * details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> 27 * 28 */ 29 30 #include <linux/module.h> 31 #include <linux/moduleparam.h> 32 #include <linux/kernel.h> 33 #include <linux/types.h> 34 #include <linux/pci.h> 35 #include "pciehp.h" 36 #include <linux/interrupt.h> 37 #include <linux/time.h> 38 39 /* Global variables */ 40 int pciehp_debug; 41 int pciehp_poll_mode; 42 int pciehp_poll_time; 43 int pciehp_force; 44 int pciehp_slot_with_bus; 45 struct workqueue_struct *pciehp_wq; 46 47 #define DRIVER_VERSION "0.4" 48 #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" 49 #define DRIVER_DESC "PCI Express Hot Plug Controller Driver" 50 51 MODULE_AUTHOR(DRIVER_AUTHOR); 52 MODULE_DESCRIPTION(DRIVER_DESC); 53 MODULE_LICENSE("GPL"); 54 55 module_param(pciehp_debug, bool, 0644); 56 module_param(pciehp_poll_mode, bool, 0644); 57 module_param(pciehp_poll_time, int, 0644); 58 module_param(pciehp_force, bool, 0644); 59 module_param(pciehp_slot_with_bus, bool, 0644); 60 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); 61 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); 62 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); 63 MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); 64 MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name"); 65 66 #define PCIE_MODULE_NAME "pciehp" 67 68 static int set_attention_status (struct hotplug_slot *slot, u8 value); 69 static int enable_slot (struct hotplug_slot *slot); 70 static int disable_slot (struct hotplug_slot *slot); 71 static int get_power_status (struct hotplug_slot *slot, u8 *value); 72 static int get_attention_status (struct hotplug_slot *slot, u8 *value); 73 static int get_latch_status (struct hotplug_slot *slot, u8 *value); 74 static int get_adapter_status (struct hotplug_slot *slot, u8 *value); 75 static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); 76 static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); 77 78 static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { 79 .owner = THIS_MODULE, 80 .set_attention_status = set_attention_status, 81 .enable_slot = enable_slot, 82 .disable_slot = disable_slot, 83 .get_power_status = get_power_status, 84 .get_attention_status = get_attention_status, 85 .get_latch_status = get_latch_status, 86 .get_adapter_status = get_adapter_status, 87 .get_max_bus_speed = get_max_bus_speed, 88 .get_cur_bus_speed = get_cur_bus_speed, 89 }; 90 91 /* 92 * Check the status of the Electro Mechanical Interlock (EMI) 93 */ 94 static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value) 95 { 96 struct slot *slot = hotplug_slot->private; 97 return (slot->hpc_ops->get_emi_status(slot, value)); 98 } 99 100 /* 101 * sysfs interface for the Electro Mechanical Interlock (EMI) 102 * 1 == locked, 0 == unlocked 103 */ 104 static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf) 105 { 106 int retval; 107 u8 value; 108 109 retval = get_lock_status(slot, &value); 110 if (retval) 111 goto lock_read_exit; 112 retval = sprintf (buf, "%d\n", value); 113 114 lock_read_exit: 115 return retval; 116 } 117 118 /* 119 * Change the status of the Electro Mechanical Interlock (EMI) 120 * This is a toggle - in addition there must be at least 1 second 121 * in between toggles. 122 */ 123 static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status) 124 { 125 struct slot *slot = hotplug_slot->private; 126 int retval; 127 u8 value; 128 129 mutex_lock(&slot->ctrl->crit_sect); 130 131 /* has it been >1 sec since our last toggle? */ 132 if ((get_seconds() - slot->last_emi_toggle) < 1) 133 return -EINVAL; 134 135 /* see what our current state is */ 136 retval = get_lock_status(hotplug_slot, &value); 137 if (retval || (value == status)) 138 goto set_lock_exit; 139 140 slot->hpc_ops->toggle_emi(slot); 141 set_lock_exit: 142 mutex_unlock(&slot->ctrl->crit_sect); 143 return 0; 144 } 145 146 /* 147 * sysfs interface which allows the user to toggle the Electro Mechanical 148 * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock 149 */ 150 static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf, 151 size_t count) 152 { 153 unsigned long llock; 154 u8 lock; 155 int retval = 0; 156 157 llock = simple_strtoul(buf, NULL, 10); 158 lock = (u8)(llock & 0xff); 159 160 switch (lock) { 161 case 0: 162 case 1: 163 retval = set_lock_status(slot, lock); 164 break; 165 default: 166 err ("%d is an invalid lock value\n", lock); 167 retval = -EINVAL; 168 } 169 if (retval) 170 return retval; 171 return count; 172 } 173 174 static struct hotplug_slot_attribute hotplug_slot_attr_lock = { 175 .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR}, 176 .show = lock_read_file, 177 .store = lock_write_file 178 }; 179 180 /** 181 * release_slot - free up the memory used by a slot 182 * @hotplug_slot: slot to free 183 */ 184 static void release_slot(struct hotplug_slot *hotplug_slot) 185 { 186 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 187 188 kfree(hotplug_slot->info); 189 kfree(hotplug_slot); 190 } 191 192 static int init_slots(struct controller *ctrl) 193 { 194 struct slot *slot; 195 struct hotplug_slot *hotplug_slot; 196 struct hotplug_slot_info *info; 197 int retval = -ENOMEM; 198 199 list_for_each_entry(slot, &ctrl->slot_list, slot_list) { 200 hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); 201 if (!hotplug_slot) 202 goto error; 203 204 info = kzalloc(sizeof(*info), GFP_KERNEL); 205 if (!info) 206 goto error_hpslot; 207 208 /* register this slot with the hotplug pci core */ 209 hotplug_slot->info = info; 210 hotplug_slot->name = slot->name; 211 hotplug_slot->private = slot; 212 hotplug_slot->release = &release_slot; 213 hotplug_slot->ops = &pciehp_hotplug_slot_ops; 214 get_power_status(hotplug_slot, &info->power_status); 215 get_attention_status(hotplug_slot, &info->attention_status); 216 get_latch_status(hotplug_slot, &info->latch_status); 217 get_adapter_status(hotplug_slot, &info->adapter_status); 218 slot->hotplug_slot = hotplug_slot; 219 220 dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " 221 "slot_device_offset=%x\n", slot->bus, slot->device, 222 slot->hp_slot, slot->number, ctrl->slot_device_offset); 223 retval = pci_hp_register(hotplug_slot, 224 ctrl->pci_dev->subordinate, 225 slot->device); 226 if (retval) { 227 err("pci_hp_register failed with error %d\n", retval); 228 if (retval == -EEXIST) 229 err("Failed to register slot because of name " 230 "collision. Try \'pciehp_slot_with_bus\' " 231 "module option.\n"); 232 goto error_info; 233 } 234 /* create additional sysfs entries */ 235 if (EMI(ctrl)) { 236 retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, 237 &hotplug_slot_attr_lock.attr); 238 if (retval) { 239 pci_hp_deregister(hotplug_slot); 240 err("cannot create additional sysfs entries\n"); 241 goto error_info; 242 } 243 } 244 } 245 246 return 0; 247 error_info: 248 kfree(info); 249 error_hpslot: 250 kfree(hotplug_slot); 251 error: 252 return retval; 253 } 254 255 static void cleanup_slots(struct controller *ctrl) 256 { 257 struct slot *slot; 258 259 list_for_each_entry(slot, &ctrl->slot_list, slot_list) { 260 if (EMI(ctrl)) 261 sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, 262 &hotplug_slot_attr_lock.attr); 263 pci_hp_deregister(slot->hotplug_slot); 264 } 265 } 266 267 /* 268 * set_attention_status - Turns the Amber LED for a slot on, off or blink 269 */ 270 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) 271 { 272 struct slot *slot = hotplug_slot->private; 273 274 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 275 276 hotplug_slot->info->attention_status = status; 277 278 if (ATTN_LED(slot->ctrl)) 279 slot->hpc_ops->set_attention_status(slot, status); 280 281 return 0; 282 } 283 284 285 static int enable_slot(struct hotplug_slot *hotplug_slot) 286 { 287 struct slot *slot = hotplug_slot->private; 288 289 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 290 291 return pciehp_sysfs_enable_slot(slot); 292 } 293 294 295 static int disable_slot(struct hotplug_slot *hotplug_slot) 296 { 297 struct slot *slot = hotplug_slot->private; 298 299 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 300 301 return pciehp_sysfs_disable_slot(slot); 302 } 303 304 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 305 { 306 struct slot *slot = hotplug_slot->private; 307 int retval; 308 309 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 310 311 retval = slot->hpc_ops->get_power_status(slot, value); 312 if (retval < 0) 313 *value = hotplug_slot->info->power_status; 314 315 return 0; 316 } 317 318 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) 319 { 320 struct slot *slot = hotplug_slot->private; 321 int retval; 322 323 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 324 325 retval = slot->hpc_ops->get_attention_status(slot, value); 326 if (retval < 0) 327 *value = hotplug_slot->info->attention_status; 328 329 return 0; 330 } 331 332 static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) 333 { 334 struct slot *slot = hotplug_slot->private; 335 int retval; 336 337 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 338 339 retval = slot->hpc_ops->get_latch_status(slot, value); 340 if (retval < 0) 341 *value = hotplug_slot->info->latch_status; 342 343 return 0; 344 } 345 346 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) 347 { 348 struct slot *slot = hotplug_slot->private; 349 int retval; 350 351 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 352 353 retval = slot->hpc_ops->get_adapter_status(slot, value); 354 if (retval < 0) 355 *value = hotplug_slot->info->adapter_status; 356 357 return 0; 358 } 359 360 static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, 361 enum pci_bus_speed *value) 362 { 363 struct slot *slot = hotplug_slot->private; 364 int retval; 365 366 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 367 368 retval = slot->hpc_ops->get_max_bus_speed(slot, value); 369 if (retval < 0) 370 *value = PCI_SPEED_UNKNOWN; 371 372 return 0; 373 } 374 375 static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) 376 { 377 struct slot *slot = hotplug_slot->private; 378 int retval; 379 380 dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); 381 382 retval = slot->hpc_ops->get_cur_bus_speed(slot, value); 383 if (retval < 0) 384 *value = PCI_SPEED_UNKNOWN; 385 386 return 0; 387 } 388 389 static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id) 390 { 391 int rc; 392 struct controller *ctrl; 393 struct slot *t_slot; 394 u8 value; 395 struct pci_dev *pdev = dev->port; 396 397 if (pciehp_force) 398 dbg("Bypassing BIOS check for pciehp use on %s\n", 399 pci_name(pdev)); 400 else if (pciehp_get_hp_hw_control_from_firmware(pdev)) 401 goto err_out_none; 402 403 ctrl = pcie_init(dev); 404 if (!ctrl) { 405 dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); 406 goto err_out_none; 407 } 408 set_service_data(dev, ctrl); 409 410 /* Setup the slot information structures */ 411 rc = init_slots(ctrl); 412 if (rc) { 413 if (rc == -EBUSY) 414 warn("%s: slot already registered by another " 415 "hotplug driver\n", PCIE_MODULE_NAME); 416 else 417 err("%s: slot initialization failed\n", 418 PCIE_MODULE_NAME); 419 goto err_out_release_ctlr; 420 } 421 422 t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); 423 424 t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ 425 if (value && pciehp_force) { 426 rc = pciehp_enable_slot(t_slot); 427 if (rc) /* -ENODEV: shouldn't happen, but deal with it */ 428 value = 0; 429 } 430 if ((POWER_CTRL(ctrl)) && !value) { 431 rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ 432 if (rc) 433 goto err_out_free_ctrl_slot; 434 } 435 436 return 0; 437 438 err_out_free_ctrl_slot: 439 cleanup_slots(ctrl); 440 err_out_release_ctlr: 441 ctrl->hpc_ops->release_ctlr(ctrl); 442 err_out_none: 443 return -ENODEV; 444 } 445 446 static void pciehp_remove (struct pcie_device *dev) 447 { 448 struct controller *ctrl = get_service_data(dev); 449 450 cleanup_slots(ctrl); 451 ctrl->hpc_ops->release_ctlr(ctrl); 452 } 453 454 #ifdef CONFIG_PM 455 static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) 456 { 457 printk("%s ENTRY\n", __func__); 458 return 0; 459 } 460 461 static int pciehp_resume (struct pcie_device *dev) 462 { 463 printk("%s ENTRY\n", __func__); 464 if (pciehp_force) { 465 struct controller *ctrl = get_service_data(dev); 466 struct slot *t_slot; 467 u8 status; 468 469 /* reinitialize the chipset's event detection logic */ 470 pcie_enable_notification(ctrl); 471 472 t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); 473 474 /* Check if slot is occupied */ 475 t_slot->hpc_ops->get_adapter_status(t_slot, &status); 476 if (status) 477 pciehp_enable_slot(t_slot); 478 else 479 pciehp_disable_slot(t_slot); 480 } 481 return 0; 482 } 483 #endif 484 485 static struct pcie_port_service_id port_pci_ids[] = { { 486 .vendor = PCI_ANY_ID, 487 .device = PCI_ANY_ID, 488 .port_type = PCIE_ANY_PORT, 489 .service_type = PCIE_PORT_SERVICE_HP, 490 .driver_data = 0, 491 }, { /* end: all zeroes */ } 492 }; 493 static const char device_name[] = "hpdriver"; 494 495 static struct pcie_port_service_driver hpdriver_portdrv = { 496 .name = (char *)device_name, 497 .id_table = &port_pci_ids[0], 498 499 .probe = pciehp_probe, 500 .remove = pciehp_remove, 501 502 #ifdef CONFIG_PM 503 .suspend = pciehp_suspend, 504 .resume = pciehp_resume, 505 #endif /* PM */ 506 }; 507 508 static int __init pcied_init(void) 509 { 510 int retval = 0; 511 512 retval = pcie_port_service_register(&hpdriver_portdrv); 513 dbg("pcie_port_service_register = %d\n", retval); 514 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 515 if (retval) 516 dbg("%s: Failure to register service\n", __func__); 517 return retval; 518 } 519 520 static void __exit pcied_cleanup(void) 521 { 522 dbg("unload_pciehpd()\n"); 523 pcie_port_service_unregister(&hpdriver_portdrv); 524 info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); 525 } 526 527 module_init(pcied_init); 528 module_exit(pcied_cleanup); 529