xref: /linux/drivers/irqchip/irq-alpine-msi.c (revision 746680ec6696585e30db3e18c93a63df9cbec39c)
1 /*
2  * Annapurna Labs MSIX support services
3  *
4  * Copyright (C) 2016, Amazon.com, Inc. or its affiliates. All Rights Reserved.
5  *
6  * Antoine Tenart <antoine.tenart@free-electrons.com>
7  *
8  * This file is licensed under the terms of the GNU General Public
9  * License version 2. This program is licensed "as is" without any
10  * warranty of any kind, whether express or implied.
11  */
12 
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 
15 #include <linux/irqchip.h>
16 #include <linux/irqchip/arm-gic.h>
17 #include <linux/irqchip/irq-msi-lib.h>
18 #include <linux/msi.h>
19 #include <linux/of.h>
20 #include <linux/of_address.h>
21 #include <linux/of_irq.h>
22 #include <linux/of_pci.h>
23 #include <linux/pci.h>
24 #include <linux/slab.h>
25 
26 #include <asm/irq.h>
27 #include <asm/msi.h>
28 
29 /* MSIX message address format: local GIC target */
30 #define ALPINE_MSIX_SPI_TARGET_CLUSTER0		BIT(16)
31 
32 struct alpine_msix_data {
33 	spinlock_t	msi_map_lock;
34 	phys_addr_t	addr;
35 	u32		spi_first;	/* The SGI number that MSIs start */
36 	u32		num_spis;	/* The number of SGIs for MSIs */
37 	unsigned long	*msi_map;
38 };
39 
40 static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req)
41 {
42 	int first;
43 
44 	guard(spinlock)(&priv->msi_map_lock);
45 	first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0, num_req, 0);
46 	if (first >= priv->num_spis)
47 		return -ENOSPC;
48 
49 	bitmap_set(priv->msi_map, first, num_req);
50 	return priv->spi_first + first;
51 }
52 
53 static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned int sgi, int num_req)
54 {
55 	int first = sgi - priv->spi_first;
56 
57 	guard(spinlock)(&priv->msi_map_lock);
58 	bitmap_clear(priv->msi_map, first, num_req);
59 }
60 
61 static void alpine_msix_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
62 {
63 	struct alpine_msix_data *priv = irq_data_get_irq_chip_data(data);
64 	phys_addr_t msg_addr = priv->addr;
65 
66 	msg_addr |= (data->hwirq << 3);
67 	msg->address_hi = upper_32_bits(msg_addr);
68 	msg->address_lo = lower_32_bits(msg_addr);
69 	msg->data = 0;
70 }
71 
72 static struct irq_chip middle_irq_chip = {
73 	.name			= "alpine_msix_middle",
74 	.irq_mask		= irq_chip_mask_parent,
75 	.irq_unmask		= irq_chip_unmask_parent,
76 	.irq_eoi		= irq_chip_eoi_parent,
77 	.irq_set_affinity	= irq_chip_set_affinity_parent,
78 	.irq_compose_msi_msg	= alpine_msix_compose_msi_msg,
79 };
80 
81 static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, int sgi)
82 {
83 	struct irq_fwspec fwspec;
84 	struct irq_data *d;
85 	int ret;
86 
87 	if (!is_of_node(domain->parent->fwnode))
88 		return -EINVAL;
89 
90 	fwspec.fwnode = domain->parent->fwnode;
91 	fwspec.param_count = 3;
92 	fwspec.param[0] = 0;
93 	fwspec.param[1] = sgi;
94 	fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
95 
96 	ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
97 	if (ret)
98 		return ret;
99 
100 	d = irq_domain_get_irq_data(domain->parent, virq);
101 	d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING);
102 	return 0;
103 }
104 
105 static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, unsigned int virq,
106 					   unsigned int nr_irqs, void *args)
107 {
108 	struct alpine_msix_data *priv = domain->host_data;
109 	int sgi, err, i;
110 
111 	sgi = alpine_msix_allocate_sgi(priv, nr_irqs);
112 	if (sgi < 0)
113 		return sgi;
114 
115 	for (i = 0; i < nr_irqs; i++) {
116 		err = alpine_msix_gic_domain_alloc(domain, virq + i, sgi + i);
117 		if (err)
118 			goto err_sgi;
119 
120 		irq_domain_set_hwirq_and_chip(domain, virq + i, sgi + i,
121 					      &middle_irq_chip, priv);
122 	}
123 	return 0;
124 
125 err_sgi:
126 	irq_domain_free_irqs_parent(domain, virq, i);
127 	alpine_msix_free_sgi(priv, sgi, nr_irqs);
128 	return err;
129 }
130 
131 static void alpine_msix_middle_domain_free(struct irq_domain *domain, unsigned int virq,
132 					   unsigned int nr_irqs)
133 {
134 	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
135 	struct alpine_msix_data *priv = irq_data_get_irq_chip_data(d);
136 
137 	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
138 	alpine_msix_free_sgi(priv, d->hwirq, nr_irqs);
139 }
140 
141 static const struct irq_domain_ops alpine_msix_middle_domain_ops = {
142 	.select	= msi_lib_irq_domain_select,
143 	.alloc	= alpine_msix_middle_domain_alloc,
144 	.free	= alpine_msix_middle_domain_free,
145 };
146 
147 #define ALPINE_MSI_FLAGS_REQUIRED  (MSI_FLAG_USE_DEF_DOM_OPS |		\
148 				    MSI_FLAG_USE_DEF_CHIP_OPS |		\
149 				    MSI_FLAG_PCI_MSI_MASK_PARENT)
150 
151 #define ALPINE_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK |		\
152 				    MSI_FLAG_PCI_MSIX)
153 
154 static struct msi_parent_ops alpine_msi_parent_ops = {
155 	.supported_flags	= ALPINE_MSI_FLAGS_SUPPORTED,
156 	.required_flags		= ALPINE_MSI_FLAGS_REQUIRED,
157 	.chip_flags		= MSI_CHIP_FLAG_SET_EOI,
158 	.bus_select_token	= DOMAIN_BUS_NEXUS,
159 	.bus_select_mask	= MATCH_PCI_MSI,
160 	.prefix			= "ALPINE-",
161 	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
162 };
163 
164 static int alpine_msix_init_domains(struct alpine_msix_data *priv, struct device_node *node)
165 {
166 	struct irq_domain_info info = {
167 		.fwnode		= of_fwnode_handle(node),
168 		.ops		= &alpine_msix_middle_domain_ops,
169 		.host_data	= priv,
170 	};
171 	struct device_node *gic_node;
172 
173 	gic_node = of_irq_find_parent(node);
174 	if (!gic_node) {
175 		pr_err("Failed to find the GIC node\n");
176 		return -ENODEV;
177 	}
178 
179 	info.parent = irq_find_host(gic_node);
180 	of_node_put(gic_node);
181 	if (!info.parent) {
182 		pr_err("Failed to find the GIC domain\n");
183 		return -ENXIO;
184 	}
185 
186 	if (!msi_create_parent_irq_domain(&info, &alpine_msi_parent_ops)) {
187 		pr_err("Failed to create MSI domain\n");
188 		return -ENOMEM;
189 	}
190 	return 0;
191 }
192 
193 static int alpine_msix_init(struct device_node *node, struct device_node *parent)
194 {
195 	struct alpine_msix_data *priv __free(kfree) = kzalloc(sizeof(*priv), GFP_KERNEL);
196 	struct resource res;
197 	int ret;
198 
199 	if (!priv)
200 		return -ENOMEM;
201 
202 	spin_lock_init(&priv->msi_map_lock);
203 
204 	ret = of_address_to_resource(node, 0, &res);
205 	if (ret) {
206 		pr_err("Failed to allocate resource\n");
207 		return ret;
208 	}
209 
210 	/*
211 	 * The 20 least significant bits of addr provide direct information
212 	 * regarding the interrupt destination.
213 	 *
214 	 * To select the primary GIC as the target GIC, bits [18:17] must be set
215 	 * to 0x0. In this case, bit 16 (SPI_TARGET_CLUSTER0) must be set.
216 	 */
217 	priv->addr = res.start & GENMASK_ULL(63,20);
218 	priv->addr |= ALPINE_MSIX_SPI_TARGET_CLUSTER0;
219 
220 	if (of_property_read_u32(node, "al,msi-base-spi", &priv->spi_first)) {
221 		pr_err("Unable to parse MSI base\n");
222 		return -EINVAL;
223 	}
224 
225 	if (of_property_read_u32(node, "al,msi-num-spis", &priv->num_spis)) {
226 		pr_err("Unable to parse MSI numbers\n");
227 		return -EINVAL;
228 	}
229 
230 	unsigned long *msi_map __free(kfree) = bitmap_zalloc(priv->num_spis, GFP_KERNEL);
231 
232 	if (!msi_map)
233 		return -ENOMEM;
234 	priv->msi_map = msi_map;
235 
236 	pr_debug("Registering %d msixs, starting at %d\n", priv->num_spis, priv->spi_first);
237 
238 	ret = alpine_msix_init_domains(priv, node);
239 	if (ret)
240 		return ret;
241 
242 	retain_and_null_ptr(priv);
243 	retain_and_null_ptr(msi_map);
244 	return 0;
245 }
246 IRQCHIP_DECLARE(alpine_msix, "al,alpine-msix", alpine_msix_init);
247