1283514Sarybchik/*- 2300607Sarybchik * Copyright (c) 2012-2016 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4283514Sarybchik * 5283514Sarybchik * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7283514Sarybchik * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29283514Sarybchik */ 30283514Sarybchik 31283514Sarybchik#include <sys/cdefs.h> 32283514Sarybchik__FBSDID("$FreeBSD: releng/11.0/sys/dev/sfxge/common/ef10_mcdi.c 300842 2016-05-27 11:46:35Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efx.h" 35283514Sarybchik#include "efx_impl.h" 36283514Sarybchik 37283514Sarybchik 38293757Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 39283514Sarybchik 40283514Sarybchik#if EFSYS_OPT_MCDI 41283514Sarybchik 42283514Sarybchik#ifndef WITH_MCDI_V2 43293757Sarybchik#error "WITH_MCDI_V2 required for EF10 MCDIv2 commands." 44283514Sarybchik#endif 45283514Sarybchik 46283514Sarybchik 47291436Sarybchik __checkReturn efx_rc_t 48293757Sarybchikef10_mcdi_init( 49283514Sarybchik __in efx_nic_t *enp, 50283514Sarybchik __in const efx_mcdi_transport_t *emtp) 51283514Sarybchik{ 52293765Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 53283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 54283514Sarybchik efx_dword_t dword; 55291436Sarybchik efx_rc_t rc; 56283514Sarybchik 57293757Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 58293757Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 59283514Sarybchik EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA); 60283514Sarybchik 61293765Sarybchik /* 62293765Sarybchik * All EF10 firmware supports MCDIv2 and MCDIv1. 63293765Sarybchik * Medford BootROM supports MCDIv2 and MCDIv1. 64293765Sarybchik * Huntington BootROM supports MCDIv1 only. 65293765Sarybchik */ 66293765Sarybchik emip->emi_max_version = 2; 67293765Sarybchik 68293757Sarybchik /* A host DMA buffer is required for EF10 MCDI */ 69283514Sarybchik if (esmp == NULL) { 70283514Sarybchik rc = EINVAL; 71283514Sarybchik goto fail1; 72283514Sarybchik } 73283514Sarybchik 74283514Sarybchik /* 75283514Sarybchik * Ensure that the MC doorbell is in a known state before issuing MCDI 76283514Sarybchik * commands. The recovery algorithm requires that the MC command buffer 77283514Sarybchik * must be 256 byte aligned. See bug24769. 78283514Sarybchik */ 79283514Sarybchik if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) { 80283514Sarybchik rc = EINVAL; 81283514Sarybchik goto fail2; 82283514Sarybchik } 83283514Sarybchik EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1); 84283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 85283514Sarybchik 86283514Sarybchik /* Save initial MC reboot status */ 87293757Sarybchik (void) ef10_mcdi_poll_reboot(enp); 88283514Sarybchik 89283514Sarybchik /* Start a new epoch (allow fresh MCDI requests to succeed) */ 90283514Sarybchik efx_mcdi_new_epoch(enp); 91283514Sarybchik 92283514Sarybchik return (0); 93283514Sarybchik 94283514Sarybchikfail2: 95283514Sarybchik EFSYS_PROBE(fail2); 96283514Sarybchikfail1: 97291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 98283514Sarybchik 99283514Sarybchik return (rc); 100283514Sarybchik} 101283514Sarybchik 102283514Sarybchik void 103293757Sarybchikef10_mcdi_fini( 104283514Sarybchik __in efx_nic_t *enp) 105283514Sarybchik{ 106283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 107283514Sarybchik 108283514Sarybchik emip->emi_new_epoch = B_FALSE; 109283514Sarybchik} 110283514Sarybchik 111293888Sarybchik void 112293809Sarybchikef10_mcdi_send_request( 113293809Sarybchik __in efx_nic_t *enp, 114293809Sarybchik __in void *hdrp, 115293809Sarybchik __in size_t hdr_len, 116293809Sarybchik __in void *sdup, 117293809Sarybchik __in size_t sdu_len) 118293809Sarybchik{ 119293809Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 120293809Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 121293809Sarybchik efx_dword_t dword; 122293809Sarybchik unsigned int pos; 123293809Sarybchik 124293809Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 125293809Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 126293809Sarybchik 127293809Sarybchik /* Write the header */ 128293809Sarybchik for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) { 129293809Sarybchik dword = *(efx_dword_t *)((uint8_t *)hdrp + pos); 130293809Sarybchik EFSYS_MEM_WRITED(esmp, pos, &dword); 131293809Sarybchik } 132293809Sarybchik 133293809Sarybchik /* Write the payload */ 134293809Sarybchik for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) { 135293809Sarybchik dword = *(efx_dword_t *)((uint8_t *)sdup + pos); 136293809Sarybchik EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword); 137293809Sarybchik } 138293809Sarybchik 139293809Sarybchik /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ 140293809Sarybchik EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len); 141293809Sarybchik EFSYS_PIO_WRITE_BARRIER(); 142293809Sarybchik 143293809Sarybchik /* Ring the doorbell to post the command DMA address to the MC */ 144293809Sarybchik EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 145293809Sarybchik EFSYS_MEM_ADDR(esmp) >> 32); 146293809Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); 147293809Sarybchik 148293809Sarybchik EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 149293809Sarybchik EFSYS_MEM_ADDR(esmp) & 0xffffffff); 150293809Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 151293809Sarybchik} 152293809Sarybchik 153292090Sarybchik __checkReturn boolean_t 154293757Sarybchikef10_mcdi_poll_response( 155291928Sarybchik __in efx_nic_t *enp) 156291928Sarybchik{ 157291928Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 158291928Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 159291928Sarybchik efx_dword_t hdr; 160291928Sarybchik 161291928Sarybchik EFSYS_MEM_READD(esmp, 0, &hdr); 162291928Sarybchik return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); 163291928Sarybchik} 164291928Sarybchik 165291985Sarybchik void 166293757Sarybchikef10_mcdi_read_response( 167293817Sarybchik __in efx_nic_t *enp, 168293817Sarybchik __out_bcount(length) void *bufferp, 169293817Sarybchik __in size_t offset, 170293817Sarybchik __in size_t length) 171291985Sarybchik{ 172291985Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 173291985Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 174291985Sarybchik unsigned int pos; 175291985Sarybchik efx_dword_t data; 176291985Sarybchik 177291985Sarybchik for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) { 178291985Sarybchik EFSYS_MEM_READD(esmp, offset + pos, &data); 179291985Sarybchik memcpy((uint8_t *)bufferp + pos, &data, 180291985Sarybchik MIN(sizeof (data), length - pos)); 181291985Sarybchik } 182291985Sarybchik} 183291985Sarybchik 184291436Sarybchik efx_rc_t 185293757Sarybchikef10_mcdi_poll_reboot( 186283514Sarybchik __in efx_nic_t *enp) 187283514Sarybchik{ 188283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 189283514Sarybchik efx_dword_t dword; 190283514Sarybchik uint32_t old_status; 191283514Sarybchik uint32_t new_status; 192291436Sarybchik efx_rc_t rc; 193283514Sarybchik 194283514Sarybchik old_status = emip->emi_mc_reboot_status; 195283514Sarybchik 196283514Sarybchik /* Update MC reboot status word */ 197283514Sarybchik EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); 198283514Sarybchik new_status = dword.ed_u32[0]; 199283514Sarybchik 200283514Sarybchik /* MC has rebooted if the value has changed */ 201283514Sarybchik if (new_status != old_status) { 202283514Sarybchik emip->emi_mc_reboot_status = new_status; 203283514Sarybchik 204283514Sarybchik /* 205283514Sarybchik * FIXME: Ignore detected MC REBOOT for now. 206283514Sarybchik * 207283514Sarybchik * The Siena support for checking for MC reboot from status 208283514Sarybchik * flags is broken - see comments in siena_mcdi_poll_reboot(). 209293757Sarybchik * As the generic MCDI code is shared the EF10 reboot 210283514Sarybchik * detection suffers similar problems. 211283514Sarybchik * 212283514Sarybchik * Do not report an error when the boot status changes until 213283514Sarybchik * this can be handled by common code drivers (and reworked to 214283514Sarybchik * support Siena too). 215283514Sarybchik */ 216300841Sarybchik _NOTE(CONSTANTCONDITION) 217283514Sarybchik if (B_FALSE) { 218283514Sarybchik rc = EIO; 219283514Sarybchik goto fail1; 220283514Sarybchik } 221283514Sarybchik } 222283514Sarybchik 223283514Sarybchik return (0); 224283514Sarybchik 225283514Sarybchikfail1: 226291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 227283514Sarybchik 228283514Sarybchik return (rc); 229283514Sarybchik} 230283514Sarybchik 231291436Sarybchik __checkReturn efx_rc_t 232293757Sarybchikef10_mcdi_feature_supported( 233283514Sarybchik __in efx_nic_t *enp, 234292055Sarybchik __in efx_mcdi_feature_id_t id, 235283514Sarybchik __out boolean_t *supportedp) 236283514Sarybchik{ 237283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 238291585Sarybchik uint32_t privilege_mask = encp->enc_privilege_mask; 239292055Sarybchik efx_rc_t rc; 240283514Sarybchik 241293757Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 242293757Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 243283514Sarybchik 244291585Sarybchik /* 245291585Sarybchik * Use privilege mask state at MCDI attach. 246291585Sarybchik */ 247283514Sarybchik 248292055Sarybchik switch (id) { 249292055Sarybchik case EFX_MCDI_FEATURE_FW_UPDATE: 250292055Sarybchik /* 251292055Sarybchik * Admin privilege must be used prior to introduction of 252292055Sarybchik * specific flag. 253292055Sarybchik */ 254292055Sarybchik *supportedp = 255292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 256292055Sarybchik break; 257292055Sarybchik case EFX_MCDI_FEATURE_LINK_CONTROL: 258292055Sarybchik /* 259292055Sarybchik * Admin privilege used prior to introduction of 260292055Sarybchik * specific flag. 261292055Sarybchik */ 262292055Sarybchik *supportedp = 263292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) || 264292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 265292055Sarybchik break; 266292055Sarybchik case EFX_MCDI_FEATURE_MACADDR_CHANGE: 267292055Sarybchik /* 268292055Sarybchik * Admin privilege must be used prior to introduction of 269292055Sarybchik * mac spoofing privilege (at v4.6), which is used up to 270292055Sarybchik * introduction of change mac spoofing privilege (at v4.7) 271292055Sarybchik */ 272292055Sarybchik *supportedp = 273292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) || 274292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 275292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 276292055Sarybchik break; 277292055Sarybchik case EFX_MCDI_FEATURE_MAC_SPOOFING: 278292055Sarybchik /* 279292055Sarybchik * Admin privilege must be used prior to introduction of 280292055Sarybchik * mac spoofing privilege (at v4.6), which is used up to 281292055Sarybchik * introduction of mac spoofing TX privilege (at v4.7) 282292055Sarybchik */ 283292055Sarybchik *supportedp = 284292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) || 285292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 286292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 287292055Sarybchik break; 288292055Sarybchik default: 289292055Sarybchik rc = ENOTSUP; 290292055Sarybchik goto fail1; 291292055Sarybchik } 292283514Sarybchik 293292008Sarybchik return (0); 294292008Sarybchik 295292055Sarybchikfail1: 296292055Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 297292008Sarybchik 298292055Sarybchik return (rc); 299291588Sarybchik} 300291588Sarybchik 301283514Sarybchik#endif /* EFSYS_OPT_MCDI */ 302283514Sarybchik 303293757Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 304