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