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
46struct v2m_data {
47	spinlock_t msi_cnt_lock;
48	struct msi_controller mchip;
49	struct resource res;	/* GICv2m resource */
50	void __iomem *base;	/* GICv2m virt address */
51	u32 spi_start;		/* The SPI number that MSIs start */
52	u32 nr_spis;		/* The number of SPIs for MSIs */
53	unsigned long *bm;	/* MSI vector bitmap */
54	struct irq_domain *domain;
55};
56
57static void gicv2m_mask_msi_irq(struct irq_data *d)
58{
59	pci_msi_mask_irq(d);
60	irq_chip_mask_parent(d);
61}
62
63static void gicv2m_unmask_msi_irq(struct irq_data *d)
64{
65	pci_msi_unmask_irq(d);
66	irq_chip_unmask_parent(d);
67}
68
69static struct irq_chip gicv2m_msi_irq_chip = {
70	.name			= "MSI",
71	.irq_mask		= gicv2m_mask_msi_irq,
72	.irq_unmask		= gicv2m_unmask_msi_irq,
73	.irq_eoi		= irq_chip_eoi_parent,
74	.irq_write_msi_msg	= pci_msi_domain_write_msg,
75};
76
77static struct msi_domain_info gicv2m_msi_domain_info = {
78	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
79		   MSI_FLAG_PCI_MSIX),
80	.chip	= &gicv2m_msi_irq_chip,
81};
82
83static int gicv2m_set_affinity(struct irq_data *irq_data,
84			       const struct cpumask *mask, bool force)
85{
86	int ret;
87
88	ret = irq_chip_set_affinity_parent(irq_data, mask, force);
89	if (ret == IRQ_SET_MASK_OK)
90		ret = IRQ_SET_MASK_OK_DONE;
91
92	return ret;
93}
94
95static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
96{
97	struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
98	phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS;
99
100	msg->address_hi = (u32) (addr >> 32);
101	msg->address_lo = (u32) (addr);
102	msg->data = data->hwirq;
103}
104
105static struct irq_chip gicv2m_irq_chip = {
106	.name			= "GICv2m",
107	.irq_mask		= irq_chip_mask_parent,
108	.irq_unmask		= irq_chip_unmask_parent,
109	.irq_eoi		= irq_chip_eoi_parent,
110	.irq_set_affinity	= gicv2m_set_affinity,
111	.irq_compose_msi_msg	= gicv2m_compose_msi_msg,
112};
113
114static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
115				       unsigned int virq,
116				       irq_hw_number_t hwirq)
117{
118	struct of_phandle_args args;
119	struct irq_data *d;
120	int err;
121
122	args.np = domain->parent->of_node;
123	args.args_count = 3;
124	args.args[0] = 0;
125	args.args[1] = hwirq - 32;
126	args.args[2] = IRQ_TYPE_EDGE_RISING;
127
128	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
129	if (err)
130		return err;
131
132	/* Configure the interrupt line to be edge */
133	d = irq_domain_get_irq_data(domain->parent, virq);
134	d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING);
135	return 0;
136}
137
138static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq)
139{
140	int pos;
141
142	pos = hwirq - v2m->spi_start;
143	if (pos < 0 || pos >= v2m->nr_spis) {
144		pr_err("Failed to teardown msi. Invalid hwirq %d\n", hwirq);
145		return;
146	}
147
148	spin_lock(&v2m->msi_cnt_lock);
149	__clear_bit(pos, v2m->bm);
150	spin_unlock(&v2m->msi_cnt_lock);
151}
152
153static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
154				   unsigned int nr_irqs, void *args)
155{
156	struct v2m_data *v2m = domain->host_data;
157	int hwirq, offset, err = 0;
158
159	spin_lock(&v2m->msi_cnt_lock);
160	offset = find_first_zero_bit(v2m->bm, v2m->nr_spis);
161	if (offset < v2m->nr_spis)
162		__set_bit(offset, v2m->bm);
163	else
164		err = -ENOSPC;
165	spin_unlock(&v2m->msi_cnt_lock);
166
167	if (err)
168		return err;
169
170	hwirq = v2m->spi_start + offset;
171
172	err = gicv2m_irq_gic_domain_alloc(domain, virq, hwirq);
173	if (err) {
174		gicv2m_unalloc_msi(v2m, hwirq);
175		return err;
176	}
177
178	irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
179				      &gicv2m_irq_chip, v2m);
180
181	return 0;
182}
183
184static void gicv2m_irq_domain_free(struct irq_domain *domain,
185				   unsigned int virq, unsigned int nr_irqs)
186{
187	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
188	struct v2m_data *v2m = irq_data_get_irq_chip_data(d);
189
190	BUG_ON(nr_irqs != 1);
191	gicv2m_unalloc_msi(v2m, d->hwirq);
192	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
193}
194
195static const struct irq_domain_ops gicv2m_domain_ops = {
196	.alloc			= gicv2m_irq_domain_alloc,
197	.free			= gicv2m_irq_domain_free,
198};
199
200static bool is_msi_spi_valid(u32 base, u32 num)
201{
202	if (base < V2M_MIN_SPI) {
203		pr_err("Invalid MSI base SPI (base:%u)\n", base);
204		return false;
205	}
206
207	if ((num == 0) || (base + num > V2M_MAX_SPI)) {
208		pr_err("Number of SPIs (%u) exceed maximum (%u)\n",
209		       num, V2M_MAX_SPI - V2M_MIN_SPI + 1);
210		return false;
211	}
212
213	return true;
214}
215
216static int __init gicv2m_init_one(struct device_node *node,
217				  struct irq_domain *parent)
218{
219	int ret;
220	struct v2m_data *v2m;
221
222	v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL);
223	if (!v2m) {
224		pr_err("Failed to allocate struct v2m_data.\n");
225		return -ENOMEM;
226	}
227
228	ret = of_address_to_resource(node, 0, &v2m->res);
229	if (ret) {
230		pr_err("Failed to allocate v2m resource.\n");
231		goto err_free_v2m;
232	}
233
234	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
235	if (!v2m->base) {
236		pr_err("Failed to map GICv2m resource\n");
237		ret = -ENOMEM;
238		goto err_free_v2m;
239	}
240
241	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
242	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
243		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
244			v2m->spi_start, v2m->nr_spis);
245	} else {
246		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
247
248		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
249		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
250	}
251
252	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
253		ret = -EINVAL;
254		goto err_iounmap;
255	}
256
257	v2m->bm = kzalloc(sizeof(long) * BITS_TO_LONGS(v2m->nr_spis),
258			  GFP_KERNEL);
259	if (!v2m->bm) {
260		ret = -ENOMEM;
261		goto err_iounmap;
262	}
263
264	v2m->domain = irq_domain_add_tree(NULL, &gicv2m_domain_ops, v2m);
265	if (!v2m->domain) {
266		pr_err("Failed to create GICv2m domain\n");
267		ret = -ENOMEM;
268		goto err_free_bm;
269	}
270
271	v2m->domain->parent = parent;
272	v2m->mchip.of_node = node;
273	v2m->mchip.domain = pci_msi_create_irq_domain(node,
274						      &gicv2m_msi_domain_info,
275						      v2m->domain);
276	if (!v2m->mchip.domain) {
277		pr_err("Failed to create MSI domain\n");
278		ret = -ENOMEM;
279		goto err_free_domains;
280	}
281
282	spin_lock_init(&v2m->msi_cnt_lock);
283
284	ret = of_pci_msi_chip_add(&v2m->mchip);
285	if (ret) {
286		pr_err("Failed to add msi_chip.\n");
287		goto err_free_domains;
288	}
289
290	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
291		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
292		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
293
294	return 0;
295
296err_free_domains:
297	if (v2m->mchip.domain)
298		irq_domain_remove(v2m->mchip.domain);
299	if (v2m->domain)
300		irq_domain_remove(v2m->domain);
301err_free_bm:
302	kfree(v2m->bm);
303err_iounmap:
304	iounmap(v2m->base);
305err_free_v2m:
306	kfree(v2m);
307	return ret;
308}
309
310static struct of_device_id gicv2m_device_id[] = {
311	{	.compatible	= "arm,gic-v2m-frame",	},
312	{},
313};
314
315int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
316{
317	int ret = 0;
318	struct device_node *child;
319
320	for (child = of_find_matching_node(node, gicv2m_device_id); child;
321	     child = of_find_matching_node(child, gicv2m_device_id)) {
322		if (!of_find_property(child, "msi-controller", NULL))
323			continue;
324
325		ret = gicv2m_init_one(child, parent);
326		if (ret) {
327			of_node_put(node);
328			break;
329		}
330	}
331
332	return ret;
333}
334