cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

shpchp_ctrl.c (17833B)


      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}