pciehp_ctrl.c 21 KB

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