| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * Low-Level PCI Support for PC -- Routing of Interrupts | |||
| 3 | * | |||
| 4 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> | |||
| 5 | */ | |||
| 6 | ||||
| 7 | #include <linux/config.h> | |||
| 8 | #include <linux/types.h> | |||
| 9 | #include <linux/kernel.h> | |||
| 10 | #include <linux/pci.h> | |||
| 11 | #include <linux/init.h> | |||
| 12 | #include <linux/slab.h> | |||
| 13 | #include <linux/interrupt.h> | |||
| 14 | #include <linux/dmi.h> | |||
| 15 | #include <asm/io.h> | |||
| 16 | #include <asm/smp.h> | |||
| 17 | #include <asm/io_apic.h> | |||
| 18 | #include <linux/irq.h> | |||
| 19 | #include <linux/acpi.h> | |||
| 20 | ||||
| 21 | #include "pci.h" | |||
| 22 | ||||
| 23 | #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) | |||
| 24 | #define PIRQ_VERSION 0x0100 | |||
| 25 | ||||
| 26 | static int broken_hp_bios_irq9; | |||
| 27 | static int acer_tm360_irqrouting; | |||
| 28 | ||||
| 29 | static struct irq_routing_table *pirq_table; | |||
| 30 | ||||
| 31 | static int pirq_enable_irq(struct pci_dev *dev); | |||
| 32 | ||||
| 33 | /* | |||
| 34 | * Never use: 0, 1, 2 (timer, keyboard, and cascade) | |||
| 35 | * Avoid using: 13, 14 and 15 (FP error and IDE). | |||
| 36 | * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse) | |||
| 37 | */ | |||
| 38 | unsigned int pcibios_irq_mask = 0xfff8; | |||
| 39 | ||||
| 40 | static int pirq_penalty[16] = { | |||
| 41 | 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000, | |||
| 42 | 0, 0, 0, 0, 1000, 100000, 100000, 100000 | |||
| 43 | }; | |||
| 44 | ||||
| 45 | struct irq_router { | |||
| 46 | char *name; | |||
| 47 | u16 vendor, device; | |||
| 48 | int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq); | |||
| 49 | int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); | |||
| 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 | ||||
| 57 | int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; | |||
| 58 | void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; | |||
| 59 | ||||
| 60 | /* | |||
| 61 | * Check passed address for the PCI IRQ Routing Table signature | |||
| 62 | * and perform checksum verification. | |||
| 63 | */ | |||
| 64 | ||||
| 0 | 0 | - | 65 | static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr) |
| 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 || | |||
| 0 | 0 | - | 75 | rt->size < sizeof(struct irq_routing_table)) |
| 0 | - | 75 | T || _ || _ || _ | |
| 0 | - | 75 | F || T || _ || _ | |
| 0 | - | 75 | F || F || T || _ | |
| 0 | - | 75 | F || F || F || T | |
| 0 | - | 75 | F || F || F || F | |
| 0 | - | 76 | return NULL; | |
| 77 | sum = 0; | |||
| 0 | 0 | - | 78 | for (i=0; i < rt->size; i++) |
| 79 | sum += addr[i]; | |||
| 0 | 0 | - | 80 | if (!sum) { |
| 81 | DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt); | |||
| 0 | - | 82 | return rt; | |
| 83 | } | |||
| 0 | - | 84 | return NULL; | |
| 85 | } | |||
| 86 | ||||
| 87 | ||||
| 88 | ||||
| 89 | /* | |||
| 90 | * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. | |||
| 91 | */ | |||
| 92 | ||||
| 0 | 0 | - | 93 | static struct irq_routing_table * __init pirq_find_routing_table(void) |
| 94 | { | |||
| 95 | u8 *addr; | |||
| 96 | struct irq_routing_table *rt; | |||
| 97 | ||||
| 0 | 0 | - | 98 | if (pirq_table_addr) { |
| 99 | rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); | |||
| 0 | 0 | - | 100 | if (rt) |
| 0 | - | 101 | return rt; | |
| 102 | printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); | |||
| 103 | } | |||
| 0 | 0 | - | 104 | for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { |
| 105 | rt = pirq_check_routing_table(addr); | |||
| 0 | 0 | - | 106 | if (rt) |
| 0 | - | 107 | return rt; | |
| 108 | } | |||
| 0 | - | 109 | return NULL; | |
| 110 | } | |||
| 111 | ||||
| 112 | /* | |||
| 113 | * If we have a IRQ routing table, use it to search for peer host | |||
| 114 | * bridges. It's a gross hack, but since there are no other known | |||
| 115 | * ways how to get a list of buses, we have to go this way. | |||
| 116 | */ | |||
| 117 | ||||
| 0 | 0 | - | 118 | static void __init pirq_peer_trick(void) |
| 119 | { | |||
| 120 | struct irq_routing_table *rt = pirq_table; | |||
| 121 | u8 busmap[256]; | |||
| 122 | int i; | |||
| 123 | struct irq_info *e; | |||
| 124 | ||||
| 125 | memset(busmap, 0, sizeof(busmap)); | |||
| 0 | 0 | - | 126 | for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) { |
| 127 | e = &rt->slots[i]; | |||
| 128 | #ifdef DEBUG | |||
| 129 | { | |||
| 130 | int j; | |||
| 131 | DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot); | |||
| 132 | for(j=0; j<4; j++) | |||
| 133 | DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap); | |||
| 134 | DBG("\n"); | |||
| 135 | } | |||
| 136 | #endif | |||
| 137 | busmap[e->bus] = 1; | |||
| 138 | } | |||
| 0 | 0 | - | 139 | for(i = 1; i < 256; i++) { |
| 0 | 0 | - | 140 | if (!busmap[i] || pci_find_bus(0, i)) |
| 0 | - | 140 | T || _ | |
| 0 | - | 140 | F || T | |
| 0 | - | 140 | F || F | |
| 0 | - | 141 | continue; | |
| 0 | 0 | - | 142 | if (pci_scan_bus(i, &pci_root_ops, NULL)) |
| 143 | printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); | |||
| 144 | } | |||
| 145 | pcibios_last_bus = -1; | |||
| 146 | } | |||
| 147 | ||||
| 148 | /* | |||
| 149 | * Code for querying and setting of IRQ routes on various interrupt routers. | |||
| 150 | */ | |||
| 151 | ||||
| 0 | 0 | - | 152 | void eisa_set_level_irq(unsigned int irq) |
| 153 | { | |||
| 154 | unsigned char mask = 1 << (irq & 7); | |||
| 155 | unsigned int port = 0x4d0 + (irq >> 3); | |||
| 156 | unsigned char val; | |||
| 157 | static u16 eisa_irq_mask; | |||
| 158 | ||||
| 0 | 0 | - | 159 | if (irq >= 16 || (1 << irq) & eisa_irq_mask) |
| 0 | - | 159 | T || _ | |
| 0 | - | 159 | F || T | |
| 0 | - | 159 | F || F | |
| 0 | - | 160 | return; | |
| 161 | ||||
| 162 | eisa_irq_mask |= (1 << irq); | |||
| 163 | printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq); | |||
| 164 | val = inb(port); | |||
| 0 | 0 | - | 165 | if (!(val & mask)) { |
| 166 | DBG(KERN_DEBUG " -> edge"); | |||
| 167 | outb(val | mask, port); | |||
| 168 | } | |||
| 169 | } | |||
| 170 | ||||
| 171 | /* | |||
| 172 | * Common IRQ routing practice: nybbles in config space, | |||
| 173 | * offset by some magic constant. | |||
| 174 | */ | |||
| 0 | 0 | - | 175 | static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr) |
| 176 | { | |||
| 177 | u8 x; | |||
| 178 | unsigned reg = offset + (nr >> 1); | |||
| 179 | ||||
| 180 | pci_read_config_byte(router, reg, &x); | |||
| 181 | return (nr & 1) ? (x >> 4) : (x & 0xf); | |||
| 0 | 0 | - | 181 | ternary-?: ( nr & 1 ) |
| 0 | - | 181 | return ( nr & 1 ) ? ( x >> 4 ) : ( x & 0xf ) | |
| 182 | } | |||
| 183 | ||||
| 0 | 0 | - | 184 | static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val) |
| 185 | { | |||
| 186 | u8 x; | |||
| 187 | unsigned reg = offset + (nr >> 1); | |||
| 188 | ||||
| 189 | pci_read_config_byte(router, reg, &x); | |||
| 190 | x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val); | |||
| 0 | 0 | - | 190 | ternary-?: ( nr & 1 ) |
| 191 | pci_write_config_byte(router, reg, x); | |||
| 192 | } | |||
| 193 | ||||
| 194 | /* | |||
| 195 | * ALI pirq entries are damn ugly, and completely undocumented. | |||
| 196 | * This has been figured out from pirq tables, and it's not a pretty | |||
| 197 | * picture. | |||
| 198 | */ | |||
| 0 | 0 | - | 199 | static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 200 | { | |||
| 201 | static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; | |||
| 202 | ||||
| 0 | - | 203 | return irqmap[read_config_nybble(router, 0x48, pirq-1)]; | |
| 204 | } | |||
| 205 | ||||
| 0 | 0 | - | 206 | static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 207 | { | |||
| 208 | static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; | |||
| 209 | unsigned int val = irqmap[irq]; | |||
| 210 | ||||
| 0 | 0 | - | 211 | if (val) { |
| 212 | write_config_nybble(router, 0x48, pirq-1, val); | |||
| 0 | - | 213 | return 1; | |
| 214 | } | |||
| 0 | - | 215 | return 0; | |
| 216 | } | |||
| 217 | ||||
| 218 | /* | |||
| 219 | * The Intel PIIX4 pirq rules are fairly simple: "pirq" is | |||
| 220 | * just a pointer to the config space. | |||
| 221 | */ | |||
| 0 | 0 | - | 222 | static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 223 | { | |||
| 224 | u8 x; | |||
| 225 | ||||
| 226 | pci_read_config_byte(router, pirq, &x); | |||
| 227 | return (x < 16) ? x : 0; | |||
| 0 | 0 | - | 227 | ternary-?: ( x < 16 ) |
| 0 | - | 227 | return ( x < 16 ) ? x : 0 | |
| 228 | } | |||
| 229 | ||||
| 0 | 0 | - | 230 | static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 231 | { | |||
| 232 | pci_write_config_byte(router, pirq, irq); | |||
| 0 | - | 233 | return 1; | |
| 234 | } | |||
| 235 | ||||
| 236 | /* | |||
| 237 | * The VIA pirq rules are nibble-based, like ALI, | |||
| 238 | * but without the ugly irq number munging. | |||
| 239 | * However, PIRQD is in the upper instead of lower 4 bits. | |||
| 240 | */ | |||
| 0 | 0 | - | 241 | static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 242 | { | |||
| 243 | return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq); | |||
| 0 | 0 | - | 243 | ternary-?: pirq == 4 |
| 0 | - | 243 | return read_config_nybble ( router , 0x55 , pi.. | |
| 244 | } | |||
| 245 | ||||
| 0 | 0 | - | 246 | static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 247 | { | |||
| 248 | write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq); | |||
| 0 | 0 | - | 248 | ternary-?: pirq == 4 |
| 0 | - | 249 | return 1; | |
| 250 | } | |||
| 251 | ||||
| 252 | /* | |||
| 253 | * The VIA pirq rules are nibble-based, like ALI, | |||
| 254 | * but without the ugly irq number munging. | |||
| 255 | * However, for 82C586, nibble map is different . | |||
| 256 | */ | |||
| 0 | 0 | - | 257 | static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 258 | { | |||
| 259 | static unsigned int pirqmap[4] = { 3, 2, 5, 1 }; | |||
| 0 | - | 260 | return read_config_nybble(router, 0x55, pirqmap[pirq-1]); | |
| 261 | } | |||
| 262 | ||||
| 0 | 0 | - | 263 | static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 264 | { | |||
| 265 | static unsigned int pirqmap[4] = { 3, 2, 5, 1 }; | |||
| 266 | write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); | |||
| 0 | - | 267 | return 1; | |
| 268 | } | |||
| 269 | ||||
| 270 | /* | |||
| 271 | * ITE 8330G pirq rules are nibble-based | |||
| 272 | * FIXME: pirqmap may be { 1, 0, 3, 2 }, | |||
| 273 | * 2+3 are both mapped to irq 9 on my system | |||
| 274 | */ | |||
| 0 | 0 | - | 275 | static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 276 | { | |||
| 277 | static unsigned char pirqmap[4] = { 1, 0, 2, 3 }; | |||
| 0 | - | 278 | return read_config_nybble(router,0x43, pirqmap[pirq-1]); | |
| 279 | } | |||
| 280 | ||||
| 0 | 0 | - | 281 | static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 282 | { | |||
| 283 | static unsigned char pirqmap[4] = { 1, 0, 2, 3 }; | |||
| 284 | write_config_nybble(router, 0x43, pirqmap[pirq-1], irq); | |||
| 0 | - | 285 | return 1; | |
| 286 | } | |||
| 287 | ||||
| 288 | /* | |||
| 289 | * OPTI: high four bits are nibble pointer.. | |||
| 290 | * I wonder what the low bits do? | |||
| 291 | */ | |||
| 0 | 0 | - | 292 | static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 293 | { | |||
| 0 | - | 294 | return read_config_nybble(router, 0xb8, pirq >> 4); | |
| 295 | } | |||
| 296 | ||||
| 0 | 0 | - | 297 | static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 298 | { | |||
| 299 | write_config_nybble(router, 0xb8, pirq >> 4, irq); | |||
| 0 | - | 300 | return 1; | |
| 301 | } | |||
| 302 | ||||
| 303 | /* | |||
| 304 | * Cyrix: nibble offset 0x5C | |||
| 305 | * 0x5C bits 7:4 is INTB bits 3:0 is INTA | |||
| 306 | * 0x5D bits 7:4 is INTD bits 3:0 is INTC | |||
| 307 | */ | |||
| 0 | 0 | - | 308 | static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 309 | { | |||
| 0 | - | 310 | return read_config_nybble(router, 0x5C, (pirq-1)^1); | |
| 311 | } | |||
| 312 | ||||
| 0 | 0 | - | 313 | static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 314 | { | |||
| 315 | write_config_nybble(router, 0x5C, (pirq-1)^1, irq); | |||
| 0 | - | 316 | return 1; | |
| 317 | } | |||
| 318 | ||||
| 319 | /* | |||
| 320 | * PIRQ routing for SiS 85C503 router used in several SiS chipsets. | |||
| 321 | * We have to deal with the following issues here: | |||
| 322 | * - vendors have different ideas about the meaning of link values | |||
| 323 | * - some onboard devices (integrated in the chipset) have special | |||
| 324 | * links and are thus routed differently (i.e. not via PCI INTA-INTD) | |||
| 325 | * - different revision of the router have a different layout for | |||
| 326 | * the routing registers, particularly for the onchip devices | |||
| 327 | * | |||
| 328 | * For all routing registers the common thing is we have one byte | |||
| 329 | * per routeable link which is defined as: | |||
| 330 | * bit 7 IRQ mapping enabled (0) or disabled (1) | |||
| 331 | * bits [6:4] reserved (sometimes used for onchip devices) | |||
| 332 | * bits [3:0] IRQ to map to | |||
| 333 | * allowed: 3-7, 9-12, 14-15 | |||
| 334 | * reserved: 0, 1, 2, 8, 13 | |||
| 335 | * | |||
| 336 | * The config-space registers located at 0x41/0x42/0x43/0x44 are | |||
| 337 | * always used to route the normal PCI INT A/B/C/D respectively. | |||
| 338 | * Apparently there are systems implementing PCI routing table using | |||
| 339 | * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D. | |||
| 340 | * We try our best to handle both link mappings. | |||
| 341 | * | |||
| 342 | * Currently (2003-05-21) it appears most SiS chipsets follow the | |||
| 343 | * definition of routing registers from the SiS-5595 southbridge. | |||
| 344 | * According to the SiS 5595 datasheets the revision id's of the | |||
| 345 | * router (ISA-bridge) should be 0x01 or 0xb0. | |||
| 346 | * | |||
| 347 | * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1. | |||
| 348 | * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets. | |||
| 349 | * They seem to work with the current routing code. However there is | |||
| 350 | * some concern because of the two USB-OHCI HCs (original SiS 5595 | |||
| 351 | * had only one). YMMV. | |||
| 352 | * | |||
| 353 | * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1: | |||
| 354 | * | |||
| 355 | * 0x61: IDEIRQ: | |||
| 356 | * bits [6:5] must be written 01 | |||
| 357 | * bit 4 channel-select primary (0), secondary (1) | |||
| 358 | * | |||
| 359 | * 0x62: USBIRQ: | |||
| 360 | * bit 6 OHCI function disabled (0), enabled (1) | |||
| 361 | * | |||
| 362 | * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved | |||
| 363 | * | |||
| 364 | * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved | |||
| 365 | * | |||
| 366 | * We support USBIRQ (in addition to INTA-INTD) and keep the | |||
| 367 | * IDE, ACPI and DAQ routing untouched as set by the BIOS. | |||
| 368 | * | |||
| 369 | * Currently the only reported exception is the new SiS 65x chipset | |||
| 370 | * which includes the SiS 69x southbridge. Here we have the 85C503 | |||
| 371 | * router revision 0x04 and there are changes in the register layout | |||
| 372 | * mostly related to the different USB HCs with USB 2.0 support. | |||
| 373 | * | |||
| 374 | * Onchip routing for router rev-id 0x04 (try-and-error observation) | |||
| 375 | * | |||
| 376 | * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs | |||
| 377 | * bit 6-4 are probably unused, not like 5595 | |||
| 378 | */ | |||
| 379 | ||||
| 380 | #define PIRQ_SIS_IRQ_MASK 0x0f | |||
| 381 | #define PIRQ_SIS_IRQ_DISABLE 0x80 | |||
| 382 | #define PIRQ_SIS_USB_ENABLE 0x40 | |||
| 383 | ||||
| 0 | 0 | - | 384 | static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 385 | { | |||
| 386 | u8 x; | |||
| 387 | int reg; | |||
| 388 | ||||
| 389 | reg = pirq; | |||
| 0 | 0 | - | 390 | if (reg >= 0x01 && reg <= 0x04) |
| 0 | - | 390 | T && T | |
| 0 | - | 390 | T && F | |
| 0 | - | 390 | F && _ | |
| 391 | reg += 0x40; | |||
| 392 | pci_read_config_byte(router, reg, &x); | |||
| 393 | return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); | |||
| 0 | 0 | - | 393 | ternary-?: ( x & 0x80 ) |
| 0 | - | 393 | return ( x & 0x80 ) ? 0 : ( x & 0x0f ) | |
| 394 | } | |||
| 395 | ||||
| 0 | 0 | - | 396 | static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 397 | { | |||
| 398 | u8 x; | |||
| 399 | int reg; | |||
| 400 | ||||
| 401 | reg = pirq; | |||
| 0 | 0 | - | 402 | if (reg >= 0x01 && reg <= 0x04) |
| 0 | - | 402 | T && T | |
| 0 | - | 402 | T && F | |
| 0 | - | 402 | F && _ | |
| 403 | reg += 0x40; | |||
| 404 | pci_read_config_byte(router, reg, &x); | |||
| 405 | x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE); | |||
| 406 | x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE; | |||
| 0 | 0 | - | 406 | ternary-?: irq |
| 407 | pci_write_config_byte(router, reg, x); | |||
| 0 | - | 408 | return 1; | |
| 409 | } | |||
| 410 | ||||
| 411 | ||||
| 412 | /* | |||
| 413 | * VLSI: nibble offset 0x74 - educated guess due to routing table and | |||
| 414 | * config space of VLSI 82C534 PCI-bridge/router (1004:0102) | |||
| 415 | * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard | |||
| 416 | * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6 | |||
| 417 | * for the busbridge to the docking station. | |||
| 418 | */ | |||
| 419 | ||||
| 0 | 0 | - | 420 | static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 421 | { | |||
| 0 | 0 | - | 422 | if (pirq > 8) { |
| 423 | printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); | |||
| 0 | - | 424 | return 0; | |
| 425 | } | |||
| 0 | - | 426 | return read_config_nybble(router, 0x74, pirq-1); | |
| 427 | } | |||
| 428 | ||||
| 0 | 0 | - | 429 | static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 430 | { | |||
| 0 | 0 | - | 431 | if (pirq > 8) { |
| 432 | printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); | |||
| 0 | - | 433 | return 0; | |
| 434 | } | |||
| 435 | write_config_nybble(router, 0x74, pirq-1, irq); | |||
| 0 | - | 436 | return 1; | |
| 437 | } | |||
| 438 | ||||
| 439 | /* | |||
| 440 | * ServerWorks: PCI interrupts mapped to system IRQ lines through Index | |||
| 441 | * and Redirect I/O registers (0x0c00 and 0x0c01). The Index register | |||
| 442 | * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect | |||
| 443 | * register is a straight binary coding of desired PIC IRQ (low nibble). | |||
| 444 | * | |||
| 445 | * The 'link' value in the PIRQ table is already in the correct format | |||
| 446 | * for the Index register. There are some special index values: | |||
| 447 | * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1, | |||
| 448 | * and 0x03 for SMBus. | |||
| 449 | */ | |||
| 0 | 0 | - | 450 | static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 451 | { | |||
| 452 | outb_p(pirq, 0xc00); | |||
| 0 | - | 453 | return inb(0xc01) & 0xf; | |
| 454 | } | |||
| 455 | ||||
| 0 | 0 | - | 456 | static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 457 | { | |||
| 458 | outb_p(pirq, 0xc00); | |||
| 459 | outb_p(irq, 0xc01); | |||
| 0 | - | 460 | return 1; | |
| 461 | } | |||
| 462 | ||||
| 463 | /* Support for AMD756 PCI IRQ Routing | |||
| 464 | * Jhon H. Caicedo <jhcaiced@osso.org.co> | |||
| 465 | * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced) | |||
| 466 | * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced) | |||
| 467 | * The AMD756 pirq rules are nibble-based | |||
| 468 | * offset 0x56 0-3 PIRQA 4-7 PIRQB | |||
| 469 | * offset 0x57 0-3 PIRQC 4-7 PIRQD | |||
| 470 | */ | |||
| 0 | 0 | - | 471 | static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq) |
| 472 | { | |||
| 473 | u8 irq; | |||
| 474 | irq = 0; | |||
| 0 | 0 | - | 475 | if (pirq <= 4) |
| 476 | { | |||
| 477 | irq = read_config_nybble(router, 0x56, pirq - 1); | |||
| 478 | } | |||
| 479 | printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n", | |||
| 480 | dev->vendor, dev->device, pirq, irq); | |||
| 0 | - | 481 | return irq; | |
| 482 | } | |||
| 483 | ||||
| 0 | 0 | - | 484 | static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) |
| 485 | { | |||
| 486 | printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", | |||
| 487 | dev->vendor, dev->device, pirq, irq); | |||
| 0 | 0 | - | 488 | if (pirq <= 4) |
| 489 | { | |||
| 490 | write_config_nybble(router, 0x56, pirq - 1, irq); | |||
| 491 | } | |||
| 0 | - | 492 | return 1; | |
| 493 | } | |||
| 494 | ||||
| 495 | #ifdef CONFIG_PCI_BIOS | |||
| 496 | ||||
| 497 | static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) | |||
| 498 | { | |||
| 499 | struct pci_dev *bridge; | |||
| 500 | int pin = pci_get_interrupt_pin(dev, &bridge); | |||
| 501 | return pcibios_set_irq_routing(bridge, pin, irq); | |||
| 502 | } | |||
| 503 | ||||
| 504 | #endif | |||
| 505 | ||||
| 0 | 0 | - | 506 | static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) |
| 507 | { | |||
| 508 | static struct pci_device_id pirq_440gx[] = { | |||
| 509 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) }, | |||
| 510 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) }, | |||
| 511 | { }, | |||
| 512 | }; | |||
| 513 | ||||
| 514 | /* 440GX has a proprietary PIRQ router -- don't use it */ | |||
| 0 | 0 | - | ||