shpchp_ctrl.c 18 KB

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