lkml.org 
[lkml]   [2015]   [May]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 1/7] staging: fsl-mc: MC bus IRQ support
    Date
    All the IRQs for DPAA2 objects in the same DPRC must use
    the ICID of that DPRC, as their device Id in the GIC-ITS.
    Thus, all these IRQs must share the same ITT table in GIC. As
    a result, a pool of IRQs with the same device Id must be
    preallocated per DPRC (fsl-mc bus instance). So, the fsl-mc
    bus object allocator is extended to also provide services
    to allocate IRQs to DPAA2 devices, from their parent fsl-mc bus
    IRQ pool.

    Also, the interrupt handler for DPRC IRQs is added. DPRC IRQs are
    generated for hot plug events related to DPAA2 objects in a given
    DPRC. These events include, creating/destroying DPAA2 objects in
    the DPRC, changing the "plugged" state of DPAA2 objects and moving
    objects between DPRCs.

    Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
    Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com>
    ---
    Changes in v2:
    - Addressed comments from Dan Carpenter and Scott Wood:
    * Removed unnecessary lines from commit messages
    * Replaced single error cleanup label with multiple labels, one for
    each error case and return directly when no cleanup is needed.
    * Fixed conditional alignment
    * Removed error messages for devm_kzalloc() errors
    * Removed WARN_ON in dprc_irq0_handler_thread()
    * Removed devm_kfree() calls

    drivers/staging/fsl-mc/TODO | 3 +
    drivers/staging/fsl-mc/bus/dprc-driver.c | 351 +++++++++++++++++++++++----
    drivers/staging/fsl-mc/bus/mc-allocator.c | 102 +++++++-
    drivers/staging/fsl-mc/bus/mc-bus.c | 364 +++++++++++++++++++++++++++-
    drivers/staging/fsl-mc/include/mc-private.h | 26 +-
    drivers/staging/fsl-mc/include/mc.h | 25 ++
    6 files changed, 808 insertions(+), 63 deletions(-)

    diff --git a/drivers/staging/fsl-mc/TODO b/drivers/staging/fsl-mc/TODO
    index d78288b..1b8868d 100644
    --- a/drivers/staging/fsl-mc/TODO
    +++ b/drivers/staging/fsl-mc/TODO
    @@ -8,6 +8,9 @@
    * Add at least one device driver for a DPAA2 object (child device of the
    fsl-mc bus).

    +* Enable code blocks guarded by #ifdef GIC_ITS_MC_SUPPORT, when GIC-ITS
    + support for the MC MSIs gets merged.
    +
    Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
    german.rivera@freescale.com, devel@driverdev.osuosl.org,
    linux-kernel@vger.kernel.org
    diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
    index 35c06cf..7504466 100644
    --- a/drivers/staging/fsl-mc/bus/dprc-driver.c
    +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
    @@ -13,6 +13,7 @@
    #include "../include/mc-sys.h"
    #include <linux/module.h>
    #include <linux/slab.h>
    +#include <linux/interrupt.h>
    #include "dprc-cmd.h"

    struct dprc_child_objs {
    @@ -206,41 +207,11 @@ static void dprc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
    }
    }

    -static void dprc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev,
    - enum fsl_mc_pool_type pool_type)
    -{
    - struct fsl_mc_resource *resource;
    - struct fsl_mc_resource *next;
    - struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
    - struct fsl_mc_resource_pool *res_pool =
    - &mc_bus->resource_pools[pool_type];
    - int free_count = 0;
    -
    - WARN_ON(res_pool->type != pool_type);
    - WARN_ON(res_pool->free_count != res_pool->max_count);
    -
    - list_for_each_entry_safe(resource, next, &res_pool->free_list, node) {
    - free_count++;
    - WARN_ON(resource->type != res_pool->type);
    - WARN_ON(resource->parent_pool != res_pool);
    - devm_kfree(&mc_bus_dev->dev, resource);
    - }
    -
    - WARN_ON(free_count != res_pool->free_count);
    -}
    -
    -static void dprc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
    -{
    - int pool_type;
    -
    - for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++)
    - dprc_cleanup_resource_pool(mc_bus_dev, pool_type);
    -}
    -
    /**
    * dprc_scan_objects - Discover objects in a DPRC
    *
    * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
    + * @total_irq_count: total number of IRQs needed by objects in the DPRC.
    *
    * Detects objects added and removed from a DPRC and synchronizes the
    * state of the Linux bus driver, MC by adding and removing
    @@ -254,11 +225,13 @@ static void dprc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
    * populated before they can get allocation requests from probe callbacks
    * of the device drivers for the non-allocatable devices.
    */
    -int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev)
    +int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
    + unsigned int *total_irq_count)
    {
    int num_child_objects;
    int dprc_get_obj_failures;
    int error;
    + unsigned int irq_count = mc_bus_dev->obj_desc.irq_count;
    struct dprc_obj_desc *child_obj_desc_array = NULL;

    error = dprc_get_obj_count(mc_bus_dev->mc_io,
    @@ -274,9 +247,9 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev)
    int i;

    child_obj_desc_array =
    - devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects,
    - sizeof(*child_obj_desc_array),
    - GFP_KERNEL);
    + kmalloc_array(num_child_objects,
    + sizeof(*child_obj_desc_array),
    + GFP_KERNEL);
    if (!child_obj_desc_array)
    return -ENOMEM;

    @@ -305,6 +278,7 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev)
    continue;
    }

    + irq_count += obj_desc->irq_count;
    dev_dbg(&mc_bus_dev->dev,
    "Discovered object: type %s, id %d\n",
    obj_desc->type, obj_desc->id);
    @@ -317,15 +291,14 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev)
    }
    }

    + *total_irq_count = irq_count;
    dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
    num_child_objects);

    dprc_add_new_devices(mc_bus_dev, child_obj_desc_array,
    num_child_objects);

    - if (child_obj_desc_array)
    - devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
    -
    + kfree(child_obj_desc_array);
    return 0;
    }
    EXPORT_SYMBOL_GPL(dprc_scan_objects);
    @@ -339,9 +312,10 @@ EXPORT_SYMBOL_GPL(dprc_scan_objects);
    * bus driver with the actual state of the MC by adding and removing
    * devices as appropriate.
    */
    -int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
    +static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
    {
    int error;
    + unsigned int irq_count;
    struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);

    dprc_init_all_resource_pools(mc_bus_dev);
    @@ -350,17 +324,280 @@ int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
    * Discover objects in the DPRC:
    */
    mutex_lock(&mc_bus->scan_mutex);
    - error = dprc_scan_objects(mc_bus_dev);
    + error = dprc_scan_objects(mc_bus_dev, &irq_count);
    mutex_unlock(&mc_bus->scan_mutex);
    if (error < 0)
    - goto error;
    + return error;
    +
    + if (!mc_bus->irq_resources) {
    + irq_count += FSL_MC_IRQ_POOL_MAX_EXTRA_IRQS;
    + error = fsl_mc_populate_irq_pool(mc_bus, irq_count);
    + if (error < 0)
    + return error;
    + }
    +
    + return 0;
    +}
    +
    +/**
    + * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
    + *
    + * @irq: IRQ number of the interrupt being handled
    + * @arg: Pointer to device structure
    + */
    +static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
    +{
    + return IRQ_WAKE_THREAD;
    +}
    +
    +/**
    + * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
    + *
    + * @irq: IRQ number of the interrupt being handled
    + * @arg: Pointer to device structure
    + */
    +static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
    +{
    + int error;
    + uint32_t status;
    + struct device *dev = (struct device *)arg;
    + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
    + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
    + struct fsl_mc_io *mc_io = mc_dev->mc_io;
    + int irq_index = 0;
    +
    + dev_dbg(dev, "DPRC IRQ %d\n", irq_num);
    + if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
    + return IRQ_HANDLED;
    +
    + mutex_lock(&mc_bus->scan_mutex);
    + if (WARN_ON(mc_dev->irqs[irq_index]->irq_number != (uint32_t)irq_num))
    + goto out;
    +
    + error = dprc_get_irq_status(mc_io, mc_dev->mc_handle, irq_index,
    + &status);
    + if (error < 0) {
    + dev_err(dev,
    + "dprc_get_irq_status() failed: %d\n", error);
    + goto out;
    + }
    +
    + error = dprc_clear_irq_status(mc_io, mc_dev->mc_handle, irq_index,
    + status);
    + if (error < 0) {
    + dev_err(dev,
    + "dprc_clear_irq_status() failed: %d\n", error);
    + goto out;
    + }
    +
    + if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
    + DPRC_IRQ_EVENT_OBJ_REMOVED |
    + DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
    + DPRC_IRQ_EVENT_OBJ_DESTROYED |
    + DPRC_IRQ_EVENT_OBJ_CREATED)) {
    + unsigned int irq_count;
    +
    + error = dprc_scan_objects(mc_dev, &irq_count);
    + if (error < 0) {
    + dev_err(dev, "dprc_scan_objects() failed: %d\n", error);
    + goto out;
    + }
    +
    + if (irq_count >
    + mc_bus->resource_pools[FSL_MC_POOL_IRQ].max_count) {
    + dev_warn(dev,
    + "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
    + irq_count,
    + mc_bus->resource_pools[FSL_MC_POOL_IRQ].
    + max_count);
    + }
    + }
    +
    +out:
    + mutex_unlock(&mc_bus->scan_mutex);
    + return IRQ_HANDLED;
    +}
    +
    +/*
    + * Disable and clear interrupts for a given DPRC object
    + */
    +static int disable_dprc_irqs(struct fsl_mc_device *mc_dev)
    +{
    + int i;
    + int error;
    + struct fsl_mc_io *mc_io = mc_dev->mc_io;
    + int irq_count = mc_dev->obj_desc.irq_count;
    +
    + if (WARN_ON(irq_count == 0))
    + return -EINVAL;
    +
    + for (i = 0; i < irq_count; i++) {
    + /*
    + * Disable generation of interrupt i, while we configure it:
    + */
    + error = dprc_set_irq_enable(mc_io, mc_dev->mc_handle, i, 0);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "dprc_set_irq_enable() failed: %d\n", error);
    +
    + return error;
    + }
    +
    + /*
    + * Disable all interrupt causes for interrupt i:
    + */
    + error = dprc_set_irq_mask(mc_io, mc_dev->mc_handle, i, 0x0);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "dprc_set_irq_mask() failed: %d\n", error);
    +
    + return error;
    + }
    +
    + /*
    + * Clear any leftover interrupt i:
    + */
    + error = dprc_clear_irq_status(mc_io, mc_dev->mc_handle, i,
    + ~0x0U);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "dprc_clear_irq_status() failed: %d\n",
    + error);
    + return error;
    + }
    + }
    +
    + return 0;
    +}
    +
    +static int register_dprc_irq_handlers(struct fsl_mc_device *mc_dev)
    +{
    + static const struct irq_handler {
    + irq_handler_t irq_handler;
    + irq_handler_t irq_handler_thread;
    + const char *irq_name;
    + } irq_handlers[] = {
    + [0] = {
    + .irq_handler = dprc_irq0_handler,
    + .irq_handler_thread = dprc_irq0_handler_thread,
    + .irq_name = "FSL MC DPRC irq0",
    + },
    + };
    +
    + unsigned int i;
    + int error;
    + struct fsl_mc_device_irq *irq;
    + int irq_count = mc_dev->obj_desc.irq_count;
    +
    + if (WARN_ON(irq_count != ARRAY_SIZE(irq_handlers)))
    + return -EINVAL;
    +
    + for (i = 0; i < ARRAY_SIZE(irq_handlers); i++) {
    + irq = mc_dev->irqs[i];
    + error = devm_request_threaded_irq(&mc_dev->dev,
    + irq->irq_number,
    + irq_handlers[i].irq_handler,
    + irq_handlers[i].
    + irq_handler_thread,
    + IRQF_NO_SUSPEND |
    + IRQF_ONESHOT,
    + irq_handlers[i].irq_name,
    + &mc_dev->dev);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "devm_request_threaded_irq() failed: %d\n",
    + error);
    + return error;
    + }
    +
    + /*
    + * Program the MSI (paddr, value) pair in the device:
    + *
    + * TODO: This needs to be moved to mc_bus_msi_domain_write_msg()
    + * when the MC object-independent dprc_set_irq() flib API
    + * becomes available
    + */
    + error = dprc_set_irq(mc_dev->mc_io, mc_dev->mc_handle,
    + i, irq->msi_paddr,
    + irq->msi_value,
    + irq->irq_number);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "mc_set_irq() failed: %d\n", error);
    + return error;
    + }
    + }
    +
    + return 0;
    +}
    +
    +static int enable_dprc_irqs(struct fsl_mc_device *mc_dev)
    +{
    + int i;
    + int error;
    + int irq_count = mc_dev->obj_desc.irq_count;
    +
    + for (i = 0; i < irq_count; i++) {
    + /*
    + * Enable all interrupt causes for the interrupt:
    + */
    + error = dprc_set_irq_mask(mc_dev->mc_io,
    + mc_dev->mc_handle,
    + i,
    + ~0x0u);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "dprc_set_irq_mask() failed: %d\n", error);
    +
    + return error;
    + }
    +
    + /*
    + * Enable generation of the interrupt:
    + */
    + error = dprc_set_irq_enable(mc_dev->mc_io,
    + mc_dev->mc_handle,
    + i, 1);
    + if (error < 0) {
    + dev_err(&mc_dev->dev,
    + "dprc_set_irq_enable() failed: %d\n", error);
    +
    + return error;
    + }
    + }
    +
    + return 0;
    +}
    +
    +/*
    + * Setup interrupts for a given DPRC device
    + */
    +static int dprc_setup_irqs(struct fsl_mc_device *mc_dev)
    +{
    + int error;
    +
    + error = fsl_mc_allocate_irqs(mc_dev);
    + if (error < 0)
    + return error;
    +
    + error = disable_dprc_irqs(mc_dev);
    + if (error < 0)
    + goto error_free_irqs;
    +
    + error = register_dprc_irq_handlers(mc_dev);
    + if (error < 0)
    + goto error_free_irqs;
    +
    + error = enable_dprc_irqs(mc_dev);
    + if (error < 0)
    + goto error_free_irqs;

    return 0;
    -error:
    - dprc_cleanup_all_resource_pools(mc_bus_dev);
    +
    +error_free_irqs:
    + fsl_mc_free_irqs(mc_dev);
    return error;
    }
    -EXPORT_SYMBOL_GPL(dprc_scan_container);

    /**
    * dprc_probe - callback invoked when a DPRC is being bound to this driver
    @@ -415,10 +652,20 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
    if (error < 0)
    goto error_cleanup_open;

    + /*
    + * Configure interrupts for the DPRC object associated with this MC bus:
    + */
    + error = dprc_setup_irqs(mc_dev);
    + if (error < 0)
    + goto error_cleanup_open;
    +
    dev_info(&mc_dev->dev, "DPRC device bound to driver");
    return 0;

    error_cleanup_open:
    + if (mc_bus->irq_resources)
    + fsl_mc_cleanup_irq_pool(mc_bus);
    +
    (void)dprc_close(mc_dev->mc_io, mc_dev->mc_handle);

    error_cleanup_mc_io:
    @@ -426,6 +673,15 @@ error_cleanup_mc_io:
    return error;
    }

    +/*
    + * Tear down interrupts for a given DPRC object
    + */
    +static void dprc_teardown_irqs(struct fsl_mc_device *mc_dev)
    +{
    + (void)disable_dprc_irqs(mc_dev);
    + fsl_mc_free_irqs(mc_dev);
    +}
    +
    /**
    * dprc_remove - callback invoked when a DPRC is being unbound from this driver
    *
    @@ -439,18 +695,23 @@ error_cleanup_mc_io:
    static int dprc_remove(struct fsl_mc_device *mc_dev)
    {
    int error;
    + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);

    if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
    return -EINVAL;
    if (WARN_ON(!mc_dev->mc_io))
    return -EINVAL;

    + if (WARN_ON(!mc_bus->irq_resources))
    + return -EINVAL;
    +
    + dprc_teardown_irqs(mc_dev);
    device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
    - dprc_cleanup_all_resource_pools(mc_dev);
    error = dprc_close(mc_dev->mc_io, mc_dev->mc_handle);
    if (error < 0)
    dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error);

    + fsl_mc_cleanup_irq_pool(mc_bus);
    dev_info(&mc_dev->dev, "DPRC device unbound from driver");
    return 0;
    }
    diff --git a/drivers/staging/fsl-mc/bus/mc-allocator.c b/drivers/staging/fsl-mc/bus/mc-allocator.c
    index e36235d..aa8280a 100644
    --- a/drivers/staging/fsl-mc/bus/mc-allocator.c
    +++ b/drivers/staging/fsl-mc/bus/mc-allocator.c
    @@ -66,8 +66,6 @@ static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus
    GFP_KERNEL);
    if (!resource) {
    error = -ENOMEM;
    - dev_err(&mc_bus_dev->dev,
    - "Failed to allocate memory for fsl_mc_resource\n");
    goto out;
    }

    @@ -145,8 +143,6 @@ static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device
    INIT_LIST_HEAD(&resource->node);
    res_pool->free_count--;
    res_pool->max_count--;
    -
    - devm_kfree(&mc_bus_dev->dev, resource);
    mc_dev->resource = NULL;
    error = 0;
    out:
    @@ -160,6 +156,7 @@ static const char *const fsl_mc_pool_type_strings[] = {
    [FSL_MC_POOL_DPMCP] = "dpmcp",
    [FSL_MC_POOL_DPBP] = "dpbp",
    [FSL_MC_POOL_DPCON] = "dpcon",
    + [FSL_MC_POOL_IRQ] = "irq",
    };

    static int __must_check object_type_to_pool_type(const char *object_type,
    @@ -473,6 +470,103 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
    EXPORT_SYMBOL_GPL(fsl_mc_object_free);

    /**
    + * It allocates the IRQs required by a given MC object device. The
    + * IRQs are allocated from the interrupt pool associated with the
    + * MC bus that contains the device, if the device is not a DPRC device.
    + * Otherwise, the IRQs are allocated from the interrupt pool associated
    + * with the MC bus that represents the DPRC device itself.
    + */
    +int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
    +{
    + int i;
    + int irq_count;
    + int res_allocated_count = 0;
    + int error = -EINVAL;
    + struct fsl_mc_device_irq **irqs = NULL;
    + struct fsl_mc_bus *mc_bus;
    + struct fsl_mc_resource_pool *res_pool;
    +
    + if (WARN_ON(mc_dev->irqs))
    + return -EINVAL;
    +
    + irq_count = mc_dev->obj_desc.irq_count;
    + if (WARN_ON(irq_count == 0))
    + return -EINVAL;
    +
    + if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
    + mc_bus = to_fsl_mc_bus(mc_dev);
    + else
    + mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
    +
    + if (WARN_ON(!mc_bus->irq_resources))
    + return -EINVAL;
    +
    + res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
    + if (res_pool->free_count < irq_count) {
    + dev_err(&mc_dev->dev,
    + "Not able to allocate %u irqs for device\n", irq_count);
    + return -ENOSPC;
    + }
    +
    + irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]),
    + GFP_KERNEL);
    + if (!irqs)
    + return -ENOMEM;
    +
    + for (i = 0; i < irq_count; i++) {
    + struct fsl_mc_resource *resource;
    +
    + error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ,
    + &resource);
    + if (error < 0)
    + goto error_resource_alloc;
    +
    + irqs[i] = to_fsl_mc_irq(resource);
    + res_allocated_count++;
    + }
    +
    + mc_dev->irqs = irqs;
    + return 0;
    +
    +error_resource_alloc:
    + for (i = 0; i < res_allocated_count; i++)
    + fsl_mc_resource_free(&irqs[i]->resource);
    +
    + return error;
    +}
    +EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs);
    +
    +/*
    + * It frees the IRQs that were allocated for a MC object device, by
    + * returning them to the corresponding interrupt pool.
    + */
    +void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
    +{
    + int i;
    + int irq_count;
    + struct fsl_mc_bus *mc_bus;
    +
    + if (WARN_ON(!mc_dev->irqs))
    + return;
    +
    + irq_count = mc_dev->obj_desc.irq_count;
    +
    + if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
    + mc_bus = to_fsl_mc_bus(mc_dev);
    + else
    + mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
    +
    + if (WARN_ON(!mc_bus->irq_resources))
    + return;
    +
    + for (i = 0; i < irq_count; i++)
    + fsl_mc_resource_free(&mc_dev->irqs[i]->resource);
    +
    + mc_dev->irqs = NULL;
    +}
    +EXPORT_SYMBOL_GPL(fsl_mc_free_irqs);
    +
    +/**
    * fsl_mc_allocator_probe - callback invoked when an allocatable device is
    * being added to the system
    */
    diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c
    index 23512d0..d51120a 100644
    --- a/drivers/staging/fsl-mc/bus/mc-bus.c
    +++ b/drivers/staging/fsl-mc/bus/mc-bus.c
    @@ -15,11 +15,27 @@
    #include <linux/of_address.h>
    #include <linux/ioport.h>
    #include <linux/slab.h>
    +#include <linux/irqchip/arm-gic-v3.h>
    +#include <linux/irq.h>
    +#include <linux/irqdomain.h>
    #include <linux/limits.h>
    +#include <linux/bitops.h>
    #include "../include/dpmng.h"
    #include "../include/mc-sys.h"
    #include "dprc-cmd.h"

    +/*
    + * IOMMU stream ID flags
    + */
    +#define STREAM_ID_PL_MASK BIT(9) /* privilege level */
    +#define STREAM_ID_BMT_MASK BIT(8) /* bypass memory translation */
    +#define STREAM_ID_VA_MASK BIT(7) /* virtual address translation
    + * (two-stage translation) */
    +#define STREAM_ID_ICID_MASK (BIT(7) - 1) /* isolation context ID
    + * (translation context) */
    +
    +#define MAX_STREAM_ID_ICID STREAM_ID_ICID_MASK
    +
    static struct kmem_cache *mc_dev_cache;

    /**
    @@ -295,8 +311,9 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
    &regions[i].start);
    if (error < 0) {
    dev_err(parent_dev,
    - "Invalid MC address: %#llx\n",
    - region_desc.base_paddr);
    + "Invalid MC address: %#llx (for %s.%d\'s region %d)\n",
    + region_desc.base_paddr,
    + obj_desc->type, obj_desc->id, i);
    goto error_cleanup_regions;
    }

    @@ -335,7 +352,7 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
    /*
    * Allocate an MC bus device object:
    */
    - mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL);
    + mc_bus = kzalloc(sizeof(*mc_bus), GFP_KERNEL);
    if (!mc_bus)
    return -ENOMEM;

    @@ -352,6 +369,13 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
    mc_dev->obj_desc = *obj_desc;
    mc_dev->mc_io = mc_io;
    device_initialize(&mc_dev->dev);
    +
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + INIT_LIST_HEAD(&mc_dev->dev.msi_list);
    +#endif
    mc_dev->dev.parent = parent_dev;
    mc_dev->dev.bus = &fsl_mc_bus_type;
    dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id);
    @@ -437,10 +461,10 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,

    error_cleanup_dev:
    kfree(mc_dev->regions);
    - if (mc_bus)
    - devm_kfree(parent_dev, mc_bus);
    - else
    + if (!mc_bus)
    kmem_cache_free(mc_dev_cache, mc_dev);
    + else
    + kfree(mc_bus);

    return error;
    }
    @@ -475,13 +499,317 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
    fsl_mc_bus_type.dev_root = NULL;
    }

    - if (mc_bus)
    - devm_kfree(mc_dev->dev.parent, mc_bus);
    - else
    + if (!mc_bus)
    kmem_cache_free(mc_dev_cache, mc_dev);
    + else
    + kfree(mc_bus);
    }
    EXPORT_SYMBOL_GPL(fsl_mc_device_remove);

    +/*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    +static int mc_bus_msi_prepare(struct irq_domain *domain, struct device *dev,
    + int nvec, msi_alloc_info_t *info)
    +{
    + int error;
    + u32 its_dev_id;
    + struct dprc_attributes dprc_attr;
    + struct fsl_mc_device *mc_bus_dev = to_fsl_mc_device(dev);
    +
    + if (WARN_ON(!(mc_bus_dev->flags & FSL_MC_IS_DPRC)))
    + return -EINVAL;
    +
    + error = dprc_get_attributes(mc_bus_dev->mc_io,
    + mc_bus_dev->mc_handle, &dprc_attr);
    + if (error < 0) {
    + dev_err(&mc_bus_dev->dev,
    + "dprc_get_attributes() failed: %d\n",
    + error);
    + return error;
    + }
    +
    + /*
    + * Build the device Id to be passed to the GIC-ITS:
    + *
    + * NOTE: This device id corresponds to the IOMMU stream ID
    + * associated with the DPRC object.
    + */
    + its_dev_id = mc_bus_dev->icid;
    + if (its_dev_id > STREAM_ID_ICID_MASK) {
    + dev_err(&mc_bus_dev->dev,
    + "Invalid ICID: %#x\n", its_dev_id);
    + return -ERANGE;
    + }
    +
    + if (dprc_attr.options & DPRC_CFG_OPT_IOMMU_BYPASS)
    + its_dev_id |= STREAM_ID_PL_MASK | STREAM_ID_BMT_MASK;
    +
    + return __its_msi_prepare(domain->parent, its_dev_id, dev, nvec, info);
    +}
    +
    +static void mc_bus_mask_msi_irq(struct irq_data *d)
    +{
    + /* Bus specefic Mask */
    + irq_chip_mask_parent(d);
    +}
    +
    +static void mc_bus_unmask_msi_irq(struct irq_data *d)
    +{
    + /* Bus specefic unmask */
    + irq_chip_unmask_parent(d);
    +}
    +
    +static void mc_bus_msi_domain_write_msg(struct irq_data *irq_data,
    + struct msi_msg *msg)
    +{
    + struct msi_desc *msi_entry = irq_data->msi_desc;
    + struct fsl_mc_device *mc_bus_dev = to_fsl_mc_device(msi_entry->dev);
    + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
    + struct fsl_mc_device_irq *irq_res =
    + &mc_bus->irq_resources[msi_entry->msi_attrib.entry_nr];
    +
    + if (irq_res->irq_number == irq_data->irq) {
    + /*
    + * write msg->address_hi/lo to irq_resource
    + */
    + irq_res->msi_paddr =
    + ((u64)msg->address_hi << 32) | msg->address_lo;
    + irq_res->msi_value = msg->data;
    + }
    +}
    +
    +static struct irq_chip mc_bus_msi_irq_chip = {
    + .name = "fsl-mc-bus-msi",
    + .irq_unmask = mc_bus_unmask_msi_irq,
    + .irq_mask = mc_bus_mask_msi_irq,
    + .irq_eoi = irq_chip_eoi_parent,
    + .irq_write_msi_msg = mc_bus_msi_domain_write_msg,
    +};
    +
    +static struct msi_domain_ops mc_bus_msi_ops = {
    + .msi_prepare = mc_bus_msi_prepare,
    +};
    +
    +static struct msi_domain_info mc_bus_msi_domain_info = {
    + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
    + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
    + .ops = &mc_bus_msi_ops,
    + .chip = &mc_bus_msi_irq_chip,
    +};
    +
    +static int create_mc_irq_domain(struct platform_device *mc_pdev,
    + struct irq_domain **new_irq_domain)
    +{
    + int error;
    + struct device_node *its_of_node;
    + struct irq_domain *its_domain;
    + struct irq_domain *irq_domain;
    + struct device_node *mc_of_node = mc_pdev->dev.of_node;
    +
    + its_of_node = of_parse_phandle(mc_of_node, "lpi-parent", 0);
    + if (!its_of_node) {
    + dev_err(&mc_pdev->dev,
    + "lpi-parent phandle missing for %s\n",
    + mc_of_node->full_name);
    + return -ENOENT;
    + }
    +
    + /*
    + * Extract MSI parent node:
    + */
    + its_domain = irq_find_host(its_of_node);
    + if (!its_domain) {
    + dev_err(&mc_pdev->dev, "Unable to find parent domain\n");
    + error = -ENOENT;
    + goto cleanup_its_of_node;
    + }
    +
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + irq_domain = msi_create_irq_domain(mc_of_node, &mc_bus_msi_domain_info,
    + its_domain->parent);
    + if (!irq_domain) {
    + dev_err(&mc_pdev->dev, "Failed to allocate msi_domain\n");
    + error = -ENOMEM;
    + goto cleanup_its_of_node;
    + }
    +
    + dev_dbg(&mc_pdev->dev, "Allocated MSI domain\n");
    +#else
    + irq_domain = NULL;
    +#endif
    + *new_irq_domain = irq_domain;
    + return 0;
    +
    +cleanup_its_of_node:
    + of_node_put(its_of_node);
    + return error;
    +}
    +#endif /* GIC_ITS_MC_SUPPORT */
    +
    +/*
    + * Initialize the interrupt pool associated with a MC bus.
    + * It allocates a block of IRQs from the GIC-ITS
    + */
    +int __must_check fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
    + unsigned int irq_count)
    +{
    + unsigned int i;
    + struct fsl_mc_device_irq *irq_resources;
    + struct fsl_mc_device_irq *irq_res;
    + struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev;
    + struct fsl_mc_resource_pool *res_pool =
    + &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + int error;
    + struct msi_desc *msi_entry;
    + struct msi_desc *next_msi_entry;
    + struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
    +
    + /*
    + * Detect duplicate invocations of this function:
    + */
    + if (WARN_ON(!list_empty(&mc_bus_dev->dev.msi_list)))
    + return -EINVAL;
    +#endif
    +
    + if (WARN_ON(irq_count == 0 ||
    + irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS))
    + return -EINVAL;
    +
    + irq_resources =
    + devm_kzalloc(&mc_bus_dev->dev,
    + sizeof(*irq_resources) * irq_count,
    + GFP_KERNEL);
    + if (!irq_resources)
    + return -ENOMEM;
    +
    + for (i = 0; i < irq_count; i++) {
    + irq_res = &irq_resources[i];
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + msi_entry = alloc_msi_entry(&mc_bus_dev->dev);
    + if (!msi_entry) {
    + dev_err(&mc_bus_dev->dev, "Failed to allocate msi entry\n");
    + error = -ENOMEM;
    + goto cleanup_msi_entries;
    + }
    +
    + msi_entry->msi_attrib.is_msix = 1;
    + msi_entry->msi_attrib.is_64 = 1;
    + msi_entry->msi_attrib.entry_nr = i;
    + msi_entry->nvec_used = 1;
    + list_add_tail(&msi_entry->list, &mc_bus_dev->dev.msi_list);
    +#endif
    +
    + /*
    + * NOTE: irq_res->msi_paddr will be set by the
    + * mc_bus_msi_domain_write_msg() callback
    + */
    + irq_res->resource.type = res_pool->type;
    + irq_res->resource.data = irq_res;
    + irq_res->resource.parent_pool = res_pool;
    + INIT_LIST_HEAD(&irq_res->resource.node);
    + list_add_tail(&irq_res->resource.node, &res_pool->free_list);
    + }
    +
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + /*
    + * NOTE: Calling this function will trigger the invocation of the
    + * mc_bus_msi_prepare() callback
    + */
    + error = msi_domain_alloc_irqs(mc->irq_domain,
    + &mc_bus_dev->dev, irq_count);
    +
    + if (error) {
    + dev_err(&mc_bus_dev->dev, "Failed to allocate IRQs\n");
    + goto cleanup_msi_entries;
    + }
    +#endif
    +
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + for_each_msi_entry(msi_entry, &mc_bus_dev->dev) {
    + u32 irq_num = msi_entry->irq;
    +
    + irq_res = &irq_resources[msi_entry->msi_attrib.entry_nr];
    + irq_res->irq_number = irq_num;
    + irq_res->resource.id = irq_num;
    + }
    +#endif
    +
    + res_pool->max_count = irq_count;
    + res_pool->free_count = irq_count;
    + mc_bus->irq_resources = irq_resources;
    + return 0;
    +
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    +cleanup_msi_entries:
    + list_for_each_entry_safe(msi_entry, next_msi_entry,
    + &mc_bus_dev->dev.msi_list, list)
    + kfree(msi_entry);
    +
    + return error;
    +#endif
    +}
    +EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
    +
    +/**
    + * Teardown the interrupt pool associated with an MC bus.
    + * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
    + */
    +void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus)
    +{
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + struct msi_desc *msi_entry;
    + struct msi_desc *next_msi_entry;
    + struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
    +#endif
    + struct fsl_mc_resource_pool *res_pool =
    + &mc_bus->resource_pools[FSL_MC_POOL_IRQ];
    +
    + if (WARN_ON(res_pool->max_count == 0))
    + return;
    +
    + if (WARN_ON(res_pool->free_count != res_pool->max_count))
    + return;
    +
    + /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + msi_domain_free_irqs(mc->irq_domain, &mc_bus->mc_dev.dev);
    + list_for_each_entry_safe(msi_entry, next_msi_entry,
    + &mc_bus->mc_dev.dev.msi_list, list)
    + kfree(msi_entry);
    +#endif
    +
    + res_pool->max_count = 0;
    + res_pool->free_count = 0;
    + mc_bus->irq_resources = NULL;
    +}
    +EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
    +
    static int parse_mc_ranges(struct device *dev,
    int *paddr_cells,
    int *mc_addr_cells,
    @@ -613,6 +941,15 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
    platform_set_drvdata(pdev, mc);

    /*
    + * FIXME: Enable this code when the GIC-ITS MC support patch is merged
    + */
    +#ifdef GIC_ITS_MC_SUPPORT
    + error = create_mc_irq_domain(pdev, &mc->irq_domain);
    + if (error < 0)
    + return error;
    +#endif
    +
    + /*
    * Get physical address of MC portal for the root DPRC:
    */
    error = of_address_to_resource(pdev->dev.of_node, 0, &res);
    @@ -620,7 +957,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
    dev_err(&pdev->dev,
    "of_address_to_resource() failed for %s\n",
    pdev->dev.of_node->full_name);
    - return error;
    + goto error_cleanup_irq_domain;
    }

    mc_portal_phys_addr = res.start;
    @@ -628,7 +965,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
    error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr,
    mc_portal_size, NULL, 0, &mc_io);
    if (error < 0)
    - return error;
    + goto error_cleanup_irq_domain;

    error = mc_get_version(mc_io, &mc_version);
    if (error != 0) {
    @@ -673,6 +1010,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
    obj_desc.id = container_id;
    obj_desc.ver_major = DPRC_VER_MAJOR;
    obj_desc.ver_minor = DPRC_VER_MINOR;
    + obj_desc.irq_count = 1;
    obj_desc.region_count = 0;

    error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev);
    @@ -684,6 +1022,9 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)

    error_cleanup_mc_io:
    fsl_destroy_mc_io(mc_io);
    +
    +error_cleanup_irq_domain:
    + irq_domain_remove(mc->irq_domain);
    return error;
    }

    @@ -698,6 +1039,7 @@ static int fsl_mc_bus_remove(struct platform_device *pdev)
    if (WARN_ON(&mc->root_mc_bus_dev->dev != fsl_mc_bus_type.dev_root))
    return -EINVAL;

    + irq_domain_remove(mc->irq_domain);
    fsl_mc_device_remove(mc->root_mc_bus_dev);
    dev_info(&pdev->dev, "Root MC bus device removed");
    return 0;
    diff --git a/drivers/staging/fsl-mc/include/mc-private.h b/drivers/staging/fsl-mc/include/mc-private.h
    index c045f49..6e33942 100644
    --- a/drivers/staging/fsl-mc/include/mc-private.h
    +++ b/drivers/staging/fsl-mc/include/mc-private.h
    @@ -27,12 +27,26 @@
    strcmp(_obj_type, "dpcon") == 0)

    /**
    + * Maximum number of total IRQs that can be pre-allocated for an MC bus'
    + * IRQ pool
    + */
    +#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS 256
    +
    +/**
    + * Maximum number of extra IRQs pre-reallocated for an MC bus' IRQ pool,
    + * to be used by dynamically created MC objects
    + */
    +#define FSL_MC_IRQ_POOL_MAX_EXTRA_IRQS 64
    +
    +/**
    * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device
    * @root_mc_bus_dev: MC object device representing the root DPRC
    + * @irq_domain: IRQ domain for the fsl-mc bus type
    * @addr_translation_ranges: array of bus to system address translation ranges
    */
    struct fsl_mc {
    struct fsl_mc_device *root_mc_bus_dev;
    + struct irq_domain *irq_domain;
    uint8_t num_translation_ranges;
    struct fsl_mc_addr_translation_range *translation_ranges;
    };
    @@ -76,11 +90,13 @@ struct fsl_mc_resource_pool {
    * @resource_pools: array of resource pools (one pool per resource type)
    * for this MC bus. These resources represent allocatable entities
    * from the physical DPRC.
    + * @irq_resources: Pointer to array of IRQ objects for the IRQ pool.
    * @scan_mutex: Serializes bus scanning
    */
    struct fsl_mc_bus {
    struct fsl_mc_device mc_dev;
    struct fsl_mc_resource_pool resource_pools[FSL_MC_NUM_POOL_TYPES];
    + struct fsl_mc_device_irq *irq_resources;
    struct mutex scan_mutex; /* serializes bus scanning */
    };

    @@ -94,9 +110,8 @@ int __must_check fsl_mc_device_add(struct dprc_obj_desc *obj_desc,

    void fsl_mc_device_remove(struct fsl_mc_device *mc_dev);

    -int dprc_scan_container(struct fsl_mc_device *mc_bus_dev);
    -
    -int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev);
    +int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
    + unsigned int *total_irq_count);

    int __init dprc_driver_init(void);

    @@ -113,4 +128,9 @@ int __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus,

    void fsl_mc_resource_free(struct fsl_mc_resource *resource);

    +int __must_check fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus,
    + unsigned int irq_count);
    +
    +void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus);
    +
    #endif /* _FSL_MC_PRIVATE_H_ */
    diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h
    index fa02ef0..531cb8c 100644
    --- a/drivers/staging/fsl-mc/include/mc.h
    +++ b/drivers/staging/fsl-mc/include/mc.h
    @@ -14,6 +14,7 @@
    #include <linux/device.h>
    #include <linux/mod_devicetable.h>
    #include <linux/list.h>
    +#include <linux/interrupt.h>
    #include "../include/dprc.h"

    #define FSL_MC_VENDOR_FREESCALE 0x1957
    @@ -75,6 +76,7 @@ enum fsl_mc_pool_type {
    FSL_MC_POOL_DPMCP = 0x0, /* corresponds to "dpmcp" in the MC */
    FSL_MC_POOL_DPBP, /* corresponds to "dpbp" in the MC */
    FSL_MC_POOL_DPCON, /* corresponds to "dpcon" in the MC */
    + FSL_MC_POOL_IRQ,

    /*
    * NOTE: New resource pool types must be added before this entry
    @@ -104,6 +106,23 @@ struct fsl_mc_resource {
    };

    /**
    + * struct fsl_mc_device_irq - MC object device message-based interrupt
    + * @msi_paddr: message-based interrupt physical address
    + * @msi_value: message-based interrupt data value
    + * @irq_number: Linux IRQ number assigned to the interrupt
    + * @resource: MC generic resource associated with the interrupt
    + */
    +struct fsl_mc_device_irq {
    + phys_addr_t msi_paddr;
    + uint32_t msi_value;
    + uint32_t irq_number;
    + struct fsl_mc_resource resource;
    +};
    +
    +#define to_fsl_mc_irq(_mc_resource) \
    + container_of(_mc_resource, struct fsl_mc_device_irq, resource)
    +
    +/**
    * Bit masks for a MC object device (struct fsl_mc_device) flags
    */
    #define FSL_MC_IS_DPRC 0x0001
    @@ -124,6 +143,7 @@ struct fsl_mc_resource {
    * NULL if none.
    * @obj_desc: MC description of the DPAA device
    * @regions: pointer to array of MMIO region entries
    + * @irqs: pointer to array of pointers to interrupts allocated to this device
    * @resource: generic resource associated with this MC object device, if any.
    *
    * Generic device object for MC object devices that are "attached" to a
    @@ -155,6 +175,7 @@ struct fsl_mc_device {
    struct fsl_mc_io *mc_io;
    struct dprc_obj_desc obj_desc;
    struct resource *regions;
    + struct fsl_mc_device_irq **irqs;
    struct fsl_mc_resource *resource;
    };

    @@ -196,6 +217,10 @@ int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev,

    void fsl_mc_object_free(struct fsl_mc_device *mc_adev);

    +int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev);
    +
    +void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev);
    +
    extern struct bus_type fsl_mc_bus_type;

    #endif /* _FSL_MC_H_ */
    --
    2.3.3


    \
     
     \ /
      Last update: 2015-05-07 00:21    [W:5.022 / U:0.140 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site