]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * Low-Level PCI Support for PC -- Routing of Interrupts | |
4 | * | |
5 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> | |
6 | */ | |
7 | ||
1da177e4 LT |
8 | #include <linux/types.h> |
9 | #include <linux/kernel.h> | |
10 | #include <linux/pci.h> | |
11 | #include <linux/init.h> | |
1da177e4 | 12 | #include <linux/interrupt.h> |
1da177e4 | 13 | #include <linux/dmi.h> |
7058b061 PC |
14 | #include <linux/io.h> |
15 | #include <linux/smp.h> | |
1da177e4 | 16 | #include <asm/io_apic.h> |
b33fa1f3 | 17 | #include <linux/irq.h> |
1da177e4 | 18 | #include <linux/acpi.h> |
82487711 | 19 | #include <asm/pci_x86.h> |
1da177e4 LT |
20 | |
21 | #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) | |
22 | #define PIRQ_VERSION 0x0100 | |
23 | ||
24 | static int broken_hp_bios_irq9; | |
25 | static int acer_tm360_irqrouting; | |
26 | ||
27 | static struct irq_routing_table *pirq_table; | |
28 | ||
29 | static int pirq_enable_irq(struct pci_dev *dev); | |
c03b3b07 | 30 | static void pirq_disable_irq(struct pci_dev *dev); |
1da177e4 LT |
31 | |
32 | /* | |
33 | * Never use: 0, 1, 2 (timer, keyboard, and cascade) | |
34 | * Avoid using: 13, 14 and 15 (FP error and IDE). | |
35 | * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse) | |
36 | */ | |
37 | unsigned int pcibios_irq_mask = 0xfff8; | |
38 | ||
39 | static int pirq_penalty[16] = { | |
40 | 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000, | |
41 | 0, 0, 0, 0, 1000, 100000, 100000, 100000 | |
42 | }; | |
43 | ||
44 | struct irq_router { | |
45 | char *name; | |
46 | u16 vendor, device; | |
47 | int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq); | |
273c1127 MV |
48 | int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, |
49 | int new); | |
1da177e4 LT |
50 | }; |
51 | ||
52 | struct irq_router_handler { | |
53 | u16 vendor; | |
54 | int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); | |
55 | }; | |
56 | ||
ab3b3793 | 57 | int (*pcibios_enable_irq)(struct pci_dev *dev) = pirq_enable_irq; |
c03b3b07 | 58 | void (*pcibios_disable_irq)(struct pci_dev *dev) = pirq_disable_irq; |
1da177e4 | 59 | |
120bb424 | 60 | /* |
61 | * Check passed address for the PCI IRQ Routing Table signature | |
62 | * and perform checksum verification. | |
63 | */ | |
64 | ||
7058b061 | 65 | static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr) |
120bb424 | 66 | { |
67 | struct irq_routing_table *rt; | |
68 | int i; | |
69 | u8 sum; | |
70 | ||
71 | rt = (struct irq_routing_table *) addr; | |
72 | if (rt->signature != PIRQ_SIGNATURE || | |
73 | rt->version != PIRQ_VERSION || | |
74 | rt->size % 16 || | |
75 | rt->size < sizeof(struct irq_routing_table)) | |
76 | return NULL; | |
77 | sum = 0; | |
7058b061 | 78 | for (i = 0; i < rt->size; i++) |
120bb424 | 79 | sum += addr[i]; |
80 | if (!sum) { | |
273c1127 MV |
81 | DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", |
82 | rt); | |
120bb424 | 83 | return rt; |
84 | } | |
85 | return NULL; | |
86 | } | |
87 | ||
88 | ||
89 | ||
1da177e4 LT |
90 | /* |
91 | * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. | |
92 | */ | |
93 | ||
94 | static struct irq_routing_table * __init pirq_find_routing_table(void) | |
95 | { | |
96 | u8 *addr; | |
97 | struct irq_routing_table *rt; | |
1da177e4 | 98 | |
120bb424 | 99 | if (pirq_table_addr) { |
100 | rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); | |
101 | if (rt) | |
102 | return rt; | |
103 | printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); | |
104 | } | |
7058b061 | 105 | for (addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { |
120bb424 | 106 | rt = pirq_check_routing_table(addr); |
107 | if (rt) | |
1da177e4 | 108 | return rt; |
1da177e4 LT |
109 | } |
110 | return NULL; | |
111 | } | |
112 | ||
113 | /* | |
114 | * If we have a IRQ routing table, use it to search for peer host | |
115 | * bridges. It's a gross hack, but since there are no other known | |
116 | * ways how to get a list of buses, we have to go this way. | |
117 | */ | |
118 | ||
119 | static void __init pirq_peer_trick(void) | |
120 | { | |
121 | struct irq_routing_table *rt = pirq_table; | |
122 | u8 busmap[256]; | |
123 | int i; | |
124 | struct irq_info *e; | |
125 | ||
126 | memset(busmap, 0, sizeof(busmap)); | |
7058b061 | 127 | for (i = 0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) { |
1da177e4 LT |
128 | e = &rt->slots[i]; |
129 | #ifdef DEBUG | |
130 | { | |
131 | int j; | |