shpchp_ctrl.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  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. #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. rc = POWER_FAILURE;
  252. p_slot->status = 0;
  253. goto err_exit;
  254. }
  255. if (shpchp_configure_device(p_slot)) {
  256. ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n",
  257. pci_domain_nr(parent), p_slot->bus, p_slot->device);
  258. goto err_exit;
  259. }
  260. p_slot->status = 0;
  261. p_slot->is_a_board = 0x01;
  262. p_slot->pwr_save = 1;
  263. p_slot->hpc_ops->green_led_on(p_slot);
  264. return 0;
  265. err_exit:
  266. /* turn off slot, turn on Amber LED, turn off Green LED */
  267. rc = p_slot->hpc_ops->slot_disable(p_slot);
  268. if (rc) {
  269. ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
  270. __func__);
  271. return rc;
  272. }
  273. return(rc);
  274. }
  275. /**
  276. * remove_board - Turns off slot and LEDs
  277. * @p_slot: target &slot
  278. */
  279. static int remove_board(struct slot *p_slot)
  280. {
  281. struct controller *ctrl = p_slot->ctrl;
  282. u8 hp_slot;
  283. int rc;
  284. if (shpchp_unconfigure_device(p_slot))
  285. return(1);
  286. hp_slot = p_slot->device - ctrl->slot_device_offset;
  287. p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  288. ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot);
  289. /* Change status to shutdown */
  290. if (p_slot->is_a_board)
  291. p_slot->status = 0x01;
  292. /* turn off slot, turn on Amber LED, turn off Green LED */
  293. rc = p_slot->hpc_ops->slot_disable(p_slot);
  294. if (rc) {
  295. ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
  296. __func__);
  297. return rc;
  298. }
  299. rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
  300. if (rc) {
  301. ctrl_err(ctrl, "Issue of Set Attention command failed\n");
  302. return rc;
  303. }
  304. p_slot->pwr_save = 0;
  305. p_slot->is_a_board = 0;
  306. return 0;
  307. }
  308. struct pushbutton_work_info {
  309. struct slot *p_slot;
  310. struct work_struct work;
  311. };
  312. /**
  313. * shpchp_pushbutton_thread - handle pushbutton events
  314. * @work: &struct work_struct to be handled
  315. *
  316. * Scheduled procedure to handle blocking stuff for the pushbuttons.
  317. * Handles all pending events and exits.
  318. */
  319. static void shpchp_pushbutton_thread(struct work_struct *work)
  320. {
  321. struct pushbutton_work_info *info =
  322. container_of(work, struct pushbutton_work_info, work);
  323. struct slot *p_slot = info->p_slot;
  324. mutex_lock(&p_slot->lock);
  325. switch (p_slot->state) {
  326. case POWEROFF_STATE:
  327. mutex_unlock(&p_slot->lock);
  328. shpchp_disable_slot(p_slot);
  329. mutex_lock(&p_slot->lock);
  330. p_slot->state = STATIC_STATE;
  331. break;
  332. case POWERON_STATE:
  333. mutex_unlock(&p_slot->lock);
  334. if (shpchp_enable_slot(p_slot))
  335. p_slot->hpc_ops->green_led_off(p_slot);
  336. mutex_lock(&p_slot->lock);
  337. p_slot->state = STATIC_STATE;
  338. break;
  339. default:
  340. break;
  341. }
  342. mutex_unlock(&p_slot->lock);
  343. kfree(info);
  344. }
  345. void shpchp_queue_pushbutton_work(struct work_struct *work)
  346. {
  347. struct slot *p_slot = container_of(work, struct slot, work.work);
  348. struct pushbutton_work_info *info;
  349. info = kmalloc(sizeof(*info), GFP_KERNEL);
  350. if (!info) {
  351. ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
  352. __func__);
  353. return;
  354. }
  355. info->p_slot = p_slot;
  356. INIT_WORK(&info->work, shpchp_pushbutton_thread);
  357. mutex_lock(&p_slot->lock);
  358. switch (p_slot->state) {
  359. case BLINKINGOFF_STATE:
  360. p_slot->state = POWEROFF_STATE;
  361. break;
  362. case BLINKINGON_STATE:
  363. p_slot->state = POWERON_STATE;
  364. break;
  365. default:
  366. kfree(info);
  367. goto out;
  368. }
  369. queue_work(p_slot->wq, &info->work);
  370. out:
  371. mutex_unlock(&p_slot->lock);
  372. }
  373. static void update_slot_info(struct slot *slot)
  374. {
  375. slot->hpc_ops->get_power_status(slot, &slot->pwr_save);
  376. slot->hpc_ops->get_attention_status(slot, &slot->attention_save);
  377. slot->hpc_ops->get_latch_status(slot, &slot->latch_save);
  378. slot->hpc_ops->get_adapter_status(slot, &slot->presence_save);
  379. }
  380. /*
  381. * Note: This function must be called with slot->lock held
  382. */
  383. static void handle_button_press_event(struct slot *p_slot)
  384. {
  385. u8 getstatus;
  386. struct controller *ctrl = p_slot->ctrl;
  387. switch (p_slot->state) {
  388. case STATIC_STATE:
  389. p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  390. if (getstatus) {
  391. p_slot->state = BLINKINGOFF_STATE;
  392. ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n",
  393. slot_name(p_slot));
  394. } else {
  395. p_slot->state = BLINKINGON_STATE;
  396. ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n",
  397. slot_name(p_slot));
  398. }
  399. /* blink green LED and turn off amber */
  400. p_slot->hpc_ops->green_led_blink(p_slot);
  401. p_slot->hpc_ops->set_attention_status(p_slot, 0);
  402. queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
  403. break;
  404. case BLINKINGOFF_STATE:
  405. case BLINKINGON_STATE:
  406. /*
  407. * Cancel if we are still blinking; this means that we
  408. * press the attention again before the 5 sec. limit
  409. * expires to cancel hot-add or hot-remove
  410. */
  411. ctrl_info(ctrl, "Button cancel on Slot(%s)\n",
  412. slot_name(p_slot));
  413. cancel_delayed_work(&p_slot->work);
  414. if (p_slot->state == BLINKINGOFF_STATE)
  415. p_slot->hpc_ops->green_led_on(p_slot);
  416. else
  417. p_slot->hpc_ops->green_led_off(p_slot);
  418. p_slot->hpc_ops->set_attention_status(p_slot, 0);
  419. ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n",
  420. slot_name(p_slot));
  421. p_slot->state = STATIC_STATE;
  422. break;
  423. case POWEROFF_STATE:
  424. case POWERON_STATE:
  425. /*
  426. * Ignore if the slot is on power-on or power-off state;
  427. * this means that the previous attention button action
  428. * to hot-add or hot-remove is undergoing
  429. */
  430. ctrl_info(ctrl, "Button ignore on Slot(%s)\n",
  431. slot_name(p_slot));
  432. update_slot_info(p_slot);
  433. break;
  434. default:
  435. ctrl_warn(ctrl, "Not a valid state\n");
  436. break;
  437. }
  438. }
  439. static void interrupt_event_handler(struct work_struct *work)
  440. {
  441. struct event_info *info = container_of(work, struct event_info, work);
  442. struct slot *p_slot = info->p_slot;
  443. mutex_lock(&p_slot->lock);
  444. switch (info->event_type) {
  445. case INT_BUTTON_PRESS:
  446. handle_button_press_event(p_slot);
  447. break;
  448. case INT_POWER_FAULT:
  449. ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__);
  450. p_slot->hpc_ops->set_attention_status(p_slot, 1);
  451. p_slot->hpc_ops->green_led_off(p_slot);
  452. break;
  453. default:
  454. update_slot_info(p_slot);
  455. break;
  456. }
  457. mutex_unlock(&p_slot->lock);
  458. kfree(info);
  459. }
  460. static int shpchp_enable_slot (struct slot *p_slot)
  461. {
  462. u8 getstatus = 0;
  463. int rc, retval = -ENODEV;
  464. struct controller *ctrl = p_slot->ctrl;
  465. /* Check to see if (latch closed, card present, power off) */
  466. mutex_lock(&p_slot->ctrl->crit_sect);
  467. rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
  468. if (rc || !getstatus) {
  469. ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
  470. goto out;
  471. }
  472. rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  473. if (rc || getstatus) {
  474. ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
  475. goto out;
  476. }
  477. rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  478. if (rc || getstatus) {
  479. ctrl_info(ctrl, "Already enabled on slot(%s)\n",
  480. slot_name(p_slot));
  481. goto out;
  482. }
  483. p_slot->is_a_board = 1;
  484. /* We have to save the presence info for these slots */
  485. p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
  486. p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
  487. ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
  488. p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  489. if ((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD &&
  490. p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)
  491. && p_slot->ctrl->num_slots == 1) {
  492. /* handle AMD POGO errata; this must be done before enable */
  493. amd_pogo_errata_save_misc_reg(p_slot);
  494. retval = board_added(p_slot);
  495. /* handle AMD POGO errata; this must be done after enable */
  496. amd_pogo_errata_restore_misc_reg(p_slot);
  497. } else
  498. retval = board_added(p_slot);
  499. if (retval) {
  500. p_slot->hpc_ops->get_adapter_status(p_slot,
  501. &(p_slot->presence_save));
  502. p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  503. }
  504. update_slot_info(p_slot);
  505. out:
  506. mutex_unlock(&p_slot->ctrl->crit_sect);
  507. return retval;
  508. }
  509. static int shpchp_disable_slot (struct slot *p_slot)
  510. {
  511. u8 getstatus = 0;
  512. int rc, retval = -ENODEV;
  513. struct controller *ctrl = p_slot->ctrl;
  514. if (!p_slot->ctrl)
  515. return -ENODEV;
  516. /* Check to see if (latch closed, card present, power on) */
  517. mutex_lock(&p_slot->ctrl->crit_sect);
  518. rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
  519. if (rc || !getstatus) {
  520. ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
  521. goto out;
  522. }
  523. rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  524. if (rc || getstatus) {
  525. ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
  526. goto out;
  527. }
  528. rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  529. if (rc || !getstatus) {
  530. ctrl_info(ctrl, "Already disabled on slot(%s)\n",
  531. slot_name(p_slot));
  532. goto out;
  533. }
  534. retval = remove_board(p_slot);
  535. update_slot_info(p_slot);
  536. out:
  537. mutex_unlock(&p_slot->ctrl->crit_sect);
  538. return retval;
  539. }
  540. int shpchp_sysfs_enable_slot(struct slot *p_slot)
  541. {
  542. int retval = -ENODEV;
  543. struct controller *ctrl = p_slot->ctrl;
  544. mutex_lock(&p_slot->lock);
  545. switch (p_slot->state) {
  546. case BLINKINGON_STATE:
  547. cancel_delayed_work(&p_slot->work);
  548. /* fall through */
  549. case STATIC_STATE:
  550. p_slot->state = POWERON_STATE;
  551. mutex_unlock(&p_slot->lock);
  552. retval = shpchp_enable_slot(p_slot);
  553. mutex_lock(&p_slot->lock);
  554. p_slot->state = STATIC_STATE;
  555. break;
  556. case POWERON_STATE:
  557. ctrl_info(ctrl, "Slot %s is already in powering on state\n",
  558. slot_name(p_slot));
  559. break;
  560. case BLINKINGOFF_STATE:
  561. case POWEROFF_STATE:
  562. ctrl_info(ctrl, "Already enabled on slot %s\n",
  563. slot_name(p_slot));
  564. break;
  565. default:
  566. ctrl_err(ctrl, "Not a valid state on slot %s\n",
  567. slot_name(p_slot));
  568. break;
  569. }
  570. mutex_unlock(&p_slot->lock);
  571. return retval;
  572. }
  573. int shpchp_sysfs_disable_slot(struct slot *p_slot)
  574. {
  575. int retval = -ENODEV;
  576. struct controller *ctrl = p_slot->ctrl;
  577. mutex_lock(&p_slot->lock);
  578. switch (p_slot->state) {
  579. case BLINKINGOFF_STATE:
  580. cancel_delayed_work(&p_slot->work);
  581. /* fall through */
  582. case STATIC_STATE:
  583. p_slot->state = POWEROFF_STATE;
  584. mutex_unlock(&p_slot->lock);
  585. retval = shpchp_disable_slot(p_slot);
  586. mutex_lock(&p_slot->lock);
  587. p_slot->state = STATIC_STATE;
  588. break;
  589. case POWEROFF_STATE:
  590. ctrl_info(ctrl, "Slot %s is already in powering off state\n",
  591. slot_name(p_slot));
  592. break;
  593. case BLINKINGON_STATE:
  594. case POWERON_STATE:
  595. ctrl_info(ctrl, "Already disabled on slot %s\n",
  596. slot_name(p_slot));
  597. break;
  598. default:
  599. ctrl_err(ctrl, "Not a valid state on slot %s\n",
  600. slot_name(p_slot));
  601. break;
  602. }
  603. mutex_unlock(&p_slot->lock);
  604. return retval;
  605. }