ef10_nic.c revision 291747
1220137Strasz/*- 2220137Strasz * Copyright (c) 2012-2015 Solarflare Communications Inc. 3220137Strasz * All rights reserved. 4220137Strasz * 5220137Strasz * Redistribution and use in source and binary forms, with or without 6220137Strasz * modification, are permitted provided that the following conditions are met: 7220137Strasz * 8220137Strasz * 1. Redistributions of source code must retain the above copyright notice, 9220137Strasz * this list of conditions and the following disclaimer. 10220137Strasz * 2. Redistributions in binary form must reproduce the above copyright notice, 11220137Strasz * this list of conditions and the following disclaimer in the documentation 12220137Strasz * and/or other materials provided with the distribution. 13220137Strasz * 14220137Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15220137Strasz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16220137Strasz * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17220137Strasz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18220137Strasz * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19220137Strasz * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20220137Strasz * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21220137Strasz * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22220137Strasz * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23220137Strasz * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24220137Strasz * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25220137Strasz * 26220137Strasz * The views and conclusions contained in the software and documentation are 27220137Strasz * those of the authors and should not be interpreted as representing official 28220137Strasz * policies, either expressed or implied, of the FreeBSD Project. 29220137Strasz */ 30220137Strasz 31220137Strasz#include <sys/cdefs.h> 32220137Strasz__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_nic.c 291747 2015-12-04 06:54:46Z arybchik $"); 33220137Strasz 34220137Strasz#include "efsys.h" 35242139Strasz#include "efx.h" 36220137Strasz#include "efx_impl.h" 37220137Strasz#include "mcdi_mon.h" 38228430Savg 39220137Strasz#if EFSYS_OPT_HUNTINGTON 40220137Strasz 41220137Strasz#include "ef10_tlv_layout.h" 42220137Strasz 43220137Straszstatic __checkReturn efx_rc_t 44220137Straszefx_mcdi_get_port_assignment( 45220137Strasz __in efx_nic_t *enp, 46220137Strasz __out uint32_t *portp) 47220137Strasz{ 48220137Strasz efx_mcdi_req_t req; 49220137Strasz uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, 50220137Strasz MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; 51220137Strasz efx_rc_t rc; 52220137Strasz 53242139Strasz EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 54220137Strasz 55242139Strasz (void) memset(payload, 0, sizeof (payload)); 56220137Strasz req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; 57220137Strasz req.emr_in_buf = payload; 58220137Strasz req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; 59242139Strasz req.emr_out_buf = payload; 60220137Strasz req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN; 61220137Strasz 62220137Strasz efx_mcdi_execute(enp, &req); 63220137Strasz 64220137Strasz if (req.emr_rc != 0) { 65220137Strasz rc = req.emr_rc; 66220137Strasz goto fail1; 67220137Strasz } 68220137Strasz 69242139Strasz if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) { 70242139Strasz rc = EMSGSIZE; 71242139Strasz goto fail2; 72242139Strasz } 73242139Strasz 74242139Strasz *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); 75242139Strasz 76242139Strasz return (0); 77242139Strasz 78242139Straszfail2: 79242139Strasz EFSYS_PROBE(fail2); 80242139Straszfail1: 81242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 82242139Strasz 83242139Strasz return (rc); 84242139Strasz} 85242139Strasz 86220137Straszstatic __checkReturn efx_rc_t 87220137Straszefx_mcdi_get_port_modes( 88220137Strasz __in efx_nic_t *enp, 89220137Strasz __out uint32_t *modesp) 90220137Strasz{ 91220137Strasz efx_mcdi_req_t req; 92220137Strasz uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, 93220137Strasz MC_CMD_GET_PORT_MODES_OUT_LEN)]; 94220137Strasz efx_rc_t rc; 95220137Strasz 96220137Strasz EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 97220137Strasz 98258622Savg (void) memset(payload, 0, sizeof (payload)); 99220137Strasz req.emr_cmd = MC_CMD_GET_PORT_MODES; 100258622Savg req.emr_in_buf = payload; 101220137Strasz req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; 102258622Savg req.emr_out_buf = payload; 103220137Strasz req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; 104258622Savg 105220137Strasz efx_mcdi_execute(enp, &req); 106258622Savg 107220137Strasz if (req.emr_rc != 0) { 108258622Savg rc = req.emr_rc; 109220137Strasz goto fail1; 110258622Savg } 111220137Strasz 112258622Savg /* Accept pre-Medford size (8 bytes - no CurrentMode field) */ 113220137Strasz if (req.emr_out_length_used < 114258622Savg MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { 115258622Savg rc = EMSGSIZE; 116258622Savg goto fail2; 117220137Strasz } 118258622Savg 119220137Strasz *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); 120258622Savg 121220137Strasz return (0); 122220137Strasz 123220137Straszfail2: 124220137Strasz EFSYS_PROBE(fail2); 125224036Straszfail1: 126220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 127220137Strasz 128220137Strasz return (rc); 129220137Strasz} 130220137Strasz 131220137Strasz 132220137Straszstatic __checkReturn efx_rc_t 133220137Straszefx_mcdi_vadaptor_alloc( 134220137Strasz __in efx_nic_t *enp, 135220137Strasz __in uint32_t port_id) 136220137Strasz{ 137220137Strasz efx_mcdi_req_t req; 138220137Strasz uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, 139220137Strasz MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; 140220137Strasz efx_rc_t rc; 141220137Strasz 142220137Strasz EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); 143220137Strasz 144220137Strasz (void) memset(payload, 0, sizeof (payload)); 145220137Strasz req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; 146220137Strasz req.emr_in_buf = payload; 147220137Strasz req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; 148220137Strasz req.emr_out_buf = payload; 149220137Strasz req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; 150220137Strasz 151220137Strasz MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); 152220137Strasz 153220137Strasz efx_mcdi_execute(enp, &req); 154220137Strasz 155220137Strasz if (req.emr_rc != 0) { 156220137Strasz rc = req.emr_rc; 157220137Strasz goto fail1; 158220137Strasz } 159220137Strasz 160220137Strasz return (0); 161220137Strasz 162220137Straszfail1: 163242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 164242139Strasz 165242139Strasz return (rc); 166220137Strasz} 167242139Strasz 168242139Straszstatic __checkReturn efx_rc_t 169242139Straszefx_mcdi_vadaptor_free( 170242139Strasz __in efx_nic_t *enp, 171242139Strasz __in uint32_t port_id) 172242139Strasz{ 173242139Strasz efx_mcdi_req_t req; 174242139Strasz uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, 175242139Strasz MC_CMD_VADAPTOR_FREE_OUT_LEN)]; 176242139Strasz efx_rc_t rc; 177242139Strasz 178242139Strasz (void) memset(payload, 0, sizeof (payload)); 179242139Strasz req.emr_cmd = MC_CMD_VADAPTOR_FREE; 180242139Strasz req.emr_in_buf = payload; 181242139Strasz req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; 182242139Strasz req.emr_out_buf = payload; 183242139Strasz req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; 184242139Strasz 185242139Strasz MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); 186242139Strasz 187242139Strasz efx_mcdi_execute(enp, &req); 188242139Strasz 189242139Strasz if (req.emr_rc != 0) { 190242139Strasz rc = req.emr_rc; 191242139Strasz goto fail1; 192242139Strasz } 193242139Strasz 194242139Strasz return (0); 195242139Strasz 196242139Straszfail1: 197242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 198242139Strasz 199242139Strasz return (rc); 200242139Strasz} 201242139Strasz 202242139Straszstatic __checkReturn efx_rc_t 203242139Straszefx_mcdi_get_mac_address_pf( 204242139Strasz __in efx_nic_t *enp, 205242139Strasz __out_ecount_opt(6) uint8_t mac_addrp[6]) 206242139Strasz{ 207242139Strasz efx_mcdi_req_t req; 208242139Strasz uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, 209242139Strasz MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; 210242139Strasz efx_rc_t rc; 211242139Strasz 212242139Strasz EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 213242139Strasz 214242139Strasz (void) memset(payload, 0, sizeof (payload)); 215242139Strasz req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; 216242139Strasz req.emr_in_buf = payload; 217242139Strasz req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; 218242139Strasz req.emr_out_buf = payload; 219242139Strasz req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN; 220242139Strasz 221242139Strasz efx_mcdi_execute(enp, &req); 222242139Strasz 223242139Strasz if (req.emr_rc != 0) { 224242139Strasz rc = req.emr_rc; 225242139Strasz goto fail1; 226242139Strasz } 227242139Strasz 228242139Strasz if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) { 229242139Strasz rc = EMSGSIZE; 230242139Strasz goto fail2; 231242139Strasz } 232242139Strasz 233242139Strasz if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { 234242139Strasz rc = ENOENT; 235242139Strasz goto fail3; 236242139Strasz } 237242139Strasz 238242139Strasz if (mac_addrp != NULL) { 239242139Strasz uint8_t *addrp; 240242139Strasz 241242139Strasz addrp = MCDI_OUT2(req, uint8_t, 242242139Strasz GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); 243242139Strasz 244242139Strasz EFX_MAC_ADDR_COPY(mac_addrp, addrp); 245242139Strasz } 246242139Strasz 247242139Strasz return (0); 248242139Strasz 249242139Straszfail3: 250242139Strasz EFSYS_PROBE(fail3); 251242139Straszfail2: 252242139Strasz EFSYS_PROBE(fail2); 253242139Straszfail1: 254242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 255242139Strasz 256242139Strasz return (rc); 257242139Strasz} 258242139Strasz 259242139Straszstatic __checkReturn efx_rc_t 260242139Straszefx_mcdi_get_mac_address_vf( 261242139Strasz __in efx_nic_t *enp, 262242139Strasz __out_ecount_opt(6) uint8_t mac_addrp[6]) 263242139Strasz{ 264242139Strasz efx_mcdi_req_t req; 265242139Strasz uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, 266242139Strasz MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; 267242139Strasz efx_rc_t rc; 268242139Strasz 269242139Strasz EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 270242139Strasz 271242139Strasz (void) memset(payload, 0, sizeof (payload)); 272242139Strasz req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; 273242139Strasz req.emr_in_buf = payload; 274242139Strasz req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; 275242139Strasz req.emr_out_buf = payload; 276242139Strasz req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; 277242139Strasz 278242139Strasz MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, 279242139Strasz EVB_PORT_ID_ASSIGNED); 280242139Strasz 281242139Strasz efx_mcdi_execute(enp, &req); 282242139Strasz 283242139Strasz if (req.emr_rc != 0) { 284242139Strasz rc = req.emr_rc; 285242139Strasz goto fail1; 286242139Strasz } 287242139Strasz 288242139Strasz if (req.emr_out_length_used < 289242139Strasz MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { 290242139Strasz rc = EMSGSIZE; 291242139Strasz goto fail2; 292242139Strasz } 293242139Strasz 294242139Strasz if (MCDI_OUT_DWORD(req, 295242139Strasz VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { 296242139Strasz rc = ENOENT; 297242139Strasz goto fail3; 298242139Strasz } 299242139Strasz 300242139Strasz if (mac_addrp != NULL) { 301242139Strasz uint8_t *addrp; 302242139Strasz 303242139Strasz addrp = MCDI_OUT2(req, uint8_t, 304242139Strasz VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); 305242139Strasz 306242139Strasz EFX_MAC_ADDR_COPY(mac_addrp, addrp); 307242139Strasz } 308242139Strasz 309242139Strasz return (0); 310242139Strasz 311242139Straszfail3: 312242139Strasz EFSYS_PROBE(fail3); 313242139Straszfail2: 314242139Strasz EFSYS_PROBE(fail2); 315242139Straszfail1: 316242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 317242139Strasz 318242139Strasz return (rc); 319242139Strasz} 320242139Strasz 321242139Straszstatic __checkReturn efx_rc_t 322242139Straszefx_mcdi_get_clock( 323242139Strasz __in efx_nic_t *enp, 324242139Strasz __out uint32_t *sys_freqp) 325242139Strasz{ 326242139Strasz efx_mcdi_req_t req; 327242139Strasz uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, 328242139Strasz MC_CMD_GET_CLOCK_OUT_LEN)]; 329242139Strasz efx_rc_t rc; 330242139Strasz 331242139Strasz EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 332242139Strasz 333242139Strasz (void) memset(payload, 0, sizeof (payload)); 334242139Strasz req.emr_cmd = MC_CMD_GET_CLOCK; 335242139Strasz req.emr_in_buf = payload; 336242139Strasz req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; 337242139Strasz req.emr_out_buf = payload; 338242139Strasz req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN; 339242139Strasz 340242139Strasz efx_mcdi_execute(enp, &req); 341242139Strasz 342242139Strasz if (req.emr_rc != 0) { 343242139Strasz rc = req.emr_rc; 344242139Strasz goto fail1; 345242139Strasz } 346242139Strasz 347242139Strasz if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) { 348242139Strasz rc = EMSGSIZE; 349242139Strasz goto fail2; 350242139Strasz } 351242139Strasz 352242139Strasz *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); 353242139Strasz if (*sys_freqp == 0) { 354242139Strasz rc = EINVAL; 355242139Strasz goto fail3; 356242139Strasz } 357242139Strasz 358242139Strasz return (0); 359242139Strasz 360242139Straszfail3: 361242139Strasz EFSYS_PROBE(fail3); 362242139Straszfail2: 363242139Strasz EFSYS_PROBE(fail2); 364242139Straszfail1: 365242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 366242139Strasz 367242139Strasz return (rc); 368242139Strasz} 369242139Strasz 370242139Straszstatic __checkReturn efx_rc_t 371242139Straszefx_mcdi_get_vector_cfg( 372242139Strasz __in efx_nic_t *enp, 373242139Strasz __out_opt uint32_t *vec_basep, 374242139Strasz __out_opt uint32_t *pf_nvecp, 375220137Strasz __out_opt uint32_t *vf_nvecp) 376220137Strasz{ 377220137Strasz efx_mcdi_req_t req; 378220137Strasz uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, 379220137Strasz MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; 380220137Strasz efx_rc_t rc; 381220137Strasz 382220137Strasz (void) memset(payload, 0, sizeof (payload)); 383220137Strasz req.emr_cmd = MC_CMD_GET_VECTOR_CFG; 384220137Strasz req.emr_in_buf = payload; 385220137Strasz req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; 386220137Strasz req.emr_out_buf = payload; 387243088Strasz req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN; 388243088Strasz 389220137Strasz efx_mcdi_execute(enp, &req); 390243088Strasz 391243088Strasz if (req.emr_rc != 0) { 392220137Strasz rc = req.emr_rc; 393220137Strasz goto fail1; 394220137Strasz } 395220137Strasz 396220137Strasz if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) { 397220137Strasz rc = EMSGSIZE; 398220137Strasz goto fail2; 399220137Strasz } 400220137Strasz 401220137Strasz if (vec_basep != NULL) 402220137Strasz *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); 403220137Strasz if (pf_nvecp != NULL) 404220137Strasz *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); 405220137Strasz if (vf_nvecp != NULL) 406220137Strasz *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); 407243070Strasz 408220137Strasz return (0); 409243088Strasz 410243088Straszfail2: 411220137Strasz EFSYS_PROBE(fail2); 412243088Straszfail1: 413243088Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 414220137Strasz 415243088Strasz return (rc); 416243088Strasz} 417220137Strasz 418242139Straszstatic __checkReturn efx_rc_t 419220137Straszefx_mcdi_get_capabilities( 420220137Strasz __in efx_nic_t *enp, 421243070Strasz __out efx_dword_t *flagsp) 422243070Strasz{ 423243088Strasz efx_mcdi_req_t req; 424220137Strasz uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, 425220137Strasz MC_CMD_GET_CAPABILITIES_OUT_LEN)]; 426220137Strasz efx_rc_t rc; 427220137Strasz 428220137Strasz (void) memset(payload, 0, sizeof (payload)); 429220137Strasz req.emr_cmd = MC_CMD_GET_CAPABILITIES; 430220137Strasz req.emr_in_buf = payload; 431220137Strasz req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; 432220137Strasz req.emr_out_buf = payload; 433220137Strasz req.emr_out_length = MC_CMD_GET_CAPABILITIES_OUT_LEN; 434220137Strasz 435220137Strasz efx_mcdi_execute(enp, &req); 436220137Strasz 437220137Strasz if (req.emr_rc != 0) { 438220137Strasz rc = req.emr_rc; 439220137Strasz goto fail1; 440220137Strasz } 441220137Strasz 442220137Strasz if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { 443220137Strasz rc = EMSGSIZE; 444220137Strasz goto fail2; 445220137Strasz } 446220137Strasz 447220137Strasz *flagsp = *MCDI_OUT2(req, efx_dword_t, GET_CAPABILITIES_OUT_FLAGS1); 448220137Strasz 449220137Strasz return (0); 450220137Strasz 451220137Straszfail2: 452220137Strasz EFSYS_PROBE(fail2); 453220137Straszfail1: 454220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 455220137Strasz 456223844Strasz return (rc); 457220137Strasz} 458223844Strasz 459220137Strasz 460220137Straszstatic __checkReturn efx_rc_t 461220137Straszefx_mcdi_alloc_vis( 462220137Strasz __in efx_nic_t *enp, 463220137Strasz __in uint32_t min_vi_count, 464220137Strasz __in uint32_t max_vi_count, 465220137Strasz __out_opt uint32_t *vi_basep, 466220137Strasz __out uint32_t *vi_countp) 467220137Strasz 468220137Strasz{ 469220137Strasz efx_mcdi_req_t req; 470220137Strasz uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, 471220137Strasz MC_CMD_ALLOC_VIS_OUT_LEN)]; 472220137Strasz efx_rc_t rc; 473220137Strasz 474220137Strasz if (vi_countp == NULL) { 475220137Strasz rc = EINVAL; 476220137Strasz goto fail1; 477220137Strasz } 478220137Strasz 479220137Strasz (void) memset(payload, 0, sizeof (payload)); 480220137Strasz req.emr_cmd = MC_CMD_ALLOC_VIS; 481220137Strasz req.emr_in_buf = payload; 482220137Strasz req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; 483220137Strasz req.emr_out_buf = payload; 484220137Strasz req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; 485220137Strasz 486220137Strasz MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); 487220137Strasz MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); 488220137Strasz 489220137Strasz efx_mcdi_execute(enp, &req); 490220137Strasz 491220137Strasz if (req.emr_rc != 0) { 492220137Strasz rc = req.emr_rc; 493242139Strasz goto fail2; 494243088Strasz } 495220137Strasz 496220137Strasz if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { 497242139Strasz rc = EMSGSIZE; 498242139Strasz goto fail3; 499242139Strasz } 500242139Strasz 501242139Strasz if (vi_basep != NULL) 502242139Strasz *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); 503242139Strasz 504242139Strasz if (vi_countp != NULL) 505242139Strasz *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); 506242139Strasz 507242139Strasz return (0); 508242139Strasz 509242139Straszfail3: 510220137Strasz EFSYS_PROBE(fail3); 511220137Straszfail2: 512225944Strasz EFSYS_PROBE(fail2); 513225944Straszfail1: 514220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 515220137Strasz 516220137Strasz return (rc); 517220137Strasz} 518220137Strasz 519220137Strasz 520220137Straszstatic __checkReturn efx_rc_t 521220137Straszefx_mcdi_free_vis( 522220137Strasz __in efx_nic_t *enp) 523220137Strasz{ 524220137Strasz efx_mcdi_req_t req; 525220137Strasz efx_rc_t rc; 526220137Strasz 527220137Strasz EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); 528223844Strasz EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); 529258622Savg 530220137Strasz req.emr_cmd = MC_CMD_FREE_VIS; 531220137Strasz req.emr_in_buf = NULL; 532220137Strasz req.emr_in_length = 0; 533220137Strasz req.emr_out_buf = NULL; 534220137Strasz req.emr_out_length = 0; 535220137Strasz 536220137Strasz efx_mcdi_execute_quiet(enp, &req); 537220137Strasz 538220137Strasz /* Ignore ELREADY (no allocated VIs, so nothing to free) */ 539220137Strasz if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { 540225944Strasz rc = req.emr_rc; 541225944Strasz goto fail1; 542225944Strasz } 543225944Strasz 544225944Strasz return (0); 545225944Strasz 546225944Straszfail1: 547225944Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 548225944Strasz 549225944Strasz return (rc); 550225944Strasz} 551225944Strasz 552225944Strasz 553225944Straszstatic __checkReturn efx_rc_t 554225944Straszefx_mcdi_alloc_piobuf( 555220137Strasz __in efx_nic_t *enp, 556220137Strasz __out efx_piobuf_handle_t *handlep) 557220137Strasz{ 558220137Strasz efx_mcdi_req_t req; 559220137Strasz uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, 560258622Savg MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; 561220137Strasz efx_rc_t rc; 562220137Strasz 563220137Strasz if (handlep == NULL) { 564220137Strasz rc = EINVAL; 565221362Strasz goto fail1; 566221362Strasz } 567220137Strasz 568220137Strasz (void) memset(payload, 0, sizeof (payload)); 569220137Strasz req.emr_cmd = MC_CMD_ALLOC_PIOBUF; 570220137Strasz req.emr_in_buf = payload; 571220137Strasz req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; 572220137Strasz req.emr_out_buf = payload; 573220137Strasz req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; 574220137Strasz 575220137Strasz efx_mcdi_execute_quiet(enp, &req); 576220137Strasz 577220137Strasz if (req.emr_rc != 0) { 578220137Strasz rc = req.emr_rc; 579220137Strasz goto fail2; 580220137Strasz } 581220137Strasz 582220137Strasz if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { 583220137Strasz rc = EMSGSIZE; 584220137Strasz goto fail3; 585220137Strasz } 586220137Strasz 587220137Strasz *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); 588220137Strasz 589220137Strasz return (0); 590220137Strasz 591220137Straszfail3: 592220137Strasz EFSYS_PROBE(fail3); 593258622Savgfail2: 594220137Strasz EFSYS_PROBE(fail2); 595220137Straszfail1: 596220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 597220137Strasz 598220137Strasz return (rc); 599220137Strasz} 600220137Strasz 601220137Straszstatic __checkReturn efx_rc_t 602220137Straszefx_mcdi_free_piobuf( 603220137Strasz __in efx_nic_t *enp, 604220137Strasz __in efx_piobuf_handle_t handle) 605220137Strasz{ 606220137Strasz efx_mcdi_req_t req; 607220137Strasz uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, 608220137Strasz MC_CMD_FREE_PIOBUF_OUT_LEN)]; 609242139Strasz efx_rc_t rc; 610242139Strasz 611220137Strasz (void) memset(payload, 0, sizeof (payload)); 612220137Strasz req.emr_cmd = MC_CMD_FREE_PIOBUF; 613220137Strasz req.emr_in_buf = payload; 614220137Strasz req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; 615220137Strasz req.emr_out_buf = payload; 616220137Strasz req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; 617220137Strasz 618220137Strasz MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); 619220137Strasz 620220137Strasz efx_mcdi_execute_quiet(enp, &req); 621220137Strasz 622242139Strasz if (req.emr_rc != 0) { 623242139Strasz rc = req.emr_rc; 624242139Strasz goto fail1; 625242139Strasz } 626242139Strasz 627242139Strasz return (0); 628242139Strasz 629242139Straszfail1: 630242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 631242139Strasz 632242139Strasz return (rc); 633242139Strasz} 634242139Strasz 635242139Straszstatic __checkReturn efx_rc_t 636242139Straszefx_mcdi_link_piobuf( 637242139Strasz __in efx_nic_t *enp, 638220137Strasz __in uint32_t vi_index, 639242139Strasz __in efx_piobuf_handle_t handle) 640243088Strasz{ 641220137Strasz efx_mcdi_req_t req; 642220137Strasz uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, 643220137Strasz MC_CMD_LINK_PIOBUF_OUT_LEN)]; 644242139Strasz efx_rc_t rc; 645242139Strasz 646223844Strasz (void) memset(payload, 0, sizeof (payload)); 647258622Savg req.emr_cmd = MC_CMD_LINK_PIOBUF; 648220137Strasz req.emr_in_buf = payload; 649220137Strasz req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; 650220137Strasz req.emr_out_buf = payload; 651220137Strasz req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; 652220137Strasz 653242139Strasz MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); 654242139Strasz MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); 655242139Strasz 656242139Strasz efx_mcdi_execute(enp, &req); 657242139Strasz 658220137Strasz if (req.emr_rc != 0) { 659220137Strasz rc = req.emr_rc; 660220137Strasz goto fail1; 661220137Strasz } 662220137Strasz 663220137Strasz return (0); 664220137Strasz 665220137Straszfail1: 666220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 667220137Strasz 668220137Strasz return (rc); 669220137Strasz} 670220137Strasz 671220137Straszstatic __checkReturn efx_rc_t 672220137Straszefx_mcdi_unlink_piobuf( 673220137Strasz __in efx_nic_t *enp, 674220137Strasz __in uint32_t vi_index) 675220137Strasz{ 676220137Strasz efx_mcdi_req_t req; 677220137Strasz uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, 678220137Strasz MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; 679220137Strasz efx_rc_t rc; 680242139Strasz 681242139Strasz (void) memset(payload, 0, sizeof (payload)); 682220137Strasz req.emr_cmd = MC_CMD_UNLINK_PIOBUF; 683242139Strasz req.emr_in_buf = payload; 684242139Strasz req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; 685220137Strasz req.emr_out_buf = payload; 686220137Strasz req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; 687220137Strasz 688220137Strasz MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); 689220137Strasz 690220137Strasz efx_mcdi_execute(enp, &req); 691220137Strasz 692220137Strasz if (req.emr_rc != 0) { 693242139Strasz rc = req.emr_rc; 694242139Strasz goto fail1; 695242139Strasz } 696242139Strasz 697242139Strasz return (0); 698242139Strasz 699242139Straszfail1: 700242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 701242139Strasz 702242139Strasz return (rc); 703242139Strasz} 704242139Strasz 705242139Straszstatic void 706242139Straszhunt_nic_alloc_piobufs( 707242139Strasz __in efx_nic_t *enp, 708242139Strasz __in uint32_t max_piobuf_count) 709242139Strasz{ 710242139Strasz efx_piobuf_handle_t *handlep; 711242139Strasz unsigned int i; 712242139Strasz efx_rc_t rc; 713242139Strasz 714242139Strasz EFSYS_ASSERT3U(max_piobuf_count, <=, 715242139Strasz EFX_ARRAY_SIZE(enp->en_u.hunt.enu_piobuf_handle)); 716242139Strasz 717242139Strasz enp->en_u.hunt.enu_piobuf_count = 0; 718242139Strasz 719242139Strasz for (i = 0; i < max_piobuf_count; i++) { 720220137Strasz handlep = &enp->en_u.hunt.enu_piobuf_handle[i]; 721242139Strasz 722220137Strasz if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) 723220137Strasz goto fail1; 724220137Strasz 725220137Strasz enp->en_u.hunt.enu_pio_alloc_map[i] = 0; 726220137Strasz enp->en_u.hunt.enu_piobuf_count++; 727220137Strasz } 728220137Strasz 729220137Strasz return; 730220137Strasz 731220137Straszfail1: 732220137Strasz for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 733220137Strasz handlep = &enp->en_u.hunt.enu_piobuf_handle[i]; 734220137Strasz 735220137Strasz efx_mcdi_free_piobuf(enp, *handlep); 736220137Strasz *handlep = EFX_PIOBUF_HANDLE_INVALID; 737220137Strasz } 738220137Strasz enp->en_u.hunt.enu_piobuf_count = 0; 739220137Strasz} 740220137Strasz 741220137Strasz 742220137Straszstatic void 743220137Straszhunt_nic_free_piobufs( 744220137Strasz __in efx_nic_t *enp) 745220137Strasz{ 746220137Strasz efx_piobuf_handle_t *handlep; 747220137Strasz unsigned int i; 748220137Strasz 749220137Strasz for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 750220137Strasz handlep = &enp->en_u.hunt.enu_piobuf_handle[i]; 751220137Strasz 752220137Strasz efx_mcdi_free_piobuf(enp, *handlep); 753220137Strasz *handlep = EFX_PIOBUF_HANDLE_INVALID; 754220137Strasz } 755220137Strasz enp->en_u.hunt.enu_piobuf_count = 0; 756220137Strasz} 757220137Strasz 758220137Strasz/* Sub-allocate a block from a piobuf */ 759220137Strasz __checkReturn efx_rc_t 760242139Straszhunt_nic_pio_alloc( 761242139Strasz __inout efx_nic_t *enp, 762242139Strasz __out uint32_t *bufnump, 763242139Strasz __out efx_piobuf_handle_t *handlep, 764242139Strasz __out uint32_t *blknump, 765242139Strasz __out uint32_t *offsetp, 766242139Strasz __out size_t *sizep) 767242139Strasz{ 768242139Strasz efx_drv_cfg_t *edcp = &enp->en_drv_cfg; 769242139Strasz uint32_t blk_per_buf; 770242139Strasz uint32_t buf, blk; 771242139Strasz efx_rc_t rc; 772242139Strasz 773242139Strasz EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 774242139Strasz EFSYS_ASSERT(bufnump); 775242139Strasz EFSYS_ASSERT(handlep); 776220137Strasz EFSYS_ASSERT(blknump); 777220137Strasz EFSYS_ASSERT(offsetp); 778220137Strasz EFSYS_ASSERT(sizep); 779220137Strasz 780220137Strasz if ((edcp->edc_pio_alloc_size == 0) || 781220137Strasz (enp->en_u.hunt.enu_piobuf_count == 0)) { 782220137Strasz rc = ENOMEM; 783220137Strasz goto fail1; 784220137Strasz } 785220137Strasz blk_per_buf = HUNT_PIOBUF_SIZE / edcp->edc_pio_alloc_size; 786220137Strasz 787220137Strasz for (buf = 0; buf < enp->en_u.hunt.enu_piobuf_count; buf++) { 788242139Strasz uint32_t *map = &enp->en_u.hunt.enu_pio_alloc_map[buf]; 789243088Strasz 790220137Strasz if (~(*map) == 0) 791220137Strasz continue; 792220137Strasz 793243088Strasz EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); 794243088Strasz for (blk = 0; blk < blk_per_buf; blk++) { 795220137Strasz if ((*map & (1u << blk)) == 0) { 796220137Strasz *map |= (1u << blk); 797220137Strasz goto done; 798220137Strasz } 799220137Strasz } 800220137Strasz } 801220137Strasz rc = ENOMEM; 802220137Strasz goto fail2; 803220137Strasz 804220137Straszdone: 805220137Strasz *handlep = enp->en_u.hunt.enu_piobuf_handle[buf]; 806220137Strasz *bufnump = buf; 807258622Savg *blknump = blk; 808220137Strasz *sizep = edcp->edc_pio_alloc_size; 809220137Strasz *offsetp = blk * (*sizep); 810220137Strasz 811242139Strasz return (0); 812243088Strasz 813220137Straszfail2: 814220137Strasz EFSYS_PROBE(fail2); 815220137Straszfail1: 816220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 817220137Strasz 818221362Strasz return (rc); 819221362Strasz} 820220137Strasz 821220137Strasz/* Free a piobuf sub-allocated block */ 822220137Strasz __checkReturn efx_rc_t 823220137Straszhunt_nic_pio_free( 824220137Strasz __inout efx_nic_t *enp, 825220137Strasz __in uint32_t bufnum, 826220137Strasz __in uint32_t blknum) 827220137Strasz{ 828220137Strasz uint32_t *map; 829220137Strasz efx_rc_t rc; 830220137Strasz 831220137Strasz if ((bufnum >= enp->en_u.hunt.enu_piobuf_count) || 832220137Strasz (blknum >= (8 * sizeof (*map)))) { 833220137Strasz rc = EINVAL; 834220137Strasz goto fail1; 835220137Strasz } 836220137Strasz 837220137Strasz map = &enp->en_u.hunt.enu_pio_alloc_map[bufnum]; 838220137Strasz if ((*map & (1u << blknum)) == 0) { 839220137Strasz rc = ENOENT; 840220137Strasz goto fail2; 841220137Strasz } 842220137Strasz *map &= ~(1u << blknum); 843220137Strasz 844220137Strasz return (0); 845220137Strasz 846220137Straszfail2: 847220137Strasz EFSYS_PROBE(fail2); 848220137Straszfail1: 849220137Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 850220137Strasz 851220137Strasz return (rc); 852225981Strasz} 853225981Strasz 854225981Strasz __checkReturn efx_rc_t 855225981Straszhunt_nic_pio_link( 856225981Strasz __inout efx_nic_t *enp, 857225981Strasz __in uint32_t vi_index, 858242139Strasz __in efx_piobuf_handle_t handle) 859242139Strasz{ 860242139Strasz return (efx_mcdi_link_piobuf(enp, vi_index, handle)); 861242139Strasz} 862220137Strasz 863220137Strasz __checkReturn efx_rc_t 864220137Straszhunt_nic_pio_unlink( 865220137Strasz __inout efx_nic_t *enp, 866220137Strasz __in uint32_t vi_index) 867223844Strasz{ 868220137Strasz return (efx_mcdi_unlink_piobuf(enp, vi_index)); 869220137Strasz} 870220137Strasz 871220137Straszstatic __checkReturn efx_rc_t 872225938Straszhunt_get_datapath_caps( 873220137Strasz __in efx_nic_t *enp) 874220137Strasz{ 875220137Strasz efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 876225944Strasz efx_dword_t datapath_capabilities; 877225944Strasz efx_rc_t rc; 878225944Strasz 879220137Strasz if ((rc = efx_mcdi_get_capabilities(enp, &datapath_capabilities)) != 0) 880220137Strasz goto fail1; 881220137Strasz 882220137Strasz /* 883220137Strasz * Huntington RXDP firmware inserts a 0 or 14 byte prefix. 884235787Strasz * We only support the 14 byte prefix here. 885235787Strasz */ 886235787Strasz if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 887220137Strasz GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14) != 1) { 888220137Strasz rc = ENOTSUP; 889220137Strasz goto fail2; 890225940Strasz } 891225940Strasz encp->enc_rx_prefix_size = 14; 892225940Strasz 893225940Strasz /* Check if the firmware supports TSO */ 894220137Strasz if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 895225940Strasz GET_CAPABILITIES_OUT_TX_TSO) == 1) 896225940Strasz encp->enc_fw_assisted_tso_enabled = B_TRUE; 897225940Strasz else 898225940Strasz encp->enc_fw_assisted_tso_enabled = B_FALSE; 899225940Strasz 900225940Strasz /* Check if the firmware has vadapter/vport/vswitch support */ 901225940Strasz if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 902225940Strasz GET_CAPABILITIES_OUT_EVB) == 1) 903225940Strasz encp->enc_datapath_cap_evb = B_TRUE; 904225940Strasz else 905225940Strasz encp->enc_datapath_cap_evb = B_FALSE; 906225940Strasz 907225940Strasz /* Check if the firmware supports VLAN insertion */ 908225940Strasz if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 909220137Strasz GET_CAPABILITIES_OUT_TX_VLAN_INSERTION) == 1) 910220137Strasz encp->enc_hw_tx_insert_vlan_enabled = B_TRUE; 911225364Strasz else 912220137Strasz encp->enc_hw_tx_insert_vlan_enabled = B_FALSE; 913242139Strasz 914242139Strasz /* Check if the firmware supports RX event batching */ 915220137Strasz if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 916220137Strasz GET_CAPABILITIES_OUT_RX_BATCHING) == 1) { 917220137Strasz encp->enc_rx_batching_enabled = B_TRUE; 918220137Strasz encp->enc_rx_batch_max = 16; 919220137Strasz } else { 920220137Strasz encp->enc_rx_batching_enabled = B_FALSE; 921220137Strasz } 922220137Strasz 923220137Strasz /* Check if the firmware supports disabling scatter on RXQs */ 924220137Strasz if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 925220137Strasz GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER) == 1) { 926220137Strasz encp->enc_rx_disable_scatter_supported = B_TRUE; 927242139Strasz } else { 928242139Strasz encp->enc_rx_disable_scatter_supported = B_FALSE; 929242957Strasz } 930242957Strasz 931242957Strasz return (0); 932242957Strasz 933242957Straszfail2: 934242957Strasz EFSYS_PROBE(fail2); 935242139Straszfail1: 936242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 937225364Strasz 938225364Strasz return (rc); 939242139Strasz} 940220137Strasz 941225364Strasz/* 942225364Strasz * The external port mapping is a one-based numbering of the external 943225364Strasz * connectors on the board. It does not distinguish off-board separated 944225364Strasz * outputs such as multi-headed cables. 945225364Strasz * The number of ports that map to each external port connector 946225364Strasz * on the board is determined by the chip family and the port modes to 947225364Strasz * which the NIC can be configured. The mapping table lists modes with 948225364Strasz * port numbering requirements in increasing order. 949225364Strasz */ 950220137Straszstatic struct { 951220137Strasz efx_family_t family; 952220137Strasz uint32_t modes_mask; 953220137Strasz uint32_t stride; 954220137Strasz} __hunt_external_port_mappings[] = { 955220137Strasz /* Supported modes requiring 1 output per port */ 956220137Strasz { 957220137Strasz EFX_FAMILY_HUNTINGTON, 958220137Strasz (1 << TLV_PORT_MODE_10G) | 959220137Strasz (1 << TLV_PORT_MODE_10G_10G) | 960220137Strasz (1 << TLV_PORT_MODE_10G_10G_10G_10G), 961220137Strasz 1 962220137Strasz }, 963220137Strasz /* Supported modes requiring 2 outputs per port */ 964220137Strasz { 965220137Strasz EFX_FAMILY_HUNTINGTON, 966220137Strasz (1 << TLV_PORT_MODE_40G) | 967220137Strasz (1 << TLV_PORT_MODE_40G_40G) | 968220137Strasz (1 << TLV_PORT_MODE_40G_10G_10G) | 969220137Strasz (1 << TLV_PORT_MODE_10G_10G_40G), 970220137Strasz 2 971220137Strasz } 972220137Strasz /* 973220137Strasz * NOTE: Medford modes will require 4 outputs per port: 974220137Strasz * TLV_PORT_MODE_10G_10G_10G_10G_Q 975220137Strasz * TLV_PORT_MODE_10G_10G_10G_10G_Q2 976220137Strasz * The Q2 mode routes outputs to external port 2. Support for this 977220137Strasz * will require a new field specifying the number to add after 978220137Strasz * scaling by stride. This is fixed at 1 currently. 979220137Strasz */ 980220137Strasz}; 981220137Strasz 982220137Straszstatic __checkReturn efx_rc_t 983220137Straszhunt_external_port_mapping( 984220137Strasz __in efx_nic_t *enp, 985220137Strasz __in uint32_t port, 986220137Strasz __out uint8_t *external_portp) 987220137Strasz{ 988220137Strasz efx_rc_t rc; 989220137Strasz int i; 990221362Strasz uint32_t port_modes; 991221362Strasz uint32_t matches; 992220137Strasz uint32_t stride = 1; /* default 1-1 mapping */ 993221362Strasz 994221362Strasz if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { 995220137Strasz /* No port mode information available - use default mapping */ 996220137Strasz goto out; 997220137Strasz } 998220137Strasz 999220137Strasz /* 1000220137Strasz * Infer the internal port -> external port mapping from 1001220137Strasz * the possible port modes for this NIC. 1002220137Strasz */ 1003232598Strasz for (i = 0; i < EFX_ARRAY_SIZE(__hunt_external_port_mappings); ++i) { 1004232598Strasz if (__hunt_external_port_mappings[i].family != 1005232598Strasz enp->en_family) 1006232598Strasz continue; 1007232598Strasz matches = (__hunt_external_port_mappings[i].modes_mask & 1008232598Strasz port_modes); 1009232598Strasz if (matches != 0) { 1010232598Strasz stride = __hunt_external_port_mappings[i].stride; 1011232598Strasz port_modes &= ~matches; 1012232598Strasz } 1013232598Strasz } 1014232598Strasz 1015220137Strasz if (port_modes != 0) { 1016242139Strasz /* Some advertised modes are not supported */ 1017242139Strasz rc = ENOTSUP; 1018242139Strasz goto fail1; 1019242139Strasz } 1020242139Strasz 1021242139Straszout: 1022242139Strasz /* 1023242139Strasz * Scale as required by last matched mode and then convert to 1024242139Strasz * one-based numbering 1025242139Strasz */ 1026242139Strasz *external_portp = (uint8_t)(port / stride) + 1; 1027242139Strasz return (0); 1028242139Strasz 1029242139Straszfail1: 1030242139Strasz EFSYS_PROBE1(fail1, efx_rc_t, rc); 1031242139Strasz 1032242139Strasz return (rc); 1033242139Strasz} 1034242139Strasz 1035248298Straszstatic __checkReturn efx_rc_t 1036242139Straszhunt_board_cfg( 1037242139Strasz __in efx_nic_t *enp) 1038242139Strasz{ 1039242139Strasz efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1040242139Strasz efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1041242139Strasz uint8_t mac_addr[6]; 1042242139Strasz uint32_t board_type = 0; 1043242139Strasz hunt_link_state_t hls; 1044242139Strasz efx_port_t *epp = &(enp->en_port); 1045242139Strasz uint32_t port; 1046242139Strasz uint32_t pf; 1047242139Strasz uint32_t vf; 1048242139Strasz uint32_t mask; 1049242139Strasz uint32_t flags; 1050242139Strasz uint32_t sysclk; 1051242139Strasz uint32_t base, nvec; 1052242139Strasz efx_rc_t rc; 1053242139Strasz 1054242139Strasz if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0) 1055242139Strasz goto fail1; 1056242139Strasz 1057242139Strasz /* 1058242139Strasz * NOTE: The MCDI protocol numbers ports from zero. 1059242139Strasz * The common code MCDI interface numbers ports from one. 1060242139Strasz */ 1061248298Strasz emip->emi_port = port + 1; 1062242139Strasz 1063242139Strasz if ((rc = hunt_external_port_mapping(enp, port, 1064242139Strasz &encp->enc_external_port)) != 0) 1065242139Strasz goto fail2; 1066242139Strasz 1067242139Strasz /* 1068242139Strasz * Get PCIe function number from firmware (used for 1069242139Strasz * per-function privilege and dynamic config info). 1070242139Strasz * - PCIe PF: pf = PF number, vf = 0xffff. 1071242139Strasz * - PCIe VF: pf = parent PF, vf = VF number. 1072242139Strasz */ 1073242139Strasz if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0) 1074242139Strasz goto fail3; 1075242139Strasz 1076242139Strasz encp->enc_pf = pf; 1077242139Strasz encp->enc_vf = vf; 1078242139Strasz 1079242139Strasz /* MAC address for this function */ 1080242139Strasz if (EFX_PCI_FUNCTION_IS_PF(encp)) { 1081242139Strasz rc = efx_mcdi_get_mac_address_pf(enp, mac_addr); 1082242139Strasz if ((rc == 0) && (mac_addr[0] & 0x02)) { 1083242139Strasz /* 1084242139Strasz * If the static config does not include a global MAC 1085242139Strasz * address pool then the board may return a locally 1086242139Strasz * administered MAC address (this should only happen on 1087242139Strasz * incorrectly programmed boards). 1088242139Strasz */ 1089242139Strasz rc = EINVAL; 1090242139Strasz } 1091242139Strasz } else { 1092242139Strasz rc = efx_mcdi_get_mac_address_vf(enp, mac_addr); 1093242139Strasz } 1094242139Strasz if (rc != 0) 1095242139Strasz goto fail4; 1096242139Strasz 1097242139Strasz EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr); 1098242139Strasz 1099242139Strasz /* Board configuration */ 1100242139Strasz rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL); 1101242139Strasz if (rc != 0) { 1102242139Strasz /* Unprivileged functions may not be able to read board cfg */ 1103242139Strasz if (rc == EACCES) 1104220137Strasz board_type = 0; 1105220137Strasz else 1106220137Strasz goto fail5; 1107220137Strasz } 1108220137Strasz 1109220137Strasz encp->enc_board_type = board_type; 1110242139Strasz encp->enc_clk_mult = 1; /* not used for Huntington */ 1111220137Strasz 1112220137Strasz /* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */ 1113242139Strasz if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0) 1114242139Strasz goto fail6; 1115220137Strasz 1116220137Strasz /* Obtain the default PHY advertised capabilities */ 1117242139Strasz if ((rc = hunt_phy_get_link(enp, &hls)) != 0) 1118242139Strasz goto fail7; 1119242139Strasz epp->ep_default_adv_cap_mask = hls.hls_adv_cap_mask; 1120242139Strasz epp->ep_adv_cap_mask = hls.hls_adv_cap_mask; 1121242139Strasz 1122242139Strasz /* 1123220137Strasz * Enable firmware workarounds for hardware errata. 1124242139Strasz * Expected responses are: 1125242139Strasz * - 0 (zero): 1126242139Strasz * Success: workaround enabled or disabled as requested. 1127220137Strasz * - MC_CMD_ERR_ENOSYS (reported as ENOTSUP): 1128242139Strasz * Firmware does not support the MC_CMD_WORKAROUND request. 1129220137Strasz * (assume that the workaround is not supported). 1130220137Strasz * - MC_CMD_ERR_ENOENT (reported as ENOENT): 1131220137Strasz * Firmware does not support the requested workaround. 1132220137Strasz * - MC_CMD_ERR_EPERM (reported as EACCES): 1133232782Strasz * Unprivileged function cannot enable/disable workarounds. 1134220137Strasz * 1135220137Strasz * See efx_mcdi_request_errcode() for MCDI error translations. 1136220137Strasz */ 1137220137Strasz 1138220137Strasz /* 1139220137Strasz * If the bug35388 workaround is enabled, then use an indirect access 1140220137Strasz * method to avoid unsafe EVQ writes. 1141220137Strasz */ 1142220137Strasz rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE, 1143220137Strasz NULL); 1144220137Strasz if ((rc == 0) || (rc == EACCES)) 1145242957Strasz encp->enc_bug35388_workaround = B_TRUE; 1146242957Strasz else if ((rc == ENOTSUP) || (rc == ENOENT)) 1147242957Strasz encp->enc_bug35388_workaround = B_FALSE; 1148242957Strasz else 1149242957Strasz goto fail8; 1150242957Strasz 1151242139Strasz /* 1152220137Strasz * If the bug41750 workaround is enabled, then do not test interrupts, 1153242139Strasz * as the test will fail (seen with Greenport controllers). 1154220137Strasz */ 1155220137Strasz rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE, 1156233126Sjh NULL); 1157233126Sjh if (rc == 0) { 1158220137Strasz encp->enc_bug41750_workaround = B_TRUE; 1159220137Strasz } else if (rc == EACCES) { 1160220137Strasz /* Assume a controller with 40G ports needs the workaround. */ 1161242139Strasz if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX) 1162242139Strasz encp->enc_bug41750_workaround = B_TRUE; 1163242139Strasz else 1164242139Strasz encp->enc_bug41750_workaround = B_FALSE; 1165242139Strasz } else if ((rc == ENOTSUP) || (rc == ENOENT)) { 1166242139Strasz encp->enc_bug41750_workaround = B_FALSE; 1167242139Strasz } else { 1168242139Strasz goto fail9; 1169242139Strasz } 1170242139Strasz if (EFX_PCI_FUNCTION_IS_VF(encp)) { 1171242139Strasz /* Interrupt testing does not work for VFs. See bug50084. */ 1172242139Strasz encp->enc_bug41750_workaround = B_TRUE; 1173242139Strasz } 1174242139Strasz 1175242139Strasz /* 1176242139Strasz * If the bug26807 workaround is enabled, then firmware has enabled 1177242139Strasz * support for chained multicast filters. Firmware will reset (FLR) 1178242139Strasz * functions which have filters in the hardware filter table when the 1179242139Strasz * workaround is enabled/disabled. 1180242139Strasz * 1181220137Strasz * We must recheck if the workaround is enabled after inserting the 1182220137Strasz * first hardware filter, in case it has been changed since this check. 1183220137Strasz */ 1184220137Strasz rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807, 1185220137Strasz B_TRUE, &flags); 1186220137Strasz if (rc == 0) { 1187220137Strasz encp->enc_bug26807_workaround = B_TRUE; 1188220137Strasz if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) { 1189220137Strasz /* 1190220137Strasz * Other functions had installed filters before the 1191220137Strasz * workaround was enabled, and they have been reset 1192220137Strasz * by firmware. 1193220137Strasz */ 1194220137Strasz EFSYS_PROBE(bug26807_workaround_flr_done); 1195220137Strasz /* FIXME: bump MC warm boot count ? */ 1196220137Strasz } 1197220137Strasz } else if (rc == EACCES) { 1198220137Strasz /* 1199220137Strasz * Unprivileged functions cannot enable the workaround in older 1200220137Strasz * firmware. 1201220137Strasz */ 1202221362Strasz encp->enc_bug26807_workaround = B_FALSE; 1203220137Strasz } else if ((rc == ENOTSUP) || (rc == ENOENT)) { 1204220137Strasz encp->enc_bug26807_workaround = B_FALSE; 1205220137Strasz } else { 1206220137Strasz goto fail10; 1207220137Strasz } 1208220137Strasz 1209220137Strasz /* Get sysclk frequency (in MHz). */ 1210220137Strasz if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0) 1211220137Strasz goto fail11; 1212220137Strasz 1213220137Strasz /* 1214220137Strasz * The timer quantum is 1536 sysclk cycles, documented for the 1215220137Strasz * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units. 1216220137Strasz */ 1217220137Strasz encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */ 1218220137Strasz if (encp->enc_bug35388_workaround) { 1219220137Strasz encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << 1220220137Strasz ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000; 1221220137Strasz } else { 1222220137Strasz encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << 1223220137Strasz FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000; 1224220137Strasz } 1225220137Strasz 1226220137Strasz /* Check capabilities of running datapath firmware */ 1227220137Strasz if ((rc = hunt_get_datapath_caps(enp)) != 0) 1228220137Strasz goto fail12; 1229220137Strasz 1230220137Strasz /* Alignment for receive packet DMA buffers */ 1231220137Strasz encp->enc_rx_buf_align_start = 1; 1232220137Strasz encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */ 1233220137Strasz 1234220137Strasz /* Alignment for WPTR updates */ 1235220372Strasz encp->enc_rx_push_align = HUNTINGTON_RX_WPTR_ALIGN; 1236220372Strasz 1237220372Strasz /* 1238220372Strasz * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use 1239220372Strasz * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available 1240220137Strasz * resources (allocated to this PCIe function), which is zero until 1241220137Strasz * after we have allocated VIs. 1242220137Strasz */ 1243220137Strasz encp->enc_evq_limit = 1024; 1244220137Strasz encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET; 1245220137Strasz encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET; 1246220137Strasz 1247220137Strasz encp->enc_buftbl_limit = 0xFFFFFFFF; 1248220137Strasz 1249220137Strasz encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS; 1250220137Strasz encp->enc_piobuf_size = HUNT_PIOBUF_SIZE; 1251220137Strasz 1252220137Strasz /* 1253220137Strasz * Get the current privilege mask. Note that this may be modified 1254220137Strasz * dynamically, so this value is informational only. DO NOT use 1255220137Strasz * the privilege mask to check for sufficient privileges, as that 1256220372Strasz * can result in time-of-check/time-of-use bugs. 1257220372Strasz */ 1258220372Strasz if ((rc = efx_mcdi_privilege_mask(enp, pf, vf, &mask)) != 0) { 1259220372Strasz if (rc != ENOTSUP) 1260220372Strasz goto fail13; 1261220372Strasz 1262220372Strasz /* Fallback for old firmware without privilege mask support */ 1263220137Strasz if (EFX_PCI_FUNCTION_IS_PF(encp)) { 1264220137Strasz /* Assume PF has admin privilege */ 1265220137Strasz mask = HUNT_LEGACY_PF_PRIVILEGE_MASK; 1266220137Strasz } else { 1267220137Strasz /* VF is always unprivileged by default */ 1268220137Strasz mask = HUNT_LEGACY_VF_PRIVILEGE_MASK; 1269220137Strasz } 1270220137Strasz } 1271220137Strasz 1272220137Strasz encp->enc_privilege_mask = mask; 1273220137Strasz 1274220137Strasz /* Get interrupt vector limits */ 1275220137Strasz if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) { 1276220137Strasz if (EFX_PCI_FUNCTION_IS_PF(encp)) 1277220137Strasz goto fail14; 1278220137Strasz 1279220137Strasz /* Ignore error (cannot query vector limits from a VF). */ 1280220137Strasz base = 0; 1281225940Strasz nvec = 1024; 1282225940Strasz } 1283225940Strasz encp->enc_intr_vec_base = base; 1284225940Strasz encp->enc_intr_limit = nvec; 1285225940Strasz 1286220137Strasz /* 1287220137Strasz * Maximum number of bytes into the frame the TCP header can start for 1288220137Strasz * firmware assisted TSO to work. 1289220137Strasz */ 1290220137Strasz encp->enc_tx_tso_tcp_header_offset_limit = 208; 1291 1292 return (0); 1293 1294fail14: 1295 EFSYS_PROBE(fail14); 1296fail13: 1297 EFSYS_PROBE(fail13); 1298fail12: 1299 EFSYS_PROBE(fail12); 1300fail11: 1301 EFSYS_PROBE(fail11); 1302fail10: 1303 EFSYS_PROBE(fail10); 1304fail9: 1305 EFSYS_PROBE(fail9); 1306fail8: 1307 EFSYS_PROBE(fail8); 1308fail7: 1309 EFSYS_PROBE(fail7); 1310fail6: 1311 EFSYS_PROBE(fail6); 1312fail5: 1313 EFSYS_PROBE(fail5); 1314fail4: 1315 EFSYS_PROBE(fail4); 1316fail3: 1317 EFSYS_PROBE(fail3); 1318fail2: 1319 EFSYS_PROBE(fail2); 1320fail1: 1321 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1322 1323 return (rc); 1324} 1325 1326 1327 __checkReturn efx_rc_t 1328hunt_nic_probe( 1329 __in efx_nic_t *enp) 1330{ 1331 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1332 efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); 1333 efx_rc_t rc; 1334 1335 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1336 1337 /* Read and clear any assertion state */ 1338 if ((rc = efx_mcdi_read_assertion(enp)) != 0) 1339 goto fail1; 1340 1341 /* Exit the assertion handler */ 1342 if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) 1343 if (rc != EACCES) 1344 goto fail2; 1345 1346 if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) 1347 goto fail3; 1348 1349 if ((rc = hunt_board_cfg(enp)) != 0) 1350 if (rc != EACCES) 1351 goto fail4; 1352 1353 /* 1354 * Set default driver config limits (based on board config). 1355 * 1356 * FIXME: For now allocate a fixed number of VIs which is likely to be 1357 * sufficient and small enough to allow multiple functions on the same 1358 * port. 1359 */ 1360 edcp->edc_min_vi_count = edcp->edc_max_vi_count = 1361 MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); 1362 1363 /* The client driver must configure and enable PIO buffer support */ 1364 edcp->edc_max_piobuf_count = 0; 1365 edcp->edc_pio_alloc_size = 0; 1366 1367#if EFSYS_OPT_MAC_STATS 1368 /* Wipe the MAC statistics */ 1369 if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) 1370 goto fail5; 1371#endif 1372 1373#if EFSYS_OPT_LOOPBACK 1374 if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) 1375 goto fail6; 1376#endif 1377 1378#if EFSYS_OPT_MON_STATS 1379 if ((rc = mcdi_mon_cfg_build(enp)) != 0) { 1380 /* Unprivileged functions do not have access to sensors */ 1381 if (rc != EACCES) 1382 goto fail7; 1383 } 1384#endif 1385 1386 encp->enc_features = enp->en_features; 1387 1388 return (0); 1389 1390#if EFSYS_OPT_MON_STATS 1391fail7: 1392 EFSYS_PROBE(fail7); 1393#endif 1394#if EFSYS_OPT_LOOPBACK 1395fail6: 1396 EFSYS_PROBE(fail6); 1397#endif 1398#if EFSYS_OPT_MAC_STATS 1399fail5: 1400 EFSYS_PROBE(fail5); 1401#endif 1402fail4: 1403 EFSYS_PROBE(fail4); 1404fail3: 1405 EFSYS_PROBE(fail3); 1406fail2: 1407 EFSYS_PROBE(fail2); 1408fail1: 1409 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1410 1411 return (rc); 1412} 1413 1414 __checkReturn efx_rc_t 1415hunt_nic_set_drv_limits( 1416 __inout efx_nic_t *enp, 1417 __in efx_drv_limits_t *edlp) 1418{ 1419 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1420 efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); 1421 uint32_t min_evq_count, max_evq_count; 1422 uint32_t min_rxq_count, max_rxq_count; 1423 uint32_t min_txq_count, max_txq_count; 1424 efx_rc_t rc; 1425 1426 if (edlp == NULL) { 1427 rc = EINVAL; 1428 goto fail1; 1429 } 1430 1431 /* Get minimum required and maximum usable VI limits */ 1432 min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); 1433 min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); 1434 min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); 1435 1436 edcp->edc_min_vi_count = 1437 MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); 1438 1439 max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); 1440 max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); 1441 max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); 1442 1443 edcp->edc_max_vi_count = 1444 MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); 1445 1446 /* 1447 * Check limits for sub-allocated piobuf blocks. 1448 * PIO is optional, so don't fail if the limits are incorrect. 1449 */ 1450 if ((encp->enc_piobuf_size == 0) || 1451 (encp->enc_piobuf_limit == 0) || 1452 (edlp->edl_min_pio_alloc_size == 0) || 1453 (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { 1454 /* Disable PIO */ 1455 edcp->edc_max_piobuf_count = 0; 1456 edcp->edc_pio_alloc_size = 0; 1457 } else { 1458 uint32_t blk_size, blk_count, blks_per_piobuf; 1459 1460 blk_size = 1461 MAX(edlp->edl_min_pio_alloc_size, HUNT_MIN_PIO_ALLOC_SIZE); 1462 1463 blks_per_piobuf = encp->enc_piobuf_size / blk_size; 1464 EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); 1465 1466 blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); 1467 1468 /* A zero max pio alloc count means unlimited */ 1469 if ((edlp->edl_max_pio_alloc_count > 0) && 1470 (edlp->edl_max_pio_alloc_count < blk_count)) { 1471 blk_count = edlp->edl_max_pio_alloc_count; 1472 } 1473 1474 edcp->edc_pio_alloc_size = blk_size; 1475 edcp->edc_max_piobuf_count = 1476 (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; 1477 } 1478 1479 return (0); 1480 1481fail1: 1482 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1483 1484 return (rc); 1485} 1486 1487 1488 __checkReturn efx_rc_t 1489hunt_nic_reset( 1490 __in efx_nic_t *enp) 1491{ 1492 efx_mcdi_req_t req; 1493 uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, 1494 MC_CMD_ENTITY_RESET_OUT_LEN)]; 1495 efx_rc_t rc; 1496 1497 /* hunt_nic_reset() is called to recover from BADASSERT failures. */ 1498 if ((rc = efx_mcdi_read_assertion(enp)) != 0) 1499 goto fail1; 1500 if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) 1501 goto fail2; 1502 1503 (void) memset(payload, 0, sizeof (payload)); 1504 req.emr_cmd = MC_CMD_ENTITY_RESET; 1505 req.emr_in_buf = payload; 1506 req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; 1507 req.emr_out_buf = payload; 1508 req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; 1509 1510 MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, 1511 ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); 1512 1513 efx_mcdi_execute(enp, &req); 1514 1515 if (req.emr_rc != 0) { 1516 rc = req.emr_rc; 1517 goto fail3; 1518 } 1519 1520 /* Clear RX/TX DMA queue errors */ 1521 enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); 1522 1523 return (0); 1524 1525fail3: 1526 EFSYS_PROBE(fail3); 1527fail2: 1528 EFSYS_PROBE(fail2); 1529fail1: 1530 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1531 1532 return (rc); 1533} 1534 1535 __checkReturn efx_rc_t 1536hunt_nic_init( 1537 __in efx_nic_t *enp) 1538{ 1539 efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); 1540 uint32_t min_vi_count, max_vi_count; 1541 uint32_t vi_count, vi_base; 1542 uint32_t i; 1543 uint32_t retry; 1544 uint32_t delay_us; 1545 efx_rc_t rc; 1546 1547 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1548 1549 /* Enable reporting of some events (e.g. link change) */ 1550 if ((rc = efx_mcdi_log_ctrl(enp)) != 0) 1551 goto fail1; 1552 1553 /* Allocate (optional) on-chip PIO buffers */ 1554 hunt_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); 1555 1556 /* 1557 * For best performance, PIO writes should use a write-combined 1558 * (WC) memory mapping. Using a separate WC mapping for the PIO 1559 * aperture of each VI would be a burden to drivers (and not 1560 * possible if the host page size is >4Kbyte). 1561 * 1562 * To avoid this we use a single uncached (UC) mapping for VI 1563 * register access, and a single WC mapping for extra VIs used 1564 * for PIO writes. 1565 * 1566 * Each piobuf must be linked to a VI in the WC mapping, and to 1567 * each VI that is using a sub-allocated block from the piobuf. 1568 */ 1569 min_vi_count = edcp->edc_min_vi_count; 1570 max_vi_count = edcp->edc_max_vi_count + enp->en_u.hunt.enu_piobuf_count; 1571 1572 /* Ensure that the previously attached driver's VIs are freed */ 1573 if ((rc = efx_mcdi_free_vis(enp)) != 0) 1574 goto fail2; 1575 1576 /* 1577 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this 1578 * fails then retrying the request for fewer VI resources may succeed. 1579 */ 1580 vi_count = 0; 1581 if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, 1582 &vi_base, &vi_count)) != 0) 1583 goto fail3; 1584 1585 EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); 1586 1587 if (vi_count < min_vi_count) { 1588 rc = ENOMEM; 1589 goto fail4; 1590 } 1591 1592 enp->en_u.hunt.enu_vi_base = vi_base; 1593 enp->en_u.hunt.enu_vi_count = vi_count; 1594 1595 if (vi_count < min_vi_count + enp->en_u.hunt.enu_piobuf_count) { 1596 /* Not enough extra VIs to map piobufs */ 1597 hunt_nic_free_piobufs(enp); 1598 } 1599 1600 enp->en_u.hunt.enu_pio_write_vi_base = 1601 vi_count - enp->en_u.hunt.enu_piobuf_count; 1602 1603 /* Save UC memory mapping details */ 1604 enp->en_u.hunt.enu_uc_mem_map_offset = 0; 1605 if (enp->en_u.hunt.enu_piobuf_count > 0) { 1606 enp->en_u.hunt.enu_uc_mem_map_size = 1607 (ER_DZ_TX_PIOBUF_STEP * 1608 enp->en_u.hunt.enu_pio_write_vi_base); 1609 } else { 1610 enp->en_u.hunt.enu_uc_mem_map_size = 1611 (ER_DZ_TX_PIOBUF_STEP * 1612 enp->en_u.hunt.enu_vi_count); 1613 } 1614 1615 /* Save WC memory mapping details */ 1616 enp->en_u.hunt.enu_wc_mem_map_offset = 1617 enp->en_u.hunt.enu_uc_mem_map_offset + 1618 enp->en_u.hunt.enu_uc_mem_map_size; 1619 1620 enp->en_u.hunt.enu_wc_mem_map_size = 1621 (ER_DZ_TX_PIOBUF_STEP * 1622 enp->en_u.hunt.enu_piobuf_count); 1623 1624 /* Link piobufs to extra VIs in WC mapping */ 1625 if (enp->en_u.hunt.enu_piobuf_count > 0) { 1626 for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 1627 rc = efx_mcdi_link_piobuf(enp, 1628 enp->en_u.hunt.enu_pio_write_vi_base + i, 1629 enp->en_u.hunt.enu_piobuf_handle[i]); 1630 if (rc != 0) 1631 break; 1632 } 1633 } 1634 1635 /* 1636 * Allocate a vAdaptor attached to our upstream vPort/pPort. 1637 * 1638 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF 1639 * driver has yet to bring up the EVB port. See bug 56147. In this case, 1640 * retry the request several times after waiting a while. The wait time 1641 * between retries starts small (10ms) and exponentially increases. 1642 * Total wait time is a little over two seconds. Retry logic in the 1643 * client driver may mean this whole loop is repeated if it continues to 1644 * fail. 1645 */ 1646 retry = 0; 1647 delay_us = 10000; 1648 while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { 1649 if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || 1650 (rc != ENOENT)) { 1651 /* 1652 * Do not retry alloc for PF, or for other errors on 1653 * a VF. 1654 */ 1655 goto fail5; 1656 } 1657 1658 /* VF startup before PF is ready. Retry allocation. */ 1659 if (retry > 5) { 1660 /* Too many attempts */ 1661 rc = EINVAL; 1662 goto fail6; 1663 } 1664 EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); 1665 EFSYS_SLEEP(delay_us); 1666 retry++; 1667 if (delay_us < 500000) 1668 delay_us <<= 2; 1669 } 1670 1671 enp->en_vport_id = EVB_PORT_ID_ASSIGNED; 1672 1673 return (0); 1674 1675fail6: 1676 EFSYS_PROBE(fail6); 1677fail5: 1678 EFSYS_PROBE(fail5); 1679fail4: 1680 EFSYS_PROBE(fail4); 1681fail3: 1682 EFSYS_PROBE(fail3); 1683fail2: 1684 EFSYS_PROBE(fail2); 1685 1686 hunt_nic_free_piobufs(enp); 1687 1688fail1: 1689 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1690 1691 return (rc); 1692} 1693 1694 __checkReturn efx_rc_t 1695hunt_nic_get_vi_pool( 1696 __in efx_nic_t *enp, 1697 __out uint32_t *vi_countp) 1698{ 1699 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1700 1701 /* 1702 * Report VIs that the client driver can use. 1703 * Do not include VIs used for PIO buffer writes. 1704 */ 1705 *vi_countp = enp->en_u.hunt.enu_pio_write_vi_base; 1706 1707 return (0); 1708} 1709 1710 __checkReturn efx_rc_t 1711hunt_nic_get_bar_region( 1712 __in efx_nic_t *enp, 1713 __in efx_nic_region_t region, 1714 __out uint32_t *offsetp, 1715 __out size_t *sizep) 1716{ 1717 efx_rc_t rc; 1718 1719 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1720 1721 /* 1722 * TODO: Specify host memory mapping alignment and granularity 1723 * in efx_drv_limits_t so that they can be taken into account 1724 * when allocating extra VIs for PIO writes. 1725 */ 1726 switch (region) { 1727 case EFX_REGION_VI: 1728 /* UC mapped memory BAR region for VI registers */ 1729 *offsetp = enp->en_u.hunt.enu_uc_mem_map_offset; 1730 *sizep = enp->en_u.hunt.enu_uc_mem_map_size; 1731 break; 1732 1733 case EFX_REGION_PIO_WRITE_VI: 1734 /* WC mapped memory BAR region for piobuf writes */ 1735 *offsetp = enp->en_u.hunt.enu_wc_mem_map_offset; 1736 *sizep = enp->en_u.hunt.enu_wc_mem_map_size; 1737 break; 1738 1739 default: 1740 rc = EINVAL; 1741 goto fail1; 1742 } 1743 1744 return (0); 1745 1746fail1: 1747 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1748 1749 return (rc); 1750} 1751 1752 void 1753hunt_nic_fini( 1754 __in efx_nic_t *enp) 1755{ 1756 uint32_t i; 1757 efx_rc_t rc; 1758 1759 (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); 1760 enp->en_vport_id = 0; 1761 1762 /* Unlink piobufs from extra VIs in WC mapping */ 1763 if (enp->en_u.hunt.enu_piobuf_count > 0) { 1764 for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 1765 rc = efx_mcdi_unlink_piobuf(enp, 1766 enp->en_u.hunt.enu_pio_write_vi_base + i); 1767 if (rc != 0) 1768 break; 1769 } 1770 } 1771 1772 hunt_nic_free_piobufs(enp); 1773 1774 (void) efx_mcdi_free_vis(enp); 1775 enp->en_u.hunt.enu_vi_count = 0; 1776} 1777 1778 void 1779hunt_nic_unprobe( 1780 __in efx_nic_t *enp) 1781{ 1782#if EFSYS_OPT_MON_STATS 1783 mcdi_mon_cfg_free(enp); 1784#endif /* EFSYS_OPT_MON_STATS */ 1785 (void) efx_mcdi_drv_attach(enp, B_FALSE); 1786} 1787 1788#if EFSYS_OPT_DIAG 1789 1790 __checkReturn efx_rc_t 1791hunt_nic_register_test( 1792 __in efx_nic_t *enp) 1793{ 1794 efx_rc_t rc; 1795 1796 /* FIXME */ 1797 _NOTE(ARGUNUSED(enp)) 1798 if (B_FALSE) { 1799 rc = ENOTSUP; 1800 goto fail1; 1801 } 1802 /* FIXME */ 1803 1804 return (0); 1805 1806fail1: 1807 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1808 1809 return (rc); 1810} 1811 1812#endif /* EFSYS_OPT_DIAG */ 1813 1814 1815 1816#endif /* EFSYS_OPT_HUNTINGTON */ 1817