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