Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Standard Hot Plug Controller Driver
0004  *
0005  * Copyright (C) 1995,2001 Compaq Computer Corporation
0006  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
0007  * Copyright (C) 2001 IBM Corp.
0008  * Copyright (C) 2003-2004 Intel Corporation
0009  *
0010  * All rights reserved.
0011  *
0012  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
0013  *
0014  */
0015 
0016 #include <linux/module.h>
0017 #include <linux/kernel.h>
0018 #include <linux/types.h>
0019 #include <linux/slab.h>
0020 #include <linux/pci.h>
0021 #include "../pci.h"
0022 #include "shpchp.h"
0023 
0024 static void interrupt_event_handler(struct work_struct *work);
0025 static int shpchp_enable_slot(struct slot *p_slot);
0026 static int shpchp_disable_slot(struct slot *p_slot);
0027 
0028 static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
0029 {
0030     struct event_info *info;
0031 
0032     info = kmalloc(sizeof(*info), GFP_ATOMIC);
0033     if (!info)
0034         return -ENOMEM;
0035 
0036     info->event_type = event_type;
0037     info->p_slot = p_slot;
0038     INIT_WORK(&info->work, interrupt_event_handler);
0039 
0040     queue_work(p_slot->wq, &info->work);
0041 
0042     return 0;
0043 }
0044 
0045 u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
0046 {
0047     struct slot *p_slot;
0048     u32 event_type;
0049 
0050     /* Attention Button Change */
0051     ctrl_dbg(ctrl, "Attention button interrupt received\n");
0052 
0053     p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
0054     p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
0055 
0056     /*
0057      *  Button pressed - See if need to TAKE ACTION!!!
0058      */
0059     ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot));
0060     event_type = INT_BUTTON_PRESS;
0061 
0062     queue_interrupt_event(p_slot, event_type);
0063 
0064     return 0;
0065 
0066 }
0067 
0068 u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
0069 {
0070     struct slot *p_slot;
0071     u8 getstatus;
0072     u32 event_type;
0073 
0074     /* Switch Change */
0075     ctrl_dbg(ctrl, "Switch interrupt received\n");
0076 
0077     p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
0078     p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
0079     p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
0080     ctrl_dbg(ctrl, "Card present %x Power status %x\n",
0081          p_slot->presence_save, p_slot->pwr_save);
0082 
0083     if (getstatus) {
0084         /*
0085          * Switch opened
0086          */
0087         ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot));
0088         event_type = INT_SWITCH_OPEN;
0089         if (p_slot->pwr_save && p_slot->presence_save) {
0090             event_type = INT_POWER_FAULT;
0091             ctrl_err(ctrl, "Surprise Removal of card\n");
0092         }
0093     } else {
0094         /*
0095          *  Switch closed
0096          */
0097         ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot));
0098         event_type = INT_SWITCH_CLOSE;
0099     }
0100 
0101     queue_interrupt_event(p_slot, event_type);
0102 
0103     return 1;
0104 }
0105 
0106 u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
0107 {
0108     struct slot *p_slot;
0109     u32 event_type;
0110 
0111     /* Presence Change */
0112     ctrl_dbg(ctrl, "Presence/Notify input change\n");
0113 
0114     p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
0115 
0116     /*
0117      * Save the presence state
0118      */
0119     p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
0120     if (p_slot->presence_save) {
0121         /*
0122          * Card Present
0123          */
0124         ctrl_info(ctrl, "Card present on Slot(%s)\n",
0125               slot_name(p_slot));
0126         event_type = INT_PRESENCE_ON;
0127     } else {
0128         /*
0129          * Not Present
0130          */
0131         ctrl_info(ctrl, "Card not present on Slot(%s)\n",
0132               slot_name(p_slot));
0133         event_type = INT_PRESENCE_OFF;
0134     }
0135 
0136     queue_interrupt_event(p_slot, event_type);
0137 
0138     return 1;
0139 }
0140 
0141 u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
0142 {
0143     struct slot *p_slot;
0144     u32 event_type;
0145 
0146     /* Power fault */
0147     ctrl_dbg(ctrl, "Power fault interrupt received\n");
0148 
0149     p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
0150 
0151     if (!(p_slot->hpc_ops->query_power_fault(p_slot))) {
0152         /*
0153          * Power fault Cleared
0154          */
0155         ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n",
0156               slot_name(p_slot));
0157         p_slot->status = 0x00;
0158         event_type = INT_POWER_FAULT_CLEAR;
0159     } else {
0160         /*
0161          *   Power fault
0162          */
0163         ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot));
0164         event_type = INT_POWER_FAULT;
0165         /* set power fault status for this board */
0166         p_slot->status = 0xFF;
0167         ctrl_info(ctrl, "Power fault bit %x set\n", hp_slot);
0168     }
0169 
0170     queue_interrupt_event(p_slot, event_type);
0171 
0172     return 1;
0173 }
0174 
0175 /* The following routines constitute the bulk of the
0176    hotplug controller logic
0177  */
0178 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
0179         enum pci_bus_speed speed)
0180 {
0181     int rc = 0;
0182 
0183     ctrl_dbg(ctrl, "Change speed to %d\n", speed);
0184     rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed);
0185     if (rc) {
0186         ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n",
0187              __func__);
0188         return WRONG_BUS_FREQUENCY;
0189     }
0190     return rc;
0191 }
0192 
0193 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
0194         u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
0195         enum pci_bus_speed msp)
0196 {
0197     int rc = 0;
0198 
0199     /*
0200      * If other slots on the same bus are occupied, we cannot
0201      * change the bus speed.
0202      */
0203     if (flag) {
0204         if (asp < bsp) {
0205             ctrl_err(ctrl, "Speed of bus %x and adapter %x mismatch\n",
0206                  bsp, asp);
0207             rc = WRONG_BUS_FREQUENCY;
0208         }
0209         return rc;
0210     }
0211 
0212     if (asp < msp) {
0213         if (bsp != asp)
0214             rc = change_bus_speed(ctrl, pslot, asp);
0215     } else {
0216         if (bsp != msp)
0217             rc = change_bus_speed(ctrl, pslot, msp);
0218     }
0219     return rc;
0220 }
0221 
0222 /**
0223  * board_added - Called after a board has been added to the system.
0224  * @p_slot: target &slot
0225  *
0226  * Turns power on for the board.
0227  * Configures board.
0228  */
0229 static int board_added(struct slot *p_slot)
0230 {
0231     u8 hp_slot;
0232     u8 slots_not_empty = 0;
0233     int rc = 0;
0234     enum pci_bus_speed asp, bsp, msp;
0235     struct controller *ctrl = p_slot->ctrl;
0236     struct pci_bus *parent = ctrl->pci_dev->subordinate;
0237 
0238     hp_slot = p_slot->device - ctrl->slot_device_offset;
0239 
0240     ctrl_dbg(ctrl, "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n",
0241          __func__, p_slot->device, ctrl->slot_device_offset, hp_slot);
0242 
0243     /* Power on slot without connecting to bus */
0244     rc = p_slot->hpc_ops->power_on_slot(p_slot);
0245     if (rc) {
0246         ctrl_err(ctrl, "Failed to power on slot\n");
0247         return -1;
0248     }
0249 
0250     if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
0251         rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz);
0252         if (rc) {
0253             ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n",
0254                  __func__);
0255             return WRONG_BUS_FREQUENCY;
0256         }
0257 
0258         /* turn on board, blink green LED, turn off Amber LED */
0259         rc = p_slot->hpc_ops->slot_enable(p_slot);
0260         if (rc) {
0261             ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
0262             return rc;
0263         }
0264     }
0265 
0266     rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
0267     if (rc) {
0268         ctrl_err(ctrl, "Can't get adapter speed or bus mode mismatch\n");
0269         return WRONG_BUS_FREQUENCY;
0270     }
0271 
0272     bsp = ctrl->pci_dev->subordinate->cur_bus_speed;
0273     msp = ctrl->pci_dev->subordinate->max_bus_speed;
0274 
0275     /* Check if there are other slots or devices on the same bus */
0276     if (!list_empty(&ctrl->pci_dev->subordinate->devices))
0277         slots_not_empty = 1;
0278 
0279     ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, max_bus_speed %d\n",
0280          __func__, slots_not_empty, asp,
0281          bsp, msp);
0282 
0283     rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp);
0284     if (rc)
0285         return rc;
0286 
0287     /* turn on board, blink green LED, turn off Amber LED */
0288     rc = p_slot->hpc_ops->slot_enable(p_slot);
0289     if (rc) {
0290         ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
0291         return rc;
0292     }
0293 
0294     /* Wait for ~1 second */
0295     msleep(1000);
0296 
0297     ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status);
0298     /* Check for a power fault */
0299     if (p_slot->status == 0xFF) {
0300         /* power fault occurred, but it was benign */
0301         ctrl_dbg(ctrl, "%s: Power fault\n", __func__);
0302         p_slot->status = 0;
0303         goto err_exit;
0304     }
0305 
0306     if (shpchp_configure_device(p_slot)) {
0307         ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n",
0308              pci_domain_nr(parent), p_slot->bus, p_slot->device);
0309         goto err_exit;
0310     }
0311 
0312     p_slot->status = 0;
0313     p_slot->is_a_board = 0x01;
0314     p_slot->pwr_save = 1;
0315 
0316     p_slot->hpc_ops->green_led_on(p_slot);
0317 
0318     return 0;
0319 
0320 err_exit:
0321     /* turn off slot, turn on Amber LED, turn off Green LED */
0322     rc = p_slot->hpc_ops->slot_disable(p_slot);
0323     if (rc) {
0324         ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
0325              __func__);
0326         return rc;
0327     }
0328 
0329     return(rc);
0330 }
0331 
0332 
0333 /**
0334  * remove_board - Turns off slot and LEDs
0335  * @p_slot: target &slot
0336  */
0337 static int remove_board(struct slot *p_slot)
0338 {
0339     struct controller *ctrl = p_slot->ctrl;
0340     u8 hp_slot;
0341     int rc;
0342 
0343     shpchp_unconfigure_device(p_slot);
0344 
0345     hp_slot = p_slot->device - ctrl->slot_device_offset;
0346     p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
0347 
0348     ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot);
0349 
0350     /* Change status to shutdown */
0351     if (p_slot->is_a_board)
0352         p_slot->status = 0x01;
0353 
0354     /* turn off slot, turn on Amber LED, turn off Green LED */
0355     rc = p_slot->hpc_ops->slot_disable(p_slot);
0356     if (rc) {
0357         ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
0358              __func__);
0359         return rc;
0360     }
0361 
0362     rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
0363     if (rc) {
0364         ctrl_err(ctrl, "Issue of Set Attention command failed\n");
0365         return rc;
0366     }
0367 
0368     p_slot->pwr_save = 0;
0369     p_slot->is_a_board = 0;
0370 
0371     return 0;
0372 }
0373 
0374 
0375 struct pushbutton_work_info {
0376     struct slot *p_slot;
0377     struct work_struct work;
0378 };
0379 
0380 /**
0381  * shpchp_pushbutton_thread - handle pushbutton events
0382  * @work: &struct work_struct to be handled
0383  *
0384  * Scheduled procedure to handle blocking stuff for the pushbuttons.
0385  * Handles all pending events and exits.
0386  */
0387 static void shpchp_pushbutton_thread(struct work_struct *work)
0388 {
0389     struct pushbutton_work_info *info =
0390         container_of(work, struct pushbutton_work_info, work);
0391     struct slot *p_slot = info->p_slot;
0392 
0393     mutex_lock(&p_slot->lock);
0394     switch (p_slot->state) {
0395     case POWEROFF_STATE:
0396         mutex_unlock(&p_slot->lock);
0397         shpchp_disable_slot(p_slot);
0398         mutex_lock(&p_slot->lock);
0399         p_slot->state = STATIC_STATE;
0400         break;
0401     case POWERON_STATE:
0402         mutex_unlock(&p_slot->lock);
0403         if (shpchp_enable_slot(p_slot))
0404             p_slot->hpc_ops->green_led_off(p_slot);
0405         mutex_lock(&p_slot->lock);
0406         p_slot->state = STATIC_STATE;
0407         break;
0408     default:
0409         break;
0410     }
0411     mutex_unlock(&p_slot->lock);
0412 
0413     kfree(info);
0414 }
0415 
0416 void shpchp_queue_pushbutton_work(struct work_struct *work)
0417 {
0418     struct slot *p_slot = container_of(work, struct slot, work.work);
0419     struct pushbutton_work_info *info;
0420 
0421     info = kmalloc(sizeof(*info), GFP_KERNEL);
0422     if (!info) {
0423         ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
0424              __func__);
0425         return;
0426     }
0427     info->p_slot = p_slot;
0428     INIT_WORK(&info->work, shpchp_pushbutton_thread);
0429 
0430     mutex_lock(&p_slot->lock);
0431     switch (p_slot->state) {
0432     case BLINKINGOFF_STATE:
0433         p_slot->state = POWEROFF_STATE;
0434         break;
0435     case BLINKINGON_STATE:
0436         p_slot->state = POWERON_STATE;
0437         break;
0438     default:
0439         kfree(info);
0440         goto out;
0441     }
0442     queue_work(p_slot->wq, &info->work);
0443  out:
0444     mutex_unlock(&p_slot->lock);
0445 }
0446 
0447 static void update_slot_info(struct slot *slot)
0448 {
0449     slot->hpc_ops->get_power_status(slot, &slot->pwr_save);
0450     slot->hpc_ops->get_attention_status(slot, &slot->attention_save);
0451     slot->hpc_ops->get_latch_status(slot, &slot->latch_save);
0452     slot->hpc_ops->get_adapter_status(slot, &slot->presence_save);
0453 }
0454 
0455 /*
0456  * Note: This function must be called with slot->lock held
0457  */
0458 static void handle_button_press_event(struct slot *p_slot)
0459 {
0460     u8 getstatus;
0461     struct controller *ctrl = p_slot->ctrl;
0462 
0463     switch (p_slot->state) {
0464     case STATIC_STATE:
0465         p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
0466         if (getstatus) {
0467             p_slot->state = BLINKINGOFF_STATE;
0468             ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n",
0469                   slot_name(p_slot));
0470         } else {
0471             p_slot->state = BLINKINGON_STATE;
0472             ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n",
0473                   slot_name(p_slot));
0474         }
0475         /* blink green LED and turn off amber */
0476         p_slot->hpc_ops->green_led_blink(p_slot);
0477         p_slot->hpc_ops->set_attention_status(p_slot, 0);
0478 
0479         queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
0480         break;
0481     case BLINKINGOFF_STATE:
0482     case BLINKINGON_STATE:
0483         /*
0484          * Cancel if we are still blinking; this means that we
0485          * press the attention again before the 5 sec. limit
0486          * expires to cancel hot-add or hot-remove
0487          */
0488         ctrl_info(ctrl, "Button cancel on Slot(%s)\n",
0489               slot_name(p_slot));
0490         cancel_delayed_work(&p_slot->work);
0491         if (p_slot->state == BLINKINGOFF_STATE)
0492             p_slot->hpc_ops->green_led_on(p_slot);
0493         else
0494             p_slot->hpc_ops->green_led_off(p_slot);
0495         p_slot->hpc_ops->set_attention_status(p_slot, 0);
0496         ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n",
0497               slot_name(p_slot));
0498         p_slot->state = STATIC_STATE;
0499         break;
0500     case POWEROFF_STATE:
0501     case POWERON_STATE:
0502         /*
0503          * Ignore if the slot is on power-on or power-off state;
0504          * this means that the previous attention button action
0505          * to hot-add or hot-remove is undergoing
0506          */
0507         ctrl_info(ctrl, "Button ignore on Slot(%s)\n",
0508               slot_name(p_slot));
0509         update_slot_info(p_slot);
0510         break;
0511     default:
0512         ctrl_warn(ctrl, "Not a valid state\n");
0513         break;
0514     }
0515 }
0516 
0517 static void interrupt_event_handler(struct work_struct *work)
0518 {
0519     struct event_info *info = container_of(work, struct event_info, work);
0520     struct slot *p_slot = info->p_slot;
0521 
0522     mutex_lock(&p_slot->lock);
0523     switch (info->event_type) {
0524     case INT_BUTTON_PRESS:
0525         handle_button_press_event(p_slot);
0526         break;
0527     case INT_POWER_FAULT:
0528         ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__);
0529         p_slot->hpc_ops->set_attention_status(p_slot, 1);
0530         p_slot->hpc_ops->green_led_off(p_slot);
0531         break;
0532     default:
0533         update_slot_info(p_slot);
0534         break;
0535     }
0536     mutex_unlock(&p_slot->lock);
0537 
0538     kfree(info);
0539 }
0540 
0541 
0542 static int shpchp_enable_slot (struct slot *p_slot)
0543 {
0544     u8 getstatus = 0;
0545     int rc, retval = -ENODEV;
0546     struct controller *ctrl = p_slot->ctrl;
0547 
0548     /* Check to see if (latch closed, card present, power off) */
0549     mutex_lock(&p_slot->ctrl->crit_sect);
0550     rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
0551     if (rc || !getstatus) {
0552         ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
0553         goto out;
0554     }
0555     rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
0556     if (rc || getstatus) {
0557         ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
0558         goto out;
0559     }
0560     rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
0561     if (rc || getstatus) {
0562         ctrl_info(ctrl, "Already enabled on slot(%s)\n",
0563               slot_name(p_slot));
0564         goto out;
0565     }
0566 
0567     p_slot->is_a_board = 1;
0568 
0569     /* We have to save the presence info for these slots */
0570     p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
0571     p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
0572     ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
0573     p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
0574 
0575     if ((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD &&
0576          p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)
0577          && p_slot->ctrl->num_slots == 1) {
0578         /* handle AMD POGO errata; this must be done before enable  */
0579         amd_pogo_errata_save_misc_reg(p_slot);
0580         retval = board_added(p_slot);
0581         /* handle AMD POGO errata; this must be done after enable  */
0582         amd_pogo_errata_restore_misc_reg(p_slot);
0583     } else
0584         retval = board_added(p_slot);
0585 
0586     if (retval) {
0587         p_slot->hpc_ops->get_adapter_status(p_slot,
0588                 &(p_slot->presence_save));
0589         p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
0590     }
0591 
0592     update_slot_info(p_slot);
0593  out:
0594     mutex_unlock(&p_slot->ctrl->crit_sect);
0595     return retval;
0596 }
0597 
0598 
0599 static int shpchp_disable_slot (struct slot *p_slot)
0600 {
0601     u8 getstatus = 0;
0602     int rc, retval = -ENODEV;
0603     struct controller *ctrl = p_slot->ctrl;
0604 
0605     if (!p_slot->ctrl)
0606         return -ENODEV;
0607 
0608     /* Check to see if (latch closed, card present, power on) */
0609     mutex_lock(&p_slot->ctrl->crit_sect);
0610 
0611     rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
0612     if (rc || !getstatus) {
0613         ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
0614         goto out;
0615     }
0616     rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
0617     if (rc || getstatus) {
0618         ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
0619         goto out;
0620     }
0621     rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
0622     if (rc || !getstatus) {
0623         ctrl_info(ctrl, "Already disabled on slot(%s)\n",
0624               slot_name(p_slot));
0625         goto out;
0626     }
0627 
0628     retval = remove_board(p_slot);
0629     update_slot_info(p_slot);
0630  out:
0631     mutex_unlock(&p_slot->ctrl->crit_sect);
0632     return retval;
0633 }
0634 
0635 int shpchp_sysfs_enable_slot(struct slot *p_slot)
0636 {
0637     int retval = -ENODEV;
0638     struct controller *ctrl = p_slot->ctrl;
0639 
0640     mutex_lock(&p_slot->lock);
0641     switch (p_slot->state) {
0642     case BLINKINGON_STATE:
0643         cancel_delayed_work(&p_slot->work);
0644         fallthrough;
0645     case STATIC_STATE:
0646         p_slot->state = POWERON_STATE;
0647         mutex_unlock(&p_slot->lock);
0648         retval = shpchp_enable_slot(p_slot);
0649         mutex_lock(&p_slot->lock);
0650         p_slot->state = STATIC_STATE;
0651         break;
0652     case POWERON_STATE:
0653         ctrl_info(ctrl, "Slot %s is already in powering on state\n",
0654               slot_name(p_slot));
0655         break;
0656     case BLINKINGOFF_STATE:
0657     case POWEROFF_STATE:
0658         ctrl_info(ctrl, "Already enabled on slot %s\n",
0659               slot_name(p_slot));
0660         break;
0661     default:
0662         ctrl_err(ctrl, "Not a valid state on slot %s\n",
0663              slot_name(p_slot));
0664         break;
0665     }
0666     mutex_unlock(&p_slot->lock);
0667 
0668     return retval;
0669 }
0670 
0671 int shpchp_sysfs_disable_slot(struct slot *p_slot)
0672 {
0673     int retval = -ENODEV;
0674     struct controller *ctrl = p_slot->ctrl;
0675 
0676     mutex_lock(&p_slot->lock);
0677     switch (p_slot->state) {
0678     case BLINKINGOFF_STATE:
0679         cancel_delayed_work(&p_slot->work);
0680         fallthrough;
0681     case STATIC_STATE:
0682         p_slot->state = POWEROFF_STATE;
0683         mutex_unlock(&p_slot->lock);
0684         retval = shpchp_disable_slot(p_slot);
0685         mutex_lock(&p_slot->lock);
0686         p_slot->state = STATIC_STATE;
0687         break;
0688     case POWEROFF_STATE:
0689         ctrl_info(ctrl, "Slot %s is already in powering off state\n",
0690               slot_name(p_slot));
0691         break;
0692     case BLINKINGON_STATE:
0693     case POWERON_STATE:
0694         ctrl_info(ctrl, "Already disabled on slot %s\n",
0695               slot_name(p_slot));
0696         break;
0697     default:
0698         ctrl_err(ctrl, "Not a valid state on slot %s\n",
0699              slot_name(p_slot));
0700         break;
0701     }
0702     mutex_unlock(&p_slot->lock);
0703 
0704     return retval;
0705 }