1 From 23b09c6b4162a8264b600f35d7048256a7afc0cd Mon Sep 17 00:00:00 2001
2 From: "J. German Rivera" <German.Rivera@freescale.com>
3 Date: Wed, 6 Jan 2016 16:03:23 -0600
4 Subject: [PATCH 147/226] staging: fsl-mc: Extended MC bus allocator to
7 All the IRQs for DPAA2 objects in the same DPRC must use
8 the ICID of that DPRC, as their device Id in the GIC-ITS.
9 Thus, all these IRQs must share the same ITT table in the GIC.
10 As a result, a pool of IRQs with the same device Id must be
11 preallocated per DPRC (fsl-mc bus instance). So, the fsl-mc
12 bus object allocator is extended to also provide services
13 to allocate IRQs to DPAA2 devices, from their parent fsl-mc bus
16 Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
17 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
19 drivers/staging/fsl-mc/bus/mc-allocator.c | 199 +++++++++++++++++++++++++++
20 drivers/staging/fsl-mc/include/mc-private.h | 15 ++
21 drivers/staging/fsl-mc/include/mc.h | 9 ++
22 3 files changed, 223 insertions(+)
24 --- a/drivers/staging/fsl-mc/bus/mc-allocator.c
25 +++ b/drivers/staging/fsl-mc/bus/mc-allocator.c
27 #include "../include/dpcon-cmd.h"
28 #include "dpmcp-cmd.h"
30 +#include <linux/msi.h>
33 * fsl_mc_resource_pool_add_device - add allocatable device to a resource
34 @@ -160,6 +161,7 @@ static const char *const fsl_mc_pool_typ
35 [FSL_MC_POOL_DPMCP] = "dpmcp",
36 [FSL_MC_POOL_DPBP] = "dpbp",
37 [FSL_MC_POOL_DPCON] = "dpcon",
38 + [FSL_MC_POOL_IRQ] = "irq",
41 static int __must_check object_type_to_pool_type(const char *object_type,
42 @@ -465,6 +467,203 @@ void fsl_mc_object_free(struct fsl_mc_de
44 EXPORT_SYMBOL_GPL(fsl_mc_object_free);
47 + * Initialize the interrupt pool associated with a MC bus.
48 + * It allocates a block of IRQs from the GIC-ITS
50 +int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
51 + unsigned int irq_count)
54 + struct msi_desc *msi_desc;
55 + struct fsl_mc_device_irq *irq_resources;
56 + struct fsl_mc_device_irq *mc_dev_irq;
58 + struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
59 + struct fsl_mc_resource_pool *res_pool =
60 + &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
62 + if (WARN_ON(irq_count == 0 ||
63 + irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS))
66 + error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count);
70 + irq_resources = devm_kzalloc(&mc_bus_dev->dev,
71 + sizeof(*irq_resources) * irq_count,
73 + if (!irq_resources) {
75 + goto cleanup_msi_irqs;
78 + for (i = 0; i < irq_count; i++) {
79 + mc_dev_irq = &irq_resources[i];
82 + * NOTE: This mc_dev_irq's MSI addr/value pair will be set
83 + * by the fsl_mc_msi_write_msg() callback
85 + mc_dev_irq->resource.type = res_pool->type;
86 + mc_dev_irq->resource.data = mc_dev_irq;
87 + mc_dev_irq->resource.parent_pool = res_pool;
88 + INIT_LIST_HEAD(&mc_dev_irq->resource.node);
89 + list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list);
92 + for_each_msi_entry(msi_desc, &mc_bus_dev->dev) {
93 + mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index];
94 + mc_dev_irq->msi_desc = msi_desc;
95 + mc_dev_irq->resource.id = msi_desc->irq;
98 + res_pool->max_count = irq_count;
99 + res_pool->free_count = irq_count;
100 + mc_bus->irq_resources = irq_resources;
104 + fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
107 +EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
110 + * Teardown the interrupt pool associated with an MC bus.
111 + * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
113 +void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus)
115 + struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
116 + struct fsl_mc_resource_pool *res_pool =
117 + &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
119 + if (WARN_ON(!mc_bus->irq_resources))
122 + if (WARN_ON(res_pool->max_count == 0))
125 + if (WARN_ON(res_pool->free_count != res_pool->max_count))
128 + INIT_LIST_HEAD(&res_pool->free_list);
129 + res_pool->max_count = 0;
130 + res_pool->free_count = 0;
131 + mc_bus->irq_resources = NULL;
132 + fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
134 +EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
137 + * It allocates the IRQs required by a given MC object device. The
138 + * IRQs are allocated from the interrupt pool associated with the
139 + * MC bus that contains the device, if the device is not a DPRC device.
140 + * Otherwise, the IRQs are allocated from the interrupt pool associated
141 + * with the MC bus that represents the DPRC device itself.
143 +int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
147 + int res_allocated_count = 0;
148 + int error = -EINVAL;
149 + struct fsl_mc_device_irq **irqs = NULL;
150 + struct fsl_mc_bus *mc_bus;
151 + struct fsl_mc_resource_pool *res_pool;
153 + if (WARN_ON(mc_dev->irqs))
156 + irq_count = mc_dev->obj_desc.irq_count;
157 + if (WARN_ON(irq_count == 0))
160 + if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
161 + mc_bus = to_fsl_mc_bus(mc_dev);
163 + mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
165 + if (WARN_ON(!mc_bus->irq_resources))
168 + res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
169 + if (res_pool->free_count < irq_count) {
170 + dev_err(&mc_dev->dev,
171 + "Not able to allocate %u irqs for device\n", irq_count);
175 + irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]),
180 + for (i = 0; i < irq_count; i++) {
181 + struct fsl_mc_resource *resource;
183 + error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ,
186 + goto error_resource_alloc;
188 + irqs[i] = to_fsl_mc_irq(resource);
189 + res_allocated_count++;
191 + WARN_ON(irqs[i]->mc_dev);
192 + irqs[i]->mc_dev = mc_dev;
193 + irqs[i]->dev_irq_index = i;
196 + mc_dev->irqs = irqs;
199 +error_resource_alloc:
200 + for (i = 0; i < res_allocated_count; i++) {
201 + irqs[i]->mc_dev = NULL;
202 + fsl_mc_resource_free(&irqs[i]->resource);
207 +EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs);
210 + * It frees the IRQs that were allocated for a MC object device, by
211 + * returning them to the corresponding interrupt pool.
213 +void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
217 + struct fsl_mc_bus *mc_bus;
218 + struct fsl_mc_device_irq **irqs = mc_dev->irqs;
220 + if (WARN_ON(!irqs))
223 + irq_count = mc_dev->obj_desc.irq_count;
225 + if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
226 + mc_bus = to_fsl_mc_bus(mc_dev);
228 + mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
230 + if (WARN_ON(!mc_bus->irq_resources))
233 + for (i = 0; i < irq_count; i++) {
234 + WARN_ON(!irqs[i]->mc_dev);
235 + irqs[i]->mc_dev = NULL;
236 + fsl_mc_resource_free(&irqs[i]->resource);
239 + mc_dev->irqs = NULL;
241 +EXPORT_SYMBOL_GPL(fsl_mc_free_irqs);
244 * fsl_mc_allocator_probe - callback invoked when an allocatable device is
245 * being added to the system
246 --- a/drivers/staging/fsl-mc/include/mc-private.h
247 +++ b/drivers/staging/fsl-mc/include/mc-private.h
248 @@ -30,6 +30,16 @@ struct irq_domain;
249 struct msi_domain_info;
252 + * Maximum number of total IRQs that can be pre-allocated for an MC bus'
255 +#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS 256
259 +struct msi_domain_info;
262 * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device
263 * @root_mc_bus_dev: MC object device representing the root DPRC
264 * @num_translation_ranges: number of entries in addr_translation_ranges
265 @@ -137,4 +147,9 @@ int __init its_fsl_mc_msi_init(void);
267 void its_fsl_mc_msi_cleanup(void);
269 +int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
270 + unsigned int irq_count);
272 +void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus);
274 #endif /* _FSL_MC_PRIVATE_H_ */
275 --- a/drivers/staging/fsl-mc/include/mc.h
276 +++ b/drivers/staging/fsl-mc/include/mc.h
278 #include <linux/device.h>
279 #include <linux/mod_devicetable.h>
280 #include <linux/list.h>
281 +#include <linux/interrupt.h>
282 #include "../include/dprc.h"
284 #define FSL_MC_VENDOR_FREESCALE 0x1957
286 struct fsl_mc_device;
291 * struct fsl_mc_driver - MC object device driver object
292 @@ -75,6 +77,7 @@ enum fsl_mc_pool_type {
293 FSL_MC_POOL_DPMCP = 0x0, /* corresponds to "dpmcp" in the MC */
294 FSL_MC_POOL_DPBP, /* corresponds to "dpbp" in the MC */
295 FSL_MC_POOL_DPCON, /* corresponds to "dpcon" in the MC */
299 * NOTE: New resource pool types must be added before this entry
300 @@ -141,6 +144,7 @@ struct fsl_mc_device_irq {
302 * @obj_desc: MC description of the DPAA device
303 * @regions: pointer to array of MMIO region entries
304 + * @irqs: pointer to array of pointers to interrupts allocated to this device
305 * @resource: generic resource associated with this MC object device, if any.
307 * Generic device object for MC object devices that are "attached" to a
308 @@ -172,6 +176,7 @@ struct fsl_mc_device {
309 struct fsl_mc_io *mc_io;
310 struct dprc_obj_desc obj_desc;
311 struct resource *regions;
312 + struct fsl_mc_device_irq **irqs;
313 struct fsl_mc_resource *resource;
316 @@ -215,6 +220,10 @@ int __must_check fsl_mc_object_allocate(
318 void fsl_mc_object_free(struct fsl_mc_device *mc_adev);
320 +int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev);
322 +void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev);
324 extern struct bus_type fsl_mc_bus_type;
326 #endif /* _FSL_MC_H_ */