pciehp_ctrl.c 23 KB

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