staging: media: Remove unneeded parentheses
[deliverable/linux.git] / drivers / staging / fsl-mc / bus / dprc-driver.c
CommitLineData
f2f2726b
GR
1/*
2 * Freescale data path resource container (DPRC) driver
3 *
4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
5 * Author: German Rivera <German.Rivera@freescale.com>
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include "../include/mc-private.h"
13#include "../include/mc-sys.h"
14#include <linux/module.h>
15#include <linux/slab.h>
232ae8f2 16#include <linux/interrupt.h>
f52dee5c 17#include <linux/msi.h>
f2f2726b
GR
18#include "dprc-cmd.h"
19
20struct dprc_child_objs {
21 int child_count;
22 struct dprc_obj_desc *child_array;
23};
24
25static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
26{
27 int i;
28 struct dprc_child_objs *objs;
29 struct fsl_mc_device *mc_dev;
30
31 WARN_ON(!dev);
32 WARN_ON(!data);
33 mc_dev = to_fsl_mc_device(dev);
34 objs = data;
35
36 for (i = 0; i < objs->child_count; i++) {
37 struct dprc_obj_desc *obj_desc = &objs->child_array[i];
38
39 if (strlen(obj_desc->type) != 0 &&
40 FSL_MC_DEVICE_MATCH(mc_dev, obj_desc))
41 break;
42 }
43
44 if (i == objs->child_count)
45 fsl_mc_device_remove(mc_dev);
46
47 return 0;
48}
49
50static int __fsl_mc_device_remove(struct device *dev, void *data)
51{
52 WARN_ON(!dev);
53 WARN_ON(data);
54 fsl_mc_device_remove(to_fsl_mc_device(dev));
55 return 0;
56}
57
58/**
59 * dprc_remove_devices - Removes devices for objects removed from a DPRC
60 *
61 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
62 * @obj_desc_array: array of object descriptors for child objects currently
63 * present in the DPRC in the MC.
64 * @num_child_objects_in_mc: number of entries in obj_desc_array
65 *
66 * Synchronizes the state of the Linux bus driver with the actual state of
67 * the MC by removing devices that represent MC objects that have
68 * been dynamically removed in the physical DPRC.
69 */
70static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev,
71 struct dprc_obj_desc *obj_desc_array,
72 int num_child_objects_in_mc)
73{
74 if (num_child_objects_in_mc != 0) {
75 /*
76 * Remove child objects that are in the DPRC in Linux,
77 * but not in the MC:
78 */
79 struct dprc_child_objs objs;
80
81 objs.child_count = num_child_objects_in_mc;
82 objs.child_array = obj_desc_array;
83 device_for_each_child(&mc_bus_dev->dev, &objs,
84 __fsl_mc_device_remove_if_not_in_mc);
85 } else {
86 /*
87 * There are no child objects for this DPRC in the MC.
88 * So, remove all the child devices from Linux:
89 */
90 device_for_each_child(&mc_bus_dev->dev, NULL,
91 __fsl_mc_device_remove);
92 }
93}
94
95static int __fsl_mc_device_match(struct device *dev, void *data)
96{
97 struct dprc_obj_desc *obj_desc = data;
98 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
99
100 return FSL_MC_DEVICE_MATCH(mc_dev, obj_desc);
101}
102
103static struct fsl_mc_device *fsl_mc_device_lookup(struct dprc_obj_desc
104 *obj_desc,
105 struct fsl_mc_device
106 *mc_bus_dev)
107{
108 struct device *dev;
109
110 dev = device_find_child(&mc_bus_dev->dev, obj_desc,
111 __fsl_mc_device_match);
112
113 return dev ? to_fsl_mc_device(dev) : NULL;
114}
115
1663e809
GR
116/**
117 * check_plugged_state_change - Check change in an MC object's plugged state
118 *
119 * @mc_dev: pointer to the fsl-mc device for a given MC object
120 * @obj_desc: pointer to the MC object's descriptor in the MC
121 *
122 * If the plugged state has changed from unplugged to plugged, the fsl-mc
123 * device is bound to the corresponding device driver.
124 * If the plugged state has changed from plugged to unplugged, the fsl-mc
125 * device is unbound from the corresponding device driver.
126 */
127static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
128 struct dprc_obj_desc *obj_desc)
129{
130 int error;
ba72f25b 131 u32 plugged_flag_at_mc =
1663e809
GR
132 (obj_desc->state & DPRC_OBJ_STATE_PLUGGED);
133
134 if (plugged_flag_at_mc !=
135 (mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED)) {
136 if (plugged_flag_at_mc) {
137 mc_dev->obj_desc.state |= DPRC_OBJ_STATE_PLUGGED;
138 error = device_attach(&mc_dev->dev);
139 if (error < 0) {
140 dev_err(&mc_dev->dev,
141 "device_attach() failed: %d\n",
142 error);
143 }
144 } else {
145 mc_dev->obj_desc.state &= ~DPRC_OBJ_STATE_PLUGGED;
146 device_release_driver(&mc_dev->dev);
147 }
148 }
149}
150
f2f2726b
GR
151/**
152 * dprc_add_new_devices - Adds devices to the logical bus for a DPRC
153 *
154 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
155 * @obj_desc_array: array of device descriptors for child devices currently
156 * present in the physical DPRC.
157 * @num_child_objects_in_mc: number of entries in obj_desc_array
158 *
159 * Synchronizes the state of the Linux bus driver with the actual
160 * state of the MC by adding objects that have been newly discovered
161 * in the physical DPRC.
162 */
163static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
164 struct dprc_obj_desc *obj_desc_array,
165 int num_child_objects_in_mc)
166{
167 int error;
168 int i;
169
170 for (i = 0; i < num_child_objects_in_mc; i++) {
171 struct fsl_mc_device *child_dev;
f2f2726b
GR
172 struct dprc_obj_desc *obj_desc = &obj_desc_array[i];
173
174 if (strlen(obj_desc->type) == 0)
175 continue;
176
177 /*
178 * Check if device is already known to Linux:
179 */
180 child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
1663e809
GR
181 if (child_dev) {
182 check_plugged_state_change(child_dev, obj_desc);
f2f2726b 183 continue;
1663e809 184 }
f2f2726b 185
2bdc55d9 186 error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
f2f2726b 187 &child_dev);
2bdc55d9 188 if (error < 0)
f2f2726b 189 continue;
f2f2726b
GR
190 }
191}
192
197f4d6a
GR
193static void dprc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
194{
195 int pool_type;
196 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
197
198 for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) {
199 struct fsl_mc_resource_pool *res_pool =
200 &mc_bus->resource_pools[pool_type];
201
202 res_pool->type = pool_type;
203 res_pool->max_count = 0;
204 res_pool->free_count = 0;
205 res_pool->mc_bus = mc_bus;
206 INIT_LIST_HEAD(&res_pool->free_list);
207 mutex_init(&res_pool->mutex);
208 }
209}
210
211static void dprc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev,
212 enum fsl_mc_pool_type pool_type)
213{
214 struct fsl_mc_resource *resource;
215 struct fsl_mc_resource *next;
216 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
217 struct fsl_mc_resource_pool *res_pool =
218 &mc_bus->resource_pools[pool_type];
219 int free_count = 0;
220
221 WARN_ON(res_pool->type != pool_type);
222 WARN_ON(res_pool->free_count != res_pool->max_count);
223
224 list_for_each_entry_safe(resource, next, &res_pool->free_list, node) {
225 free_count++;
226 WARN_ON(resource->type != res_pool->type);
227 WARN_ON(resource->parent_pool != res_pool);
228 devm_kfree(&mc_bus_dev->dev, resource);
229 }
230
231 WARN_ON(free_count != res_pool->free_count);
232}
233
234static void dprc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
235{
236 int pool_type;
237
238 for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++)
239 dprc_cleanup_resource_pool(mc_bus_dev, pool_type);
240}
241
f2f2726b
GR
242/**
243 * dprc_scan_objects - Discover objects in a DPRC
244 *
245 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
1e4aa42a 246 * @total_irq_count: total number of IRQs needed by objects in the DPRC.
f2f2726b
GR
247 *
248 * Detects objects added and removed from a DPRC and synchronizes the
249 * state of the Linux bus driver, MC by adding and removing
250 * devices accordingly.
197f4d6a
GR
251 * Two types of devices can be found in a DPRC: allocatable objects (e.g.,
252 * dpbp, dpmcp) and non-allocatable devices (e.g., dprc, dpni).
253 * All allocatable devices needed to be probed before all non-allocatable
254 * devices, to ensure that device drivers for non-allocatable
255 * devices can allocate any type of allocatable devices.
256 * That is, we need to ensure that the corresponding resource pools are
257 * populated before they can get allocation requests from probe callbacks
258 * of the device drivers for the non-allocatable devices.
f2f2726b 259 */
1e4aa42a
GR
260int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
261 unsigned int *total_irq_count)
f2f2726b
GR
262{
263 int num_child_objects;
264 int dprc_get_obj_failures;
265 int error;
1e4aa42a 266 unsigned int irq_count = mc_bus_dev->obj_desc.irq_count;
f2f2726b
GR
267 struct dprc_obj_desc *child_obj_desc_array = NULL;
268
269 error = dprc_get_obj_count(mc_bus_dev->mc_io,
1ee695fa 270 0,
f2f2726b
GR
271 mc_bus_dev->mc_handle,
272 &num_child_objects);
273 if (error < 0) {
274 dev_err(&mc_bus_dev->dev, "dprc_get_obj_count() failed: %d\n",
275 error);
276 return error;
277 }
278
279 if (num_child_objects != 0) {
280 int i;
281
282 child_obj_desc_array =
283 devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects,
284 sizeof(*child_obj_desc_array),
285 GFP_KERNEL);
286 if (!child_obj_desc_array)
287 return -ENOMEM;
288
289 /*
290 * Discover objects currently present in the physical DPRC:
291 */
292 dprc_get_obj_failures = 0;
293 for (i = 0; i < num_child_objects; i++) {
294 struct dprc_obj_desc *obj_desc =
295 &child_obj_desc_array[i];
296
297 error = dprc_get_obj(mc_bus_dev->mc_io,
1ee695fa 298 0,
f2f2726b
GR
299 mc_bus_dev->mc_handle,
300 i, obj_desc);
301 if (error < 0) {
302 dev_err(&mc_bus_dev->dev,
303 "dprc_get_obj(i=%d) failed: %d\n",
304 i, error);
305 /*
306 * Mark the obj entry as "invalid", by using the
307 * empty string as obj type:
308 */
309 obj_desc->type[0] = '\0';
310 obj_desc->id = error;
311 dprc_get_obj_failures++;
312 continue;
313 }
314
1e4aa42a 315 irq_count += obj_desc->irq_count;
f2f2726b
GR
316 dev_dbg(&mc_bus_dev->dev,
317 "Discovered object: type %s, id %d\n",
318 obj_desc->type, obj_desc->id);
319 }
320
321 if (dprc_get_obj_failures != 0) {
322 dev_err(&mc_bus_dev->dev,
323 "%d out of %d devices could not be retrieved\n",
324 dprc_get_obj_failures, num_child_objects);
325 }
326 }
327
1e4aa42a 328 *total_irq_count = irq_count;
f2f2726b
GR
329 dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
330 num_child_objects);
331
332 dprc_add_new_devices(mc_bus_dev, child_obj_desc_array,
333 num_child_objects);
334
335 if (child_obj_desc_array)
336 devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
337
338 return 0;
339}
340EXPORT_SYMBOL_GPL(dprc_scan_objects);
341
342/**
343 * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state
344 *
345 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
346 *
347 * Scans the physical DPRC and synchronizes the state of the Linux
348 * bus driver with the actual state of the MC by adding and removing
349 * devices as appropriate.
350 */
351int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
352{
353 int error;
1e4aa42a 354 unsigned int irq_count;
f2f2726b
GR
355 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
356
197f4d6a
GR
357 dprc_init_all_resource_pools(mc_bus_dev);
358
f2f2726b
GR
359 /*
360 * Discover objects in the DPRC:
361 */
362 mutex_lock(&mc_bus->scan_mutex);
1e4aa42a 363 error = dprc_scan_objects(mc_bus_dev, &irq_count);
f2f2726b 364 mutex_unlock(&mc_bus->scan_mutex);
197f4d6a
GR
365 if (error < 0)
366 goto error;
367
1e4aa42a
GR
368 if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) {
369 if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
370 dev_warn(&mc_bus_dev->dev,
371 "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
372 irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
373 }
374
375 error = fsl_mc_populate_irq_pool(
376 mc_bus,
377 FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
378 if (error < 0)
379 goto error;
380 }
381
197f4d6a
GR
382 return 0;
383error:
384 dprc_cleanup_all_resource_pools(mc_bus_dev);
f2f2726b
GR
385 return error;
386}
387EXPORT_SYMBOL_GPL(dprc_scan_container);
388
f52dee5c
GR
389/**
390 * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
391 *
392 * @irq: IRQ number of the interrupt being handled
393 * @arg: Pointer to device structure
394 */
395static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
396{
397 return IRQ_WAKE_THREAD;
398}
399
400/**
401 * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
402 *
403 * @irq: IRQ number of the interrupt being handled
404 * @arg: Pointer to device structure
405 */
406static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
407{
408 int error;
409 u32 status;
410 struct device *dev = (struct device *)arg;
411 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
412 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
413 struct fsl_mc_io *mc_io = mc_dev->mc_io;
414 struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc;
415
416 dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
417 irq_num, smp_processor_id());
418
419 if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
420 return IRQ_HANDLED;
421
422 mutex_lock(&mc_bus->scan_mutex);
423 if (WARN_ON(!msi_desc || msi_desc->irq != (u32)irq_num))
424 goto out;
425
426 error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
427 &status);
428 if (error < 0) {
429 dev_err(dev,
430 "dprc_get_irq_status() failed: %d\n", error);
431 goto out;
432 }
433
434 error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
435 status);
436 if (error < 0) {
437 dev_err(dev,
438 "dprc_clear_irq_status() failed: %d\n", error);
439 goto out;
440 }
441
442 if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
443 DPRC_IRQ_EVENT_OBJ_REMOVED |
444 DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
445 DPRC_IRQ_EVENT_OBJ_DESTROYED |
446 DPRC_IRQ_EVENT_OBJ_CREATED)) {
447 unsigned int irq_count;
448
449 error = dprc_scan_objects(mc_dev, &irq_count);
450 if (error < 0) {
451 /*
452 * If the error is -ENXIO, we ignore it, as it indicates
453 * that the object scan was aborted, as we detected that
454 * an object was removed from the DPRC in the MC, while
455 * we were scanning the DPRC.
456 */
457 if (error != -ENXIO) {
458 dev_err(dev, "dprc_scan_objects() failed: %d\n",
459 error);
460 }
461
462 goto out;
463 }
464
465 if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
466 dev_warn(dev,
467 "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
468 irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
469 }
470 }
471
472out:
473 mutex_unlock(&mc_bus->scan_mutex);
474 return IRQ_HANDLED;
475}
476
477/*
478 * Disable and clear interrupt for a given DPRC object
479 */
480static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
481{
482 int error;
483 struct fsl_mc_io *mc_io = mc_dev->mc_io;
484
485 WARN_ON(mc_dev->obj_desc.irq_count != 1);
486
487 /*
488 * Disable generation of interrupt, while we configure it:
489 */
490 error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0);
491 if (error < 0) {
492 dev_err(&mc_dev->dev,
493 "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
494 error);
495 return error;
496 }
497
498 /*
499 * Disable all interrupt causes for the interrupt:
500 */
501 error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0);
502 if (error < 0) {
503 dev_err(&mc_dev->dev,
504 "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
505 error);
506 return error;
507 }
508
509 /*
510 * Clear any leftover interrupts:
511 */
512 error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U);
513 if (error < 0) {
514 dev_err(&mc_dev->dev,
515 "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n",
516 error);
517 return error;
518 }
519
520 return 0;
521}
522
523static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
524{
525 int error;
526 struct fsl_mc_device_irq *irq = mc_dev->irqs[0];
527
528 WARN_ON(mc_dev->obj_desc.irq_count != 1);
529
530 /*
531 * NOTE: devm_request_threaded_irq() invokes the device-specific
532 * function that programs the MSI physically in the device
533 */
534 error = devm_request_threaded_irq(&mc_dev->dev,
535 irq->msi_desc->irq,
536 dprc_irq0_handler,
537 dprc_irq0_handler_thread,
538 IRQF_NO_SUSPEND | IRQF_ONESHOT,
539 "FSL MC DPRC irq0",
540 &mc_dev->dev);
541 if (error < 0) {
542 dev_err(&mc_dev->dev,
543 "devm_request_threaded_irq() failed: %d\n",
544 error);
545 return error;
546 }
547
548 return 0;
549}
550
551static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
552{
553 int error;
554
555 /*
556 * Enable all interrupt causes for the interrupt:
557 */
558 error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0,
559 ~0x0u);
560 if (error < 0) {
561 dev_err(&mc_dev->dev,
562 "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
563 error);
564
565 return error;
566 }
567
568 /*
569 * Enable generation of the interrupt:
570 */
571 error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1);
572 if (error < 0) {
573 dev_err(&mc_dev->dev,
574 "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
575 error);
576
577 return error;
578 }
579
580 return 0;
581}
582
583/*
584 * Setup interrupt for a given DPRC device
585 */
586static int dprc_setup_irq(struct fsl_mc_device *mc_dev)
587{
588 int error;
589
590 error = fsl_mc_allocate_irqs(mc_dev);
591 if (error < 0)
592 return error;
593
594 error = disable_dprc_irq(mc_dev);
595 if (error < 0)
596 goto error_free_irqs;
597
598 error = register_dprc_irq_handler(mc_dev);
599 if (error < 0)
600 goto error_free_irqs;
601
602 error = enable_dprc_irq(mc_dev);
603 if (error < 0)
604 goto error_free_irqs;
605
606 return 0;
607
608error_free_irqs:
609 fsl_mc_free_irqs(mc_dev);
610 return error;
611}
612
f2f2726b
GR
613/**
614 * dprc_probe - callback invoked when a DPRC is being bound to this driver
615 *
616 * @mc_dev: Pointer to fsl-mc device representing a DPRC
617 *
618 * It opens the physical DPRC in the MC.
619 * It scans the DPRC to discover the MC objects contained in it.
197f4d6a
GR
620 * It creates the interrupt pool for the MC bus associated with the DPRC.
621 * It configures the interrupts for the DPRC device itself.
f2f2726b
GR
622 */
623static int dprc_probe(struct fsl_mc_device *mc_dev)
624{
625 int error;
626 size_t region_size;
232ae8f2 627 struct device *parent_dev = mc_dev->dev.parent;
f2f2726b 628 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
8804f9fc 629 bool mc_io_created = false;
232ae8f2 630 bool msi_domain_set = false;
f2f2726b
GR
631
632 if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
633 return -EINVAL;
634
232ae8f2
GR
635 if (WARN_ON(dev_get_msi_domain(&mc_dev->dev)))
636 return -EINVAL;
637
f2f2726b
GR
638 if (!mc_dev->mc_io) {
639 /*
640 * This is a child DPRC:
641 */
8804f9fc
GR
642 if (WARN_ON(parent_dev->bus != &fsl_mc_bus_type))
643 return -EINVAL;
644
f2f2726b
GR
645 if (WARN_ON(mc_dev->obj_desc.region_count == 0))
646 return -EINVAL;
647
648 region_size = mc_dev->regions[0].end -
649 mc_dev->regions[0].start + 1;
650
651 error = fsl_create_mc_io(&mc_dev->dev,
652 mc_dev->regions[0].start,
653 region_size,
1129cde5
GR
654 NULL,
655 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
656 &mc_dev->mc_io);
f2f2726b
GR
657 if (error < 0)
658 return error;
8804f9fc
GR
659
660 mc_io_created = true;
661
232ae8f2
GR
662 /*
663 * Inherit parent MSI domain:
664 */
665 dev_set_msi_domain(&mc_dev->dev,
666 dev_get_msi_domain(parent_dev));
667 msi_domain_set = true;
668 } else {
669 /*
670 * This is a root DPRC
671 */
672 struct irq_domain *mc_msi_domain;
673
674 if (WARN_ON(parent_dev->bus == &fsl_mc_bus_type))
675 return -EINVAL;
676
677 error = fsl_mc_find_msi_domain(parent_dev,
678 &mc_msi_domain);
679 if (error < 0) {
680 dev_warn(&mc_dev->dev,
681 "WARNING: MC bus without interrupt support\n");
682 } else {
683 dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
684 msi_domain_set = true;
685 }
f2f2726b
GR
686 }
687
1ee695fa 688 error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
f2f2726b
GR
689 &mc_dev->mc_handle);
690 if (error < 0) {
691 dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error);
8804f9fc 692 goto error_cleanup_msi_domain;
f2f2726b
GR
693 }
694
695 mutex_init(&mc_bus->scan_mutex);
696
697 /*
698 * Discover MC objects in DPRC object:
699 */
700 error = dprc_scan_container(mc_dev);
701 if (error < 0)
702 goto error_cleanup_open;
703
f52dee5c
GR
704 /*
705 * Configure interrupt for the DPRC object associated with this MC bus:
706 */
707 error = dprc_setup_irq(mc_dev);
708 if (error < 0)
709 goto error_cleanup_open;
710
f2f2726b
GR
711 dev_info(&mc_dev->dev, "DPRC device bound to driver");
712 return 0;
713
714error_cleanup_open:
1ee695fa 715 (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
f2f2726b 716
8804f9fc 717error_cleanup_msi_domain:
232ae8f2
GR
718 if (msi_domain_set)
719 dev_set_msi_domain(&mc_dev->dev, NULL);
720
8804f9fc
GR
721 if (mc_io_created) {
722 fsl_destroy_mc_io(mc_dev->mc_io);
723 mc_dev->mc_io = NULL;
724 }
725
f2f2726b
GR
726 return error;
727}
728
f52dee5c
GR
729/*
730 * Tear down interrupt for a given DPRC object
731 */
732static void dprc_teardown_irq(struct fsl_mc_device *mc_dev)
733{
734 (void)disable_dprc_irq(mc_dev);
735 fsl_mc_free_irqs(mc_dev);
736}
737
f2f2726b
GR
738/**
739 * dprc_remove - callback invoked when a DPRC is being unbound from this driver
740 *
741 * @mc_dev: Pointer to fsl-mc device representing the DPRC
742 *
743 * It removes the DPRC's child objects from Linux (not from the MC) and
744 * closes the DPRC device in the MC.
197f4d6a
GR
745 * It tears down the interrupts that were configured for the DPRC device.
746 * It destroys the interrupt pool associated with this MC bus.
f2f2726b
GR
747 */
748static int dprc_remove(struct fsl_mc_device *mc_dev)
749{
750 int error;
232ae8f2 751 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
f2f2726b
GR
752
753 if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
754 return -EINVAL;
755 if (WARN_ON(!mc_dev->mc_io))
756 return -EINVAL;
757
f52dee5c
GR
758 if (WARN_ON(!mc_bus->irq_resources))
759 return -EINVAL;
760
761 if (dev_get_msi_domain(&mc_dev->dev))
762 dprc_teardown_irq(mc_dev);
763
f2f2726b 764 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
197f4d6a 765 dprc_cleanup_all_resource_pools(mc_dev);
1ee695fa 766 error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
f2f2726b
GR
767 if (error < 0)
768 dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error);
769
232ae8f2
GR
770 if (dev_get_msi_domain(&mc_dev->dev)) {
771 fsl_mc_cleanup_irq_pool(mc_bus);
772 dev_set_msi_domain(&mc_dev->dev, NULL);
773 }
774
f2f2726b
GR
775 dev_info(&mc_dev->dev, "DPRC device unbound from driver");
776 return 0;
777}
778
779static const struct fsl_mc_device_match_id match_id_table[] = {
780 {
781 .vendor = FSL_MC_VENDOR_FREESCALE,
782 .obj_type = "dprc",
783 .ver_major = DPRC_VER_MAJOR,
784 .ver_minor = DPRC_VER_MINOR},
785 {.vendor = 0x0},
786};
787
788static struct fsl_mc_driver dprc_driver = {
789 .driver = {
790 .name = FSL_MC_DPRC_DRIVER_NAME,
791 .owner = THIS_MODULE,
792 .pm = NULL,
793 },
794 .match_id_table = match_id_table,
795 .probe = dprc_probe,
796 .remove = dprc_remove,
797};
798
799int __init dprc_driver_init(void)
800{
801 return fsl_mc_driver_register(&dprc_driver);
802}
803
3c7b67f9 804void dprc_driver_exit(void)
f2f2726b
GR
805{
806 fsl_mc_driver_unregister(&dprc_driver);
807}
This page took 0.1799 seconds and 5 git commands to generate.