layerscape: add ls1088ardb device support
[openwrt/staging/lynxis/omap.git] / target / linux / layerscape / patches-4.4 / 7152-staging-fsl-mc-Added-DPRC-interrupt-handler.patch
1 From aa83997b14c31b34d9af24cb42726b55fa630464 Mon Sep 17 00:00:00 2001
2 From: "J. German Rivera" <German.Rivera@freescale.com>
3 Date: Wed, 6 Jan 2016 16:03:28 -0600
4 Subject: [PATCH 152/226] staging: fsl-mc: Added DPRC interrupt handler
5
6 The interrupt handler for DPRC IRQs is added. DPRC IRQs are
7 generated for hot plug events related to DPAA2 objects in a given
8 DPRC. These events include, creating/destroying DPAA2 objects in
9 the DPRC, changing the "plugged" state of DPAA2 objects and moving
10 objects between DPRCs.
11
12 Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
13 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
14 ---
15 drivers/staging/fsl-mc/bus/dprc-driver.c | 247 ++++++++++++++++++++++++++++++
16 1 file changed, 247 insertions(+)
17
18 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c
19 +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
20 @@ -14,6 +14,7 @@
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/interrupt.h>
24 +#include <linux/msi.h>
25 #include "dprc-cmd.h"
26
27 struct dprc_child_objs {
28 @@ -386,6 +387,230 @@ error:
29 EXPORT_SYMBOL_GPL(dprc_scan_container);
30
31 /**
32 + * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
33 + *
34 + * @irq: IRQ number of the interrupt being handled
35 + * @arg: Pointer to device structure
36 + */
37 +static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
38 +{
39 + return IRQ_WAKE_THREAD;
40 +}
41 +
42 +/**
43 + * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
44 + *
45 + * @irq: IRQ number of the interrupt being handled
46 + * @arg: Pointer to device structure
47 + */
48 +static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
49 +{
50 + int error;
51 + u32 status;
52 + struct device *dev = (struct device *)arg;
53 + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
54 + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
55 + struct fsl_mc_io *mc_io = mc_dev->mc_io;
56 + struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc;
57 +
58 + dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
59 + irq_num, smp_processor_id());
60 +
61 + if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
62 + return IRQ_HANDLED;
63 +
64 + mutex_lock(&mc_bus->scan_mutex);
65 + if (WARN_ON(!msi_desc || msi_desc->irq != (u32)irq_num))
66 + goto out;
67 +
68 + error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
69 + &status);
70 + if (error < 0) {
71 + dev_err(dev,
72 + "dprc_get_irq_status() failed: %d\n", error);
73 + goto out;
74 + }
75 +
76 + error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
77 + status);
78 + if (error < 0) {
79 + dev_err(dev,
80 + "dprc_clear_irq_status() failed: %d\n", error);
81 + goto out;
82 + }
83 +
84 + if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
85 + DPRC_IRQ_EVENT_OBJ_REMOVED |
86 + DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
87 + DPRC_IRQ_EVENT_OBJ_DESTROYED |
88 + DPRC_IRQ_EVENT_OBJ_CREATED)) {
89 + unsigned int irq_count;
90 +
91 + error = dprc_scan_objects(mc_dev, &irq_count);
92 + if (error < 0) {
93 + /*
94 + * If the error is -ENXIO, we ignore it, as it indicates
95 + * that the object scan was aborted, as we detected that
96 + * an object was removed from the DPRC in the MC, while
97 + * we were scanning the DPRC.
98 + */
99 + if (error != -ENXIO) {
100 + dev_err(dev, "dprc_scan_objects() failed: %d\n",
101 + error);
102 + }
103 +
104 + goto out;
105 + }
106 +
107 + if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
108 + dev_warn(dev,
109 + "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
110 + irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
111 + }
112 + }
113 +
114 +out:
115 + mutex_unlock(&mc_bus->scan_mutex);
116 + return IRQ_HANDLED;
117 +}
118 +
119 +/*
120 + * Disable and clear interrupt for a given DPRC object
121 + */
122 +static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
123 +{
124 + int error;
125 + struct fsl_mc_io *mc_io = mc_dev->mc_io;
126 +
127 + WARN_ON(mc_dev->obj_desc.irq_count != 1);
128 +
129 + /*
130 + * Disable generation of interrupt, while we configure it:
131 + */
132 + error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0);
133 + if (error < 0) {
134 + dev_err(&mc_dev->dev,
135 + "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
136 + error);
137 + return error;
138 + }
139 +
140 + /*
141 + * Disable all interrupt causes for the interrupt:
142 + */
143 + error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0);
144 + if (error < 0) {
145 + dev_err(&mc_dev->dev,
146 + "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
147 + error);
148 + return error;
149 + }
150 +
151 + /*
152 + * Clear any leftover interrupts:
153 + */
154 + error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U);
155 + if (error < 0) {
156 + dev_err(&mc_dev->dev,
157 + "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n",
158 + error);
159 + return error;
160 + }
161 +
162 + return 0;
163 +}
164 +
165 +static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
166 +{
167 + int error;
168 + struct fsl_mc_device_irq *irq = mc_dev->irqs[0];
169 +
170 + WARN_ON(mc_dev->obj_desc.irq_count != 1);
171 +
172 + /*
173 + * NOTE: devm_request_threaded_irq() invokes the device-specific
174 + * function that programs the MSI physically in the device
175 + */
176 + error = devm_request_threaded_irq(&mc_dev->dev,
177 + irq->msi_desc->irq,
178 + dprc_irq0_handler,
179 + dprc_irq0_handler_thread,
180 + IRQF_NO_SUSPEND | IRQF_ONESHOT,
181 + "FSL MC DPRC irq0",
182 + &mc_dev->dev);
183 + if (error < 0) {
184 + dev_err(&mc_dev->dev,
185 + "devm_request_threaded_irq() failed: %d\n",
186 + error);
187 + return error;
188 + }
189 +
190 + return 0;
191 +}
192 +
193 +static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
194 +{
195 + int error;
196 +
197 + /*
198 + * Enable all interrupt causes for the interrupt:
199 + */
200 + error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0,
201 + ~0x0u);
202 + if (error < 0) {
203 + dev_err(&mc_dev->dev,
204 + "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
205 + error);
206 +
207 + return error;
208 + }
209 +
210 + /*
211 + * Enable generation of the interrupt:
212 + */
213 + error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1);
214 + if (error < 0) {
215 + dev_err(&mc_dev->dev,
216 + "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
217 + error);
218 +
219 + return error;
220 + }
221 +
222 + return 0;
223 +}
224 +
225 +/*
226 + * Setup interrupt for a given DPRC device
227 + */
228 +static int dprc_setup_irq(struct fsl_mc_device *mc_dev)
229 +{
230 + int error;
231 +
232 + error = fsl_mc_allocate_irqs(mc_dev);
233 + if (error < 0)
234 + return error;
235 +
236 + error = disable_dprc_irq(mc_dev);
237 + if (error < 0)
238 + goto error_free_irqs;
239 +
240 + error = register_dprc_irq_handler(mc_dev);
241 + if (error < 0)
242 + goto error_free_irqs;
243 +
244 + error = enable_dprc_irq(mc_dev);
245 + if (error < 0)
246 + goto error_free_irqs;
247 +
248 + return 0;
249 +
250 +error_free_irqs:
251 + fsl_mc_free_irqs(mc_dev);
252 + return error;
253 +}
254 +
255 +/**
256 * dprc_probe - callback invoked when a DPRC is being bound to this driver
257 *
258 * @mc_dev: Pointer to fsl-mc device representing a DPRC
259 @@ -476,6 +701,13 @@ static int dprc_probe(struct fsl_mc_devi
260 if (error < 0)
261 goto error_cleanup_open;
262
263 + /*
264 + * Configure interrupt for the DPRC object associated with this MC bus:
265 + */
266 + error = dprc_setup_irq(mc_dev);
267 + if (error < 0)
268 + goto error_cleanup_open;
269 +
270 dev_info(&mc_dev->dev, "DPRC device bound to driver");
271 return 0;
272
273 @@ -494,6 +726,15 @@ error_cleanup_msi_domain:
274 return error;
275 }
276
277 +/*
278 + * Tear down interrupt for a given DPRC object
279 + */
280 +static void dprc_teardown_irq(struct fsl_mc_device *mc_dev)
281 +{
282 + (void)disable_dprc_irq(mc_dev);
283 + fsl_mc_free_irqs(mc_dev);
284 +}
285 +
286 /**
287 * dprc_remove - callback invoked when a DPRC is being unbound from this driver
288 *
289 @@ -514,6 +755,12 @@ static int dprc_remove(struct fsl_mc_dev
290 if (WARN_ON(!mc_dev->mc_io))
291 return -EINVAL;
292
293 + if (WARN_ON(!mc_bus->irq_resources))
294 + return -EINVAL;
295 +
296 + if (dev_get_msi_domain(&mc_dev->dev))
297 + dprc_teardown_irq(mc_dev);
298 +
299 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
300 dprc_cleanup_all_resource_pools(mc_dev);
301 error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);