]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/fsl-mc/bus/mc-bus.c
Merge remote-tracking branch 'staging/staging-next'
[karo-tx-linux.git] / drivers / staging / fsl-mc / bus / mc-bus.c
1 /*
2  * Freescale Management Complex (MC) bus 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 <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/of_address.h>
16 #include <linux/ioport.h>
17 #include <linux/slab.h>
18 #include <linux/limits.h>
19 #include "../include/dpmng.h"
20 #include "../include/mc-sys.h"
21 #include "dprc-cmd.h"
22
23 static struct kmem_cache *mc_dev_cache;
24
25 static bool fsl_mc_is_root_dprc(struct device *dev);
26
27 /**
28  * fsl_mc_bus_match - device to driver matching callback
29  * @dev: the MC object device structure to match against
30  * @drv: the device driver to search for matching MC object device id
31  * structures
32  *
33  * Returns 1 on success, 0 otherwise.
34  */
35 static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv)
36 {
37         const struct fsl_mc_device_match_id *id;
38         struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
39         struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv);
40         bool found = false;
41         bool major_version_mismatch = false;
42         bool minor_version_mismatch = false;
43
44         if (WARN_ON(!fsl_mc_bus_exists()))
45                 goto out;
46
47         if (!mc_drv->match_id_table)
48                 goto out;
49
50         /*
51          * If the object is not 'plugged' don't match.
52          * Only exception is the root DPRC, which is a special case.
53          */
54         if ((mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED) == 0 &&
55             !fsl_mc_is_root_dprc(&mc_dev->dev))
56                 goto out;
57
58         /*
59          * Traverse the match_id table of the given driver, trying to find
60          * a matching for the given MC object device.
61          */
62         for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) {
63                 if (id->vendor == mc_dev->obj_desc.vendor &&
64                     strcmp(id->obj_type, mc_dev->obj_desc.type) == 0) {
65                         if (id->ver_major == mc_dev->obj_desc.ver_major) {
66                                 found = true;
67                                 if (id->ver_minor != mc_dev->obj_desc.ver_minor)
68                                         minor_version_mismatch = true;
69                         } else {
70                                 major_version_mismatch = true;
71                         }
72
73                         break;
74                 }
75         }
76
77         if (major_version_mismatch) {
78                 dev_warn(dev,
79                          "Major version mismatch: driver version %u.%u, MC object version %u.%u\n",
80                          id->ver_major, id->ver_minor,
81                          mc_dev->obj_desc.ver_major,
82                          mc_dev->obj_desc.ver_minor);
83         } else if (minor_version_mismatch) {
84                 dev_warn(dev,
85                          "Minor version mismatch: driver version %u.%u, MC object version %u.%u\n",
86                          id->ver_major, id->ver_minor,
87                          mc_dev->obj_desc.ver_major,
88                          mc_dev->obj_desc.ver_minor);
89         }
90
91 out:
92         dev_dbg(dev, "%smatched\n", found ? "" : "not ");
93         return found;
94 }
95
96 /**
97  * fsl_mc_bus_uevent - callback invoked when a device is added
98  */
99 static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
100 {
101         pr_debug("%s invoked\n", __func__);
102         return 0;
103 }
104
105 struct bus_type fsl_mc_bus_type = {
106         .name = "fsl-mc",
107         .match = fsl_mc_bus_match,
108         .uevent = fsl_mc_bus_uevent,
109 };
110 EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
111
112 static atomic_t root_dprc_count = ATOMIC_INIT(0);
113
114 static int fsl_mc_driver_probe(struct device *dev)
115 {
116         struct fsl_mc_driver *mc_drv;
117         struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
118         int error;
119
120         if (WARN_ON(!dev->driver))
121                 return -EINVAL;
122
123         mc_drv = to_fsl_mc_driver(dev->driver);
124         if (WARN_ON(!mc_drv->probe))
125                 return -EINVAL;
126
127         error = mc_drv->probe(mc_dev);
128         if (error < 0) {
129                 dev_err(dev, "MC object device probe callback failed: %d\n",
130                         error);
131                 return error;
132         }
133
134         return 0;
135 }
136
137 static int fsl_mc_driver_remove(struct device *dev)
138 {
139         struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
140         struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
141         int error;
142
143         if (WARN_ON(!dev->driver))
144                 return -EINVAL;
145
146         error = mc_drv->remove(mc_dev);
147         if (error < 0) {
148                 dev_err(dev,
149                         "MC object device remove callback failed: %d\n",
150                         error);
151                 return error;
152         }
153
154         return 0;
155 }
156
157 static void fsl_mc_driver_shutdown(struct device *dev)
158 {
159         struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
160         struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
161
162         mc_drv->shutdown(mc_dev);
163 }
164
165 /**
166  * __fsl_mc_driver_register - registers a child device driver with the
167  * MC bus
168  *
169  * This function is implicitly invoked from the registration function of
170  * fsl_mc device drivers, which is generated by the
171  * module_fsl_mc_driver() macro.
172  */
173 int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver,
174                              struct module *owner)
175 {
176         int error;
177
178         mc_driver->driver.owner = owner;
179         mc_driver->driver.bus = &fsl_mc_bus_type;
180
181         if (mc_driver->probe)
182                 mc_driver->driver.probe = fsl_mc_driver_probe;
183
184         if (mc_driver->remove)
185                 mc_driver->driver.remove = fsl_mc_driver_remove;
186
187         if (mc_driver->shutdown)
188                 mc_driver->driver.shutdown = fsl_mc_driver_shutdown;
189
190         error = driver_register(&mc_driver->driver);
191         if (error < 0) {
192                 pr_err("driver_register() failed for %s: %d\n",
193                        mc_driver->driver.name, error);
194                 return error;
195         }
196
197         pr_info("MC object device driver %s registered\n",
198                 mc_driver->driver.name);
199         return 0;
200 }
201 EXPORT_SYMBOL_GPL(__fsl_mc_driver_register);
202
203 /**
204  * fsl_mc_driver_unregister - unregisters a device driver from the
205  * MC bus
206  */
207 void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver)
208 {
209         driver_unregister(&mc_driver->driver);
210 }
211 EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister);
212
213 /**
214  * fsl_mc_bus_exists - check if a root dprc exists
215  */
216 bool fsl_mc_bus_exists(void)
217 {
218         return atomic_read(&root_dprc_count) > 0;
219 }
220 EXPORT_SYMBOL_GPL(fsl_mc_bus_exists);
221
222 /**
223 * fsl_mc_get_root_dprc - function to traverse to the root dprc
224 */
225 static void fsl_mc_get_root_dprc(struct device *dev,
226                                  struct device **root_dprc_dev)
227 {
228         if (WARN_ON(!dev)) {
229                 *root_dprc_dev = NULL;
230         } else if (WARN_ON(dev->bus != &fsl_mc_bus_type)) {
231                 *root_dprc_dev = NULL;
232         } else {
233                 *root_dprc_dev = dev;
234                 while ((*root_dprc_dev)->parent->bus == &fsl_mc_bus_type)
235                         *root_dprc_dev = (*root_dprc_dev)->parent;
236         }
237 }
238
239 /**
240  * fsl_mc_is_root_dprc - function to check if a given device is a root dprc
241  */
242 static bool fsl_mc_is_root_dprc(struct device *dev)
243 {
244         struct device *root_dprc_dev;
245
246         fsl_mc_get_root_dprc(dev, &root_dprc_dev);
247         if (!root_dprc_dev)
248                 return false;
249         else
250                 return dev == root_dprc_dev;
251 }
252
253 static int get_dprc_icid(struct fsl_mc_io *mc_io,
254                          int container_id, u16 *icid)
255 {
256         u16 dprc_handle;
257         struct dprc_attributes attr;
258         int error;
259
260         error = dprc_open(mc_io, 0, container_id, &dprc_handle);
261         if (error < 0) {
262                 pr_err("dprc_open() failed: %d\n", error);
263                 return error;
264         }
265
266         memset(&attr, 0, sizeof(attr));
267         error = dprc_get_attributes(mc_io, 0, dprc_handle, &attr);
268         if (error < 0) {
269                 pr_err("dprc_get_attributes() failed: %d\n", error);
270                 goto common_cleanup;
271         }
272
273         *icid = attr.icid;
274         error = 0;
275
276 common_cleanup:
277         (void)dprc_close(mc_io, 0, dprc_handle);
278         return error;
279 }
280
281 static int translate_mc_addr(struct fsl_mc_device *mc_dev,
282                              enum dprc_region_type mc_region_type,
283                              u64 mc_offset, phys_addr_t *phys_addr)
284 {
285         int i;
286         struct device *root_dprc_dev;
287         struct fsl_mc *mc;
288
289         fsl_mc_get_root_dprc(&mc_dev->dev, &root_dprc_dev);
290         if (WARN_ON(!root_dprc_dev))
291                 return -EINVAL;
292         mc = dev_get_drvdata(root_dprc_dev->parent);
293
294         if (mc->num_translation_ranges == 0) {
295                 /*
296                  * Do identity mapping:
297                  */
298                 *phys_addr = mc_offset;
299                 return 0;
300         }
301
302         for (i = 0; i < mc->num_translation_ranges; i++) {
303                 struct fsl_mc_addr_translation_range *range =
304                         &mc->translation_ranges[i];
305
306                 if (mc_region_type == range->mc_region_type &&
307                     mc_offset >= range->start_mc_offset &&
308                     mc_offset < range->end_mc_offset) {
309                         *phys_addr = range->start_phys_addr +
310                                      (mc_offset - range->start_mc_offset);
311                         return 0;
312                 }
313         }
314
315         return -EFAULT;
316 }
317
318 static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
319                                           struct fsl_mc_device *mc_bus_dev)
320 {
321         int i;
322         int error;
323         struct resource *regions;
324         struct dprc_obj_desc *obj_desc = &mc_dev->obj_desc;
325         struct device *parent_dev = mc_dev->dev.parent;
326         enum dprc_region_type mc_region_type;
327
328         if (strcmp(obj_desc->type, "dprc") == 0 ||
329             strcmp(obj_desc->type, "dpmcp") == 0) {
330                 mc_region_type = DPRC_REGION_TYPE_MC_PORTAL;
331         } else if (strcmp(obj_desc->type, "dpio") == 0) {
332                 mc_region_type = DPRC_REGION_TYPE_QBMAN_PORTAL;
333         } else {
334                 /*
335                  * This function should not have been called for this MC object
336                  * type, as this object type is not supposed to have MMIO
337                  * regions
338                  */
339                 WARN_ON(true);
340                 return -EINVAL;
341         }
342
343         regions = kmalloc_array(obj_desc->region_count,
344                                 sizeof(regions[0]), GFP_KERNEL);
345         if (!regions)
346                 return -ENOMEM;
347
348         for (i = 0; i < obj_desc->region_count; i++) {
349                 struct dprc_region_desc region_desc;
350
351                 error = dprc_get_obj_region(mc_bus_dev->mc_io,
352                                             0,
353                                             mc_bus_dev->mc_handle,
354                                             obj_desc->type,
355                                             obj_desc->id, i, &region_desc);
356                 if (error < 0) {
357                         dev_err(parent_dev,
358                                 "dprc_get_obj_region() failed: %d\n", error);
359                         goto error_cleanup_regions;
360                 }
361
362                 WARN_ON(region_desc.size == 0);
363                 error = translate_mc_addr(mc_dev, mc_region_type,
364                                           region_desc.base_offset,
365                                           &regions[i].start);
366                 if (error < 0) {
367                         dev_err(parent_dev,
368                                 "Invalid MC offset: %#x (for %s.%d\'s region %d)\n",
369                                 region_desc.base_offset,
370                                 obj_desc->type, obj_desc->id, i);
371                         goto error_cleanup_regions;
372                 }
373
374                 regions[i].end = regions[i].start + region_desc.size - 1;
375                 regions[i].name = "fsl-mc object MMIO region";
376                 regions[i].flags = IORESOURCE_IO;
377         }
378
379         mc_dev->regions = regions;
380         return 0;
381
382 error_cleanup_regions:
383         kfree(regions);
384         return error;
385 }
386
387 /**
388  * Add a newly discovered MC object device to be visible in Linux
389  */
390 int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
391                       struct fsl_mc_io *mc_io,
392                       struct device *parent_dev,
393                       struct fsl_mc_device **new_mc_dev)
394 {
395         int error;
396         struct fsl_mc_device *mc_dev = NULL;
397         struct fsl_mc_bus *mc_bus = NULL;
398         struct fsl_mc_device *parent_mc_dev;
399
400         if (parent_dev->bus == &fsl_mc_bus_type)
401                 parent_mc_dev = to_fsl_mc_device(parent_dev);
402         else
403                 parent_mc_dev = NULL;
404
405         if (strcmp(obj_desc->type, "dprc") == 0) {
406                 /*
407                  * Allocate an MC bus device object:
408                  */
409                 mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL);
410                 if (!mc_bus)
411                         return -ENOMEM;
412
413                 mc_dev = &mc_bus->mc_dev;
414         } else {
415                 /*
416                  * Allocate a regular fsl_mc_device object:
417                  */
418                 mc_dev = kmem_cache_zalloc(mc_dev_cache, GFP_KERNEL);
419                 if (!mc_dev)
420                         return -ENOMEM;
421         }
422
423         mc_dev->obj_desc = *obj_desc;
424         mc_dev->mc_io = mc_io;
425         device_initialize(&mc_dev->dev);
426         mc_dev->dev.parent = parent_dev;
427         mc_dev->dev.bus = &fsl_mc_bus_type;
428         dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id);
429
430         if (strcmp(obj_desc->type, "dprc") == 0) {
431                 struct fsl_mc_io *mc_io2;
432
433                 mc_dev->flags |= FSL_MC_IS_DPRC;
434
435                 /*
436                  * To get the DPRC's ICID, we need to open the DPRC
437                  * in get_dprc_icid(). For child DPRCs, we do so using the
438                  * parent DPRC's MC portal instead of the child DPRC's MC
439                  * portal, in case the child DPRC is already opened with
440                  * its own portal (e.g., the DPRC used by AIOP).
441                  *
442                  * NOTE: There cannot be more than one active open for a
443                  * given MC object, using the same MC portal.
444                  */
445                 if (parent_mc_dev) {
446                         /*
447                          * device being added is a child DPRC device
448                          */
449                         mc_io2 = parent_mc_dev->mc_io;
450                 } else {
451                         /*
452                          * device being added is the root DPRC device
453                          */
454                         if (WARN_ON(!mc_io)) {
455                                 error = -EINVAL;
456                                 goto error_cleanup_dev;
457                         }
458
459                         mc_io2 = mc_io;
460
461                         atomic_inc(&root_dprc_count);
462                 }
463
464                 error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid);
465                 if (error < 0)
466                         goto error_cleanup_dev;
467         } else {
468                 /*
469                  * A non-DPRC MC object device has to be a child of another
470                  * MC object (specifically a DPRC object)
471                  */
472                 mc_dev->icid = parent_mc_dev->icid;
473                 mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK;
474                 mc_dev->dev.dma_mask = &mc_dev->dma_mask;
475         }
476
477         /*
478          * Get MMIO regions for the device from the MC:
479          *
480          * NOTE: the root DPRC is a special case as its MMIO region is
481          * obtained from the device tree
482          */
483         if (parent_mc_dev && obj_desc->region_count != 0) {
484                 error = fsl_mc_device_get_mmio_regions(mc_dev,
485                                                        parent_mc_dev);
486                 if (error < 0)
487                         goto error_cleanup_dev;
488         }
489
490         /*
491          * The device-specific probe callback will get invoked by device_add()
492          */
493         error = device_add(&mc_dev->dev);
494         if (error < 0) {
495                 dev_err(parent_dev,
496                         "device_add() failed for device %s: %d\n",
497                         dev_name(&mc_dev->dev), error);
498                 goto error_cleanup_dev;
499         }
500
501         (void)get_device(&mc_dev->dev);
502         dev_dbg(parent_dev, "Added MC object device %s\n",
503                 dev_name(&mc_dev->dev));
504
505         *new_mc_dev = mc_dev;
506         return 0;
507
508 error_cleanup_dev:
509         kfree(mc_dev->regions);
510         if (mc_bus)
511                 devm_kfree(parent_dev, mc_bus);
512         else
513                 kmem_cache_free(mc_dev_cache, mc_dev);
514
515         return error;
516 }
517 EXPORT_SYMBOL_GPL(fsl_mc_device_add);
518
519 /**
520  * fsl_mc_device_remove - Remove a MC object device from being visible to
521  * Linux
522  *
523  * @mc_dev: Pointer to a MC object device object
524  */
525 void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
526 {
527         struct fsl_mc_bus *mc_bus = NULL;
528
529         kfree(mc_dev->regions);
530
531         /*
532          * The device-specific remove callback will get invoked by device_del()
533          */
534         device_del(&mc_dev->dev);
535         put_device(&mc_dev->dev);
536
537         if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) {
538                 mc_bus = to_fsl_mc_bus(mc_dev);
539                 if (mc_dev->mc_io) {
540                         fsl_destroy_mc_io(mc_dev->mc_io);
541                         mc_dev->mc_io = NULL;
542                 }
543
544                 if (fsl_mc_is_root_dprc(&mc_dev->dev)) {
545                         if (atomic_read(&root_dprc_count) > 0)
546                                 atomic_dec(&root_dprc_count);
547                         else
548                                 WARN_ON(1);
549                 }
550         }
551
552         if (mc_bus)
553                 devm_kfree(mc_dev->dev.parent, mc_bus);
554         else
555                 kmem_cache_free(mc_dev_cache, mc_dev);
556 }
557 EXPORT_SYMBOL_GPL(fsl_mc_device_remove);
558
559 static int parse_mc_ranges(struct device *dev,
560                            int *paddr_cells,
561                            int *mc_addr_cells,
562                            int *mc_size_cells,
563                            const __be32 **ranges_start,
564                            u8 *num_ranges)
565 {
566         const __be32 *prop;
567         int range_tuple_cell_count;
568         int ranges_len;
569         int tuple_len;
570         struct device_node *mc_node = dev->of_node;
571
572         *ranges_start = of_get_property(mc_node, "ranges", &ranges_len);
573         if (!(*ranges_start) || !ranges_len) {
574                 dev_warn(dev,
575                          "missing or empty ranges property for device tree node '%s'\n",
576                          mc_node->name);
577
578                 *num_ranges = 0;
579                 return 0;
580         }
581
582         *paddr_cells = of_n_addr_cells(mc_node);
583
584         prop = of_get_property(mc_node, "#address-cells", NULL);
585         if (prop)
586                 *mc_addr_cells = be32_to_cpup(prop);
587         else
588                 *mc_addr_cells = *paddr_cells;
589
590         prop = of_get_property(mc_node, "#size-cells", NULL);
591         if (prop)
592                 *mc_size_cells = be32_to_cpup(prop);
593         else
594                 *mc_size_cells = of_n_size_cells(mc_node);
595
596         range_tuple_cell_count = *paddr_cells + *mc_addr_cells +
597                                  *mc_size_cells;
598
599         tuple_len = range_tuple_cell_count * sizeof(__be32);
600         if (ranges_len % tuple_len != 0) {
601                 dev_err(dev, "malformed ranges property '%s'\n", mc_node->name);
602                 return -EINVAL;
603         }
604
605         *num_ranges = ranges_len / tuple_len;
606         return 0;
607 }
608
609 static int get_mc_addr_translation_ranges(struct device *dev,
610                                           struct fsl_mc_addr_translation_range
611                                                 **ranges,
612                                           u8 *num_ranges)
613 {
614         int error;
615         int paddr_cells;
616         int mc_addr_cells;
617         int mc_size_cells;
618         int i;
619         const __be32 *ranges_start;
620         const __be32 *cell;
621
622         error = parse_mc_ranges(dev,
623                                 &paddr_cells,
624                                 &mc_addr_cells,
625                                 &mc_size_cells,
626                                 &ranges_start,
627                                 num_ranges);
628         if (error < 0)
629                 return error;
630
631         if (!(*num_ranges)) {
632                 /*
633                  * Missing or empty ranges property ("ranges;") for the
634                  * 'fsl,qoriq-mc' node. In this case, identity mapping
635                  * will be used.
636                  */
637                 *ranges = NULL;
638                 return 0;
639         }
640
641         *ranges = devm_kcalloc(dev, *num_ranges,
642                                sizeof(struct fsl_mc_addr_translation_range),
643                                GFP_KERNEL);
644         if (!(*ranges))
645                 return -ENOMEM;
646
647         cell = ranges_start;
648         for (i = 0; i < *num_ranges; ++i) {
649                 struct fsl_mc_addr_translation_range *range = &(*ranges)[i];
650
651                 range->mc_region_type = of_read_number(cell, 1);
652                 range->start_mc_offset = of_read_number(cell + 1,
653                                                         mc_addr_cells - 1);
654                 cell += mc_addr_cells;
655                 range->start_phys_addr = of_read_number(cell, paddr_cells);
656                 cell += paddr_cells;
657                 range->end_mc_offset = range->start_mc_offset +
658                                      of_read_number(cell, mc_size_cells);
659
660                 cell += mc_size_cells;
661         }
662
663         return 0;
664 }
665
666 /**
667  * fsl_mc_bus_probe - callback invoked when the root MC bus is being
668  * added
669  */
670 static int fsl_mc_bus_probe(struct platform_device *pdev)
671 {
672         struct dprc_obj_desc obj_desc;
673         int error;
674         struct fsl_mc *mc;
675         struct fsl_mc_device *mc_bus_dev = NULL;
676         struct fsl_mc_io *mc_io = NULL;
677         int container_id;
678         phys_addr_t mc_portal_phys_addr;
679         u32 mc_portal_size;
680         struct mc_version mc_version;
681         struct resource res;
682
683         dev_info(&pdev->dev, "Root MC bus device probed");
684
685         mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
686         if (!mc)
687                 return -ENOMEM;
688
689         platform_set_drvdata(pdev, mc);
690
691         /*
692          * Get physical address of MC portal for the root DPRC:
693          */
694         error = of_address_to_resource(pdev->dev.of_node, 0, &res);
695         if (error < 0) {
696                 dev_err(&pdev->dev,
697                         "of_address_to_resource() failed for %s\n",
698                         pdev->dev.of_node->full_name);
699                 return error;
700         }
701
702         mc_portal_phys_addr = res.start;
703         mc_portal_size = resource_size(&res);
704         error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr,
705                                  mc_portal_size, NULL, 0, &mc_io);
706         if (error < 0)
707                 return error;
708
709         error = mc_get_version(mc_io, 0, &mc_version);
710         if (error != 0) {
711                 dev_err(&pdev->dev,
712                         "mc_get_version() failed with error %d\n", error);
713                 goto error_cleanup_mc_io;
714         }
715
716         dev_info(&pdev->dev,
717                  "Freescale Management Complex Firmware version: %u.%u.%u\n",
718                  mc_version.major, mc_version.minor, mc_version.revision);
719
720         if (mc_version.major < MC_VER_MAJOR) {
721                 dev_err(&pdev->dev,
722                         "ERROR: MC firmware version not supported by driver (driver version: %u.%u)\n",
723                         MC_VER_MAJOR, MC_VER_MINOR);
724                 error = -ENOTSUPP;
725                 goto error_cleanup_mc_io;
726         }
727
728         if (mc_version.major > MC_VER_MAJOR) {
729                 dev_warn(&pdev->dev,
730                          "WARNING: driver may not support newer MC firmware features (driver version: %u.%u)\n",
731                          MC_VER_MAJOR, MC_VER_MINOR);
732         }
733
734         error = get_mc_addr_translation_ranges(&pdev->dev,
735                                                &mc->translation_ranges,
736                                                &mc->num_translation_ranges);
737         if (error < 0)
738                 goto error_cleanup_mc_io;
739
740         error = dpmng_get_container_id(mc_io, 0, &container_id);
741         if (error < 0) {
742                 dev_err(&pdev->dev,
743                         "dpmng_get_container_id() failed: %d\n", error);
744                 goto error_cleanup_mc_io;
745         }
746
747         obj_desc.vendor = FSL_MC_VENDOR_FREESCALE;
748         strcpy(obj_desc.type, "dprc");
749         obj_desc.id = container_id;
750         obj_desc.ver_major = DPRC_VER_MAJOR;
751         obj_desc.ver_minor = DPRC_VER_MINOR;
752         obj_desc.irq_count = 1;
753         obj_desc.region_count = 0;
754
755         error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev);
756         if (error < 0)
757                 goto error_cleanup_mc_io;
758
759         mc->root_mc_bus_dev = mc_bus_dev;
760         return 0;
761
762 error_cleanup_mc_io:
763         fsl_destroy_mc_io(mc_io);
764         return error;
765 }
766
767 /**
768  * fsl_mc_bus_remove - callback invoked when the root MC bus is being
769  * removed
770  */
771 static int fsl_mc_bus_remove(struct platform_device *pdev)
772 {
773         struct fsl_mc *mc = platform_get_drvdata(pdev);
774
775         if (WARN_ON(!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev)))
776                 return -EINVAL;
777
778         fsl_mc_device_remove(mc->root_mc_bus_dev);
779         dev_info(&pdev->dev, "Root MC bus device removed");
780         return 0;
781 }
782
783 static const struct of_device_id fsl_mc_bus_match_table[] = {
784         {.compatible = "fsl,qoriq-mc",},
785         {},
786 };
787
788 MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table);
789
790 static struct platform_driver fsl_mc_bus_driver = {
791         .driver = {
792                    .name = "fsl_mc_bus",
793                    .owner = THIS_MODULE,
794                    .pm = NULL,
795                    .of_match_table = fsl_mc_bus_match_table,
796                    },
797         .probe = fsl_mc_bus_probe,
798         .remove = fsl_mc_bus_remove,
799 };
800
801 static int __init fsl_mc_bus_driver_init(void)
802 {
803         int error;
804
805         mc_dev_cache = kmem_cache_create("fsl_mc_device",
806                                          sizeof(struct fsl_mc_device), 0, 0,
807                                          NULL);
808         if (!mc_dev_cache) {
809                 pr_err("Could not create fsl_mc_device cache\n");
810                 return -ENOMEM;
811         }
812
813         error = bus_register(&fsl_mc_bus_type);
814         if (error < 0) {
815                 pr_err("fsl-mc bus type registration failed: %d\n", error);
816                 goto error_cleanup_cache;
817         }
818
819         pr_info("fsl-mc bus type registered\n");
820
821         error = platform_driver_register(&fsl_mc_bus_driver);
822         if (error < 0) {
823                 pr_err("platform_driver_register() failed: %d\n", error);
824                 goto error_cleanup_bus;
825         }
826
827         error = dprc_driver_init();
828         if (error < 0)
829                 goto error_cleanup_driver;
830
831         error = fsl_mc_allocator_driver_init();
832         if (error < 0)
833                 goto error_cleanup_dprc_driver;
834
835         return 0;
836
837 error_cleanup_dprc_driver:
838         dprc_driver_exit();
839
840 error_cleanup_driver:
841         platform_driver_unregister(&fsl_mc_bus_driver);
842
843 error_cleanup_bus:
844         bus_unregister(&fsl_mc_bus_type);
845
846 error_cleanup_cache:
847         kmem_cache_destroy(mc_dev_cache);
848         return error;
849 }
850
851 postcore_initcall(fsl_mc_bus_driver_init);
852
853 static void __exit fsl_mc_bus_driver_exit(void)
854 {
855         if (WARN_ON(!mc_dev_cache))
856                 return;
857
858         fsl_mc_allocator_driver_exit();
859         dprc_driver_exit();
860         platform_driver_unregister(&fsl_mc_bus_driver);
861         bus_unregister(&fsl_mc_bus_type);
862         kmem_cache_destroy(mc_dev_cache);
863         pr_info("MC bus unregistered\n");
864 }
865
866 module_exit(fsl_mc_bus_driver_exit);
867
868 MODULE_AUTHOR("Freescale Semiconductor Inc.");
869 MODULE_DESCRIPTION("Freescale Management Complex (MC) bus driver");
870 MODULE_LICENSE("GPL");