[PATCH v2 6/7] staging: fsl-mc: Add locking to serialize mc_send_command() calls

From: J. German Rivera
Date: Wed May 06 2015 - 17:36:55 EST


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 <German.Rivera@xxxxxxxxxxxxx>
Reviewed-by: Stuart Yoder <stuart.yoder@xxxxxxxxxxxxx>
---
Changes in v2:
- Relaxed rules for FSL_MC_IO_ATOMIC_CONTEXT_PORTAL.
Some drivers (e.g., DPNI) need to send MC commands with the same
mc_io object, from both atomic and non-atomic context. So, we
need to relax the rules to use mc_io objects created with the
FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag on, to allow this.
- Use msecs_to_jiffies() instead of HZ in timeout-related expression

drivers/staging/fsl-mc/bus/dprc-driver.c | 6 ++---
drivers/staging/fsl-mc/bus/mc-sys.c | 40 +++++++++++++++++++++++++-------
drivers/staging/fsl-mc/include/mc-sys.h | 23 ++++++++++++++++--
3 files changed, 55 insertions(+), 14 deletions(-)

diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c
index 72eacee..5e24f46 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/staging/fsl-mc/bus/dprc-driver.c
@@ -502,10 +502,8 @@ 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)) {
- error = -EINVAL;
- goto error_unregister_irq_handlers;
- }
+ if (WARN_ON(irq->dev_irq_index != i))
+ return -EINVAL;

/*
* NOTE: Normally, devm_request_threaded_irq() programs the MSI
diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c
index 9ae000c..2b3d18c 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..7ea12a6 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;
+ uint16_t flags;
+ uint16_t 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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/