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 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel