net/sfc/base: provide proxy APIs to client drivers
authorGautam Dawar <gdawar@solarflare.com>
Mon, 10 Jun 2019 07:38:41 +0000 (08:38 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 20 Jun 2019 21:42:04 +0000 (23:42 +0200)
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 <gdawar@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
drivers/net/sfc/base/ef10_impl.h
drivers/net/sfc/base/ef10_proxy.c
drivers/net/sfc/base/efx.h
drivers/net/sfc/base/efx_impl.h
drivers/net/sfc/base/efx_mcdi.c
drivers/net/sfc/base/efx_mcdi.h
drivers/net/sfc/base/efx_proxy.c

index 4b719c9..e9ce31a 100644 (file)
@@ -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
index 6b1afcc..a3b73f4 100644 (file)
@@ -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 */
index 97c4e62..e43302a 100644 (file)
@@ -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
index 6a8fee8..6c72166 100644 (file)
@@ -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 */
index 325c2e4..e840401 100644 (file)
@@ -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) {
index 56c0ab1..74cde50 100644 (file)
@@ -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;
index 6aadf07..b04e7dd 100644 (file)
@@ -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 */