Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
19 | /** | |
20 | * fsl_mc_resource_pool_add_device - add allocatable device to a resource | |
21 | * pool of a given MC bus | |
22 | * | |
23 | * @mc_bus: pointer to the MC bus | |
24 | * @pool_type: MC bus pool type | |
25 | * @mc_dev: Pointer to allocatable MC object device | |
26 | * | |
27 | * It adds an allocatable MC object device to a container's resource pool of | |
28 | * the given resource type | |
29 | */ | |
30 | static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus | |
31 | *mc_bus, | |
32 | enum fsl_mc_pool_type | |
33 | pool_type, | |
34 | struct fsl_mc_device | |
35 | *mc_dev) | |
36 | { | |
37 | struct fsl_mc_resource_pool *res_pool; | |
38 | struct fsl_mc_resource *resource; | |
39 | struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; | |
40 | int error = -EINVAL; | |
41 | bool mutex_locked = false; | |
42 | ||
43 | if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES)) | |
44 | goto out; | |
45 | if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) | |
46 | goto out; | |
47 | if (WARN_ON(mc_dev->resource)) | |
48 | goto out; | |
49 | ||
50 | res_pool = &mc_bus->resource_pools[pool_type]; | |
51 | if (WARN_ON(res_pool->type != pool_type)) | |
52 | goto out; | |
53 | if (WARN_ON(res_pool->mc_bus != mc_bus)) | |
54 | goto out; | |
55 | ||
56 | mutex_lock(&res_pool->mutex); | |
57 | mutex_locked = true; | |
58 | ||
59 | if (WARN_ON(res_pool->max_count < 0)) | |
60 | goto out; | |
61 | if (WARN_ON(res_pool->free_count < 0 || | |
62 | res_pool->free_count > res_pool->max_count)) | |
63 | goto out; | |
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; | |
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: | |
85 | if (mutex_locked) | |
86 | mutex_unlock(&res_pool->mutex); | |
87 | ||
88 | return error; | |
89 | } | |
90 | ||
91 | /** | |
92 | * fsl_mc_resource_pool_remove_device - remove an allocatable device from a | |
93 | * resource pool | |
94 | * | |
95 | * @mc_dev: Pointer to allocatable MC object device | |
96 | * | |
97 | * It permanently removes an allocatable MC object device from the resource | |
98 | * pool, the device is currently in, as long as it is in the pool's free list. | |
99 | */ | |
100 | static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device | |
101 | *mc_dev) | |
102 | { | |
103 | struct fsl_mc_device *mc_bus_dev; | |
104 | struct fsl_mc_bus *mc_bus; | |
105 | struct fsl_mc_resource_pool *res_pool; | |
106 | struct fsl_mc_resource *resource; | |
107 | int error = -EINVAL; | |
108 | bool mutex_locked = false; | |
109 | ||
110 | if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) | |
111 | goto out; | |
112 | ||
113 | resource = mc_dev->resource; | |
114 | if (WARN_ON(resource->data != mc_dev)) | |
115 | goto out; | |
116 | ||
117 | mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); | |
118 | mc_bus = to_fsl_mc_bus(mc_bus_dev); | |
119 | res_pool = resource->parent_pool; | |
120 | if (WARN_ON(res_pool != &mc_bus->resource_pools[resource->type])) | |
121 | goto out; | |
122 | ||
123 | mutex_lock(&res_pool->mutex); | |
124 | mutex_locked = true; | |
125 | ||
126 | if (WARN_ON(res_pool->max_count <= 0)) | |
127 | goto out; | |
128 | if (WARN_ON(res_pool->free_count <= 0 || | |
129 | res_pool->free_count > res_pool->max_count)) | |
130 | goto out; | |
131 | ||
132 | /* | |
133 | * If the device is currently allocated, its resource is not | |
134 | * in the free list and thus, the device cannot be removed. | |
135 | */ | |
136 | if (list_empty(&resource->node)) { | |
137 | error = -EBUSY; | |
138 | dev_err(&mc_bus_dev->dev, | |
139 | "Device %s cannot be removed from resource pool\n", | |
140 | dev_name(&mc_dev->dev)); | |
141 | goto out; | |
142 | } | |
143 | ||
144 | list_del(&resource->node); | |
145 | INIT_LIST_HEAD(&resource->node); | |
146 | res_pool->free_count--; | |
147 | res_pool->max_count--; | |
148 | ||
149 | devm_kfree(&mc_bus_dev->dev, resource); | |
150 | mc_dev->resource = NULL; | |
151 | error = 0; | |
152 | out: | |
153 | if (mutex_locked) | |
154 | mutex_unlock(&res_pool->mutex); | |
155 | ||
156 | return error; | |
157 | } | |
158 | ||
159 | static 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", | |
163 | }; | |
164 | ||
165 | static int __must_check object_type_to_pool_type(const char *object_type, | |
166 | enum fsl_mc_pool_type | |
167 | *pool_type) | |
168 | { | |
169 | unsigned int i; | |
170 | ||
171 | for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) { | |
172 | if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) { | |
173 | *pool_type = i; | |
174 | return 0; | |
175 | } | |
176 | } | |
177 | ||
178 | return -EINVAL; | |
179 | } | |
180 | ||
181 | int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus, | |
182 | enum fsl_mc_pool_type pool_type, | |
183 | struct fsl_mc_resource **new_resource) | |
184 | { | |
185 | struct fsl_mc_resource_pool *res_pool; | |
186 | struct fsl_mc_resource *resource; | |
187 | struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; | |
188 | int error = -EINVAL; | |
189 | bool mutex_locked = false; | |
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)) | |
196 | goto error; | |
197 | ||
198 | res_pool = &mc_bus->resource_pools[pool_type]; | |
199 | if (WARN_ON(res_pool->mc_bus != mc_bus)) | |
200 | goto error; | |
201 | ||
202 | mutex_lock(&res_pool->mutex); | |
203 | mutex_locked = true; | |
204 | resource = list_first_entry_or_null(&res_pool->free_list, | |
205 | struct fsl_mc_resource, node); | |
206 | ||
207 | if (!resource) { | |
208 | WARN_ON(res_pool->free_count != 0); | |
209 | error = -ENXIO; | |
210 | dev_err(&mc_bus_dev->dev, | |
211 | "No more resources of type %s left\n", | |
212 | fsl_mc_pool_type_strings[pool_type]); | |
213 | goto error; | |
214 | } | |
215 | ||
216 | if (WARN_ON(resource->type != pool_type)) | |
217 | goto error; | |
218 | if (WARN_ON(resource->parent_pool != res_pool)) | |
219 | goto error; | |
220 | if (WARN_ON(res_pool->free_count <= 0 || | |
221 | res_pool->free_count > res_pool->max_count)) | |
222 | goto error; | |
223 | ||
224 | list_del(&resource->node); | |
225 | INIT_LIST_HEAD(&resource->node); | |
226 | ||
227 | res_pool->free_count--; | |
228 | mutex_unlock(&res_pool->mutex); | |
229 | *new_resource = resource; | |
230 | return 0; | |
231 | error: | |
232 | if (mutex_locked) | |
233 | mutex_unlock(&res_pool->mutex); | |
234 | ||
235 | return error; | |
236 | } | |
237 | EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate); | |
238 | ||
239 | void fsl_mc_resource_free(struct fsl_mc_resource *resource) | |
240 | { | |
241 | struct fsl_mc_resource_pool *res_pool; | |
242 | bool mutex_locked = false; | |
243 | ||
244 | res_pool = resource->parent_pool; | |
245 | if (WARN_ON(resource->type != res_pool->type)) | |
246 | goto out; | |
247 | ||
248 | mutex_lock(&res_pool->mutex); | |
249 | mutex_locked = true; | |
250 | if (WARN_ON(res_pool->free_count < 0 || | |
251 | res_pool->free_count >= res_pool->max_count)) | |
252 | goto out; | |
253 | ||
254 | if (WARN_ON(!list_empty(&resource->node))) | |
255 | goto out; | |
256 | ||
257 | list_add_tail(&resource->node, &res_pool->free_list); | |
258 | res_pool->free_count++; | |
259 | out: | |
260 | if (mutex_locked) | |
261 | mutex_unlock(&res_pool->mutex); | |
262 | } | |
263 | EXPORT_SYMBOL_GPL(fsl_mc_resource_free); | |
264 | ||
265 | /** | |
266 | * fsl_mc_portal_allocate - Allocates an MC portal | |
267 | * | |
268 | * @mc_dev: MC device for which the MC portal is to be allocated | |
269 | * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated | |
270 | * MC portal. | |
271 | * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object | |
272 | * that wraps the allocated MC portal is to be returned | |
273 | * | |
274 | * This function allocates an MC portal from the device's parent DPRC, | |
275 | * from the corresponding MC bus' pool of MC portals and wraps | |
276 | * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the | |
277 | * portal is allocated from its own MC bus. | |
278 | */ | |
279 | int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, | |
280 | uint16_t mc_io_flags, | |
281 | struct fsl_mc_io **new_mc_io) | |
282 | { | |
283 | struct fsl_mc_device *mc_bus_dev; | |
284 | struct fsl_mc_bus *mc_bus; | |
285 | phys_addr_t mc_portal_phys_addr; | |
286 | size_t mc_portal_size; | |
287 | struct fsl_mc_device *mc_adev; | |
288 | int error = -EINVAL; | |
289 | struct fsl_mc_resource *resource = NULL; | |
290 | struct fsl_mc_io *mc_io = NULL; | |
291 | ||
292 | if (mc_dev->flags & FSL_MC_IS_DPRC) { | |
293 | mc_bus_dev = mc_dev; | |
294 | } else { | |
295 | if (WARN_ON(mc_dev->dev.parent->bus != &fsl_mc_bus_type)) | |
296 | return error; | |
297 | ||
298 | mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); | |
299 | } | |
300 | ||
301 | mc_bus = to_fsl_mc_bus(mc_bus_dev); | |
302 | *new_mc_io = NULL; | |
303 | error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource); | |
304 | if (error < 0) | |
305 | return error; | |
306 | ||
307 | mc_adev = resource->data; | |
308 | if (WARN_ON(!mc_adev)) | |
309 | goto error_cleanup_resource; | |
310 | ||
311 | if (WARN_ON(mc_adev->obj_desc.region_count == 0)) | |
312 | goto error_cleanup_resource; | |
313 | ||
314 | mc_portal_phys_addr = mc_adev->regions[0].start; | |
315 | mc_portal_size = mc_adev->regions[0].end - | |
316 | mc_adev->regions[0].start + 1; | |
317 | ||
318 | if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size)) | |
319 | goto error_cleanup_resource; | |
320 | ||
321 | error = fsl_create_mc_io(&mc_bus_dev->dev, | |
322 | mc_portal_phys_addr, | |
323 | mc_portal_size, resource, | |
324 | mc_io_flags, &mc_io); | |
325 | if (error < 0) | |
326 | goto error_cleanup_resource; | |
327 | ||
328 | *new_mc_io = mc_io; | |
329 | return 0; | |
330 | ||
331 | error_cleanup_resource: | |
332 | fsl_mc_resource_free(resource); | |
333 | return error; | |
334 | } | |
335 | EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate); | |
336 | ||
337 | /** | |
338 | * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals | |
339 | * of a given MC bus | |
340 | * | |
341 | * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free | |
342 | */ | |
343 | void fsl_mc_portal_free(struct fsl_mc_io *mc_io) | |
344 | { | |
345 | struct fsl_mc_resource *resource; | |
346 | ||
347 | resource = mc_io->resource; | |
348 | if (WARN_ON(resource->type != FSL_MC_POOL_DPMCP)) | |
349 | return; | |
350 | if (WARN_ON(!resource->data)) | |
351 | return; | |
352 | ||
353 | fsl_destroy_mc_io(mc_io); | |
354 | fsl_mc_resource_free(resource); | |
355 | } | |
356 | EXPORT_SYMBOL_GPL(fsl_mc_portal_free); | |
357 | ||
358 | /** | |
359 | * fsl_mc_portal_reset - Resets the dpmcp object for a given fsl_mc_io object | |
360 | * | |
361 | * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free | |
362 | */ | |
363 | int fsl_mc_portal_reset(struct fsl_mc_io *mc_io) | |
364 | { | |
365 | int error; | |
366 | uint16_t token; | |
367 | struct fsl_mc_resource *resource = mc_io->resource; | |
368 | struct fsl_mc_device *mc_dev = resource->data; | |
369 | ||
370 | if (WARN_ON(resource->type != FSL_MC_POOL_DPMCP)) | |
371 | return -EINVAL; | |
372 | ||
373 | if (WARN_ON(!mc_dev)) | |
374 | return -EINVAL; | |
375 | ||
376 | error = dpmcp_open(mc_io, mc_dev->obj_desc.id, &token); | |
377 | if (error < 0) { | |
378 | dev_err(&mc_dev->dev, "dpmcp_open() failed: %d\n", error); | |
379 | return error; | |
380 | } | |
381 | ||
382 | error = dpmcp_reset(mc_io, token); | |
383 | if (error < 0) { | |
384 | dev_err(&mc_dev->dev, "dpmcp_reset() failed: %d\n", error); | |
385 | return error; | |
386 | } | |
387 | ||
388 | error = dpmcp_close(mc_io, token); | |
389 | if (error < 0) { | |
390 | dev_err(&mc_dev->dev, "dpmcp_close() failed: %d\n", error); | |
391 | return error; | |
392 | } | |
393 | ||
394 | return 0; | |
395 | } | |
396 | EXPORT_SYMBOL_GPL(fsl_mc_portal_reset); | |
397 | ||
398 | /** | |
399 | * fsl_mc_object_allocate - Allocates a MC object device of the given | |
400 | * pool type from a given MC bus | |
401 | * | |
402 | * @mc_dev: MC device for which the MC object device is to be allocated | |
403 | * @pool_type: MC bus resource pool type | |
404 | * @new_mc_dev: Pointer to area where the pointer to the allocated | |
405 | * MC object device is to be returned | |
406 | * | |
407 | * This function allocates a MC object device from the device's parent DPRC, | |
408 | * from the corresponding MC bus' pool of allocatable MC object devices of | |
409 | * the given resource type. mc_dev cannot be a DPRC itself. | |
410 | * | |
411 | * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC | |
412 | * portals are allocated using fsl_mc_portal_allocate(), instead of | |
413 | * this function. | |
414 | */ | |
415 | int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, | |
416 | enum fsl_mc_pool_type pool_type, | |
417 | struct fsl_mc_device **new_mc_adev) | |
418 | { | |
419 | struct fsl_mc_device *mc_bus_dev; | |
420 | struct fsl_mc_bus *mc_bus; | |
421 | struct fsl_mc_device *mc_adev; | |
422 | int error = -EINVAL; | |
423 | struct fsl_mc_resource *resource = NULL; | |
424 | ||
425 | *new_mc_adev = NULL; | |
426 | if (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC)) | |
427 | goto error; | |
428 | ||
429 | if (WARN_ON(mc_dev->dev.parent->bus != &fsl_mc_bus_type)) | |
430 | goto error; | |
431 | ||
432 | if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP)) | |
433 | goto error; | |
434 | ||
435 | mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); | |
436 | mc_bus = to_fsl_mc_bus(mc_bus_dev); | |
437 | error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource); | |
438 | if (error < 0) | |
439 | goto error; | |
440 | ||
441 | mc_adev = resource->data; | |
442 | if (WARN_ON(!mc_adev)) | |
443 | goto error; | |
444 | ||
445 | *new_mc_adev = mc_adev; | |
446 | return 0; | |
447 | error: | |
448 | if (resource) | |
449 | fsl_mc_resource_free(resource); | |
450 | ||
451 | return error; | |
452 | } | |
453 | EXPORT_SYMBOL_GPL(fsl_mc_object_allocate); | |
454 | ||
455 | /** | |
456 | * fsl_mc_object_free - Returns an allocatable MC object device to the | |
457 | * corresponding resource pool of a given MC bus. | |
458 | * | |
459 | * @mc_adev: Pointer to the MC object device | |
460 | */ | |
461 | void fsl_mc_object_free(struct fsl_mc_device *mc_adev) | |
462 | { | |
463 | struct fsl_mc_resource *resource; | |
464 | ||
465 | resource = mc_adev->resource; | |
466 | if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP)) | |
467 | return; | |
468 | if (WARN_ON(resource->data != mc_adev)) | |
469 | return; | |
470 | ||
471 | fsl_mc_resource_free(resource); | |
472 | } | |
473 | EXPORT_SYMBOL_GPL(fsl_mc_object_free); | |
474 | ||
475 | /** | |
476 | * fsl_mc_allocator_probe - callback invoked when an allocatable device is | |
477 | * being added to the system | |
478 | */ | |
479 | static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev) | |
480 | { | |
481 | enum fsl_mc_pool_type pool_type; | |
482 | struct fsl_mc_device *mc_bus_dev; | |
483 | struct fsl_mc_bus *mc_bus; | |
484 | int error = -EINVAL; | |
485 | ||
486 | if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) | |
487 | goto error; | |
488 | ||
489 | mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); | |
490 | if (WARN_ON(mc_bus_dev->dev.bus != &fsl_mc_bus_type)) | |
491 | goto error; | |
492 | ||
493 | mc_bus = to_fsl_mc_bus(mc_bus_dev); | |
494 | error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type); | |
495 | if (error < 0) | |
496 | goto error; | |
497 | ||
498 | error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev); | |
499 | if (error < 0) | |
500 | goto error; | |
501 | ||
502 | dev_info(&mc_dev->dev, | |
503 | "Allocatable MC object device bound to fsl_mc_allocator driver"); | |
504 | return 0; | |
505 | error: | |
506 | ||
507 | return error; | |
508 | } | |
509 | ||
510 | /** | |
511 | * fsl_mc_allocator_remove - callback invoked when an allocatable device is | |
512 | * being removed from the system | |
513 | */ | |
514 | static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev) | |
515 | { | |
516 | int error = -EINVAL; | |
517 | ||
518 | if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type))) | |
519 | goto out; | |
520 | ||
521 | error = fsl_mc_resource_pool_remove_device(mc_dev); | |
522 | if (error < 0) | |
523 | goto out; | |
524 | ||
525 | dev_info(&mc_dev->dev, | |
526 | "Allocatable MC object device unbound from fsl_mc_allocator driver"); | |
527 | error = 0; | |
528 | out: | |
529 | return error; | |
530 | } | |
531 | ||
532 | static const struct fsl_mc_device_match_id match_id_table[] = { | |
533 | { | |
534 | .vendor = FSL_MC_VENDOR_FREESCALE, | |
535 | .obj_type = "dpbp", | |
536 | .ver_major = DPBP_VER_MAJOR, | |
537 | .ver_minor = DPBP_VER_MINOR | |
538 | }, | |
539 | { | |
540 | .vendor = FSL_MC_VENDOR_FREESCALE, | |
541 | .obj_type = "dpmcp", | |
542 | .ver_major = DPMCP_VER_MAJOR, | |
543 | .ver_minor = DPMCP_VER_MINOR | |
544 | }, | |
545 | { | |
546 | .vendor = FSL_MC_VENDOR_FREESCALE, | |
547 | .obj_type = "dpcon", | |
548 | .ver_major = DPCON_VER_MAJOR, | |
549 | .ver_minor = DPCON_VER_MINOR | |
550 | }, | |
551 | {.vendor = 0x0}, | |
552 | }; | |
553 | ||
554 | static struct fsl_mc_driver fsl_mc_allocator_driver = { | |
555 | .driver = { | |
556 | .name = "fsl_mc_allocator", | |
557 | .owner = THIS_MODULE, | |
558 | .pm = NULL, | |
559 | }, | |
560 | .match_id_table = match_id_table, | |
561 | .probe = fsl_mc_allocator_probe, | |
562 | .remove = fsl_mc_allocator_remove, | |
563 | }; | |
564 | ||
565 | module_fsl_mc_driver(fsl_mc_allocator_driver); | |
566 | ||
567 | MODULE_AUTHOR("Freescale Semiconductor Inc."); | |
568 | MODULE_DESCRIPTION("Freescale's MC object device allocator"); | |
569 | MODULE_LICENSE("GPL"); |