Commit 63f2be5c authored by J. German Rivera's avatar J. German Rivera Committed by Greg Kroah-Hartman

staging: fsl-mc: Added serialization to mc_send_command()

When the same portal is used to call mc_send_command() from two
different threads or a thread and an interrupt handler, serialization
is required, as the MC only supports one outstanding command per MC
portal. Thus, a new command should not be sent to the MC until the
last command sent has been responded by the MC.
Signed-off-by: default avatarJ. German Rivera <German.Rivera@freescale.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3f95ad21
...@@ -88,6 +88,11 @@ int __must_check fsl_create_mc_io(struct device *dev, ...@@ -88,6 +88,11 @@ int __must_check fsl_create_mc_io(struct device *dev,
mc_io->flags = flags; mc_io->flags = flags;
mc_io->portal_phys_addr = mc_portal_phys_addr; mc_io->portal_phys_addr = mc_portal_phys_addr;
mc_io->portal_size = mc_portal_size; mc_io->portal_size = mc_portal_size;
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, res = devm_request_mem_region(dev,
mc_portal_phys_addr, mc_portal_phys_addr,
mc_portal_size, mc_portal_size,
...@@ -391,11 +396,17 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) ...@@ -391,11 +396,17 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
{ {
int error; int error;
enum mc_cmd_status status; enum mc_cmd_status status;
unsigned long irq_flags = 0;
if (WARN_ON(in_irq() && if (WARN_ON(in_irq() &&
!(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL))) !(mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)))
return -EINVAL; return -EINVAL;
if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
spin_lock_irqsave(&mc_io->spinlock, irq_flags);
else
mutex_lock(&mc_io->mutex);
/* /*
* Send command to the MC hardware: * Send command to the MC hardware:
*/ */
...@@ -410,7 +421,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) ...@@ -410,7 +421,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
error = mc_polling_wait_atomic(mc_io, cmd, &status); error = mc_polling_wait_atomic(mc_io, cmd, &status);
if (error < 0) if (error < 0)
return error; goto common_exit;
if (status != MC_CMD_STATUS_OK) { 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 command failed: portal: %#llx, obj handle: %#x, command: %#x, status: %s (%#x)\n",
...@@ -420,9 +431,17 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) ...@@ -420,9 +431,17 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
mc_status_to_string(status), mc_status_to_string(status),
(unsigned int)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_irqrestore(&mc_io->spinlock, irq_flags);
else
mutex_unlock(&mc_io->mutex);
return error;
} }
EXPORT_SYMBOL(mc_send_command); EXPORT_SYMBOL(mc_send_command);
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/dma-mapping.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 * Bit masks for a MC I/O object (struct fsl_mc_io) flags
...@@ -56,6 +58,20 @@ struct mc_command; ...@@ -56,6 +58,20 @@ struct mc_command;
* @portal_phys_addr: MC command portal physical address * @portal_phys_addr: MC command portal physical address
* @portal_virt_addr: MC command portal virtual address * @portal_virt_addr: MC command portal virtual address
* @dpmcp_dev: pointer to the DPMCP device associated with the MC portal. * @dpmcp_dev: pointer to the DPMCP device associated with the MC portal.
*
* Fields are only meaningful if the FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not
* set:
* @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.
*
* Fields are only meaningful if the FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is
* set:
* @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 fsl_mc_io {
struct device *dev; struct device *dev;
...@@ -64,6 +80,19 @@ struct fsl_mc_io { ...@@ -64,6 +80,19 @@ struct fsl_mc_io {
phys_addr_t portal_phys_addr; phys_addr_t portal_phys_addr;
void __iomem *portal_virt_addr; void __iomem *portal_virt_addr;
struct fsl_mc_device *dpmcp_dev; struct fsl_mc_device *dpmcp_dev;
union {
/*
* This field is only meaningful if the
* FSL_MC_IO_ATOMIC_CONTEXT_PORTAL flag is not set
*/
struct mutex mutex; /* serializes mc_send_command() */
/*
* 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, int __must_check fsl_create_mc_io(struct device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment