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