Commit 95691c9c authored by Tomer Tayar's avatar Tomer Tayar Committed by David S. Miller

qed: Support management-based resource locking

Global locking can't properly be used to synchronize between different
PFs in all scenarios, as those instances might reside in different
logical partitions [e.g., when a PF is assigned via PDA to some VM].

The management firmware provides a generic infrastructure for
device locks. For each 'resource', it's guaranteed it could be acquired
by at most a single PF at any given time [or by management firmware].

This patch adds the necessary logic in qed for utilizing said
infrastructure, implementing lock/unlock internal APIs.
Signed-off-by: default avatarTomer Tayar <Tomer.Tayar@cavium.com>
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 18a69e36
...@@ -10119,6 +10119,33 @@ struct public_drv_mb { ...@@ -10119,6 +10119,33 @@ struct public_drv_mb {
#define DRV_MSG_CODE_BIST_TEST 0x001e0000 #define DRV_MSG_CODE_BIST_TEST 0x001e0000
#define DRV_MSG_CODE_SET_LED_MODE 0x00200000 #define DRV_MSG_CODE_SET_LED_MODE 0x00200000
#define DRV_MSG_CODE_RESOURCE_CMD 0x00230000
#define RESOURCE_CMD_REQ_RESC_MASK 0x0000001F
#define RESOURCE_CMD_REQ_RESC_SHIFT 0
#define RESOURCE_CMD_REQ_OPCODE_MASK 0x000000E0
#define RESOURCE_CMD_REQ_OPCODE_SHIFT 5
#define RESOURCE_OPCODE_REQ 1
#define RESOURCE_OPCODE_REQ_WO_AGING 2
#define RESOURCE_OPCODE_REQ_W_AGING 3
#define RESOURCE_OPCODE_RELEASE 4
#define RESOURCE_OPCODE_FORCE_RELEASE 5
#define RESOURCE_CMD_REQ_AGE_MASK 0x0000FF00
#define RESOURCE_CMD_REQ_AGE_SHIFT 8
#define RESOURCE_CMD_RSP_OWNER_MASK 0x000000FF
#define RESOURCE_CMD_RSP_OWNER_SHIFT 0
#define RESOURCE_CMD_RSP_OPCODE_MASK 0x00000700
#define RESOURCE_CMD_RSP_OPCODE_SHIFT 8
#define RESOURCE_OPCODE_GNT 1
#define RESOURCE_OPCODE_BUSY 2
#define RESOURCE_OPCODE_RELEASED 3
#define RESOURCE_OPCODE_RELEASED_PREVIOUS 4
#define RESOURCE_OPCODE_WRONG_OWNER 5
#define RESOURCE_OPCODE_UNKNOWN_CMD 255
#define RESOURCE_DUMP 0
#define DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL 0x002b0000 #define DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL 0x002b0000
#define DRV_MSG_CODE_OS_WOL 0x002e0000 #define DRV_MSG_CODE_OS_WOL 0x002e0000
...@@ -10207,6 +10234,7 @@ struct public_drv_mb { ...@@ -10207,6 +10234,7 @@ struct public_drv_mb {
u32 fw_mb_header; u32 fw_mb_header;
#define FW_MSG_CODE_MASK 0xffff0000 #define FW_MSG_CODE_MASK 0xffff0000
#define FW_MSG_CODE_UNSUPPORTED 0x00000000
#define FW_MSG_CODE_DRV_LOAD_ENGINE 0x10100000 #define FW_MSG_CODE_DRV_LOAD_ENGINE 0x10100000
#define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000 #define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000
#define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000 #define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000
......
...@@ -2271,3 +2271,179 @@ int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) ...@@ -2271,3 +2271,179 @@ int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0,
&mcp_resp, &mcp_param); &mcp_resp, &mcp_param);
} }
static int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 param, u32 *p_mcp_resp, u32 *p_mcp_param)
{
int rc;
rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param,
p_mcp_resp, p_mcp_param);
if (rc)
return rc;
if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
DP_INFO(p_hwfn,
"The resource command is unsupported by the MFW\n");
return -EINVAL;
}
if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) {
u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE);
DP_NOTICE(p_hwfn,
"The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n",
param, opcode);
return -EINVAL;
}
return rc;
}
int
__qed_mcp_resc_lock(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_resc_lock_params *p_params)
{
u32 param = 0, mcp_resp, mcp_param;
u8 opcode;
int rc;
switch (p_params->timeout) {
case QED_MCP_RESC_LOCK_TO_DEFAULT:
opcode = RESOURCE_OPCODE_REQ;
p_params->timeout = 0;
break;
case QED_MCP_RESC_LOCK_TO_NONE:
opcode = RESOURCE_OPCODE_REQ_WO_AGING;
p_params->timeout = 0;
break;
default:
opcode = RESOURCE_OPCODE_REQ_W_AGING;
break;
}
QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource);
QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode);
QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout);
DP_VERBOSE(p_hwfn,
QED_MSG_SP,
"Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n",
param, p_params->timeout, opcode, p_params->resource);
/* Attempt to acquire the resource */
rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param);
if (rc)
return rc;
/* Analyze the response */
p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER);
opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE);
DP_VERBOSE(p_hwfn,
QED_MSG_SP,
"Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n",
mcp_param, opcode, p_params->owner);
switch (opcode) {
case RESOURCE_OPCODE_GNT:
p_params->b_granted = true;
break;
case RESOURCE_OPCODE_BUSY:
p_params->b_granted = false;
break;
default:
DP_NOTICE(p_hwfn,
"Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n",
mcp_param, opcode);
return -EINVAL;
}
return 0;
}
int
qed_mcp_resc_lock(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params)
{
u32 retry_cnt = 0;
int rc;
do {
/* No need for an interval before the first iteration */
if (retry_cnt) {
if (p_params->sleep_b4_retry) {
u16 retry_interval_in_ms =
DIV_ROUND_UP(p_params->retry_interval,
1000);
msleep(retry_interval_in_ms);
} else {
udelay(p_params->retry_interval);
}
}
rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params);
if (rc)
return rc;
if (p_params->b_granted)
break;
} while (retry_cnt++ < p_params->retry_num);
return 0;
}
int
qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_resc_unlock_params *p_params)
{
u32 param = 0, mcp_resp, mcp_param;
u8 opcode;
int rc;
opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE
: RESOURCE_OPCODE_RELEASE;
QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource);
QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode);
DP_VERBOSE(p_hwfn, QED_MSG_SP,
"Resource unlock request: param 0x%08x [opcode %d, resource %d]\n",
param, opcode, p_params->resource);
/* Attempt to release the resource */
rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param);
if (rc)
return rc;
/* Analyze the response */
opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE);
DP_VERBOSE(p_hwfn, QED_MSG_SP,
"Resource unlock response: mcp_param 0x%08x [opcode %d]\n",
mcp_param, opcode);
switch (opcode) {
case RESOURCE_OPCODE_RELEASED_PREVIOUS:
DP_INFO(p_hwfn,
"Resource unlock request for an already released resource [%d]\n",
p_params->resource);
/* Fallthrough */
case RESOURCE_OPCODE_RELEASED:
p_params->b_released = true;
break;
case RESOURCE_OPCODE_WRONG_OWNER:
p_params->b_released = false;
break;
default:
DP_NOTICE(p_hwfn,
"Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n",
mcp_param, opcode);
return -EINVAL;
}
return 0;
}
...@@ -780,4 +780,69 @@ int qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, ...@@ -780,4 +780,69 @@ int qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn,
* @return int - 0 - operation was successful. * @return int - 0 - operation was successful.
*/ */
int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
struct qed_resc_lock_params {
/* Resource number [valid values are 0..31] */
u8 resource;
/* Lock timeout value in seconds [default, none or 1..254] */
u8 timeout;
#define QED_MCP_RESC_LOCK_TO_DEFAULT 0
#define QED_MCP_RESC_LOCK_TO_NONE 255
/* Number of times to retry locking */
u8 retry_num;
/* The interval in usec between retries */
u16 retry_interval;
/* Use sleep or delay between retries */
bool sleep_b4_retry;
/* Will be set as true if the resource is free and granted */
bool b_granted;
/* Will be filled with the resource owner.
* [0..15 = PF0-15, 16 = MFW]
*/
u8 owner;
};
/**
* @brief Acquires MFW generic resource lock
*
* @param p_hwfn
* @param p_ptt
* @param p_params
*
* @return int - 0 - operation was successful.
*/
int
qed_mcp_resc_lock(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params);
struct qed_resc_unlock_params {
/* Resource number [valid values are 0..31] */
u8 resource;
/* Allow to release a resource even if belongs to another PF */
bool b_force;
/* Will be set as true if the resource is released */
bool b_released;
};
/**
* @brief Releases MFW generic resource lock
*
* @param p_hwfn
* @param p_ptt
* @param p_params
*
* @return int - 0 - operation was successful.
*/
int
qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_resc_unlock_params *p_params);
#endif #endif
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