net/sfc/base: import SFN7xxx family support
[dpdk.git] / drivers / net / sfc / base / efx_mcdi.c
index a87a223..338ff49 100644 (file)
 
 
 
+#if EFSYS_OPT_SIENA
+
+static const efx_mcdi_ops_t    __efx_mcdi_siena_ops = {
+       siena_mcdi_init,                /* emco_init */
+       siena_mcdi_send_request,        /* emco_send_request */
+       siena_mcdi_poll_reboot,         /* emco_poll_reboot */
+       siena_mcdi_poll_response,       /* emco_poll_response */
+       siena_mcdi_read_response,       /* emco_read_response */
+       siena_mcdi_fini,                /* emco_fini */
+       siena_mcdi_feature_supported,   /* emco_feature_supported */
+       siena_mcdi_get_timeout,         /* emco_get_timeout */
+};
+
+#endif /* EFSYS_OPT_SIENA */
+
+#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
+
+static const efx_mcdi_ops_t    __efx_mcdi_ef10_ops = {
+       ef10_mcdi_init,                 /* emco_init */
+       ef10_mcdi_send_request,         /* emco_send_request */
+       ef10_mcdi_poll_reboot,          /* emco_poll_reboot */
+       ef10_mcdi_poll_response,        /* emco_poll_response */
+       ef10_mcdi_read_response,        /* emco_read_response */
+       ef10_mcdi_fini,                 /* emco_fini */
+       ef10_mcdi_feature_supported,    /* emco_feature_supported */
+       ef10_mcdi_get_timeout,          /* emco_get_timeout */
+};
+
+#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
+
+
+
        __checkReturn   efx_rc_t
 efx_mcdi_init(
        __in            efx_nic_t *enp,
@@ -66,6 +98,17 @@ efx_mcdi_init(
        EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
 
        switch (enp->en_family) {
+#if EFSYS_OPT_SIENA
+       case EFX_FAMILY_SIENA:
+               emcop = &__efx_mcdi_siena_ops;
+               break;
+#endif /* EFSYS_OPT_SIENA */
+
+#if EFSYS_OPT_HUNTINGTON
+       case EFX_FAMILY_HUNTINGTON:
+               emcop = &__efx_mcdi_ef10_ops;
+               break;
+#endif /* EFSYS_OPT_HUNTINGTON */
 
        default:
                EFSYS_ASSERT(0);
@@ -352,6 +395,21 @@ efx_mcdi_read_response_header(
                emrp->emr_err_code = err_code;
                emrp->emr_err_arg = err_arg;
 
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+               if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
+                   (err_len == sizeof (err))) {
+                       /*
+                        * The MCDI request would normally fail with EPERM, but
+                        * firmware has forwarded it to an authorization agent
+                        * attached to a privileged PF.
+                        *
+                        * Save the authorization request handle. The client
+                        * must wait for a PROXY_RESPONSE event, or timeout.
+                        */
+                       emrp->emr_proxy_handle = err_arg;
+               }
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
+
 #if EFSYS_OPT_MCDI_LOGGING
                if (emtp->emt_logger != NULL) {
                        emtp->emt_logger(emtp->emt_context,
@@ -372,6 +430,9 @@ efx_mcdi_read_response_header(
 
        emrp->emr_rc = 0;
        emrp->emr_out_length_used = data_len;
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+       emrp->emr_proxy_handle = 0;
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
        return;
 
 fail3:
@@ -732,6 +793,62 @@ efx_mcdi_ev_cpl(
        emtp->emt_ev_cpl(emtp->emt_context);
 }
 
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+
+       __checkReturn   efx_rc_t
+efx_mcdi_get_proxy_handle(
+       __in            efx_nic_t *enp,
+       __in            efx_mcdi_req_t *emrp,
+       __out           uint32_t *handlep)
+{
+       efx_rc_t rc;
+
+       /*
+        * Return proxy handle from MCDI request that returned with error
+        * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
+        * PROXY_RESPONSE event.
+        */
+       if ((emrp == NULL) || (handlep == NULL)) {
+               rc = EINVAL;
+               goto fail1;
+       }
+       if ((emrp->emr_rc != 0) &&
+           (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
+               *handlep = emrp->emr_proxy_handle;
+               rc = 0;
+       } else {
+               *handlep = 0;
+               rc = ENOENT;
+       }
+       return (rc);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+       return (rc);
+}
+
+                       void
+efx_mcdi_ev_proxy_response(
+       __in            efx_nic_t *enp,
+       __in            unsigned int handle,
+       __in            unsigned int status)
+{
+       const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
+       efx_rc_t rc;
+
+       /*
+        * Handle results of an authorization request for a privileged MCDI
+        * command. If authorization was granted then we must re-issue the
+        * original MCDI request. If authorization failed or timed out,
+        * then the original MCDI request should be completed with the
+        * result code from this event.
+        */
+       rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
+
+       emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
+}
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
+
                        void
 efx_mcdi_ev_death(
        __in            efx_nic_t *enp,
@@ -1457,6 +1574,107 @@ fail1:
 }
 
 
+#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
+
+/*
+ * This function returns the pf and vf number of a function.  If it is a pf the
+ * vf number is 0xffff.  The vf number is the index of the vf on that
+ * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
+ * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
+ */
+       __checkReturn           efx_rc_t
+efx_mcdi_get_function_info(
+       __in                    efx_nic_t *enp,
+       __out                   uint32_t *pfp,
+       __out_opt               uint32_t *vfp)
+{
+       efx_mcdi_req_t req;
+       uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
+                           MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
+       efx_rc_t rc;
+
+       (void) memset(payload, 0, sizeof (payload));
+       req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
+       req.emr_out_buf = payload;
+       req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
+
+       efx_mcdi_execute(enp, &req);
+
+       if (req.emr_rc != 0) {
+               rc = req.emr_rc;
+               goto fail1;
+       }
+
+       if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
+               rc = EMSGSIZE;
+               goto fail2;
+       }
+
+       *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
+       if (vfp != NULL)
+               *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+       __checkReturn           efx_rc_t
+efx_mcdi_privilege_mask(
+       __in                    efx_nic_t *enp,
+       __in                    uint32_t pf,
+       __in                    uint32_t vf,
+       __out                   uint32_t *maskp)
+{
+       efx_mcdi_req_t req;
+       uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
+                           MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
+       efx_rc_t rc;
+
+       (void) 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;
+
+       MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
+           PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
+           PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
+
+       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;
+       }
+
+       *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
+
        __checkReturn           efx_rc_t
 efx_mcdi_set_workaround(
        __in                    efx_nic_t *enp,