linux/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c
<<
>>
Prefs
   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 <linux/module.h>
  12#include <linux/msi.h>
  13#include "../include/mc-bus.h"
  14#include "../include/mc-sys.h"
  15#include "../include/dpbp-cmd.h"
  16#include "../include/dpcon-cmd.h"
  17
  18#include "fsl-mc-private.h"
  19
  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
  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;
  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);
  62
  63        if (WARN_ON(res_pool->max_count < 0))
  64                goto out_unlock;
  65        if (WARN_ON(res_pool->free_count < 0 ||
  66                    res_pool->free_count > res_pool->max_count))
  67                goto out_unlock;
  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");
  75                goto out_unlock;
  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;
  88out_unlock:
  89        mutex_unlock(&res_pool->mutex);
  90out:
  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;
 111
 112        if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
 113                goto out;
 114
 115        resource = mc_dev->resource;
 116        if (WARN_ON(!resource || resource->data != mc_dev))
 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);
 126
 127        if (WARN_ON(res_pool->max_count <= 0))
 128                goto out_unlock;
 129        if (WARN_ON(res_pool->free_count <= 0 ||
 130                    res_pool->free_count > res_pool->max_count))
 131                goto out_unlock;
 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_unlock;
 143        }
 144
 145        list_del_init(&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;
 152out_unlock:
 153        mutex_unlock(&res_pool->mutex);
 154out:
 155        return error;
 156}
 157
 158static const char *const fsl_mc_pool_type_strings[] = {
 159        [FSL_MC_POOL_DPMCP] = "dpmcp",
 160        [FSL_MC_POOL_DPBP] = "dpbp",
 161        [FSL_MC_POOL_DPCON] = "dpcon",
 162        [FSL_MC_POOL_IRQ] = "irq",
 163};
 164
 165static 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
 181int __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
 190        BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) !=
 191                     FSL_MC_NUM_POOL_TYPES);
 192
 193        *new_resource = NULL;
 194        if (WARN_ON(pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES))
 195                goto out;
 196
 197        res_pool = &mc_bus->resource_pools[pool_type];
 198        if (WARN_ON(res_pool->mc_bus != mc_bus))
 199                goto out;
 200
 201        mutex_lock(&res_pool->mutex);
 202        resource = list_first_entry_or_null(&res_pool->free_list,
 203                                            struct fsl_mc_resource, node);
 204
 205        if (!resource) {
 206                WARN_ON(res_pool->free_count != 0);
 207                error = -ENXIO;
 208                dev_err(&mc_bus_dev->dev,
 209                        "No more resources of type %s left\n",
 210                        fsl_mc_pool_type_strings[pool_type]);
 211                goto out_unlock;
 212        }
 213
 214        if (WARN_ON(resource->type != pool_type))
 215                goto out_unlock;
 216        if (WARN_ON(resource->parent_pool != res_pool))
 217                goto out_unlock;
 218        if (WARN_ON(res_pool->free_count <= 0 ||
 219                    res_pool->free_count > res_pool->max_count))
 220                goto out_unlock;
 221
 222        list_del_init(&resource->node);
 223
 224        res_pool->free_count--;
 225        error = 0;
 226out_unlock:
 227        mutex_unlock(&res_pool->mutex);
 228        *new_resource = resource;
 229out:
 230        return error;
 231}
 232EXPORT_SYMBOL_GPL(fsl_mc_resource_allocate);
 233
 234void fsl_mc_resource_free(struct fsl_mc_resource *resource)
 235{
 236        struct fsl_mc_resource_pool *res_pool;
 237
 238        res_pool = resource->parent_pool;
 239        if (WARN_ON(resource->type != res_pool->type))
 240                return;
 241
 242        mutex_lock(&res_pool->mutex);
 243        if (WARN_ON(res_pool->free_count < 0 ||
 244                    res_pool->free_count >= res_pool->max_count))
 245                goto out_unlock;
 246
 247        if (WARN_ON(!list_empty(&resource->node)))
 248                goto out_unlock;
 249
 250        list_add_tail(&resource->node, &res_pool->free_list);
 251        res_pool->free_count++;
 252out_unlock:
 253        mutex_unlock(&res_pool->mutex);
 254}
 255EXPORT_SYMBOL_GPL(fsl_mc_resource_free);
 256
 257/**
 258 * fsl_mc_object_allocate - Allocates a MC object device of the given
 259 * pool type from a given MC bus
 260 *
 261 * @mc_dev: MC device for which the MC object device is to be allocated
 262 * @pool_type: MC bus resource pool type
 263 * @new_mc_dev: Pointer to area where the pointer to the allocated
 264 * MC object device is to be returned
 265 *
 266 * This function allocates a MC object device from the device's parent DPRC,
 267 * from the corresponding MC bus' pool of allocatable MC object devices of
 268 * the given resource type. mc_dev cannot be a DPRC itself.
 269 *
 270 * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC
 271 * portals are allocated using fsl_mc_portal_allocate(), instead of
 272 * this function.
 273 */
 274int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev,
 275                                        enum fsl_mc_pool_type pool_type,
 276                                        struct fsl_mc_device **new_mc_adev)
 277{
 278        struct fsl_mc_device *mc_bus_dev;
 279        struct fsl_mc_bus *mc_bus;
 280        struct fsl_mc_device *mc_adev;
 281        int error = -EINVAL;
 282        struct fsl_mc_resource *resource = NULL;
 283
 284        *new_mc_adev = NULL;
 285        if (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC))
 286                goto error;
 287
 288        if (WARN_ON(!dev_is_fsl_mc(mc_dev->dev.parent)))
 289                goto error;
 290
 291        if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP))
 292                goto error;
 293
 294        mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
 295        mc_bus = to_fsl_mc_bus(mc_bus_dev);
 296        error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource);
 297        if (error < 0)
 298                goto error;
 299
 300        mc_adev = resource->data;
 301        if (WARN_ON(!mc_adev))
 302                goto error;
 303
 304        *new_mc_adev = mc_adev;
 305        return 0;
 306error:
 307        if (resource)
 308                fsl_mc_resource_free(resource);
 309
 310        return error;
 311}
 312EXPORT_SYMBOL_GPL(fsl_mc_object_allocate);
 313
 314/**
 315 * fsl_mc_object_free - Returns an allocatable MC object device to the
 316 * corresponding resource pool of a given MC bus.
 317 *
 318 * @mc_adev: Pointer to the MC object device
 319 */
 320void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
 321{
 322        struct fsl_mc_resource *resource;
 323
 324        resource = mc_adev->resource;
 325        if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP))
 326                return;
 327        if (WARN_ON(resource->data != mc_adev))
 328                return;
 329
 330        fsl_mc_resource_free(resource);
 331}
 332EXPORT_SYMBOL_GPL(fsl_mc_object_free);
 333
 334/*
 335 * Initialize the interrupt pool associated with a MC bus.
 336 * It allocates a block of IRQs from the GIC-ITS
 337 */
 338int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
 339                             unsigned int irq_count)
 340{
 341        unsigned int i;
 342        struct msi_desc *msi_desc;
 343        struct fsl_mc_device_irq *irq_resources;
 344        struct fsl_mc_device_irq *mc_dev_irq;
 345        int error;
 346        struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
 347        struct fsl_mc_resource_pool *res_pool =
 348                        &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
 349
 350        if (WARN_ON(irq_count == 0 ||
 351                    irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS))
 352                return -EINVAL;
 353
 354        error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count);
 355        if (error < 0)
 356                return error;
 357
 358        irq_resources = devm_kzalloc(&mc_bus_dev->dev,
 359                                     sizeof(*irq_resources) * irq_count,
 360                                     GFP_KERNEL);
 361        if (!irq_resources) {
 362                error = -ENOMEM;
 363                goto cleanup_msi_irqs;
 364        }
 365
 366        for (i = 0; i < irq_count; i++) {
 367                mc_dev_irq = &irq_resources[i];
 368
 369                /*
 370                 * NOTE: This mc_dev_irq's MSI addr/value pair will be set
 371                 * by the fsl_mc_msi_write_msg() callback
 372                 */
 373                mc_dev_irq->resource.type = res_pool->type;
 374                mc_dev_irq->resource.data = mc_dev_irq;
 375                mc_dev_irq->resource.parent_pool = res_pool;
 376                INIT_LIST_HEAD(&mc_dev_irq->resource.node);
 377                list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list);
 378        }
 379
 380        for_each_msi_entry(msi_desc, &mc_bus_dev->dev) {
 381                mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index];
 382                mc_dev_irq->msi_desc = msi_desc;
 383                mc_dev_irq->resource.id = msi_desc->irq;
 384        }
 385
 386        res_pool->max_count = irq_count;
 387        res_pool->free_count = irq_count;
 388        mc_bus->irq_resources = irq_resources;
 389        return 0;
 390
 391cleanup_msi_irqs:
 392        fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
 393        return error;
 394}
 395EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
 396
 397/**
 398 * Teardown the interrupt pool associated with an MC bus.
 399 * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
 400 */
 401void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus)
 402{
 403        struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
 404        struct fsl_mc_resource_pool *res_pool =
 405                        &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
 406
 407        if (WARN_ON(!mc_bus->irq_resources))
 408                return;
 409
 410        if (WARN_ON(res_pool->max_count == 0))
 411                return;
 412
 413        if (WARN_ON(res_pool->free_count != res_pool->max_count))
 414                return;
 415
 416        INIT_LIST_HEAD(&res_pool->free_list);
 417        res_pool->max_count = 0;
 418        res_pool->free_count = 0;
 419        mc_bus->irq_resources = NULL;
 420        fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev);
 421}
 422EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
 423
 424/**
 425 * It allocates the IRQs required by a given MC object device. The
 426 * IRQs are allocated from the interrupt pool associated with the
 427 * MC bus that contains the device, if the device is not a DPRC device.
 428 * Otherwise, the IRQs are allocated from the interrupt pool associated
 429 * with the MC bus that represents the DPRC device itself.
 430 */
 431int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
 432{
 433        int i;
 434        int irq_count;
 435        int res_allocated_count = 0;
 436        int error = -EINVAL;
 437        struct fsl_mc_device_irq **irqs = NULL;
 438        struct fsl_mc_bus *mc_bus;
 439        struct fsl_mc_resource_pool *res_pool;
 440
 441        if (WARN_ON(mc_dev->irqs))
 442                return -EINVAL;
 443
 444        irq_count = mc_dev->obj_desc.irq_count;
 445        if (WARN_ON(irq_count == 0))
 446                return -EINVAL;
 447
 448        if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
 449                mc_bus = to_fsl_mc_bus(mc_dev);
 450        else
 451                mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
 452
 453        if (WARN_ON(!mc_bus->irq_resources))
 454                return -EINVAL;
 455
 456        res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
 457        if (res_pool->free_count < irq_count) {
 458                dev_err(&mc_dev->dev,
 459                        "Not able to allocate %u irqs for device\n", irq_count);
 460                return -ENOSPC;
 461        }
 462
 463        irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]),
 464                            GFP_KERNEL);
 465        if (!irqs)
 466                return -ENOMEM;
 467
 468        for (i = 0; i < irq_count; i++) {
 469                struct fsl_mc_resource *resource;
 470
 471                error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ,
 472                                                 &resource);
 473                if (error < 0)
 474                        goto error_resource_alloc;
 475
 476                irqs[i] = to_fsl_mc_irq(resource);
 477                res_allocated_count++;
 478
 479                WARN_ON(irqs[i]->mc_dev);
 480                irqs[i]->mc_dev = mc_dev;
 481                irqs[i]->dev_irq_index = i;
 482        }
 483
 484        mc_dev->irqs = irqs;
 485        return 0;
 486
 487error_resource_alloc:
 488        for (i = 0; i < res_allocated_count; i++) {
 489                irqs[i]->mc_dev = NULL;
 490                fsl_mc_resource_free(&irqs[i]->resource);
 491        }
 492
 493        return error;
 494}
 495EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs);
 496
 497/*
 498 * It frees the IRQs that were allocated for a MC object device, by
 499 * returning them to the corresponding interrupt pool.
 500 */
 501void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
 502{
 503        int i;
 504        int irq_count;
 505        struct fsl_mc_bus *mc_bus;
 506        struct fsl_mc_device_irq **irqs = mc_dev->irqs;
 507
 508        if (WARN_ON(!irqs))
 509                return;
 510
 511        irq_count = mc_dev->obj_desc.irq_count;
 512
 513        if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
 514                mc_bus = to_fsl_mc_bus(mc_dev);
 515        else
 516                mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
 517
 518        if (WARN_ON(!mc_bus->irq_resources))
 519                return;
 520
 521        for (i = 0; i < irq_count; i++) {
 522                WARN_ON(!irqs[i]->mc_dev);
 523                irqs[i]->mc_dev = NULL;
 524                fsl_mc_resource_free(&irqs[i]->resource);
 525        }
 526
 527        mc_dev->irqs = NULL;
 528}
 529EXPORT_SYMBOL_GPL(fsl_mc_free_irqs);
 530
 531void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
 532{
 533        int pool_type;
 534        struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
 535
 536        for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) {
 537                struct fsl_mc_resource_pool *res_pool =
 538                    &mc_bus->resource_pools[pool_type];
 539
 540                res_pool->type = pool_type;
 541                res_pool->max_count = 0;
 542                res_pool->free_count = 0;
 543                res_pool->mc_bus = mc_bus;
 544                INIT_LIST_HEAD(&res_pool->free_list);
 545                mutex_init(&res_pool->mutex);
 546        }
 547}
 548
 549static void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev,
 550                                         enum fsl_mc_pool_type pool_type)
 551{
 552        struct fsl_mc_resource *resource;
 553        struct fsl_mc_resource *next;
 554        struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
 555        struct fsl_mc_resource_pool *res_pool =
 556                                        &mc_bus->resource_pools[pool_type];
 557        int free_count = 0;
 558
 559        WARN_ON(res_pool->type != pool_type);
 560        WARN_ON(res_pool->free_count != res_pool->max_count);
 561
 562        list_for_each_entry_safe(resource, next, &res_pool->free_list, node) {
 563                free_count++;
 564                WARN_ON(resource->type != res_pool->type);
 565                WARN_ON(resource->parent_pool != res_pool);
 566                devm_kfree(&mc_bus_dev->dev, resource);
 567        }
 568
 569        WARN_ON(free_count != res_pool->free_count);
 570}
 571
 572void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
 573{
 574        int pool_type;
 575
 576        for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++)
 577                fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type);
 578}
 579
 580/**
 581 * fsl_mc_allocator_probe - callback invoked when an allocatable device is
 582 * being added to the system
 583 */
 584static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
 585{
 586        enum fsl_mc_pool_type pool_type;
 587        struct fsl_mc_device *mc_bus_dev;
 588        struct fsl_mc_bus *mc_bus;
 589        int error;
 590
 591        if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
 592                return -EINVAL;
 593
 594        mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
 595        if (WARN_ON(!dev_is_fsl_mc(&mc_bus_dev->dev)))
 596                return -EINVAL;
 597
 598        mc_bus = to_fsl_mc_bus(mc_bus_dev);
 599        error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type);
 600        if (error < 0)
 601                return error;
 602
 603        error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev);
 604        if (error < 0)
 605                return error;
 606
 607        dev_dbg(&mc_dev->dev,
 608                "Allocatable MC object device bound to fsl_mc_allocator driver");
 609        return 0;
 610}
 611
 612/**
 613 * fsl_mc_allocator_remove - callback invoked when an allocatable device is
 614 * being removed from the system
 615 */
 616static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
 617{
 618        int error;
 619
 620        if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
 621                return -EINVAL;
 622
 623        if (mc_dev->resource) {
 624                error = fsl_mc_resource_pool_remove_device(mc_dev);
 625                if (error < 0)
 626                        return error;
 627        }
 628
 629        dev_dbg(&mc_dev->dev,
 630                "Allocatable MC object device unbound from fsl_mc_allocator driver");
 631        return 0;
 632}
 633
 634static const struct fsl_mc_device_id match_id_table[] = {
 635        {
 636         .vendor = FSL_MC_VENDOR_FREESCALE,
 637         .obj_type = "dpbp",
 638        },
 639        {
 640         .vendor = FSL_MC_VENDOR_FREESCALE,
 641         .obj_type = "dpmcp",
 642        },
 643        {
 644         .vendor = FSL_MC_VENDOR_FREESCALE,
 645         .obj_type = "dpcon",
 646        },
 647        {.vendor = 0x0},
 648};
 649
 650static struct fsl_mc_driver fsl_mc_allocator_driver = {
 651        .driver = {
 652                   .name = "fsl_mc_allocator",
 653                   .pm = NULL,
 654                   },
 655        .match_id_table = match_id_table,
 656        .probe = fsl_mc_allocator_probe,
 657        .remove = fsl_mc_allocator_remove,
 658};
 659
 660int __init fsl_mc_allocator_driver_init(void)
 661{
 662        return fsl_mc_driver_register(&fsl_mc_allocator_driver);
 663}
 664
 665void fsl_mc_allocator_driver_exit(void)
 666{
 667        fsl_mc_driver_unregister(&fsl_mc_allocator_driver);
 668}
 669