xref: /openbmc/u-boot/arch/x86/cpu/irq.c (revision 5e90470a)
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