import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / hotplug / acpiphp_pci.c
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 */
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 */
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
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
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 */
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 */
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 */
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 */
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 */
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  */
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  */
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  */
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  */
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  */
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  */
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 }