dpdk/drivers/common/sfc_efx/base/siena_mcdi.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 *
   3 * Copyright(c) 2019-2020 Xilinx, Inc.
   4 * Copyright(c) 2012-2019 Solarflare Communications Inc.
   5 */
   6
   7#include "efx.h"
   8#include "efx_impl.h"
   9
  10#if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
  11
  12#define SIENA_MCDI_PDU(_emip)                   \
  13        (((emip)->emi_port == 1)                \
  14        ? MC_SMEM_P0_PDU_OFST >> 2              \
  15        : MC_SMEM_P1_PDU_OFST >> 2)
  16
  17#define SIENA_MCDI_DOORBELL(_emip)              \
  18        (((emip)->emi_port == 1)                \
  19        ? MC_SMEM_P0_DOORBELL_OFST >> 2         \
  20        : MC_SMEM_P1_DOORBELL_OFST >> 2)
  21
  22#define SIENA_MCDI_STATUS(_emip)                \
  23        (((emip)->emi_port == 1)                \
  24        ? MC_SMEM_P0_STATUS_OFST >> 2           \
  25        : MC_SMEM_P1_STATUS_OFST >> 2)
  26
  27
  28                        void
  29siena_mcdi_send_request(
  30        __in                    efx_nic_t *enp,
  31        __in_bcount(hdr_len)    void *hdrp,
  32        __in                    size_t hdr_len,
  33        __in_bcount(sdu_len)    void *sdup,
  34        __in                    size_t sdu_len)
  35{
  36        efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  37        efx_dword_t dword;
  38        unsigned int pdur;
  39        unsigned int dbr;
  40        unsigned int pos;
  41
  42        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
  43
  44        EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
  45        pdur = SIENA_MCDI_PDU(emip);
  46        dbr = SIENA_MCDI_DOORBELL(emip);
  47
  48        /* Write the header */
  49        EFSYS_ASSERT3U(hdr_len, ==, sizeof (efx_dword_t));
  50        dword = *(efx_dword_t *)hdrp;
  51        EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);
  52
  53        /* Write the payload */
  54        for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
  55                dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
  56                EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
  57                    pdur + 1 + (pos >> 2), &dword, B_FALSE);
  58        }
  59
  60        /* Ring the doorbell */
  61        EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
  62        EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
  63}
  64
  65                        efx_rc_t
  66siena_mcdi_poll_reboot(
  67        __in            efx_nic_t *enp)
  68{
  69#if 1
  70        /*
  71         * XXX Bug 25922, bug 26099: This function is not being used
  72         * properly.  Until its callers are fixed, it should always
  73         * return 0.
  74         */
  75        _NOTE(ARGUNUSED(enp))
  76        return (0);
  77#else
  78        efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  79        unsigned int rebootr;
  80        efx_dword_t dword;
  81        uint32_t value;
  82
  83        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
  84        EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
  85        rebootr = SIENA_MCDI_STATUS(emip);
  86
  87        EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
  88        value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
  89
  90        if (value == 0)
  91                return (0);
  92
  93        EFX_ZERO_DWORD(dword);
  94        EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
  95
  96        if (value == MC_STATUS_DWORD_ASSERT)
  97                return (EINTR);
  98        else
  99                return (EIO);
 100#endif
 101}
 102
 103extern  __checkReturn   boolean_t
 104siena_mcdi_poll_response(
 105        __in            efx_nic_t *enp)
 106{
 107        efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
 108        efx_dword_t hdr;
 109        unsigned int pdur;
 110
 111        EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
 112        pdur = SIENA_MCDI_PDU(emip);
 113
 114        EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE);
 115        return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
 116}
 117
 118                        void
 119siena_mcdi_read_response(
 120        __in                    efx_nic_t *enp,
 121        __out_bcount(length)    void *bufferp,
 122        __in                    size_t offset,
 123        __in                    size_t length)
 124{
 125        efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
 126        unsigned int pdur;
 127        unsigned int pos = 0;
 128        efx_dword_t data;
 129        size_t remaining = length;
 130
 131        EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
 132        pdur = SIENA_MCDI_PDU(emip);
 133
 134        while (remaining > 0) {
 135                size_t chunk = MIN(remaining, sizeof (data));
 136
 137                EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
 138                    pdur + ((offset + pos) >> 2), &data, B_FALSE);
 139                memcpy((uint8_t *)bufferp + pos, &data, chunk);
 140                pos += chunk;
 141                remaining -= chunk;
 142        }
 143}
 144
 145        __checkReturn   efx_rc_t
 146siena_mcdi_init(
 147        __in            efx_nic_t *enp,
 148        __in            const efx_mcdi_transport_t *mtp)
 149{
 150        efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
 151        efx_oword_t oword;
 152        unsigned int portnum;
 153        efx_rc_t rc;
 154
 155        _NOTE(ARGUNUSED(mtp))
 156
 157        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 158
 159        /* Determine the port number to use for MCDI */
 160        EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
 161        portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
 162
 163        if (portnum == 0) {
 164                /* Presumably booted from ROM; only MCDI port 1 will work */
 165                emip->emi_port = 1;
 166        } else if (portnum <= 2) {
 167                emip->emi_port = portnum;
 168        } else {
 169                rc = EINVAL;
 170                goto fail1;
 171        }
 172
 173        /* Siena BootROM and firmware only support MCDIv1 */
 174        emip->emi_max_version = 1;
 175
 176        /*
 177         * Wipe the atomic reboot status so subsequent MCDI requests succeed.
 178         * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
 179         * assertion handler.
 180         */
 181        (void) siena_mcdi_poll_reboot(enp);
 182
 183        return (0);
 184
 185fail1:
 186        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 187
 188        return (rc);
 189}
 190
 191                        void
 192siena_mcdi_fini(
 193        __in            efx_nic_t *enp)
 194{
 195        _NOTE(ARGUNUSED(enp))
 196}
 197
 198        __checkReturn   efx_rc_t
 199siena_mcdi_feature_supported(
 200        __in            efx_nic_t *enp,
 201        __in            efx_mcdi_feature_id_t id,
 202        __out           boolean_t *supportedp)
 203{
 204        efx_rc_t rc;
 205
 206        EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
 207
 208        switch (id) {
 209        case EFX_MCDI_FEATURE_FW_UPDATE:
 210        case EFX_MCDI_FEATURE_LINK_CONTROL:
 211        case EFX_MCDI_FEATURE_MACADDR_CHANGE:
 212        case EFX_MCDI_FEATURE_MAC_SPOOFING:
 213                *supportedp = B_TRUE;
 214                break;
 215        default:
 216                rc = ENOTSUP;
 217                goto fail1;
 218        }
 219
 220        return (0);
 221
 222fail1:
 223        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 224
 225        return (rc);
 226}
 227
 228/* Default timeout for MCDI command processing. */
 229#define SIENA_MCDI_CMD_TIMEOUT_US       (10 * 1000 * 1000)
 230
 231                        void
 232siena_mcdi_get_timeout(
 233        __in            efx_nic_t *enp,
 234        __in            efx_mcdi_req_t *emrp,
 235        __out           uint32_t *timeoutp)
 236{
 237        _NOTE(ARGUNUSED(enp, emrp))
 238
 239        *timeoutp = SIENA_MCDI_CMD_TIMEOUT_US;
 240}
 241
 242
 243#endif  /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */
 244