* [PATCH v4 1/7] staging: fsl-mc: MC bus IRQ support
2015-06-09 21:59 [PATCH v4 0/7] staging: fsl-mc: New functionality to the MC bus driver J. German Rivera
@ 2015-06-09 21:59 ` J. German Rivera
2015-06-09 21:59 ` [PATCH v4 2/7] staging: fsl_-mc: add device binding path 'driver_override' J. German Rivera
` (7 subsequent siblings)
8 siblings, 0 replies; 21+ messages in thread
From: J. German Rivera @ 2015-06-09 21:59 UTC (permalink / raw)
To: gregkh, arnd, devel, linux-kernel
Cc: stuart.yoder, itai.katz, scottwood, agraf, bhamciu1, R89243,
bhupesh.sharma, nir.erez, richard.schmitt, dan.carpenter,
J. German Rivera
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 v4:
- Addressed comments from Dan Carpenter and Greg Kroah-Hartman:
* Removed all #ifdefed-out code
- Fixed new checkpatch "check" warnings
Changes in v3:
- Addressed comments from Dan Carpenter:
* Removed nested redundant #ifdef GIC_ITS_MC_SUPPORT
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/bus/dprc-driver.c | 353 ++++++++++++++++++++++++----
drivers/staging/fsl-mc/bus/mc-allocator.c | 102 +++++++-
drivers/staging/fsl-mc/bus/mc-bus.c | 156 +++++++++++-
drivers/staging/fsl-mc/include/mc-private.h | 26 +-
drivers/staging/fsl-mc/include/mc.h | 29 ++-
5 files changed, 599 insertions(+), 67 deletions(-)
diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 35c06cf..5351170 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 {
@@ -126,7 +127,7 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
struct dprc_obj_desc *obj_desc)
{
int error;
- uint32_t plugged_flag_at_mc =
+ u32 plugged_flag_at_mc =
(obj_desc->state & DPRC_OBJ_STATE_PLUGGED);
if (plugged_flag_at_mc !=
@@ -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;
+ u32 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 != (u32)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 766a659..9d98828 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,
®ions[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;
@@ -437,10 +454,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 +492,120 @@ 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);
+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 device_node *mc_of_node = mc_pdev->dev.of_node;
+
+ its_of_node = of_parse_phandle(mc_of_node, "msi-parent", 0);
+ if (!its_of_node) {
+ dev_err(&mc_pdev->dev,
+ "msi-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;
+ }
+
+ /*
+ * TODO: Call msi_create_irq_domain() to create IRQ domain for MC MSIs
+ * when complete GIC-ITS support * for generic MSIs is upstream. On
+ * success, set mc->gic_supported to true.
+ */
+ *new_irq_domain = NULL;
+ dev_err(&mc_pdev->dev, "Cannot create MSI domain\n");
+ error = -ENOTSUPP;
+
+cleanup_its_of_node:
+ of_node_put(its_of_node);
+ return error;
+}
+
+/*
+ * 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];
+
+ 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];
+ /*
+ * TODO: set irq_res->msi_paddr and irq_res->irq_number with
+ * values obtained from the GIC-ITS.
+ * Also, set irq_res->resource.id to irq_number.
+ */
+ 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);
+ }
+
+ res_pool->max_count = irq_count;
+ res_pool->free_count = irq_count;
+ mc_bus->irq_resources = irq_resources;
+ return 0;
+}
+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)
+{
+ 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;
+
+ 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,
@@ -600,7 +724,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
struct fsl_mc_io *mc_io = NULL;
int container_id;
phys_addr_t mc_portal_phys_addr;
- uint32_t mc_portal_size;
+ u32 mc_portal_size;
struct mc_version mc_version;
struct resource res;
@@ -611,6 +735,9 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, mc);
+ error = create_mc_irq_domain(pdev, &mc->irq_domain);
+ if (error < 0)
+ return error;
/*
* Get physical address of MC portal for the root DPRC:
@@ -620,7 +747,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 +755,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 +800,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 +812,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 +829,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..c543a84 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
@@ -61,8 +62,8 @@ struct fsl_mc_driver {
struct fsl_mc_device_match_id {
uint16_t vendor;
const char obj_type[16];
- uint32_t ver_major;
- uint32_t ver_minor;
+ u32 ver_major;
+ u32 ver_minor;
};
/**
@@ -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;
+ u32 msi_value;
+ u32 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
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v4 4/7] staging: fsl-mc: Upgraded MC bus driver to match MC fw 7.0.0
2015-06-09 21:59 [PATCH v4 0/7] staging: fsl-mc: New functionality to the MC bus driver J. German Rivera
` (2 preceding siblings ...)
2015-06-09 21:59 ` [PATCH v4 3/7] staging: fsl-mc: Propagate driver_override for a child DPRC's children J. German Rivera
@ 2015-06-09 21:59 ` J. German Rivera
2015-06-09 21:59 ` [PATCH v4 5/7] staging: fsl-mc: Allow the MC bus driver to run without GIC support J. German Rivera
` (4 subsequent siblings)
8 siblings, 0 replies; 21+ messages in thread
From: J. German Rivera @ 2015-06-09 21:59 UTC (permalink / raw)
To: gregkh, arnd, devel, linux-kernel
Cc: stuart.yoder, itai.katz, scottwood, agraf, bhamciu1, R89243,
bhupesh.sharma, nir.erez, richard.schmitt, dan.carpenter,
J. German Rivera
- Migrated MC bus driver to use DPRC API 0.6.
- Changed IRQ setup infrastructure to be able to program MSIs
for MC objects in an object-independent way.
Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
---
Changes in v4:
- Fixed new checkpatch warnings and checks
- Add missing error handling in dprc_probe()
drivers/staging/fsl-mc/bus/dpmcp-cmd.h | 79 ---------
drivers/staging/fsl-mc/bus/dprc-cmd.h | 6 +-
drivers/staging/fsl-mc/bus/dprc-driver.c | 64 +++++--
drivers/staging/fsl-mc/bus/dprc.c | 253 +++++++++++++++++++---------
drivers/staging/fsl-mc/bus/mc-allocator.c | 26 ++-
drivers/staging/fsl-mc/bus/mc-bus.c | 58 ++++---
drivers/staging/fsl-mc/bus/mc-sys.c | 8 +-
drivers/staging/fsl-mc/include/dpmng.h | 4 +-
drivers/staging/fsl-mc/include/dprc.h | 244 +++++++++++++++++----------
drivers/staging/fsl-mc/include/mc-private.h | 31 +++-
drivers/staging/fsl-mc/include/mc.h | 4 +
11 files changed, 474 insertions(+), 303 deletions(-)
diff --git a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h
index 57f326b..62bdc18 100644
--- a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h
+++ b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h
@@ -54,83 +54,4 @@
#define DPMCP_CMDID_GET_IRQ_STATUS 0x016
#define DPMCP_CMDID_CLEAR_IRQ_STATUS 0x017
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_CREATE(cmd, cfg) \
- MC_CMD_OP(cmd, 0, 0, 32, int, cfg->portal_id)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_SET_IRQ(cmd, irq_index, irq_addr, irq_val, user_irq_id) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 8, uint8_t, irq_index);\
- MC_CMD_OP(cmd, 0, 32, 32, uint32_t, irq_val);\
- MC_CMD_OP(cmd, 1, 0, 64, uint64_t, irq_addr); \
- MC_CMD_OP(cmd, 2, 0, 32, int, user_irq_id); \
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_GET_IRQ(cmd, irq_index) \
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_RSP_GET_IRQ(cmd, type, irq_addr, irq_val, user_irq_id) \
-do { \
- MC_RSP_OP(cmd, 0, 0, 32, uint32_t, irq_val); \
- MC_RSP_OP(cmd, 1, 0, 64, uint64_t, irq_addr); \
- MC_RSP_OP(cmd, 2, 0, 32, int, user_irq_id); \
- MC_RSP_OP(cmd, 2, 32, 32, int, type); \
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_SET_IRQ_ENABLE(cmd, irq_index, en) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 8, uint8_t, en); \
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_GET_IRQ_ENABLE(cmd, irq_index) \
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_RSP_GET_IRQ_ENABLE(cmd, en) \
- MC_RSP_OP(cmd, 0, 0, 8, uint8_t, en)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_SET_IRQ_MASK(cmd, irq_index, mask) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 32, uint32_t, mask);\
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_GET_IRQ_MASK(cmd, irq_index) \
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_RSP_GET_IRQ_MASK(cmd, mask) \
- MC_RSP_OP(cmd, 0, 0, 32, uint32_t, mask)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_GET_IRQ_STATUS(cmd, irq_index) \
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_RSP_GET_IRQ_STATUS(cmd, status) \
- MC_RSP_OP(cmd, 0, 0, 32, uint32_t, status)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status); \
- MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMCP_RSP_GET_ATTRIBUTES(cmd, attr) \
-do { \
- MC_RSP_OP(cmd, 0, 32, 32, int, attr->id);\
- MC_RSP_OP(cmd, 1, 0, 16, uint16_t, attr->version.major);\
- MC_RSP_OP(cmd, 1, 16, 16, uint16_t, attr->version.minor);\
-} while (0)
-
#endif /* _FSL_DPMCP_CMD_H */
diff --git a/drivers/staging/fsl-mc/bus/dprc-cmd.h b/drivers/staging/fsl-mc/bus/dprc-cmd.h
index 0920248..df5ad5f 100644
--- a/drivers/staging/fsl-mc/bus/dprc-cmd.h
+++ b/drivers/staging/fsl-mc/bus/dprc-cmd.h
@@ -41,7 +41,7 @@
#define _FSL_DPRC_CMD_H
/* DPRC Version */
-#define DPRC_VER_MAJOR 3
+#define DPRC_VER_MAJOR 4
#define DPRC_VER_MINOR 0
/* Command IDs */
@@ -72,12 +72,14 @@
#define DPRC_CMDID_GET_RES_COUNT 0x15B
#define DPRC_CMDID_GET_RES_IDS 0x15C
#define DPRC_CMDID_GET_OBJ_REG 0x15E
+#define DPRC_CMDID_OBJ_SET_IRQ 0x15F
+#define DPRC_CMDID_OBJ_GET_IRQ 0x160
+#define DPRC_CMDID_SET_OBJ_LABEL 0x161
#define DPRC_CMDID_CONNECT 0x167
#define DPRC_CMDID_DISCONNECT 0x168
#define DPRC_CMDID_GET_POOL 0x169
#define DPRC_CMDID_GET_POOL_COUNT 0x16A
-#define DPRC_CMDID_GET_PORTAL_PADDR 0x16B
#define DPRC_CMDID_GET_CONNECTION 0x16C
diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 85ec91b..6bd20c0 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -500,6 +500,19 @@ static int register_dprc_irq_handlers(struct fsl_mc_device *mc_dev)
for (i = 0; i < ARRAY_SIZE(irq_handlers); i++) {
irq = mc_dev->irqs[i];
+
+ if (WARN_ON(irq->dev_irq_index != i))
+ return -EINVAL;
+
+ /*
+ * NOTE: Normally, devm_request_threaded_irq() programs the MSI
+ * physically in the device (by invoking a device-specific
+ * callback). However, for MC IRQs, we have to program the MSI
+ * outside of this callback in an object-specific way, because
+ * the object-independent way of programming MSI is not reliable
+ * yet. For now, the MC callback just sets the msi_paddr and
+ * msi_value fields of the irq structure.
+ */
error = devm_request_threaded_irq(&mc_dev->dev,
irq->irq_number,
irq_handlers[i].irq_handler,
@@ -518,18 +531,17 @@ static int register_dprc_irq_handlers(struct fsl_mc_device *mc_dev)
/*
* 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,
+ 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);
+ "dprc_set_irq() failed for IRQ %u: %d\n",
+ i, error);
return error;
}
}
@@ -620,14 +632,28 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
int error;
size_t region_size;
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
+ bool mc_io_created = false;
+ bool dev_root_set = false;
if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
return -EINVAL;
- if (!mc_dev->mc_io) {
+ if (mc_dev->mc_io) {
/*
- * This is a child DPRC:
+ * This is the root DPRC
*/
+ if (WARN_ON(fsl_mc_bus_type.dev_root))
+ return -EINVAL;
+
+ fsl_mc_bus_type.dev_root = &mc_dev->dev;
+ dev_root_set = true;
+ } else {
+ /*
+ * This is a child DPRC
+ */
+ if (WARN_ON(!fsl_mc_bus_type.dev_root))
+ return -EINVAL;
+
if (WARN_ON(mc_dev->obj_desc.region_count == 0))
return -EINVAL;
@@ -640,6 +666,8 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
NULL, 0, &mc_dev->mc_io);
if (error < 0)
return error;
+
+ mc_io_created = true;
}
error = dprc_open(mc_dev->mc_io, mc_dev->obj_desc.id,
@@ -663,19 +691,27 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
*/
error = dprc_setup_irqs(mc_dev);
if (error < 0)
- goto error_cleanup_open;
+ goto error_cleanup_dprc_scan;
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);
+error_cleanup_dprc_scan:
+ device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
+ fsl_mc_cleanup_irq_pool(mc_bus);
+error_cleanup_open:
(void)dprc_close(mc_dev->mc_io, mc_dev->mc_handle);
error_cleanup_mc_io:
- fsl_destroy_mc_io(mc_dev->mc_io);
+ if (mc_io_created) {
+ fsl_destroy_mc_io(mc_dev->mc_io);
+ mc_dev->mc_io = NULL;
+ }
+
+ if (dev_root_set)
+ fsl_mc_bus_type.dev_root = NULL;
+
return error;
}
diff --git a/drivers/staging/fsl-mc/bus/dprc.c b/drivers/staging/fsl-mc/bus/dprc.c
index 19b26e6..4a5f13a 100644
--- a/drivers/staging/fsl-mc/bus/dprc.c
+++ b/drivers/staging/fsl-mc/bus/dprc.c
@@ -34,7 +34,7 @@
#include "../include/dprc.h"
#include "dprc-cmd.h"
-int dprc_open(struct fsl_mc_io *mc_io, int container_id, uint16_t *token)
+int dprc_open(struct fsl_mc_io *mc_io, int container_id, u16 *token)
{
struct mc_command cmd = { 0 };
int err;
@@ -56,7 +56,7 @@ int dprc_open(struct fsl_mc_io *mc_io, int container_id, uint16_t *token)
}
EXPORT_SYMBOL(dprc_open);
-int dprc_close(struct fsl_mc_io *mc_io, uint16_t token)
+int dprc_close(struct fsl_mc_io *mc_io, u16 token)
{
struct mc_command cmd = { 0 };
@@ -70,10 +70,10 @@ int dprc_close(struct fsl_mc_io *mc_io, uint16_t token)
EXPORT_SYMBOL(dprc_close);
int dprc_create_container(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
struct dprc_cfg *cfg,
int *child_container_id,
- uint64_t *child_portal_paddr)
+ u64 *child_portal_offset)
{
struct mc_command cmd = { 0 };
int err;
@@ -82,6 +82,22 @@ int dprc_create_container(struct fsl_mc_io *mc_io,
cmd.params[0] |= mc_enc(32, 16, cfg->icid);
cmd.params[0] |= mc_enc(0, 32, cfg->options);
cmd.params[1] |= mc_enc(32, 32, cfg->portal_id);
+ cmd.params[2] |= mc_enc(0, 8, cfg->label[0]);
+ cmd.params[2] |= mc_enc(8, 8, cfg->label[1]);
+ cmd.params[2] |= mc_enc(16, 8, cfg->label[2]);
+ cmd.params[2] |= mc_enc(24, 8, cfg->label[3]);
+ cmd.params[2] |= mc_enc(32, 8, cfg->label[4]);
+ cmd.params[2] |= mc_enc(40, 8, cfg->label[5]);
+ cmd.params[2] |= mc_enc(48, 8, cfg->label[6]);
+ cmd.params[2] |= mc_enc(56, 8, cfg->label[7]);
+ cmd.params[3] |= mc_enc(0, 8, cfg->label[8]);
+ cmd.params[3] |= mc_enc(8, 8, cfg->label[9]);
+ cmd.params[3] |= mc_enc(16, 8, cfg->label[10]);
+ cmd.params[3] |= mc_enc(24, 8, cfg->label[11]);
+ cmd.params[3] |= mc_enc(32, 8, cfg->label[12]);
+ cmd.params[3] |= mc_enc(40, 8, cfg->label[13]);
+ cmd.params[3] |= mc_enc(48, 8, cfg->label[14]);
+ cmd.params[3] |= mc_enc(56, 8, cfg->label[15]);
cmd.header = mc_encode_cmd_header(DPRC_CMDID_CREATE_CONT,
MC_CMD_PRI_LOW, token);
@@ -93,13 +109,13 @@ int dprc_create_container(struct fsl_mc_io *mc_io,
/* retrieve response parameters */
*child_container_id = mc_dec(cmd.params[1], 0, 32);
- *child_portal_paddr = mc_dec(cmd.params[2], 0, 64);
+ *child_portal_offset = mc_dec(cmd.params[2], 0, 64);
return 0;
}
int dprc_destroy_container(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id)
{
struct mc_command cmd = { 0 };
@@ -114,7 +130,7 @@ int dprc_destroy_container(struct fsl_mc_io *mc_io,
}
int dprc_reset_container(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id)
{
struct mc_command cmd = { 0 };
@@ -129,11 +145,11 @@ int dprc_reset_container(struct fsl_mc_io *mc_io,
}
int dprc_get_irq(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
+ u16 token,
+ u8 irq_index,
int *type,
- uint64_t *irq_paddr,
- uint32_t *irq_val,
+ u64 *irq_paddr,
+ u32 *irq_val,
int *user_irq_id)
{
struct mc_command cmd = { 0 };
@@ -159,11 +175,44 @@ int dprc_get_irq(struct fsl_mc_io *mc_io,
return 0;
}
+int dprc_obj_get_irq(struct fsl_mc_io *mc_io,
+ u16 token,
+ int obj_index,
+ u8 irq_index,
+ int *type,
+ u64 *irq_addr,
+ u32 *irq_val,
+ int *user_irq_id)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_OBJ_GET_IRQ,
+ MC_CMD_PRI_LOW,
+ token);
+
+ cmd.params[0] |= mc_enc(0, 32, obj_index);
+ cmd.params[0] |= mc_enc(32, 8, irq_index);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *irq_val = mc_dec(cmd.params[0], 0, 32);
+ *irq_addr = mc_dec(cmd.params[1], 0, 64);
+ *user_irq_id = mc_dec(cmd.params[2], 0, 32);
+ *type = mc_dec(cmd.params[2], 32, 32);
+ return 0;
+}
+
int dprc_set_irq(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint64_t irq_paddr,
- uint32_t irq_val,
+ u16 token,
+ u8 irq_index,
+ u64 irq_paddr,
+ u32 irq_val,
int user_irq_id)
{
struct mc_command cmd = { 0 };
@@ -181,10 +230,35 @@ int dprc_set_irq(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd);
}
+int dprc_obj_set_irq(struct fsl_mc_io *mc_io,
+ u16 token,
+ int obj_index,
+ u8 irq_index,
+ u64 irq_addr,
+ u32 irq_val,
+ int user_irq_id)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_OBJ_SET_IRQ,
+ MC_CMD_PRI_LOW,
+ token);
+
+ cmd.params[0] |= mc_enc(32, 8, irq_index);
+ cmd.params[0] |= mc_enc(0, 32, irq_val);
+ cmd.params[1] |= mc_enc(0, 64, irq_addr);
+ cmd.params[2] |= mc_enc(0, 32, user_irq_id);
+ cmd.params[2] |= mc_enc(32, 32, obj_index);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
int dprc_get_irq_enable(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint8_t *en)
+ u16 token,
+ u8 irq_index,
+ u8 *en)
{
struct mc_command cmd = { 0 };
int err;
@@ -206,9 +280,9 @@ int dprc_get_irq_enable(struct fsl_mc_io *mc_io,
}
int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint8_t en)
+ u16 token,
+ u8 irq_index,
+ u8 en)
{
struct mc_command cmd = { 0 };
@@ -223,9 +297,9 @@ int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
}
int dprc_get_irq_mask(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t *mask)
+ u16 token,
+ u8 irq_index,
+ u32 *mask)
{
struct mc_command cmd = { 0 };
int err;
@@ -247,9 +321,9 @@ int dprc_get_irq_mask(struct fsl_mc_io *mc_io,
}
int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t mask)
+ u16 token,
+ u8 irq_index,
+ u32 mask)
{
struct mc_command cmd = { 0 };
@@ -264,9 +338,9 @@ int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
}
int dprc_get_irq_status(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t *status)
+ u16 token,
+ u8 irq_index,
+ u32 *status)
{
struct mc_command cmd = { 0 };
int err;
@@ -288,9 +362,9 @@ int dprc_get_irq_status(struct fsl_mc_io *mc_io,
}
int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t status)
+ u16 token,
+ u8 irq_index,
+ u32 status)
{
struct mc_command cmd = { 0 };
@@ -305,7 +379,7 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
}
int dprc_get_attributes(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
struct dprc_attributes *attr)
{
struct mc_command cmd = { 0 };
@@ -333,10 +407,10 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io,
}
int dprc_set_res_quota(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id,
char *type,
- uint16_t quota)
+ u16 quota)
{
struct mc_command cmd = { 0 };
@@ -367,10 +441,10 @@ int dprc_set_res_quota(struct fsl_mc_io *mc_io,
}
int dprc_get_res_quota(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id,
char *type,
- uint16_t *quota)
+ u16 *quota)
{
struct mc_command cmd = { 0 };
int err;
@@ -408,7 +482,7 @@ int dprc_get_res_quota(struct fsl_mc_io *mc_io,
}
int dprc_assign(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int container_id,
struct dprc_res_req *res_req)
{
@@ -443,7 +517,7 @@ int dprc_assign(struct fsl_mc_io *mc_io,
}
int dprc_unassign(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id,
struct dprc_res_req *res_req)
{
@@ -479,7 +553,7 @@ int dprc_unassign(struct fsl_mc_io *mc_io,
}
int dprc_get_pool_count(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int *pool_count)
{
struct mc_command cmd = { 0 };
@@ -501,7 +575,7 @@ int dprc_get_pool_count(struct fsl_mc_io *mc_io,
}
int dprc_get_pool(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int pool_index,
char *type)
{
@@ -540,7 +614,7 @@ int dprc_get_pool(struct fsl_mc_io *mc_io,
return 0;
}
-int dprc_get_obj_count(struct fsl_mc_io *mc_io, uint16_t token, int *obj_count)
+int dprc_get_obj_count(struct fsl_mc_io *mc_io, u16 token, int *obj_count)
{
struct mc_command cmd = { 0 };
int err;
@@ -562,7 +636,7 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io, uint16_t token, int *obj_count)
EXPORT_SYMBOL(dprc_get_obj_count);
int dprc_get_obj(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int obj_index,
struct dprc_obj_desc *obj_desc)
{
@@ -604,13 +678,28 @@ int dprc_get_obj(struct fsl_mc_io *mc_io,
obj_desc->type[13] = mc_dec(cmd.params[4], 40, 8);
obj_desc->type[14] = mc_dec(cmd.params[4], 48, 8);
obj_desc->type[15] = '\0';
-
+ obj_desc->label[0] = mc_dec(cmd.params[5], 0, 8);
+ obj_desc->label[1] = mc_dec(cmd.params[5], 8, 8);
+ obj_desc->label[2] = mc_dec(cmd.params[5], 16, 8);
+ obj_desc->label[3] = mc_dec(cmd.params[5], 24, 8);
+ obj_desc->label[4] = mc_dec(cmd.params[5], 32, 8);
+ obj_desc->label[5] = mc_dec(cmd.params[5], 40, 8);
+ obj_desc->label[6] = mc_dec(cmd.params[5], 48, 8);
+ obj_desc->label[7] = mc_dec(cmd.params[5], 56, 8);
+ obj_desc->label[8] = mc_dec(cmd.params[6], 0, 8);
+ obj_desc->label[9] = mc_dec(cmd.params[6], 8, 8);
+ obj_desc->label[10] = mc_dec(cmd.params[6], 16, 8);
+ obj_desc->label[11] = mc_dec(cmd.params[6], 24, 8);
+ obj_desc->label[12] = mc_dec(cmd.params[6], 32, 8);
+ obj_desc->label[13] = mc_dec(cmd.params[6], 40, 8);
+ obj_desc->label[14] = mc_dec(cmd.params[6], 48, 8);
+ obj_desc->label[15] = '\0';
return 0;
}
EXPORT_SYMBOL(dprc_get_obj);
int dprc_get_res_count(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
char *type,
int *res_count)
{
@@ -652,7 +741,7 @@ int dprc_get_res_count(struct fsl_mc_io *mc_io,
EXPORT_SYMBOL(dprc_get_res_count);
int dprc_get_res_ids(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
char *type,
struct dprc_res_ids_range_desc *range_desc)
{
@@ -696,36 +785,11 @@ int dprc_get_res_ids(struct fsl_mc_io *mc_io,
}
EXPORT_SYMBOL(dprc_get_res_ids);
-int dprc_get_portal_paddr(struct fsl_mc_io *mc_io,
- uint16_t token,
- int portal_id,
- uint64_t *portal_addr)
-{
- struct mc_command cmd = { 0 };
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_PORTAL_PADDR,
- MC_CMD_PRI_LOW, token);
- cmd.params[0] |= mc_enc(0, 32, portal_id);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- *portal_addr = mc_dec(cmd.params[1], 0, 64);
-
- return 0;
-}
-EXPORT_SYMBOL(dprc_get_portal_paddr);
-
int dprc_get_obj_region(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
char *obj_type,
int obj_id,
- uint8_t region_index,
+ u8 region_index,
struct dprc_region_desc *region_desc)
{
struct mc_command cmd = { 0 };
@@ -759,15 +823,48 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
return err;
/* retrieve response parameters */
- region_desc->base_paddr = mc_dec(cmd.params[1], 0, 64);
+ region_desc->base_offset = mc_dec(cmd.params[1], 0, 64);
region_desc->size = mc_dec(cmd.params[2], 0, 32);
return 0;
}
EXPORT_SYMBOL(dprc_get_obj_region);
+int dprc_set_obj_label(struct fsl_mc_io *mc_io,
+ u16 token,
+ int obj_index,
+ char *label)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_LABEL,
+ MC_CMD_PRI_LOW, token);
+
+ cmd.params[0] |= mc_enc(0, 32, obj_index);
+ cmd.params[1] |= mc_enc(0, 8, label[0]);
+ cmd.params[1] |= mc_enc(8, 8, label[1]);
+ cmd.params[1] |= mc_enc(16, 8, label[2]);
+ cmd.params[1] |= mc_enc(24, 8, label[3]);
+ cmd.params[1] |= mc_enc(32, 8, label[4]);
+ cmd.params[1] |= mc_enc(40, 8, label[5]);
+ cmd.params[1] |= mc_enc(48, 8, label[6]);
+ cmd.params[1] |= mc_enc(56, 8, label[7]);
+ cmd.params[2] |= mc_enc(0, 8, label[8]);
+ cmd.params[2] |= mc_enc(8, 8, label[9]);
+ cmd.params[2] |= mc_enc(16, 8, label[10]);
+ cmd.params[2] |= mc_enc(24, 8, label[11]);
+ cmd.params[2] |= mc_enc(32, 8, label[12]);
+ cmd.params[2] |= mc_enc(40, 8, label[13]);
+ cmd.params[2] |= mc_enc(48, 8, label[14]);
+ cmd.params[2] |= mc_enc(56, 8, label[15]);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
int dprc_connect(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
const struct dprc_endpoint *endpoint1,
const struct dprc_endpoint *endpoint2)
{
@@ -819,7 +916,7 @@ int dprc_connect(struct fsl_mc_io *mc_io,
}
int dprc_disconnect(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
const struct dprc_endpoint *endpoint)
{
struct mc_command cmd = { 0 };
@@ -852,7 +949,7 @@ int dprc_disconnect(struct fsl_mc_io *mc_io,
}
int dprc_get_connection(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
const struct dprc_endpoint *endpoint1,
struct dprc_endpoint *endpoint2,
int *state)
diff --git a/drivers/staging/fsl-mc/bus/mc-allocator.c b/drivers/staging/fsl-mc/bus/mc-allocator.c
index aa8280a..e445f79 100644
--- a/drivers/staging/fsl-mc/bus/mc-allocator.c
+++ b/drivers/staging/fsl-mc/bus/mc-allocator.c
@@ -523,14 +523,20 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
irqs[i] = to_fsl_mc_irq(resource);
res_allocated_count++;
+
+ WARN_ON(irqs[i]->mc_dev);
+ irqs[i]->mc_dev = mc_dev;
+ irqs[i]->dev_irq_index = i;
}
mc_dev->irqs = irqs;
return 0;
error_resource_alloc:
- for (i = 0; i < res_allocated_count; i++)
+ for (i = 0; i < res_allocated_count; i++) {
+ irqs[i]->mc_dev = NULL;
fsl_mc_resource_free(&irqs[i]->resource);
+ }
return error;
}
@@ -545,8 +551,9 @@ void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
int i;
int irq_count;
struct fsl_mc_bus *mc_bus;
+ struct fsl_mc_device_irq **irqs = mc_dev->irqs;
- if (WARN_ON(!mc_dev->irqs))
+ if (WARN_ON(!irqs))
return;
irq_count = mc_dev->obj_desc.irq_count;
@@ -559,8 +566,11 @@ void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
if (WARN_ON(!mc_bus->irq_resources))
return;
- for (i = 0; i < irq_count; i++)
- fsl_mc_resource_free(&mc_dev->irqs[i]->resource);
+ for (i = 0; i < irq_count; i++) {
+ WARN_ON(!irqs[i]->mc_dev);
+ irqs[i]->mc_dev = NULL;
+ fsl_mc_resource_free(&irqs[i]->resource);
+ }
mc_dev->irqs = NULL;
}
@@ -593,8 +603,8 @@ static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
if (error < 0)
goto error;
- dev_info(&mc_dev->dev,
- "Allocatable MC object device bound to fsl_mc_allocator driver");
+ dev_dbg(&mc_dev->dev,
+ "Allocatable MC object device bound to fsl_mc_allocator driver");
return 0;
error:
@@ -616,8 +626,8 @@ static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
if (error < 0)
goto out;
- dev_info(&mc_dev->dev,
- "Allocatable MC object device unbound from fsl_mc_allocator driver");
+ dev_dbg(&mc_dev->dev,
+ "Allocatable MC object device unbound from fsl_mc_allocator driver");
error = 0;
out:
return error;
diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c
index 60e45be..e5ea3ea 100644
--- a/drivers/staging/fsl-mc/bus/mc-bus.c
+++ b/drivers/staging/fsl-mc/bus/mc-bus.c
@@ -55,9 +55,6 @@ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv)
bool major_version_mismatch = false;
bool minor_version_mismatch = false;
- if (WARN_ON(!fsl_mc_bus_type.dev_root))
- goto out;
-
/* When driver_override is set, only bind to the matching driver */
if (mc_dev->driver_override) {
found = !strcmp(mc_dev->driver_override, mc_drv->driver.name);
@@ -70,9 +67,12 @@ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv)
/*
* If the object is not 'plugged' don't match.
* Only exception is the root DPRC, which is a special case.
+ *
+ * NOTE: Only when this function is invoked for the root DPRC,
+ * mc_dev->mc_io is not NULL
*/
if ((mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED) == 0 &&
- &mc_dev->dev != fsl_mc_bus_type.dev_root)
+ !mc_dev->mc_io)
goto out;
/*
@@ -315,7 +315,8 @@ common_cleanup:
return error;
}
-static int translate_mc_addr(uint64_t mc_addr, phys_addr_t *phys_addr)
+static int translate_mc_addr(enum fsl_mc_region_types mc_region_type,
+ u64 mc_offset, phys_addr_t *phys_addr)
{
int i;
struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
@@ -324,7 +325,7 @@ static int translate_mc_addr(uint64_t mc_addr, phys_addr_t *phys_addr)
/*
* Do identity mapping:
*/
- *phys_addr = mc_addr;
+ *phys_addr = mc_offset;
return 0;
}
@@ -332,10 +333,11 @@ static int translate_mc_addr(uint64_t mc_addr, phys_addr_t *phys_addr)
struct fsl_mc_addr_translation_range *range =
&mc->translation_ranges[i];
- if (mc_addr >= range->start_mc_addr &&
- mc_addr < range->end_mc_addr) {
+ if (mc_region_type == range->mc_region_type &&
+ mc_offset >= range->start_mc_offset &&
+ mc_offset < range->end_mc_offset) {
*phys_addr = range->start_phys_addr +
- (mc_addr - range->start_mc_addr);
+ (mc_offset - range->start_mc_offset);
return 0;
}
}
@@ -351,6 +353,22 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
struct resource *regions;
struct dprc_obj_desc *obj_desc = &mc_dev->obj_desc;
struct device *parent_dev = mc_dev->dev.parent;
+ enum fsl_mc_region_types mc_region_type;
+
+ if (strcmp(obj_desc->type, "dprc") == 0 ||
+ strcmp(obj_desc->type, "dpmcp") == 0) {
+ mc_region_type = FSL_MC_PORTAL;
+ } else if (strcmp(obj_desc->type, "dpio") == 0) {
+ mc_region_type = FSL_QBMAN_PORTAL;
+ } else {
+ /*
+ * This function should not have been called for this MC object
+ * type, as this object type is not supposed to have MMIO
+ * regions
+ */
+ WARN_ON(true);
+ return -EINVAL;
+ }
regions = kmalloc_array(obj_desc->region_count,
sizeof(regions[0]), GFP_KERNEL);
@@ -370,14 +388,14 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
goto error_cleanup_regions;
}
- WARN_ON(region_desc.base_paddr == 0x0);
WARN_ON(region_desc.size == 0);
- error = translate_mc_addr(region_desc.base_paddr,
+ error = translate_mc_addr(mc_region_type,
+ region_desc.base_offset,
®ions[i].start);
if (error < 0) {
dev_err(parent_dev,
- "Invalid MC address: %#llx (for %s.%d\'s region %d)\n",
- region_desc.base_paddr,
+ "Invalid MC offset: %#llx (for %s.%d\'s region %d)\n",
+ region_desc.base_offset,
obj_desc->type, obj_desc->id, i);
goto error_cleanup_regions;
}
@@ -481,9 +499,6 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
}
mc_io2 = mc_io;
-
- if (!fsl_mc_bus_type.dev_root)
- fsl_mc_bus_type.dev_root = &mc_dev->dev;
}
error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid);
@@ -674,6 +689,9 @@ void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus)
struct fsl_mc_resource_pool *res_pool =
&mc_bus->resource_pools[FSL_MC_POOL_IRQ];
+ if (WARN_ON(!mc_bus->irq_resources))
+ return;
+
if (WARN_ON(res_pool->max_count == 0))
return;
@@ -778,12 +796,14 @@ static int get_mc_addr_translation_ranges(struct device *dev,
for (i = 0; i < *num_ranges; ++i) {
struct fsl_mc_addr_translation_range *range = &(*ranges)[i];
- range->start_mc_addr = of_read_number(cell, mc_addr_cells);
+ range->mc_region_type = of_read_number(cell, 1);
+ range->start_mc_offset = of_read_number(cell + 1,
+ mc_addr_cells - 1);
cell += mc_addr_cells;
range->start_phys_addr = of_read_number(cell, paddr_cells);
cell += paddr_cells;
- range->end_mc_addr = range->start_mc_addr +
- of_read_number(cell, mc_size_cells);
+ range->end_mc_offset = range->start_mc_offset +
+ of_read_number(cell, mc_size_cells);
cell += mc_size_cells;
}
diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c
index 5737f59..f421411 100644
--- a/drivers/staging/fsl-mc/bus/mc-sys.c
+++ b/drivers/staging/fsl-mc/bus/mc-sys.c
@@ -256,11 +256,13 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
* TODO: When MC command completion interrupts are supported
* call wait function here instead of usleep_range()
*/
- usleep_range(MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS,
- MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
+ if (preemptible()) {
+ usleep_range(MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS,
+ MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
+ }
if (time_after_eq(jiffies, jiffies_until_timeout)) {
- pr_debug("MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n",
+ pr_debug("MC timed out (portal: %#llx, obj handle: %#x, command: %#x)\n",
mc_io->portal_phys_addr,
(unsigned int)
MC_CMD_HDR_READ_TOKEN(cmd->header),
diff --git a/drivers/staging/fsl-mc/include/dpmng.h b/drivers/staging/fsl-mc/include/dpmng.h
index 1b052b8..a38eb1a 100644
--- a/drivers/staging/fsl-mc/include/dpmng.h
+++ b/drivers/staging/fsl-mc/include/dpmng.h
@@ -41,11 +41,11 @@ struct fsl_mc_io;
/**
* Management Complex firmware version information
*/
-#define MC_VER_MAJOR 6
+#define MC_VER_MAJOR 7
#define MC_VER_MINOR 0
/**
- * struct mc_versoin
+ * struct mc_version
* @major: Major version number: incremented on API compatibility changes
* @minor: Minor version number: incremented on API additions (that are
* backward compatible); reset when major version is incremented
diff --git a/drivers/staging/fsl-mc/include/dprc.h b/drivers/staging/fsl-mc/include/dprc.h
index f1862a7..1646e63 100644
--- a/drivers/staging/fsl-mc/include/dprc.h
+++ b/drivers/staging/fsl-mc/include/dprc.h
@@ -43,7 +43,7 @@ struct fsl_mc_io;
* container, in case the ICID is not selected by the user and should be
* allocated by the DPRC from the pool of ICIDs.
*/
-#define DPRC_GET_ICID_FROM_POOL (uint16_t)(~(0))
+#define DPRC_GET_ICID_FROM_POOL (u16)(~(0))
/**
* Set this value as the portal_id value in dprc_cfg structure when creating a
@@ -62,7 +62,7 @@ struct fsl_mc_io;
*
* @warning Required before any operation on the object.
*/
-int dprc_open(struct fsl_mc_io *mc_io, int container_id, uint16_t *token);
+int dprc_open(struct fsl_mc_io *mc_io, int container_id, u16 *token);
/**
* dprc_close() - Close the control session of the object
@@ -74,7 +74,7 @@ int dprc_open(struct fsl_mc_io *mc_io, int container_id, uint16_t *token);
*
* Return: '0' on Success; Error code otherwise.
*/
-int dprc_close(struct fsl_mc_io *mc_io, uint16_t token);
+int dprc_close(struct fsl_mc_io *mc_io, u16 token);
/**
* Container general options
@@ -99,7 +99,7 @@ int dprc_close(struct fsl_mc_io *mc_io, uint16_t token);
/* Object initialization allowed - software context associated with this
* container is allowed to invoke object initialization operations.
*/
-#define DPRC_CFG_OPT_OBJ_CREATE_ALLOWED 0x00000004
+#define DPRC_CFG_OPT_OBJ_CREATE_ALLOWED 0x00000004
/* Topology change allowed - software context associated with this
* container is allowed to invoke topology operations, such as attach/detach
@@ -115,6 +115,9 @@ int dprc_close(struct fsl_mc_io *mc_io, uint16_t token);
/* AIOP - Indicates that container belongs to AIOP. */
#define DPRC_CFG_OPT_AIOP 0x00000020
+/* IRQ Config - Indicates that the container allowed to configure its IRQs. */
+#define DPRC_CFG_OPT_IRQ_CFG_ALLOWED 0x00000040
+
/**
* struct dprc_cfg - Container configuration options
* @icid: Container's ICID; if set to 'DPRC_GET_ICID_FROM_POOL', a free
@@ -122,11 +125,13 @@ int dprc_close(struct fsl_mc_io *mc_io, uint16_t token);
* @portal_id: Portal ID; if set to 'DPRC_GET_PORTAL_ID_FROM_POOL', a free
* portal ID is allocated by the DPRC
* @options: Combination of 'DPRC_CFG_OPT_<X>' options
+ * @label: Object's label
*/
struct dprc_cfg {
- uint16_t icid;
+ u16 icid;
int portal_id;
- uint64_t options;
+ u64 options;
+ char label[16];
};
/**
@@ -135,16 +140,15 @@ struct dprc_cfg {
* @token: Token of DPRC object
* @cfg: Child container configuration
* @child_container_id: Returned child container ID
- * @child_portal_paddr: Returned base physical address of the
- * child portal
+ * @child_portal_offset: Returned child portal offset from MC portal base
*
* Return: '0' on Success; Error code otherwise.
*/
int dprc_create_container(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
struct dprc_cfg *cfg,
int *child_container_id,
- uint64_t *child_portal_paddr);
+ u64 *child_portal_offset);
/**
* dprc_destroy_container() - Destroy child container.
@@ -168,7 +172,7 @@ int dprc_create_container(struct fsl_mc_io *mc_io,
*
*/
int dprc_destroy_container(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id);
/**
@@ -193,7 +197,7 @@ int dprc_destroy_container(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_reset_container(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id);
/* IRQ */
@@ -201,16 +205,20 @@ int dprc_reset_container(struct fsl_mc_io *mc_io,
/* Number of dprc's IRQs */
#define DPRC_NUM_OF_IRQS 1
-/* Object irq events */
+/* DPRC IRQ events */
-/* IRQ event - Indicates that a new object assigned to the container */
+/* IRQ event - Indicates that a new object added to the container */
#define DPRC_IRQ_EVENT_OBJ_ADDED 0x00000001
-/* IRQ event - Indicates that an object was unassigned from the container */
+
+/* IRQ event - Indicates that an object was removed from the container */
#define DPRC_IRQ_EVENT_OBJ_REMOVED 0x00000002
-/* IRQ event - Indicates that resources assigned to the container */
+
+/* IRQ event - Indicates that resources added to the container */
#define DPRC_IRQ_EVENT_RES_ADDED 0x00000004
-/* IRQ event - Indicates that resources unassigned from the container */
+
+/* IRQ event - Indicates that resources removed from the container */
#define DPRC_IRQ_EVENT_RES_REMOVED 0x00000008
+
/* IRQ event - Indicates that one of the descendant containers that opened by
* this container is destroyed
*/
@@ -237,10 +245,10 @@ int dprc_reset_container(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_set_irq(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint64_t irq_addr,
- uint32_t irq_val,
+ u16 token,
+ u8 irq_index,
+ u64 irq_addr,
+ u32 irq_val,
int user_irq_id);
/**
@@ -258,11 +266,11 @@ int dprc_set_irq(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_irq(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
+ u16 token,
+ u8 irq_index,
int *type,
- uint64_t *irq_addr,
- uint32_t *irq_val,
+ u64 *irq_addr,
+ u32 *irq_val,
int *user_irq_id);
/**
@@ -280,9 +288,9 @@ int dprc_get_irq(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint8_t en);
+ u16 token,
+ u8 irq_index,
+ u8 en);
/**
* dprc_get_irq_enable() - Get overall interrupt state.
@@ -294,9 +302,9 @@ int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_irq_enable(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint8_t *en);
+ u16 token,
+ u8 irq_index,
+ u8 *en);
/**
* dprc_set_irq_mask() - Set interrupt mask.
@@ -314,9 +322,9 @@ int dprc_get_irq_enable(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t mask);
+ u16 token,
+ u8 irq_index,
+ u32 mask);
/**
* dprc_get_irq_mask() - Get interrupt mask.
@@ -331,9 +339,9 @@ int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_irq_mask(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t *mask);
+ u16 token,
+ u8 irq_index,
+ u32 *mask);
/**
* dprc_get_irq_status() - Get the current status of any pending interrupts.
@@ -347,9 +355,9 @@ int dprc_get_irq_mask(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_irq_status(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t *status);
+ u16 token,
+ u8 irq_index,
+ u32 *status);
/**
* dprc_clear_irq_status() - Clear a pending interrupt's status
@@ -363,9 +371,9 @@ int dprc_get_irq_status(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
- uint16_t token,
- uint8_t irq_index,
- uint32_t status);
+ u16 token,
+ u8 irq_index,
+ u32 status);
/**
* struct dprc_attributes - Container attributes
@@ -377,17 +385,17 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
*/
struct dprc_attributes {
int container_id;
- uint16_t icid;
+ u16 icid;
int portal_id;
- uint64_t options;
+ u64 options;
/**
* struct version - DPRC version
* @major: DPRC major version
* @minor: DPRC minor version
*/
struct {
- uint16_t major;
- uint16_t minor;
+ u16 major;
+ u16 minor;
} version;
};
@@ -400,7 +408,7 @@ struct dprc_attributes {
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_attributes(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
struct dprc_attributes *attributes);
/**
@@ -428,10 +436,10 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io,
* @warning Only the parent container is allowed to change a child policy.
*/
int dprc_set_res_quota(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id,
char *type,
- uint16_t quota);
+ u16 quota);
/**
* dprc_get_res_quota() - Gets the allocation policy of a specific
@@ -448,10 +456,10 @@ int dprc_set_res_quota(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_res_quota(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id,
char *type,
- uint16_t *quota);
+ u16 *quota);
/* Resource request options */
@@ -492,8 +500,8 @@ int dprc_get_res_quota(struct fsl_mc_io *mc_io,
*/
struct dprc_res_req {
char type[16];
- uint32_t num;
- uint32_t options;
+ u32 num;
+ u32 options;
int id_base_align;
};
@@ -529,7 +537,7 @@ struct dprc_res_req {
* Return: '0' on Success; Error code otherwise.
*/
int dprc_assign(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int container_id,
struct dprc_res_req *res_req);
@@ -548,7 +556,7 @@ int dprc_assign(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_unassign(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int child_container_id,
struct dprc_res_req *res_req);
@@ -561,7 +569,7 @@ int dprc_unassign(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_pool_count(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int *pool_count);
/**
@@ -579,7 +587,7 @@ int dprc_get_pool_count(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_pool(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int pool_index,
char *type);
@@ -591,7 +599,7 @@ int dprc_get_pool(struct fsl_mc_io *mc_io,
*
* Return: '0' on Success; Error code otherwise.
*/
-int dprc_get_obj_count(struct fsl_mc_io *mc_io, uint16_t token, int *obj_count);
+int dprc_get_obj_count(struct fsl_mc_io *mc_io, u16 token, int *obj_count);
/* Objects Attributes Flags */
@@ -610,16 +618,18 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io, uint16_t token, int *obj_count);
* @irq_count: Number of interrupts supported by the object
* @region_count: Number of mappable regions supported by the object
* @state: Object state: combination of DPRC_OBJ_STATE_ states
+ * @label: Object label
*/
struct dprc_obj_desc {
char type[16];
int id;
- uint16_t vendor;
- uint16_t ver_major;
- uint16_t ver_minor;
- uint8_t irq_count;
- uint8_t region_count;
- uint32_t state;
+ u16 vendor;
+ u16 ver_major;
+ u16 ver_minor;
+ u8 irq_count;
+ u8 region_count;
+ u32 state;
+ char label[16];
};
/**
@@ -637,11 +647,58 @@ struct dprc_obj_desc {
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_obj(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
int obj_index,
struct dprc_obj_desc *obj_desc);
/**
+ * dprc_obj_set_irq() - Set IRQ information for object to trigger an interrupt.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @token: Token of DPRC object
+ * @obj_index: Index of the object to set its IRQ (< obj_count returned from
+ * dprc_get_obj_count())
+ * @irq_index: Identifies the interrupt index to configure
+ * @irq_addr: Address that must be written to
+ * signal a message-based interrupt
+ * @irq_val: Value to write into irq_addr address
+ * @user_irq_id: Returned a user defined number associated with this IRQ
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprc_obj_set_irq(struct fsl_mc_io *mc_io,
+ u16 token,
+ int obj_index,
+ u8 irq_index,
+ u64 irq_addr,
+ u32 irq_val,
+ int user_irq_id);
+
+/**
+ * dprc_obj_get_irq() - Get IRQ information from object.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @token: Token of DPRC object
+ * @obj_index: Index of the object to get its IRQ (< obj_count returned from
+ * dprc_get_obj_count())
+ * @irq_index: The interrupt index to configure
+ * @type: Returned interrupt type: 0 represents message interrupt
+ * type (both irq_addr and irq_val are valid)
+ * @irq_addr: Returned address that must be written to
+ * signal the message-based interrupt
+ * @irq_val: Value to write into irq_addr address
+ * @user_irq_id: A user defined number associated with this IRQ
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprc_obj_get_irq(struct fsl_mc_io *mc_io,
+ u16 token,
+ int obj_index,
+ u8 irq_index,
+ int *type,
+ u64 *irq_addr,
+ u32 *irq_val,
+ int *user_irq_id);
+
+/**
* dprc_get_res_count() - Obtains the number of free resources that are assigned
* to this container, by pool type
* @mc_io: Pointer to MC portal's I/O object
@@ -653,7 +710,7 @@ int dprc_get_obj(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_res_count(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
char *type,
int *res_count);
@@ -694,32 +751,21 @@ struct dprc_res_ids_range_desc {
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_res_ids(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
char *type,
struct dprc_res_ids_range_desc *range_desc);
/**
- * dprc_get_portal_paddr() - Get the physical address of MC portals
- * @mc_io: Pointer to MC portal's I/O object
- * @token: Token of DPRC object
- * @portal_id: MC portal ID
- * @portal_addr: The physical address of the MC portal ID
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_get_portal_paddr(struct fsl_mc_io *mc_io,
- uint16_t token,
- int portal_id,
- uint64_t *portal_addr);
-
-/**
* struct dprc_region_desc - Mappable region descriptor
- * @base_paddr: Region base physical address
+ * @base_offset: Region offset from region's base address.
+ * For DPMCP and DPRC objects, region base is offset from SoC MC portals
+ * base address; For DPIO, region base is offset from SoC QMan portals
+ * base address
* @size: Region size (in bytes)
*/
struct dprc_region_desc {
- uint64_t base_paddr;
- uint32_t size;
+ u64 base_offset;
+ u32 size;
};
/**
@@ -734,13 +780,27 @@ struct dprc_region_desc {
* Return: '0' on Success; Error code otherwise.
*/
int dprc_get_obj_region(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
char *obj_type,
int obj_id,
- uint8_t region_index,
+ u8 region_index,
struct dprc_region_desc *region_desc);
/**
+ * dprc_set_obj_label() - Set object label.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @token: Token of DPRC object
+ * @obj_index; Object index
+ * @label: The required label. The maximum length is 16 chars.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprc_set_obj_label(struct fsl_mc_io *mc_io,
+ u16 token,
+ int obj_index,
+ char *label);
+
+/**
* struct dprc_endpoint - Endpoint description for link connect/disconnect
* operations
* @type: Endpoint object type: NULL terminated string
@@ -764,7 +824,7 @@ struct dprc_endpoint {
* Return: '0' on Success; Error code otherwise.
*/
int dprc_connect(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
const struct dprc_endpoint *endpoint1,
const struct dprc_endpoint *endpoint2);
@@ -777,14 +837,14 @@ int dprc_connect(struct fsl_mc_io *mc_io,
* Return: '0' on Success; Error code otherwise.
*/
int dprc_disconnect(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
const struct dprc_endpoint *endpoint);
/**
* dprc_get_connection() - Get connected endpoint and link status if connection
* exists.
-* @mc_io Pointer to MC portal's I/O object
-* @token Token of DPRC object
+* @mc_io Pointer to MC portal's I/O object
+* @token Token of DPRC object
* @endpoint1 Endpoint 1 configuration parameters
* @endpoint2 Returned endpoint 2 configuration parameters
* @state: Returned link state: 1 - link is up, 0 - link is down
@@ -792,7 +852,7 @@ int dprc_disconnect(struct fsl_mc_io *mc_io,
* Return: '0' on Success; -ENAVAIL if connection does not exist.
*/
int dprc_get_connection(struct fsl_mc_io *mc_io,
- uint16_t token,
+ u16 token,
const struct dprc_endpoint *endpoint1,
struct dprc_endpoint *endpoint2,
int *state);
diff --git a/drivers/staging/fsl-mc/include/mc-private.h b/drivers/staging/fsl-mc/include/mc-private.h
index 5b9c8f2..8e02dc9 100644
--- a/drivers/staging/fsl-mc/include/mc-private.h
+++ b/drivers/staging/fsl-mc/include/mc-private.h
@@ -47,21 +47,36 @@
struct fsl_mc {
struct fsl_mc_device *root_mc_bus_dev;
struct irq_domain *irq_domain;
- uint8_t num_translation_ranges;
+ u8 num_translation_ranges;
struct fsl_mc_addr_translation_range *translation_ranges;
};
/**
+ * enum mc_region_types - Types of MC MMIO regions
+ */
+enum fsl_mc_region_types {
+ FSL_MC_PORTAL = 0x0,
+ FSL_QBMAN_PORTAL,
+
+ /*
+ * New offset types must be added above this entry
+ */
+ FSL_NUM_MC_OFFSET_TYPES
+};
+
+/**
* struct fsl_mc_addr_translation_range - bus to system address translation
* range
- * @start_mc_addr: Start MC address of the range being translated
- * @end_mc_addr: MC address of the first byte after the range (last MC
- * address of the range is end_mc_addr - 1)
+ * @mc_region_type: Type of MC region for the range being translated
+ * @start_mc_offset: Start MC offset of the range being translated
+ * @end_mc_offset: MC offset of the first byte after the range (last MC
+ * offset of the range is end_mc_offset - 1)
* @start_phys_addr: system physical address corresponding to start_mc_addr
*/
struct fsl_mc_addr_translation_range {
- uint64_t start_mc_addr;
- uint64_t end_mc_addr;
+ enum fsl_mc_region_types mc_region_type;
+ u64 start_mc_offset;
+ u64 end_mc_offset;
phys_addr_t start_phys_addr;
};
@@ -115,6 +130,10 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
const char *driver_override,
unsigned int *total_irq_count);
+int dprc_lookup_object(struct fsl_mc_device *mc_bus_dev,
+ struct fsl_mc_device *child_dev,
+ u32 *child_obj_index);
+
int __init dprc_driver_init(void);
void __exit dprc_driver_exit(void);
diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h
index 322b594..7fa2816 100644
--- a/drivers/staging/fsl-mc/include/mc.h
+++ b/drivers/staging/fsl-mc/include/mc.h
@@ -110,12 +110,16 @@ struct fsl_mc_resource {
* @msi_paddr: message-based interrupt physical address
* @msi_value: message-based interrupt data value
* @irq_number: Linux IRQ number assigned to the interrupt
+ * @mc_dev: MC object device that owns this interrupt
+ * @dev_irq_index: device-relative IRQ index
* @resource: MC generic resource associated with the interrupt
*/
struct fsl_mc_device_irq {
phys_addr_t msi_paddr;
u32 msi_value;
u32 irq_number;
+ struct fsl_mc_device *mc_dev;
+ u8 dev_irq_index;
struct fsl_mc_resource resource;
};
--
2.3.3
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v4 7/7] staging: fsl-mc: Use DPMCP IRQ and completion var to wait for MC
2015-06-09 21:59 [PATCH v4 0/7] staging: fsl-mc: New functionality to the MC bus driver J. German Rivera
` (5 preceding siblings ...)
2015-06-09 21:59 ` [PATCH v4 6/7] staging: fsl-mc: Add locking to serialize mc_send_command() calls J. German Rivera
@ 2015-06-09 21:59 ` J. German Rivera
2015-06-09 22:11 ` [PATCH v4 0/7] staging: fsl-mc: New functionality to the MC bus driver Fabio Estevam
2015-06-13 0:18 ` Greg KH
8 siblings, 0 replies; 21+ messages in thread
From: J. German Rivera @ 2015-06-09 21:59 UTC (permalink / raw)
To: gregkh, arnd, devel, linux-kernel
Cc: stuart.yoder, itai.katz, scottwood, agraf, bhamciu1, R89243,
bhupesh.sharma, nir.erez, richard.schmitt, dan.carpenter,
J. German Rivera
- Refactored fsl_mc_io object to have a DPMCP object attached to it
- Created DPMCP object for DPRC's built-in portal, so that waiting
on MC command completions for MC commands sent on the DPRC's built-in
portal can be done using a DPMCP interrupt and a Linux completion
variable. For most cases, mc_send_command() will wait on this
completion variable, instead of doing polling. This completion
variable will be signaled from the DPMCP IRQ handler.
Signed-off-by: J. German Rivera <German.Rivera@freescale.com>
Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com>
---
Changes in v4:
- Fixed new checkpatch warnings and checks
drivers/staging/fsl-mc/bus/dprc-driver.c | 172 ++++++++++--
drivers/staging/fsl-mc/bus/mc-allocator.c | 111 ++++----
drivers/staging/fsl-mc/bus/mc-bus.c | 19 +-
drivers/staging/fsl-mc/bus/mc-sys.c | 422 +++++++++++++++++++++++++---
drivers/staging/fsl-mc/include/mc-private.h | 6 +-
drivers/staging/fsl-mc/include/mc-sys.h | 37 ++-
6 files changed, 648 insertions(+), 119 deletions(-)
diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
index dc97681..ade2503 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include "dprc-cmd.h"
+#include "dpmcp.h"
struct dprc_child_objs {
int child_count;
@@ -323,7 +324,6 @@ 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);
- struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
dprc_init_all_resource_pools(mc_bus_dev);
@@ -336,7 +336,7 @@ static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
if (error < 0)
return error;
- if (mc->gic_supported && !mc_bus->irq_resources) {
+ if (fsl_mc_interrupts_supported() && !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)
@@ -373,7 +373,8 @@ static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
struct fsl_mc_io *mc_io = mc_dev->mc_io;
int irq_index = 0;
- dev_dbg(dev, "DPRC IRQ %d\n", irq_num);
+ dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
+ irq_num, smp_processor_id());
if (WARN_ON(!(mc_dev->flags & FSL_MC_IS_DPRC)))
return IRQ_HANDLED;
@@ -445,7 +446,8 @@ static int disable_dprc_irqs(struct fsl_mc_device *mc_dev)
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);
+ "Disabling DPRC IRQ %d failed: dprc_set_irq_enable() failed: %d\n",
+ i, error);
return error;
}
@@ -456,7 +458,8 @@ static int disable_dprc_irqs(struct fsl_mc_device *mc_dev)
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);
+ "Disabling DPRC IRQ %d failed: dprc_set_irq_mask() failed: %d\n",
+ i, error);
return error;
}
@@ -468,8 +471,9 @@ static int disable_dprc_irqs(struct fsl_mc_device *mc_dev)
~0x0U);
if (error < 0) {
dev_err(&mc_dev->dev,
- "dprc_clear_irq_status() failed: %d\n",
- error);
+ "Disabling DPRC IRQ %d failed: dprc_clear_irq_status() failed: %d\n",
+ i, error);
+
return error;
}
}
@@ -566,7 +570,8 @@ static int enable_dprc_irqs(struct fsl_mc_device *mc_dev)
~0x0u);
if (error < 0) {
dev_err(&mc_dev->dev,
- "dprc_set_irq_mask() failed: %d\n", error);
+ "Enabling DPRC IRQ %d failed: dprc_set_irq_mask() failed: %d\n",
+ i, error);
return error;
}
@@ -579,7 +584,8 @@ static int enable_dprc_irqs(struct fsl_mc_device *mc_dev)
i, 1);
if (error < 0) {
dev_err(&mc_dev->dev,
- "dprc_set_irq_enable() failed: %d\n", error);
+ "Enabling DPRC IRQ %d failed: dprc_set_irq_enable() failed: %d\n",
+ i, error);
return error;
}
@@ -618,6 +624,95 @@ error_free_irqs:
return error;
}
+/*
+ * Creates a DPMCP for a DPRC's built-in MC portal
+ */
+static int dprc_create_dpmcp(struct fsl_mc_device *dprc_dev)
+{
+ int error;
+ struct dpmcp_cfg dpmcp_cfg;
+ u16 dpmcp_handle;
+ struct dprc_res_req res_req;
+ struct dpmcp_attr dpmcp_attr;
+ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(dprc_dev);
+
+ dpmcp_cfg.portal_id = mc_bus->dprc_attr.portal_id;
+ error = dpmcp_create(dprc_dev->mc_io, &dpmcp_cfg, &dpmcp_handle);
+ if (error < 0) {
+ dev_err(&dprc_dev->dev, "dpmcp_create() failed: %d\n",
+ error);
+ return error;
+ }
+
+ /*
+ * Set the state of the newly created DPMCP object to be "plugged":
+ */
+
+ error = dpmcp_get_attributes(dprc_dev->mc_io, dpmcp_handle,
+ &dpmcp_attr);
+ if (error < 0) {
+ dev_err(&dprc_dev->dev, "dpmcp_get_attributes() failed: %d\n",
+ error);
+ goto error_destroy_dpmcp;
+ }
+
+ if (WARN_ON(dpmcp_attr.id != mc_bus->dprc_attr.portal_id)) {
+ error = -EINVAL;
+ goto error_destroy_dpmcp;
+ }
+
+ strcpy(res_req.type, "dpmcp");
+ res_req.num = 1;
+ res_req.options =
+ (DPRC_RES_REQ_OPT_EXPLICIT | DPRC_RES_REQ_OPT_PLUGGED);
+ res_req.id_base_align = dpmcp_attr.id;
+
+ error = dprc_assign(dprc_dev->mc_io,
+ dprc_dev->mc_handle,
+ dprc_dev->obj_desc.id,
+ &res_req);
+
+ if (error < 0) {
+ dev_err(&dprc_dev->dev, "dprc_assign() failed: %d\n", error);
+ goto error_destroy_dpmcp;
+ }
+
+ (void)dpmcp_close(dprc_dev->mc_io, dpmcp_handle);
+ return 0;
+
+error_destroy_dpmcp:
+ (void)dpmcp_destroy(dprc_dev->mc_io, dpmcp_handle);
+ return error;
+}
+
+/*
+ * Destroys the DPMCP for a DPRC's built-in MC portal
+ */
+static void dprc_destroy_dpmcp(struct fsl_mc_device *dprc_dev)
+{
+ int error;
+ u16 dpmcp_handle;
+ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(dprc_dev);
+
+ if (WARN_ON(!dprc_dev->mc_io || dprc_dev->mc_io->dpmcp_dev))
+ return;
+
+ error = dpmcp_open(dprc_dev->mc_io, mc_bus->dprc_attr.portal_id,
+ &dpmcp_handle);
+ if (error < 0) {
+ dev_err(&dprc_dev->dev, "dpmcp_open() failed: %d\n",
+ error);
+ return;
+ }
+
+ error = dpmcp_destroy(dprc_dev->mc_io, dpmcp_handle);
+ if (error < 0) {
+ dev_err(&dprc_dev->dev, "dpmcp_destroy() failed: %d\n",
+ error);
+ return;
+ }
+}
+
/**
* dprc_probe - callback invoked when a DPRC is being bound to this driver
*
@@ -635,7 +730,6 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
bool mc_io_created = false;
bool dev_root_set = false;
- struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
return -EINVAL;
@@ -679,16 +773,55 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
goto error_cleanup_mc_io;
}
+ error = dprc_get_attributes(mc_dev->mc_io, mc_dev->mc_handle,
+ &mc_bus->dprc_attr);
+ if (error < 0) {
+ dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n",
+ error);
+ goto error_cleanup_open;
+ }
+
+ if (fsl_mc_interrupts_supported()) {
+ /*
+ * Create DPMCP for the DPRC's built-in portal:
+ */
+ error = dprc_create_dpmcp(mc_dev);
+ if (error < 0)
+ goto error_cleanup_open;
+ }
+
mutex_init(&mc_bus->scan_mutex);
/*
- * Discover MC objects in DPRC object:
+ * Discover MC objects in the DPRC object:
*/
error = dprc_scan_container(mc_dev);
if (error < 0)
- goto error_cleanup_open;
+ goto error_destroy_dpmcp;
+
+ if (fsl_mc_interrupts_supported()) {
+ /*
+ * The fsl_mc_device object associated with the DPMCP object
+ * created above was created as part of the
+ * dprc_scan_container() call above:
+ */
+ if (WARN_ON(!mc_dev->mc_io->dpmcp_dev)) {
+ error = -EINVAL;
+ goto error_cleanup_dprc_scan;
+ }
+
+ /*
+ * Configure interrupt for the DPMCP object associated with the
+ * DPRC object's built-in portal:
+ *
+ * NOTE: We have to do this after calling dprc_scan_container(),
+ * since dprc_scan_container() will populate the IRQ pool for
+ * this DPRC.
+ */
+ error = fsl_mc_io_setup_dpmcp_irq(mc_dev->mc_io);
+ if (error < 0)
+ goto error_cleanup_dprc_scan;
- if (mc->gic_supported) {
/*
* Configure interrupts for the DPRC object associated with
* this MC bus:
@@ -702,10 +835,14 @@ static int dprc_probe(struct fsl_mc_device *mc_dev)
return 0;
error_cleanup_dprc_scan:
+ fsl_mc_io_unset_dpmcp(mc_dev->mc_io);
device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
- if (mc->gic_supported)
+ if (fsl_mc_interrupts_supported())
fsl_mc_cleanup_irq_pool(mc_bus);
+error_destroy_dpmcp:
+ dprc_destroy_dpmcp(mc_dev);
+
error_cleanup_open:
(void)dprc_close(mc_dev->mc_io, mc_dev->mc_handle);
@@ -744,7 +881,6 @@ static int dprc_remove(struct fsl_mc_device *mc_dev)
{
int error;
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
- struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
return -EINVAL;
@@ -754,15 +890,17 @@ static int dprc_remove(struct fsl_mc_device *mc_dev)
if (WARN_ON(!mc_bus->irq_resources))
return -EINVAL;
- if (mc->gic_supported)
+ if (fsl_mc_interrupts_supported())
dprc_teardown_irqs(mc_dev);
+ fsl_mc_io_unset_dpmcp(mc_dev->mc_io);
device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
+ dprc_destroy_dpmcp(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);
- if (mc->gic_supported)
+ if (fsl_mc_interrupts_supported())
fsl_mc_cleanup_irq_pool(mc_bus);
dev_info(&mc_dev->dev, "DPRC device unbound from driver");
diff --git a/drivers/staging/fsl-mc/bus/mc-allocator.c b/drivers/staging/fsl-mc/bus/mc-allocator.c
index 3bdfefb..87b3d59 100644
--- a/drivers/staging/fsl-mc/bus/mc-allocator.c
+++ b/drivers/staging/fsl-mc/bus/mc-allocator.c
@@ -109,7 +109,7 @@ static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device
goto out;
resource = mc_dev->resource;
- if (WARN_ON(resource->data != mc_dev))
+ if (WARN_ON(!resource || resource->data != mc_dev))
goto out;
mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
@@ -281,7 +281,7 @@ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev,
struct fsl_mc_bus *mc_bus;
phys_addr_t mc_portal_phys_addr;
size_t mc_portal_size;
- struct fsl_mc_device *mc_adev;
+ struct fsl_mc_device *dpmcp_dev;
int error = -EINVAL;
struct fsl_mc_resource *resource = NULL;
struct fsl_mc_io *mc_io = NULL;
@@ -301,23 +301,24 @@ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev,
if (error < 0)
return error;
- mc_adev = resource->data;
- if (WARN_ON(!mc_adev))
+ dpmcp_dev = resource->data;
+ if (WARN_ON(!dpmcp_dev ||
+ strcmp(dpmcp_dev->obj_desc.type, "dpmcp") != 0))
goto error_cleanup_resource;
- if (WARN_ON(mc_adev->obj_desc.region_count == 0))
+ if (WARN_ON(dpmcp_dev->obj_desc.region_count == 0))
goto error_cleanup_resource;
- mc_portal_phys_addr = mc_adev->regions[0].start;
- mc_portal_size = mc_adev->regions[0].end -
- mc_adev->regions[0].start + 1;
+ mc_portal_phys_addr = dpmcp_dev->regions[0].start;
+ mc_portal_size = dpmcp_dev->regions[0].end -
+ dpmcp_dev->regions[0].start + 1;
if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size))
goto error_cleanup_resource;
error = fsl_create_mc_io(&mc_bus_dev->dev,
mc_portal_phys_addr,
- mc_portal_size, resource,
+ mc_portal_size, dpmcp_dev,
mc_io_flags, &mc_io);
if (error < 0)
goto error_cleanup_resource;
@@ -339,12 +340,26 @@ EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate);
*/
void fsl_mc_portal_free(struct fsl_mc_io *mc_io)
{
+ struct fsl_mc_device *dpmcp_dev;
struct fsl_mc_resource *resource;
- resource = mc_io->resource;
- if (WARN_ON(resource->type != FSL_MC_POOL_DPMCP))
+ /*
+ * Every mc_io obtained by calling fsl_mc_portal_allocate() is supposed
+ * to have a DPMCP object associated with.
+ */
+ dpmcp_dev = mc_io->dpmcp_dev;
+ if (WARN_ON(!dpmcp_dev))
+ return;
+ if (WARN_ON(strcmp(dpmcp_dev->obj_desc.type, "dpmcp") != 0))
+ return;
+ if (WARN_ON(dpmcp_dev->mc_io != mc_io))
+ return;
+
+ resource = dpmcp_dev->resource;
+ if (WARN_ON(!resource || resource->type != FSL_MC_POOL_DPMCP))
return;
- if (WARN_ON(!resource->data))
+
+ if (WARN_ON(resource->data != dpmcp_dev))
return;
fsl_destroy_mc_io(mc_io);
@@ -360,31 +375,14 @@ EXPORT_SYMBOL_GPL(fsl_mc_portal_free);
int fsl_mc_portal_reset(struct fsl_mc_io *mc_io)
{
int error;
- uint16_t token;
- struct fsl_mc_resource *resource = mc_io->resource;
- struct fsl_mc_device *mc_dev = resource->data;
-
- if (WARN_ON(resource->type != FSL_MC_POOL_DPMCP))
- return -EINVAL;
+ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
- if (WARN_ON(!mc_dev))
+ if (WARN_ON(!dpmcp_dev))
return -EINVAL;
- error = dpmcp_open(mc_io, mc_dev->obj_desc.id, &token);
+ error = dpmcp_reset(mc_io, dpmcp_dev->mc_handle);
if (error < 0) {
- dev_err(&mc_dev->dev, "dpmcp_open() failed: %d\n", error);
- return error;
- }
-
- error = dpmcp_reset(mc_io, token);
- if (error < 0) {
- dev_err(&mc_dev->dev, "dpmcp_reset() failed: %d\n", error);
- return error;
- }
-
- error = dpmcp_close(mc_io, token);
- if (error < 0) {
- dev_err(&mc_dev->dev, "dpmcp_close() failed: %d\n", error);
+ dev_err(&dpmcp_dev->dev, "dpmcp_reset() failed: %d\n", error);
return error;
}
@@ -599,16 +597,31 @@ static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
goto error;
mc_bus = to_fsl_mc_bus(mc_bus_dev);
- error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type);
- if (error < 0)
- goto error;
- error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev);
- if (error < 0)
- goto error;
+ /*
+ * If mc_dev is the DPMCP object for the parent DPRC's built-in
+ * portal, we don't add this DPMCP to the DPMCP object pool,
+ * but instead allocate it directly to the parent DPRC (mc_bus_dev):
+ */
+ if (strcmp(mc_dev->obj_desc.type, "dpmcp") == 0 &&
+ mc_dev->obj_desc.id == mc_bus->dprc_attr.portal_id) {
+ error = fsl_mc_io_set_dpmcp(mc_bus_dev->mc_io, mc_dev);
+ if (error < 0)
+ goto error;
+ } else {
+ error = object_type_to_pool_type(mc_dev->obj_desc.type,
+ &pool_type);
+ if (error < 0)
+ goto error;
+
+ error = fsl_mc_resource_pool_add_device(mc_bus, pool_type,
+ mc_dev);
+ if (error < 0)
+ goto error;
+ }
dev_dbg(&mc_dev->dev,
- "Allocatable MC object device bound to fsl_mc_allocator driver");
+ "Allocatable MC object device bound to fsl_mc_allocator");
return 0;
error:
@@ -621,20 +634,20 @@ error:
*/
static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
{
- int error = -EINVAL;
+ int error;
if (WARN_ON(!FSL_MC_IS_ALLOCATABLE(mc_dev->obj_desc.type)))
- goto out;
+ return -EINVAL;
- error = fsl_mc_resource_pool_remove_device(mc_dev);
- if (error < 0)
- goto out;
+ if (mc_dev->resource) {
+ error = fsl_mc_resource_pool_remove_device(mc_dev);
+ if (error < 0)
+ return error;
+ }
dev_dbg(&mc_dev->dev,
- "Allocatable MC object device unbound from fsl_mc_allocator driver");
- error = 0;
-out:
- return error;
+ "Allocatable MC object device unbound from fsl_mc_allocator");
+ return 0;
}
static const struct fsl_mc_device_match_id match_id_table[] = {
diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c
index 36bfe68..400300d 100644
--- a/drivers/staging/fsl-mc/bus/mc-bus.c
+++ b/drivers/staging/fsl-mc/bus/mc-bus.c
@@ -591,6 +591,11 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
if (&mc_dev->dev == fsl_mc_bus_type.dev_root)
fsl_mc_bus_type.dev_root = NULL;
+ } else if (strcmp(mc_dev->obj_desc.type, "dpmcp") == 0) {
+ if (mc_dev->mc_io) {
+ fsl_destroy_mc_io(mc_dev->mc_io);
+ mc_dev->mc_io = NULL;
+ }
}
kfree(mc_dev->driver_override);
@@ -844,13 +849,9 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mc);
error = create_mc_irq_domain(pdev, &mc->irq_domain);
- if (error < 0)
- return error;
-
- error = create_mc_irq_domain(pdev, &mc->irq_domain);
if (error < 0) {
dev_warn(&pdev->dev,
- "WARNING: MC bus driver will run without interrupt support\n");
+ "WARNING: MC bus driver running without interrupt support\n");
} else {
mc->gic_supported = true;
}
@@ -931,7 +932,9 @@ error_cleanup_mc_io:
fsl_destroy_mc_io(mc_io);
error_cleanup_irq_domain:
- irq_domain_remove(mc->irq_domain);
+ if (mc->gic_supported)
+ irq_domain_remove(mc->irq_domain);
+
return error;
}
@@ -946,7 +949,9 @@ 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);
+ if (mc->gic_supported)
+ 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/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c
index 0da7700..151f148 100644
--- a/drivers/staging/fsl-mc/bus/mc-sys.c
+++ b/drivers/staging/fsl-mc/bus/mc-sys.c
@@ -34,10 +34,13 @@
#include "../include/mc-sys.h"
#include "../include/mc-cmd.h"
+#include "../include/mc.h"
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/device.h>
+#include <linux/interrupt.h>
+#include "dpmcp.h"
/**
* Timeout in milliseconds to wait for the completion of an MC command
@@ -55,6 +58,230 @@
((uint16_t)mc_dec((_hdr), MC_CMD_HDR_CMDID_O, MC_CMD_HDR_CMDID_S))
/**
+ * dpmcp_irq0_handler - Regular ISR for DPMCP interrupt 0
+ *
+ * @irq: IRQ number of the interrupt being handled
+ * @arg: Pointer to device structure
+ */
+static irqreturn_t dpmcp_irq0_handler(int irq_num, void *arg)
+{
+ struct device *dev = (struct device *)arg;
+ struct fsl_mc_device *dpmcp_dev = to_fsl_mc_device(dev);
+
+ dev_dbg(dev, "DPMCP IRQ %d triggered on CPU %u\n", irq_num,
+ smp_processor_id());
+
+ if (WARN_ON(dpmcp_dev->irqs[0]->irq_number != (uint32_t)irq_num))
+ goto out;
+
+ if (WARN_ON(!dpmcp_dev->mc_io))
+ goto out;
+
+ /*
+ * NOTE: We cannot invoke MC flib function here
+ */
+
+ complete(&dpmcp_dev->mc_io->mc_command_done_completion);
+out:
+ return IRQ_HANDLED;
+}
+
+/*
+ * Disable and clear interrupts for a given DPMCP object
+ */
+static int disable_dpmcp_irq(struct fsl_mc_device *dpmcp_dev)
+{
+ int error;
+
+ /*
+ * Disable generation of the DPMCP interrupt:
+ */
+ error = dpmcp_set_irq_enable(dpmcp_dev->mc_io,
+ dpmcp_dev->mc_handle,
+ DPMCP_IRQ_INDEX, 0);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "dpmcp_set_irq_enable() failed: %d\n", error);
+
+ return error;
+ }
+
+ /*
+ * Disable all DPMCP interrupt causes:
+ */
+ error = dpmcp_set_irq_mask(dpmcp_dev->mc_io, dpmcp_dev->mc_handle,
+ DPMCP_IRQ_INDEX, 0x0);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "dpmcp_set_irq_mask() failed: %d\n", error);
+
+ return error;
+ }
+
+ /*
+ * Clear any leftover interrupts:
+ */
+ error = dpmcp_clear_irq_status(dpmcp_dev->mc_io, dpmcp_dev->mc_handle,
+ DPMCP_IRQ_INDEX, ~0x0U);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "dpmcp_clear_irq_status() failed: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void unregister_dpmcp_irq_handler(struct fsl_mc_device *dpmcp_dev)
+{
+ struct fsl_mc_device_irq *irq = dpmcp_dev->irqs[DPMCP_IRQ_INDEX];
+
+ devm_free_irq(&dpmcp_dev->dev, irq->irq_number, &dpmcp_dev->dev);
+}
+
+static int register_dpmcp_irq_handler(struct fsl_mc_device *dpmcp_dev)
+{
+ int error;
+ struct fsl_mc_device_irq *irq = dpmcp_dev->irqs[DPMCP_IRQ_INDEX];
+
+ error = devm_request_irq(&dpmcp_dev->dev,
+ irq->irq_number,
+ dpmcp_irq0_handler,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ "FSL MC DPMCP irq0",
+ &dpmcp_dev->dev);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "devm_request_irq() failed: %d\n",
+ error);
+ return error;
+ }
+
+ error = dpmcp_set_irq(dpmcp_dev->mc_io,
+ dpmcp_dev->mc_handle,
+ DPMCP_IRQ_INDEX,
+ irq->msi_paddr,
+ irq->msi_value,
+ irq->irq_number);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "dpmcp_set_irq() failed: %d\n", error);
+ goto error_unregister_irq_handler;
+ }
+
+ return 0;
+
+error_unregister_irq_handler:
+ devm_free_irq(&dpmcp_dev->dev, irq->irq_number, &dpmcp_dev->dev);
+ return error;
+}
+
+static int enable_dpmcp_irq(struct fsl_mc_device *dpmcp_dev)
+{
+ int error;
+
+ /*
+ * Enable MC command completion event to trigger DPMCP interrupt:
+ */
+ error = dpmcp_set_irq_mask(dpmcp_dev->mc_io,
+ dpmcp_dev->mc_handle,
+ DPMCP_IRQ_INDEX,
+ DPMCP_IRQ_EVENT_CMD_DONE);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "dpmcp_set_irq_mask() failed: %d\n", error);
+
+ return error;
+ }
+
+ /*
+ * Enable generation of the interrupt:
+ */
+ error = dpmcp_set_irq_enable(dpmcp_dev->mc_io,
+ dpmcp_dev->mc_handle,
+ DPMCP_IRQ_INDEX, 1);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev,
+ "dpmcp_set_irq_enable() failed: %d\n", error);
+
+ return error;
+ }
+
+ return 0;
+}
+
+/*
+ * Setup MC command completion interrupt for the DPMCP device associated with a
+ * given fsl_mc_io object
+ */
+int fsl_mc_io_setup_dpmcp_irq(struct fsl_mc_io *mc_io)
+{
+ int error;
+ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
+
+ if (WARN_ON(!dpmcp_dev))
+ return -EINVAL;
+
+ if (WARN_ON(!fsl_mc_interrupts_supported()))
+ return -EINVAL;
+
+ if (WARN_ON(dpmcp_dev->obj_desc.irq_count != 1))
+ return -EINVAL;
+
+ if (WARN_ON(!dpmcp_dev->mc_io))
+ return -EINVAL;
+
+ error = fsl_mc_allocate_irqs(dpmcp_dev);
+ if (error < 0)
+ return error;
+
+ error = disable_dpmcp_irq(dpmcp_dev);
+ if (error < 0)
+ goto error_free_irqs;
+
+ error = register_dpmcp_irq_handler(dpmcp_dev);
+ if (error < 0)
+ goto error_free_irqs;
+
+ error = enable_dpmcp_irq(dpmcp_dev);
+ if (error < 0)
+ goto error_unregister_irq_handler;
+
+ mc_io->mc_command_done_irq_armed = true;
+ return 0;
+
+error_unregister_irq_handler:
+ unregister_dpmcp_irq_handler(dpmcp_dev);
+
+error_free_irqs:
+ fsl_mc_free_irqs(dpmcp_dev);
+ return error;
+}
+EXPORT_SYMBOL_GPL(fsl_mc_io_setup_dpmcp_irq);
+
+/*
+ * Tear down interrupts for the DPMCP device associated with a given fsl_mc_io
+ * object
+ */
+static void teardown_dpmcp_irq(struct fsl_mc_io *mc_io)
+{
+ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
+
+ if (WARN_ON(!dpmcp_dev))
+ return;
+ if (WARN_ON(!fsl_mc_interrupts_supported()))
+ return;
+ if (WARN_ON(!dpmcp_dev->irqs))
+ return;
+
+ mc_io->mc_command_done_irq_armed = false;
+ (void)disable_dpmcp_irq(dpmcp_dev);
+ unregister_dpmcp_irq_handler(dpmcp_dev);
+ fsl_mc_free_irqs(dpmcp_dev);
+}
+
+/**
* Creates an MC I/O object
*
* @dev: device to be associated with the MC I/O object
@@ -70,9 +297,10 @@
int __must_check fsl_create_mc_io(struct device *dev,
phys_addr_t mc_portal_phys_addr,
uint32_t mc_portal_size,
- struct fsl_mc_resource *resource,
+ struct fsl_mc_device *dpmcp_dev,
uint32_t flags, struct fsl_mc_io **new_mc_io)
{
+ int error;
struct fsl_mc_io *mc_io;
void __iomem *mc_portal_virt_addr;
struct resource *res;
@@ -85,11 +313,13 @@ int __must_check fsl_create_mc_io(struct device *dev,
mc_io->flags = flags;
mc_io->portal_phys_addr = mc_portal_phys_addr;
mc_io->portal_size = mc_portal_size;
- mc_io->resource = resource;
- if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
+ mc_io->mc_command_done_irq_armed = false;
+ if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) {
spin_lock_init(&mc_io->spinlock);
- else
+ } else {
mutex_init(&mc_io->mutex);
+ init_completion(&mc_io->mc_command_done_completion);
+ }
res = devm_request_mem_region(dev,
mc_portal_phys_addr,
@@ -113,8 +343,26 @@ int __must_check fsl_create_mc_io(struct device *dev,
}
mc_io->portal_virt_addr = mc_portal_virt_addr;
+ if (dpmcp_dev) {
+ error = fsl_mc_io_set_dpmcp(mc_io, dpmcp_dev);
+ if (error < 0)
+ goto error_destroy_mc_io;
+
+ if (!(flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL) &&
+ fsl_mc_interrupts_supported()) {
+ error = fsl_mc_io_setup_dpmcp_irq(mc_io);
+ if (error < 0)
+ goto error_destroy_mc_io;
+ }
+ }
+
*new_mc_io = mc_io;
return 0;
+
+error_destroy_mc_io:
+ fsl_destroy_mc_io(mc_io);
+ return error;
+
}
EXPORT_SYMBOL_GPL(fsl_create_mc_io);
@@ -125,6 +373,11 @@ EXPORT_SYMBOL_GPL(fsl_create_mc_io);
*/
void fsl_destroy_mc_io(struct fsl_mc_io *mc_io)
{
+ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
+
+ if (dpmcp_dev)
+ fsl_mc_io_unset_dpmcp(mc_io);
+
devm_iounmap(mc_io->dev, mc_io->portal_virt_addr);
devm_release_mem_region(mc_io->dev,
mc_io->portal_phys_addr,
@@ -135,6 +388,60 @@ void fsl_destroy_mc_io(struct fsl_mc_io *mc_io)
}
EXPORT_SYMBOL_GPL(fsl_destroy_mc_io);
+int fsl_mc_io_set_dpmcp(struct fsl_mc_io *mc_io,
+ struct fsl_mc_device *dpmcp_dev)
+{
+ int error;
+
+ if (WARN_ON(!dpmcp_dev))
+ return -EINVAL;
+
+ if (WARN_ON(mc_io->dpmcp_dev))
+ return -EINVAL;
+
+ if (WARN_ON(dpmcp_dev->mc_io))
+ return -EINVAL;
+
+ if (!(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)) {
+ error = dpmcp_open(mc_io, dpmcp_dev->obj_desc.id,
+ &dpmcp_dev->mc_handle);
+ if (error < 0)
+ return error;
+ }
+
+ mc_io->dpmcp_dev = dpmcp_dev;
+ dpmcp_dev->mc_io = mc_io;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_mc_io_set_dpmcp);
+
+void fsl_mc_io_unset_dpmcp(struct fsl_mc_io *mc_io)
+{
+ int error;
+ struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
+
+ if (WARN_ON(!dpmcp_dev))
+ return;
+
+ if (WARN_ON(dpmcp_dev->mc_io != mc_io))
+ return;
+
+ if (!(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)) {
+ if (dpmcp_dev->irqs)
+ teardown_dpmcp_irq(mc_io);
+
+ error = dpmcp_close(mc_io, dpmcp_dev->mc_handle);
+ if (error < 0) {
+ dev_err(&dpmcp_dev->dev, "dpmcp_close() failed: %d\n",
+ error);
+ }
+ }
+
+ mc_io->dpmcp_dev = NULL;
+ dpmcp_dev->mc_io = NULL;
+}
+EXPORT_SYMBOL_GPL(fsl_mc_io_unset_dpmcp);
+
static int mc_status_to_error(enum mc_cmd_status status)
{
static const int mc_status_to_error_map[] = {
@@ -228,46 +535,51 @@ static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem *
return status;
}
-/**
- * Sends an command to the MC device using the given MC I/O object
- *
- * @mc_io: MC I/O object to be used
- * @cmd: command to be sent
- *
- * Returns '0' on Success; Error code otherwise.
- */
-int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
+static int mc_completion_wait(struct fsl_mc_io *mc_io, struct mc_command *cmd,
+ enum mc_cmd_status *mc_status)
{
- int error;
enum mc_cmd_status status;
- unsigned long jiffies_until_timeout =
- jiffies + msecs_to_jiffies(MC_CMD_COMPLETION_TIMEOUT_MS);
+ unsigned long jiffies_left;
+ unsigned long timeout_jiffies =
+ msecs_to_jiffies(MC_CMD_COMPLETION_TIMEOUT_MS);
- if (WARN_ON(in_irq()))
+ if (WARN_ON(!mc_io->dpmcp_dev))
return -EINVAL;
- if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
- spin_lock(&mc_io->spinlock);
- else
- mutex_lock(&mc_io->mutex);
+ if (WARN_ON(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL))
+ return -EINVAL;
- /*
- * Send command to the MC hardware:
- */
- mc_write_command(mc_io->portal_virt_addr, cmd);
+ if (WARN_ON(!preemptible()))
+ return -EINVAL;
+
+ for (;;) {
+ status = mc_read_response(mc_io->portal_virt_addr, cmd);
+ if (status != MC_CMD_STATUS_READY)
+ break;
+
+ jiffies_left = wait_for_completion_timeout(
+ &mc_io->mc_command_done_completion,
+ timeout_jiffies);
+ if (jiffies_left == 0)
+ return -ETIMEDOUT;
+ }
+
+ *mc_status = status;
+ return 0;
+}
+
+static int mc_polling_wait(struct fsl_mc_io *mc_io, struct mc_command *cmd,
+ enum mc_cmd_status *mc_status)
+{
+ enum mc_cmd_status status;
+ unsigned long jiffies_until_timeout =
+ jiffies + msecs_to_jiffies(MC_CMD_COMPLETION_TIMEOUT_MS);
- /*
- * Wait for response from the MC hardware:
- */
for (;;) {
status = mc_read_response(mc_io->portal_virt_addr, cmd);
if (status != MC_CMD_STATUS_READY)
break;
- /*
- * TODO: When MC command completion interrupts are supported
- * call wait function here instead of usleep_range()
- */
if (preemptible()) {
usleep_range(MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS,
MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
@@ -283,13 +595,53 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
(unsigned int)
MC_CMD_HDR_READ_CMDID(cmd->header));
- error = -ETIMEDOUT;
- goto common_exit;
+ return -ETIMEDOUT;
}
}
+ *mc_status = status;
+ return 0;
+}
+
+/**
+ * Sends a command to the MC device using the given MC I/O object
+ *
+ * @mc_io: MC I/O object to be used
+ * @cmd: command to be sent
+ *
+ * Returns '0' on Success; Error code otherwise.
+ */
+int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
+{
+ int error;
+ enum mc_cmd_status status;
+
+ if (WARN_ON(in_irq()))
+ return -EINVAL;
+
+ if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
+ spin_lock(&mc_io->spinlock);
+ else
+ mutex_lock(&mc_io->mutex);
+
+ /*
+ * Send command to the MC hardware:
+ */
+ mc_write_command(mc_io->portal_virt_addr, cmd);
+
+ /*
+ * Wait for response from the MC hardware:
+ */
+ if (mc_io->mc_command_done_irq_armed)
+ error = mc_completion_wait(mc_io, cmd, &status);
+ else
+ error = mc_polling_wait(mc_io, cmd, &status);
+
+ if (error < 0)
+ goto common_exit;
+
if (status != MC_CMD_STATUS_OK) {
- pr_debug("MC command failed: portal: %#llx, obj handle: %#x, command: %#x, status: %s (%#x)\n",
+ pr_debug("MC cmd failed: portal: %#llx, obj handle: %#x, cmd: %#x, status: %s (%#x)\n",
mc_io->portal_phys_addr,
(unsigned int)MC_CMD_HDR_READ_TOKEN(cmd->header),
(unsigned int)MC_CMD_HDR_READ_CMDID(cmd->header),
diff --git a/drivers/staging/fsl-mc/include/mc-private.h b/drivers/staging/fsl-mc/include/mc-private.h
index af7bd81..ebb5061 100644
--- a/drivers/staging/fsl-mc/include/mc-private.h
+++ b/drivers/staging/fsl-mc/include/mc-private.h
@@ -111,12 +111,14 @@ struct fsl_mc_resource_pool {
* from the physical DPRC.
* @irq_resources: Pointer to array of IRQ objects for the IRQ pool.
* @scan_mutex: Serializes bus scanning
+ * @dprc_attr: DPRC attributes
*/
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 */
+ struct dprc_attributes dprc_attr;
};
#define to_fsl_mc_bus(_mc_dev) \
@@ -134,10 +136,6 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
const char *driver_override,
unsigned int *total_irq_count);
-int dprc_lookup_object(struct fsl_mc_device *mc_bus_dev,
- struct fsl_mc_device *child_dev,
- u32 *child_obj_index);
-
int __init dprc_driver_init(void);
void __exit dprc_driver_exit(void);
diff --git a/drivers/staging/fsl-mc/include/mc-sys.h b/drivers/staging/fsl-mc/include/mc-sys.h
index d2c95831..c426e63 100644
--- a/drivers/staging/fsl-mc/include/mc-sys.h
+++ b/drivers/staging/fsl-mc/include/mc-sys.h
@@ -39,6 +39,7 @@
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
@@ -57,9 +58,11 @@ struct mc_command;
* @portal_size: MC command portal size in bytes
* @portal_phys_addr: MC command portal physical address
* @portal_virt_addr: MC command portal virtual address
- * @resource: generic resource associated with the MC portal if
- * the MC portal came from a resource pool, or NULL if the MC portal
- * is permanently bound to a device (e.g., a DPRC)
+ * @dpmcp_dev: pointer to the DPMCP device associated with the MC portal.
+ * @mc_command_done_irq_armed: Flag indicating that the MC command done IRQ
+ * is currently armed.
+ * @mc_command_done_completion: Completion variable to be signaled when an MC
+ * command sent to the MC fw is completed.
* @mutex: Mutex to serialize mc_send_command() calls that use the same MC
* portal, if the fsl_mc_io object was created with the
* FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag off. mc_send_command() calls for this
@@ -75,21 +78,41 @@ struct fsl_mc_io {
u16 portal_size;
phys_addr_t portal_phys_addr;
void __iomem *portal_virt_addr;
- struct fsl_mc_resource *resource;
+ struct fsl_mc_device *dpmcp_dev;
union {
- struct mutex mutex; /* serializes mc_send_command() calls */
- spinlock_t spinlock; /* serializes mc_send_command() calls */
+ /*
+ * These fields are only meaningful if the
+ * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not set
+ */
+ struct {
+ struct mutex mutex; /* serializes mc_send_command() */
+ struct completion mc_command_done_completion;
+ bool mc_command_done_irq_armed;
+ };
+
+ /*
+ * This field is only meaningful if the
+ * FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is set
+ */
+ spinlock_t spinlock; /* serializes mc_send_command() */
};
};
int __must_check fsl_create_mc_io(struct device *dev,
phys_addr_t mc_portal_phys_addr,
uint32_t mc_portal_size,
- struct fsl_mc_resource *resource,
+ struct fsl_mc_device *dpmcp_dev,
uint32_t flags, struct fsl_mc_io **new_mc_io);
void fsl_destroy_mc_io(struct fsl_mc_io *mc_io);
+int fsl_mc_io_set_dpmcp(struct fsl_mc_io *mc_io,
+ struct fsl_mc_device *dpmcp_dev);
+
+void fsl_mc_io_unset_dpmcp(struct fsl_mc_io *mc_io);
+
+int fsl_mc_io_setup_dpmcp_irq(struct fsl_mc_io *mc_io);
+
int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd);
#endif /* _FSL_MC_SYS_H */
--
2.3.3
^ permalink raw reply related [flat|nested] 21+ messages in thread