From addbac71a01332436e5becdc9c0111880239b47e Mon Sep 17 00:00:00 2001 From: Gautam Dawar Date: Mon, 10 Jun 2019 08:38:41 +0100 Subject: [PATCH] net/sfc/base: provide proxy APIs to client drivers Implement the APIs for PROXY_CMD, PROXY_COMPLETE and PRIVILEGE_MASK messages to allow client drivers authorize VF operations like set MAC, set MTU etc. with firmware. Signed-off-by: Gautam Dawar Signed-off-by: Andrew Rybchenko --- drivers/net/sfc/base/ef10_impl.h | 19 +++ drivers/net/sfc/base/ef10_proxy.c | 208 ++++++++++++++++++++++++++++++ drivers/net/sfc/base/efx.h | 29 +++++ drivers/net/sfc/base/efx_impl.h | 5 + drivers/net/sfc/base/efx_mcdi.c | 34 ++++- drivers/net/sfc/base/efx_mcdi.h | 2 +- drivers/net/sfc/base/efx_proxy.c | 100 ++++++++++++++ 7 files changed, 394 insertions(+), 3 deletions(-) diff --git a/drivers/net/sfc/base/ef10_impl.h b/drivers/net/sfc/base/ef10_impl.h index 4b719c9e23..e9ce31a283 100644 --- a/drivers/net/sfc/base/ef10_impl.h +++ b/drivers/net/sfc/base/ef10_impl.h @@ -1376,6 +1376,25 @@ ef10_proxy_auth_privilege_modify( __in uint32_t add_privileges_mask, __in uint32_t remove_privileges_mask); + __checkReturn efx_rc_t +ef10_proxy_auth_set_privilege_mask( + __in efx_nic_t *enp, + __in uint32_t vf_index, + __in uint32_t mask, + __in uint32_t value); + + __checkReturn efx_rc_t +ef10_proxy_auth_complete_request( + __in efx_nic_t *enp, + __in uint32_t fn_index, + __in uint32_t proxy_result, + __in uint32_t handle); + + __checkReturn efx_rc_t +ef10_proxy_auth_exec_cmd( + __in efx_nic_t *enp, + __inout efx_proxy_cmd_params_t *paramsp); + #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ #if EFSYS_OPT_RX_PACKED_STREAM diff --git a/drivers/net/sfc/base/ef10_proxy.c b/drivers/net/sfc/base/ef10_proxy.c index 6b1afcc744..a3b73f4050 100644 --- a/drivers/net/sfc/base/ef10_proxy.c +++ b/drivers/net/sfc/base/ef10_proxy.c @@ -252,4 +252,212 @@ ef10_proxy_auth_privilege_modify( return (efx_mcdi_privilege_modify(enp, fn_group, pf_index, vf_index, add_privileges_mask, remove_privileges_mask)); } + +static __checkReturn efx_rc_t +efx_mcdi_privilege_mask_set( + __in efx_nic_t *enp, + __in uint32_t vf_index, + __in uint32_t mask, + __in uint32_t value) +{ + EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN, + MC_CMD_PRIVILEGE_MASK_OUT_LEN); + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_mcdi_req_t req; + efx_rc_t rc; + uint32_t old_mask = 0; + uint32_t new_mask = 0; + + EFSYS_ASSERT((value & ~mask) == 0); + + req.emr_cmd = MC_CMD_PRIVILEGE_MASK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; + + /* Get privilege mask */ + MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, + PRIVILEGE_MASK_IN_FUNCTION_PF, encp->enc_pf, + PRIVILEGE_MASK_IN_FUNCTION_VF, vf_index); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used != MC_CMD_PRIVILEGE_MASK_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + old_mask = *MCDI_OUT2(req, uint32_t, PRIVILEGE_MASK_OUT_OLD_MASK); + new_mask = old_mask & ~mask; + new_mask |= (value & mask); + + if (new_mask == old_mask) + return (0); + + new_mask |= MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE; + memset(payload, 0, sizeof (payload)); + + req.emr_cmd = MC_CMD_PRIVILEGE_MASK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; + + /* Set privilege mask */ + MCDI_IN_SET_DWORD(req, PRIVILEGE_MASK_IN_NEW_MASK, new_mask); + + efx_mcdi_execute(enp, &req); + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail3; + } + + if (req.emr_out_length_used != MC_CMD_PRIVILEGE_MASK_OUT_LEN) { + rc = EMSGSIZE; + goto fail4; + } + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + + __checkReturn efx_rc_t +ef10_proxy_auth_set_privilege_mask( + __in efx_nic_t *enp, + __in uint32_t vf_index, + __in uint32_t mask, + __in uint32_t value) +{ + return (efx_mcdi_privilege_mask_set(enp, vf_index, + mask, value)); +} + +static __checkReturn efx_rc_t +efx_mcdi_proxy_complete( + __in efx_nic_t *enp, + __in uint32_t fn_index, + __in uint32_t proxy_result, + __in uint32_t handle) +{ + EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PROXY_COMPLETE_IN_LEN, + MC_CMD_PROXY_COMPLETE_OUT_LEN); + efx_mcdi_req_t req; + efx_rc_t rc; + + req.emr_cmd = MC_CMD_PROXY_COMPLETE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_PROXY_COMPLETE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_PROXY_COMPLETE_OUT_LEN; + + MCDI_IN_SET_DWORD(req, PROXY_COMPLETE_IN_BLOCK_INDEX, fn_index); + MCDI_IN_SET_DWORD(req, PROXY_COMPLETE_IN_STATUS, proxy_result); + MCDI_IN_SET_DWORD(req, PROXY_COMPLETE_IN_HANDLE, handle); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + + __checkReturn efx_rc_t +ef10_proxy_auth_complete_request( + __in efx_nic_t *enp, + __in uint32_t fn_index, + __in uint32_t proxy_result, + __in uint32_t handle) +{ + return (efx_mcdi_proxy_complete(enp, fn_index, + proxy_result, handle)); +} + +static __checkReturn efx_rc_t +efx_mcdi_proxy_cmd( + __in efx_nic_t *enp, + __in uint32_t pf_index, + __in uint32_t vf_index, + __in_bcount(request_size) uint8_t *request_bufferp, + __in size_t request_size, + __out_bcount(response_size) uint8_t *response_bufferp, + __in size_t response_size, + __out_opt size_t *response_size_actualp) +{ + efx_dword_t *inbufp; + efx_mcdi_req_t req; + efx_rc_t rc; + + if (request_size % sizeof (*inbufp) != 0) { + rc = EINVAL; + goto fail1; + } + + EFSYS_KMEM_ALLOC(enp, (MC_CMD_PROXY_CMD_IN_LEN + request_size), inbufp); + + req.emr_cmd = MC_CMD_PROXY_CMD; + req.emr_in_buf = (uint8_t *) inbufp; + req.emr_in_length = MC_CMD_PROXY_CMD_IN_LEN + request_size; + req.emr_out_buf = response_bufferp; + req.emr_out_length = response_size; + + MCDI_IN_POPULATE_DWORD_2(req, PROXY_CMD_IN_TARGET, + PROXY_CMD_IN_TARGET_PF, pf_index, + PROXY_CMD_IN_TARGET_VF, vf_index); + + /* Proxied command should be located just after PROXY_CMD */ + memcpy(&inbufp[MC_CMD_PROXY_CMD_IN_LEN / sizeof (*inbufp)], + request_bufferp, request_size); + + efx_mcdi_execute(enp, &req); + + EFSYS_KMEM_FREE(enp, (MC_CMD_PROXY_CMD_IN_LEN + request_size), inbufp); + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (response_size_actualp != NULL) + *response_size_actualp = req.emr_out_length_used; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + + __checkReturn efx_rc_t +ef10_proxy_auth_exec_cmd( + __in efx_nic_t *enp, + __inout efx_proxy_cmd_params_t *paramsp) +{ + return (efx_mcdi_proxy_cmd(enp, paramsp->pf_index, paramsp->vf_index, + paramsp->request_bufferp, paramsp->request_size, + paramsp->response_bufferp, paramsp->response_size, + paramsp->response_size_actualp)); +} #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h index 97c4e62340..e43302a01e 100644 --- a/drivers/net/sfc/base/efx.h +++ b/drivers/net/sfc/base/efx.h @@ -3434,6 +3434,16 @@ typedef struct efx_proxy_auth_config_s { uint32_t handled_privileges; } efx_proxy_auth_config_t; +typedef struct efx_proxy_cmd_params_s { + uint32_t pf_index; + uint32_t vf_index; + uint8_t *request_bufferp; + size_t request_size; + uint8_t *response_bufferp; + size_t response_size; + size_t *response_size_actualp; +} efx_proxy_cmd_params_t; + extern __checkReturn efx_rc_t efx_proxy_auth_init( __in efx_nic_t *enp); @@ -3452,6 +3462,25 @@ efx_proxy_auth_destroy( __in efx_nic_t *enp, __in uint32_t handled_privileges); + __checkReturn efx_rc_t +efx_proxy_auth_complete_request( + __in efx_nic_t *enp, + __in uint32_t fn_index, + __in uint32_t proxy_result, + __in uint32_t handle); + + __checkReturn efx_rc_t +efx_proxy_auth_exec_cmd( + __in efx_nic_t *enp, + __inout efx_proxy_cmd_params_t *paramsp); + + __checkReturn efx_rc_t +efx_proxy_auth_set_privilege_mask( + __in efx_nic_t *enp, + __in uint32_t vf_index, + __in uint32_t mask, + __in uint32_t value); + #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ #ifdef __cplusplus diff --git a/drivers/net/sfc/base/efx_impl.h b/drivers/net/sfc/base/efx_impl.h index 6a8fee80b6..6c72166eb7 100644 --- a/drivers/net/sfc/base/efx_impl.h +++ b/drivers/net/sfc/base/efx_impl.h @@ -706,6 +706,11 @@ typedef struct efx_proxy_ops_s { efx_rc_t (*epo_disable)(efx_nic_t *); efx_rc_t (*epo_privilege_modify)(efx_nic_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + efx_rc_t (*epo_set_privilege_mask)(efx_nic_t *, uint32_t, + uint32_t, uint32_t); + efx_rc_t (*epo_complete_request)(efx_nic_t *, uint32_t, + uint32_t, uint32_t); + efx_rc_t (*epo_exec_cmd)(efx_nic_t *, efx_proxy_cmd_params_t *); } efx_proxy_ops_t; #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ diff --git a/drivers/net/sfc/base/efx_mcdi.c b/drivers/net/sfc/base/efx_mcdi.c index 325c2e44dd..e840401be8 100644 --- a/drivers/net/sfc/base/efx_mcdi.c +++ b/drivers/net/sfc/base/efx_mcdi.c @@ -360,7 +360,11 @@ efx_mcdi_read_response_header( rc = EIO; goto fail1; } +#if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER + if (((cmd != emrp->emr_cmd) && (emrp->emr_cmd != MC_CMD_PROXY_CMD)) || +#else if ((cmd != emrp->emr_cmd) || +#endif (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { /* Response is for a different request */ rc = EIO; @@ -442,6 +446,11 @@ efx_mcdi_finish_response( efx_dword_t hdr[2]; unsigned int hdr_len; size_t bytes; + unsigned int resp_off; +#if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER + unsigned int resp_cmd; + boolean_t proxied_cmd_resp = B_FALSE; +#endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ if (emrp->emr_out_buf == NULL) return; @@ -456,14 +465,35 @@ efx_mcdi_finish_response( */ efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); hdr_len += sizeof (hdr[1]); + resp_off = hdr_len; emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1], - MC_CMD_V2_EXTN_IN_ACTUAL_LEN); + MC_CMD_V2_EXTN_IN_ACTUAL_LEN); +#if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER + /* + * A proxy MCDI command is executed by PF on behalf of + * one of its VFs. The command to be proxied follows + * immediately afterward in the host buffer. + * PROXY_CMD inner call complete response should be copied to + * output buffer so that it can be returned to the requesting + * function in MC_CMD_PROXY_COMPLETE payload. + */ + resp_cmd = + EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); + proxied_cmd_resp = ((emrp->emr_cmd == MC_CMD_PROXY_CMD) && + (resp_cmd != MC_CMD_PROXY_CMD)); + if (proxied_cmd_resp) { + resp_off = 0; + emrp->emr_out_length_used += hdr_len; + } +#endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ + } else { + resp_off = hdr_len; } /* Copy payload out into caller supplied buffer */ bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); - efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes); + efx_mcdi_read_response(enp, emrp->emr_out_buf, resp_off, bytes); #if EFSYS_OPT_MCDI_LOGGING if (emtp->emt_logger != NULL) { diff --git a/drivers/net/sfc/base/efx_mcdi.h b/drivers/net/sfc/base/efx_mcdi.h index 56c0ab1050..74cde50759 100644 --- a/drivers/net/sfc/base/efx_mcdi.h +++ b/drivers/net/sfc/base/efx_mcdi.h @@ -31,7 +31,7 @@ struct efx_mcdi_req_s { unsigned int emr_cmd; uint8_t *emr_in_buf; size_t emr_in_length; - /* Outputs: retcode, buffer, length, and length used */ + /* Outputs: retcode, buffer, length and length used */ efx_rc_t emr_rc; uint8_t *emr_out_buf; size_t emr_out_length; diff --git a/drivers/net/sfc/base/efx_proxy.c b/drivers/net/sfc/base/efx_proxy.c index 6aadf076eb..b04e7ddaa8 100644 --- a/drivers/net/sfc/base/efx_proxy.c +++ b/drivers/net/sfc/base/efx_proxy.c @@ -16,6 +16,9 @@ static const efx_proxy_ops_t __efx_proxy_dummy_ops = { NULL, /* epo_mc_config */ NULL, /* epo_disable */ NULL, /* epo_privilege_modify */ + NULL, /* epo_set_privilege_mask */ + NULL, /* epo_complete_request */ + NULL, /* epo_exec_cmd */ }; #endif /* EFSYS_OPT_SIENA */ @@ -26,6 +29,9 @@ static const efx_proxy_ops_t __efx_proxy_ef10_ops = { ef10_proxy_auth_mc_config, /* epo_mc_config */ ef10_proxy_auth_disable, /* epo_disable */ ef10_proxy_auth_privilege_modify, /* epo_privilege_modify */ + ef10_proxy_auth_set_privilege_mask, /* epo_set_privilege_mask */ + ef10_proxy_auth_complete_request, /* epo_complete_request */ + ef10_proxy_auth_exec_cmd, /* epo_exec_cmd */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ @@ -197,4 +203,98 @@ fail1: return (rc); } + __checkReturn efx_rc_t +efx_proxy_auth_complete_request( + __in efx_nic_t *enp, + __in uint32_t fn_index, + __in uint32_t proxy_result, + __in uint32_t handle) +{ + const efx_proxy_ops_t *epop = enp->en_epop; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROXY); + + if (epop->epo_complete_request == NULL) { + rc = ENOTSUP; + goto fail1; + } + + rc = epop->epo_complete_request(enp, fn_index, proxy_result, handle); + if (rc != 0) + goto fail2; + + return (0); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + + __checkReturn efx_rc_t +efx_proxy_auth_exec_cmd( + __in efx_nic_t *enp, + __inout efx_proxy_cmd_params_t *paramsp) +{ + const efx_proxy_ops_t *epop = enp->en_epop; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROXY); + + if (paramsp == NULL) { + rc = EINVAL; + goto fail1; + } + + if (epop->epo_exec_cmd == NULL) { + rc = ENOTSUP; + goto fail2; + } + + rc = epop->epo_exec_cmd(enp, paramsp); + if (rc != 0) + goto fail3; + + return (0); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + + __checkReturn efx_rc_t +efx_proxy_auth_set_privilege_mask( + __in efx_nic_t *enp, + __in uint32_t vf_index, + __in uint32_t mask, + __in uint32_t value) +{ + const efx_proxy_ops_t *epop = enp->en_epop; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROXY); + + if (epop->epo_set_privilege_mask == NULL) { + rc = ENOTSUP; + goto fail1; + } + + rc = epop->epo_set_privilege_mask(enp, vf_index, mask, value); + if (rc != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + + #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ -- 2.20.1