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