This commit was manufactured by cvs2svn to create branch 'fedora'.
[linux-2.6.git] / arch / xen / i386 / pci / irq.c
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/irq.h>
15 #include <asm/io.h>
16 #include <asm/smp.h>
17 #include <asm/io_apic.h>
18 #include <asm/hw_irq.h>
19 #include <linux/acpi.h>
20
21 #include "pci.h"
22
23 #include <asm-xen/xen-public/xen.h>
24 #include <asm-xen/xen-public/physdev.h>
25
26 static int pirq_enable_irq(struct pci_dev *dev);
27
28 /*
29  * Never use: 0, 1, 2 (timer, keyboard, and cascade)
30  * Avoid using: 13, 14 and 15 (FP error and IDE).
31  * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
32  */
33 unsigned int pcibios_irq_mask = 0xfff8;
34
35 static int pirq_penalty[16] = {
36         1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
37         0, 0, 0, 0, 1000, 100000, 100000, 100000
38 };
39
40 int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
41
42 static int pirq_enable_irq(struct pci_dev *);
43
44 static int __init pcibios_irq_init(void)
45 {
46         int bus;
47         physdev_op_t op;
48
49         DBG("PCI: IRQ init\n");
50
51         if (pcibios_enable_irq || raw_pci_ops == NULL)
52                 return 0;
53
54         op.cmd = PHYSDEVOP_PCI_PROBE_ROOT_BUSES;
55         if (HYPERVISOR_physdev_op(&op) != 0) {
56                 printk(KERN_WARNING "PCI: System does not support PCI\n");
57                 return 0;
58         }
59
60         printk(KERN_INFO "PCI: Probing PCI hardware\n");
61         for (bus = 0; bus < 256; bus++)
62                 if (test_bit(bus, (unsigned long *)
63                         &op.u.pci_probe_root_buses.busmask[0]))
64                         (void)pcibios_scan_root(bus);
65
66         pcibios_enable_irq = pirq_enable_irq;
67
68         return 0;
69 }
70
71 subsys_initcall(pcibios_irq_init);
72
73
74 static void pirq_penalize_isa_irq(int irq)
75 {
76         /*
77          *  If any ISAPnP device reports an IRQ in its list of possible
78          *  IRQ's, we try to avoid assigning it to PCI devices.
79          */
80         if (irq < 16)
81                 pirq_penalty[irq] += 100;
82 }
83
84 void pcibios_penalize_isa_irq(int irq)
85 {
86 #ifdef CONFIG_ACPI_PCI
87         if (!acpi_noirq)
88                 acpi_penalize_isa_irq(irq);
89         else
90 #endif
91                 pirq_penalize_isa_irq(irq);
92 }
93
94 static int pirq_enable_irq(struct pci_dev *dev)
95 {
96         int err;
97         u8 pin;
98         physdev_op_t op;
99
100         /* Inform Xen that we are going to use this device. */
101         op.cmd = PHYSDEVOP_PCI_INITIALISE_DEVICE;
102         op.u.pci_initialise_device.bus  = dev->bus->number;
103         op.u.pci_initialise_device.dev  = PCI_SLOT(dev->devfn);
104         op.u.pci_initialise_device.func = PCI_FUNC(dev->devfn);
105         if ( (err = HYPERVISOR_physdev_op(&op)) != 0 )
106                 return err;
107
108         /* Now we can bind to the very final IRQ line. */
109         pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &pin);
110         dev->irq = pin;
111
112         /* Sanity-check that an interrupt-producing device is routed
113          * to an IRQ. */
114         pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
115         if (pin != 0) {
116                 if (dev->irq != 0)
117                         printk(KERN_INFO "PCI: Obtained IRQ %d for device %s\n",
118                             dev->irq, pci_name(dev));
119                 else
120                         printk(KERN_WARNING "PCI: No IRQ known for interrupt "
121                             "pin %c of device %s.\n", 'A' + pin - 1,
122                             pci_name(dev));
123         }
124
125         return 0;
126 }
127
128 int pci_vector_resources(int last, int nr_released)
129 {
130         int count = nr_released;
131
132         int next = last;
133         int offset = (last % 8);
134
135         while (next < FIRST_SYSTEM_VECTOR) {
136                 next += 8;
137 #ifdef CONFIG_X86_64
138                 if (next == IA32_SYSCALL_VECTOR)
139                         continue;
140 #else
141                 if (next == SYSCALL_VECTOR)
142                         continue;
143 #endif
144                 count++;
145                 if (next >= FIRST_SYSTEM_VECTOR) {
146                         if (offset%8) {
147                                 next = FIRST_DEVICE_VECTOR + offset;
148                                 offset++;
149                                 continue;
150                         }
151                         count--;
152                 }
153         }
154
155         return count;
156 }