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