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 inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, 62 u8 device, u8 func, u8 pin, u8 pirq) 63 { 64 struct irq_info *slot = *slotp; 65 66 slot->bus = bus; 67 slot->devfn = (device << 3) | func; 68 slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); 69 slot->irq[pin - 1].bitmap = irq_router.irq_mask; 70 (*entries)++; 71 (*slotp)++; 72 } 73 74 __weak void cpu_irq_init(void) 75 { 76 return; 77 } 78 79 static int create_pirq_routing_table(void) 80 { 81 const void *blob = gd->fdt_blob; 82 struct fdt_pci_addr addr; 83 int node; 84 int len, count; 85 const u32 *cell; 86 struct irq_routing_table *rt; 87 struct irq_info *slot; 88 int irq_entries = 0; 89 int i; 90 int ret; 91 92 node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); 93 if (node < 0) { 94 debug("%s: Cannot find irq router node\n", __func__); 95 return -EINVAL; 96 } 97 98 ret = fdtdec_get_pci_addr(blob, node, FDT_PCI_SPACE_CONFIG, 99 "reg", &addr); 100 if (ret) 101 return ret; 102 103 /* extract the bdf from fdt_pci_addr */ 104 irq_router.bdf = addr.phys_hi & 0xffff00; 105 106 ret = fdt_find_string(blob, node, "intel,pirq-config", "pci"); 107 if (!ret) { 108 irq_router.config = PIRQ_VIA_PCI; 109 } else { 110 ret = fdt_find_string(blob, node, "intel,pirq-config", "ibase"); 111 if (!ret) 112 irq_router.config = PIRQ_VIA_IBASE; 113 else 114 return -EINVAL; 115 } 116 117 ret = fdtdec_get_int_array(blob, node, "intel,pirq-link", 118 &irq_router.link_base, 1); 119 if (ret) 120 return ret; 121 122 irq_router.irq_mask = fdtdec_get_int(blob, node, 123 "intel,pirq-mask", PIRQ_BITMAP); 124 125 if (irq_router.config == PIRQ_VIA_IBASE) { 126 int ibase_off; 127 128 ibase_off = fdtdec_get_int(blob, node, "intel,ibase-offset", 0); 129 if (!ibase_off) 130 return -EINVAL; 131 132 /* 133 * Here we assume that the IBASE register has already been 134 * properly configured by U-Boot before. 135 * 136 * By 'valid' we mean: 137 * 1) a valid memory space carved within system memory space 138 * assigned to IBASE register block. 139 * 2) memory range decoding is enabled. 140 * Hence we don't do any santify test here. 141 */ 142 irq_router.ibase = x86_pci_read_config32(irq_router.bdf, 143 ibase_off); 144 irq_router.ibase &= ~0xf; 145 } 146 147 cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); 148 if (!cell) 149 return -EINVAL; 150 151 if ((len % sizeof(struct pirq_routing)) == 0) 152 count = len / sizeof(struct pirq_routing); 153 else 154 return -EINVAL; 155 156 rt = malloc(sizeof(struct irq_routing_table)); 157 if (!rt) 158 return -ENOMEM; 159 memset((char *)rt, 0, sizeof(struct irq_routing_table)); 160 161 /* Populate the PIRQ table fields */ 162 rt->signature = PIRQ_SIGNATURE; 163 rt->version = PIRQ_VERSION; 164 rt->rtr_bus = 0; 165 rt->rtr_devfn = (PCI_DEV(irq_router.bdf) << 3) | 166 PCI_FUNC(irq_router.bdf); 167 rt->rtr_vendor = PCI_VENDOR_ID_INTEL; 168 rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; 169 170 slot = rt->slots; 171 172 /* Now fill in the irq_info entries in the PIRQ table */ 173 for (i = 0; i < count; i++) { 174 struct pirq_routing pr; 175 176 pr.bdf = fdt_addr_to_cpu(cell[0]); 177 pr.pin = fdt_addr_to_cpu(cell[1]); 178 pr.pirq = fdt_addr_to_cpu(cell[2]); 179 180 debug("irq_info %d: b.d.f %x.%x.%x INT%c PIRQ%c\n", 181 i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), 182 PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 183 'A' + pr.pirq); 184 fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf), 185 PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), 186 pr.pin, pr.pirq); 187 cell += sizeof(struct pirq_routing) / sizeof(u32); 188 } 189 190 rt->size = irq_entries * sizeof(struct irq_info) + 32; 191 192 pirq_routing_table = rt; 193 194 return 0; 195 } 196 197 void pirq_init(void) 198 { 199 cpu_irq_init(); 200 201 if (create_pirq_routing_table()) { 202 debug("Failed to create pirq routing table\n"); 203 } else { 204 /* Route PIRQ */ 205 pirq_route_irqs(pirq_routing_table->slots, 206 get_irq_slot_count(pirq_routing_table)); 207 } 208 } 209 210 u32 write_pirq_routing_table(u32 addr) 211 { 212 if (!pirq_routing_table) 213 return addr; 214 215 return copy_pirq_routing_table(addr, pirq_routing_table); 216 } 217