xref: /openbmc/linux/drivers/irqchip/irq-gic-v2m.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * ARM GIC v2m MSI(-X) support
3  * Support for Message Signaled Interrupts for systems that
4  * implement ARM Generic Interrupt Controller: GICv2m.
5  *
6  * Copyright (C) 2014 Advanced Micro Devices, Inc.
7  * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
8  *	    Harish Kasiviswanathan <harish.kasiviswanathan@amd.com>
9  *	    Brandon Anderson <brandon.anderson@amd.com>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License version 2 as published
13  * by the Free Software Foundation.
14  */
15 
16 #define pr_fmt(fmt) "GICv2m: " fmt
17 
18 #include <linux/irq.h>
19 #include <linux/irqdomain.h>
20 #include <linux/kernel.h>
21 #include <linux/of_address.h>
22 #include <linux/of_pci.h>
23 #include <linux/slab.h>
24 #include <linux/spinlock.h>
25 
26 /*
27 * MSI_TYPER:
28 *     [31:26] Reserved
29 *     [25:16] lowest SPI assigned to MSI
30 *     [15:10] Reserved
31 *     [9:0]   Numer of SPIs assigned to MSI
32 */
33 #define V2M_MSI_TYPER		       0x008
34 #define V2M_MSI_TYPER_BASE_SHIFT       16
35 #define V2M_MSI_TYPER_BASE_MASK	       0x3FF
36 #define V2M_MSI_TYPER_NUM_MASK	       0x3FF
37 #define V2M_MSI_SETSPI_NS	       0x040
38 #define V2M_MIN_SPI		       32
39 #define V2M_MAX_SPI		       1019
40 
41 #define V2M_MSI_TYPER_BASE_SPI(x)      \
42 	       (((x) >> V2M_MSI_TYPER_BASE_SHIFT) & V2M_MSI_TYPER_BASE_MASK)
43 
44 #define V2M_MSI_TYPER_NUM_SPI(x)       ((x) & V2M_MSI_TYPER_NUM_MASK)
45 
46 struct v2m_data {
47 	spinlock_t msi_cnt_lock;
48 	struct resource res;	/* GICv2m resource */
49 	void __iomem *base;	/* GICv2m virt address */
50 	u32 spi_start;		/* The SPI number that MSIs start */
51 	u32 nr_spis;		/* The number of SPIs for MSIs */
52 	unsigned long *bm;	/* MSI vector bitmap */
53 };
54 
55 static void gicv2m_mask_msi_irq(struct irq_data *d)
56 {
57 	pci_msi_mask_irq(d);
58 	irq_chip_mask_parent(d);
59 }
60 
61 static void gicv2m_unmask_msi_irq(struct irq_data *d)
62 {
63 	pci_msi_unmask_irq(d);
64 	irq_chip_unmask_parent(d);
65 }
66 
67 static struct irq_chip gicv2m_msi_irq_chip = {
68 	.name			= "MSI",
69 	.irq_mask		= gicv2m_mask_msi_irq,
70 	.irq_unmask		= gicv2m_unmask_msi_irq,
71 	.irq_eoi		= irq_chip_eoi_parent,
72 	.irq_write_msi_msg	= pci_msi_domain_write_msg,
73 };
74 
75 static struct msi_domain_info gicv2m_msi_domain_info = {
76 	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
77 		   MSI_FLAG_PCI_MSIX),
78 	.chip	= &gicv2m_msi_irq_chip,
79 };
80 
81 static int gicv2m_set_affinity(struct irq_data *irq_data,
82 			       const struct cpumask *mask, bool force)
83 {
84 	int ret;
85 
86 	ret = irq_chip_set_affinity_parent(irq_data, mask, force);
87 	if (ret == IRQ_SET_MASK_OK)
88 		ret = IRQ_SET_MASK_OK_DONE;
89 
90 	return ret;
91 }
92 
93 static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
94 {
95 	struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
96 	phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS;
97 
98 	msg->address_hi = upper_32_bits(addr);
99 	msg->address_lo = lower_32_bits(addr);
100 	msg->data = data->hwirq;
101 }
102 
103 static struct irq_chip gicv2m_irq_chip = {
104 	.name			= "GICv2m",
105 	.irq_mask		= irq_chip_mask_parent,
106 	.irq_unmask		= irq_chip_unmask_parent,
107 	.irq_eoi		= irq_chip_eoi_parent,
108 	.irq_set_affinity	= gicv2m_set_affinity,
109 	.irq_compose_msi_msg	= gicv2m_compose_msi_msg,
110 };
111 
112 static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
113 				       unsigned int virq,
114 				       irq_hw_number_t hwirq)
115 {
116 	struct of_phandle_args args;
117 	struct irq_data *d;
118 	int err;
119 
120 	args.np = domain->parent->of_node;
121 	args.args_count = 3;
122 	args.args[0] = 0;
123 	args.args[1] = hwirq - 32;
124 	args.args[2] = IRQ_TYPE_EDGE_RISING;
125 
126 	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
127 	if (err)
128 		return err;
129 
130 	/* Configure the interrupt line to be edge */
131 	d = irq_domain_get_irq_data(domain->parent, virq);
132 	d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING);
133 	return 0;
134 }
135 
136 static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq)
137 {
138 	int pos;
139 
140 	pos = hwirq - v2m->spi_start;
141 	if (pos < 0 || pos >= v2m->nr_spis) {
142 		pr_err("Failed to teardown msi. Invalid hwirq %d\n", hwirq);
143 		return;
144 	}
145 
146 	spin_lock(&v2m->msi_cnt_lock);
147 	__clear_bit(pos, v2m->bm);
148 	spin_unlock(&v2m->msi_cnt_lock);
149 }
150 
151 static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
152 				   unsigned int nr_irqs, void *args)
153 {
154 	struct v2m_data *v2m = domain->host_data;
155 	int hwirq, offset, err = 0;
156 
157 	spin_lock(&v2m->msi_cnt_lock);
158 	offset = find_first_zero_bit(v2m->bm, v2m->nr_spis);
159 	if (offset < v2m->nr_spis)
160 		__set_bit(offset, v2m->bm);
161 	else
162 		err = -ENOSPC;
163 	spin_unlock(&v2m->msi_cnt_lock);
164 
165 	if (err)
166 		return err;
167 
168 	hwirq = v2m->spi_start + offset;
169 
170 	err = gicv2m_irq_gic_domain_alloc(domain, virq, hwirq);
171 	if (err) {
172 		gicv2m_unalloc_msi(v2m, hwirq);
173 		return err;
174 	}
175 
176 	irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
177 				      &gicv2m_irq_chip, v2m);
178 
179 	return 0;
180 }
181 
182 static void gicv2m_irq_domain_free(struct irq_domain *domain,
183 				   unsigned int virq, unsigned int nr_irqs)
184 {
185 	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
186 	struct v2m_data *v2m = irq_data_get_irq_chip_data(d);
187 
188 	BUG_ON(nr_irqs != 1);
189 	gicv2m_unalloc_msi(v2m, d->hwirq);
190 	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
191 }
192 
193 static const struct irq_domain_ops gicv2m_domain_ops = {
194 	.alloc			= gicv2m_irq_domain_alloc,
195 	.free			= gicv2m_irq_domain_free,
196 };
197 
198 static bool is_msi_spi_valid(u32 base, u32 num)
199 {
200 	if (base < V2M_MIN_SPI) {
201 		pr_err("Invalid MSI base SPI (base:%u)\n", base);
202 		return false;
203 	}
204 
205 	if ((num == 0) || (base + num > V2M_MAX_SPI)) {
206 		pr_err("Number of SPIs (%u) exceed maximum (%u)\n",
207 		       num, V2M_MAX_SPI - V2M_MIN_SPI + 1);
208 		return false;
209 	}
210 
211 	return true;
212 }
213 
214 static struct irq_chip gicv2m_pmsi_irq_chip = {
215 	.name			= "pMSI",
216 };
217 
218 static struct msi_domain_ops gicv2m_pmsi_ops = {
219 };
220 
221 static struct msi_domain_info gicv2m_pmsi_domain_info = {
222 	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
223 	.ops	= &gicv2m_pmsi_ops,
224 	.chip	= &gicv2m_pmsi_irq_chip,
225 };
226 
227 static int __init gicv2m_init_one(struct device_node *node,
228 				  struct irq_domain *parent)
229 {
230 	int ret;
231 	struct v2m_data *v2m;
232 	struct irq_domain *inner_domain, *pci_domain, *plat_domain;
233 
234 	v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL);
235 	if (!v2m) {
236 		pr_err("Failed to allocate struct v2m_data.\n");
237 		return -ENOMEM;
238 	}
239 
240 	ret = of_address_to_resource(node, 0, &v2m->res);
241 	if (ret) {
242 		pr_err("Failed to allocate v2m resource.\n");
243 		goto err_free_v2m;
244 	}
245 
246 	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
247 	if (!v2m->base) {
248 		pr_err("Failed to map GICv2m resource\n");
249 		ret = -ENOMEM;
250 		goto err_free_v2m;
251 	}
252 
253 	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
254 	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
255 		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
256 			v2m->spi_start, v2m->nr_spis);
257 	} else {
258 		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
259 
260 		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
261 		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
262 	}
263 
264 	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
265 		ret = -EINVAL;
266 		goto err_iounmap;
267 	}
268 
269 	v2m->bm = kzalloc(sizeof(long) * BITS_TO_LONGS(v2m->nr_spis),
270 			  GFP_KERNEL);
271 	if (!v2m->bm) {
272 		ret = -ENOMEM;
273 		goto err_iounmap;
274 	}
275 
276 	inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
277 	if (!inner_domain) {
278 		pr_err("Failed to create GICv2m domain\n");
279 		ret = -ENOMEM;
280 		goto err_free_bm;
281 	}
282 
283 	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
284 	inner_domain->parent = parent;
285 	pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
286 					       inner_domain);
287 	plat_domain = platform_msi_create_irq_domain(node,
288 						     &gicv2m_pmsi_domain_info,
289 						     inner_domain);
290 	if (!pci_domain || !plat_domain) {
291 		pr_err("Failed to create MSI domains\n");
292 		ret = -ENOMEM;
293 		goto err_free_domains;
294 	}
295 
296 	spin_lock_init(&v2m->msi_cnt_lock);
297 
298 	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
299 		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
300 		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
301 
302 	return 0;
303 
304 err_free_domains:
305 	if (plat_domain)
306 		irq_domain_remove(plat_domain);
307 	if (pci_domain)
308 		irq_domain_remove(pci_domain);
309 	if (inner_domain)
310 		irq_domain_remove(inner_domain);
311 err_free_bm:
312 	kfree(v2m->bm);
313 err_iounmap:
314 	iounmap(v2m->base);
315 err_free_v2m:
316 	kfree(v2m);
317 	return ret;
318 }
319 
320 static struct of_device_id gicv2m_device_id[] = {
321 	{	.compatible	= "arm,gic-v2m-frame",	},
322 	{},
323 };
324 
325 int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
326 {
327 	int ret = 0;
328 	struct device_node *child;
329 
330 	for (child = of_find_matching_node(node, gicv2m_device_id); child;
331 	     child = of_find_matching_node(child, gicv2m_device_id)) {
332 		if (!of_find_property(child, "msi-controller", NULL))
333 			continue;
334 
335 		ret = gicv2m_init_one(child, parent);
336 		if (ret) {
337 			of_node_put(node);
338 			break;
339 		}
340 	}
341 
342 	return ret;
343 }
344