Merge remote-tracking branch 'staging/staging-next'
[deliverable/linux.git] / drivers / staging / fsl-mc / bus / fsl-mc-allocator.c
CommitLineData
197f4d6a
GR
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
d4e75132
SY
11#include <linux/module.h>
12#include <linux/msi.h>
c37ebf8c 13#include "../include/mc-bus.h"
197f4d6a 14#include "../include/mc-sys.h"
197f4d6a
GR
15#include "../include/dpbp-cmd.h"
16#include "../include/dpcon-cmd.h"
d4e75132 17
243444fb 18#include "fsl-mc-private.h"
197f4d6a 19
e267dddd
SY
20#define FSL_MC_IS_ALLOCATABLE(_obj_type) \
21 (strcmp(_obj_type, "dpbp") == 0 || \
22 strcmp(_obj_type, "dpmcp") == 0 || \
23 strcmp(_obj_type, "dpcon") == 0)
24
197f4d6a
GR
25/**
26 * fsl_mc_resource_pool_add_device - add allocatable device to a resource
27 * pool of a given MC bus
28 *
29 * @mc_bus: pointer to the MC bus
30 * @pool_type: MC bus pool type
31 * @mc_dev: Pointer to allocatable MC object device
32 *
33 * It adds an allocatable MC object device to a container's resource pool of
34 * the given resource type
35 */
36static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus
37 *mc_bus,
38 enum fsl_mc_pool_type
39 pool_type,
40 struct fsl_mc_device
41 *mc_dev)
42{
43 struct fsl_mc_resource_pool *res_pool;
44 struct fsl_mc_resource *resource;
45 struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
46 int error = -EINVAL;
197f4d6a
GR
47
48 if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES))
49 goto out;
50 if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
51 goto out;
52 if (WARN_ON(mc_dev->resource))
53 goto out;
54
55 res_pool = &mc_bus->resource_pools[pool_type];
56 if (WARN_ON(res_pool->type != pool_type))
57 goto out;
58 if (WARN_ON(res_pool->mc_bus != mc_bus))
59 goto out;
60
61 mutex_lock(&res_pool->mutex);
197f4d6a
GR
62
63 if (WARN_ON(res_pool->max_count < 0))
6ffdc7b9 64 goto out_unlock;
197f4d6a
GR
65 if (WARN_ON(res_pool->free_count < 0 ||
66 res_pool->free_count > res_pool->max_count))
6ffdc7b9 67 goto out_unlock;
197f4d6a
GR
68
69 resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource),
70 GFP_KERNEL);
71 if (!resource) {
72 error = -ENOMEM;
73 dev_err(&mc_bus_dev->dev,
74 "Failed to allocate memory for fsl_mc_resource\n");
6ffdc7b9 75 goto out_unlock;
197f4d6a
GR
76 }
77
78 resource->type = pool_type;
79 resource->id = mc_dev->obj_desc.id;
80 resource->data = mc_dev;
81 resource->parent_pool = res_pool;
82 INIT_LIST_HEAD(&resource->node);
83 list_add_tail(&resource->node, &res_pool->free_list);
84 mc_dev->resource = resource;
85 res_pool->free_count++;
86 res_pool->max_count++;
87 error = 0;
6ffdc7b9
CA
88out_unlock:
89 mutex_unlock(&res_pool->mutex);
197f4d6a 90out:
197f4d6a
GR
91 return error;
92}
93
94/**
95 * fsl_mc_resource_pool_remove_device - remove an allocatable device from a
96 * resource pool
97 *
98 * @mc_dev: Pointer to allocatable MC object device
99 *
100 * It permanently removes an allocatable MC object device from the resource
101 * pool, the device is currently in, as long as it is in the pool's free list.
102 */
103static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device
104 *mc_dev)
105{
106 struct fsl_mc_device *mc_bus_dev;
107 struct fsl_mc_bus *mc_bus;
108 struct fsl_mc_resource_pool *res_pool;
109 struct fsl_mc_resource *resource;
110 int error = -EINVAL;
197f4d6a
GR
111
112 if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
113 goto out;
114
115 resource = mc_dev->resource;
2379bdbc 116 if (WARN_ON(!resource || resource->data != mc_dev))
197f4d6a
GR
117 goto out;
118
119 mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
120 mc_bus = to_fsl_mc_bus(mc_bus_dev);
121 res_pool = resource->parent_pool;
122 if (WARN_ON(res_pool != &mc_bus->resource_pools[resource->type]))
123 goto out;
124
125 mutex_lock(&res_pool->mutex);
197f4d6a
GR
126
127 if (WARN_ON(res_pool->max_count <= 0))
6ffdc7b9 128 goto out_unlock;
197f4d6a
GR
129 if (WARN_ON(res_pool->free_count <= 0 ||
130 res_pool->free_count > res_pool->max_count))
6ffdc7b9 131 goto out_unlock;
197f4d6a
GR
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));
6ffdc7b9 142 goto out_unlock;
197f4d6a
GR
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;
6ffdc7b9
CA
153out_unlock:
154 mutex_unlock(&res_pool->mutex);
197f4d6a 155out:
197f4d6a
GR
156 return error;
157}
158
159static const char *const fsl_mc_pool_type_strings[] = {
160 [FSL_MC_POOL_DPMCP] = "dpmcp",
161 [FSL_MC_POOL_DPBP] = "dpbp",
162 [FSL_MC_POOL_DPCON] = "dpcon",
89f067df 163 [FSL_MC_POOL_IRQ] = "irq",
197f4d6a
GR
164};
165
166static int __must_check object_type_to_pool_type(const char *object_type,
167 enum fsl_mc_pool_type
168 *pool_type)
169{
170 unsigned int i;
171
172 for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) {
173 if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) {
174 *pool_type = i;
175 return 0;
176 }
177 }
178
179 return -EINVAL;
180}
181
182int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus,
183 enum fsl_mc_pool_type pool_type,
184 struct fsl_mc_resource **new_resource)
185{
186 struct fsl_mc_resource_pool *res_pool;
187 struct fsl_mc_resource *resource;
188 struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
189 int error = -EINVAL;
197f4d6a
GR
190
191 BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) !=
192 FSL_MC_NUM_POOL_TYPES);
193
194 *new_resource = NULL;
195 if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES))
6ffdc7b9 196 goto out;
197f4d6a
GR
197
198 res_pool = &mc_bus->resource_pools[pool_type];
199 if (WARN_ON(res_pool->mc_bus != mc_bus))
6ffdc7b9 200 goto out;
197f4d6a
GR
201
202 mutex_lock(&res_pool->mutex);
197f4d6a
GR
203 resource = list_first_entry_or_null(&res_pool->free_list,
204 struct fsl_mc_resource, node);
205
206 if (!resource) {
207 WARN_ON(res_pool->free_count != 0);
208 error = -ENXIO;
209 dev_err(&mc_bus_dev->dev,
210 "No more resources of type %s left\n",
211 fsl_mc_pool_type_strings[pool_type]);
6ffdc7b9 212 goto out_unlock;
197f4d6a
GR
213 }
214
215 if (WARN_ON(resource->type != pool_type))
6ffdc7b9 216 goto out_unlock;
197f4d6a 217 if (WARN_ON(resource->parent_pool != res_pool))
6ffdc7b9 218 goto out_unlock;
197f4d6a
GR
219 if (WARN_ON(res_pool->free_count <= 0 ||
220 res_pool->free_count > res_pool->max_count))
6ffdc7b9 221 goto out_unlock;
197f4d6a
GR
222
223 list_del(&resource->node);
224 INIT_LIST_HEAD(&resource->node);
225
226 res_pool->free_count--;
6ffdc7b9
CA
227 error = 0;
228out_unlock:
197f4d6a
GR
229 mutex_unlock(&res_pool->mutex);
230 *new_resource = resource;
6ffdc7b9 231out:
197f4d6a
GR
232 return error;
233}
234EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate);
235
236void fsl_mc_resource_free(struct fsl_mc_resource *resource)
237{
238 struct fsl_mc_resource_pool *res_pool;
197f4d6a
GR
239
240 res_pool = resource->parent_pool;
241 if (WARN_ON(resource->type != res_pool->type))
6ffdc7b9 242 return;
197f4d6a
GR
243
244 mutex_lock(&res_pool->mutex);
197f4d6a
GR
245 if (WARN_ON(res_pool->free_count < 0 ||
246 res_pool->free_count >= res_pool->max_count))
6ffdc7b9 247 goto out_unlock;
197f4d6a
GR
248
249 if (WARN_ON(!list_empty(&resource->node)))
6ffdc7b9 250 goto out_unlock;
197f4d6a
GR
251
252 list_add_tail(&resource->node, &res_pool->free_list);
253 res_pool->free_count++;
6ffdc7b9
CA
254out_unlock:
255 mutex_unlock(&res_pool->mutex);
197f4d6a
GR
256}
257EXPORT_SYMBOL_GPL(fsl_mc_resource_free);
258
197f4d6a
GR
259/**
260 * fsl_mc_object_allocate - Allocates a MC object device of the given
261 * pool type from a given MC bus
262 *
263 * @mc_dev: MC device for which the MC object device is to be allocated
264 * @pool_type: MC bus resource pool type
265 * @new_mc_dev: Pointer to area where the pointer to the allocated
266 * MC object device is to be returned
267 *
268 * This function allocates a MC object device from the device's parent DPRC,
269 * from the corresponding MC bus' pool of allocatable MC object devices of
270 * the given resource type. mc_dev cannot be a DPRC itself.
271 *
272 * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC
273 * portals are allocated using fsl_mc_portal_allocate(), instead of
274 * this function.
275 */
276int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev,
277 enum fsl_mc_pool_type pool_type,
278 struct fsl_mc_device **new_mc_adev)
279{
280 struct fsl_mc_device *mc_bus_dev;
281 struct fsl_mc_bus *mc_bus;
282 struct fsl_mc_device *mc_adev;
283 int error = -EINVAL;
284 struct fsl_mc_resource *resource = NULL;
285
286 *new_mc_adev = NULL;
287 if (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC))
288 goto error;
289
df5e9b5f 290 if (WARN_ON(!dev_is_fsl_mc(mc_dev->dev.parent)))
197f4d6a
GR
291 goto error;
292
293 if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP))
294 goto error;
295
296 mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
297 mc_bus = to_fsl_mc_bus(mc_bus_dev);
298 error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource);
299 if (error < 0)
300 goto error;
301
302 mc_adev = resource->data;
303 if (WARN_ON(!mc_adev))
304 goto error;
305
306 *new_mc_adev = mc_adev;
307 return 0;
308error:
309 if (resource)
310 fsl_mc_resource_free(resource);
311
312 return error;
313}
314EXPORT_SYMBOL_GPL(fsl_mc_object_allocate);
315
316/**
317 * fsl_mc_object_free - Returns an allocatable MC object device to the
318 * corresponding resource pool of a given MC bus.
319 *
320 * @mc_adev: Pointer to the MC object device
321 */
322void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
323{
324 struct fsl_mc_resource *resource;
325
326 resource = mc_adev->resource;
327 if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP))
328 return;
329 if (WARN_ON(resource->data != mc_adev))
330 return;
331
332 fsl_mc_resource_free(resource);
333}
334EXPORT_SYMBOL_GPL(fsl_mc_object_free);
335
89f067df
GR
336/*
337 * Initialize the interrupt pool associated with a MC bus.
338 * It allocates a block of IRQs from the GIC-ITS
339 */
340int 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
393cleanup_msi_irqs:
394 fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
395 return error;
396}
397EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
398
399/**
400 * Teardown the interrupt pool associated with an MC bus.
401 * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
402 */
403void 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}
424EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
425
426/**
427 * It allocates the IRQs required by a given MC object device. The
428 * IRQs are allocated from the interrupt pool associated with the
429 * MC bus that contains the device, if the device is not a DPRC device.
430 * Otherwise, the IRQs are allocated from the interrupt pool associated
431 * with the MC bus that represents the DPRC device itself.
432 */
433int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
434{
435 int i;
436 int irq_count;
437 int res_allocated_count = 0;
438 int error = -EINVAL;
439 struct fsl_mc_device_irq **irqs = NULL;
440 struct fsl_mc_bus *mc_bus;
441 struct fsl_mc_resource_pool *res_pool;
442
443 if (WARN_ON(mc_dev->irqs))
444 return -EINVAL;
445
446 irq_count = mc_dev->obj_desc.irq_count;
447 if (WARN_ON(irq_count == 0))
448 return -EINVAL;
449
450 if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
451 mc_bus = to_fsl_mc_bus(mc_dev);
452 else
453 mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
454
455 if (WARN_ON(!mc_bus->irq_resources))
456 return -EINVAL;
457
458 res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
459 if (res_pool->free_count < irq_count) {
460 dev_err(&mc_dev->dev,
461 "Not able to allocate %u irqs for device\n", irq_count);
462 return -ENOSPC;
463 }
464
465 irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]),
466 GFP_KERNEL);
467 if (!irqs)
468 return -ENOMEM;
469
470 for (i = 0; i < irq_count; i++) {
471 struct fsl_mc_resource *resource;
472
473 error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ,
474 &resource);
475 if (error < 0)
476 goto error_resource_alloc;
477
478 irqs[i] = to_fsl_mc_irq(resource);
479 res_allocated_count++;
480
481 WARN_ON(irqs[i]->mc_dev);
482 irqs[i]->mc_dev = mc_dev;
483 irqs[i]->dev_irq_index = i;
484 }
485
486 mc_dev->irqs = irqs;
487 return 0;
488
489error_resource_alloc:
490 for (i = 0; i < res_allocated_count; i++) {
491 irqs[i]->mc_dev = NULL;
492 fsl_mc_resource_free(&irqs[i]->resource);
493 }
494
495 return error;
496}
497EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs);
498
499/*
500 * It frees the IRQs that were allocated for a MC object device, by
501 * returning them to the corresponding interrupt pool.
502 */
503void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
504{
505 int i;
506 int irq_count;
507 struct fsl_mc_bus *mc_bus;
508 struct fsl_mc_device_irq **irqs = mc_dev->irqs;
509
510 if (WARN_ON(!irqs))
511 return;
512
513 irq_count = mc_dev->obj_desc.irq_count;
514
515 if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
516 mc_bus = to_fsl_mc_bus(mc_dev);
517 else
518 mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
519
520 if (WARN_ON(!mc_bus->irq_resources))
521 return;
522
523 for (i = 0; i < irq_count; i++) {
524 WARN_ON(!irqs[i]->mc_dev);
525 irqs[i]->mc_dev = NULL;
526 fsl_mc_resource_free(&irqs[i]->resource);
527 }
528
529 mc_dev->irqs = NULL;
530}
531EXPORT_SYMBOL_GPL(fsl_mc_free_irqs);
532
36406955
SY
533void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
534{
535 int pool_type;
536 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
537
538 for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) {
539 struct fsl_mc_resource_pool *res_pool =
540 &mc_bus->resource_pools[pool_type];
541
542 res_pool->type = pool_type;
543 res_pool->max_count = 0;
544 res_pool->free_count = 0;
545 res_pool->mc_bus = mc_bus;
546 INIT_LIST_HEAD(&res_pool->free_list);
547 mutex_init(&res_pool->mutex);
548 }
549}
550
551static void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev,
552 enum fsl_mc_pool_type pool_type)
553{
554 struct fsl_mc_resource *resource;
555 struct fsl_mc_resource *next;
556 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
557 struct fsl_mc_resource_pool *res_pool =
558 &mc_bus->resource_pools[pool_type];
559 int free_count = 0;
560
561 WARN_ON(res_pool->type != pool_type);
562 WARN_ON(res_pool->free_count != res_pool->max_count);
563
564 list_for_each_entry_safe(resource, next, &res_pool->free_list, node) {
565 free_count++;
566 WARN_ON(resource->type != res_pool->type);
567 WARN_ON(resource->parent_pool != res_pool);
568 devm_kfree(&mc_bus_dev->dev, resource);
569 }
570
571 WARN_ON(free_count != res_pool->free_count);
572}
573
574void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
575{
576 int pool_type;
577
578 for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++)
579 fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type);
580}
581
197f4d6a
GR
582/**
583 * fsl_mc_allocator_probe - callback invoked when an allocatable device is
584 * being added to the system
585 */
586static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
587{
588 enum fsl_mc_pool_type pool_type;
589 struct fsl_mc_device *mc_bus_dev;
590 struct fsl_mc_bus *mc_bus;
09a38ab0 591 int error;
197f4d6a
GR
592
593 if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
09a38ab0 594 return -EINVAL;
197f4d6a
GR
595
596 mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
df5e9b5f 597 if (WARN_ON(!dev_is_fsl_mc(&mc_bus_dev->dev)))
09a38ab0 598 return -EINVAL;
197f4d6a
GR
599
600 mc_bus = to_fsl_mc_bus(mc_bus_dev);
601 error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type);
602 if (error < 0)
09a38ab0 603 return error;
197f4d6a
GR
604
605 error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev);
606 if (error < 0)
09a38ab0 607 return error;
197f4d6a 608
6998d6ba
GR
609 dev_dbg(&mc_dev->dev,
610 "Allocatable MC object device bound to fsl_mc_allocator driver");
197f4d6a 611 return 0;
197f4d6a
GR
612}
613
614/**
615 * fsl_mc_allocator_remove - callback invoked when an allocatable device is
616 * being removed from the system
617 */
618static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
619{
09a38ab0 620 int error;
197f4d6a
GR
621
622 if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
09a38ab0 623 return -EINVAL;
197f4d6a 624
6958cd44
GR
625 if (mc_dev->resource) {
626 error = fsl_mc_resource_pool_remove_device(mc_dev);
627 if (error < 0)
09a38ab0 628 return error;
6958cd44 629 }
197f4d6a 630
6998d6ba
GR
631 dev_dbg(&mc_dev->dev,
632 "Allocatable MC object device unbound from fsl_mc_allocator driver");
09a38ab0 633 return 0;
197f4d6a
GR
634}
635
57538afb 636static const struct fsl_mc_device_id match_id_table[] = {
197f4d6a
GR
637 {
638 .vendor = FSL_MC_VENDOR_FREESCALE,
639 .obj_type = "dpbp",
197f4d6a
GR
640 },
641 {
642 .vendor = FSL_MC_VENDOR_FREESCALE,
643 .obj_type = "dpmcp",
197f4d6a
GR
644 },
645 {
646 .vendor = FSL_MC_VENDOR_FREESCALE,
647 .obj_type = "dpcon",
197f4d6a
GR
648 },
649 {.vendor = 0x0},
650};
651
652static struct fsl_mc_driver fsl_mc_allocator_driver = {
653 .driver = {
654 .name = "fsl_mc_allocator",
655 .owner = THIS_MODULE,
656 .pm = NULL,
657 },
658 .match_id_table = match_id_table,
659 .probe = fsl_mc_allocator_probe,
660 .remove = fsl_mc_allocator_remove,
661};
662
e91ffa9e
GR
663int __init fsl_mc_allocator_driver_init(void)
664{
665 return fsl_mc_driver_register(&fsl_mc_allocator_driver);
666}
197f4d6a 667
53360607 668void fsl_mc_allocator_driver_exit(void)
e91ffa9e
GR
669{
670 fsl_mc_driver_unregister(&fsl_mc_allocator_driver);
671}
This page took 0.25294 seconds and 5 git commands to generate.