]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/fsl-mc/bus/mc-allocator.c
Merge remote-tracking branch 'staging/staging-next'
[karo-tx-linux.git] / drivers / staging / fsl-mc / bus / mc-allocator.c
1 /*
2  * Freescale MC object device allocator driver
3  *
4  * Copyright (C) 2013 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 "../include/mc-private.h"
12 #include "../include/mc-sys.h"
13 #include <linux/module.h>
14 #include "../include/dpbp-cmd.h"
15 #include "../include/dpcon-cmd.h"
16 #include "dpmcp-cmd.h"
17 #include "dpmcp.h"
18 #include <linux/msi.h>
19
20 /**
21  * fsl_mc_resource_pool_add_device - add allocatable device to a resource
22  * pool of a given MC bus
23  *
24  * @mc_bus: pointer to the MC bus
25  * @pool_type: MC bus pool type
26  * @mc_dev: Pointer to allocatable MC object device
27  *
28  * It adds an allocatable MC object device to a container's resource pool of
29  * the given resource type
30  */
31 static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus
32                                                                 *mc_bus,
33                                                         enum fsl_mc_pool_type
34                                                                 pool_type,
35                                                         struct fsl_mc_device
36                                                                 *mc_dev)
37 {
38         struct fsl_mc_resource_pool *res_pool;
39         struct fsl_mc_resource *resource;
40         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
41         int error = -EINVAL;
42         bool mutex_locked = false;
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         mutex_locked = true;
59
60         if (WARN_ON(res_pool->max_count < 0))
61                 goto out;
62         if (WARN_ON(res_pool->free_count < 0 ||
63                     res_pool->free_count > res_pool->max_count))
64                 goto out;
65
66         resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource),
67                                 GFP_KERNEL);
68         if (!resource) {
69                 error = -ENOMEM;
70                 dev_err(&mc_bus_dev->dev,
71                         "Failed to allocate memory for fsl_mc_resource\n");
72                 goto out;
73         }
74
75         resource->type = pool_type;
76         resource->id = mc_dev->obj_desc.id;
77         resource->data = mc_dev;
78         resource->parent_pool = res_pool;
79         INIT_LIST_HEAD(&resource->node);
80         list_add_tail(&resource->node, &res_pool->free_list);
81         mc_dev->resource = resource;
82         res_pool->free_count++;
83         res_pool->max_count++;
84         error = 0;
85 out:
86         if (mutex_locked)
87                 mutex_unlock(&res_pool->mutex);
88
89         return error;
90 }
91
92 /**
93  * fsl_mc_resource_pool_remove_device - remove an allocatable device from a
94  * resource pool
95  *
96  * @mc_dev: Pointer to allocatable MC object device
97  *
98  * It permanently removes an allocatable MC object device from the resource
99  * pool, the device is currently in, as long as it is in the pool's free list.
100  */
101 static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device
102                                                                    *mc_dev)
103 {
104         struct fsl_mc_device *mc_bus_dev;
105         struct fsl_mc_bus *mc_bus;
106         struct fsl_mc_resource_pool *res_pool;
107         struct fsl_mc_resource *resource;
108         int error = -EINVAL;
109         bool mutex_locked = false;
110
111         if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
112                 goto out;
113
114         resource = mc_dev->resource;
115         if (WARN_ON(!resource || resource->data != mc_dev))
116                 goto out;
117
118         mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
119         mc_bus = to_fsl_mc_bus(mc_bus_dev);
120         res_pool = resource->parent_pool;
121         if (WARN_ON(res_pool != &mc_bus->resource_pools[resource->type]))
122                 goto out;
123
124         mutex_lock(&res_pool->mutex);
125         mutex_locked = true;
126
127         if (WARN_ON(res_pool->max_count <= 0))
128                 goto out;
129         if (WARN_ON(res_pool->free_count <= 0 ||
130                     res_pool->free_count > res_pool->max_count))
131                 goto out;
132
133         /*
134          * If the device is currently allocated, its resource is not
135          * in the free list and thus, the device cannot be removed.
136          */
137         if (list_empty(&resource->node)) {
138                 error = -EBUSY;
139                 dev_err(&mc_bus_dev->dev,
140                         "Device %s cannot be removed from resource pool\n",
141                         dev_name(&mc_dev->dev));
142                 goto out;
143         }
144
145         list_del(&resource->node);
146         INIT_LIST_HEAD(&resource->node);
147         res_pool->free_count--;
148         res_pool->max_count--;
149
150         devm_kfree(&mc_bus_dev->dev, resource);
151         mc_dev->resource = NULL;
152         error = 0;
153 out:
154         if (mutex_locked)
155                 mutex_unlock(&res_pool->mutex);
156
157         return error;
158 }
159
160 static const char *const fsl_mc_pool_type_strings[] = {
161         [FSL_MC_POOL_DPMCP] = "dpmcp",
162         [FSL_MC_POOL_DPBP] = "dpbp",
163         [FSL_MC_POOL_DPCON] = "dpcon",
164         [FSL_MC_POOL_IRQ] = "irq",
165 };
166
167 static int __must_check object_type_to_pool_type(const char *object_type,
168                                                  enum fsl_mc_pool_type
169                                                                 *pool_type)
170 {
171         unsigned int i;
172
173         for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) {
174                 if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) {
175                         *pool_type = i;
176                         return 0;
177                 }
178         }
179
180         return -EINVAL;
181 }
182
183 int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus,
184                                           enum fsl_mc_pool_type pool_type,
185                                           struct fsl_mc_resource **new_resource)
186 {
187         struct fsl_mc_resource_pool *res_pool;
188         struct fsl_mc_resource *resource;
189         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
190         int error = -EINVAL;
191         bool mutex_locked = false;
192
193         BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) !=
194                      FSL_MC_NUM_POOL_TYPES);
195
196         *new_resource = NULL;
197         if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES))
198                 goto error;
199
200         res_pool = &mc_bus->resource_pools[pool_type];
201         if (WARN_ON(res_pool->mc_bus != mc_bus))
202                 goto error;
203
204         mutex_lock(&res_pool->mutex);
205         mutex_locked = true;
206         resource = list_first_entry_or_null(&res_pool->free_list,
207                                             struct fsl_mc_resource, node);
208
209         if (!resource) {
210                 WARN_ON(res_pool->free_count != 0);
211                 error = -ENXIO;
212                 dev_err(&mc_bus_dev->dev,
213                         "No more resources of type %s left\n",
214                         fsl_mc_pool_type_strings[pool_type]);
215                 goto error;
216         }
217
218         if (WARN_ON(resource->type != pool_type))
219                 goto error;
220         if (WARN_ON(resource->parent_pool != res_pool))
221                 goto error;
222         if (WARN_ON(res_pool->free_count <= 0 ||
223                     res_pool->free_count > res_pool->max_count))
224                 goto error;
225
226         list_del(&resource->node);
227         INIT_LIST_HEAD(&resource->node);
228
229         res_pool->free_count--;
230         mutex_unlock(&res_pool->mutex);
231         *new_resource = resource;
232         return 0;
233 error:
234         if (mutex_locked)
235                 mutex_unlock(&res_pool->mutex);
236
237         return error;
238 }
239 EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate);
240
241 void fsl_mc_resource_free(struct fsl_mc_resource *resource)
242 {
243         struct fsl_mc_resource_pool *res_pool;
244         bool mutex_locked = false;
245
246         res_pool = resource->parent_pool;
247         if (WARN_ON(resource->type != res_pool->type))
248                 goto out;
249
250         mutex_lock(&res_pool->mutex);
251         mutex_locked = true;
252         if (WARN_ON(res_pool->free_count < 0 ||
253                     res_pool->free_count >= res_pool->max_count))
254                 goto out;
255
256         if (WARN_ON(!list_empty(&resource->node)))
257                 goto out;
258
259         list_add_tail(&resource->node, &res_pool->free_list);
260         res_pool->free_count++;
261 out:
262         if (mutex_locked)
263                 mutex_unlock(&res_pool->mutex);
264 }
265 EXPORT_SYMBOL_GPL(fsl_mc_resource_free);
266
267 /**
268  * fsl_mc_portal_allocate - Allocates an MC portal
269  *
270  * @mc_dev: MC device for which the MC portal is to be allocated
271  * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated
272  * MC portal.
273  * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object
274  * that wraps the allocated MC portal is to be returned
275  *
276  * This function allocates an MC portal from the device's parent DPRC,
277  * from the corresponding MC bus' pool of MC portals and wraps
278  * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the
279  * portal is allocated from its own MC bus.
280  */
281 int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev,
282                                         u16 mc_io_flags,
283                                         struct fsl_mc_io **new_mc_io)
284 {
285         struct fsl_mc_device *mc_bus_dev;
286         struct fsl_mc_bus *mc_bus;
287         phys_addr_t mc_portal_phys_addr;
288         size_t mc_portal_size;
289         struct fsl_mc_device *dpmcp_dev;
290         int error = -EINVAL;
291         struct fsl_mc_resource *resource = NULL;
292         struct fsl_mc_io *mc_io = NULL;
293
294         if (mc_dev->flags & FSL_MC_IS_DPRC) {
295                 mc_bus_dev = mc_dev;
296         } else {
297                 if (WARN_ON(mc_dev->dev.parent->bus != &fsl_mc_bus_type))
298                         return error;
299
300                 mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
301         }
302
303         mc_bus = to_fsl_mc_bus(mc_bus_dev);
304         *new_mc_io = NULL;
305         error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource);
306         if (error < 0)
307                 return error;
308
309         dpmcp_dev = resource->data;
310         if (WARN_ON(!dpmcp_dev))
311                 goto error_cleanup_resource;
312
313         if (WARN_ON(dpmcp_dev->obj_desc.region_count == 0))
314                 goto error_cleanup_resource;
315
316         mc_portal_phys_addr = dpmcp_dev->regions[0].start;
317         mc_portal_size = dpmcp_dev->regions[0].end -
318                          dpmcp_dev->regions[0].start + 1;
319
320         if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size))
321                 goto error_cleanup_resource;
322
323         error = fsl_create_mc_io(&mc_bus_dev->dev,
324                                  mc_portal_phys_addr,
325                                  mc_portal_size, dpmcp_dev,
326                                  mc_io_flags, &mc_io);
327         if (error < 0)
328                 goto error_cleanup_resource;
329
330         *new_mc_io = mc_io;
331         return 0;
332
333 error_cleanup_resource:
334         fsl_mc_resource_free(resource);
335         return error;
336 }
337 EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate);
338
339 /**
340  * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals
341  * of a given MC bus
342  *
343  * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free
344  */
345 void fsl_mc_portal_free(struct fsl_mc_io *mc_io)
346 {
347         struct fsl_mc_device *dpmcp_dev;
348         struct fsl_mc_resource *resource;
349
350         /*
351          * Every mc_io obtained by calling fsl_mc_portal_allocate() is supposed
352          * to have a DPMCP object associated with.
353          */
354         dpmcp_dev = mc_io->dpmcp_dev;
355         if (WARN_ON(!dpmcp_dev))
356                 return;
357
358         resource = dpmcp_dev->resource;
359         if (WARN_ON(!resource || resource->type != FSL_MC_POOL_DPMCP))
360                 return;
361
362         if (WARN_ON(resource->data != dpmcp_dev))
363                 return;
364
365         fsl_destroy_mc_io(mc_io);
366         fsl_mc_resource_free(resource);
367 }
368 EXPORT_SYMBOL_GPL(fsl_mc_portal_free);
369
370 /**
371  * fsl_mc_portal_reset - Resets the dpmcp object for a given fsl_mc_io object
372  *
373  * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free
374  */
375 int fsl_mc_portal_reset(struct fsl_mc_io *mc_io)
376 {
377         int error;
378         struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
379
380         if (WARN_ON(!dpmcp_dev))
381                 return -EINVAL;
382
383         error = dpmcp_reset(mc_io, 0, dpmcp_dev->mc_handle);
384         if (error < 0) {
385                 dev_err(&dpmcp_dev->dev, "dpmcp_reset() failed: %d\n", error);
386                 return error;
387         }
388
389         return 0;
390 }
391 EXPORT_SYMBOL_GPL(fsl_mc_portal_reset);
392
393 /**
394  * fsl_mc_object_allocate - Allocates a MC object device of the given
395  * pool type from a given MC bus
396  *
397  * @mc_dev: MC device for which the MC object device is to be allocated
398  * @pool_type: MC bus resource pool type
399  * @new_mc_dev: Pointer to area where the pointer to the allocated
400  * MC object device is to be returned
401  *
402  * This function allocates a MC object device from the device's parent DPRC,
403  * from the corresponding MC bus' pool of allocatable MC object devices of
404  * the given resource type. mc_dev cannot be a DPRC itself.
405  *
406  * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC
407  * portals are allocated using fsl_mc_portal_allocate(), instead of
408  * this function.
409  */
410 int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev,
411                                         enum fsl_mc_pool_type pool_type,
412                                         struct fsl_mc_device **new_mc_adev)
413 {
414         struct fsl_mc_device *mc_bus_dev;
415         struct fsl_mc_bus *mc_bus;
416         struct fsl_mc_device *mc_adev;
417         int error = -EINVAL;
418         struct fsl_mc_resource *resource = NULL;
419
420         *new_mc_adev = NULL;
421         if (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC))
422                 goto error;
423
424         if (WARN_ON(mc_dev->dev.parent->bus != &fsl_mc_bus_type))
425                 goto error;
426
427         if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP))
428                 goto error;
429
430         mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
431         mc_bus = to_fsl_mc_bus(mc_bus_dev);
432         error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource);
433         if (error < 0)
434                 goto error;
435
436         mc_adev = resource->data;
437         if (WARN_ON(!mc_adev))
438                 goto error;
439
440         *new_mc_adev = mc_adev;
441         return 0;
442 error:
443         if (resource)
444                 fsl_mc_resource_free(resource);
445
446         return error;
447 }
448 EXPORT_SYMBOL_GPL(fsl_mc_object_allocate);
449
450 /**
451  * fsl_mc_object_free - Returns an allocatable MC object device to the
452  * corresponding resource pool of a given MC bus.
453  *
454  * @mc_adev: Pointer to the MC object device
455  */
456 void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
457 {
458         struct fsl_mc_resource *resource;
459
460         resource = mc_adev->resource;
461         if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP))
462                 return;
463         if (WARN_ON(resource->data != mc_adev))
464                 return;
465
466         fsl_mc_resource_free(resource);
467 }
468 EXPORT_SYMBOL_GPL(fsl_mc_object_free);
469
470 /*
471  * Initialize the interrupt pool associated with a MC bus.
472  * It allocates a block of IRQs from the GIC-ITS
473  */
474 int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
475                              unsigned int irq_count)
476 {
477         unsigned int i;
478         struct msi_desc *msi_desc;
479         struct fsl_mc_device_irq *irq_resources;
480         struct fsl_mc_device_irq *mc_dev_irq;
481         int error;
482         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
483         struct fsl_mc_resource_pool *res_pool =
484                         &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
485
486         if (WARN_ON(irq_count == 0 ||
487                     irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS))
488                 return -EINVAL;
489
490         error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count);
491         if (error < 0)
492                 return error;
493
494         irq_resources = devm_kzalloc(&mc_bus_dev->dev,
495                                      sizeof(*irq_resources) * irq_count,
496                                      GFP_KERNEL);
497         if (!irq_resources) {
498                 error = -ENOMEM;
499                 goto cleanup_msi_irqs;
500         }
501
502         for (i = 0; i < irq_count; i++) {
503                 mc_dev_irq = &irq_resources[i];
504
505                 /*
506                  * NOTE: This mc_dev_irq's MSI addr/value pair will be set
507                  * by the fsl_mc_msi_write_msg() callback
508                  */
509                 mc_dev_irq->resource.type = res_pool->type;
510                 mc_dev_irq->resource.data = mc_dev_irq;
511                 mc_dev_irq->resource.parent_pool = res_pool;
512                 INIT_LIST_HEAD(&mc_dev_irq->resource.node);
513                 list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list);
514         }
515
516         for_each_msi_entry(msi_desc, &mc_bus_dev->dev) {
517                 mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index];
518                 mc_dev_irq->msi_desc = msi_desc;
519                 mc_dev_irq->resource.id = msi_desc->irq;
520         }
521
522         res_pool->max_count = irq_count;
523         res_pool->free_count = irq_count;
524         mc_bus->irq_resources = irq_resources;
525         return 0;
526
527 cleanup_msi_irqs:
528         fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
529         return error;
530 }
531 EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
532
533 /**
534  * Teardown the interrupt pool associated with an MC bus.
535  * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
536  */
537 void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus)
538 {
539         struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
540         struct fsl_mc_resource_pool *res_pool =
541                         &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
542
543         if (WARN_ON(!mc_bus->irq_resources))
544                 return;
545
546         if (WARN_ON(res_pool->max_count == 0))
547                 return;
548
549         if (WARN_ON(res_pool->free_count != res_pool->max_count))
550                 return;
551
552         INIT_LIST_HEAD(&res_pool->free_list);
553         res_pool->max_count = 0;
554         res_pool->free_count = 0;
555         mc_bus->irq_resources = NULL;
556         fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
557 }
558 EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
559
560 /**
561  * It allocates the IRQs required by a given MC object device. The
562  * IRQs are allocated from the interrupt pool associated with the
563  * MC bus that contains the device, if the device is not a DPRC device.
564  * Otherwise, the IRQs are allocated from the interrupt pool associated
565  * with the MC bus that represents the DPRC device itself.
566  */
567 int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
568 {
569         int i;
570         int irq_count;
571         int res_allocated_count = 0;
572         int error = -EINVAL;
573         struct fsl_mc_device_irq **irqs = NULL;
574         struct fsl_mc_bus *mc_bus;
575         struct fsl_mc_resource_pool *res_pool;
576
577         if (WARN_ON(mc_dev->irqs))
578                 return -EINVAL;
579
580         irq_count = mc_dev->obj_desc.irq_count;
581         if (WARN_ON(irq_count == 0))
582                 return -EINVAL;
583
584         if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
585                 mc_bus = to_fsl_mc_bus(mc_dev);
586         else
587                 mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
588
589         if (WARN_ON(!mc_bus->irq_resources))
590                 return -EINVAL;
591
592         res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
593         if (res_pool->free_count < irq_count) {
594                 dev_err(&mc_dev->dev,
595                         "Not able to allocate %u irqs for device\n", irq_count);
596                 return -ENOSPC;
597         }
598
599         irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]),
600                             GFP_KERNEL);
601         if (!irqs)
602                 return -ENOMEM;
603
604         for (i = 0; i < irq_count; i++) {
605                 struct fsl_mc_resource *resource;
606
607                 error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ,
608                                                  &resource);
609                 if (error < 0)
610                         goto error_resource_alloc;
611
612                 irqs[i] = to_fsl_mc_irq(resource);
613                 res_allocated_count++;
614
615                 WARN_ON(irqs[i]->mc_dev);
616                 irqs[i]->mc_dev = mc_dev;
617                 irqs[i]->dev_irq_index = i;
618         }
619
620         mc_dev->irqs = irqs;
621         return 0;
622
623 error_resource_alloc:
624         for (i = 0; i < res_allocated_count; i++) {
625                 irqs[i]->mc_dev = NULL;
626                 fsl_mc_resource_free(&irqs[i]->resource);
627         }
628
629         return error;
630 }
631 EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs);
632
633 /*
634  * It frees the IRQs that were allocated for a MC object device, by
635  * returning them to the corresponding interrupt pool.
636  */
637 void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
638 {
639         int i;
640         int irq_count;
641         struct fsl_mc_bus *mc_bus;
642         struct fsl_mc_device_irq **irqs = mc_dev->irqs;
643
644         if (WARN_ON(!irqs))
645                 return;
646
647         irq_count = mc_dev->obj_desc.irq_count;
648
649         if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
650                 mc_bus = to_fsl_mc_bus(mc_dev);
651         else
652                 mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
653
654         if (WARN_ON(!mc_bus->irq_resources))
655                 return;
656
657         for (i = 0; i < irq_count; i++) {
658                 WARN_ON(!irqs[i]->mc_dev);
659                 irqs[i]->mc_dev = NULL;
660                 fsl_mc_resource_free(&irqs[i]->resource);
661         }
662
663         mc_dev->irqs = NULL;
664 }
665 EXPORT_SYMBOL_GPL(fsl_mc_free_irqs);
666
667 /**
668  * fsl_mc_allocator_probe - callback invoked when an allocatable device is
669  * being added to the system
670  */
671 static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
672 {
673         enum fsl_mc_pool_type pool_type;
674         struct fsl_mc_device *mc_bus_dev;
675         struct fsl_mc_bus *mc_bus;
676         int error;
677
678         if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
679                 return -EINVAL;
680
681         mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
682         if (WARN_ON(mc_bus_dev->dev.bus != &fsl_mc_bus_type))
683                 return -EINVAL;
684
685         mc_bus = to_fsl_mc_bus(mc_bus_dev);
686         error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type);
687         if (error < 0)
688                 return error;
689
690         error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev);
691         if (error < 0)
692                 return error;
693
694         dev_dbg(&mc_dev->dev,
695                 "Allocatable MC object device bound to fsl_mc_allocator driver");
696         return 0;
697 }
698
699 /**
700  * fsl_mc_allocator_remove - callback invoked when an allocatable device is
701  * being removed from the system
702  */
703 static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
704 {
705         int error;
706
707         if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
708                 return -EINVAL;
709
710         if (mc_dev->resource) {
711                 error = fsl_mc_resource_pool_remove_device(mc_dev);
712                 if (error < 0)
713                         return error;
714         }
715
716         dev_dbg(&mc_dev->dev,
717                 "Allocatable MC object device unbound from fsl_mc_allocator driver");
718         return 0;
719 }
720
721 static const struct fsl_mc_device_match_id match_id_table[] = {
722         {
723          .vendor = FSL_MC_VENDOR_FREESCALE,
724          .obj_type = "dpbp",
725          .ver_major = DPBP_VER_MAJOR,
726          .ver_minor = DPBP_VER_MINOR
727         },
728         {
729          .vendor = FSL_MC_VENDOR_FREESCALE,
730          .obj_type = "dpmcp",
731          .ver_major = DPMCP_VER_MAJOR,
732          .ver_minor = DPMCP_VER_MINOR
733         },
734         {
735          .vendor = FSL_MC_VENDOR_FREESCALE,
736          .obj_type = "dpcon",
737          .ver_major = DPCON_VER_MAJOR,
738          .ver_minor = DPCON_VER_MINOR
739         },
740         {.vendor = 0x0},
741 };
742
743 static struct fsl_mc_driver fsl_mc_allocator_driver = {
744         .driver = {
745                    .name = "fsl_mc_allocator",
746                    .owner = THIS_MODULE,
747                    .pm = NULL,
748                    },
749         .match_id_table = match_id_table,
750         .probe = fsl_mc_allocator_probe,
751         .remove = fsl_mc_allocator_remove,
752 };
753
754 int __init fsl_mc_allocator_driver_init(void)
755 {
756         return fsl_mc_driver_register(&fsl_mc_allocator_driver);
757 }
758
759 void __exit fsl_mc_allocator_driver_exit(void)
760 {
761         fsl_mc_driver_unregister(&fsl_mc_allocator_driver);
762 }