Merge remote-tracking branches 'asoc/topic/simple', 'asoc/topic/spear', 'asoc/topic...
[sfrench/cifs-2.6.git] / drivers / staging / fsl-mc / bus / fsl-mc-allocator.c
1 /*
2  * fsl-mc object allocator driver
3  *
4  * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2. This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10
11 #include <linux/module.h>
12 #include <linux/msi.h>
13 #include "../include/mc.h"
14
15 #include "fsl-mc-private.h"
16
17 static bool __must_check fsl_mc_is_allocatable(const char *obj_type)
18 {
19         return strcmp(obj_type, "dpbp") == 0 ||
20                strcmp(obj_type, "dpmcp") == 0 ||
21                strcmp(obj_type, "dpcon") == 0;
22 }
23
24 /**
25  * fsl_mc_resource_pool_add_device - add allocatable object to a resource
26  * pool of a given fsl-mc bus
27  *
28  * @mc_bus: pointer to the fsl-mc bus
29  * @pool_type: pool type
30  * @mc_dev: pointer to allocatable fsl-mc device
31  */
32 static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus
33                                                                 *mc_bus,
34                                                         enum fsl_mc_pool_type
35                                                                 pool_type,
36                                                         struct fsl_mc_device
37                                                                 *mc_dev)
38 {
39         struct fsl_mc_resource_pool *res_pool;
40         struct fsl_mc_resource *resource;
41         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
42         int error = -EINVAL;
43
44         if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES))
45                 goto out;
46         if (WARN_ON(!fsl_mc_is_allocatable(mc_dev->obj_desc.type)))
47                 goto out;
48         if (WARN_ON(mc_dev->resource))
49                 goto out;
50
51         res_pool = &mc_bus->resource_pools[pool_type];
52         if (WARN_ON(res_pool->type != pool_type))
53                 goto out;
54         if (WARN_ON(res_pool->mc_bus != mc_bus))
55                 goto out;
56
57         mutex_lock(&res_pool->mutex);
58
59         if (WARN_ON(res_pool->max_count < 0))
60                 goto out_unlock;
61         if (WARN_ON(res_pool->free_count < 0 ||
62                     res_pool->free_count > res_pool->max_count))
63                 goto out_unlock;
64
65         resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource),
66                                 GFP_KERNEL);
67         if (!resource) {
68                 error = -ENOMEM;
69                 dev_err(&mc_bus_dev->dev,
70                         "Failed to allocate memory for fsl_mc_resource\n");
71                 goto out_unlock;
72         }
73
74         resource->type = pool_type;
75         resource->id = mc_dev->obj_desc.id;
76         resource->data = mc_dev;
77         resource->parent_pool = res_pool;
78         INIT_LIST_HEAD(&resource->node);
79         list_add_tail(&resource->node, &res_pool->free_list);
80         mc_dev->resource = resource;
81         res_pool->free_count++;
82         res_pool->max_count++;
83         error = 0;
84 out_unlock:
85         mutex_unlock(&res_pool->mutex);
86 out:
87         return error;
88 }
89
90 /**
91  * fsl_mc_resource_pool_remove_device - remove an allocatable device from a
92  * resource pool
93  *
94  * @mc_dev: pointer to allocatable fsl-mc device
95  *
96  * It permanently removes an allocatable fsl-mc device from the resource
97  * pool. It's an error if the device is in use.
98  */
99 static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device
100                                                                    *mc_dev)
101 {
102         struct fsl_mc_device *mc_bus_dev;
103         struct fsl_mc_bus *mc_bus;
104         struct fsl_mc_resource_pool *res_pool;
105         struct fsl_mc_resource *resource;
106         int error = -EINVAL;
107
108         if (WARN_ON(!fsl_mc_is_allocatable(mc_dev->obj_desc.type)))
109                 goto out;
110
111         resource = mc_dev->resource;
112         if (WARN_ON(!resource || resource->data != mc_dev))
113                 goto out;
114
115         mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
116         mc_bus = to_fsl_mc_bus(mc_bus_dev);
117         res_pool = resource->parent_pool;
118         if (WARN_ON(res_pool != &mc_bus->resource_pools[resource->type]))
119                 goto out;
120
121         mutex_lock(&res_pool->mutex);
122
123         if (WARN_ON(res_pool->max_count <= 0))
124                 goto out_unlock;
125         if (WARN_ON(res_pool->free_count <= 0 ||
126                     res_pool->free_count > res_pool->max_count))
127                 goto out_unlock;
128
129         /*
130          * If the device is currently allocated, its resource is not
131          * in the free list and thus, the device cannot be removed.
132          */
133         if (list_empty(&resource->node)) {
134                 error = -EBUSY;
135                 dev_err(&mc_bus_dev->dev,
136                         "Device %s cannot be removed from resource pool\n",
137                         dev_name(&mc_dev->dev));
138                 goto out_unlock;
139         }
140
141         list_del_init(&resource->node);
142         res_pool->free_count--;
143         res_pool->max_count--;
144
145         devm_kfree(&mc_bus_dev->dev, resource);
146         mc_dev->resource = NULL;
147         error = 0;
148 out_unlock:
149         mutex_unlock(&res_pool->mutex);
150 out:
151         return error;
152 }
153
154 static const char *const fsl_mc_pool_type_strings[] = {
155         [FSL_MC_POOL_DPMCP] = "dpmcp",
156         [FSL_MC_POOL_DPBP] = "dpbp",
157         [FSL_MC_POOL_DPCON] = "dpcon",
158         [FSL_MC_POOL_IRQ] = "irq",
159 };
160
161 static int __must_check object_type_to_pool_type(const char *object_type,
162                                                  enum fsl_mc_pool_type
163                                                                 *pool_type)
164 {
165         unsigned int i;
166
167         for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) {
168                 if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) {
169                         *pool_type = i;
170                         return 0;
171                 }
172         }
173
174         return -EINVAL;
175 }
176
177 int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus,
178                                           enum fsl_mc_pool_type pool_type,
179                                           struct fsl_mc_resource **new_resource)
180 {
181         struct fsl_mc_resource_pool *res_pool;
182         struct fsl_mc_resource *resource;
183         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
184         int error = -EINVAL;
185
186         BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) !=
187                      FSL_MC_NUM_POOL_TYPES);
188
189         *new_resource = NULL;
190         if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES))
191                 goto out;
192
193         res_pool = &mc_bus->resource_pools[pool_type];
194         if (WARN_ON(res_pool->mc_bus != mc_bus))
195                 goto out;
196
197         mutex_lock(&res_pool->mutex);
198         resource = list_first_entry_or_null(&res_pool->free_list,
199                                             struct fsl_mc_resource, node);
200
201         if (!resource) {
202                 WARN_ON(res_pool->free_count != 0);
203                 error = -ENXIO;
204                 dev_err(&mc_bus_dev->dev,
205                         "No more resources of type %s left\n",
206                         fsl_mc_pool_type_strings[pool_type]);
207                 goto out_unlock;
208         }
209
210         if (WARN_ON(resource->type != pool_type))
211                 goto out_unlock;
212         if (WARN_ON(resource->parent_pool != res_pool))
213                 goto out_unlock;
214         if (WARN_ON(res_pool->free_count <= 0 ||
215                     res_pool->free_count > res_pool->max_count))
216                 goto out_unlock;
217
218         list_del_init(&resource->node);
219
220         res_pool->free_count--;
221         error = 0;
222 out_unlock:
223         mutex_unlock(&res_pool->mutex);
224         *new_resource = resource;
225 out:
226         return error;
227 }
228 EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate);
229
230 void fsl_mc_resource_free(struct fsl_mc_resource *resource)
231 {
232         struct fsl_mc_resource_pool *res_pool;
233
234         res_pool = resource->parent_pool;
235         if (WARN_ON(resource->type != res_pool->type))
236                 return;
237
238         mutex_lock(&res_pool->mutex);
239         if (WARN_ON(res_pool->free_count < 0 ||
240                     res_pool->free_count >= res_pool->max_count))
241                 goto out_unlock;
242
243         if (WARN_ON(!list_empty(&resource->node)))
244                 goto out_unlock;
245
246         list_add_tail(&resource->node, &res_pool->free_list);
247         res_pool->free_count++;
248 out_unlock:
249         mutex_unlock(&res_pool->mutex);
250 }
251 EXPORT_SYMBOL_GPL(fsl_mc_resource_free);
252
253 /**
254  * fsl_mc_object_allocate - Allocates an fsl-mc object of the given
255  * pool type from a given fsl-mc bus instance
256  *
257  * @mc_dev: fsl-mc device which is used in conjunction with the
258  * allocated object
259  * @pool_type: pool type
260  * @new_mc_dev: pointer to area where the pointer to the allocated device
261  * is to be returned
262  *
263  * Allocatable objects are always used in conjunction with some functional
264  * device.  This function allocates an object of the specified type from
265  * the DPRC containing the functional device.
266  *
267  * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC
268  * portals are allocated using fsl_mc_portal_allocate(), instead of
269  * this function.
270  */
271 int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev,
272                                         enum fsl_mc_pool_type pool_type,
273                                         struct fsl_mc_device **new_mc_adev)
274 {
275         struct fsl_mc_device *mc_bus_dev;
276         struct fsl_mc_bus *mc_bus;
277         struct fsl_mc_device *mc_adev;
278         int error = -EINVAL;
279         struct fsl_mc_resource *resource = NULL;
280
281         *new_mc_adev = NULL;
282         if (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC))
283                 goto error;
284
285         if (WARN_ON(!dev_is_fsl_mc(mc_dev->dev.parent)))
286                 goto error;
287
288         if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP))
289                 goto error;
290
291         mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
292         mc_bus = to_fsl_mc_bus(mc_bus_dev);
293         error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource);
294         if (error < 0)
295                 goto error;
296
297         mc_adev = resource->data;
298         if (WARN_ON(!mc_adev))
299                 goto error;
300
301         *new_mc_adev = mc_adev;
302         return 0;
303 error:
304         if (resource)
305                 fsl_mc_resource_free(resource);
306
307         return error;
308 }
309 EXPORT_SYMBOL_GPL(fsl_mc_object_allocate);
310
311 /**
312  * fsl_mc_object_free - Returns an fsl-mc object to the resource
313  * pool where it came from.
314  * @mc_adev: Pointer to the fsl-mc device
315  */
316 void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
317 {
318         struct fsl_mc_resource *resource;
319
320         resource = mc_adev->resource;
321         if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP))
322                 return;
323         if (WARN_ON(resource->data != mc_adev))
324                 return;
325
326         fsl_mc_resource_free(resource);
327 }
328 EXPORT_SYMBOL_GPL(fsl_mc_object_free);
329
330 /*
331  * A DPRC and the devices in the DPRC all share the same GIC-ITS device
332  * ID.  A block of IRQs is pre-allocated and maintained in a pool
333  * from which devices can allocate them when needed.
334  */
335
336 /*
337  * Initialize the interrupt pool associated with an fsl-mc bus.
338  * It allocates a block of IRQs from the GIC-ITS.
339  */
340 int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
341                              unsigned int irq_count)
342 {
343         unsigned int i;
344         struct msi_desc *msi_desc;
345         struct fsl_mc_device_irq *irq_resources;
346         struct fsl_mc_device_irq *mc_dev_irq;
347         int error;
348         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
349         struct fsl_mc_resource_pool *res_pool =
350                         &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
351
352         if (WARN_ON(irq_count == 0 ||
353                     irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS))
354                 return -EINVAL;
355
356         error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count);
357         if (error < 0)
358                 return error;
359
360         irq_resources = devm_kzalloc(&mc_bus_dev->dev,
361                                      sizeof(*irq_resources) * irq_count,
362                                      GFP_KERNEL);
363         if (!irq_resources) {
364                 error = -ENOMEM;
365                 goto cleanup_msi_irqs;
366         }
367
368         for (i = 0; i < irq_count; i++) {
369                 mc_dev_irq = &irq_resources[i];
370
371                 /*
372                  * NOTE: This mc_dev_irq's MSI addr/value pair will be set
373                  * by the fsl_mc_msi_write_msg() callback
374                  */
375                 mc_dev_irq->resource.type = res_pool->type;
376                 mc_dev_irq->resource.data = mc_dev_irq;
377                 mc_dev_irq->resource.parent_pool = res_pool;
378                 INIT_LIST_HEAD(&mc_dev_irq->resource.node);
379                 list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list);
380         }
381
382         for_each_msi_entry(msi_desc, &mc_bus_dev->dev) {
383                 mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index];
384                 mc_dev_irq->msi_desc = msi_desc;
385                 mc_dev_irq->resource.id = msi_desc->irq;
386         }
387
388         res_pool->max_count = irq_count;
389         res_pool->free_count = irq_count;
390         mc_bus->irq_resources = irq_resources;
391         return 0;
392
393 cleanup_msi_irqs:
394         fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
395         return error;
396 }
397 EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
398
399 /**
400  * Teardown the interrupt pool associated with an fsl-mc bus.
401  * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
402  */
403 void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus)
404 {
405         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
406         struct fsl_mc_resource_pool *res_pool =
407                         &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
408
409         if (WARN_ON(!mc_bus->irq_resources))
410                 return;
411
412         if (WARN_ON(res_pool->max_count == 0))
413                 return;
414
415         if (WARN_ON(res_pool->free_count != res_pool->max_count))
416                 return;
417
418         INIT_LIST_HEAD(&res_pool->free_list);
419         res_pool->max_count = 0;
420         res_pool->free_count = 0;
421         mc_bus->irq_resources = NULL;
422         fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
423 }
424 EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
425
426 /**
427  * Allocate the IRQs required by a given fsl-mc device.
428  */
429 int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
430 {
431         int i;
432         int irq_count;
433         int res_allocated_count = 0;
434         int error = -EINVAL;
435         struct fsl_mc_device_irq **irqs = NULL;
436         struct fsl_mc_bus *mc_bus;
437         struct fsl_mc_resource_pool *res_pool;
438
439         if (WARN_ON(mc_dev->irqs))
440                 return -EINVAL;
441
442         irq_count = mc_dev->obj_desc.irq_count;
443         if (WARN_ON(irq_count == 0))
444                 return -EINVAL;
445
446         if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
447                 mc_bus = to_fsl_mc_bus(mc_dev);
448         else
449                 mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
450
451         if (WARN_ON(!mc_bus->irq_resources))
452                 return -EINVAL;
453
454         res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
455         if (res_pool->free_count < irq_count) {
456                 dev_err(&mc_dev->dev,
457                         "Not able to allocate %u irqs for device\n", irq_count);
458                 return -ENOSPC;
459         }
460
461         irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]),
462                             GFP_KERNEL);
463         if (!irqs)
464                 return -ENOMEM;
465
466         for (i = 0; i < irq_count; i++) {
467                 struct fsl_mc_resource *resource;
468
469                 error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ,
470                                                  &resource);
471                 if (error < 0)
472                         goto error_resource_alloc;
473
474                 irqs[i] = to_fsl_mc_irq(resource);
475                 res_allocated_count++;
476
477                 WARN_ON(irqs[i]->mc_dev);
478                 irqs[i]->mc_dev = mc_dev;
479                 irqs[i]->dev_irq_index = i;
480         }
481
482         mc_dev->irqs = irqs;
483         return 0;
484
485 error_resource_alloc:
486         for (i = 0; i < res_allocated_count; i++) {
487                 irqs[i]->mc_dev = NULL;
488                 fsl_mc_resource_free(&irqs[i]->resource);
489         }
490
491         return error;
492 }
493 EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs);
494
495 /*
496  * Frees the IRQs that were allocated for an fsl-mc device.
497  */
498 void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
499 {
500         int i;
501         int irq_count;
502         struct fsl_mc_bus *mc_bus;
503         struct fsl_mc_device_irq **irqs = mc_dev->irqs;
504
505         if (WARN_ON(!irqs))
506                 return;
507
508         irq_count = mc_dev->obj_desc.irq_count;
509
510         if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
511                 mc_bus = to_fsl_mc_bus(mc_dev);
512         else
513                 mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
514
515         if (WARN_ON(!mc_bus->irq_resources))
516                 return;
517
518         for (i = 0; i < irq_count; i++) {
519                 WARN_ON(!irqs[i]->mc_dev);
520                 irqs[i]->mc_dev = NULL;
521                 fsl_mc_resource_free(&irqs[i]->resource);
522         }
523
524         mc_dev->irqs = NULL;
525 }
526 EXPORT_SYMBOL_GPL(fsl_mc_free_irqs);
527
528 void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
529 {
530         int pool_type;
531         struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
532
533         for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) {
534                 struct fsl_mc_resource_pool *res_pool =
535                     &mc_bus->resource_pools[pool_type];
536
537                 res_pool->type = pool_type;
538                 res_pool->max_count = 0;
539                 res_pool->free_count = 0;
540                 res_pool->mc_bus = mc_bus;
541                 INIT_LIST_HEAD(&res_pool->free_list);
542                 mutex_init(&res_pool->mutex);
543         }
544 }
545
546 static void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev,
547                                          enum fsl_mc_pool_type pool_type)
548 {
549         struct fsl_mc_resource *resource;
550         struct fsl_mc_resource *next;
551         struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
552         struct fsl_mc_resource_pool *res_pool =
553                                         &mc_bus->resource_pools[pool_type];
554         int free_count = 0;
555
556         WARN_ON(res_pool->type != pool_type);
557         WARN_ON(res_pool->free_count != res_pool->max_count);
558
559         list_for_each_entry_safe(resource, next, &res_pool->free_list, node) {
560                 free_count++;
561                 WARN_ON(resource->type != res_pool->type);
562                 WARN_ON(resource->parent_pool != res_pool);
563                 devm_kfree(&mc_bus_dev->dev, resource);
564         }
565
566         WARN_ON(free_count != res_pool->free_count);
567 }
568
569 void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
570 {
571         int pool_type;
572
573         for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++)
574                 fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type);
575 }
576
577 /**
578  * fsl_mc_allocator_probe - callback invoked when an allocatable device is
579  * being added to the system
580  */
581 static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
582 {
583         enum fsl_mc_pool_type pool_type;
584         struct fsl_mc_device *mc_bus_dev;
585         struct fsl_mc_bus *mc_bus;
586         int error;
587
588         if (WARN_ON(!fsl_mc_is_allocatable(mc_dev->obj_desc.type)))
589                 return -EINVAL;
590
591         mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
592         if (WARN_ON(!dev_is_fsl_mc(&mc_bus_dev->dev)))
593                 return -EINVAL;
594
595         mc_bus = to_fsl_mc_bus(mc_bus_dev);
596         error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type);
597         if (error < 0)
598                 return error;
599
600         error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev);
601         if (error < 0)
602                 return error;
603
604         dev_dbg(&mc_dev->dev,
605                 "Allocatable fsl-mc device bound to fsl_mc_allocator driver");
606         return 0;
607 }
608
609 /**
610  * fsl_mc_allocator_remove - callback invoked when an allocatable device is
611  * being removed from the system
612  */
613 static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
614 {
615         int error;
616
617         if (WARN_ON(!fsl_mc_is_allocatable(mc_dev->obj_desc.type)))
618                 return -EINVAL;
619
620         if (mc_dev->resource) {
621                 error = fsl_mc_resource_pool_remove_device(mc_dev);
622                 if (error < 0)
623                         return error;
624         }
625
626         dev_dbg(&mc_dev->dev,
627                 "Allocatable fsl-mc device unbound from fsl_mc_allocator driver");
628         return 0;
629 }
630
631 static const struct fsl_mc_device_id match_id_table[] = {
632         {
633          .vendor = FSL_MC_VENDOR_FREESCALE,
634          .obj_type = "dpbp",
635         },
636         {
637          .vendor = FSL_MC_VENDOR_FREESCALE,
638          .obj_type = "dpmcp",
639         },
640         {
641          .vendor = FSL_MC_VENDOR_FREESCALE,
642          .obj_type = "dpcon",
643         },
644         {.vendor = 0x0},
645 };
646
647 static struct fsl_mc_driver fsl_mc_allocator_driver = {
648         .driver = {
649                    .name = "fsl_mc_allocator",
650                    .pm = NULL,
651                    },
652         .match_id_table = match_id_table,
653         .probe = fsl_mc_allocator_probe,
654         .remove = fsl_mc_allocator_remove,
655 };
656
657 int __init fsl_mc_allocator_driver_init(void)
658 {
659         return fsl_mc_driver_register(&fsl_mc_allocator_driver);
660 }
661
662 void fsl_mc_allocator_driver_exit(void)
663 {
664         fsl_mc_driver_unregister(&fsl_mc_allocator_driver);
665 }