1 /* 2 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <errno.h> 9 #include <fdtdec.h> 10 #include <malloc.h> 11 #include <asm/io.h> 12 #include <asm/irq.h> 13 #include <asm/pci.h> 14 #include <asm/pirq_routing.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 static struct irq_router irq_router; 19 static struct irq_routing_table *pirq_routing_table; 20 21 bool pirq_check_irq_routed(int link, u8 irq) 22 { 23 u8 pirq; 24 int base = irq_router.link_base; 25 26 if (irq_router.config == PIRQ_VIA_PCI) 27 pirq = x86_pci_read_config8(irq_router.bdf, 28 LINK_N2V(link, base)); 29 else 30 pirq = readb(irq_router.ibase + LINK_N2V(link, base)); 31 32 pirq &= 0xf; 33 34 /* IRQ# 0/1/2/8/13 are reserved */ 35 if (pirq < 3 || pirq == 8 || pirq == 13) 36 return false; 37 38 return pirq == irq ? true : false; 39 } 40 41 int pirq_translate_link(int link) 42 { 43 return LINK_V2N(link, irq_router.link_base); 44 } 45 46 void pirq_assign_irq(int link, u8 irq) 47 { 48 int base = irq_router.link_base; 49 50 /* IRQ# 0/1/2/8/13 are reserved */ 51 if (irq < 3 || irq == 8 || irq == 13) 52 return; 53 54 if (irq_router.config == PIRQ_VIA_PCI) 55 x86_pci_write_config8(irq_router.bdf, 56 LINK_N2V(link, base), irq); 57 else 58 writeb(irq, irq_router.ibase + LINK_N2V(link, base)); 59 } 60 61 static struct irq_info *check_dup_entry(struct irq_info *slot_base, 62 int entry_num, int bus, int device) 63 { 64 struct irq_info *slot = slot_base; 65 int i; 66 67 for (i = 0; i < entry_num; i++) { 68 if (slot->bus == bus && slot->devfn == (device << 3)) 69 break; 70 slot++; 71 } 72 73 return (i == entry_num) ? NULL : slot; 74 } 75 76 static inline void fill_irq_info(struct irq_info *slot, int bus, int device, 77 int pin, int pirq) 78 { 79 slot->bus = bus; 80 slot->devfn = (device << 3) | 0; 81 slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); 82 slot->irq[pin - 1].bitmap = irq_router.irq_mask; 83 } 84 85 __weak void cpu_irq_init(void) 86 { 87 return; 88 } 89 90 static int create_pirq_routing_table(void) 91 { 92 const void *blob = gd->fdt_blob; 93 struct fdt_pci_addr addr; 94 int node; 95 int len, count; 96 const u32 *cell; 97 struct irq_routing_table *rt; 98 struct irq_info *slot, *slot_base; 99 int irq_entries = 0; 100 int i; 101 int ret; 102 103 node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); 104 if (node < 0) { 105 debug("%s: Cannot find irq router node\n", __func__); 106 return -EINVAL; 107 } 108 109 ret = fdtdec_get_pci_addr(blob, node, FDT_PCI_SPACE_CONFIG, 110 "reg", &addr); 111 if (ret) 112 return ret; 113 114 /* extract the bdf from fdt_pci_addr */ 115 irq_router.bdf = addr.phys_hi & 0xffff00; 116 117 ret = fdt_find_string(blob, node, "intel,pirq-config", "pci"); 118 if (!ret) { 119 irq_router.config = PIRQ_VIA_PCI; 120 } else { 121 ret = fdt_find_string(blob, node, "intel,pirq-config", "ibase"); 122 if (!ret) 123 irq_router.config = PIRQ_VIA_IBASE; 124 else 125 return -EINVAL; 126 } 127 128 ret = fdtdec_get_int(blob, node, "intel,pirq-link", -1); 129 if (ret == -1) 130 return ret; 131 irq_router.link_base = ret; 132 133 irq_router.irq_mask = fdtdec_get_int(blob, node, 134 "intel,pirq-mask", PIRQ_BITMAP); 135 136 if (irq_router.config == PIRQ_VIA_IBASE) { 137 int ibase_off; 138 139 ibase_off = fdtdec_get_int(blob, node, "intel,ibase-offset", 0); 140 if (!ibase_off) 141 return -EINVAL; 142 143 /* 144 * Here we assume that the IBASE register has already been 145 * properly configured by U-Boot before. 146 * 147 * By 'valid' we mean: 148 * 1) a valid memory space carved within system memory space 149 * assigned to IBASE register block. 150 * 2) memory range decoding is enabled. 151 * Hence we don't do any santify test here. 152 */ 153 irq_router.ibase = x86_pci_read_config32(irq_router.bdf, 154 ibase_off); 155 irq_router.ibase &= ~0xf; 156 } 157 158 cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); 159 if (!cell || len % sizeof(struct pirq_routing)) 160 return -EINVAL; 161 count = len / sizeof(struct pirq_routing); 162 163 rt = calloc(1, sizeof(struct irq_routing_table)); 164 if (!rt) 165 return -ENOMEM; 166 167 /* Populate the PIRQ table fields */ 168 rt->signature = PIRQ_SIGNATURE; 169 rt->version = PIRQ_VERSION; 170 rt->rtr_bus = PCI_BUS(irq_router.bdf); 171 rt->rtr_devfn = (PCI_DEV(irq_router.bdf) << 3) | 172 PCI_FUNC(irq_router.bdf); 173 rt->rtr_vendor = PCI_VENDOR_ID_INTEL; 174 rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; 175 176 slot_base = rt->slots; 177 178 /* Now fill in the irq_info entries in the PIRQ table */ 179 for (i = 0; i < count; 180 i++, cell += sizeof(struct pirq_routing) / sizeof(u32)) { 181 struct pirq_routing pr; 182 183 pr.bdf = fdt_addr_to_cpu(cell[0]); 184 pr.pin = fdt_addr_to_cpu(cell[1]); 185 pr.pirq = fdt_addr_to_cpu(cell[2]); 186 187 debug("irq_info %d: b.d.f %x.%x.%x INT%c PIRQ%c\n", 188 i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), 189 PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 190 'A' + pr.pirq); 191 192 slot = check_dup_entry(slot_base, irq_entries, 193 PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); 194 if (slot) { 195 debug("found entry for bus %d device %d, ", 196 PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); 197 198 if (slot->irq[pr.pin - 1].link) { 199 debug("skipping\n"); 200 201 /* 202 * Sanity test on the routed PIRQ pin 203 * 204 * If they don't match, show a warning to tell 205 * there might be something wrong with the PIRQ 206 * routing information in the device tree. 207 */ 208 if (slot->irq[pr.pin - 1].link != 209 LINK_N2V(pr.pirq, irq_router.link_base)) 210 debug("WARNING: Inconsistent PIRQ routing information\n"); 211 continue; 212 } 213 } else { 214 slot = slot_base + irq_entries++; 215 } 216 debug("writing INT%c\n", 'A' + pr.pin - 1); 217 fill_irq_info(slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin, 218 pr.pirq); 219 } 220 221 rt->size = irq_entries * sizeof(struct irq_info) + 32; 222 223 pirq_routing_table = rt; 224 225 return 0; 226 } 227 228 int pirq_init(void) 229 { 230 int ret; 231 232 cpu_irq_init(); 233 234 ret = create_pirq_routing_table(); 235 if (ret) { 236 debug("Failed to create pirq routing table\n"); 237 return ret; 238 } 239 /* Route PIRQ */ 240 pirq_route_irqs(pirq_routing_table->slots, 241 get_irq_slot_count(pirq_routing_table)); 242 243 return 0; 244 } 245 246 u32 write_pirq_routing_table(u32 addr) 247 { 248 if (!pirq_routing_table) 249 return addr; 250 251 return copy_pirq_routing_table(addr, pirq_routing_table); 252 } 253