1 /*
2 * ACPI PCI HotPlug PCI configuration space management
3 *
4 * Copyright (C) 1995,2001 Compaq Computer Corporation
5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001,2002 IBM Corp.
7 * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
8 * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
9 * Copyright (C) 2002 NEC Corporation
10 *
11 * All rights reserved.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
21 * NON INFRINGEMENT. See the GNU General Public License for more
22 * details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 * Send feedback to <t-kochi@bq.jp.nec.com>
29 *
30 */
31
32 #include <linux/init.h>
33 #include <linux/module.h>
34
35 #include <linux/kernel.h>
36 #include <linux/pci.h>
37 #include "pci_hotplug.h"
38 #include "acpiphp.h"
39
40 #define MY_NAME "acpiphp_pci"
41
42 static void acpiphp_configure_irq (struct pci_dev *dev);
43
44
45 /* allocate mem/pmem/io resource to a new function */
init_config_space(struct acpiphp_func * func)46 static int init_config_space (struct acpiphp_func *func)
47 {
48 u32 bar, len;
49 u32 address[] = {
50 PCI_BASE_ADDRESS_0,
51 PCI_BASE_ADDRESS_1,
52 PCI_BASE_ADDRESS_2,
53 PCI_BASE_ADDRESS_3,
54 PCI_BASE_ADDRESS_4,
55 PCI_BASE_ADDRESS_5,
56 0
57 };
58 int count;
59 struct acpiphp_bridge *bridge;
60 struct pci_resource *res;
61 struct pci_bus *bus;
62 int devfn;
63
64 bridge = func->slot->bridge;
65 bus = bridge->pci_bus;
66 devfn = PCI_DEVFN(func->slot->device, func->function);
67
68 for (count = 0; address[count]; count++) { /* for 6 BARs */
69 pci_bus_write_config_dword(bus, devfn, address[count], 0xFFFFFFFF);
70 pci_bus_read_config_dword(bus, devfn, address[count], &bar);
71
72 if (!bar) /* This BAR is not implemented */
73 continue;
74
75 dbg("Device %02x.%d BAR %d wants %x\n", PCI_SLOT(devfn),
76 PCI_FUNC(devfn), count, bar);
77
78 if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
79 /* This is IO */
80
81 len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
82 len = len & ~(len - 1);
83
84 dbg("len in IO %x, BAR %d\n", len, count);
85
86 spin_lock(&bridge->res_lock);
87 res = acpiphp_get_io_resource(&bridge->io_head, len);
88 spin_unlock(&bridge->res_lock);
89
90 if (!res) {
91 err("cannot allocate requested io for %02x:%02x.%d len %x\n",
92 bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
93 return -1;
94 }
95 pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
96 res->next = func->io_head;
97 func->io_head = res;
98
99 } else {
100 /* This is Memory */
101 if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
102 /* pfmem */
103
104 len = bar & 0xFFFFFFF0;
105 len = ~len + 1;
106
107 dbg("len in PFMEM %x, BAR %d\n", len, count);
108
109 spin_lock(&bridge->res_lock);
110 res = acpiphp_get_resource(&bridge->p_mem_head, len);
111 spin_unlock(&bridge->res_lock);
112
113 if (!res) {
114 err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
115 bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
116 return -1;
117 }
118
119 pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
120
121 if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
122 dbg("inside the pfmem 64 case, count %d\n", count);
123 count += 1;
124 pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
125 }
126
127 res->next = func->p_mem_head;
128 func->p_mem_head = res;
129
130 } else {
131 /* regular memory */
132
133 len = bar & 0xFFFFFFF0;
134 len = ~len + 1;
135
136 dbg("len in MEM %x, BAR %d\n", len, count);
137
138 spin_lock(&bridge->res_lock);
139 res = acpiphp_get_resource(&bridge->mem_head, len);
140 spin_unlock(&bridge->res_lock);
141
142 if (!res) {
143 err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
144 bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
145 return -1;
146 }
147
148 pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
149
150 if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
151 /* takes up another dword */
152 dbg("inside mem 64 case, reg. mem, count %d\n", count);
153 count += 1;
154 pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
155 }
156
157 res->next = func->mem_head;
158 func->mem_head = res;
159
160 }
161 }
162 }
163
164 /* disable expansion rom */
165 pci_bus_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, 0x00000000);
166
167 return 0;
168 }
169
170
171 /* enable pci_dev */
configure_pci_dev(struct pci_dev_wrapped * wrapped_dev,struct pci_bus_wrapped * wrapped_bus)172 static int configure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
173 {
174 u16 tmp;
175 struct acpiphp_func *func;
176 struct acpiphp_bridge *bridge;
177 struct pci_dev *dev;
178
179 func = (struct acpiphp_func *)wrapped_dev->data;
180 bridge = (struct acpiphp_bridge *)wrapped_bus->data;
181 dev = wrapped_dev->dev;
182
183 /* TBD: support PCI-to-PCI bridge case */
184 if (!func || !bridge)
185 return 0;
186
187 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, bridge->hpp.cache_line_size);
188 pci_write_config_byte(dev, PCI_LATENCY_TIMER, bridge->hpp.latency_timer);
189
190 pci_read_config_word(dev, PCI_COMMAND, &tmp);
191 if (bridge->hpp.enable_SERR)
192 tmp |= PCI_COMMAND_SERR;
193 if (bridge->hpp.enable_PERR)
194 tmp |= PCI_COMMAND_PARITY;
195 //tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
196 pci_write_config_word(dev, PCI_COMMAND, tmp);
197
198 acpiphp_configure_irq(dev);
199 #ifdef CONFIG_PROC_FS
200 pci_proc_attach_device(dev);
201 #endif
202 pci_announce_device_to_drivers(dev);
203 info("Device %s configured\n", dev->slot_name);
204
205 return 0;
206 }
207
208
is_pci_dev_in_use(struct pci_dev * dev)209 static int is_pci_dev_in_use (struct pci_dev* dev)
210 {
211 /*
212 * dev->driver will be set if the device is in use by a new-style
213 * driver -- otherwise, check the device's regions to see if any
214 * driver has claimed them
215 */
216
217 int i, inuse=0;
218
219 if (dev->driver) return 1; //assume driver feels responsible
220
221 for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
222 if (!pci_resource_start(dev, i))
223 continue;
224
225 if (pci_resource_flags(dev, i) & IORESOURCE_IO)
226 inuse = check_region(pci_resource_start(dev, i),
227 pci_resource_len(dev, i));
228 else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
229 inuse = check_mem_region(pci_resource_start(dev, i),
230 pci_resource_len(dev, i));
231 }
232
233 return inuse;
234 }
235
236
pci_hp_remove_device(struct pci_dev * dev)237 static int pci_hp_remove_device (struct pci_dev *dev)
238 {
239 if (is_pci_dev_in_use(dev)) {
240 err("***Cannot safely power down device -- "
241 "it appears to be in use***\n");
242 return -EBUSY;
243 }
244 pci_remove_device(dev);
245 return 0;
246 }
247
248
249 /* remove device driver */
unconfigure_pci_dev_driver(struct pci_dev_wrapped * wrapped_dev,struct pci_bus_wrapped * wrapped_bus)250 static int unconfigure_pci_dev_driver (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
251 {
252 struct pci_dev *dev = wrapped_dev->dev;
253
254 dbg("attempting removal of driver for device %s\n", dev->slot_name);
255
256 /* Now, remove the Linux Driver Representation */
257 if (dev->driver) {
258 if (dev->driver->remove) {
259 dev->driver->remove(dev);
260 dbg("driver was properly removed\n");
261 }
262 dev->driver = NULL;
263 }
264
265 return is_pci_dev_in_use(dev);
266 }
267
268
269 /* remove pci_dev itself from system */
unconfigure_pci_dev(struct pci_dev_wrapped * wrapped_dev,struct pci_bus_wrapped * wrapped_bus)270 static int unconfigure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
271 {
272 struct pci_dev *dev = wrapped_dev->dev;
273
274 /* Now, remove the Linux Representation */
275 if (dev) {
276 if (pci_hp_remove_device(dev) == 0) {
277 info("Device %s removed\n", dev->slot_name);
278 kfree(dev); /* Now, remove */
279 } else {
280 return -1; /* problems while freeing, abort visitation */
281 }
282 }
283
284 return 0;
285 }
286
287
288 /* remove pci_bus itself from system */
unconfigure_pci_bus(struct pci_bus_wrapped * wrapped_bus,struct pci_dev_wrapped * wrapped_dev)289 static int unconfigure_pci_bus (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev)
290 {
291 struct pci_bus *bus = wrapped_bus->bus;
292
293 #ifdef CONFIG_PROC_FS
294 /* Now, remove the Linux Representation */
295 if (bus->procdir) {
296 pci_proc_detach_bus(bus);
297 }
298 #endif
299 /* the cleanup code should live in the kernel ... */
300 bus->self->subordinate = NULL;
301 /* unlink from parent bus */
302 list_del(&bus->node);
303
304 /* Now, remove */
305 if (bus)
306 kfree(bus);
307
308 return 0;
309 }
310
311
312 /* detect_used_resource - subtract resource under dev from bridge */
detect_used_resource(struct acpiphp_bridge * bridge,struct pci_dev * dev)313 static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
314 {
315 u32 bar, len;
316 u64 base;
317 u32 address[] = {
318 PCI_BASE_ADDRESS_0,
319 PCI_BASE_ADDRESS_1,
320 PCI_BASE_ADDRESS_2,
321 PCI_BASE_ADDRESS_3,
322 PCI_BASE_ADDRESS_4,
323 PCI_BASE_ADDRESS_5,
324 0
325 };
326 int count;
327 struct pci_resource *res;
328
329 dbg("Device %s\n", dev->slot_name);
330
331 for (count = 0; address[count]; count++) { /* for 6 BARs */
332 pci_read_config_dword(dev, address[count], &bar);
333
334 if (!bar) /* This BAR is not implemented */
335 continue;
336
337 pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
338 pci_read_config_dword(dev, address[count], &len);
339
340 if (len & PCI_BASE_ADDRESS_SPACE_IO) {
341 /* This is IO */
342 base = bar & 0xFFFFFFFC;
343 len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
344 len = len & ~(len - 1);
345
346 dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
347
348 spin_lock(&bridge->res_lock);
349 res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
350 spin_unlock(&bridge->res_lock);
351 if (res)
352 kfree(res);
353 } else {
354 /* This is Memory */
355 base = bar & 0xFFFFFFF0;
356 if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
357 /* pfmem */
358
359 len &= 0xFFFFFFF0;
360 len = ~len + 1;
361
362 if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
363 dbg("prefetch mem 64\n");
364 count += 1;
365 }
366 dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
367 spin_lock(&bridge->res_lock);
368 res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
369 spin_unlock(&bridge->res_lock);
370 if (res)
371 kfree(res);
372 } else {
373 /* regular memory */
374
375 len &= 0xFFFFFFF0;
376 len = ~len + 1;
377
378 if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
379 /* takes up another dword */
380 dbg("mem 64\n");
381 count += 1;
382 }
383 dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
384 spin_lock(&bridge->res_lock);
385 res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
386 spin_unlock(&bridge->res_lock);
387 if (res)
388 kfree(res);
389 }
390 }
391
392 pci_write_config_dword(dev, address[count], bar);
393 }
394
395 return 0;
396 }
397
398
399 /* detect_pci_resource_bus - subtract resource under pci_bus */
detect_used_resource_bus(struct acpiphp_bridge * bridge,struct pci_bus * bus)400 static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus)
401 {
402 struct list_head *l;
403 struct pci_dev *dev;
404
405 list_for_each (l, &bus->devices) {
406 dev = pci_dev_b(l);
407 detect_used_resource(bridge, dev);
408 /* XXX recursive call */
409 if (dev->subordinate)
410 detect_used_resource_bus(bridge, dev->subordinate);
411 }
412 }
413
414
415 /**
416 * acpiphp_detect_pci_resource - detect resources under bridge
417 * @bridge: detect all resources already used under this bridge
418 *
419 * collect all resources already allocated for all devices under a bridge.
420 */
acpiphp_detect_pci_resource(struct acpiphp_bridge * bridge)421 int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
422 {
423 detect_used_resource_bus(bridge, bridge->pci_bus);
424
425 return 0;
426 }
427
428
429 /**
430 * acpiphp_init_slot_resource - gather resource usage information of a slot
431 * @slot: ACPI slot object to be checked, should have valid pci_dev member
432 *
433 * TBD: PCI-to-PCI bridge case
434 * use pci_dev->resource[]
435 */
acpiphp_init_func_resource(struct acpiphp_func * func)436 int acpiphp_init_func_resource (struct acpiphp_func *func)
437 {
438 u64 base;
439 u32 bar, len;
440 u32 address[] = {
441 PCI_BASE_ADDRESS_0,
442 PCI_BASE_ADDRESS_1,
443 PCI_BASE_ADDRESS_2,
444 PCI_BASE_ADDRESS_3,
445 PCI_BASE_ADDRESS_4,
446 PCI_BASE_ADDRESS_5,
447 0
448 };
449 int count;
450 struct pci_resource *res;
451 struct pci_dev *dev;
452
453 dev = func->pci_dev;
454 dbg("Hot-pluggable device %s\n", dev->slot_name);
455
456 for (count = 0; address[count]; count++) { /* for 6 BARs */
457 pci_read_config_dword(dev, address[count], &bar);
458
459 if (!bar) /* This BAR is not implemented */
460 continue;
461
462 pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
463 pci_read_config_dword(dev, address[count], &len);
464
465 if (len & PCI_BASE_ADDRESS_SPACE_IO) {
466 /* This is IO */
467 base = bar & 0xFFFFFFFC;
468 len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
469 len = len & ~(len - 1);
470
471 dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
472
473 res = acpiphp_make_resource(base, len);
474 if (!res)
475 goto no_memory;
476
477 res->next = func->io_head;
478 func->io_head = res;
479
480 } else {
481 /* This is Memory */
482 base = bar & 0xFFFFFFF0;
483 if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
484 /* pfmem */
485
486 len &= 0xFFFFFFF0;
487 len = ~len + 1;
488
489 if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
490 dbg("prefetch mem 64\n");
491 count += 1;
492 }
493 dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
494 res = acpiphp_make_resource(base, len);
495 if (!res)
496 goto no_memory;
497
498 res->next = func->p_mem_head;
499 func->p_mem_head = res;
500
501 } else {
502 /* regular memory */
503
504 len &= 0xFFFFFFF0;
505 len = ~len + 1;
506
507 if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
508 /* takes up another dword */
509 dbg("mem 64\n");
510 count += 1;
511 }
512 dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
513 res = acpiphp_make_resource(base, len);
514 if (!res)
515 goto no_memory;
516
517 res->next = func->mem_head;
518 func->mem_head = res;
519
520 }
521 }
522
523 pci_write_config_dword(dev, address[count], bar);
524 }
525 #if 1
526 acpiphp_dump_func_resource(func);
527 #endif
528
529 return 0;
530
531 no_memory:
532 err("out of memory\n");
533 acpiphp_free_resource(&func->io_head);
534 acpiphp_free_resource(&func->mem_head);
535 acpiphp_free_resource(&func->p_mem_head);
536
537 return -1;
538 }
539
540
541 /**
542 * acpiphp_configure_slot - allocate PCI resources
543 * @slot: slot to be configured
544 *
545 * initializes a PCI functions on a device inserted
546 * into the slot
547 *
548 */
acpiphp_configure_slot(struct acpiphp_slot * slot)549 int acpiphp_configure_slot (struct acpiphp_slot *slot)
550 {
551 struct acpiphp_func *func;
552 struct list_head *l;
553 u8 hdr;
554 u32 dvid;
555 int retval = 0;
556 int is_multi = 0;
557
558 pci_bus_read_config_byte(slot->bridge->pci_bus,
559 PCI_DEVFN(slot->device, 0),
560 PCI_HEADER_TYPE, &hdr);
561
562 if (hdr & 0x80)
563 is_multi = 1;
564
565 list_for_each (l, &slot->funcs) {
566 func = list_entry(l, struct acpiphp_func, sibling);
567 if (is_multi || func->function == 0) {
568 pci_bus_read_config_dword(slot->bridge->pci_bus,
569 PCI_DEVFN(slot->device,
570 func->function),
571 PCI_VENDOR_ID, &dvid);
572 if (dvid != 0xffffffff) {
573 retval = init_config_space(func);
574 if (retval)
575 break;
576 }
577 }
578 }
579
580 return retval;
581 }
582
583
584 /* for pci_visit_dev() */
585 static struct pci_visit configure_functions = {
586 .post_visit_pci_dev = configure_pci_dev
587 };
588
589 static struct pci_visit unconfigure_functions_phase1 = {
590 .post_visit_pci_dev = unconfigure_pci_dev_driver
591 };
592
593 static struct pci_visit unconfigure_functions_phase2 = {
594 .post_visit_pci_bus = unconfigure_pci_bus,
595 .post_visit_pci_dev = unconfigure_pci_dev
596 };
597
598
599 /**
600 * acpiphp_configure_function - configure PCI function
601 * @func: function to be configured
602 *
603 * initializes a PCI functions on a device inserted
604 * into the slot
605 *
606 */
acpiphp_configure_function(struct acpiphp_func * func)607 int acpiphp_configure_function (struct acpiphp_func *func)
608 {
609 int retval = 0;
610 struct pci_dev_wrapped wrapped_dev;
611 struct pci_bus_wrapped wrapped_bus;
612 struct acpiphp_bridge *bridge;
613
614 /* if pci_dev is NULL, ignore it */
615 if (!func->pci_dev)
616 goto err_exit;
617
618 bridge = func->slot->bridge;
619
620 memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
621 memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
622 wrapped_dev.dev = func->pci_dev;
623 wrapped_dev.data = func;
624 wrapped_bus.bus = bridge->pci_bus;
625 wrapped_bus.data = bridge;
626
627 retval = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
628 if (retval)
629 goto err_exit;
630
631 err_exit:
632 return retval;
633 }
634
635
636 /**
637 * acpiphp_unconfigure_function - unconfigure PCI function
638 * @func: function to be unconfigured
639 *
640 */
acpiphp_unconfigure_function(struct acpiphp_func * func)641 int acpiphp_unconfigure_function (struct acpiphp_func *func)
642 {
643 struct acpiphp_bridge *bridge;
644 struct pci_dev_wrapped wrapped_dev;
645 struct pci_bus_wrapped wrapped_bus;
646 int retval = 0;
647
648 /* if pci_dev is NULL, ignore it */
649 if (!func->pci_dev)
650 goto err_exit;
651
652 memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
653 memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
654 wrapped_dev.dev = func->pci_dev;
655 //wrapped_dev.data = func;
656 wrapped_bus.bus = func->slot->bridge->pci_bus;
657 //wrapped_bus.data = func->slot->bridge;
658
659 retval = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
660 if (retval)
661 goto err_exit;
662
663 retval = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
664 if (retval)
665 goto err_exit;
666
667 /* free all resources */
668 bridge = func->slot->bridge;
669
670 spin_lock(&bridge->res_lock);
671 acpiphp_move_resource(&func->io_head, &bridge->io_head);
672 acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
673 acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
674 acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
675 spin_unlock(&bridge->res_lock);
676
677 err_exit:
678 return retval;
679 }
680
681
682 /*
683 * acpiphp_configure_irq - configure PCI_INTERRUPT_PIN
684 *
685 * for x86 platforms, pcibios_enable_device calls pcibios_enable_irq,
686 * which allocates irq for pci_dev
687 *
688 * for IA64 platforms, we have to program dev->irq from pci IRQ routing
689 * information derived from ACPI table
690 *
691 * TBD:
692 * separate architecture dependent part
693 * (preferably, pci_enable_device() cares for allocating irq...)
694 */
acpiphp_configure_irq(struct pci_dev * dev)695 static void acpiphp_configure_irq (struct pci_dev *dev)
696 {
697 #if CONFIG_IA64 /* XXX IA64 specific */
698 extern void iosapic_fixup_pci_interrupt (struct pci_dev *dev);
699
700 iosapic_fixup_pci_interrupt(dev);
701 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
702 #endif
703 }
704