ef10_mcdi.c revision 293765
1283514Sarybchik/*- 2283514Sarybchik * Copyright (c) 2012-2015 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: head/sys/dev/sfxge/common/hunt_mcdi.c 293765 2016-01-12 15:25:03Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efsys.h" 35283514Sarybchik#include "efx.h" 36283514Sarybchik#include "efx_impl.h" 37283514Sarybchik 38283514Sarybchik 39293757Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 40283514Sarybchik 41283514Sarybchik#if EFSYS_OPT_MCDI 42283514Sarybchik 43283514Sarybchik#ifndef WITH_MCDI_V2 44293757Sarybchik#error "WITH_MCDI_V2 required for EF10 MCDIv2 commands." 45283514Sarybchik#endif 46283514Sarybchik 47283514Sarybchiktypedef enum efx_mcdi_header_type_e { 48283514Sarybchik EFX_MCDI_HEADER_TYPE_V1, /* MCDIv0 (BootROM), MCDIv1 commands */ 49283514Sarybchik EFX_MCDI_HEADER_TYPE_V2, /* MCDIv2 commands */ 50283514Sarybchik} efx_mcdi_header_type_t; 51283514Sarybchik 52283514Sarybchik/* 53283514Sarybchik * Return the header format to use for sending an MCDI request. 54283514Sarybchik * 55283514Sarybchik * An MCDIv1 (Siena compatible) command should use MCDIv2 encapsulation if the 56283514Sarybchik * request input buffer or response output buffer are too large for the MCDIv1 57283514Sarybchik * format. An MCDIv2 command must always be sent using MCDIv2 encapsulation. 58283514Sarybchik */ 59283514Sarybchik#define EFX_MCDI_HEADER_TYPE(_cmd, _length) \ 60283514Sarybchik ((((_cmd) & ~EFX_MASK32(MCDI_HEADER_CODE)) || \ 61283514Sarybchik ((_length) & ~EFX_MASK32(MCDI_HEADER_DATALEN))) ? \ 62283514Sarybchik EFX_MCDI_HEADER_TYPE_V2 : EFX_MCDI_HEADER_TYPE_V1) 63283514Sarybchik 64283514Sarybchik 65283514Sarybchik/* 66283514Sarybchik * MCDI Header NOT_EPOCH flag 67283514Sarybchik * ========================== 68283514Sarybchik * A new epoch begins at initial startup or after an MC reboot, and defines when 69283514Sarybchik * the MC should reject stale MCDI requests. 70283514Sarybchik * 71283514Sarybchik * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all 72283514Sarybchik * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1. 73283514Sarybchik * 74283514Sarybchik * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a 75283514Sarybchik * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0. 76283514Sarybchik */ 77283514Sarybchik 78283514Sarybchik 79291436Sarybchik __checkReturn efx_rc_t 80293757Sarybchikef10_mcdi_init( 81283514Sarybchik __in efx_nic_t *enp, 82283514Sarybchik __in const efx_mcdi_transport_t *emtp) 83283514Sarybchik{ 84293765Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 85283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 86283514Sarybchik efx_dword_t dword; 87291436Sarybchik efx_rc_t rc; 88283514Sarybchik 89293757Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 90293757Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 91283514Sarybchik EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA); 92283514Sarybchik 93293765Sarybchik /* 94293765Sarybchik * All EF10 firmware supports MCDIv2 and MCDIv1. 95293765Sarybchik * Medford BootROM supports MCDIv2 and MCDIv1. 96293765Sarybchik * Huntington BootROM supports MCDIv1 only. 97293765Sarybchik */ 98293765Sarybchik emip->emi_max_version = 2; 99293765Sarybchik 100293757Sarybchik /* A host DMA buffer is required for EF10 MCDI */ 101283514Sarybchik if (esmp == NULL) { 102283514Sarybchik rc = EINVAL; 103283514Sarybchik goto fail1; 104283514Sarybchik } 105283514Sarybchik 106283514Sarybchik /* 107283514Sarybchik * Ensure that the MC doorbell is in a known state before issuing MCDI 108283514Sarybchik * commands. The recovery algorithm requires that the MC command buffer 109283514Sarybchik * must be 256 byte aligned. See bug24769. 110283514Sarybchik */ 111283514Sarybchik if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) { 112283514Sarybchik rc = EINVAL; 113283514Sarybchik goto fail2; 114283514Sarybchik } 115283514Sarybchik EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1); 116283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 117283514Sarybchik 118283514Sarybchik /* Save initial MC reboot status */ 119293757Sarybchik (void) ef10_mcdi_poll_reboot(enp); 120283514Sarybchik 121283514Sarybchik /* Start a new epoch (allow fresh MCDI requests to succeed) */ 122283514Sarybchik efx_mcdi_new_epoch(enp); 123283514Sarybchik 124283514Sarybchik return (0); 125283514Sarybchik 126283514Sarybchikfail2: 127283514Sarybchik EFSYS_PROBE(fail2); 128283514Sarybchikfail1: 129291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 130283514Sarybchik 131283514Sarybchik return (rc); 132283514Sarybchik} 133283514Sarybchik 134283514Sarybchik void 135293757Sarybchikef10_mcdi_fini( 136283514Sarybchik __in efx_nic_t *enp) 137283514Sarybchik{ 138283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 139283514Sarybchik 140283514Sarybchik emip->emi_new_epoch = B_FALSE; 141283514Sarybchik} 142283514Sarybchik 143283514Sarybchik void 144293757Sarybchikef10_mcdi_request_copyin( 145283514Sarybchik __in efx_nic_t *enp, 146283514Sarybchik __in efx_mcdi_req_t *emrp, 147283514Sarybchik __in unsigned int seq, 148283514Sarybchik __in boolean_t ev_cpl, 149283514Sarybchik __in boolean_t new_epoch) 150283514Sarybchik{ 151283514Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 152283514Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 153283514Sarybchik efx_mcdi_header_type_t hdr_type; 154283514Sarybchik efx_dword_t dword; 155291677Sarybchik efx_dword_t hdr[2]; 156283514Sarybchik unsigned int xflags; 157283514Sarybchik unsigned int pos; 158283514Sarybchik size_t offset; 159283514Sarybchik 160293757Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 161293757Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 162283514Sarybchik 163283514Sarybchik xflags = 0; 164283514Sarybchik if (ev_cpl) 165283514Sarybchik xflags |= MCDI_HEADER_XFLAGS_EVREQ; 166283514Sarybchik 167283514Sarybchik offset = 0; 168283514Sarybchik 169283514Sarybchik hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd, 170283514Sarybchik MAX(emrp->emr_in_length, emrp->emr_out_length)); 171283514Sarybchik 172283514Sarybchik if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) { 173283514Sarybchik /* Construct MCDI v2 header */ 174291677Sarybchik EFX_POPULATE_DWORD_8(hdr[0], 175283514Sarybchik MCDI_HEADER_CODE, MC_CMD_V2_EXTN, 176283514Sarybchik MCDI_HEADER_RESYNC, 1, 177283514Sarybchik MCDI_HEADER_DATALEN, 0, 178283514Sarybchik MCDI_HEADER_SEQ, seq, 179283514Sarybchik MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 180283514Sarybchik MCDI_HEADER_ERROR, 0, 181283514Sarybchik MCDI_HEADER_RESPONSE, 0, 182283514Sarybchik MCDI_HEADER_XFLAGS, xflags); 183291677Sarybchik EFSYS_MEM_WRITED(esmp, offset, &hdr[0]); 184291677Sarybchik offset += sizeof (efx_dword_t); 185283514Sarybchik 186291677Sarybchik EFX_POPULATE_DWORD_2(hdr[1], 187283514Sarybchik MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, 188283514Sarybchik MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); 189291677Sarybchik EFSYS_MEM_WRITED(esmp, offset, &hdr[1]); 190291677Sarybchik offset += sizeof (efx_dword_t); 191283514Sarybchik } else { 192283514Sarybchik /* Construct MCDI v1 header */ 193291677Sarybchik EFX_POPULATE_DWORD_8(hdr[0], 194283514Sarybchik MCDI_HEADER_CODE, emrp->emr_cmd, 195283514Sarybchik MCDI_HEADER_RESYNC, 1, 196283514Sarybchik MCDI_HEADER_DATALEN, emrp->emr_in_length, 197283514Sarybchik MCDI_HEADER_SEQ, seq, 198283514Sarybchik MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 199283514Sarybchik MCDI_HEADER_ERROR, 0, 200283514Sarybchik MCDI_HEADER_RESPONSE, 0, 201283514Sarybchik MCDI_HEADER_XFLAGS, xflags); 202291677Sarybchik EFSYS_MEM_WRITED(esmp, 0, &hdr[0]); 203291677Sarybchik offset += sizeof (efx_dword_t); 204283514Sarybchik } 205283514Sarybchik 206291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING 207291677Sarybchik if (emtp->emt_logger != NULL) { 208291677Sarybchik emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST, 209291677Sarybchik &hdr, offset, 210291677Sarybchik emrp->emr_in_buf, emrp->emr_in_length); 211291677Sarybchik } 212291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 213291677Sarybchik 214283514Sarybchik /* Construct the payload */ 215283514Sarybchik for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) { 216283514Sarybchik memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos), 217283514Sarybchik MIN(sizeof (dword), emrp->emr_in_length - pos)); 218283514Sarybchik EFSYS_MEM_WRITED(esmp, offset + pos, &dword); 219283514Sarybchik } 220283514Sarybchik 221283514Sarybchik /* Ring the doorbell to post the command DMA address to the MC */ 222283514Sarybchik EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0); 223283514Sarybchik 224283514Sarybchik /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ 225283514Sarybchik EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length); 226283514Sarybchik EFSYS_PIO_WRITE_BARRIER(); 227283514Sarybchik 228283514Sarybchik EFX_POPULATE_DWORD_1(dword, 229283514Sarybchik EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32); 230283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); 231283514Sarybchik 232283514Sarybchik EFX_POPULATE_DWORD_1(dword, 233283514Sarybchik EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff); 234283514Sarybchik EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 235283514Sarybchik} 236283514Sarybchik 237283514Sarybchik void 238293757Sarybchikef10_mcdi_request_copyout( 239283514Sarybchik __in efx_nic_t *enp, 240283514Sarybchik __in efx_mcdi_req_t *emrp) 241283514Sarybchik{ 242291985Sarybchik#if EFSYS_OPT_MCDI_LOGGING 243283514Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 244291985Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 245291677Sarybchik efx_dword_t hdr[2]; 246291985Sarybchik unsigned int hdr_len; 247283514Sarybchik size_t bytes; 248283514Sarybchik 249283514Sarybchik if (emrp->emr_out_buf == NULL) 250283514Sarybchik return; 251283514Sarybchik 252283514Sarybchik /* Read the command header to detect MCDI response format */ 253291985Sarybchik hdr_len = sizeof (hdr[0]); 254293757Sarybchik ef10_mcdi_read_response(enp, &hdr[0], 0, hdr_len); 255291677Sarybchik if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 256283514Sarybchik /* 257283514Sarybchik * Read the actual payload length. The length given in the event 258283514Sarybchik * is only correct for responses with the V1 format. 259283514Sarybchik */ 260293757Sarybchik ef10_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 261291985Sarybchik hdr_len += sizeof (hdr[1]); 262291985Sarybchik 263291677Sarybchik emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1], 264283514Sarybchik MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 265283514Sarybchik } 266283514Sarybchik 267283514Sarybchik /* Copy payload out into caller supplied buffer */ 268283514Sarybchik bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); 269293757Sarybchik ef10_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes); 270291677Sarybchik 271291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING 272291677Sarybchik if (emtp->emt_logger != NULL) { 273291677Sarybchik emtp->emt_logger(emtp->emt_context, 274291677Sarybchik EFX_LOG_MCDI_RESPONSE, 275291985Sarybchik &hdr, hdr_len, 276291985Sarybchik emrp->emr_out_buf, bytes); 277291677Sarybchik } 278291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */ 279283514Sarybchik} 280283514Sarybchik 281292090Sarybchik __checkReturn boolean_t 282293757Sarybchikef10_mcdi_poll_response( 283291928Sarybchik __in efx_nic_t *enp) 284291928Sarybchik{ 285291928Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 286291928Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 287291928Sarybchik efx_dword_t hdr; 288291928Sarybchik 289291928Sarybchik EFSYS_MEM_READD(esmp, 0, &hdr); 290291928Sarybchik return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); 291291928Sarybchik} 292291928Sarybchik 293291985Sarybchik void 294293757Sarybchikef10_mcdi_read_response( 295291985Sarybchik __in efx_nic_t *enp, 296291985Sarybchik __out void *bufferp, 297291985Sarybchik __in size_t offset, 298291985Sarybchik __in size_t length) 299291985Sarybchik{ 300291985Sarybchik const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 301291985Sarybchik efsys_mem_t *esmp = emtp->emt_dma_mem; 302291985Sarybchik unsigned int pos; 303291985Sarybchik efx_dword_t data; 304291985Sarybchik 305291985Sarybchik for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) { 306291985Sarybchik EFSYS_MEM_READD(esmp, offset + pos, &data); 307291985Sarybchik memcpy((uint8_t *)bufferp + pos, &data, 308291985Sarybchik MIN(sizeof (data), length - pos)); 309291985Sarybchik } 310291985Sarybchik} 311291985Sarybchik 312291436Sarybchik efx_rc_t 313293757Sarybchikef10_mcdi_poll_reboot( 314283514Sarybchik __in efx_nic_t *enp) 315283514Sarybchik{ 316283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 317283514Sarybchik efx_dword_t dword; 318283514Sarybchik uint32_t old_status; 319283514Sarybchik uint32_t new_status; 320291436Sarybchik efx_rc_t rc; 321283514Sarybchik 322283514Sarybchik old_status = emip->emi_mc_reboot_status; 323283514Sarybchik 324283514Sarybchik /* Update MC reboot status word */ 325283514Sarybchik EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); 326283514Sarybchik new_status = dword.ed_u32[0]; 327283514Sarybchik 328283514Sarybchik /* MC has rebooted if the value has changed */ 329283514Sarybchik if (new_status != old_status) { 330283514Sarybchik emip->emi_mc_reboot_status = new_status; 331283514Sarybchik 332283514Sarybchik /* 333283514Sarybchik * FIXME: Ignore detected MC REBOOT for now. 334283514Sarybchik * 335283514Sarybchik * The Siena support for checking for MC reboot from status 336283514Sarybchik * flags is broken - see comments in siena_mcdi_poll_reboot(). 337293757Sarybchik * As the generic MCDI code is shared the EF10 reboot 338283514Sarybchik * detection suffers similar problems. 339283514Sarybchik * 340283514Sarybchik * Do not report an error when the boot status changes until 341283514Sarybchik * this can be handled by common code drivers (and reworked to 342283514Sarybchik * support Siena too). 343283514Sarybchik */ 344283514Sarybchik if (B_FALSE) { 345283514Sarybchik rc = EIO; 346283514Sarybchik goto fail1; 347283514Sarybchik } 348283514Sarybchik } 349283514Sarybchik 350283514Sarybchik return (0); 351283514Sarybchik 352283514Sarybchikfail1: 353291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 354283514Sarybchik 355283514Sarybchik return (rc); 356283514Sarybchik} 357283514Sarybchik 358291436Sarybchik __checkReturn efx_rc_t 359293757Sarybchikef10_mcdi_feature_supported( 360283514Sarybchik __in efx_nic_t *enp, 361292055Sarybchik __in efx_mcdi_feature_id_t id, 362283514Sarybchik __out boolean_t *supportedp) 363283514Sarybchik{ 364283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 365291585Sarybchik uint32_t privilege_mask = encp->enc_privilege_mask; 366292055Sarybchik efx_rc_t rc; 367283514Sarybchik 368293757Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 369293757Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 370283514Sarybchik 371291585Sarybchik /* 372291585Sarybchik * Use privilege mask state at MCDI attach. 373291585Sarybchik */ 374283514Sarybchik 375292055Sarybchik switch (id) { 376292055Sarybchik case EFX_MCDI_FEATURE_FW_UPDATE: 377292055Sarybchik /* 378292055Sarybchik * Admin privilege must be used prior to introduction of 379292055Sarybchik * specific flag. 380292055Sarybchik */ 381292055Sarybchik *supportedp = 382292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 383292055Sarybchik break; 384292055Sarybchik case EFX_MCDI_FEATURE_LINK_CONTROL: 385292055Sarybchik /* 386292055Sarybchik * Admin privilege used prior to introduction of 387292055Sarybchik * specific flag. 388292055Sarybchik */ 389292055Sarybchik *supportedp = 390292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) || 391292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 392292055Sarybchik break; 393292055Sarybchik case EFX_MCDI_FEATURE_MACADDR_CHANGE: 394292055Sarybchik /* 395292055Sarybchik * Admin privilege must be used prior to introduction of 396292055Sarybchik * mac spoofing privilege (at v4.6), which is used up to 397292055Sarybchik * introduction of change mac spoofing privilege (at v4.7) 398292055Sarybchik */ 399292055Sarybchik *supportedp = 400292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) || 401292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 402292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 403292055Sarybchik break; 404292055Sarybchik case EFX_MCDI_FEATURE_MAC_SPOOFING: 405292055Sarybchik /* 406292055Sarybchik * Admin privilege must be used prior to introduction of 407292055Sarybchik * mac spoofing privilege (at v4.6), which is used up to 408292055Sarybchik * introduction of mac spoofing TX privilege (at v4.7) 409292055Sarybchik */ 410292055Sarybchik *supportedp = 411292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) || 412292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 413292055Sarybchik EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 414292055Sarybchik break; 415292055Sarybchik default: 416292055Sarybchik rc = ENOTSUP; 417292055Sarybchik goto fail1; 418292055Sarybchik break; 419292055Sarybchik } 420283514Sarybchik 421292008Sarybchik return (0); 422292008Sarybchik 423292055Sarybchikfail1: 424292055Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 425292008Sarybchik 426292055Sarybchik return (rc); 427291588Sarybchik} 428291588Sarybchik 429283514Sarybchik#endif /* EFSYS_OPT_MCDI */ 430283514Sarybchik 431293757Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 432