• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fsl_mc_is_allocatable(const char * obj_type)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  */
fsl_mc_resource_pool_add_device(struct fsl_mc_bus * mc_bus,enum fsl_mc_pool_type pool_type,struct fsl_mc_device * mc_dev)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  */
fsl_mc_resource_pool_remove_device(struct fsl_mc_device * mc_dev)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 
object_type_to_pool_type(const char * object_type,enum fsl_mc_pool_type * pool_type)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 
fsl_mc_resource_allocate(struct fsl_mc_bus * mc_bus,enum fsl_mc_pool_type pool_type,struct fsl_mc_resource ** new_resource)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 
fsl_mc_resource_free(struct fsl_mc_resource * resource)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  */
fsl_mc_object_allocate(struct fsl_mc_device * mc_dev,enum fsl_mc_pool_type pool_type,struct fsl_mc_device ** new_mc_adev)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  */
fsl_mc_object_free(struct fsl_mc_device * mc_adev)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  */
fsl_mc_populate_irq_pool(struct fsl_mc_bus * mc_bus,unsigned int irq_count)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  */
fsl_mc_cleanup_irq_pool(struct fsl_mc_bus * mc_bus)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  */
fsl_mc_allocate_irqs(struct fsl_mc_device * mc_dev)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  */
fsl_mc_free_irqs(struct fsl_mc_device * mc_dev)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 
fsl_mc_init_all_resource_pools(struct fsl_mc_device * mc_bus_dev)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 
fsl_mc_cleanup_resource_pool(struct fsl_mc_device * mc_bus_dev,enum fsl_mc_pool_type pool_type)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 
fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device * mc_bus_dev)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  */
fsl_mc_allocator_probe(struct fsl_mc_device * mc_dev)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  */
fsl_mc_allocator_remove(struct fsl_mc_device * mc_dev)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 
fsl_mc_allocator_driver_init(void)657 int __init fsl_mc_allocator_driver_init(void)
658 {
659 	return fsl_mc_driver_register(&fsl_mc_allocator_driver);
660 }
661 
fsl_mc_allocator_driver_exit(void)662 void fsl_mc_allocator_driver_exit(void)
663 {
664 	fsl_mc_driver_unregister(&fsl_mc_allocator_driver);
665 }
666