shpchp_ctrl.c 17 KB

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