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