ACPI / EC: Work around method reentrancy limit in ACPICA for _Qxx
[cascardo/linux.git] / drivers / staging / fsl-mc / bus / dprc-driver.c
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>
16 #include <linux/interrupt.h>
17 #include <linux/msi.h>
18 #include "dprc-cmd.h"
19
20 struct dprc_child_objs {
21         int child_count;
22         struct dprc_obj_desc *child_array;
23 };
24
25 static 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
50 static 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  */
70 static 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
95 static 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
103 static 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
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  */
127 static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
128                                        struct dprc_obj_desc *obj_desc)
129 {
130         int error;
131         u32 plugged_flag_at_mc =
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
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  */
163 static 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;
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);
181                 if (child_dev) {
182                         check_plugged_state_change(child_dev, obj_desc);
183                         continue;
184                 }
185
186                 error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
187                                           &child_dev);
188                 if (error < 0)
189                         continue;
190         }
191 }
192
193 static 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
211 static 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
234 static 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
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
246  * @total_irq_count: total number of IRQs needed by objects in the DPRC.
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.
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.
259  */
260 int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
261                       unsigned int *total_irq_count)
262 {
263         int num_child_objects;
264         int dprc_get_obj_failures;
265         int error;
266         unsigned int irq_count = mc_bus_dev->obj_desc.irq_count;
267         struct dprc_obj_desc *child_obj_desc_array = NULL;
268
269         error = dprc_get_obj_count(mc_bus_dev->mc_io,
270                                    0,
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,
298                                              0,
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
315                         /*
316                          * add a quirk for all versions of dpsec < 4.0...none
317                          * are coherent regardless of what the MC reports.
318                          */
319                         if ((strcmp(obj_desc->type, "dpseci") == 0) &&
320                             (obj_desc->ver_major < 4))
321                                 obj_desc->flags |=
322                                         DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY;
323
324                         irq_count += obj_desc->irq_count;
325                         dev_dbg(&mc_bus_dev->dev,
326                                 "Discovered object: type %s, id %d\n",
327                                 obj_desc->type, obj_desc->id);
328                 }
329
330                 if (dprc_get_obj_failures != 0) {
331                         dev_err(&mc_bus_dev->dev,
332                                 "%d out of %d devices could not be retrieved\n",
333                                 dprc_get_obj_failures, num_child_objects);
334                 }
335         }
336
337         *total_irq_count = irq_count;
338         dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
339                             num_child_objects);
340
341         dprc_add_new_devices(mc_bus_dev, child_obj_desc_array,
342                              num_child_objects);
343
344         if (child_obj_desc_array)
345                 devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
346
347         return 0;
348 }
349 EXPORT_SYMBOL_GPL(dprc_scan_objects);
350
351 /**
352  * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state
353  *
354  * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
355  *
356  * Scans the physical DPRC and synchronizes the state of the Linux
357  * bus driver with the actual state of the MC by adding and removing
358  * devices as appropriate.
359  */
360 int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
361 {
362         int error;
363         unsigned int irq_count;
364         struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
365
366         dprc_init_all_resource_pools(mc_bus_dev);
367
368         /*
369          * Discover objects in the DPRC:
370          */
371         mutex_lock(&mc_bus->scan_mutex);
372         error = dprc_scan_objects(mc_bus_dev, &irq_count);
373         mutex_unlock(&mc_bus->scan_mutex);
374         if (error < 0)
375                 goto error;
376
377         if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) {
378                 if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
379                         dev_warn(&mc_bus_dev->dev,
380                                  "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
381                                  irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
382                 }
383
384                 error = fsl_mc_populate_irq_pool(
385                                 mc_bus,
386                                 FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
387                 if (error < 0)
388                         goto error;
389         }
390
391         return 0;
392 error:
393         dprc_cleanup_all_resource_pools(mc_bus_dev);
394         return error;
395 }
396 EXPORT_SYMBOL_GPL(dprc_scan_container);
397
398 /**
399  * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
400  *
401  * @irq: IRQ number of the interrupt being handled
402  * @arg: Pointer to device structure
403  */
404 static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
405 {
406         return IRQ_WAKE_THREAD;
407 }
408
409 /**
410  * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
411  *
412  * @irq: IRQ number of the interrupt being handled
413  * @arg: Pointer to device structure
414  */
415 static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
416 {
417         int error;
418         u32 status;
419         struct device *dev = arg;
420         struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
421         struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
422         struct fsl_mc_io *mc_io = mc_dev->mc_io;
423         struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc;
424
425         dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
426                 irq_num, smp_processor_id());
427
428         if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
429                 return IRQ_HANDLED;
430
431         mutex_lock(&mc_bus->scan_mutex);
432         if (WARN_ON(!msi_desc || msi_desc->irq != (u32)irq_num))
433                 goto out;
434
435         status = 0;
436         error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
437                                     &status);
438         if (error < 0) {
439                 dev_err(dev,
440                         "dprc_get_irq_status() failed: %d\n", error);
441                 goto out;
442         }
443
444         error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
445                                       status);
446         if (error < 0) {
447                 dev_err(dev,
448                         "dprc_clear_irq_status() failed: %d\n", error);
449                 goto out;
450         }
451
452         if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
453                       DPRC_IRQ_EVENT_OBJ_REMOVED |
454                       DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
455                       DPRC_IRQ_EVENT_OBJ_DESTROYED |
456                       DPRC_IRQ_EVENT_OBJ_CREATED)) {
457                 unsigned int irq_count;
458
459                 error = dprc_scan_objects(mc_dev, &irq_count);
460                 if (error < 0) {
461                         /*
462                          * If the error is -ENXIO, we ignore it, as it indicates
463                          * that the object scan was aborted, as we detected that
464                          * an object was removed from the DPRC in the MC, while
465                          * we were scanning the DPRC.
466                          */
467                         if (error != -ENXIO) {
468                                 dev_err(dev, "dprc_scan_objects() failed: %d\n",
469                                         error);
470                         }
471
472                         goto out;
473                 }
474
475                 if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
476                         dev_warn(dev,
477                                  "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
478                                  irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
479                 }
480         }
481
482 out:
483         mutex_unlock(&mc_bus->scan_mutex);
484         return IRQ_HANDLED;
485 }
486
487 /*
488  * Disable and clear interrupt for a given DPRC object
489  */
490 static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
491 {
492         int error;
493         struct fsl_mc_io *mc_io = mc_dev->mc_io;
494
495         WARN_ON(mc_dev->obj_desc.irq_count != 1);
496
497         /*
498          * Disable generation of interrupt, while we configure it:
499          */
500         error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0);
501         if (error < 0) {
502                 dev_err(&mc_dev->dev,
503                         "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
504                         error);
505                 return error;
506         }
507
508         /*
509          * Disable all interrupt causes for the interrupt:
510          */
511         error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0);
512         if (error < 0) {
513                 dev_err(&mc_dev->dev,
514                         "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
515                         error);
516                 return error;
517         }
518
519         /*
520          * Clear any leftover interrupts:
521          */
522         error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U);
523         if (error < 0) {
524                 dev_err(&mc_dev->dev,
525                         "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n",
526                         error);
527                 return error;
528         }
529
530         return 0;
531 }
532
533 static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
534 {
535         int error;
536         struct fsl_mc_device_irq *irq = mc_dev->irqs[0];
537
538         WARN_ON(mc_dev->obj_desc.irq_count != 1);
539
540         /*
541          * NOTE: devm_request_threaded_irq() invokes the device-specific
542          * function that programs the MSI physically in the device
543          */
544         error = devm_request_threaded_irq(&mc_dev->dev,
545                                           irq->msi_desc->irq,
546                                           dprc_irq0_handler,
547                                           dprc_irq0_handler_thread,
548                                           IRQF_NO_SUSPEND | IRQF_ONESHOT,
549                                           "FSL MC DPRC irq0",
550                                           &mc_dev->dev);
551         if (error < 0) {
552                 dev_err(&mc_dev->dev,
553                         "devm_request_threaded_irq() failed: %d\n",
554                         error);
555                 return error;
556         }
557
558         return 0;
559 }
560
561 static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
562 {
563         int error;
564
565         /*
566          * Enable all interrupt causes for the interrupt:
567          */
568         error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0,
569                                   ~0x0u);
570         if (error < 0) {
571                 dev_err(&mc_dev->dev,
572                         "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
573                         error);
574
575                 return error;
576         }
577
578         /*
579          * Enable generation of the interrupt:
580          */
581         error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1);
582         if (error < 0) {
583                 dev_err(&mc_dev->dev,
584                         "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
585                         error);
586
587                 return error;
588         }
589
590         return 0;
591 }
592
593 /*
594  * Setup interrupt for a given DPRC device
595  */
596 static int dprc_setup_irq(struct fsl_mc_device *mc_dev)
597 {
598         int error;
599
600         error = fsl_mc_allocate_irqs(mc_dev);
601         if (error < 0)
602                 return error;
603
604         error = disable_dprc_irq(mc_dev);
605         if (error < 0)
606                 goto error_free_irqs;
607
608         error = register_dprc_irq_handler(mc_dev);
609         if (error < 0)
610                 goto error_free_irqs;
611
612         error = enable_dprc_irq(mc_dev);
613         if (error < 0)
614                 goto error_free_irqs;
615
616         return 0;
617
618 error_free_irqs:
619         fsl_mc_free_irqs(mc_dev);
620         return error;
621 }
622
623 /**
624  * dprc_probe - callback invoked when a DPRC is being bound to this driver
625  *
626  * @mc_dev: Pointer to fsl-mc device representing a DPRC
627  *
628  * It opens the physical DPRC in the MC.
629  * It scans the DPRC to discover the MC objects contained in it.
630  * It creates the interrupt pool for the MC bus associated with the DPRC.
631  * It configures the interrupts for the DPRC device itself.
632  */
633 static int dprc_probe(struct fsl_mc_device *mc_dev)
634 {
635         int error;
636         size_t region_size;
637         struct device *parent_dev = mc_dev->dev.parent;
638         struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
639         bool mc_io_created = false;
640         bool msi_domain_set = false;
641
642         if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
643                 return -EINVAL;
644
645         if (WARN_ON(dev_get_msi_domain(&mc_dev->dev)))
646                 return -EINVAL;
647
648         if (!mc_dev->mc_io) {
649                 /*
650                  * This is a child DPRC:
651                  */
652                 if (WARN_ON(parent_dev->bus != &fsl_mc_bus_type))
653                         return -EINVAL;
654
655                 if (WARN_ON(mc_dev->obj_desc.region_count == 0))
656                         return -EINVAL;
657
658                 region_size = mc_dev->regions[0].end -
659                               mc_dev->regions[0].start + 1;
660
661                 error = fsl_create_mc_io(&mc_dev->dev,
662                                          mc_dev->regions[0].start,
663                                          region_size,
664                                          NULL,
665                                          FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
666                                          &mc_dev->mc_io);
667                 if (error < 0)
668                         return error;
669
670                 mc_io_created = true;
671
672                 /*
673                  * Inherit parent MSI domain:
674                  */
675                 dev_set_msi_domain(&mc_dev->dev,
676                                    dev_get_msi_domain(parent_dev));
677                 msi_domain_set = true;
678         } else {
679                 /*
680                  * This is a root DPRC
681                  */
682                 struct irq_domain *mc_msi_domain;
683
684                 if (WARN_ON(parent_dev->bus == &fsl_mc_bus_type))
685                         return -EINVAL;
686
687                 error = fsl_mc_find_msi_domain(parent_dev,
688                                                &mc_msi_domain);
689                 if (error < 0) {
690                         dev_warn(&mc_dev->dev,
691                                  "WARNING: MC bus without interrupt support\n");
692                 } else {
693                         dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
694                         msi_domain_set = true;
695                 }
696         }
697
698         error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
699                           &mc_dev->mc_handle);
700         if (error < 0) {
701                 dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error);
702                 goto error_cleanup_msi_domain;
703         }
704
705         error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle,
706                                     &mc_bus->dprc_attr);
707         if (error < 0) {
708                 dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n",
709                         error);
710                 goto error_cleanup_open;
711         }
712
713         if (mc_bus->dprc_attr.version.major < DPRC_MIN_VER_MAJOR ||
714            (mc_bus->dprc_attr.version.major == DPRC_MIN_VER_MAJOR &&
715             mc_bus->dprc_attr.version.minor < DPRC_MIN_VER_MINOR)) {
716                 dev_err(&mc_dev->dev,
717                         "ERROR: DPRC version %d.%d not supported\n",
718                         mc_bus->dprc_attr.version.major,
719                         mc_bus->dprc_attr.version.minor);
720                 error = -ENOTSUPP;
721                 goto error_cleanup_open;
722         }
723
724         mutex_init(&mc_bus->scan_mutex);
725
726         /*
727          * Discover MC objects in DPRC object:
728          */
729         error = dprc_scan_container(mc_dev);
730         if (error < 0)
731                 goto error_cleanup_open;
732
733         /*
734          * Configure interrupt for the DPRC object associated with this MC bus:
735          */
736         error = dprc_setup_irq(mc_dev);
737         if (error < 0)
738                 goto error_cleanup_open;
739
740         dev_info(&mc_dev->dev, "DPRC device bound to driver");
741         return 0;
742
743 error_cleanup_open:
744         (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
745
746 error_cleanup_msi_domain:
747         if (msi_domain_set)
748                 dev_set_msi_domain(&mc_dev->dev, NULL);
749
750         if (mc_io_created) {
751                 fsl_destroy_mc_io(mc_dev->mc_io);
752                 mc_dev->mc_io = NULL;
753         }
754
755         return error;
756 }
757
758 /*
759  * Tear down interrupt for a given DPRC object
760  */
761 static void dprc_teardown_irq(struct fsl_mc_device *mc_dev)
762 {
763         (void)disable_dprc_irq(mc_dev);
764         fsl_mc_free_irqs(mc_dev);
765 }
766
767 /**
768  * dprc_remove - callback invoked when a DPRC is being unbound from this driver
769  *
770  * @mc_dev: Pointer to fsl-mc device representing the DPRC
771  *
772  * It removes the DPRC's child objects from Linux (not from the MC) and
773  * closes the DPRC device in the MC.
774  * It tears down the interrupts that were configured for the DPRC device.
775  * It destroys the interrupt pool associated with this MC bus.
776  */
777 static int dprc_remove(struct fsl_mc_device *mc_dev)
778 {
779         int error;
780         struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
781
782         if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
783                 return -EINVAL;
784         if (WARN_ON(!mc_dev->mc_io))
785                 return -EINVAL;
786
787         if (WARN_ON(!mc_bus->irq_resources))
788                 return -EINVAL;
789
790         if (dev_get_msi_domain(&mc_dev->dev))
791                 dprc_teardown_irq(mc_dev);
792
793         device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
794         dprc_cleanup_all_resource_pools(mc_dev);
795         error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
796         if (error < 0)
797                 dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error);
798
799         if (dev_get_msi_domain(&mc_dev->dev)) {
800                 fsl_mc_cleanup_irq_pool(mc_bus);
801                 dev_set_msi_domain(&mc_dev->dev, NULL);
802         }
803
804         dev_info(&mc_dev->dev, "DPRC device unbound from driver");
805         return 0;
806 }
807
808 static const struct fsl_mc_device_match_id match_id_table[] = {
809         {
810          .vendor = FSL_MC_VENDOR_FREESCALE,
811          .obj_type = "dprc"},
812         {.vendor = 0x0},
813 };
814
815 static struct fsl_mc_driver dprc_driver = {
816         .driver = {
817                    .name = FSL_MC_DPRC_DRIVER_NAME,
818                    .owner = THIS_MODULE,
819                    .pm = NULL,
820                    },
821         .match_id_table = match_id_table,
822         .probe = dprc_probe,
823         .remove = dprc_remove,
824 };
825
826 int __init dprc_driver_init(void)
827 {
828         return fsl_mc_driver_register(&dprc_driver);
829 }
830
831 void dprc_driver_exit(void)
832 {
833         fsl_mc_driver_unregister(&dprc_driver);
834 }