1 /* 2 * Standard 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 <linux/workqueue.h> 36 #include "../pci.h" 37 #include "shpchp.h" 38 39 static void interrupt_event_handler(struct work_struct *work); 40 static int shpchp_enable_slot(struct slot *p_slot); 41 static int shpchp_disable_slot(struct slot *p_slot); 42 43 static int queue_interrupt_event(struct slot *p_slot, u32 event_type) 44 { 45 struct event_info *info; 46 47 info = kmalloc(sizeof(*info), GFP_ATOMIC); 48 if (!info) 49 return -ENOMEM; 50 51 info->event_type = event_type; 52 info->p_slot = p_slot; 53 INIT_WORK(&info->work, interrupt_event_handler); 54 55 schedule_work(&info->work); 56 57 return 0; 58 } 59 60 u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) 61 { 62 struct controller *ctrl = (struct controller *) inst_id; 63 struct slot *p_slot; 64 u32 event_type; 65 66 /* Attention Button Change */ 67 dbg("shpchp: Attention button interrupt received.\n"); 68 69 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 70 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 71 72 /* 73 * Button pressed - See if need to TAKE ACTION!!! 74 */ 75 info("Button pressed on Slot(%s)\n", p_slot->name); 76 event_type = INT_BUTTON_PRESS; 77 78 queue_interrupt_event(p_slot, event_type); 79 80 return 0; 81 82 } 83 84 u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) 85 { 86 struct controller *ctrl = (struct controller *) inst_id; 87 struct slot *p_slot; 88 u8 getstatus; 89 u32 event_type; 90 91 /* Switch Change */ 92 dbg("shpchp: Switch interrupt received.\n"); 93 94 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 95 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 96 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 97 dbg("%s: Card present %x Power status %x\n", __FUNCTION__, 98 p_slot->presence_save, p_slot->pwr_save); 99 100 if (getstatus) { 101 /* 102 * Switch opened 103 */ 104 info("Latch open on Slot(%s)\n", p_slot->name); 105 event_type = INT_SWITCH_OPEN; 106 if (p_slot->pwr_save && p_slot->presence_save) { 107 event_type = INT_POWER_FAULT; 108 err("Surprise Removal of card\n"); 109 } 110 } else { 111 /* 112 * Switch closed 113 */ 114 info("Latch close on Slot(%s)\n", p_slot->name); 115 event_type = INT_SWITCH_CLOSE; 116 } 117 118 queue_interrupt_event(p_slot, event_type); 119 120 return 1; 121 } 122 123 u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) 124 { 125 struct controller *ctrl = (struct controller *) inst_id; 126 struct slot *p_slot; 127 u32 event_type; 128 129 /* Presence Change */ 130 dbg("shpchp: Presence/Notify input change.\n"); 131 132 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 133 134 /* 135 * Save the presence state 136 */ 137 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 138 if (p_slot->presence_save) { 139 /* 140 * Card Present 141 */ 142 info("Card present on Slot(%s)\n", p_slot->name); 143 event_type = INT_PRESENCE_ON; 144 } else { 145 /* 146 * Not Present 147 */ 148 info("Card not present on Slot(%s)\n", p_slot->name); 149 event_type = INT_PRESENCE_OFF; 150 } 151 152 queue_interrupt_event(p_slot, event_type); 153 154 return 1; 155 } 156 157 u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) 158 { 159 struct controller *ctrl = (struct controller *) inst_id; 160 struct slot *p_slot; 161 u32 event_type; 162 163 /* Power fault */ 164 dbg("shpchp: Power fault interrupt received.\n"); 165 166 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 167 168 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { 169 /* 170 * Power fault Cleared 171 */ 172 info("Power fault cleared on Slot(%s)\n", p_slot->name); 173 p_slot->status = 0x00; 174 event_type = INT_POWER_FAULT_CLEAR; 175 } else { 176 /* 177 * Power fault 178 */ 179 info("Power fault on Slot(%s)\n", p_slot->name); 180 event_type = INT_POWER_FAULT; 181 /* set power fault status for this board */ 182 p_slot->status = 0xFF; 183 info("power fault bit %x set\n", hp_slot); 184 } 185 186 queue_interrupt_event(p_slot, event_type); 187 188 return 1; 189 } 190 191 /* The following routines constitute the bulk of the 192 hotplug controller logic 193 */ 194 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, 195 enum pci_bus_speed speed) 196 { 197 int rc = 0; 198 199 dbg("%s: change to speed %d\n", __FUNCTION__, speed); 200 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { 201 err("%s: Issue of set bus speed mode command failed\n", 202 __FUNCTION__); 203 return WRONG_BUS_FREQUENCY; 204 } 205 return rc; 206 } 207 208 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, 209 u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, 210 enum pci_bus_speed msp) 211 { 212 int rc = 0; 213 214 /* 215 * If other slots on the same bus are occupied, we cannot 216 * change the bus speed. 217 */ 218 if (flag) { 219 if (asp < bsp) { 220 err("%s: speed of bus %x and adapter %x mismatch\n", 221 __FUNCTION__, bsp, asp); 222 rc = WRONG_BUS_FREQUENCY; 223 } 224 return rc; 225 } 226 227 if (asp < msp) { 228 if (bsp != asp) 229 rc = change_bus_speed(ctrl, pslot, asp); 230 } else { 231 if (bsp != msp) 232 rc = change_bus_speed(ctrl, pslot, msp); 233 } 234 return rc; 235 } 236 237 /** 238 * board_added - Called after a board has been added to the system. 239 * 240 * Turns power on for the board 241 * Configures board 242 * 243 */ 244 static int board_added(struct slot *p_slot) 245 { 246 u8 hp_slot; 247 u8 slots_not_empty = 0; 248 int rc = 0; 249 enum pci_bus_speed asp, bsp, msp; 250 struct controller *ctrl = p_slot->ctrl; 251 252 hp_slot = p_slot->device - ctrl->slot_device_offset; 253 254 dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", 255 __FUNCTION__, p_slot->device, 256 ctrl->slot_device_offset, hp_slot); 257 258 /* Power on slot without connecting to bus */ 259 rc = p_slot->hpc_ops->power_on_slot(p_slot); 260 if (rc) { 261 err("%s: Failed to power on slot\n", __FUNCTION__); 262 return -1; 263 } 264 265 if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { 266 if (slots_not_empty) 267 return WRONG_BUS_FREQUENCY; 268 269 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { 270 err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); 271 return WRONG_BUS_FREQUENCY; 272 } 273 274 /* turn on board, blink green LED, turn off Amber LED */ 275 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { 276 err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); 277 return rc; 278 } 279 } 280 281 rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); 282 if (rc) { 283 err("%s: Can't get adapter speed or bus mode mismatch\n", 284 __FUNCTION__); 285 return WRONG_BUS_FREQUENCY; 286 } 287 288 rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bsp); 289 if (rc) { 290 err("%s: Can't get bus operation speed\n", __FUNCTION__); 291 return WRONG_BUS_FREQUENCY; 292 } 293 294 rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &msp); 295 if (rc) { 296 err("%s: Can't get max bus operation speed\n", __FUNCTION__); 297 msp = bsp; 298 } 299 300 /* Check if there are other slots or devices on the same bus */ 301 if (!list_empty(&ctrl->pci_dev->subordinate->devices)) 302 slots_not_empty = 1; 303 304 dbg("%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, " 305 "max_bus_speed %d\n", __FUNCTION__, slots_not_empty, asp, 306 bsp, msp); 307 308 rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); 309 if (rc) 310 return rc; 311 312 /* turn on board, blink green LED, turn off Amber LED */ 313 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { 314 err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); 315 return rc; 316 } 317 318 /* Wait for ~1 second */ 319 msleep(1000); 320 321 dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); 322 /* Check for a power fault */ 323 if (p_slot->status == 0xFF) { 324 /* power fault occurred, but it was benign */ 325 dbg("%s: power fault\n", __FUNCTION__); 326 rc = POWER_FAILURE; 327 p_slot->status = 0; 328 goto err_exit; 329 } 330 331 if (shpchp_configure_device(p_slot)) { 332 err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, 333 p_slot->device); 334 goto err_exit; 335 } 336 337 p_slot->status = 0; 338 p_slot->is_a_board = 0x01; 339 p_slot->pwr_save = 1; 340 341 p_slot->hpc_ops->green_led_on(p_slot); 342 343 return 0; 344 345 err_exit: 346 /* turn off slot, turn on Amber LED, turn off Green LED */ 347 rc = p_slot->hpc_ops->slot_disable(p_slot); 348 if (rc) { 349 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); 350 return rc; 351 } 352 353 return(rc); 354 } 355 356 357 /** 358 * remove_board - Turns off slot and LED's 359 * 360 */ 361 static int remove_board(struct slot *p_slot) 362 { 363 struct controller *ctrl = p_slot->ctrl; 364 u8 hp_slot; 365 int rc; 366 367 if (shpchp_unconfigure_device(p_slot)) 368 return(1); 369 370 hp_slot = p_slot->device - ctrl->slot_device_offset; 371 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 372 373 dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); 374 375 /* Change status to shutdown */ 376 if (p_slot->is_a_board) 377 p_slot->status = 0x01; 378 379 /* turn off slot, turn on Amber LED, turn off Green LED */ 380 rc = p_slot->hpc_ops->slot_disable(p_slot); 381 if (rc) { 382 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); 383 return rc; 384 } 385 386 rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); 387 if (rc) { 388 err("%s: Issue of Set Attention command failed\n", __FUNCTION__); 389 return rc; 390 } 391 392 p_slot->pwr_save = 0; 393 p_slot->is_a_board = 0; 394 395 return 0; 396 } 397 398 399 struct pushbutton_work_info { 400 struct slot *p_slot; 401 struct work_struct work; 402 }; 403 404 /** 405 * shpchp_pushbutton_thread 406 * 407 * Scheduled procedure to handle blocking stuff for the pushbuttons 408 * Handles all pending events and exits. 409 * 410 */ 411 static void shpchp_pushbutton_thread(struct work_struct *work) 412 { 413 struct pushbutton_work_info *info = 414 container_of(work, struct pushbutton_work_info, work); 415 struct slot *p_slot = info->p_slot; 416 417 mutex_lock(&p_slot->lock); 418 switch (p_slot->state) { 419 case POWEROFF_STATE: 420 mutex_unlock(&p_slot->lock); 421 shpchp_disable_slot(p_slot); 422 mutex_lock(&p_slot->lock); 423 p_slot->state = STATIC_STATE; 424 break; 425 case POWERON_STATE: 426 mutex_unlock(&p_slot->lock); 427 if (shpchp_enable_slot(p_slot)) 428 p_slot->hpc_ops->green_led_off(p_slot); 429 mutex_lock(&p_slot->lock); 430 p_slot->state = STATIC_STATE; 431 break; 432 default: 433 break; 434 } 435 mutex_unlock(&p_slot->lock); 436 437 kfree(info); 438 } 439 440 void queue_pushbutton_work(struct work_struct *work) 441 { 442 struct slot *p_slot = container_of(work, struct slot, work.work); 443 struct pushbutton_work_info *info; 444 445 info = kmalloc(sizeof(*info), GFP_KERNEL); 446 if (!info) { 447 err("%s: Cannot allocate memory\n", __FUNCTION__); 448 return; 449 } 450 info->p_slot = p_slot; 451 INIT_WORK(&info->work, shpchp_pushbutton_thread); 452 453 mutex_lock(&p_slot->lock); 454 switch (p_slot->state) { 455 case BLINKINGOFF_STATE: 456 p_slot->state = POWEROFF_STATE; 457 break; 458 case BLINKINGON_STATE: 459 p_slot->state = POWERON_STATE; 460 break; 461 default: 462 goto out; 463 } 464 queue_work(shpchp_wq, &info->work); 465 out: 466 mutex_unlock(&p_slot->lock); 467 } 468 469 static int update_slot_info (struct slot *slot) 470 { 471 struct hotplug_slot_info *info; 472 int result; 473 474 info = kmalloc(sizeof(*info), GFP_KERNEL); 475 if (!info) 476 return -ENOMEM; 477 478 slot->hpc_ops->get_power_status(slot, &(info->power_status)); 479 slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); 480 slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); 481 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); 482 483 result = pci_hp_change_slot_info(slot->hotplug_slot, info); 484 kfree (info); 485 return result; 486 } 487 488 /* 489 * Note: This function must be called with slot->lock held 490 */ 491 static void handle_button_press_event(struct slot *p_slot) 492 { 493 u8 getstatus; 494 495 switch (p_slot->state) { 496 case STATIC_STATE: 497 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 498 if (getstatus) { 499 p_slot->state = BLINKINGOFF_STATE; 500 info(msg_button_off, p_slot->name); 501 } else { 502 p_slot->state = BLINKINGON_STATE; 503 info(msg_button_on, p_slot->name); 504 } 505 /* blink green LED and turn off amber */ 506 p_slot->hpc_ops->green_led_blink(p_slot); 507 p_slot->hpc_ops->set_attention_status(p_slot, 0); 508 509 schedule_delayed_work(&p_slot->work, 5*HZ); 510 break; 511 case BLINKINGOFF_STATE: 512 case BLINKINGON_STATE: 513 /* 514 * Cancel if we are still blinking; this means that we 515 * press the attention again before the 5 sec. limit 516 * expires to cancel hot-add or hot-remove 517 */ 518 info("Button cancel on Slot(%s)\n", p_slot->name); 519 dbg("%s: button cancel\n", __FUNCTION__); 520 cancel_delayed_work(&p_slot->work); 521 if (p_slot->state == BLINKINGOFF_STATE) 522 p_slot->hpc_ops->green_led_on(p_slot); 523 else 524 p_slot->hpc_ops->green_led_off(p_slot); 525 p_slot->hpc_ops->set_attention_status(p_slot, 0); 526 info(msg_button_cancel, p_slot->name); 527 p_slot->state = STATIC_STATE; 528 break; 529 case POWEROFF_STATE: 530 case POWERON_STATE: 531 /* 532 * Ignore if the slot is on power-on or power-off state; 533 * this means that the previous attention button action 534 * to hot-add or hot-remove is undergoing 535 */ 536 info("Button ignore on Slot(%s)\n", p_slot->name); 537 update_slot_info(p_slot); 538 break; 539 default: 540 warn("Not a valid state\n"); 541 break; 542 } 543 } 544 545 static void interrupt_event_handler(struct work_struct *work) 546 { 547 struct event_info *info = container_of(work, struct event_info, work); 548 struct slot *p_slot = info->p_slot; 549 550 mutex_lock(&p_slot->lock); 551 switch (info->event_type) { 552 case INT_BUTTON_PRESS: 553 handle_button_press_event(p_slot); 554 break; 555 case INT_POWER_FAULT: 556 dbg("%s: power fault\n", __FUNCTION__); 557 p_slot->hpc_ops->set_attention_status(p_slot, 1); 558 p_slot->hpc_ops->green_led_off(p_slot); 559 break; 560 default: 561 update_slot_info(p_slot); 562 break; 563 } 564 mutex_unlock(&p_slot->lock); 565 566 kfree(info); 567 } 568 569 570 static int shpchp_enable_slot (struct slot *p_slot) 571 { 572 u8 getstatus = 0; 573 int rc, retval = -ENODEV; 574 575 /* Check to see if (latch closed, card present, power off) */ 576 mutex_lock(&p_slot->ctrl->crit_sect); 577 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 578 if (rc || !getstatus) { 579 info("No adapter on slot(%s)\n", p_slot->name); 580 goto out; 581 } 582 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 583 if (rc || getstatus) { 584 info("Latch open on slot(%s)\n", p_slot->name); 585 goto out; 586 } 587 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 588 if (rc || getstatus) { 589 info("Already enabled on slot(%s)\n", p_slot->name); 590 goto out; 591 } 592 593 p_slot->is_a_board = 1; 594 595 /* We have to save the presence info for these slots */ 596 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 597 p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); 598 dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save); 599 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 600 601 if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) || 602 (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)) 603 && p_slot->ctrl->num_slots == 1) { 604 /* handle amd pogo errata; this must be done before enable */ 605 amd_pogo_errata_save_misc_reg(p_slot); 606 retval = board_added(p_slot); 607 /* handle amd pogo errata; this must be done after enable */ 608 amd_pogo_errata_restore_misc_reg(p_slot); 609 } else 610 retval = board_added(p_slot); 611 612 if (retval) { 613 p_slot->hpc_ops->get_adapter_status(p_slot, 614 &(p_slot->presence_save)); 615 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 616 } 617 618 update_slot_info(p_slot); 619 out: 620 mutex_unlock(&p_slot->ctrl->crit_sect); 621 return retval; 622 } 623 624 625 static int shpchp_disable_slot (struct slot *p_slot) 626 { 627 u8 getstatus = 0; 628 int rc, retval = -ENODEV; 629 630 if (!p_slot->ctrl) 631 return -ENODEV; 632 633 /* Check to see if (latch closed, card present, power on) */ 634 mutex_lock(&p_slot->ctrl->crit_sect); 635 636 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 637 if (rc || !getstatus) { 638 info("No adapter on slot(%s)\n", p_slot->name); 639 goto out; 640 } 641 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 642 if (rc || getstatus) { 643 info("Latch open on slot(%s)\n", p_slot->name); 644 goto out; 645 } 646 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 647 if (rc || !getstatus) { 648 info("Already disabled slot(%s)\n", p_slot->name); 649 goto out; 650 } 651 652 retval = remove_board(p_slot); 653 update_slot_info(p_slot); 654 out: 655 mutex_unlock(&p_slot->ctrl->crit_sect); 656 return retval; 657 } 658 659 int shpchp_sysfs_enable_slot(struct slot *p_slot) 660 { 661 int retval = -ENODEV; 662 663 mutex_lock(&p_slot->lock); 664 switch (p_slot->state) { 665 case BLINKINGON_STATE: 666 cancel_delayed_work(&p_slot->work); 667 case STATIC_STATE: 668 p_slot->state = POWERON_STATE; 669 mutex_unlock(&p_slot->lock); 670 retval = shpchp_enable_slot(p_slot); 671 mutex_lock(&p_slot->lock); 672 p_slot->state = STATIC_STATE; 673 break; 674 case POWERON_STATE: 675 info("Slot %s is already in powering on state\n", 676 p_slot->name); 677 break; 678 case BLINKINGOFF_STATE: 679 case POWEROFF_STATE: 680 info("Already enabled on slot %s\n", p_slot->name); 681 break; 682 default: 683 err("Not a valid state on slot %s\n", p_slot->name); 684 break; 685 } 686 mutex_unlock(&p_slot->lock); 687 688 return retval; 689 } 690 691 int shpchp_sysfs_disable_slot(struct slot *p_slot) 692 { 693 int retval = -ENODEV; 694 695 mutex_lock(&p_slot->lock); 696 switch (p_slot->state) { 697 case BLINKINGOFF_STATE: 698 cancel_delayed_work(&p_slot->work); 699 case STATIC_STATE: 700 p_slot->state = POWEROFF_STATE; 701 mutex_unlock(&p_slot->lock); 702 retval = shpchp_disable_slot(p_slot); 703 mutex_lock(&p_slot->lock); 704 p_slot->state = STATIC_STATE; 705 break; 706 case POWEROFF_STATE: 707 info("Slot %s is already in powering off state\n", 708 p_slot->name); 709 break; 710 case BLINKINGON_STATE: 711 case POWERON_STATE: 712 info("Already disabled on slot %s\n", p_slot->name); 713 break; 714 default: 715 err("Not a valid state on slot %s\n", p_slot->name); 716 break; 717 } 718 mutex_unlock(&p_slot->lock); 719 720 return retval; 721 } 722