mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-06 16:49:22 +00:00
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: J. German Rivera <German.Rivera@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
3f95ad2185
commit
63f2be5c3b
2 changed files with 51 additions and 3 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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 @@
|
||||||
#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;
|
||||||
* @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 {
|
||||||
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,
|
||||||
|
|
Loading…
Reference in a new issue