]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/pci/hotplug/pciehp_ctrl.c
[PATCH] pciehp: reduce dependence on ACPI
[mirror_ubuntu-bionic-kernel.git] / drivers / pci / hotplug / pciehp_ctrl.c
CommitLineData
1da177e4
LT
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 *
8cf4c195 26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
1da177e4
LT
27 *
28 */
29
30#include <linux/config.h>
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/types.h>
34#include <linux/slab.h>
35#include <linux/workqueue.h>
36#include <linux/interrupt.h>
37#include <linux/delay.h>
38#include <linux/wait.h>
39#include <linux/smp_lock.h>
40#include <linux/pci.h>
41#include "../pci.h"
42#include "pciehp.h"
1da177e4 43
1da177e4
LT
44static void interrupt_event_handler(struct controller *ctrl);
45
46static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
47static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
48static int event_finished;
49static unsigned long pushbutton_pending; /* = 0 */
50static unsigned long surprise_rm_pending; /* = 0 */
51
52u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
53{
54 struct controller *ctrl = (struct controller *) inst_id;
55 struct slot *p_slot;
56 u8 rc = 0;
57 u8 getstatus;
58 struct pci_func *func;
59 struct event_info *taskInfo;
60
61 /* Attention Button Change */
62 dbg("pciehp: Attention button interrupt received.\n");
63
64 func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
65
66 /* This is the structure that tells the worker thread what to do */
67 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
68 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
69
70 p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
71 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
72
73 ctrl->next_event = (ctrl->next_event + 1) % 10;
74 taskInfo->hp_slot = hp_slot;
75
76 rc++;
77
78 /*
79 * Button pressed - See if need to TAKE ACTION!!!
80 */
81 info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
82 taskInfo->event_type = INT_BUTTON_PRESS;
83
84 if ((p_slot->state == BLINKINGON_STATE)
85 || (p_slot->state == BLINKINGOFF_STATE)) {
86 /* Cancel if we are still blinking; this means that we press the
87 * attention again before the 5 sec. limit expires to cancel hot-add
88 * or hot-remove
89 */
90 taskInfo->event_type = INT_BUTTON_CANCEL;
91 info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
92 } else if ((p_slot->state == POWERON_STATE)
93 || (p_slot->state == POWEROFF_STATE)) {
94 /* Ignore if the slot is on power-on or power-off state; this
95 * means that the previous attention button action to hot-add or
96 * hot-remove is undergoing
97 */
98 taskInfo->event_type = INT_BUTTON_IGNORE;
99 info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
100 }
101
102 if (rc)
103 up(&event_semaphore); /* signal event thread that new event is posted */
104
105 return 0;
106
107}
108
109u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
110{
111 struct controller *ctrl = (struct controller *) inst_id;
112 struct slot *p_slot;
113 u8 rc = 0;
114 u8 getstatus;
115 struct pci_func *func;
116 struct event_info *taskInfo;
117
118 /* Switch Change */
119 dbg("pciehp: Switch interrupt received.\n");
120
121 func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
122
123 /* This is the structure that tells the worker thread
124 * what to do
125 */
126 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
127 ctrl->next_event = (ctrl->next_event + 1) % 10;
128 taskInfo->hp_slot = hp_slot;
129
130 rc++;
131 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
132 p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
133 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
134
135 if (getstatus) {
136 /*
137 * Switch opened
138 */
139 info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
140 func->switch_save = 0;
141 taskInfo->event_type = INT_SWITCH_OPEN;
142 } else {
143 /*
144 * Switch closed
145 */
146 info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
147 func->switch_save = 0x10;
148 taskInfo->event_type = INT_SWITCH_CLOSE;
149 }
150
151 if (rc)
152 up(&event_semaphore); /* signal event thread that new event is posted */
153
154 return rc;
155}
156
157u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
158{
159 struct controller *ctrl = (struct controller *) inst_id;
160 struct slot *p_slot;
161 u8 rc = 0;
162 struct pci_func *func;
163 struct event_info *taskInfo;
164
165 /* Presence Change */
166 dbg("pciehp: Presence/Notify input change.\n");
167
168 func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
169
170 /* This is the structure that tells the worker thread
171 * what to do
172 */
173 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
174 ctrl->next_event = (ctrl->next_event + 1) % 10;
175 taskInfo->hp_slot = hp_slot;
176
177 rc++;
178 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
179
180 /* Switch is open, assume a presence change
181 * Save the presence state
182 */
183 p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
184 if (func->presence_save) {
185 /*
186 * Card Present
187 */
188 info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
189 taskInfo->event_type = INT_PRESENCE_ON;
190 } else {
191 /*
192 * Not Present
193 */
194 info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
195 taskInfo->event_type = INT_PRESENCE_OFF;
196 }
197
198 if (rc)
199 up(&event_semaphore); /* signal event thread that new event is posted */
200
201 return rc;
202}
203
204u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
205{
206 struct controller *ctrl = (struct controller *) inst_id;
207 struct slot *p_slot;
208 u8 rc = 0;
209 struct pci_func *func;
210 struct event_info *taskInfo;
211
212 /* power fault */
213 dbg("pciehp: Power fault interrupt received.\n");
214
215 func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
216
217 /* this is the structure that tells the worker thread
218 * what to do
219 */
220 taskInfo = &(ctrl->event_queue[ctrl->next_event]);
221 ctrl->next_event = (ctrl->next_event + 1) % 10;
222 taskInfo->hp_slot = hp_slot;
223
224 rc++;
225 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
226
227 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
228 /*
229 * power fault Cleared
230 */
231 info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
232 func->status = 0x00;
233 taskInfo->event_type = INT_POWER_FAULT_CLEAR;
234 } else {
235 /*
236 * power fault
237 */
238 info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
239 taskInfo->event_type = INT_POWER_FAULT;
240 /* set power fault status for this board */
241 func->status = 0xFF;
242 info("power fault bit %x set\n", hp_slot);
243 }
244 if (rc)
245 up(&event_semaphore); /* signal event thread that new event is posted */
246
247 return rc;
248}
249
1da177e4
LT
250/**
251 * pciehp_slot_create - Creates a node and adds it to the proper bus.
252 * @busnumber - bus where new node is to be located
253 *
254 * Returns pointer to the new node or NULL if unsuccessful
255 */
256struct pci_func *pciehp_slot_create(u8 busnumber)
257{
258 struct pci_func *new_slot;
259 struct pci_func *next;
260 dbg("%s: busnumber %x\n", __FUNCTION__, busnumber);
261 new_slot = kmalloc(sizeof(struct pci_func), GFP_KERNEL);
262
263 if (new_slot == NULL)
264 return new_slot;
265
266 memset(new_slot, 0, sizeof(struct pci_func));
267
268 new_slot->next = NULL;
269 new_slot->configured = 1;
270
271 if (pciehp_slot_list[busnumber] == NULL) {
272 pciehp_slot_list[busnumber] = new_slot;
273 } else {
274 next = pciehp_slot_list[busnumber];
275 while (next->next != NULL)
276 next = next->next;
277 next->next = new_slot;
278 }
279 return new_slot;
280}
281
282
283/**
284 * slot_remove - Removes a node from the linked list of slots.
285 * @old_slot: slot to remove
286 *
287 * Returns 0 if successful, !0 otherwise.
288 */
289static int slot_remove(struct pci_func * old_slot)
290{
291 struct pci_func *next;
292
293 if (old_slot == NULL)
294 return 1;
295
296 next = pciehp_slot_list[old_slot->bus];
297
298 if (next == NULL)
299 return 1;
300
301 if (next == old_slot) {
302 pciehp_slot_list[old_slot->bus] = old_slot->next;
1da177e4
LT
303 kfree(old_slot);
304 return 0;
305 }
306
307 while ((next->next != old_slot) && (next->next != NULL)) {
308 next = next->next;
309 }
310
311 if (next->next == old_slot) {
312 next->next = old_slot->next;
1da177e4
LT
313 kfree(old_slot);
314 return 0;
315 } else
316 return 2;
317}
318
319
320/**
321 * bridge_slot_remove - Removes a node from the linked list of slots.
322 * @bridge: bridge to remove
323 *
324 * Returns 0 if successful, !0 otherwise.
325 */
326static int bridge_slot_remove(struct pci_func *bridge)
327{
328 u8 subordinateBus, secondaryBus;
329 u8 tempBus;
330 struct pci_func *next;
331
332 if (bridge == NULL)
333 return 1;
334
335 secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
336 subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
337
338 for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
339 next = pciehp_slot_list[tempBus];
340
341 while (!slot_remove(next)) {
342 next = pciehp_slot_list[tempBus];
343 }
344 }
345
346 next = pciehp_slot_list[bridge->bus];
347
348 if (next == NULL) {
349 return 1;
350 }
351
352 if (next == bridge) {
353 pciehp_slot_list[bridge->bus] = bridge->next;
354 kfree(bridge);
355 return 0;
356 }
357
358 while ((next->next != bridge) && (next->next != NULL)) {
359 next = next->next;
360 }
361
362 if (next->next == bridge) {
363 next->next = bridge->next;
364 kfree(bridge);
365 return 0;
366 } else
367 return 2;
368}
369
370
371/**
372 * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed
373 * @bus: bus to find
374 * @device: device to find
375 * @index: is 0 for first function found, 1 for the second...
376 *
377 * Returns pointer to the node if successful, %NULL otherwise.
378 */
379struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index)
380{
381 int found = -1;
382 struct pci_func *func;
383
384 func = pciehp_slot_list[bus];
385 dbg("%s: bus %x device %x index %x\n",
386 __FUNCTION__, bus, device, index);
387 if (func != NULL) {
388 dbg("%s: func-> bus %x device %x function %x pci_dev %p\n",
389 __FUNCTION__, func->bus, func->device, func->function,
390 func->pci_dev);
391 } else
392 dbg("%s: func == NULL\n", __FUNCTION__);
393
394 if ((func == NULL) || ((func->device == device) && (index == 0)))
395 return func;
396
397 if (func->device == device)
398 found++;
399
400 while (func->next != NULL) {
401 func = func->next;
402
403 dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n",
404 __FUNCTION__, func->bus, func->device, func->function,
405 func->pci_dev);
406 if (func->device == device)
407 found++;
408 dbg("%s: while loop, found %d, index %d\n", __FUNCTION__,
409 found, index);
410
411 if ((found == index) || (func->function == index)) {
412 dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__,
413 func->bus, func->device, func->function);
414 return func;
415 }
416 }
417
418 return NULL;
419}
420
421static int is_bridge(struct pci_func * func)
422{
423 /* Check the header type */
424 if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
425 return 1;
426 else
427 return 0;
428}
429
430
431/* The following routines constitute the bulk of the
432 hotplug controller logic
433 */
434
435static void set_slot_off(struct controller *ctrl, struct slot * pslot)
436{
437 /* Wait for exclusive access to hardware */
438 down(&ctrl->crit_sect);
439
440 /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
441 if (POWER_CTRL(ctrl->ctrlcap)) {
442 if (pslot->hpc_ops->power_off_slot(pslot)) {
443 err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
444 up(&ctrl->crit_sect);
445 return;
446 }
447 wait_for_ctrl_irq (ctrl);
448 }
449
450 if (PWR_LED(ctrl->ctrlcap)) {
451 pslot->hpc_ops->green_led_off(pslot);
452 wait_for_ctrl_irq (ctrl);
453 }
454
455 if (ATTN_LED(ctrl->ctrlcap)) {
456 if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
457 err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
458 up(&ctrl->crit_sect);
459 return;
460 }
461 wait_for_ctrl_irq (ctrl);
462 }
463
464 /* Done with exclusive hardware access */
465 up(&ctrl->crit_sect);
466}
467
468/**
469 * board_added - Called after a board has been added to the system.
470 *
471 * Turns power on for the board
472 * Configures board
473 *
474 */
475static u32 board_added(struct pci_func * func, struct controller * ctrl)
476{
477 u8 hp_slot;
1da177e4
LT
478 u32 temp_register = 0xFFFFFFFF;
479 u32 rc = 0;
1da177e4 480 struct slot *p_slot;
1da177e4
LT
481
482 p_slot = pciehp_find_slot(ctrl, func->device);
483 hp_slot = func->device - ctrl->slot_device_offset;
484
485 dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
486
487 /* Wait for exclusive access to hardware */
488 down(&ctrl->crit_sect);
489
490 if (POWER_CTRL(ctrl->ctrlcap)) {
491 /* Power on slot */
492 rc = p_slot->hpc_ops->power_on_slot(p_slot);
493 if (rc) {
494 up(&ctrl->crit_sect);
495 return -1;
496 }
497
498 /* Wait for the command to complete */
499 wait_for_ctrl_irq (ctrl);
500 }
501
502 if (PWR_LED(ctrl->ctrlcap)) {
503 p_slot->hpc_ops->green_led_blink(p_slot);
504
505 /* Wait for the command to complete */
506 wait_for_ctrl_irq (ctrl);
507 }
508
509 /* Done with exclusive hardware access */
510 up(&ctrl->crit_sect);
511
512 /* Wait for ~1 second */
513 dbg("%s: before long_delay\n", __FUNCTION__);
514 wait_for_ctrl_irq (ctrl);
515 dbg("%s: afterlong_delay\n", __FUNCTION__);
516
517 /* Check link training status */
518 rc = p_slot->hpc_ops->check_lnk_status(ctrl);
519 if (rc) {
520 err("%s: Failed to check link status\n", __FUNCTION__);
521 set_slot_off(ctrl, p_slot);
522 return rc;
523 }
524
525 dbg("%s: func status = %x\n", __FUNCTION__, func->status);
526
527 /* Check for a power fault */
528 if (func->status == 0xFF) {
529 /* power fault occurred, but it was benign */
530 temp_register = 0xFFFFFFFF;
531 dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
532 rc = POWER_FAILURE;
533 func->status = 0;
71b720c0 534 goto err_exit;
1da177e4
LT
535 }
536
71b720c0
RS
537 rc = pciehp_configure_device(p_slot);
538 if (rc) {
539 err("Cannot add device 0x%x:%x\n", p_slot->bus,
540 p_slot->device);
541 goto err_exit;
542 }
1da177e4 543
71b720c0
RS
544 pciehp_save_slot_config(ctrl, func);
545 func->status = 0;
546 func->switch_save = 0x10;
547 func->is_a_board = 0x01;
1da177e4 548
71b720c0
RS
549 /*
550 * Some PCI Express root ports require fixup after hot-plug operation.
551 */
552 if (pcie_mch_quirk)
553 pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
554 if (PWR_LED(ctrl->ctrlcap)) {
555 /* Wait for exclusive access to hardware */
556 down(&ctrl->crit_sect);
1da177e4 557
71b720c0 558 p_slot->hpc_ops->green_led_on(p_slot);
1da177e4 559
71b720c0
RS
560 /* Wait for the command to complete */
561 wait_for_ctrl_irq (ctrl);
1da177e4 562
71b720c0
RS
563 /* Done with exclusive hardware access */
564 up(&ctrl->crit_sect);
565 }
1da177e4 566 return 0;
71b720c0
RS
567
568err_exit:
569 set_slot_off(ctrl, p_slot);
570 return -1;
1da177e4
LT
571}
572
573
574/**
575 * remove_board - Turns off slot and LED's
576 *
577 */
578static u32 remove_board(struct pci_func *func, struct controller *ctrl)
579{
1da177e4
LT
580 u8 device;
581 u8 hp_slot;
582 u32 rc;
1da177e4
LT
583 struct slot *p_slot;
584
585 if (func == NULL)
586 return 1;
587
588 if (pciehp_unconfigure_device(func))
589 return 1;
590
591 device = func->device;
592
593 hp_slot = func->device - ctrl->slot_device_offset;
594 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
595
596 dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
597
1da177e4
LT
598 /* Change status to shutdown */
599 if (func->is_a_board)
600 func->status = 0x01;
601 func->configured = 0;
602
603 /* Wait for exclusive access to hardware */
604 down(&ctrl->crit_sect);
605
606 if (POWER_CTRL(ctrl->ctrlcap)) {
607 /* power off slot */
608 rc = p_slot->hpc_ops->power_off_slot(p_slot);
609 if (rc) {
610 err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
611 up(&ctrl->crit_sect);
612 return rc;
613 }
614 /* Wait for the command to complete */
615 wait_for_ctrl_irq (ctrl);
616 }
617
618 if (PWR_LED(ctrl->ctrlcap)) {
619 /* turn off Green LED */
620 p_slot->hpc_ops->green_led_off(p_slot);
621
622 /* Wait for the command to complete */
623 wait_for_ctrl_irq (ctrl);
624 }
625
626 /* Done with exclusive hardware access */
627 up(&ctrl->crit_sect);
628
629 if (ctrl->add_support) {
630 while (func) {
1da177e4
LT
631 if (is_bridge(func)) {
632 dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n",
633 ctrl->seg, func->bus, func->device, func->function);
634 bridge_slot_remove(func);
635 } else {
636 dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n",
637 ctrl->seg, func->bus, func->device, func->function);
638 slot_remove(func);
639 }
640
641 func = pciehp_slot_find(ctrl->slot_bus, device, 0);
642 }
643
644 /* Setup slot structure with entry for empty slot */
645 func = pciehp_slot_create(ctrl->slot_bus);
646
647 if (func == NULL) {
648 return 1;
649 }
650
651 func->bus = ctrl->slot_bus;
652 func->device = device;
653 func->function = 0;
654 func->configured = 0;
655 func->switch_save = 0x10;
656 func->is_a_board = 0;
657 }
658
659 return 0;
660}
661
662
663static void pushbutton_helper_thread(unsigned long data)
664{
665 pushbutton_pending = data;
666
667 up(&event_semaphore);
668}
669
670/**
671 * pciehp_pushbutton_thread
672 *
673 * Scheduled procedure to handle blocking stuff for the pushbuttons
674 * Handles all pending events and exits.
675 *
676 */
677static void pciehp_pushbutton_thread(unsigned long slot)
678{
679 struct slot *p_slot = (struct slot *) slot;
680 u8 getstatus;
681
682 pushbutton_pending = 0;
683
684 if (!p_slot) {
685 dbg("%s: Error! slot NULL\n", __FUNCTION__);
686 return;
687 }
688
689 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
690 if (getstatus) {
691 p_slot->state = POWEROFF_STATE;
692 dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
693
694 pciehp_disable_slot(p_slot);
695 p_slot->state = STATIC_STATE;
696 } else {
697 p_slot->state = POWERON_STATE;
698 dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
699
700 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
701 /* Wait for exclusive access to hardware */
702 down(&p_slot->ctrl->crit_sect);
703
704 p_slot->hpc_ops->green_led_off(p_slot);
705
706 /* Wait for the command to complete */
707 wait_for_ctrl_irq (p_slot->ctrl);
708
709 /* Done with exclusive hardware access */
710 up(&p_slot->ctrl->crit_sect);
711 }
712 p_slot->state = STATIC_STATE;
713 }
714
715 return;
716}
717
718/**
719 * pciehp_surprise_rm_thread
720 *
721 * Scheduled procedure to handle blocking stuff for the surprise removal
722 * Handles all pending events and exits.
723 *
724 */
725static void pciehp_surprise_rm_thread(unsigned long slot)
726{
727 struct slot *p_slot = (struct slot *) slot;
728 u8 getstatus;
729
730 surprise_rm_pending = 0;
731
732 if (!p_slot) {
733 dbg("%s: Error! slot NULL\n", __FUNCTION__);
734 return;
735 }
736
737 p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
738 if (!getstatus) {
739 p_slot->state = POWEROFF_STATE;
740 dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
741
742 pciehp_disable_slot(p_slot);
743 p_slot->state = STATIC_STATE;
744 } else {
745 p_slot->state = POWERON_STATE;
746 dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
747
748 if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
749 /* Wait for exclusive access to hardware */
750 down(&p_slot->ctrl->crit_sect);
751
752 p_slot->hpc_ops->green_led_off(p_slot);
753
754 /* Wait for the command to complete */
755 wait_for_ctrl_irq (p_slot->ctrl);
756
757 /* Done with exclusive hardware access */
758 up(&p_slot->ctrl->crit_sect);
759 }
760 p_slot->state = STATIC_STATE;
761 }
762
763 return;
764}
765
766
767
768/* this is the main worker thread */
769static int event_thread(void* data)
770{
771 struct controller *ctrl;
772 lock_kernel();
773 daemonize("pciehpd_event");
774
775 unlock_kernel();
776
777 while (1) {
778 dbg("!!!!event_thread sleeping\n");
779 down_interruptible (&event_semaphore);
780 dbg("event_thread woken finished = %d\n", event_finished);
781 if (event_finished || signal_pending(current))
782 break;
783 /* Do stuff here */
784 if (pushbutton_pending)
785 pciehp_pushbutton_thread(pushbutton_pending);
786 else if (surprise_rm_pending)
787 pciehp_surprise_rm_thread(surprise_rm_pending);
788 else
789 for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
790 interrupt_event_handler(ctrl);
791 }
792 dbg("event_thread signals exit\n");
793 up(&event_exit);
794 return 0;
795}
796
797int pciehp_event_start_thread(void)
798{
799 int pid;
800
801 /* initialize our semaphores */
802 init_MUTEX_LOCKED(&event_exit);
803 event_finished=0;
804
805 init_MUTEX_LOCKED(&event_semaphore);
806 pid = kernel_thread(event_thread, NULL, 0);
807
808 if (pid < 0) {
809 err ("Can't start up our event thread\n");
810 return -1;
811 }
812 dbg("Our event thread pid = %d\n", pid);
813 return 0;
814}
815
816
817void pciehp_event_stop_thread(void)
818{
819 event_finished = 1;
820 dbg("event_thread finish command given\n");
821 up(&event_semaphore);
822 dbg("wait for event_thread to exit\n");
823 down(&event_exit);
824}
825
826
827static int update_slot_info(struct slot *slot)
828{
829 struct hotplug_slot_info *info;
830 /* char buffer[SLOT_NAME_SIZE]; */
831 int result;
832
833 info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
834 if (!info)
835 return -ENOMEM;
836
837 /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
838
839 slot->hpc_ops->get_power_status(slot, &(info->power_status));
840 slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
841 slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
842 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
843
844 /* result = pci_hp_change_slot_info(buffer, info); */
845 result = pci_hp_change_slot_info(slot->hotplug_slot, info);
846 kfree (info);
847 return result;
848}
849
850static void interrupt_event_handler(struct controller *ctrl)
851{
852 int loop = 0;
853 int change = 1;
854 struct pci_func *func;
855 u8 hp_slot;
856 u8 getstatus;
857 struct slot *p_slot;
858
859 while (change) {
860 change = 0;
861
862 for (loop = 0; loop < 10; loop++) {
863 if (ctrl->event_queue[loop].event_type != 0) {
864 hp_slot = ctrl->event_queue[loop].hp_slot;
865
866 func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
867
868 p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
869
870 dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot);
871
872 if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
873 dbg("button cancel\n");
874 del_timer(&p_slot->task_event);
875
876 switch (p_slot->state) {
877 case BLINKINGOFF_STATE:
878 /* Wait for exclusive access to hardware */
879 down(&ctrl->crit_sect);
880
881 if (PWR_LED(ctrl->ctrlcap)) {
882 p_slot->hpc_ops->green_led_on(p_slot);
883 /* Wait for the command to complete */
884 wait_for_ctrl_irq (ctrl);
885 }
886 if (ATTN_LED(ctrl->ctrlcap)) {
887 p_slot->hpc_ops->set_attention_status(p_slot, 0);
888
889 /* Wait for the command to complete */
890 wait_for_ctrl_irq (ctrl);
891 }
892 /* Done with exclusive hardware access */
893 up(&ctrl->crit_sect);
894 break;
895 case BLINKINGON_STATE:
896 /* Wait for exclusive access to hardware */
897 down(&ctrl->crit_sect);
898
899 if (PWR_LED(ctrl->ctrlcap)) {
900 p_slot->hpc_ops->green_led_off(p_slot);
901 /* Wait for the command to complete */
902 wait_for_ctrl_irq (ctrl);
903 }
904 if (ATTN_LED(ctrl->ctrlcap)){
905 p_slot->hpc_ops->set_attention_status(p_slot, 0);
906 /* Wait for the command to complete */
907 wait_for_ctrl_irq (ctrl);
908 }
909 /* Done with exclusive hardware access */
910 up(&ctrl->crit_sect);
911
912 break;
913 default:
914 warn("Not a valid state\n");
915 return;
916 }
917 info(msg_button_cancel, p_slot->number);
918 p_slot->state = STATIC_STATE;
919 }
920 /* ***********Button Pressed (No action on 1st press...) */
921 else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
922
923 if (ATTN_BUTTN(ctrl->ctrlcap)) {
924 dbg("Button pressed\n");
925 p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
926 if (getstatus) {
927 /* slot is on */
928 dbg("slot is on\n");
929 p_slot->state = BLINKINGOFF_STATE;
930 info(msg_button_off, p_slot->number);
931 } else {
932 /* slot is off */
933 dbg("slot is off\n");
934 p_slot->state = BLINKINGON_STATE;
935 info(msg_button_on, p_slot->number);
936 }
937
938 /* Wait for exclusive access to hardware */
939 down(&ctrl->crit_sect);
940
941 /* blink green LED and turn off amber */
942 if (PWR_LED(ctrl->ctrlcap)) {
943 p_slot->hpc_ops->green_led_blink(p_slot);
944 /* Wait for the command to complete */
945 wait_for_ctrl_irq (ctrl);
946 }
947
948 if (ATTN_LED(ctrl->ctrlcap)) {
949 p_slot->hpc_ops->set_attention_status(p_slot, 0);
950
951 /* Wait for the command to complete */
952 wait_for_ctrl_irq (ctrl);
953 }
954
955 /* Done with exclusive hardware access */
956 up(&ctrl->crit_sect);
957
958 init_timer(&p_slot->task_event);
959 p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
960 p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
961 p_slot->task_event.data = (unsigned long) p_slot;
962
963 dbg("add_timer p_slot = %p\n", (void *) p_slot);
964 add_timer(&p_slot->task_event);
965 }
966 }
967 /***********POWER FAULT********************/
968 else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
969 if (POWER_CTRL(ctrl->ctrlcap)) {
970 dbg("power fault\n");
971 /* Wait for exclusive access to hardware */
972 down(&ctrl->crit_sect);
973
974 if (ATTN_LED(ctrl->ctrlcap)) {
975 p_slot->hpc_ops->set_attention_status(p_slot, 1);
976 wait_for_ctrl_irq (ctrl);
977 }
978
979 if (PWR_LED(ctrl->ctrlcap)) {
980 p_slot->hpc_ops->green_led_off(p_slot);
981 wait_for_ctrl_irq (ctrl);
982 }
983
984 /* Done with exclusive hardware access */
985 up(&ctrl->crit_sect);
986 }
987 }
988 /***********SURPRISE REMOVAL********************/
989 else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) ||
990 (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
991 if (HP_SUPR_RM(ctrl->ctrlcap)) {
992 dbg("Surprise Removal\n");
993 if (p_slot) {
994 surprise_rm_pending = (unsigned long) p_slot;
995 up(&event_semaphore);
996 update_slot_info(p_slot);
997 }
998 }
999 } else {
1000 /* refresh notification */
1001 if (p_slot)
1002 update_slot_info(p_slot);
1003 }
1004
1005 ctrl->event_queue[loop].event_type = 0;
1006
1007 change = 1;
1008 }
1009 } /* End of FOR loop */
1010 }
1011}
1012
1013
1014int pciehp_enable_slot(struct slot *p_slot)
1015{
1016 u8 getstatus = 0;
1017 int rc;
1018 struct pci_func *func;
1019
1020 func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
1021 if (!func) {
1022 dbg("%s: Error! slot NULL\n", __FUNCTION__);
1023 return 1;
1024 }
1025
1026 /* Check to see if (latch closed, card present, power off) */
1027 down(&p_slot->ctrl->crit_sect);
1028
1029 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
1030 if (rc || !getstatus) {
1031 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
1032 up(&p_slot->ctrl->crit_sect);
1033 return 1;
1034 }
1035 if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
1036 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1037 if (rc || getstatus) {
1038 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
1039 up(&p_slot->ctrl->crit_sect);
1040 return 1;
1041 }
1042 }
1043
1044 if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
1045 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
1046 if (rc || getstatus) {
1047 info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
1048 up(&p_slot->ctrl->crit_sect);
1049 return 1;
1050 }
1051 }
1052 up(&p_slot->ctrl->crit_sect);
1053
1054 slot_remove(func);
1055
1056 func = pciehp_slot_create(p_slot->bus);
1057 if (func == NULL)
1058 return 1;
1059
1060 func->bus = p_slot->bus;
1061 func->device = p_slot->device;
1062 func->function = 0;
1063 func->configured = 0;
1064 func->is_a_board = 1;
1065
1066 /* We have to save the presence info for these slots */
1067 p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
1068 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1069 func->switch_save = !getstatus? 0x10:0;
1070
1071 rc = board_added(func, p_slot->ctrl);
1072 if (rc) {
1073 if (is_bridge(func))
1074 bridge_slot_remove(func);
1075 else
1076 slot_remove(func);
1077
1078 /* Setup slot structure with entry for empty slot */
1079 func = pciehp_slot_create(p_slot->bus);
1080 if (func == NULL)
1081 return 1; /* Out of memory */
1082
1083 func->bus = p_slot->bus;
1084 func->device = p_slot->device;
1085 func->function = 0;
1086 func->configured = 0;
1087 func->is_a_board = 1;
1088
1089 /* We have to save the presence info for these slots */
1090 p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
1091 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1092 func->switch_save = !getstatus? 0x10:0;
1093 }
1094
1095 if (p_slot)
1096 update_slot_info(p_slot);
1097
1098 return rc;
1099}
1100
1101
1102int pciehp_disable_slot(struct slot *p_slot)
1103{
1104 u8 class_code, header_type, BCR;
1105 u8 index = 0;
1106 u8 getstatus = 0;
1107 u32 rc = 0;
1108 int ret = 0;
1109 unsigned int devfn;
1110 struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate;
1111 struct pci_func *func;
1112
1113 if (!p_slot->ctrl)
1114 return 1;
1115
1116 /* Check to see if (latch closed, card present, power on) */
1117 down(&p_slot->ctrl->crit_sect);
1118
1119 if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
1120 ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
1121 if (ret || !getstatus) {
1122 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
1123 up(&p_slot->ctrl->crit_sect);
1124 return 1;
1125 }
1126 }
1127
1128 if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
1129 ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
1130 if (ret || getstatus) {
1131 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
1132 up(&p_slot->ctrl->crit_sect);
1133 return 1;
1134 }
1135 }
1136
1137 if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
1138 ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
1139 if (ret || !getstatus) {
1140 info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
1141 up(&p_slot->ctrl->crit_sect);
1142 return 1;
1143 }
1144 }
1145
1146 up(&p_slot->ctrl->crit_sect);
1147
1148 func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
1149
1150 /* Make sure there are no video controllers here
1151 * for all func of p_slot
1152 */
1153 while (func && !rc) {
1154 pci_bus->number = func->bus;
1155 devfn = PCI_DEVFN(func->device, func->function);
1156
1157 /* Check the Class Code */
1158 rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
1159 if (rc)
1160 return rc;
1161
1162 if (class_code == PCI_BASE_CLASS_DISPLAY) {
1163 /* Display/Video adapter (not supported) */
1164 rc = REMOVE_NOT_SUPPORTED;
1165 } else {
1166 /* See if it's a bridge */
1167 rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
1168 if (rc)
1169 return rc;
1170
1171 /* If it's a bridge, check the VGA Enable bit */
1172 if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
1173 rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
1174 if (rc)
1175 return rc;
1176
1177 /* If the VGA Enable bit is set, remove isn't supported */
1178 if (BCR & PCI_BRIDGE_CTL_VGA) {
1179 rc = REMOVE_NOT_SUPPORTED;
1180 }
1181 }
1182 }
1183
1184 func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
1185 }
1186
1187 func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
1188 if ((func != NULL) && !rc) {
1189 rc = remove_board(func, p_slot->ctrl);
1190 } else if (!rc)
1191 rc = 1;
1192
1193 if (p_slot)
1194 update_slot_info(p_slot);
1195
1196 return rc;
1197}
1198