net/qede/base: serialize access to MFW mbox

Add ecore_mcp_mb_lock() and ecore_mcp_mb_unlock() APIs to ensure
a single thread is accessing MFW mailbox.

Signed-off-by: Harish Patil <harish.patil@qlogic.com>
This commit is contained in:
Harish Patil 2016-10-18 21:11:23 -07:00 committed by Bruce Richardson
parent ffdd059917
commit 1db31dcd6e
2 changed files with 66 additions and 8 deletions

View File

@ -202,6 +202,51 @@ err:
return ECORE_NOMEM;
}
/* Locks the MFW mailbox of a PF to ensure a single access.
* The lock is achieved in most cases by holding a spinlock, causing other
* threads to wait till a previous access is done.
* In some cases (currently when a [UN]LOAD_REQ commands are sent), the single
* access is achieved by setting a blocking flag, which will fail other
* competing contexts to send their mailboxes.
*/
static enum _ecore_status_t ecore_mcp_mb_lock(struct ecore_hwfn *p_hwfn,
u32 cmd)
{
OSAL_SPIN_LOCK(&p_hwfn->mcp_info->lock);
/* The spinlock shouldn't be acquired when the mailbox command is
* [UN]LOAD_REQ, since the engine is locked by the MFW, and a parallel
* pending [UN]LOAD_REQ command of another PF together with a spinlock
* (i.e. interrupts are disabled) - can lead to a deadlock.
* It is assumed that for a single PF, no other mailbox commands can be
* sent from another context while sending LOAD_REQ, and that any
* parallel commands to UNLOAD_REQ can be cancelled.
*/
if (cmd == DRV_MSG_CODE_LOAD_DONE || cmd == DRV_MSG_CODE_UNLOAD_DONE)
p_hwfn->mcp_info->block_mb_sending = false;
if (p_hwfn->mcp_info->block_mb_sending) {
DP_NOTICE(p_hwfn, false,
"Trying to send a MFW mailbox command [0x%x] in parallel to [UN]LOAD_REQ. Aborting.\n",
cmd);
OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
return ECORE_BUSY;
}
if (cmd == DRV_MSG_CODE_LOAD_REQ || cmd == DRV_MSG_CODE_UNLOAD_REQ) {
p_hwfn->mcp_info->block_mb_sending = true;
OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
}
return ECORE_SUCCESS;
}
static void ecore_mcp_mb_unlock(struct ecore_hwfn *p_hwfn, u32 cmd)
{
if (cmd != DRV_MSG_CODE_LOAD_REQ && cmd != DRV_MSG_CODE_UNLOAD_REQ)
OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
}
enum _ecore_status_t ecore_mcp_reset(struct ecore_hwfn *p_hwfn,
struct ecore_ptt *p_ptt)
{
@ -214,8 +259,12 @@ enum _ecore_status_t ecore_mcp_reset(struct ecore_hwfn *p_hwfn,
if (CHIP_REV_IS_EMUL(p_hwfn->p_dev))
delay = EMUL_MCP_RESP_ITER_US;
#endif
OSAL_SPIN_LOCK(&p_hwfn->mcp_info->lock);
/* Ensure that only a single thread is accessing the mailbox at a
* certain time.
*/
rc = ecore_mcp_mb_lock(p_hwfn, DRV_MSG_CODE_MCP_RESET);
if (rc != ECORE_SUCCESS)
return rc;
/* Set drv command along with the updated sequence */
org_mcp_reset_seq = ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0);
@ -238,7 +287,7 @@ enum _ecore_status_t ecore_mcp_reset(struct ecore_hwfn *p_hwfn,
rc = ECORE_AGAIN;
}
OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
ecore_mcp_mb_unlock(p_hwfn, DRV_MSG_CODE_MCP_RESET);
return rc;
}
@ -327,14 +376,16 @@ ecore_mcp_cmd_and_union(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
return ECORE_BUSY;
}
/* Acquiring a spinlock is needed to ensure that only a single thread
* is accessing the mailbox at a certain time.
*/
OSAL_SPIN_LOCK(&p_hwfn->mcp_info->lock);
union_data_addr = p_hwfn->mcp_info->drv_mb_addr +
OFFSETOF(struct public_drv_mb, union_data);
/* Ensure that only a single thread is accessing the mailbox at a
* certain time.
*/
rc = ecore_mcp_mb_lock(p_hwfn, p_mb_params->cmd);
if (rc != ECORE_SUCCESS)
return rc;
if (p_mb_params->p_data_src != OSAL_NULL)
ecore_memcpy_to(p_hwfn, p_ptt, union_data_addr,
p_mb_params->p_data_src,
@ -348,6 +399,9 @@ ecore_mcp_cmd_and_union(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
ecore_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst,
union_data_addr,
sizeof(*p_mb_params->p_data_dst));
ecore_mcp_mb_unlock(p_hwfn, p_mb_params->cmd);
return rc;
}

View File

@ -32,6 +32,10 @@
((_p_hwfn)->p_dev->num_ports_in_engines * 2))
struct ecore_mcp_info {
osal_spinlock_t lock; /* Spinlock used for accessing MCP mailbox */
/* Flag to indicate whether sending a MFW mailbox is forbidden */
bool block_mb_sending;
u32 public_base; /* Address of the MCP public area */
u32 drv_mb_addr; /* Address of the driver mailbox */
u32 mfw_mb_addr; /* Address of the MFW mailbox */