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/smp_lock.h> 34 #include <linux/pci.h> 35 #include "../pci.h" 36 #include "pciehp.h" 37 38 static void interrupt_event_handler(struct controller *ctrl); 39 40 static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ 41 static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ 42 static int event_finished; 43 static unsigned long pushbutton_pending; /* = 0 */ 44 static unsigned long surprise_rm_pending; /* = 0 */ 45 46 static inline char *slot_name(struct slot *p_slot) 47 { 48 return p_slot->hotplug_slot->name; 49 } 50 51 u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) 52 { 53 struct controller *ctrl = (struct controller *) inst_id; 54 struct slot *p_slot; 55 u8 rc = 0; 56 u8 getstatus; 57 struct event_info *taskInfo; 58 59 /* Attention Button Change */ 60 dbg("pciehp: Attention button interrupt received.\n"); 61 62 /* This is the structure that tells the worker thread what to do */ 63 taskInfo = &(ctrl->event_queue[ctrl->next_event]); 64 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 65 66 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 67 68 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; 69 taskInfo->hp_slot = hp_slot; 70 71 rc++; 72 73 /* 74 * Button pressed - See if need to TAKE ACTION!!! 75 */ 76 info("Button pressed on Slot(%s)\n", slot_name(p_slot)); 77 taskInfo->event_type = INT_BUTTON_PRESS; 78 79 if ((p_slot->state == BLINKINGON_STATE) 80 || (p_slot->state == BLINKINGOFF_STATE)) { 81 /* Cancel if we are still blinking; this means that we press the 82 * attention again before the 5 sec. limit expires to cancel hot-add 83 * or hot-remove 84 */ 85 taskInfo->event_type = INT_BUTTON_CANCEL; 86 info("Button cancel on Slot(%s)\n", slot_name(p_slot)); 87 } else if ((p_slot->state == POWERON_STATE) 88 || (p_slot->state == POWEROFF_STATE)) { 89 /* Ignore if the slot is on power-on or power-off state; this 90 * means that the previous attention button action to hot-add or 91 * hot-remove is undergoing 92 */ 93 taskInfo->event_type = INT_BUTTON_IGNORE; 94 info("Button ignore on Slot(%s)\n", slot_name(p_slot)); 95 } 96 97 if (rc) 98 up(&event_semaphore); /* signal event thread that new event is posted */ 99 100 return 0; 101 102 } 103 104 u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) 105 { 106 struct controller *ctrl = (struct controller *) inst_id; 107 struct slot *p_slot; 108 u8 rc = 0; 109 u8 getstatus; 110 struct event_info *taskInfo; 111 112 /* Switch Change */ 113 dbg("pciehp: Switch interrupt received.\n"); 114 115 /* This is the structure that tells the worker thread 116 * what to do 117 */ 118 taskInfo = &(ctrl->event_queue[ctrl->next_event]); 119 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; 120 taskInfo->hp_slot = hp_slot; 121 122 rc++; 123 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 124 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 125 126 if (getstatus) { 127 /* 128 * Switch opened 129 */ 130 info("Latch open on Slot(%s)\n", slot_name(p_slot)); 131 taskInfo->event_type = INT_SWITCH_OPEN; 132 } else { 133 /* 134 * Switch closed 135 */ 136 info("Latch close on Slot(%s)\n", slot_name(p_slot)); 137 taskInfo->event_type = INT_SWITCH_CLOSE; 138 } 139 140 if (rc) 141 up(&event_semaphore); /* signal event thread that new event is posted */ 142 143 return rc; 144 } 145 146 u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) 147 { 148 struct controller *ctrl = (struct controller *) inst_id; 149 struct slot *p_slot; 150 u8 presence_save, rc = 0; 151 struct event_info *taskInfo; 152 153 /* Presence Change */ 154 dbg("pciehp: Presence/Notify input change.\n"); 155 156 /* This is the structure that tells the worker thread 157 * what to do 158 */ 159 taskInfo = &(ctrl->event_queue[ctrl->next_event]); 160 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; 161 taskInfo->hp_slot = hp_slot; 162 163 rc++; 164 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 165 166 /* Switch is open, assume a presence change 167 * Save the presence state 168 */ 169 p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save); 170 if (presence_save) { 171 /* 172 * Card Present 173 */ 174 info("Card present on Slot(%s)\n", slot_name(p_slot)); 175 taskInfo->event_type = INT_PRESENCE_ON; 176 } else { 177 /* 178 * Not Present 179 */ 180 info("Card not present on Slot(%s)\n", slot_name(p_slot)); 181 taskInfo->event_type = INT_PRESENCE_OFF; 182 } 183 184 if (rc) 185 up(&event_semaphore); /* signal event thread that new event is posted */ 186 187 return rc; 188 } 189 190 u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) 191 { 192 struct controller *ctrl = (struct controller *) inst_id; 193 struct slot *p_slot; 194 u8 rc = 0; 195 struct event_info *taskInfo; 196 197 /* power fault */ 198 dbg("pciehp: Power fault interrupt received.\n"); 199 200 /* this is the structure that tells the worker thread 201 * what to do 202 */ 203 taskInfo = &(ctrl->event_queue[ctrl->next_event]); 204 ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; 205 taskInfo->hp_slot = hp_slot; 206 207 rc++; 208 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 209 210 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { 211 /* 212 * power fault Cleared 213 */ 214 info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); 215 taskInfo->event_type = INT_POWER_FAULT_CLEAR; 216 } else { 217 /* 218 * power fault 219 */ 220 info("Power fault on Slot(%s)\n", slot_name(p_slot)); 221 taskInfo->event_type = INT_POWER_FAULT; 222 info("power fault bit %x set\n", hp_slot); 223 } 224 if (rc) 225 up(&event_semaphore); /* signal event thread that new event is posted */ 226 227 return rc; 228 } 229 230 /* The following routines constitute the bulk of the 231 hotplug controller logic 232 */ 233 234 static void set_slot_off(struct controller *ctrl, struct slot * pslot) 235 { 236 /* Wait for exclusive access to hardware */ 237 mutex_lock(&ctrl->ctrl_lock); 238 239 /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ 240 if (POWER_CTRL(ctrl->ctrlcap)) { 241 if (pslot->hpc_ops->power_off_slot(pslot)) { 242 err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); 243 mutex_unlock(&ctrl->ctrl_lock); 244 return; 245 } 246 wait_for_ctrl_irq (ctrl); 247 } 248 249 if (PWR_LED(ctrl->ctrlcap)) { 250 pslot->hpc_ops->green_led_off(pslot); 251 wait_for_ctrl_irq (ctrl); 252 } 253 254 if (ATTN_LED(ctrl->ctrlcap)) { 255 if (pslot->hpc_ops->set_attention_status(pslot, 1)) { 256 err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); 257 mutex_unlock(&ctrl->ctrl_lock); 258 return; 259 } 260 wait_for_ctrl_irq (ctrl); 261 } 262 263 /* Done with exclusive hardware access */ 264 mutex_unlock(&ctrl->ctrl_lock); 265 } 266 267 /** 268 * board_added - Called after a board has been added to the system. 269 * 270 * Turns power on for the board 271 * Configures board 272 * 273 */ 274 static int board_added(struct slot *p_slot) 275 { 276 u8 hp_slot; 277 int rc = 0; 278 struct controller *ctrl = p_slot->ctrl; 279 280 hp_slot = p_slot->device - ctrl->slot_device_offset; 281 282 dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n", 283 __FUNCTION__, p_slot->device, 284 ctrl->slot_device_offset, hp_slot); 285 286 /* Wait for exclusive access to hardware */ 287 mutex_lock(&ctrl->ctrl_lock); 288 289 if (POWER_CTRL(ctrl->ctrlcap)) { 290 /* Power on slot */ 291 rc = p_slot->hpc_ops->power_on_slot(p_slot); 292 if (rc) { 293 mutex_unlock(&ctrl->ctrl_lock); 294 return -1; 295 } 296 297 /* Wait for the command to complete */ 298 wait_for_ctrl_irq (ctrl); 299 } 300 301 if (PWR_LED(ctrl->ctrlcap)) { 302 p_slot->hpc_ops->green_led_blink(p_slot); 303 304 /* Wait for the command to complete */ 305 wait_for_ctrl_irq (ctrl); 306 } 307 308 /* Done with exclusive hardware access */ 309 mutex_unlock(&ctrl->ctrl_lock); 310 311 /* Wait for ~1 second */ 312 wait_for_ctrl_irq (ctrl); 313 314 /* Check link training status */ 315 rc = p_slot->hpc_ops->check_lnk_status(ctrl); 316 if (rc) { 317 err("%s: Failed to check link status\n", __FUNCTION__); 318 set_slot_off(ctrl, p_slot); 319 return rc; 320 } 321 322 /* Check for a power fault */ 323 if (p_slot->hpc_ops->query_power_fault(p_slot)) { 324 dbg("%s: power fault detected\n", __FUNCTION__); 325 rc = POWER_FAILURE; 326 goto err_exit; 327 } 328 329 rc = pciehp_configure_device(p_slot); 330 if (rc) { 331 err("Cannot add device 0x%x:%x\n", p_slot->bus, 332 p_slot->device); 333 goto err_exit; 334 } 335 336 /* 337 * Some PCI Express root ports require fixup after hot-plug operation. 338 */ 339 if (pcie_mch_quirk) 340 pci_fixup_device(pci_fixup_final, ctrl->pci_dev); 341 if (PWR_LED(ctrl->ctrlcap)) { 342 /* Wait for exclusive access to hardware */ 343 mutex_lock(&ctrl->ctrl_lock); 344 345 p_slot->hpc_ops->green_led_on(p_slot); 346 347 /* Wait for the command to complete */ 348 wait_for_ctrl_irq (ctrl); 349 350 /* Done with exclusive hardware access */ 351 mutex_unlock(&ctrl->ctrl_lock); 352 } 353 return 0; 354 355 err_exit: 356 set_slot_off(ctrl, p_slot); 357 return -1; 358 } 359 360 361 /** 362 * remove_board - Turns off slot and LED's 363 * 364 */ 365 static int remove_board(struct slot *p_slot) 366 { 367 u8 device; 368 u8 hp_slot; 369 int rc; 370 struct controller *ctrl = p_slot->ctrl; 371 372 if (pciehp_unconfigure_device(p_slot)) 373 return 1; 374 375 device = p_slot->device; 376 377 hp_slot = p_slot->device - ctrl->slot_device_offset; 378 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 379 380 dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); 381 382 /* Wait for exclusive access to hardware */ 383 mutex_lock(&ctrl->ctrl_lock); 384 385 if (POWER_CTRL(ctrl->ctrlcap)) { 386 /* power off slot */ 387 rc = p_slot->hpc_ops->power_off_slot(p_slot); 388 if (rc) { 389 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); 390 mutex_unlock(&ctrl->ctrl_lock); 391 return rc; 392 } 393 /* Wait for the command to complete */ 394 wait_for_ctrl_irq (ctrl); 395 } 396 397 if (PWR_LED(ctrl->ctrlcap)) { 398 /* turn off Green LED */ 399 p_slot->hpc_ops->green_led_off(p_slot); 400 401 /* Wait for the command to complete */ 402 wait_for_ctrl_irq (ctrl); 403 } 404 405 /* Done with exclusive hardware access */ 406 mutex_unlock(&ctrl->ctrl_lock); 407 408 return 0; 409 } 410 411 412 static void pushbutton_helper_thread(unsigned long data) 413 { 414 pushbutton_pending = data; 415 416 up(&event_semaphore); 417 } 418 419 /** 420 * pciehp_pushbutton_thread 421 * 422 * Scheduled procedure to handle blocking stuff for the pushbuttons 423 * Handles all pending events and exits. 424 * 425 */ 426 static void pciehp_pushbutton_thread(unsigned long slot) 427 { 428 struct slot *p_slot = (struct slot *) slot; 429 u8 getstatus; 430 431 pushbutton_pending = 0; 432 433 if (!p_slot) { 434 dbg("%s: Error! slot NULL\n", __FUNCTION__); 435 return; 436 } 437 438 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 439 if (getstatus) { 440 p_slot->state = POWEROFF_STATE; 441 dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__, 442 p_slot->bus, p_slot->device); 443 444 pciehp_disable_slot(p_slot); 445 p_slot->state = STATIC_STATE; 446 } else { 447 p_slot->state = POWERON_STATE; 448 dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, 449 p_slot->bus, p_slot->device); 450 451 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { 452 /* Wait for exclusive access to hardware */ 453 mutex_lock(&p_slot->ctrl->ctrl_lock); 454 455 p_slot->hpc_ops->green_led_off(p_slot); 456 457 /* Wait for the command to complete */ 458 wait_for_ctrl_irq (p_slot->ctrl); 459 460 /* Done with exclusive hardware access */ 461 mutex_unlock(&p_slot->ctrl->ctrl_lock); 462 } 463 p_slot->state = STATIC_STATE; 464 } 465 466 return; 467 } 468 469 /** 470 * pciehp_surprise_rm_thread 471 * 472 * Scheduled procedure to handle blocking stuff for the surprise removal 473 * Handles all pending events and exits. 474 * 475 */ 476 static void pciehp_surprise_rm_thread(unsigned long slot) 477 { 478 struct slot *p_slot = (struct slot *) slot; 479 u8 getstatus; 480 481 surprise_rm_pending = 0; 482 483 if (!p_slot) { 484 dbg("%s: Error! slot NULL\n", __FUNCTION__); 485 return; 486 } 487 488 p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 489 if (!getstatus) { 490 p_slot->state = POWEROFF_STATE; 491 dbg("%s: removing bus:device(%x:%x)\n", 492 __FUNCTION__, p_slot->bus, p_slot->device); 493 494 pciehp_disable_slot(p_slot); 495 p_slot->state = STATIC_STATE; 496 } else { 497 p_slot->state = POWERON_STATE; 498 dbg("%s: adding bus:device(%x:%x)\n", 499 __FUNCTION__, p_slot->bus, p_slot->device); 500 501 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { 502 /* Wait for exclusive access to hardware */ 503 mutex_lock(&p_slot->ctrl->ctrl_lock); 504 505 p_slot->hpc_ops->green_led_off(p_slot); 506 507 /* Wait for the command to complete */ 508 wait_for_ctrl_irq (p_slot->ctrl); 509 510 /* Done with exclusive hardware access */ 511 mutex_unlock(&p_slot->ctrl->ctrl_lock); 512 } 513 p_slot->state = STATIC_STATE; 514 } 515 516 return; 517 } 518 519 520 521 /* this is the main worker thread */ 522 static int event_thread(void* data) 523 { 524 struct controller *ctrl; 525 lock_kernel(); 526 daemonize("pciehpd_event"); 527 528 unlock_kernel(); 529 530 while (1) { 531 dbg("!!!!event_thread sleeping\n"); 532 down_interruptible (&event_semaphore); 533 dbg("event_thread woken finished = %d\n", event_finished); 534 if (event_finished || signal_pending(current)) 535 break; 536 /* Do stuff here */ 537 if (pushbutton_pending) 538 pciehp_pushbutton_thread(pushbutton_pending); 539 else if (surprise_rm_pending) 540 pciehp_surprise_rm_thread(surprise_rm_pending); 541 else 542 for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) 543 interrupt_event_handler(ctrl); 544 } 545 dbg("event_thread signals exit\n"); 546 up(&event_exit); 547 return 0; 548 } 549 550 int pciehp_event_start_thread(void) 551 { 552 int pid; 553 554 /* initialize our semaphores */ 555 init_MUTEX_LOCKED(&event_exit); 556 event_finished=0; 557 558 init_MUTEX_LOCKED(&event_semaphore); 559 pid = kernel_thread(event_thread, NULL, 0); 560 561 if (pid < 0) { 562 err ("Can't start up our event thread\n"); 563 return -1; 564 } 565 return 0; 566 } 567 568 569 void pciehp_event_stop_thread(void) 570 { 571 event_finished = 1; 572 up(&event_semaphore); 573 down(&event_exit); 574 } 575 576 577 static int update_slot_info(struct slot *slot) 578 { 579 struct hotplug_slot_info *info; 580 /* char buffer[SLOT_NAME_SIZE]; */ 581 int result; 582 583 info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); 584 if (!info) 585 return -ENOMEM; 586 587 /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */ 588 589 slot->hpc_ops->get_power_status(slot, &(info->power_status)); 590 slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); 591 slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); 592 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); 593 594 /* result = pci_hp_change_slot_info(buffer, info); */ 595 result = pci_hp_change_slot_info(slot->hotplug_slot, info); 596 kfree (info); 597 return result; 598 } 599 600 static void interrupt_event_handler(struct controller *ctrl) 601 { 602 int loop = 0; 603 int change = 1; 604 u8 hp_slot; 605 u8 getstatus; 606 struct slot *p_slot; 607 608 while (change) { 609 change = 0; 610 611 for (loop = 0; loop < MAX_EVENTS; loop++) { 612 if (ctrl->event_queue[loop].event_type != 0) { 613 hp_slot = ctrl->event_queue[loop].hp_slot; 614 615 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 616 617 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { 618 dbg("button cancel\n"); 619 del_timer(&p_slot->task_event); 620 621 switch (p_slot->state) { 622 case BLINKINGOFF_STATE: 623 /* Wait for exclusive access to hardware */ 624 mutex_lock(&ctrl->ctrl_lock); 625 626 if (PWR_LED(ctrl->ctrlcap)) { 627 p_slot->hpc_ops->green_led_on(p_slot); 628 /* Wait for the command to complete */ 629 wait_for_ctrl_irq (ctrl); 630 } 631 if (ATTN_LED(ctrl->ctrlcap)) { 632 p_slot->hpc_ops->set_attention_status(p_slot, 0); 633 634 /* Wait for the command to complete */ 635 wait_for_ctrl_irq (ctrl); 636 } 637 /* Done with exclusive hardware access */ 638 mutex_unlock(&ctrl->ctrl_lock); 639 break; 640 case BLINKINGON_STATE: 641 /* Wait for exclusive access to hardware */ 642 mutex_lock(&ctrl->ctrl_lock); 643 644 if (PWR_LED(ctrl->ctrlcap)) { 645 p_slot->hpc_ops->green_led_off(p_slot); 646 /* Wait for the command to complete */ 647 wait_for_ctrl_irq (ctrl); 648 } 649 if (ATTN_LED(ctrl->ctrlcap)){ 650 p_slot->hpc_ops->set_attention_status(p_slot, 0); 651 /* Wait for the command to complete */ 652 wait_for_ctrl_irq (ctrl); 653 } 654 /* Done with exclusive hardware access */ 655 mutex_unlock(&ctrl->ctrl_lock); 656 657 break; 658 default: 659 warn("Not a valid state\n"); 660 return; 661 } 662 info(msg_button_cancel, slot_name(p_slot)); 663 p_slot->state = STATIC_STATE; 664 } 665 /* ***********Button Pressed (No action on 1st press...) */ 666 else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { 667 668 if (ATTN_BUTTN(ctrl->ctrlcap)) { 669 dbg("Button pressed\n"); 670 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 671 if (getstatus) { 672 /* slot is on */ 673 dbg("slot is on\n"); 674 p_slot->state = BLINKINGOFF_STATE; 675 info(msg_button_off, slot_name(p_slot)); 676 } else { 677 /* slot is off */ 678 dbg("slot is off\n"); 679 p_slot->state = BLINKINGON_STATE; 680 info(msg_button_on, slot_name(p_slot)); 681 } 682 683 /* Wait for exclusive access to hardware */ 684 mutex_lock(&ctrl->ctrl_lock); 685 686 /* blink green LED and turn off amber */ 687 if (PWR_LED(ctrl->ctrlcap)) { 688 p_slot->hpc_ops->green_led_blink(p_slot); 689 /* Wait for the command to complete */ 690 wait_for_ctrl_irq (ctrl); 691 } 692 693 if (ATTN_LED(ctrl->ctrlcap)) { 694 p_slot->hpc_ops->set_attention_status(p_slot, 0); 695 696 /* Wait for the command to complete */ 697 wait_for_ctrl_irq (ctrl); 698 } 699 700 /* Done with exclusive hardware access */ 701 mutex_unlock(&ctrl->ctrl_lock); 702 703 init_timer(&p_slot->task_event); 704 p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ 705 p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; 706 p_slot->task_event.data = (unsigned long) p_slot; 707 708 add_timer(&p_slot->task_event); 709 } 710 } 711 /***********POWER FAULT********************/ 712 else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { 713 if (POWER_CTRL(ctrl->ctrlcap)) { 714 dbg("power fault\n"); 715 /* Wait for exclusive access to hardware */ 716 mutex_lock(&ctrl->ctrl_lock); 717 718 if (ATTN_LED(ctrl->ctrlcap)) { 719 p_slot->hpc_ops->set_attention_status(p_slot, 1); 720 wait_for_ctrl_irq (ctrl); 721 } 722 723 if (PWR_LED(ctrl->ctrlcap)) { 724 p_slot->hpc_ops->green_led_off(p_slot); 725 wait_for_ctrl_irq (ctrl); 726 } 727 728 /* Done with exclusive hardware access */ 729 mutex_unlock(&ctrl->ctrl_lock); 730 } 731 } 732 /***********SURPRISE REMOVAL********************/ 733 else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || 734 (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) { 735 if (HP_SUPR_RM(ctrl->ctrlcap)) { 736 dbg("Surprise Removal\n"); 737 if (p_slot) { 738 surprise_rm_pending = (unsigned long) p_slot; 739 up(&event_semaphore); 740 update_slot_info(p_slot); 741 } 742 } 743 } else { 744 /* refresh notification */ 745 if (p_slot) 746 update_slot_info(p_slot); 747 } 748 749 ctrl->event_queue[loop].event_type = 0; 750 751 change = 1; 752 } 753 } /* End of FOR loop */ 754 } 755 } 756 757 758 int pciehp_enable_slot(struct slot *p_slot) 759 { 760 u8 getstatus = 0; 761 int rc; 762 763 /* Check to see if (latch closed, card present, power off) */ 764 mutex_lock(&p_slot->ctrl->crit_sect); 765 766 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 767 if (rc || !getstatus) { 768 info("%s: no adapter on slot(%s)\n", __FUNCTION__, 769 slot_name(p_slot)); 770 mutex_unlock(&p_slot->ctrl->crit_sect); 771 return -ENODEV; 772 } 773 if (MRL_SENS(p_slot->ctrl->ctrlcap)) { 774 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 775 if (rc || getstatus) { 776 info("%s: latch open on slot(%s)\n", __FUNCTION__, 777 slot_name(p_slot)); 778 mutex_unlock(&p_slot->ctrl->crit_sect); 779 return -ENODEV; 780 } 781 } 782 783 if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { 784 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 785 if (rc || getstatus) { 786 info("%s: already enabled on slot(%s)\n", __FUNCTION__, 787 slot_name(p_slot)); 788 mutex_unlock(&p_slot->ctrl->crit_sect); 789 return -EINVAL; 790 } 791 } 792 793 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 794 795 rc = board_added(p_slot); 796 if (rc) { 797 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 798 } 799 800 update_slot_info(p_slot); 801 802 mutex_unlock(&p_slot->ctrl->crit_sect); 803 return rc; 804 } 805 806 807 int pciehp_disable_slot(struct slot *p_slot) 808 { 809 u8 getstatus = 0; 810 int ret = 0; 811 812 if (!p_slot->ctrl) 813 return 1; 814 815 /* Check to see if (latch closed, card present, power on) */ 816 mutex_lock(&p_slot->ctrl->crit_sect); 817 818 if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { 819 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 820 if (ret || !getstatus) { 821 info("%s: no adapter on slot(%s)\n", __FUNCTION__, 822 slot_name(p_slot)); 823 mutex_unlock(&p_slot->ctrl->crit_sect); 824 return -ENODEV; 825 } 826 } 827 828 if (MRL_SENS(p_slot->ctrl->ctrlcap)) { 829 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 830 if (ret || getstatus) { 831 info("%s: latch open on slot(%s)\n", __FUNCTION__, 832 slot_name(p_slot)); 833 mutex_unlock(&p_slot->ctrl->crit_sect); 834 return -ENODEV; 835 } 836 } 837 838 if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { 839 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 840 if (ret || !getstatus) { 841 info("%s: already disabled slot(%s)\n", __FUNCTION__, 842 slot_name(p_slot)); 843 mutex_unlock(&p_slot->ctrl->crit_sect); 844 return -EINVAL; 845 } 846 } 847 848 ret = remove_board(p_slot); 849 update_slot_info(p_slot); 850 851 mutex_unlock(&p_slot->ctrl->crit_sect); 852 return ret; 853 } 854 855