Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 1 | #include <console/console.h> |
| 2 | #include <arch/pirq_routing.h> |
| 3 | #include <string.h> |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 4 | #include <device/pci.h> |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 5 | |
Myles Watson | 80e914ff | 2010-06-01 19:25:31 +0000 | [diff] [blame] | 6 | #if CONFIG_DEBUG_PIRQ |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 7 | static void check_pirq_routing_table(struct irq_routing_table *rt) |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 8 | { |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 9 | uint8_t *addr = (uint8_t *)rt; |
| 10 | uint8_t sum=0; |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 11 | int i; |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 12 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 13 | printk(BIOS_INFO, "Checking Interrupt Routing Table consistency...\n"); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 14 | |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 15 | if (sizeof(struct irq_routing_table) != rt->size) { |
Myles Watson | 80e914ff | 2010-06-01 19:25:31 +0000 | [diff] [blame] | 16 | printk(BIOS_WARNING, "Inconsistent Interrupt Routing Table size (0x%lx/0x%x).\n", |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 17 | sizeof(struct irq_routing_table), |
| 18 | rt->size |
Li-Ta Lo | 8e79fc3 | 2004-04-15 17:33:21 +0000 | [diff] [blame] | 19 | ); |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 20 | rt->size=sizeof(struct irq_routing_table); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 21 | } |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 22 | |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 23 | for (i = 0; i < rt->size; i++) |
| 24 | sum += addr[i]; |
| 25 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 26 | printk(BIOS_DEBUG, "%s(): Interrupt Routing Table located at %p.\n", |
Myles Watson | 552b327 | 2009-02-12 21:30:06 +0000 | [diff] [blame] | 27 | __func__, addr); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 28 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 29 | |
Eric Biederman | eb00fa5 | 2003-04-25 02:02:25 +0000 | [diff] [blame] | 30 | sum = rt->checksum - sum; |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 31 | |
| 32 | if (sum != rt->checksum) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 33 | printk(BIOS_WARNING, "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n", |
Stefan Reinauer | 94f1777 | 2009-01-20 19:21:47 +0000 | [diff] [blame] | 34 | rt->checksum, sum); |
Stefan Reinauer | 40cba39 | 2003-10-28 17:02:10 +0000 | [diff] [blame] | 35 | rt->checksum = sum; |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION || |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 39 | rt->size % 16 ) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 40 | printk(BIOS_WARNING, "Interrupt Routing Table not valid.\n"); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 41 | return; |
| 42 | } |
| 43 | |
| 44 | sum = 0; |
| 45 | for (i=0; i<rt->size; i++) |
| 46 | sum += addr[i]; |
| 47 | |
Stefan Reinauer | 94f1777 | 2009-01-20 19:21:47 +0000 | [diff] [blame] | 48 | /* We're manually fixing the checksum above. This warning can probably |
| 49 | * never happen because if the target location is read-only this |
| 50 | * function would have bailed out earlier. |
| 51 | */ |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 52 | if (sum) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 53 | printk(BIOS_WARNING, "Checksum error in Interrupt Routing Table " |
Myles Watson | 80e914ff | 2010-06-01 19:25:31 +0000 | [diff] [blame] | 54 | "could not be fixed.\n"); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 55 | } |
| 56 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 57 | printk(BIOS_INFO, "done.\n"); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 58 | } |
| 59 | |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 60 | static int verify_copy_pirq_routing_table(unsigned long addr) |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 61 | { |
| 62 | int i; |
Eric Biederman | 8cd55d7 | 2003-04-24 06:56:37 +0000 | [diff] [blame] | 63 | uint8_t *rt_orig, *rt_curr; |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 64 | |
Eric Biederman | 8cd55d7 | 2003-04-24 06:56:37 +0000 | [diff] [blame] | 65 | rt_curr = (uint8_t*)addr; |
| 66 | rt_orig = (uint8_t*)&intel_irq_routing_table; |
Marc Bertens | e9d4bcc | 2010-06-01 19:28:45 +0000 | [diff] [blame^] | 67 | printk(BIOS_INFO, "Verifying copy of Interrupt Routing Table at 0x%08lx... ", addr); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 68 | for (i = 0; i < intel_irq_routing_table.size; i++) { |
| 69 | if (*(rt_curr + i) != *(rt_orig + i)) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 70 | printk(BIOS_INFO, "failed\n"); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 71 | return -1; |
| 72 | } |
| 73 | } |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 74 | printk(BIOS_INFO, "done\n"); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 75 | |
Stefan Reinauer | 0b607b3 | 2004-06-07 10:25:42 +0000 | [diff] [blame] | 76 | check_pirq_routing_table((struct irq_routing_table *)addr); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 77 | |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 78 | return 0; |
| 79 | } |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 80 | #endif |
| 81 | |
| 82 | unsigned long copy_pirq_routing_table(unsigned long addr) |
| 83 | { |
| 84 | /* Align the table to be 16 byte aligned. */ |
| 85 | addr += 15; |
| 86 | addr &= ~15; |
| 87 | |
| 88 | /* This table must be betweeen 0xf0000 & 0x100000 */ |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 89 | printk(BIOS_INFO, "Copying Interrupt Routing Table to 0x%08lx... ", addr); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 90 | memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size); |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 91 | printk(BIOS_INFO, "done.\n"); |
Myles Watson | 80e914ff | 2010-06-01 19:25:31 +0000 | [diff] [blame] | 92 | #if CONFIG_DEBUG_PIRQ |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 93 | verify_copy_pirq_routing_table(addr); |
Stefan Reinauer | 159b012 | 2010-02-22 07:28:06 +0000 | [diff] [blame] | 94 | #endif |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 95 | pirq_routing_irqs(addr); |
Eric Biederman | 8ca8d76 | 2003-04-22 19:02:15 +0000 | [diff] [blame] | 96 | return addr + intel_irq_routing_table.size; |
| 97 | } |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 98 | |
Stefan Reinauer | de3206a | 2010-02-22 06:09:43 +0000 | [diff] [blame] | 99 | #if CONFIG_PIRQ_ROUTE |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 100 | void pirq_routing_irqs(unsigned long addr) |
| 101 | { |
| 102 | int i, j, k, num_entries; |
| 103 | unsigned char irq_slot[4]; |
| 104 | unsigned char pirq[4] = {0, 0, 0, 0}; |
| 105 | struct irq_routing_table *pirq_tbl; |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 106 | |
| 107 | pirq_tbl = (struct irq_routing_table *)(addr); |
| 108 | num_entries = (pirq_tbl->size - 32) / 16; |
| 109 | |
| 110 | /* Set PCI IRQs. */ |
| 111 | for (i = 0; i < num_entries; i++) { |
| 112 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 113 | printk(BIOS_DEBUG, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i, |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 114 | pirq_tbl->slots[i].devfn >> 3, pirq_tbl->slots[i].slot); |
| 115 | |
| 116 | for (j = 0; j < 4; j++) { |
| 117 | |
| 118 | int link = pirq_tbl->slots[i].irq[j].link; |
Marc Jones(marc.jones | df22f78 | 2008-04-07 17:49:57 +0000 | [diff] [blame] | 119 | int bitmap = pirq_tbl->slots[i].irq[j].bitmap; |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 120 | int irq = 0; |
| 121 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 122 | printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ", |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 123 | 'A' + j, link, bitmap); |
| 124 | |
| 125 | if (!bitmap|| !link || link > 4) { |
| 126 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 127 | printk(BIOS_DEBUG, "not routed\n"); |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 128 | irq_slot[j] = irq; |
| 129 | continue; |
| 130 | } |
| 131 | |
| 132 | /* yet not routed */ |
| 133 | if (!pirq[link - 1]) { |
| 134 | |
Jens Rottmann | 9a9e61b | 2008-10-22 22:20:48 +0000 | [diff] [blame] | 135 | for (k = 2; k <= 15; k++) { |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 136 | |
| 137 | if (!((bitmap >> k) & 1)) |
| 138 | continue; |
| 139 | |
| 140 | irq = k; |
| 141 | |
| 142 | /* yet not routed */ |
| 143 | if (pirq[0] != irq && pirq[1] != irq && pirq[2] != irq && pirq[3] != irq) |
| 144 | break; |
| 145 | } |
| 146 | |
| 147 | if (irq) |
| 148 | pirq[link - 1] = irq; |
| 149 | } |
| 150 | else |
| 151 | irq = pirq[link - 1]; |
| 152 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 153 | printk(BIOS_DEBUG, "IRQ: %d\n", irq); |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 154 | irq_slot[j] = irq; |
| 155 | } |
| 156 | |
| 157 | /* Bus, device, slots IRQs for {A,B,C,D}. */ |
| 158 | pci_assign_irqs(pirq_tbl->slots[i].bus, |
| 159 | pirq_tbl->slots[i].devfn >> 3, irq_slot); |
| 160 | } |
| 161 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 162 | printk(BIOS_DEBUG, "PIRQ1: %d\n", pirq[0]); |
| 163 | printk(BIOS_DEBUG, "PIRQ2: %d\n", pirq[1]); |
| 164 | printk(BIOS_DEBUG, "PIRQ3: %d\n", pirq[2]); |
| 165 | printk(BIOS_DEBUG, "PIRQ4: %d\n", pirq[3]); |
Nikolay Petukhov | 9c2255c | 2008-03-29 16:59:27 +0000 | [diff] [blame] | 166 | |
| 167 | pirq_assign_irqs(pirq); |
| 168 | } |
| 169 | #endif |