Fixes a off-by-one error when routing the IRQs. This led to IRQ15 not
[coreboot.git] / src / arch / i386 / boot / pirq_routing.c
1 #include <console/console.h>
2 #include <arch/pirq_routing.h>
3 #include <string.h>
4 #include <device/pci.h>
5
6 #if (DEBUG==1 && HAVE_PIRQ_TABLE==1)
7 static void check_pirq_routing_table(struct irq_routing_table *rt)
8 {
9         uint8_t *addr = (uint8_t *)rt;
10         uint8_t sum=0;
11         int i;
12
13         printk_info("Checking IRQ routing table consistency...\n");
14
15 #if defined(IRQ_SLOT_COUNT)
16         if (sizeof(struct irq_routing_table) != rt->size) {
17                 printk_warning("Inconsistent IRQ routing table size (0x%x/0x%x)\n",
18                                sizeof(struct irq_routing_table),
19                                rt->size
20                         );
21                 rt->size=sizeof(struct irq_routing_table);
22         }
23 #endif
24
25         for (i = 0; i < rt->size; i++)
26                 sum += addr[i];
27
28         printk_debug("%s() - irq_routing_table located at: 0x%p\n",
29                      __FUNCTION__, addr);
30
31         
32         sum = rt->checksum - sum;
33
34         if (sum != rt->checksum) {
35                 printk_warning("%s:%6d:%s() - "
36                                "checksum is: 0x%02x but should be: 0x%02x\n",
37                                __FILE__, __LINE__, __FUNCTION__, rt->checksum, sum);
38                 rt->checksum = sum;
39         }
40
41         if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
42             rt->size % 16 ) {
43                 printk_warning("%s:%6d:%s() - "
44                                "Interrupt Routing Table not valid\n",
45                                __FILE__, __LINE__, __FUNCTION__);
46                 return;
47         }
48
49         sum = 0;
50         for (i=0; i<rt->size; i++)
51                 sum += addr[i];
52
53         if (sum) {
54                 printk_warning("%s:%6d:%s() - "
55                                "checksum error in irq routing table\n",
56                                __FILE__, __LINE__, __FUNCTION__);
57         }
58
59         printk_info("done.\n");
60 }
61
62 static int verify_copy_pirq_routing_table(unsigned long addr)
63 {
64         int i;
65         uint8_t *rt_orig, *rt_curr;
66
67         rt_curr = (uint8_t*)addr;
68         rt_orig = (uint8_t*)&intel_irq_routing_table;
69         printk_info("Verifing copy of IRQ routing tables at 0x%x...", addr);
70         for (i = 0; i < intel_irq_routing_table.size; i++) {
71                 if (*(rt_curr + i) != *(rt_orig + i)) {
72                         printk_info("failed\n");
73                         return -1;
74                 }
75         }
76         printk_info("done\n");
77         
78         check_pirq_routing_table((struct irq_routing_table *)addr);
79         
80         return 0;
81 }
82 #else
83 #define verify_copy_pirq_routing_table(addr)
84 #endif
85
86 #if HAVE_PIRQ_TABLE==1
87 unsigned long copy_pirq_routing_table(unsigned long addr)
88 {
89         /* Align the table to be 16 byte aligned. */
90         addr += 15;
91         addr &= ~15;
92
93         /* This table must be betweeen 0xf0000 & 0x100000 */
94         printk_info("Copying IRQ routing tables to 0x%x...", addr);
95         memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size);
96         printk_info("done.\n");
97         verify_copy_pirq_routing_table(addr);
98         pirq_routing_irqs(addr);
99         return addr + intel_irq_routing_table.size;
100 }
101 #endif
102
103 #if (PIRQ_ROUTE==1 && HAVE_PIRQ_TABLE==1)
104 void pirq_routing_irqs(unsigned long addr)
105 {
106         int i, j, k, num_entries;
107         unsigned char irq_slot[4];
108         unsigned char pirq[4] = {0, 0, 0, 0};
109         struct irq_routing_table *pirq_tbl;
110         device_t pdev;
111
112         pirq_tbl = (struct irq_routing_table *)(addr);
113         num_entries = (pirq_tbl->size - 32) / 16;
114
115         /* Set PCI IRQs. */
116         for (i = 0; i < num_entries; i++) {
117
118                 printk_debug("PIR Entry %d Dev/Fn: %X Slot: %d\n", i,
119                         pirq_tbl->slots[i].devfn >> 3, pirq_tbl->slots[i].slot);
120
121                 for (j = 0; j < 4; j++) {
122
123                         int link = pirq_tbl->slots[i].irq[j].link;
124                         int bitmap = pirq_tbl->slots[i].irq[j].bitmap;
125                         int irq = 0;
126
127                         printk_debug("INT: %c link: %x bitmap: %x  ",
128                                 'A' + j, link, bitmap);
129
130                         if (!bitmap|| !link || link > 4) {
131
132                                 printk_debug("not routed\n");
133                                 irq_slot[j] = irq;
134                                 continue;
135                         }
136
137                         /* yet not routed */
138                         if (!pirq[link - 1]) {
139
140                                 for (k = 2; k <= 15; k++) {
141
142                                         if (!((bitmap >> k) & 1))
143                                                 continue;
144
145                                         irq = k;
146
147                                         /* yet not routed */
148                                         if (pirq[0] != irq && pirq[1] != irq && pirq[2] != irq && pirq[3] != irq)
149                                                 break;
150                                 }
151
152                                 if (irq)
153                                         pirq[link - 1] = irq;
154                         }
155                         else
156                                 irq = pirq[link - 1];
157
158                         printk_debug("IRQ: %d\n", irq);
159                         irq_slot[j] = irq;
160                 }
161
162                 /* Bus, device, slots IRQs for {A,B,C,D}. */
163                 pci_assign_irqs(pirq_tbl->slots[i].bus,
164                         pirq_tbl->slots[i].devfn >> 3, irq_slot);
165         }
166
167         printk_debug("PIRQ1: %d\n", pirq[0]);
168         printk_debug("PIRQ2: %d\n", pirq[1]);
169         printk_debug("PIRQ3: %d\n", pirq[2]);
170         printk_debug("PIRQ4: %d\n", pirq[3]);
171
172         pirq_assign_irqs(pirq);
173 }
174 #endif