This patch series includes new functionality for the Freescale fsl-mc
bus driver.
Patch 1: MC bus IRQ support
Patch 2: add device binding path 'driver_override'
Patch 3: Propagate driver_override for a child DPRC's children
Patch 4: Upgraded MC bus driver to match MC fw 7.0.0
Patch 5: Allow the MC bus driver to run without GIC support
Patch 6: Add locking to serialize mc_send_command() calls
Patch 7: Use DPMCP IRQ and completion var to wait for MC
CHANGE HISTORY
Changes in v4:
- Addressed comments from Dan Carpenter and Greg Kroah-Hartman.
Changes in v3:
- Addressed comments from Dan Carpenter.
Changes in v2:
- Addressed comments from Dan Carpenter and Scott Wood.
Details in each patch.
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 <[email protected]>
Reviewed-by: Stuart Yoder <[email protected]>
---
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
From: Bharat Bhushan <[email protected]>
This patch is required for vfio-fsl-mc meta driver to successfully bind
layerscape container devices for device passthrough. This patch adds
a mechanism to allow a layerscape device to specify a driver rather than
a layerscape driver provide a device match.
This patch is based on following proposed patches for PCI and platform devices
- https://lkml.org/lkml/2014/4/8/571 :- For Platform devices
- http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-device-binding-path-using-pci_dev-driver_override.html :- For PCI devices
Example to allow a device (dprc.1) to specifically bind
with driver (vfio-fsl-mc):-
- echo vfio-fsl-mc > /sys/bus/fsl-mc/devices/dprc.1/driver_override
- echo dprc.1 > /sys/bus/fsl-mc/drivers/fsl_mc_dprc/unbind
- echo dprc.1 > /sys/bus/fsl-mc/drivers/vfio-fsl-mc/bind
Signed-off-by: J. German Rivera <[email protected]>
Reviewed-by: Stuart Yoder <[email protected]>
Tested-by: Stuart Yoder <[email protected]>
---
drivers/staging/fsl-mc/bus/mc-bus.c | 67 +++++++++++++++++++++++++++++++++++++
drivers/staging/fsl-mc/include/mc.h | 2 ++
2 files changed, 69 insertions(+)
diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c
index 9d98828..fdd3d17 100644
--- a/drivers/staging/fsl-mc/bus/mc-bus.c
+++ b/drivers/staging/fsl-mc/bus/mc-bus.c
@@ -58,6 +58,12 @@ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv)
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);
+ goto out;
+ }
+
if (!mc_drv->match_id_table)
goto out;
@@ -116,10 +122,69 @@ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+ const char *driver_override, *old = mc_dev->driver_override;
+ char *cp;
+
+ if (WARN_ON(dev->bus != &fsl_mc_bus_type))
+ return -EINVAL;
+
+ if (count > PATH_MAX)
+ return -EINVAL;
+
+ driver_override = kstrndup(buf, count, GFP_KERNEL);
+ if (!driver_override)
+ return -ENOMEM;
+
+ cp = strchr(driver_override, '\n');
+ if (cp)
+ *cp = '\0';
+
+ if (strlen(driver_override)) {
+ mc_dev->driver_override = driver_override;
+ } else {
+ kfree(driver_override);
+ mc_dev->driver_override = NULL;
+ }
+
+ kfree(old);
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+
+ return sprintf(buf, "%s\n", mc_dev->driver_override);
+}
+
+static DEVICE_ATTR_RW(driver_override);
+
+static struct attribute *fsl_mc_dev_attrs[] = {
+ &dev_attr_driver_override.attr,
+ NULL,
+};
+
+static const struct attribute_group fsl_mc_dev_group = {
+ .attrs = fsl_mc_dev_attrs,
+};
+
+static const struct attribute_group *fsl_mc_dev_groups[] = {
+ &fsl_mc_dev_group,
+ NULL,
+};
+
struct bus_type fsl_mc_bus_type = {
.name = "fsl-mc",
.match = fsl_mc_bus_match,
.uevent = fsl_mc_bus_uevent,
+ .dev_groups = fsl_mc_dev_groups,
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
@@ -492,6 +557,8 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
fsl_mc_bus_type.dev_root = NULL;
}
+ kfree(mc_dev->driver_override);
+ mc_dev->driver_override = NULL;
if (!mc_bus)
kmem_cache_free(mc_dev_cache, mc_dev);
else
diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h
index c543a84..322b594 100644
--- a/drivers/staging/fsl-mc/include/mc.h
+++ b/drivers/staging/fsl-mc/include/mc.h
@@ -145,6 +145,7 @@ struct fsl_mc_device_irq {
* @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.
+ * @driver_override: Driver name to force a match
*
* Generic device object for MC object devices that are "attached" to a
* MC bus.
@@ -177,6 +178,7 @@ struct fsl_mc_device {
struct resource *regions;
struct fsl_mc_device_irq **irqs;
struct fsl_mc_resource *resource;
+ const char *driver_override;
};
#define to_fsl_mc_device(_dev) \
--
2.3.3
When a child DPRC is bound to the vfio_fsl_mc driver via driver_override,
its own children should not be bound to corresponding host kernel
drivers, but instead should be bound to the vfio_fsl_mc driver as
well.
Currently, when a child container is scanned by the vfio_fsl_mc driver,
child devices found are automatically bound to corresponding host kernel
drivers (e.g., DPMCP and DPBP objects are bound to the fsl_mc_allocator
driver, DPNI objects are bound to the ldpaa_eth driver, etc), Then,
the user has to manually unbind these child devices from their drivers,
set the driver_override sysfs attribute to vfio_fsl_mc driver, for each
of them and rebind them.
Signed-off-by: J. German Rivera <[email protected]>
Reviewed-by: Stuart Yoder <[email protected]>
Tested-by: Stuart Yoder <[email protected]>
---
drivers/staging/fsl-mc/bus/dprc-driver.c | 14 ++++++++++----
drivers/staging/fsl-mc/bus/mc-bus.c | 16 +++++++++++++++-
drivers/staging/fsl-mc/include/mc-private.h | 2 ++
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 5351170..85ec91b 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -151,6 +151,8 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
* dprc_add_new_devices - Adds devices to the logical bus for a DPRC
*
* @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
+ * @driver_override: driver override to apply to new objects found in the DPRC,
+ * or NULL, if none.
* @obj_desc_array: array of device descriptors for child devices currently
* present in the physical DPRC.
* @num_child_objects_in_mc: number of entries in obj_desc_array
@@ -160,6 +162,7 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
* in the physical DPRC.
*/
static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
+ const char *driver_override,
struct dprc_obj_desc *obj_desc_array,
int num_child_objects_in_mc)
{
@@ -183,7 +186,7 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
}
error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
- &child_dev);
+ driver_override, &child_dev);
if (error < 0)
continue;
}
@@ -211,6 +214,8 @@ static void dprc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
* dprc_scan_objects - Discover objects in a DPRC
*
* @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
+ * @driver_override: driver override to apply to new objects found in the DPRC,
+ * or NULL, if none.
* @total_irq_count: total number of IRQs needed by objects in the DPRC.
*
* Detects objects added and removed from a DPRC and synchronizes the
@@ -226,6 +231,7 @@ static void dprc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
* of the device drivers for the non-allocatable devices.
*/
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
+ const char *driver_override,
unsigned int *total_irq_count)
{
int num_child_objects;
@@ -295,7 +301,7 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
num_child_objects);
- dprc_add_new_devices(mc_bus_dev, child_obj_desc_array,
+ dprc_add_new_devices(mc_bus_dev, driver_override, child_obj_desc_array,
num_child_objects);
kfree(child_obj_desc_array);
@@ -324,7 +330,7 @@ static 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, &irq_count);
+ error = dprc_scan_objects(mc_bus_dev, NULL, &irq_count);
mutex_unlock(&mc_bus->scan_mutex);
if (error < 0)
return error;
@@ -397,7 +403,7 @@ static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
DPRC_IRQ_EVENT_OBJ_CREATED)) {
unsigned int irq_count;
- error = dprc_scan_objects(mc_dev, &irq_count);
+ error = dprc_scan_objects(mc_dev, NULL, &irq_count);
if (error < 0) {
dev_err(dev, "dprc_scan_objects() failed: %d\n", error);
goto out;
diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c
index fdd3d17..60e45be 100644
--- a/drivers/staging/fsl-mc/bus/mc-bus.c
+++ b/drivers/staging/fsl-mc/bus/mc-bus.c
@@ -401,6 +401,7 @@ error_cleanup_regions:
int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
struct fsl_mc_io *mc_io,
struct device *parent_dev,
+ const char *driver_override,
struct fsl_mc_device **new_mc_dev)
{
int error;
@@ -433,6 +434,18 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
mc_dev->obj_desc = *obj_desc;
mc_dev->mc_io = mc_io;
+ if (driver_override) {
+ /*
+ * We trust driver_override, so we don't need to use
+ * kstrndup() here
+ */
+ mc_dev->driver_override = kstrdup(driver_override, GFP_KERNEL);
+ if (!mc_dev->driver_override) {
+ error = -ENOMEM;
+ goto error_cleanup_dev;
+ }
+ }
+
device_initialize(&mc_dev->dev);
mc_dev->dev.parent = parent_dev;
mc_dev->dev.bus = &fsl_mc_bus_type;
@@ -870,7 +883,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
obj_desc.irq_count = 1;
obj_desc.region_count = 0;
- error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev);
+ error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, NULL,
+ &mc_bus_dev);
if (error < 0)
goto error_cleanup_mc_io;
diff --git a/drivers/staging/fsl-mc/include/mc-private.h b/drivers/staging/fsl-mc/include/mc-private.h
index 6e33942..5b9c8f2 100644
--- a/drivers/staging/fsl-mc/include/mc-private.h
+++ b/drivers/staging/fsl-mc/include/mc-private.h
@@ -106,11 +106,13 @@ struct fsl_mc_bus {
int __must_check fsl_mc_device_add(struct dprc_obj_desc *obj_desc,
struct fsl_mc_io *mc_io,
struct device *parent_dev,
+ const char *driver_override,
struct fsl_mc_device **new_mc_dev);
void fsl_mc_device_remove(struct fsl_mc_device *mc_dev);
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
+ const char *driver_override,
unsigned int *total_irq_count);
int __init dprc_driver_init(void);
--
2.3.3
- 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 <[email protected]>
---
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
If the msi-parent property is not present in the fsl,qoriq-mc node
of the device tree, the MC bus driver will assume that the GIC is not
supported.
This change is made in order to be able to use the MC bus driver in a
KVM VM, without having GIC-ITS support in guests. Added function
fsl_mc_interrupts_supported(), which can be called from DPAA2 object
drivers.
Signed-off-by: J. German Rivera <[email protected]>
Reviewed-by: Stuart Yoder <[email protected]>
---
drivers/staging/fsl-mc/bus/dprc-driver.c | 31 +++++++++++++++++++----------
drivers/staging/fsl-mc/bus/mc-allocator.c | 4 ++++
drivers/staging/fsl-mc/bus/mc-bus.c | 16 +++++++++++++++
drivers/staging/fsl-mc/include/mc-private.h | 4 ++++
drivers/staging/fsl-mc/include/mc.h | 2 ++
5 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 6bd20c0..dc97681 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -323,6 +323,7 @@ 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);
@@ -335,7 +336,7 @@ static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev)
if (error < 0)
return error;
- if (!mc_bus->irq_resources) {
+ if (mc->gic_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)
@@ -634,6 +635,7 @@ 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;
@@ -686,19 +688,23 @@ 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_dprc_scan;
+ if (mc->gic_supported) {
+ /*
+ * Configure interrupts for the DPRC object associated with
+ * this MC bus:
+ */
+ error = dprc_setup_irqs(mc_dev);
+ if (error < 0)
+ goto error_cleanup_dprc_scan;
+ }
dev_info(&mc_dev->dev, "DPRC device bound to driver");
return 0;
error_cleanup_dprc_scan:
device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
- fsl_mc_cleanup_irq_pool(mc_bus);
+ if (mc->gic_supported)
+ fsl_mc_cleanup_irq_pool(mc_bus);
error_cleanup_open:
(void)dprc_close(mc_dev->mc_io, mc_dev->mc_handle);
@@ -738,6 +744,7 @@ 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;
@@ -747,13 +754,17 @@ static int dprc_remove(struct fsl_mc_device *mc_dev)
if (WARN_ON(!mc_bus->irq_resources))
return -EINVAL;
- dprc_teardown_irqs(mc_dev);
+ if (mc->gic_supported)
+ dprc_teardown_irqs(mc_dev);
+
device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
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);
+ if (mc->gic_supported)
+ 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 e445f79..3bdfefb 100644
--- a/drivers/staging/fsl-mc/bus/mc-allocator.c
+++ b/drivers/staging/fsl-mc/bus/mc-allocator.c
@@ -485,6 +485,10 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
struct fsl_mc_device_irq **irqs = NULL;
struct fsl_mc_bus *mc_bus;
struct fsl_mc_resource_pool *res_pool;
+ struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
+
+ if (!mc->gic_supported)
+ return -ENOTSUPP;
if (WARN_ON(mc_dev->irqs))
return -EINVAL;
diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c
index e5ea3ea..36bfe68 100644
--- a/drivers/staging/fsl-mc/bus/mc-bus.c
+++ b/drivers/staging/fsl-mc/bus/mc-bus.c
@@ -287,6 +287,14 @@ void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver)
}
EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister);
+bool fsl_mc_interrupts_supported(void)
+{
+ struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
+
+ return mc->gic_supported;
+}
+EXPORT_SYMBOL_GPL(fsl_mc_interrupts_supported);
+
static int get_dprc_icid(struct fsl_mc_io *mc_io,
int container_id, uint16_t *icid)
{
@@ -839,6 +847,14 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
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");
+ } else {
+ mc->gic_supported = true;
+ }
+
/*
* Get physical address of MC portal for the root DPRC:
*/
diff --git a/drivers/staging/fsl-mc/include/mc-private.h b/drivers/staging/fsl-mc/include/mc-private.h
index 8e02dc9..af7bd81 100644
--- a/drivers/staging/fsl-mc/include/mc-private.h
+++ b/drivers/staging/fsl-mc/include/mc-private.h
@@ -42,11 +42,15 @@
* 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
+ * @gic_supported: boolean flag that indicates if the GIC interrupt controller
+ * is supported.
+ * @num_translation_ranges: number of entries in addr_translation_ranges
* @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;
+ bool gic_supported;
u8 num_translation_ranges;
struct fsl_mc_addr_translation_range *translation_ranges;
};
diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h
index 7fa2816..56b7b47 100644
--- a/drivers/staging/fsl-mc/include/mc.h
+++ b/drivers/staging/fsl-mc/include/mc.h
@@ -209,6 +209,8 @@ int __must_check __fsl_mc_driver_register(struct fsl_mc_driver *fsl_mc_driver,
void fsl_mc_driver_unregister(struct fsl_mc_driver *driver);
+bool fsl_mc_interrupts_supported(void);
+
int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev,
uint16_t mc_io_flags,
struct fsl_mc_io **new_mc_io);
--
2.3.3
Add a locking mechanism to serialize mc_send_command() calls that use
the same fsl_mc_io object (same MC portal). When the fsl_mc_io object is
created the owner needs to know in which type of context the fsl_mc_io
object is going to be used. A flag passed-in to fsl_create_mc_io()
will indicate whether the fsl_mc_io object will be used in atomic or
non-atomic context. If the fsl_mc_io object is going to be used in
non-atomic context only, mc_send_command() calls with it will be
serialized using a mutex. Otherwise, if the fsl_mc_io object is
going to be used in atomic context, mc_semd_command() calls with it
will be serialized using a spinlock.
Signed-off-by: J. German Rivera <[email protected]>
Reviewed-by: Stuart Yoder <[email protected]>
---
Changes in v4:
- Fixed new checkpatch checks
drivers/staging/fsl-mc/bus/mc-sys.c | 40 ++++++++++++++++++++++++++-------
drivers/staging/fsl-mc/include/mc-sys.h | 23 +++++++++++++++++--
2 files changed, 53 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c
index f421411..0da7700 100644
--- a/drivers/staging/fsl-mc/bus/mc-sys.c
+++ b/drivers/staging/fsl-mc/bus/mc-sys.c
@@ -40,9 +40,9 @@
#include <linux/device.h>
/**
- * Timeout in jiffies to wait for the completion of an MC command
+ * Timeout in milliseconds to wait for the completion of an MC command
*/
-#define MC_CMD_COMPLETION_TIMEOUT_JIFFIES (HZ / 2) /* 500 ms */
+#define MC_CMD_COMPLETION_TIMEOUT_MS 500
/*
* usleep_range() min and max values used to throttle down polling
@@ -86,6 +86,11 @@ int __must_check fsl_create_mc_io(struct device *dev,
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)
+ spin_lock_init(&mc_io->spinlock);
+ else
+ mutex_init(&mc_io->mutex);
+
res = devm_request_mem_region(dev,
mc_portal_phys_addr,
mc_portal_size,
@@ -230,14 +235,21 @@ static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem *
* @cmd: command to be sent
*
* Returns '0' on Success; Error code otherwise.
- *
- * NOTE: This function cannot be invoked from from atomic contexts.
*/
int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
{
+ int error;
enum mc_cmd_status status;
unsigned long jiffies_until_timeout =
- jiffies + MC_CMD_COMPLETION_TIMEOUT_JIFFIES;
+ jiffies + msecs_to_jiffies(MC_CMD_COMPLETION_TIMEOUT_MS);
+
+ 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:
@@ -259,6 +271,8 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
if (preemptible()) {
usleep_range(MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS,
MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
+ } else {
+ udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
}
if (time_after_eq(jiffies, jiffies_until_timeout)) {
@@ -269,7 +283,8 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
(unsigned int)
MC_CMD_HDR_READ_CMDID(cmd->header));
- return -ETIMEDOUT;
+ error = -ETIMEDOUT;
+ goto common_exit;
}
}
@@ -281,9 +296,18 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
mc_status_to_string(status),
(unsigned int)status);
- return mc_status_to_error(status);
+ error = mc_status_to_error(status);
+ goto common_exit;
}
- return 0;
+ error = 0;
+
+common_exit:
+ if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
+ spin_unlock(&mc_io->spinlock);
+ else
+ mutex_unlock(&mc_io->mutex);
+
+ return error;
}
EXPORT_SYMBOL(mc_send_command);
diff --git a/drivers/staging/fsl-mc/include/mc-sys.h b/drivers/staging/fsl-mc/include/mc-sys.h
index cb3b5a2..d2c95831 100644
--- a/drivers/staging/fsl-mc/include/mc-sys.h
+++ b/drivers/staging/fsl-mc/include/mc-sys.h
@@ -39,6 +39,13 @@
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+/**
+ * Bit masks for a MC I/O object (struct fsl_mc_io) flags
+ */
+#define FSL_MC_IO_ATOMIC_CONTEXT_PORTAL 0x0001
struct fsl_mc_resource;
struct mc_command;
@@ -53,14 +60,26 @@ struct mc_command;
* @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)
+ * @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
+ * fsl_mc_io object must be made only from non-atomic context.
+ * @spinlock: Spinlock 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 on. mc_send_command() calls for this
+ * fsl_mc_io object can be made from atomic or non-atomic context.
*/
struct fsl_mc_io {
struct device *dev;
- uint32_t flags;
- uint32_t portal_size;
+ u16 flags;
+ u16 portal_size;
phys_addr_t portal_phys_addr;
void __iomem *portal_virt_addr;
struct fsl_mc_resource *resource;
+ union {
+ struct mutex mutex; /* serializes mc_send_command() calls */
+ spinlock_t spinlock; /* serializes mc_send_command() calls */
+ };
};
int __must_check fsl_create_mc_io(struct device *dev,
--
2.3.3
- 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 <[email protected]>
Reviewed-by: Stuart Yoder <[email protected]>
---
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
Hi German,
On Tue, Jun 9, 2015 at 6:59 PM, J. German Rivera
<[email protected]> wrote:
> This patch series includes new functionality for the Freescale fsl-mc
> bus driver.
>
> Patch 1: MC bus IRQ support
> Patch 2: add device binding path 'driver_override'
> Patch 3: Propagate driver_override for a child DPRC's children
> Patch 4: Upgraded MC bus driver to match MC fw 7.0.0
> Patch 5: Allow the MC bus driver to run without GIC support
> Patch 6: Add locking to serialize mc_send_command() calls
> Patch 7: Use DPMCP IRQ and completion var to wait for MC
>
> CHANGE HISTORY
>
> Changes in v4:
> - Addressed comments from Dan Carpenter and Greg Kroah-Hartman.
>
> Changes in v3:
> - Addressed comments from Dan Carpenter.
>
> Changes in v2:
> - Addressed comments from Dan Carpenter and Scott Wood.
> Details in each patch.
Not related to this series, but if you have a chance, please fix this
section mismatch warning from the fsl-mc driver:
allmodconfig WARNING:
drivers/staging/fsl-mc/bus/mc-bus-driver.o(.init.text+0x18c): Section
mismatch in reference from the function init_module() to the function
.exit.text:dprc_driver_exit()
> -----Original Message-----
> From: Fabio Estevam [mailto:[email protected]]
> Sent: Tuesday, June 09, 2015 5:12 PM
> To: Rivera Jose-B46482
> Cc: Greg Kroah-Hartman; Arnd Bergmann; [email protected]; linux-
> kernel; Yoder Stuart-B08248; Sharma Bhupesh-B45370; [email protected];
> Hamciuc Bogdan-BHAMCIU1; Erez Nir-RM30794; katz Itai-RM05202; Wood Scott-
> B07421; Marginean Alexandru-R89243; Dan Carpenter; Schmitt Richard-B43082
> Subject: Re: [PATCH v4 0/7] staging: fsl-mc: New functionality to the MC
> bus driver
>
> Hi German,
>
> On Tue, Jun 9, 2015 at 6:59 PM, J. German Rivera
> <[email protected]> wrote:
> > This patch series includes new functionality for the Freescale fsl-mc
> > bus driver.
> >
> > Patch 1: MC bus IRQ support
> > Patch 2: add device binding path 'driver_override'
> > Patch 3: Propagate driver_override for a child DPRC's children Patch
> > 4: Upgraded MC bus driver to match MC fw 7.0.0 Patch 5: Allow the MC
> > bus driver to run without GIC support Patch 6: Add locking to
> > serialize mc_send_command() calls Patch 7: Use DPMCP IRQ and
> > completion var to wait for MC
> >
> > CHANGE HISTORY
> >
> > Changes in v4:
> > - Addressed comments from Dan Carpenter and Greg Kroah-Hartman.
> >
> > Changes in v3:
> > - Addressed comments from Dan Carpenter.
> >
> > Changes in v2:
> > - Addressed comments from Dan Carpenter and Scott Wood.
> > Details in each patch.
>
> Not related to this series, but if you have a chance, please fix this
> section mismatch warning from the fsl-mc driver:
>
Sure. Thanks for your feedback.
> allmodconfig WARNING:
> drivers/staging/fsl-mc/bus/mc-bus-driver.o(.init.text+0x18c): Section
> mismatch in reference from the function init_module() to the function
> .exit.text:dprc_driver_exit()
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
On Tue, Jun 09, 2015 at 04:59:07PM -0500, J. German Rivera wrote:
> Add a locking mechanism to serialize mc_send_command() calls that use
> the same fsl_mc_io object (same MC portal). When the fsl_mc_io object is
> created the owner needs to know in which type of context the fsl_mc_io
> object is going to be used. A flag passed-in to fsl_create_mc_io()
> will indicate whether the fsl_mc_io object will be used in atomic or
> non-atomic context. If the fsl_mc_io object is going to be used in
> non-atomic context only, mc_send_command() calls with it will be
> serialized using a mutex. Otherwise, if the fsl_mc_io object is
> going to be used in atomic context, mc_semd_command() calls with it
> will be serialized using a spinlock.
>
> Signed-off-by: J. German Rivera <[email protected]>
> Reviewed-by: Stuart Yoder <[email protected]>
My understanding is that no one actually sets
FSL_MC_IO_ATOMIC_CONTEXT_PORTAL?
It's hard to review patches 6 & 7 properly without users. Why don't you
just wait on those until we have a use for it.
regards,
dan carpenter
On Tue, Jun 09, 2015 at 04:59:01PM -0500, J. German Rivera wrote:
> This patch series includes new functionality for the Freescale fsl-mc
> bus driver.
Why are people working on "new functionality" instead of working on
getting this out of the staging tree? I really hate adding new
functions to staging drivers, as this is not the correct place for
drivers to be in the tree. People should be working to get them out of
this location, and then you can add new functions to them.
So I really don't want to take this series, sorry, someone better start
working on getting this out of drivers/staging/ or I'm going to have to
drop the driver entirely from the tree.
thanks,
greg k-h
On Fri, Jun 12, 2015 at 05:18:49PM -0700, Greg KH wrote:
> On Tue, Jun 09, 2015 at 04:59:01PM -0500, J. German Rivera wrote:
> > This patch series includes new functionality for the Freescale fsl-mc
> > bus driver.
>
> Why are people working on "new functionality" instead of working on
> getting this out of the staging tree? I really hate adding new
> functions to staging drivers, as this is not the correct place for
> drivers to be in the tree. People should be working to get them out of
> this location, and then you can add new functions to them.
Hi Greg,
Your reply above was for a different thread but my doubt started from
this. I was working on adding the Dual-Head support to sm7xxfb. So that
is also a new functionality which is not in the current driver as of now.
Then should i instead concentrate on getting that out of staging? If yes,
can you please have a look (when you are free) at it to see if anything
else needs to be done.
regards
sudip
On Sat, Jun 13, 2015 at 02:16:18PM +0530, Sudip Mukherjee wrote:
> On Fri, Jun 12, 2015 at 05:18:49PM -0700, Greg KH wrote:
> > On Tue, Jun 09, 2015 at 04:59:01PM -0500, J. German Rivera wrote:
> > > This patch series includes new functionality for the Freescale fsl-mc
> > > bus driver.
> >
> > Why are people working on "new functionality" instead of working on
> > getting this out of the staging tree? I really hate adding new
> > functions to staging drivers, as this is not the correct place for
> > drivers to be in the tree. People should be working to get them out of
> > this location, and then you can add new functions to them.
> Hi Greg,
> Your reply above was for a different thread but my doubt started from
> this. I was working on adding the Dual-Head support to sm7xxfb. So that
> is also a new functionality which is not in the current driver as of now.
> Then should i instead concentrate on getting that out of staging? If yes,
> can you please have a look (when you are free) at it to see if anything
> else needs to be done.
Yes, please work on getting it out of staging.
If you think it's ready, then submit a patch that moves it, copying the
proper maintainers, and I'll be glad to review it.
thanks,
greg k-h
On Sat, 2015-06-13 at 09:28 -0700, Greg KH wrote:
> On Sat, Jun 13, 2015 at 02:16:18PM +0530, Sudip Mukherjee wrote:
[]
> > Your reply above was for a different thread but my doubt started from
> > this. I was working on adding the Dual-Head support to sm7xxfb. So that
> > is also a new functionality which is not in the current driver as of now.
> > Then should i instead concentrate on getting that out of staging? If yes,
> > can you please have a look (when you are free) at it to see if anything
> > else needs to be done.
>
> Yes, please work on getting it out of staging.
>
> If you think it's ready, then submit a patch that moves it, copying the
> proper maintainers, and I'll be glad to review it.
It seems ready to me.
As far as I can tell, there's just a few niggles
that could be done:
Something like (too lazy to separate them into multiple patches)
o reduce indentation a couple of places
o add newlines to logging messages
o add const to static array
o use consistent function declaration style
It's unfortunate there are so many #ifdef __BIG_ENDIAN uses.
---
drivers/staging/sm7xxfb/sm7xxfb.c | 203 ++++++++++++++++++--------------------
1 file changed, 96 insertions(+), 107 deletions(-)
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
index 5db26f1..5be2560 100644
--- a/drivers/staging/sm7xxfb/sm7xxfb.c
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -94,7 +94,7 @@ struct vesa_mode {
u16 lfb_depth;
};
-static struct vesa_mode vesa_mode_table[] = {
+static const struct vesa_mode vesa_mode_table[] = {
{"0x301", 640, 480, 8},
{"0x303", 800, 600, 8},
{"0x305", 1024, 768, 8},
@@ -255,37 +255,32 @@ static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
/*
* 16/32 bit true-colour, use pseudo-palette for 16 base color
*/
- if (regno < 16) {
- if (sfb->fb->var.bits_per_pixel == 16) {
- u32 *pal = sfb->fb->pseudo_palette;
-
- val = chan_to_field(red, &sfb->fb->var.red);
- val |= chan_to_field(green,
- &sfb->fb->var.green);
- val |= chan_to_field(blue, &sfb->fb->var.blue);
+ if (regno >= 16)
+ break;
+ if (sfb->fb->var.bits_per_pixel == 16) {
+ u32 *pal = sfb->fb->pseudo_palette;
+
+ val = chan_to_field(red, &sfb->fb->var.red);
+ val |= chan_to_field(green, &sfb->fb->var.green);
+ val |= chan_to_field(blue, &sfb->fb->var.blue);
#ifdef __BIG_ENDIAN
- pal[regno] =
- ((red & 0xf800) >> 8) |
- ((green & 0xe000) >> 13) |
- ((green & 0x1c00) << 3) |
- ((blue & 0xf800) >> 3);
+ pal[regno] = (((red & 0xf800) >> 8) |
+ ((green & 0xe000) >> 13) |
+ ((green & 0x1c00) << 3) |
+ ((blue & 0xf800) >> 3));
#else
- pal[regno] = val;
+ pal[regno] = val;
#endif
- } else {
- u32 *pal = sfb->fb->pseudo_palette;
+ } else {
+ u32 *pal = sfb->fb->pseudo_palette;
- val = chan_to_field(red, &sfb->fb->var.red);
- val |= chan_to_field(green,
- &sfb->fb->var.green);
- val |= chan_to_field(blue, &sfb->fb->var.blue);
+ val = chan_to_field(red, &sfb->fb->var.red);
+ val |= chan_to_field(green, &sfb->fb->var.green);
+ val |= chan_to_field(blue, &sfb->fb->var.blue);
#ifdef __BIG_ENDIAN
- val =
- (val & 0xff00ff00 >> 8) |
- (val & 0x00ff00ff << 8);
+ val = (val & 0xff00ff00 >> 8) | (val & 0x00ff00ff << 8);
#endif
- pal[regno] = val;
- }
+ pal[regno] = val;
}
break;
@@ -302,8 +297,8 @@ static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
}
#ifdef __BIG_ENDIAN
-static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
- count, loff_t *ppos)
+static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
@@ -346,9 +341,8 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
dst = buffer;
for (i = c >> 2; i--;) {
*dst = fb_readl(src++);
- *dst =
- (*dst & 0xff00ff00 >> 8) |
- (*dst & 0x00ff00ff << 8);
+ *dst = (*dst & 0xff00ff00 >> 8) |
+ (*dst & 0x00ff00ff << 8);
dst++;
}
if (c & 3) {
@@ -381,9 +375,8 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
return (err) ? err : cnt;
}
-static ssize_t
-smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
- loff_t *ppos)
+static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
@@ -478,72 +471,69 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb)
sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
for (j = 0; j < numvgamodes; j++) {
- if (vgamode[j].mmsizex == sfb->width &&
- vgamode[j].mmsizey == sfb->height &&
- vgamode[j].bpp == sfb->fb->var.bits_per_pixel &&
- vgamode[j].hz == sfb->hz) {
- dev_dbg(&sfb->pdev->dev,
- "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
- vgamode[j].mmsizex, vgamode[j].mmsizey,
- vgamode[j].bpp, vgamode[j].hz);
-
- dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
-
- smtc_mmiowb(0x0, 0x3c6);
-
- smtc_seqw(0, 0x1);
-
- smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
-
- /* init SEQ register SR00 - SR04 */
- for (i = 0; i < SIZE_SR00_SR04; i++)
- smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
-
- /* init SEQ register SR10 - SR24 */
- for (i = 0; i < SIZE_SR10_SR24; i++)
- smtc_seqw(i + 0x10,
- vgamode[j].init_sr10_sr24[i]);
-
- /* init SEQ register SR30 - SR75 */
- for (i = 0; i < SIZE_SR30_SR75; i++)
- if ((i + 0x30) != 0x62 &&
- (i + 0x30) != 0x6a &&
- (i + 0x30) != 0x6b)
- smtc_seqw(i + 0x30,
- vgamode[j].init_sr30_sr75[i]);
-
- /* init SEQ register SR80 - SR93 */
- for (i = 0; i < SIZE_SR80_SR93; i++)
- smtc_seqw(i + 0x80,
- vgamode[j].init_sr80_sr93[i]);
-
- /* init SEQ register SRA0 - SRAF */
- for (i = 0; i < SIZE_SRA0_SRAF; i++)
- smtc_seqw(i + 0xa0,
- vgamode[j].init_sra0_sraf[i]);
-
- /* init Graphic register GR00 - GR08 */
- for (i = 0; i < SIZE_GR00_GR08; i++)
- smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
-
- /* init Attribute register AR00 - AR14 */
- for (i = 0; i < SIZE_AR00_AR14; i++)
- smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
-
- /* init CRTC register CR00 - CR18 */
- for (i = 0; i < SIZE_CR00_CR18; i++)
- smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
-
- /* init CRTC register CR30 - CR4D */
- for (i = 0; i < SIZE_CR30_CR4D; i++)
- smtc_crtcw(i + 0x30,
- vgamode[j].init_cr30_cr4d[i]);
-
- /* init CRTC register CR90 - CRA7 */
- for (i = 0; i < SIZE_CR90_CRA7; i++)
- smtc_crtcw(i + 0x90,
- vgamode[j].init_cr90_cra7[i]);
+ if (vgamode[j].mmsizex != sfb->width ||
+ vgamode[j].mmsizey != sfb->height ||
+ vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
+ vgamode[j].hz != sfb->hz)
+ continue;
+
+ dev_dbg(&sfb->pdev->dev,
+ "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
+ vgamode[j].mmsizex, vgamode[j].mmsizey,
+ vgamode[j].bpp, vgamode[j].hz);
+
+ dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
+
+ smtc_mmiowb(0x0, 0x3c6);
+
+ smtc_seqw(0, 0x1);
+
+ smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
+
+ /* init SEQ register SR00 - SR04 */
+ for (i = 0; i < SIZE_SR00_SR04; i++)
+ smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
+
+ /* init SEQ register SR10 - SR24 */
+ for (i = 0; i < SIZE_SR10_SR24; i++)
+ smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
+
+ /* init SEQ register SR30 - SR75 */
+ for (i = 0; i < SIZE_SR30_SR75; i++) {
+ if ((i + 0x30) != 0x62 &&
+ (i + 0x30) != 0x6a &&
+ (i + 0x30) != 0x6b)
+ smtc_seqw(i + 0x30,
+ vgamode[j].init_sr30_sr75[i]);
}
+
+ /* init SEQ register SR80 - SR93 */
+ for (i = 0; i < SIZE_SR80_SR93; i++)
+ smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
+
+ /* init SEQ register SRA0 - SRAF */
+ for (i = 0; i < SIZE_SRA0_SRAF; i++)
+ smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
+
+ /* init Graphic register GR00 - GR08 */
+ for (i = 0; i < SIZE_GR00_GR08; i++)
+ smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
+
+ /* init Attribute register AR00 - AR14 */
+ for (i = 0; i < SIZE_AR00_AR14; i++)
+ smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
+
+ /* init CRTC register CR00 - CR18 */
+ for (i = 0; i < SIZE_CR00_CR18; i++)
+ smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
+
+ /* init CRTC register CR30 - CR4D */
+ for (i = 0; i < SIZE_CR30_CR4D; i++)
+ smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
+
+ /* init CRTC register CR90 - CRA7 */
+ for (i = 0; i < SIZE_CR90_CRA7; i++)
+ smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
}
smtc_mmiowb(0x67, 0x3c2);
@@ -552,8 +542,7 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb)
writel(0x0, sfb->vp_regs + 0x40);
/* set data width */
- m_nscreenstride =
- (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
+ m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
switch (sfb->fb->var.bits_per_pixel) {
case 8:
writel(0x0, sfb->vp_regs + 0x0);
@@ -741,7 +730,7 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
int err;
unsigned long mmio_base;
- dev_info(&pdev->dev, "Silicon Motion display driver.");
+ dev_info(&pdev->dev, "Silicon Motion display driver\n");
err = pci_enable_device(pdev); /* enable SMTC chip */
if (err)
@@ -815,12 +804,12 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
#ifdef __BIG_ENDIAN
if (sfb->fb->var.bits_per_pixel == 32) {
sfb->lfb += 0x800000;
- dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
+ dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
}
#endif
if (!smtc_regbaseaddress) {
dev_err(&pdev->dev,
- "%s: unable to map memory mapped IO!",
+ "%s: unable to map memory mapped IO!\n",
sfb->fb->fix.id);
err = -ENOMEM;
goto failed_fb;
@@ -854,7 +843,7 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
break;
default:
dev_err(&pdev->dev,
- "No valid Silicon Motion display chip was detected!");
+ "No valid Silicon Motion display chip was detected!\n");
goto failed_fb;
}
@@ -876,14 +865,14 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
goto failed;
dev_info(&pdev->dev,
- "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete\n",
sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
return 0;
failed:
- dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init failed\n");
smtc_unmap_smem(sfb);
smtc_unmap_mmio(sfb);
On Sat, Jun 13, 2015 at 09:57:05AM -0700, Joe Perches wrote:
>
> It seems ready to me.
>
> As far as I can tell, there's just a few niggles
> that could be done:
>
> Something like (too lazy to separate them into multiple patches)
Thanks. I will break into patches. Call me lazy for not having it done
till now.
>
> o reduce indentation a couple of places
> o add newlines to logging messages
> o add const to static array
> o use consistent function declaration style
>
> It's unfortunate there are so many #ifdef __BIG_ENDIAN uses.
instead of #ifdef __BIG_ENDIAN can i then use a bool flag to check by if-else?
regards
sudip
On Mon, 2015-06-15 at 10:47 +0530, Sudip Mukherjee wrote:
> On Sat, Jun 13, 2015 at 09:57:05AM -0700, Joe Perches wrote:
> > It's unfortunate there are so many #ifdef __BIG_ENDIAN uses.
> instead of #ifdef __BIG_ENDIAN can i then use a bool flag to check by if-else?
I think that'd be worse. Moving the #ifdef into the .h
may be better, but <shrug>, whatever works well enough.
Another thing may be to move the vgamode array declaration
in fb7xx.h to the .c file and make it const and remove the
#define numvgamodes and just use ARRAY_SIZE directly in
the one place it's used.
Greg,
Thanks for your feedback. It is our fault that we did not articulate
clearly our intent with this patch series. First, for reference, let
us summarize here the patches in question:
Patch 1: MC bus IRQ support
Patch 2: add device binding path 'driver_override'
Patch 3: Propagate driver_override for a child DPRC's children
Patch 4: Upgraded MC bus driver to match MC fw 7.0.0
Patch 5: Allow the MC bus driver to run without GIC support
Patch 6: Add locking to serialize mc_send_command() calls
Patch 7: Use DPMCP IRQ and completion var to wait for MC
With the exception of patches 2 and 3 (needed for vfio), our intent with
the rest was to make to changes to work towards completing the "Add at
least one device driver for a DPAA2 object" on the TODO list.
Before sending further patches we will submit an update to the TODO list
to provide more detail and visibility into our plan to complete the
"Add at least one device driver..." item. It's too broad as written.
In particular, we think interrupt support is required and a pre-requisite.
Thanks,
German
> -----Original Message-----
> From: Greg KH [mailto:[email protected]]
> Sent: Friday, June 12, 2015 7:19 PM
> To: Rivera Jose-B46482
> Cc: [email protected]; [email protected]; linux-
> [email protected]; Yoder Stuart-B08248; Sharma Bhupesh-B45370;
> [email protected]; Hamciuc Bogdan-BHAMCIU1; Erez Nir-RM30794; katz Itai-
> RM05202; Wood Scott-B07421; Marginean Alexandru-R89243;
> [email protected]; Schmitt Richard-B43082
> Subject: Re: [PATCH v4 0/7] staging: fsl-mc: New functionality to the MC
> bus driver
>
> On Tue, Jun 09, 2015 at 04:59:01PM -0500, J. German Rivera wrote:
> > This patch series includes new functionality for the Freescale fsl-mc
> > bus driver.
>
> Why are people working on "new functionality" instead of working on
> getting this out of the staging tree? I really hate adding new functions
> to staging drivers, as this is not the correct place for drivers to be in
> the tree. People should be working to get them out of this location, and
> then you can add new functions to them.
>
> So I really don't want to take this series, sorry, someone better start
> working on getting this out of drivers/staging/ or I'm going to have to
> drop the driver entirely from the tree.
>
> thanks,
>
> greg k-h
On Thu, Jun 18, 2015 at 03:01:22PM +0000, Jose Rivera wrote:
> Greg,
>
> Thanks for your feedback. It is our fault that we did not articulate
> clearly our intent with this patch series. First, for reference, let
> us summarize here the patches in question:
>
> Patch 1: MC bus IRQ support
> Patch 2: add device binding path 'driver_override'
> Patch 3: Propagate driver_override for a child DPRC's children
> Patch 4: Upgraded MC bus driver to match MC fw 7.0.0
> Patch 5: Allow the MC bus driver to run without GIC support
> Patch 6: Add locking to serialize mc_send_command() calls
> Patch 7: Use DPMCP IRQ and completion var to wait for MC
>
> With the exception of patches 2 and 3 (needed for vfio), our intent with
> the rest was to make to changes to work towards completing the "Add at
> least one device driver for a DPAA2 object" on the TODO list.
ah, missed that item, my fault.
> Before sending further patches we will submit an update to the TODO list
> to provide more detail and visibility into our plan to complete the
> "Add at least one device driver..." item. It's too broad as written.
> In particular, we think interrupt support is required and a pre-requisite.
Ok, that sounds good, please do.
thanks,
greg k-h
On Sat, Jun 13, 2015 at 02:16:18PM +0530, Sudip Mukherjee wrote:
>
> can you please have a look (when you are free) at it to see if anything
> else needs to be done.
Remove any unused macros.
Cleanup indenting in the .h file.
drivers/staging/sm7xxfb/sm7xxfb.c:821 smtcfb_pci_probe() warn: 'smtc_regbaseaddress' can't be NULL.
move the BIG_ENDIAN ifdefs to the .h file. I don't understand why only
big endian systems get a fb_read/write? Cleanup casts in fb_read/write.
cleanup comments. make sure they are up to date and make sense.
cleanup function declarations. Make the style consistent.
run checkpatch.pl --strict
Remind me we need the #ifndef MODULE?
regards,
dan carpenter
On Fri, Jun 19, 2015 at 01:29:13PM +0300, Dan Carpenter wrote:
> On Sat, Jun 13, 2015 at 02:16:18PM +0530, Sudip Mukherjee wrote:
> >
> > can you please have a look (when you are free) at it to see if anything
> > else needs to be done.
>
> Remove any unused macros.
I will check.
> Cleanup indenting in the .h file.
done.
> drivers/staging/sm7xxfb/sm7xxfb.c:821 smtcfb_pci_probe() warn: 'smtc_regbaseaddress' can't be NULL.
i dont see this warning. Is it smatch?
> move the BIG_ENDIAN ifdefs to the .h file. I don't understand why only
> big endian systems get a fb_read/write?
Greg asked to remove the BIG_ENDIAN ifdefs. for BIG_ENDIAN some
calculations are involved that is why the functions are defined.
LITTLE_ENDIAN will use the default read/write provided by fb core.
> cleanup comments. make sure they are up to date and make sense.
will do.
> cleanup function declarations. Make the style consistent.
i think its already done, with Joe's help.
> run checkpatch.pl --strict
done.
> Remind me we need the #ifndef MODULE?
This one I introduced with the plan that if it is built-in then it will
use the commandline to get the mode, but if it is a module then it will
use module parameters. But later Greg told that framebuffers should not
use module_param. I dont see any reason why a module can nor get the mode
values from the command line. I will test that during this period of the
merge window and prepare the final patch.
regards
sudip