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/kernel.h> 32#include <linux/types.h> 33#include <linux/slab.h> 34#include <linux/pci.h> 35#include <linux/workqueue.h> 36#include "../pci.h" 37#include "pciehp.h" 38 39static void interrupt_event_handler(struct work_struct *work); 40 41static int queue_interrupt_event(struct slot *p_slot, u32 event_type) 42{ 43 struct event_info *info; 44 45 info = kmalloc(sizeof(*info), GFP_ATOMIC); 46 if (!info) 47 return -ENOMEM; 48 49 info->event_type = event_type; 50 info->p_slot = p_slot; 51 INIT_WORK(&info->work, interrupt_event_handler); 52 53 schedule_work(&info->work); 54 55 return 0; 56} 57 58u8 pciehp_handle_attention_button(struct slot *p_slot) 59{ 60 u32 event_type; 61 struct controller *ctrl = p_slot->ctrl; 62 63 /* Attention Button Change */ 64 ctrl_dbg(ctrl, "Attention button interrupt received\n"); 65 66 /* 67 * Button pressed - See if need to TAKE ACTION!!! 68 */ 69 ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot)); 70 event_type = INT_BUTTON_PRESS; 71 72 queue_interrupt_event(p_slot, event_type); 73 74 return 0; 75} 76 77u8 pciehp_handle_switch_change(struct slot *p_slot) 78{ 79 u8 getstatus; 80 u32 event_type; 81 struct controller *ctrl = p_slot->ctrl; 82 83 /* Switch Change */ 84 ctrl_dbg(ctrl, "Switch interrupt received\n"); 85 86 pciehp_get_latch_status(p_slot, &getstatus); 87 if (getstatus) { 88 /* 89 * Switch opened 90 */ 91 ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot)); 92 event_type = INT_SWITCH_OPEN; 93 } else { 94 /* 95 * Switch closed 96 */ 97 ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot)); 98 event_type = INT_SWITCH_CLOSE; 99 } 100 101 queue_interrupt_event(p_slot, event_type); 102 103 return 1; 104} 105 106u8 pciehp_handle_presence_change(struct slot *p_slot) 107{ 108 u32 event_type; 109 u8 presence_save; 110 struct controller *ctrl = p_slot->ctrl; 111 112 /* Presence Change */ 113 ctrl_dbg(ctrl, "Presence/Notify input change\n"); 114 115 /* Switch is open, assume a presence change 116 * Save the presence state 117 */ 118 pciehp_get_adapter_status(p_slot, &presence_save); 119 if (presence_save) { 120 /* 121 * Card Present 122 */ 123 ctrl_info(ctrl, "Card present on Slot(%s)\n", slot_name(p_slot)); 124 event_type = INT_PRESENCE_ON; 125 } else { 126 /* 127 * Not Present 128 */ 129 ctrl_info(ctrl, "Card not present on Slot(%s)\n", 130 slot_name(p_slot)); 131 event_type = INT_PRESENCE_OFF; 132 } 133 134 queue_interrupt_event(p_slot, event_type); 135 136 return 1; 137} 138 139u8 pciehp_handle_power_fault(struct slot *p_slot) 140{ 141 u32 event_type; 142 struct controller *ctrl = p_slot->ctrl; 143 144 /* power fault */ 145 ctrl_dbg(ctrl, "Power fault interrupt received\n"); 146 ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); 147 event_type = INT_POWER_FAULT; 148 ctrl_info(ctrl, "Power fault bit %x set\n", 0); 149 queue_interrupt_event(p_slot, event_type); 150 151 return 1; 152} 153 154/* The following routines constitute the bulk of the 155 hotplug controller logic 156 */ 157 158static void set_slot_off(struct controller *ctrl, struct slot * pslot) 159{ 160 /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ 161 if (POWER_CTRL(ctrl)) { 162 if (pciehp_power_off_slot(pslot)) { 163 ctrl_err(ctrl, 164 "Issue of Slot Power Off command failed\n"); 165 return; 166 } 167 /* 168 * After turning power off, we must wait for at least 1 second 169 * before taking any action that relies on power having been 170 * removed from the slot/adapter. 171 */ 172 msleep(1000); 173 } 174 175 if (PWR_LED(ctrl)) 176 pciehp_green_led_off(pslot); 177 178 if (ATTN_LED(ctrl)) { 179 if (pciehp_set_attention_status(pslot, 1)) { 180 ctrl_err(ctrl, 181 "Issue of Set Attention Led command failed\n"); 182 return; 183 } 184 } 185} 186 187/** 188 * board_added - Called after a board has been added to the system. 189 * @p_slot: &slot where board is added 190 * 191 * Turns power on for the board. 192 * Configures board. 193 */ 194static int board_added(struct slot *p_slot) 195{ 196 int retval = 0; 197 struct controller *ctrl = p_slot->ctrl; 198 struct pci_bus *parent = ctrl->pcie->port->subordinate; 199 200 if (POWER_CTRL(ctrl)) { 201 /* Power on slot */ 202 retval = pciehp_power_on_slot(p_slot); 203 if (retval) 204 return retval; 205 } 206 207 if (PWR_LED(ctrl)) 208 pciehp_green_led_blink(p_slot); 209 210 /* Check link training status */ 211 retval = pciehp_check_link_status(ctrl); 212 if (retval) { 213 ctrl_err(ctrl, "Failed to check link status\n"); 214 goto err_exit; 215 } 216 217 /* Check for a power fault */ 218 if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { 219 ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); 220 retval = -EIO; 221 goto err_exit; 222 } 223 224 retval = pciehp_configure_device(p_slot); 225 if (retval) { 226 ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", 227 pci_domain_nr(parent), parent->number); 228 goto err_exit; 229 } 230 231 if (PWR_LED(ctrl)) 232 pciehp_green_led_on(p_slot); 233 234 return 0; 235 236err_exit: 237 set_slot_off(ctrl, p_slot); 238 return retval; 239} 240 241/** 242 * remove_board - Turns off slot and LEDs 243 * @p_slot: slot where board is being removed 244 */ 245static int remove_board(struct slot *p_slot) 246{ 247 int retval = 0; 248 struct controller *ctrl = p_slot->ctrl; 249 250 retval = pciehp_unconfigure_device(p_slot); 251 if (retval) 252 return retval; 253 254 if (POWER_CTRL(ctrl)) { 255 /* power off slot */ 256 retval = pciehp_power_off_slot(p_slot); 257 if (retval) { 258 ctrl_err(ctrl, 259 "Issue of Slot Disable command failed\n"); 260 return retval; 261 } 262 /* 263 * After turning power off, we must wait for at least 1 second 264 * before taking any action that relies on power having been 265 * removed from the slot/adapter. 266 */ 267 msleep(1000); 268 } 269 270 /* turn off Green LED */ 271 if (PWR_LED(ctrl)) 272 pciehp_green_led_off(p_slot); 273 274 return 0; 275} 276 277struct power_work_info { 278 struct slot *p_slot; 279 struct work_struct work; 280}; 281 282/** 283 * pciehp_power_thread - handle pushbutton events 284 * @work: &struct work_struct describing work to be done 285 * 286 * Scheduled procedure to handle blocking stuff for the pushbuttons. 287 * Handles all pending events and exits. 288 */ 289static void pciehp_power_thread(struct work_struct *work) 290{ 291 struct power_work_info *info = 292 container_of(work, struct power_work_info, work); 293 struct slot *p_slot = info->p_slot; 294 295 mutex_lock(&p_slot->lock); 296 switch (p_slot->state) { 297 case POWEROFF_STATE: 298 mutex_unlock(&p_slot->lock); 299 ctrl_dbg(p_slot->ctrl, 300 "Disabling domain:bus:device=%04x:%02x:00\n", 301 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), 302 p_slot->ctrl->pcie->port->subordinate->number); 303 pciehp_disable_slot(p_slot); 304 mutex_lock(&p_slot->lock); 305 p_slot->state = STATIC_STATE; 306 break; 307 case POWERON_STATE: 308 mutex_unlock(&p_slot->lock); 309 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl)) 310 pciehp_green_led_off(p_slot); 311 mutex_lock(&p_slot->lock); 312 p_slot->state = STATIC_STATE; 313 break; 314 default: 315 break; 316 } 317 mutex_unlock(&p_slot->lock); 318 319 kfree(info); 320} 321 322void pciehp_queue_pushbutton_work(struct work_struct *work) 323{ 324 struct slot *p_slot = container_of(work, struct slot, work.work); 325 struct power_work_info *info; 326 327 info = kmalloc(sizeof(*info), GFP_KERNEL); 328 if (!info) { 329 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 330 __func__); 331 return; 332 } 333 info->p_slot = p_slot; 334 INIT_WORK(&info->work, pciehp_power_thread); 335 336 mutex_lock(&p_slot->lock); 337 switch (p_slot->state) { 338 case BLINKINGOFF_STATE: 339 p_slot->state = POWEROFF_STATE; 340 break; 341 case BLINKINGON_STATE: 342 p_slot->state = POWERON_STATE; 343 break; 344 default: 345 kfree(info); 346 goto out; 347 } 348 queue_work(pciehp_wq, &info->work); 349 out: 350 mutex_unlock(&p_slot->lock); 351} 352 353/* 354 * Note: This function must be called with slot->lock held 355 */ 356static void handle_button_press_event(struct slot *p_slot) 357{ 358 struct controller *ctrl = p_slot->ctrl; 359 u8 getstatus; 360 361 switch (p_slot->state) { 362 case STATIC_STATE: 363 pciehp_get_power_status(p_slot, &getstatus); 364 if (getstatus) { 365 p_slot->state = BLINKINGOFF_STATE; 366 ctrl_info(ctrl, 367 "PCI slot #%s - powering off due to button " 368 "press.\n", slot_name(p_slot)); 369 } else { 370 p_slot->state = BLINKINGON_STATE; 371 ctrl_info(ctrl, 372 "PCI slot #%s - powering on due to button " 373 "press.\n", slot_name(p_slot)); 374 } 375 /* blink green LED and turn off amber */ 376 if (PWR_LED(ctrl)) 377 pciehp_green_led_blink(p_slot); 378 if (ATTN_LED(ctrl)) 379 pciehp_set_attention_status(p_slot, 0); 380 381 schedule_delayed_work(&p_slot->work, 5*HZ); 382 break; 383 case BLINKINGOFF_STATE: 384 case BLINKINGON_STATE: 385 /* 386 * Cancel if we are still blinking; this means that we 387 * press the attention again before the 5 sec. limit 388 * expires to cancel hot-add or hot-remove 389 */ 390 ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); 391 cancel_delayed_work(&p_slot->work); 392 if (p_slot->state == BLINKINGOFF_STATE) { 393 if (PWR_LED(ctrl)) 394 pciehp_green_led_on(p_slot); 395 } else { 396 if (PWR_LED(ctrl)) 397 pciehp_green_led_off(p_slot); 398 } 399 if (ATTN_LED(ctrl)) 400 pciehp_set_attention_status(p_slot, 0); 401 ctrl_info(ctrl, "PCI slot #%s - action canceled " 402 "due to button press\n", slot_name(p_slot)); 403 p_slot->state = STATIC_STATE; 404 break; 405 case POWEROFF_STATE: 406 case POWERON_STATE: 407 /* 408 * Ignore if the slot is on power-on or power-off state; 409 * this means that the previous attention button action 410 * to hot-add or hot-remove is undergoing 411 */ 412 ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); 413 break; 414 default: 415 ctrl_warn(ctrl, "Not a valid state\n"); 416 break; 417 } 418} 419 420/* 421 * Note: This function must be called with slot->lock held 422 */ 423static void handle_surprise_event(struct slot *p_slot) 424{ 425 u8 getstatus; 426 struct power_work_info *info; 427 428 info = kmalloc(sizeof(*info), GFP_KERNEL); 429 if (!info) { 430 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 431 __func__); 432 return; 433 } 434 info->p_slot = p_slot; 435 INIT_WORK(&info->work, pciehp_power_thread); 436 437 pciehp_get_adapter_status(p_slot, &getstatus); 438 if (!getstatus) 439 p_slot->state = POWEROFF_STATE; 440 else 441 p_slot->state = POWERON_STATE; 442 443 queue_work(pciehp_wq, &info->work); 444} 445 446static void interrupt_event_handler(struct work_struct *work) 447{ 448 struct event_info *info = container_of(work, struct event_info, work); 449 struct slot *p_slot = info->p_slot; 450 struct controller *ctrl = p_slot->ctrl; 451 452 mutex_lock(&p_slot->lock); 453 switch (info->event_type) { 454 case INT_BUTTON_PRESS: 455 handle_button_press_event(p_slot); 456 break; 457 case INT_POWER_FAULT: 458 if (!POWER_CTRL(ctrl)) 459 break; 460 if (ATTN_LED(ctrl)) 461 pciehp_set_attention_status(p_slot, 1); 462 if (PWR_LED(ctrl)) 463 pciehp_green_led_off(p_slot); 464 break; 465 case INT_PRESENCE_ON: 466 case INT_PRESENCE_OFF: 467 if (!HP_SUPR_RM(ctrl)) 468 break; 469 ctrl_dbg(ctrl, "Surprise Removal\n"); 470 handle_surprise_event(p_slot); 471 break; 472 default: 473 break; 474 } 475 mutex_unlock(&p_slot->lock); 476 477 kfree(info); 478} 479 480int pciehp_enable_slot(struct slot *p_slot) 481{ 482 u8 getstatus = 0; 483 int rc; 484 struct controller *ctrl = p_slot->ctrl; 485 486 rc = pciehp_get_adapter_status(p_slot, &getstatus); 487 if (rc || !getstatus) { 488 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 489 return -ENODEV; 490 } 491 if (MRL_SENS(p_slot->ctrl)) { 492 rc = pciehp_get_latch_status(p_slot, &getstatus); 493 if (rc || getstatus) { 494 ctrl_info(ctrl, "Latch open on slot(%s)\n", 495 slot_name(p_slot)); 496 return -ENODEV; 497 } 498 } 499 500 if (POWER_CTRL(p_slot->ctrl)) { 501 rc = pciehp_get_power_status(p_slot, &getstatus); 502 if (rc || getstatus) { 503 ctrl_info(ctrl, "Already enabled on slot(%s)\n", 504 slot_name(p_slot)); 505 return -EINVAL; 506 } 507 } 508 509 pciehp_get_latch_status(p_slot, &getstatus); 510 511 rc = board_added(p_slot); 512 if (rc) { 513 pciehp_get_latch_status(p_slot, &getstatus); 514 } 515 return rc; 516} 517 518 519int pciehp_disable_slot(struct slot *p_slot) 520{ 521 u8 getstatus = 0; 522 int ret = 0; 523 struct controller *ctrl = p_slot->ctrl; 524 525 if (!p_slot->ctrl) 526 return 1; 527 528 if (!HP_SUPR_RM(p_slot->ctrl)) { 529 ret = pciehp_get_adapter_status(p_slot, &getstatus); 530 if (ret || !getstatus) { 531 ctrl_info(ctrl, "No adapter on slot(%s)\n", 532 slot_name(p_slot)); 533 return -ENODEV; 534 } 535 } 536 537 if (MRL_SENS(p_slot->ctrl)) { 538 ret = pciehp_get_latch_status(p_slot, &getstatus); 539 if (ret || getstatus) { 540 ctrl_info(ctrl, "Latch open on slot(%s)\n", 541 slot_name(p_slot)); 542 return -ENODEV; 543 } 544 } 545 546 if (POWER_CTRL(p_slot->ctrl)) { 547 ret = pciehp_get_power_status(p_slot, &getstatus); 548 if (ret || !getstatus) { 549 ctrl_info(ctrl, "Already disabled on slot(%s)\n", 550 slot_name(p_slot)); 551 return -EINVAL; 552 } 553 } 554 555 return remove_board(p_slot); 556} 557 558int pciehp_sysfs_enable_slot(struct slot *p_slot) 559{ 560 int retval = -ENODEV; 561 struct controller *ctrl = p_slot->ctrl; 562 563 mutex_lock(&p_slot->lock); 564 switch (p_slot->state) { 565 case BLINKINGON_STATE: 566 cancel_delayed_work(&p_slot->work); 567 case STATIC_STATE: 568 p_slot->state = POWERON_STATE; 569 mutex_unlock(&p_slot->lock); 570 retval = pciehp_enable_slot(p_slot); 571 mutex_lock(&p_slot->lock); 572 p_slot->state = STATIC_STATE; 573 break; 574 case POWERON_STATE: 575 ctrl_info(ctrl, "Slot %s is already in powering on state\n", 576 slot_name(p_slot)); 577 break; 578 case BLINKINGOFF_STATE: 579 case POWEROFF_STATE: 580 ctrl_info(ctrl, "Already enabled on slot %s\n", 581 slot_name(p_slot)); 582 break; 583 default: 584 ctrl_err(ctrl, "Not a valid state on slot %s\n", 585 slot_name(p_slot)); 586 break; 587 } 588 mutex_unlock(&p_slot->lock); 589 590 return retval; 591} 592 593int pciehp_sysfs_disable_slot(struct slot *p_slot) 594{ 595 int retval = -ENODEV; 596 struct controller *ctrl = p_slot->ctrl; 597 598 mutex_lock(&p_slot->lock); 599 switch (p_slot->state) { 600 case BLINKINGOFF_STATE: 601 cancel_delayed_work(&p_slot->work); 602 case STATIC_STATE: 603 p_slot->state = POWEROFF_STATE; 604 mutex_unlock(&p_slot->lock); 605 retval = pciehp_disable_slot(p_slot); 606 mutex_lock(&p_slot->lock); 607 p_slot->state = STATIC_STATE; 608 break; 609 case POWEROFF_STATE: 610 ctrl_info(ctrl, "Slot %s is already in powering off state\n", 611 slot_name(p_slot)); 612 break; 613 case BLINKINGON_STATE: 614 case POWERON_STATE: 615 ctrl_info(ctrl, "Already disabled on slot %s\n", 616 slot_name(p_slot)); 617 break; 618 default: 619 ctrl_err(ctrl, "Not a valid state on slot %s\n", 620 slot_name(p_slot)); 621 break; 622 } 623 mutex_unlock(&p_slot->lock); 624 625 return retval; 626} 627