pciehp_ctrl.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. /*
  2. * PCI Express 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 "../pci.h"
  35. #include "pciehp.h"
  36. static void interrupt_event_handler(struct controller *ctrl);
  37. static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
  38. static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
  39. static int event_finished;
  40. static unsigned long pushbutton_pending; /* = 0 */
  41. static unsigned long surprise_rm_pending; /* = 0 */
  42. static inline char *slot_name(struct slot *p_slot)
  43. {
  44. return p_slot->hotplug_slot->name;
  45. }
  46. u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
  47. {
  48. struct slot *p_slot;
  49. u8 rc = 0;
  50. u8 getstatus;
  51. struct event_info *taskInfo;
  52. /* Attention Button Change */
  53. dbg("pciehp: Attention button interrupt received.\n");
  54. /* This is the structure that tells the worker thread what to do */
  55. taskInfo = &(ctrl->event_queue[ctrl->next_event]);
  56. p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  57. p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  58. ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
  59. taskInfo->hp_slot = hp_slot;
  60. rc++;
  61. /*
  62. * Button pressed - See if need to TAKE ACTION!!!
  63. */
  64. info("Button pressed on Slot(%s)\n", slot_name(p_slot));
  65. taskInfo->event_type = INT_BUTTON_PRESS;
  66. if ((p_slot->state == BLINKINGON_STATE)
  67. || (p_slot->state == BLINKINGOFF_STATE)) {
  68. /* Cancel if we are still blinking; this means that we press the
  69. * attention again before the 5 sec. limit expires to cancel hot-add
  70. * or hot-remove
  71. */
  72. taskInfo->event_type = INT_BUTTON_CANCEL;
  73. info("Button cancel on Slot(%s)\n", slot_name(p_slot));
  74. } else if ((p_slot->state == POWERON_STATE)
  75. || (p_slot->state == POWEROFF_STATE)) {
  76. /* Ignore if the slot is on power-on or power-off state; this
  77. * means that the previous attention button action to hot-add or
  78. * hot-remove is undergoing
  79. */
  80. taskInfo->event_type = INT_BUTTON_IGNORE;
  81. info("Button ignore on Slot(%s)\n", slot_name(p_slot));
  82. }
  83. if (rc)
  84. up(&event_semaphore); /* signal event thread that new event is posted */
  85. return 0;
  86. }
  87. u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
  88. {
  89. struct slot *p_slot;
  90. u8 rc = 0;
  91. u8 getstatus;
  92. struct event_info *taskInfo;
  93. /* Switch Change */
  94. dbg("pciehp: Switch interrupt received.\n");
  95. /* This is the structure that tells the worker thread
  96. * what to do
  97. */
  98. taskInfo = &(ctrl->event_queue[ctrl->next_event]);
  99. ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
  100. taskInfo->hp_slot = hp_slot;
  101. rc++;
  102. p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  103. p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  104. if (getstatus) {
  105. /*
  106. * Switch opened
  107. */
  108. info("Latch open on Slot(%s)\n", slot_name(p_slot));
  109. taskInfo->event_type = INT_SWITCH_OPEN;
  110. } else {
  111. /*
  112. * Switch closed
  113. */
  114. info("Latch close on Slot(%s)\n", slot_name(p_slot));
  115. taskInfo->event_type = INT_SWITCH_CLOSE;
  116. }
  117. if (rc)
  118. up(&event_semaphore); /* signal event thread that new event is posted */
  119. return rc;
  120. }
  121. u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
  122. {
  123. struct slot *p_slot;
  124. u8 presence_save, rc = 0;
  125. struct event_info *taskInfo;
  126. /* Presence Change */
  127. dbg("pciehp: Presence/Notify input change.\n");
  128. /* This is the structure that tells the worker thread
  129. * what to do
  130. */
  131. taskInfo = &(ctrl->event_queue[ctrl->next_event]);
  132. ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
  133. taskInfo->hp_slot = hp_slot;
  134. rc++;
  135. p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  136. /* Switch is open, assume a presence change
  137. * Save the presence state
  138. */
  139. p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save);
  140. if (presence_save) {
  141. /*
  142. * Card Present
  143. */
  144. info("Card present on Slot(%s)\n", slot_name(p_slot));
  145. taskInfo->event_type = INT_PRESENCE_ON;
  146. } else {
  147. /*
  148. * Not Present
  149. */
  150. info("Card not present on Slot(%s)\n", slot_name(p_slot));
  151. taskInfo->event_type = INT_PRESENCE_OFF;
  152. }
  153. if (rc)
  154. up(&event_semaphore); /* signal event thread that new event is posted */
  155. return rc;
  156. }
  157. u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
  158. {
  159. struct slot *p_slot;
  160. u8 rc = 0;
  161. struct event_info *taskInfo;
  162. /* power fault */
  163. dbg("pciehp: Power fault interrupt received.\n");
  164. /* this is the structure that tells the worker thread
  165. * what to do
  166. */
  167. taskInfo = &(ctrl->event_queue[ctrl->next_event]);
  168. ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
  169. taskInfo->hp_slot = hp_slot;
  170. rc++;
  171. p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  172. if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
  173. /*
  174. * power fault Cleared
  175. */
  176. info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
  177. taskInfo->event_type = INT_POWER_FAULT_CLEAR;
  178. } else {
  179. /*
  180. * power fault
  181. */
  182. info("Power fault on Slot(%s)\n", slot_name(p_slot));
  183. taskInfo->event_type = INT_POWER_FAULT;
  184. info("power fault bit %x set\n", hp_slot);
  185. }
  186. if (rc)
  187. up(&event_semaphore); /* signal event thread that new event is posted */
  188. return rc;
  189. }
  190. /* The following routines constitute the bulk of the
  191. hotplug controller logic
  192. */
  193. static void set_slot_off(struct controller *ctrl, struct slot * pslot)
  194. {
  195. /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
  196. if (POWER_CTRL(ctrl->ctrlcap)) {
  197. if (pslot->hpc_ops->power_off_slot(pslot)) {
  198. err("%s: Issue of Slot Power Off command failed\n",
  199. __FUNCTION__);
  200. return;
  201. }
  202. }
  203. if (PWR_LED(ctrl->ctrlcap))
  204. pslot->hpc_ops->green_led_off(pslot);
  205. if (ATTN_LED(ctrl->ctrlcap)) {
  206. if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
  207. err("%s: Issue of Set Attention Led command failed\n",
  208. __FUNCTION__);
  209. return;
  210. }
  211. }
  212. }
  213. /**
  214. * board_added - Called after a board has been added to the system.
  215. *
  216. * Turns power on for the board
  217. * Configures board
  218. *
  219. */
  220. static int board_added(struct slot *p_slot)
  221. {
  222. u8 hp_slot;
  223. int retval = 0;
  224. struct controller *ctrl = p_slot->ctrl;
  225. hp_slot = p_slot->device - ctrl->slot_device_offset;
  226. dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
  227. __FUNCTION__, p_slot->device,
  228. ctrl->slot_device_offset, hp_slot);
  229. if (POWER_CTRL(ctrl->ctrlcap)) {
  230. /* Power on slot */
  231. retval = p_slot->hpc_ops->power_on_slot(p_slot);
  232. if (retval)
  233. return retval;
  234. }
  235. if (PWR_LED(ctrl->ctrlcap))
  236. p_slot->hpc_ops->green_led_blink(p_slot);
  237. /* Wait for ~1 second */
  238. msleep(1000);
  239. /* Check link training status */
  240. retval = p_slot->hpc_ops->check_lnk_status(ctrl);
  241. if (retval) {
  242. err("%s: Failed to check link status\n", __FUNCTION__);
  243. set_slot_off(ctrl, p_slot);
  244. return retval;
  245. }
  246. /* Check for a power fault */
  247. if (p_slot->hpc_ops->query_power_fault(p_slot)) {
  248. dbg("%s: power fault detected\n", __FUNCTION__);
  249. retval = POWER_FAILURE;
  250. goto err_exit;
  251. }
  252. retval = pciehp_configure_device(p_slot);
  253. if (retval) {
  254. err("Cannot add device 0x%x:%x\n", p_slot->bus,
  255. p_slot->device);
  256. goto err_exit;
  257. }
  258. /*
  259. * Some PCI Express root ports require fixup after hot-plug operation.
  260. */
  261. if (pcie_mch_quirk)
  262. pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
  263. if (PWR_LED(ctrl->ctrlcap))
  264. p_slot->hpc_ops->green_led_on(p_slot);
  265. return 0;
  266. err_exit:
  267. set_slot_off(ctrl, p_slot);
  268. return retval;
  269. }
  270. /**
  271. * remove_board - Turns off slot and LED's
  272. *
  273. */
  274. static int remove_board(struct slot *p_slot)
  275. {
  276. u8 device;
  277. u8 hp_slot;
  278. int retval = 0;
  279. struct controller *ctrl = p_slot->ctrl;
  280. retval = pciehp_unconfigure_device(p_slot);
  281. if (retval)
  282. return retval;
  283. device = p_slot->device;
  284. hp_slot = p_slot->device - ctrl->slot_device_offset;
  285. p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  286. dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
  287. if (POWER_CTRL(ctrl->ctrlcap)) {
  288. /* power off slot */
  289. retval = p_slot->hpc_ops->power_off_slot(p_slot);
  290. if (retval) {
  291. err("%s: Issue of Slot Disable command failed\n",
  292. __FUNCTION__);
  293. return retval;
  294. }
  295. }
  296. if (PWR_LED(ctrl->ctrlcap))
  297. /* turn off Green LED */
  298. p_slot->hpc_ops->green_led_off(p_slot);
  299. return 0;
  300. }
  301. static void pushbutton_helper_thread(unsigned long data)
  302. {
  303. pushbutton_pending = data;
  304. up(&event_semaphore);
  305. }
  306. /**
  307. * pciehp_pushbutton_thread
  308. *
  309. * Scheduled procedure to handle blocking stuff for the pushbuttons
  310. * Handles all pending events and exits.
  311. *
  312. */
  313. static void pciehp_pushbutton_thread(unsigned long slot)
  314. {
  315. struct slot *p_slot = (struct slot *) slot;
  316. u8 getstatus;
  317. pushbutton_pending = 0;
  318. if (!p_slot) {
  319. dbg("%s: Error! slot NULL\n", __FUNCTION__);
  320. return;
  321. }
  322. p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  323. if (getstatus) {
  324. p_slot->state = POWEROFF_STATE;
  325. dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__,
  326. p_slot->bus, p_slot->device);
  327. pciehp_disable_slot(p_slot);
  328. p_slot->state = STATIC_STATE;
  329. } else {
  330. p_slot->state = POWERON_STATE;
  331. dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
  332. p_slot->bus, p_slot->device);
  333. if (pciehp_enable_slot(p_slot) &&
  334. PWR_LED(p_slot->ctrl->ctrlcap))
  335. p_slot->hpc_ops->green_led_off(p_slot);
  336. p_slot->state = STATIC_STATE;
  337. }
  338. return;
  339. }
  340. /**
  341. * pciehp_surprise_rm_thread
  342. *
  343. * Scheduled procedure to handle blocking stuff for the surprise removal
  344. * Handles all pending events and exits.
  345. *
  346. */
  347. static void pciehp_surprise_rm_thread(unsigned long slot)
  348. {
  349. struct slot *p_slot = (struct slot *) slot;
  350. u8 getstatus;
  351. surprise_rm_pending = 0;
  352. if (!p_slot) {
  353. dbg("%s: Error! slot NULL\n", __FUNCTION__);
  354. return;
  355. }
  356. p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
  357. if (!getstatus) {
  358. p_slot->state = POWEROFF_STATE;
  359. dbg("%s: removing bus:device(%x:%x)\n",
  360. __FUNCTION__, p_slot->bus, p_slot->device);
  361. pciehp_disable_slot(p_slot);
  362. p_slot->state = STATIC_STATE;
  363. } else {
  364. p_slot->state = POWERON_STATE;
  365. dbg("%s: adding bus:device(%x:%x)\n",
  366. __FUNCTION__, p_slot->bus, p_slot->device);
  367. if (pciehp_enable_slot(p_slot) &&
  368. PWR_LED(p_slot->ctrl->ctrlcap))
  369. p_slot->hpc_ops->green_led_off(p_slot);
  370. p_slot->state = STATIC_STATE;
  371. }
  372. return;
  373. }
  374. /* this is the main worker thread */
  375. static int event_thread(void* data)
  376. {
  377. struct controller *ctrl;
  378. lock_kernel();
  379. daemonize("pciehpd_event");
  380. unlock_kernel();
  381. while (1) {
  382. dbg("!!!!event_thread sleeping\n");
  383. down_interruptible (&event_semaphore);
  384. dbg("event_thread woken finished = %d\n", event_finished);
  385. if (event_finished || signal_pending(current))
  386. break;
  387. /* Do stuff here */
  388. if (pushbutton_pending)
  389. pciehp_pushbutton_thread(pushbutton_pending);
  390. else if (surprise_rm_pending)
  391. pciehp_surprise_rm_thread(surprise_rm_pending);
  392. else
  393. for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
  394. interrupt_event_handler(ctrl);
  395. }
  396. dbg("event_thread signals exit\n");
  397. up(&event_exit);
  398. return 0;
  399. }
  400. int pciehp_event_start_thread(void)
  401. {
  402. int pid;
  403. /* initialize our semaphores */
  404. init_MUTEX_LOCKED(&event_exit);
  405. event_finished=0;
  406. init_MUTEX_LOCKED(&event_semaphore);
  407. pid = kernel_thread(event_thread, NULL, 0);
  408. if (pid < 0) {
  409. err ("Can't start up our event thread\n");
  410. return -1;
  411. }
  412. return 0;
  413. }
  414. void pciehp_event_stop_thread(void)
  415. {
  416. event_finished = 1;
  417. up(&event_semaphore);
  418. down(&event_exit);
  419. }
  420. static int update_slot_info(struct slot *slot)
  421. {
  422. struct hotplug_slot_info *info;
  423. /* char buffer[SLOT_NAME_SIZE]; */
  424. int result;
  425. info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
  426. if (!info)
  427. return -ENOMEM;
  428. /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
  429. slot->hpc_ops->get_power_status(slot, &(info->power_status));
  430. slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
  431. slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
  432. slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
  433. /* result = pci_hp_change_slot_info(buffer, info); */
  434. result = pci_hp_change_slot_info(slot->hotplug_slot, info);
  435. kfree (info);
  436. return result;
  437. }
  438. static void interrupt_event_handler(struct controller *ctrl)
  439. {
  440. int loop = 0;
  441. int change = 1;
  442. u8 hp_slot;
  443. u8 getstatus;
  444. struct slot *p_slot;
  445. while (change) {
  446. change = 0;
  447. for (loop = 0; loop < MAX_EVENTS; loop++) {
  448. if (ctrl->event_queue[loop].event_type != 0) {
  449. hp_slot = ctrl->event_queue[loop].hp_slot;
  450. p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
  451. if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
  452. dbg("button cancel\n");
  453. del_timer(&p_slot->task_event);
  454. switch (p_slot->state) {
  455. case BLINKINGOFF_STATE:
  456. if (PWR_LED(ctrl->ctrlcap))
  457. p_slot->hpc_ops->green_led_on(p_slot);
  458. if (ATTN_LED(ctrl->ctrlcap))
  459. p_slot->hpc_ops->set_attention_status(p_slot, 0);
  460. break;
  461. case BLINKINGON_STATE:
  462. if (PWR_LED(ctrl->ctrlcap))
  463. p_slot->hpc_ops->green_led_off(p_slot);
  464. if (ATTN_LED(ctrl->ctrlcap))
  465. p_slot->hpc_ops->set_attention_status(p_slot, 0);
  466. break;
  467. default:
  468. warn("Not a valid state\n");
  469. return;
  470. }
  471. info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
  472. p_slot->state = STATIC_STATE;
  473. }
  474. /* ***********Button Pressed (No action on 1st press...) */
  475. else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
  476. if (ATTN_BUTTN(ctrl->ctrlcap)) {
  477. dbg("Button pressed\n");
  478. p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  479. if (getstatus) {
  480. /* slot is on */
  481. dbg("slot is on\n");
  482. p_slot->state = BLINKINGOFF_STATE;
  483. info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
  484. } else {
  485. /* slot is off */
  486. dbg("slot is off\n");
  487. p_slot->state = BLINKINGON_STATE;
  488. info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
  489. }
  490. /* blink green LED and turn off amber */
  491. if (PWR_LED(ctrl->ctrlcap))
  492. p_slot->hpc_ops->green_led_blink(p_slot);
  493. if (ATTN_LED(ctrl->ctrlcap))
  494. p_slot->hpc_ops->set_attention_status(p_slot, 0);
  495. init_timer(&p_slot->task_event);
  496. p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
  497. p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
  498. p_slot->task_event.data = (unsigned long) p_slot;
  499. add_timer(&p_slot->task_event);
  500. }
  501. }
  502. /***********POWER FAULT********************/
  503. else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
  504. if (POWER_CTRL(ctrl->ctrlcap)) {
  505. dbg("power fault\n");
  506. if (ATTN_LED(ctrl->ctrlcap))
  507. p_slot->hpc_ops->set_attention_status(p_slot, 1);
  508. if (PWR_LED(ctrl->ctrlcap))
  509. p_slot->hpc_ops->green_led_off(p_slot);
  510. }
  511. }
  512. /***********SURPRISE REMOVAL********************/
  513. else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) ||
  514. (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
  515. if (HP_SUPR_RM(ctrl->ctrlcap)) {
  516. dbg("Surprise Removal\n");
  517. if (p_slot) {
  518. surprise_rm_pending = (unsigned long) p_slot;
  519. up(&event_semaphore);
  520. update_slot_info(p_slot);
  521. }
  522. }
  523. } else {
  524. /* refresh notification */
  525. if (p_slot)
  526. update_slot_info(p_slot);
  527. }
  528. ctrl->event_queue[loop].event_type = 0;
  529. change = 1;
  530. }
  531. } /* End of FOR loop */
  532. }
  533. }
  534. int pciehp_enable_slot(struct slot *p_slot)
  535. {
  536. u8 getstatus = 0;
  537. int rc;
  538. /* Check to see if (latch closed, card present, power off) */
  539. mutex_lock(&p_slot->ctrl->crit_sect);
  540. rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
  541. if (rc || !getstatus) {
  542. info("%s: no adapter on slot(%s)\n", __FUNCTION__,
  543. slot_name(p_slot));
  544. mutex_unlock(&p_slot->ctrl->crit_sect);
  545. return -ENODEV;
  546. }
  547. if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
  548. rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  549. if (rc || getstatus) {
  550. info("%s: latch open on slot(%s)\n", __FUNCTION__,
  551. slot_name(p_slot));
  552. mutex_unlock(&p_slot->ctrl->crit_sect);
  553. return -ENODEV;
  554. }
  555. }
  556. if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
  557. rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  558. if (rc || getstatus) {
  559. info("%s: already enabled on slot(%s)\n", __FUNCTION__,
  560. slot_name(p_slot));
  561. mutex_unlock(&p_slot->ctrl->crit_sect);
  562. return -EINVAL;
  563. }
  564. }
  565. p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  566. rc = board_added(p_slot);
  567. if (rc) {
  568. p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  569. }
  570. update_slot_info(p_slot);
  571. mutex_unlock(&p_slot->ctrl->crit_sect);
  572. return rc;
  573. }
  574. int pciehp_disable_slot(struct slot *p_slot)
  575. {
  576. u8 getstatus = 0;
  577. int ret = 0;
  578. if (!p_slot->ctrl)
  579. return 1;
  580. /* Check to see if (latch closed, card present, power on) */
  581. mutex_lock(&p_slot->ctrl->crit_sect);
  582. if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
  583. ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
  584. if (ret || !getstatus) {
  585. info("%s: no adapter on slot(%s)\n", __FUNCTION__,
  586. slot_name(p_slot));
  587. mutex_unlock(&p_slot->ctrl->crit_sect);
  588. return -ENODEV;
  589. }
  590. }
  591. if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
  592. ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
  593. if (ret || getstatus) {
  594. info("%s: latch open on slot(%s)\n", __FUNCTION__,
  595. slot_name(p_slot));
  596. mutex_unlock(&p_slot->ctrl->crit_sect);
  597. return -ENODEV;
  598. }
  599. }
  600. if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
  601. ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
  602. if (ret || !getstatus) {
  603. info("%s: already disabled slot(%s)\n", __FUNCTION__,
  604. slot_name(p_slot));
  605. mutex_unlock(&p_slot->ctrl->crit_sect);
  606. return -EINVAL;
  607. }
  608. }
  609. ret = remove_board(p_slot);
  610. update_slot_info(p_slot);
  611. mutex_unlock(&p_slot->ctrl->crit_sect);
  612. return ret;
  613. }