ef10_nic.c revision 291393
1193323Sed/*- 2193323Sed * Copyright (c) 2012-2015 Solarflare Communications Inc. 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions are met: 7193323Sed * 8193323Sed * 1. Redistributions of source code must retain the above copyright notice, 9193323Sed * this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright notice, 11193323Sed * this list of conditions and the following disclaimer in the documentation 12193323Sed * and/or other materials provided with the distribution. 13193323Sed * 14210299Sed * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15193323Sed * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16218893Sdim * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17193323Sed * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18226633Sdim * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19193323Sed * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20193323Sed * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21193323Sed * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22193323Sed * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23193323Sed * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24198090Srdivacky * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25193323Sed * 26193323Sed * The views and conclusions contained in the software and documentation are 27193323Sed * those of the authors and should not be interpreted as representing official 28193323Sed * policies, either expressed or implied, of the FreeBSD Project. 29193323Sed */ 30193323Sed 31193323Sed#include <sys/cdefs.h> 32207631Srdivacky__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_nic.c 291393 2015-11-27 16:03:51Z arybchik $"); 33193323Sed 34193323Sed#include "efsys.h" 35198090Srdivacky#include "efx.h" 36198090Srdivacky#include "efx_impl.h" 37198090Srdivacky#include "mcdi_mon.h" 38193323Sed 39193323Sed#if EFSYS_OPT_HUNTINGTON 40212904Sdim 41212904Sdim#include "ef10_tlv_layout.h" 42212904Sdim 43212904Sdimstatic __checkReturn int 44212904Sdimefx_mcdi_get_port_assignment( 45218893Sdim __in efx_nic_t *enp, 46218893Sdim __out uint32_t *portp) 47218893Sdim{ 48221345Sdim efx_mcdi_req_t req; 49218893Sdim uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, 50193323Sed MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; 51193323Sed int rc; 52193323Sed 53193323Sed EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 54193323Sed 55218893Sdim (void) memset(payload, 0, sizeof (payload)); 56218893Sdim req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; 57218893Sdim req.emr_in_buf = payload; 58218893Sdim req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; 59218893Sdim req.emr_out_buf = payload; 60218893Sdim req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN; 61193323Sed 62195098Sed efx_mcdi_execute(enp, &req); 63218893Sdim 64193323Sed if (req.emr_rc != 0) { 65193323Sed rc = req.emr_rc; 66193323Sed goto fail1; 67193323Sed } 68193323Sed 69193323Sed if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) { 70198090Srdivacky rc = EMSGSIZE; 71198090Srdivacky goto fail2; 72198090Srdivacky } 73218893Sdim 74218893Sdim *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); 75193323Sed 76193323Sed return (0); 77193323Sed 78193323Sedfail2: 79194612Sed EFSYS_PROBE(fail2); 80194612Sedfail1: 81198090Srdivacky EFSYS_PROBE1(fail1, int, rc); 82198090Srdivacky 83194612Sed return (rc); 84194612Sed} 85194612Sed 86194612Sedstatic __checkReturn int 87202375Srdivackyefx_mcdi_get_port_modes( 88203954Srdivacky __in efx_nic_t *enp, 89218893Sdim __out uint32_t *modesp) 90218893Sdim{ 91218893Sdim efx_mcdi_req_t req; 92218893Sdim uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, 93226633Sdim MC_CMD_GET_PORT_MODES_OUT_LEN)]; 94221345Sdim int rc; 95221345Sdim 96226633Sdim EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 97226633Sdim 98226633Sdim (void) memset(payload, 0, sizeof (payload)); 99221345Sdim req.emr_cmd = MC_CMD_GET_PORT_MODES; 100221345Sdim req.emr_in_buf = payload; 101226633Sdim req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; 102221345Sdim req.emr_out_buf = payload; 103226633Sdim req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; 104226633Sdim 105226633Sdim efx_mcdi_execute(enp, &req); 106226633Sdim 107226633Sdim if (req.emr_rc != 0) { 108221345Sdim rc = req.emr_rc; 109218893Sdim goto fail1; 110218893Sdim } 111218893Sdim 112218893Sdim /* Accept pre-Medford size (8 bytes - no CurrentMode field) */ 113218893Sdim if (req.emr_out_length_used < 114218893Sdim MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { 115218893Sdim rc = EMSGSIZE; 116218893Sdim goto fail2; 117218893Sdim } 118218893Sdim 119218893Sdim *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); 120218893Sdim 121218893Sdim return (0); 122218893Sdim 123218893Sdimfail2: 124218893Sdim EFSYS_PROBE(fail2); 125218893Sdimfail1: 126218893Sdim EFSYS_PROBE1(fail1, int, rc); 127218893Sdim 128218893Sdim return (rc); 129218893Sdim} 130218893Sdim 131218893Sdim 132226633Sdimstatic __checkReturn int 133193323Sedefx_mcdi_vadaptor_alloc( 134226633Sdim __in efx_nic_t *enp, 135226633Sdim __in uint32_t port_id) 136226633Sdim{ 137226633Sdim efx_mcdi_req_t req; 138226633Sdim uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, 139218893Sdim MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; 140193323Sed int rc; 141202375Srdivacky 142193323Sed EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); 143218893Sdim 144193323Sed (void) memset(payload, 0, sizeof (payload)); 145218893Sdim req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; 146219077Sdim req.emr_in_buf = payload; 147193323Sed req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; 148218893Sdim req.emr_out_buf = payload; 149193323Sed req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; 150218893Sdim 151218893Sdim MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); 152218893Sdim 153218893Sdim efx_mcdi_execute(enp, &req); 154218893Sdim 155218893Sdim if (req.emr_rc != 0) { 156218893Sdim rc = req.emr_rc; 157218893Sdim goto fail1; 158218893Sdim } 159218893Sdim 160218893Sdim return (0); 161218893Sdim 162218893Sdimfail1: 163218893Sdim EFSYS_PROBE1(fail1, int, rc); 164218893Sdim 165218893Sdim return (rc); 166193323Sed} 167218893Sdim 168218893Sdimstatic __checkReturn int 169195098Sedefx_mcdi_vadaptor_free( 170218893Sdim __in efx_nic_t *enp, 171218893Sdim __in uint32_t port_id) 172195340Sed{ 173202375Srdivacky efx_mcdi_req_t req; 174195340Sed uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, 175218893Sdim MC_CMD_VADAPTOR_FREE_OUT_LEN)]; 176195340Sed int rc; 177195340Sed 178218893Sdim (void) memset(payload, 0, sizeof (payload)); 179218893Sdim req.emr_cmd = MC_CMD_VADAPTOR_FREE; 180218893Sdim req.emr_in_buf = payload; 181218893Sdim req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; 182218893Sdim req.emr_out_buf = payload; 183218893Sdim req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; 184218893Sdim 185218893Sdim MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); 186218893Sdim 187218893Sdim efx_mcdi_execute(enp, &req); 188218893Sdim 189218893Sdim if (req.emr_rc != 0) { 190218893Sdim rc = req.emr_rc; 191218893Sdim goto fail1; 192218893Sdim } 193218893Sdim 194193323Sed return (0); 195193323Sed 196193323Sedfail1: 197193323Sed EFSYS_PROBE1(fail1, int, rc); 198195340Sed 199195340Sed return (rc); 200202375Srdivacky} 201202375Srdivacky 202195340Sedstatic __checkReturn int 203206083Srdivackyefx_mcdi_get_mac_address_pf( 204206083Srdivacky __in efx_nic_t *enp, 205198090Srdivacky __out_ecount_opt(6) uint8_t mac_addrp[6]) 206206083Srdivacky{ 207218893Sdim efx_mcdi_req_t req; 208239462Sdim uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, 209239462Sdim MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; 210198090Srdivacky int rc; 211198113Srdivacky 212206083Srdivacky EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 213198113Srdivacky 214206083Srdivacky (void) memset(payload, 0, sizeof (payload)); 215218893Sdim req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; 216239462Sdim req.emr_in_buf = payload; 217239462Sdim req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; 218198113Srdivacky req.emr_out_buf = payload; 219198090Srdivacky req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN; 220198090Srdivacky 221218893Sdim efx_mcdi_execute(enp, &req); 222218893Sdim 223218893Sdim if (req.emr_rc != 0) { 224239462Sdim rc = req.emr_rc; 225198090Srdivacky goto fail1; 226218893Sdim } 227218893Sdim 228218893Sdim if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) { 229218893Sdim rc = EMSGSIZE; 230239462Sdim goto fail2; 231218893Sdim } 232210299Sed 233210299Sed if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { 234210299Sed rc = ENOENT; 235210299Sed goto fail3; 236210299Sed } 237198090Srdivacky 238207618Srdivacky if (mac_addrp != NULL) { 239198090Srdivacky uint8_t *addrp; 240199989Srdivacky 241202375Srdivacky addrp = MCDI_OUT2(req, uint8_t, 242202375Srdivacky GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); 243199989Srdivacky 244199989Srdivacky EFX_MAC_ADDR_COPY(mac_addrp, addrp); 245202375Srdivacky } 246199989Srdivacky 247199989Srdivacky return (0); 248218893Sdim 249199989Srdivackyfail3: 250199989Srdivacky EFSYS_PROBE(fail3); 251218893Sdimfail2: 252199989Srdivacky EFSYS_PROBE(fail2); 253199989Srdivackyfail1: 254199989Srdivacky EFSYS_PROBE1(fail1, int, rc); 255226633Sdim 256226633Sdim return (rc); 257226633Sdim} 258208599Srdivacky 259208599Srdivackystatic __checkReturn int 260226633Sdimefx_mcdi_get_mac_address_vf( 261226633Sdim __in efx_nic_t *enp, 262195340Sed __out_ecount_opt(6) uint8_t mac_addrp[6]) 263195340Sed{ 264195340Sed efx_mcdi_req_t req; 265195340Sed uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, 266195340Sed MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; 267198090Srdivacky int rc; 268210299Sed 269210299Sed EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 270198090Srdivacky 271208599Srdivacky (void) memset(payload, 0, sizeof (payload)); 272208599Srdivacky req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; 273210299Sed req.emr_in_buf = payload; 274210299Sed req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; 275208599Srdivacky req.emr_out_buf = payload; 276208599Srdivacky req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; 277208599Srdivacky 278218893Sdim MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, 279218893Sdim EVB_PORT_ID_ASSIGNED); 280193323Sed 281193323Sed efx_mcdi_execute(enp, &req); 282193323Sed 283198090Srdivacky if (req.emr_rc != 0) { 284198090Srdivacky rc = req.emr_rc; 285198090Srdivacky goto fail1; 286198090Srdivacky } 287198090Srdivacky 288198090Srdivacky if (req.emr_out_length_used < 289198090Srdivacky MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { 290198090Srdivacky rc = EMSGSIZE; 291198090Srdivacky goto fail2; 292198090Srdivacky } 293198090Srdivacky 294198090Srdivacky if (MCDI_OUT_DWORD(req, 295198090Srdivacky VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { 296198090Srdivacky rc = ENOENT; 297198090Srdivacky goto fail3; 298198090Srdivacky } 299198090Srdivacky 300198090Srdivacky if (mac_addrp != NULL) { 301198090Srdivacky uint8_t *addrp; 302198090Srdivacky 303198090Srdivacky addrp = MCDI_OUT2(req, uint8_t, 304198090Srdivacky VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); 305198090Srdivacky 306198090Srdivacky EFX_MAC_ADDR_COPY(mac_addrp, addrp); 307218893Sdim } 308243830Sdim 309218893Sdim return (0); 310218893Sdim 311226633Sdimfail3: 312218893Sdim EFSYS_PROBE(fail3); 313218893Sdimfail2: 314226633Sdim EFSYS_PROBE(fail2); 315198090Srdivackyfail1: 316218893Sdim EFSYS_PROBE1(fail1, int, rc); 317218893Sdim 318218893Sdim return (rc); 319218893Sdim} 320218893Sdim 321218893Sdimstatic __checkReturn int 322218893Sdimefx_mcdi_get_clock( 323218893Sdim __in efx_nic_t *enp, 324218893Sdim __out uint32_t *sys_freqp) 325218893Sdim{ 326218893Sdim efx_mcdi_req_t req; 327218893Sdim uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, 328218893Sdim MC_CMD_GET_CLOCK_OUT_LEN)]; 329218893Sdim int rc; 330218893Sdim 331218893Sdim EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 332218893Sdim 333218893Sdim (void) memset(payload, 0, sizeof (payload)); 334218893Sdim req.emr_cmd = MC_CMD_GET_CLOCK; 335218893Sdim req.emr_in_buf = payload; 336218893Sdim req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; 337218893Sdim req.emr_out_buf = payload; 338218893Sdim req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN; 339243830Sdim 340243830Sdim efx_mcdi_execute(enp, &req); 341218893Sdim 342218893Sdim if (req.emr_rc != 0) { 343218893Sdim rc = req.emr_rc; 344218893Sdim goto fail1; 345218893Sdim } 346218893Sdim 347218893Sdim if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) { 348218893Sdim rc = EMSGSIZE; 349218893Sdim goto fail2; 350224145Sdim } 351224145Sdim 352218893Sdim *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); 353224145Sdim if (*sys_freqp == 0) { 354218893Sdim rc = EINVAL; 355218893Sdim goto fail3; 356218893Sdim } 357218893Sdim 358218893Sdim return (0); 359218893Sdim 360218893Sdimfail3: 361218893Sdim EFSYS_PROBE(fail3); 362218893Sdimfail2: 363218893Sdim EFSYS_PROBE(fail2); 364218893Sdimfail1: 365218893Sdim EFSYS_PROBE1(fail1, int, rc); 366218893Sdim 367218893Sdim return (rc); 368218893Sdim} 369218893Sdim 370218893Sdimstatic __checkReturn int 371218893Sdimefx_mcdi_get_vector_cfg( 372218893Sdim __in efx_nic_t *enp, 373218893Sdim __out_opt uint32_t *vec_basep, 374218893Sdim __out_opt uint32_t *pf_nvecp, 375218893Sdim __out_opt uint32_t *vf_nvecp) 376218893Sdim{ 377218893Sdim efx_mcdi_req_t req; 378243830Sdim uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, 379218893Sdim MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; 380218893Sdim int rc; 381218893Sdim 382218893Sdim (void) memset(payload, 0, sizeof (payload)); 383243830Sdim req.emr_cmd = MC_CMD_GET_VECTOR_CFG; 384243830Sdim req.emr_in_buf = payload; 385218893Sdim req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; 386218893Sdim req.emr_out_buf = payload; 387226633Sdim req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN; 388195340Sed 389226633Sdim efx_mcdi_execute(enp, &req); 390226633Sdim 391226633Sdim if (req.emr_rc != 0) { 392226633Sdim rc = req.emr_rc; 393226633Sdim goto fail1; 394226633Sdim } 395226633Sdim 396226633Sdim if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) { 397226633Sdim rc = EMSGSIZE; 398226633Sdim goto fail2; 399226633Sdim } 400226633Sdim 401226633Sdim if (vec_basep != NULL) 402226633Sdim *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); 403226633Sdim if (pf_nvecp != NULL) 404226633Sdim *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); 405226633Sdim if (vf_nvecp != NULL) 406226633Sdim *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); 407226633Sdim 408226633Sdim return (0); 409226633Sdim 410226633Sdimfail2: 411226633Sdim EFSYS_PROBE(fail2); 412195340Sedfail1: 413221345Sdim EFSYS_PROBE1(fail1, int, rc); 414221345Sdim 415212904Sdim return (rc); 416212904Sdim} 417212904Sdim 418226633Sdimstatic __checkReturn int 419195340Sedefx_mcdi_get_capabilities( 420195340Sed __in efx_nic_t *enp, 421195340Sed __out efx_dword_t *flagsp) 422195340Sed{ 423198090Srdivacky efx_mcdi_req_t req; 424195340Sed uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, 425195340Sed MC_CMD_GET_CAPABILITIES_OUT_LEN)]; 426226633Sdim int rc; 427226633Sdim 428226633Sdim (void) memset(payload, 0, sizeof (payload)); 429226633Sdim req.emr_cmd = MC_CMD_GET_CAPABILITIES; 430226633Sdim req.emr_in_buf = payload; 431226633Sdim req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; 432195340Sed req.emr_out_buf = payload; 433195340Sed req.emr_out_length = MC_CMD_GET_CAPABILITIES_OUT_LEN; 434195340Sed 435195340Sed efx_mcdi_execute(enp, &req); 436195340Sed 437226633Sdim if (req.emr_rc != 0) { 438218893Sdim rc = req.emr_rc; 439218893Sdim goto fail1; 440218893Sdim } 441218893Sdim 442218893Sdim if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { 443218893Sdim rc = EMSGSIZE; 444218893Sdim goto fail2; 445218893Sdim } 446218893Sdim 447218893Sdim *flagsp = *MCDI_OUT2(req, efx_dword_t, GET_CAPABILITIES_OUT_FLAGS1); 448218893Sdim 449218893Sdim return (0); 450218893Sdim 451218893Sdimfail2: 452218893Sdim EFSYS_PROBE(fail2); 453221345Sdimfail1: 454218893Sdim EFSYS_PROBE1(fail1, int, rc); 455218893Sdim 456218893Sdim return (rc); 457218893Sdim} 458218893Sdim 459218893Sdim 460218893Sdimstatic __checkReturn int 461218893Sdimefx_mcdi_alloc_vis( 462218893Sdim __in efx_nic_t *enp, 463218893Sdim __in uint32_t min_vi_count, 464218893Sdim __in uint32_t max_vi_count, 465218893Sdim __out_opt uint32_t *vi_basep, 466218893Sdim __out uint32_t *vi_countp) 467218893Sdim 468218893Sdim{ 469218893Sdim efx_mcdi_req_t req; 470218893Sdim uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, 471218893Sdim MC_CMD_ALLOC_VIS_OUT_LEN)]; 472218893Sdim int rc; 473218893Sdim 474218893Sdim if (vi_countp == NULL) { 475218893Sdim rc = EINVAL; 476218893Sdim goto fail1; 477218893Sdim } 478218893Sdim 479218893Sdim (void) memset(payload, 0, sizeof (payload)); 480218893Sdim req.emr_cmd = MC_CMD_ALLOC_VIS; 481218893Sdim req.emr_in_buf = payload; 482218893Sdim req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; 483218893Sdim req.emr_out_buf = payload; 484218893Sdim req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; 485218893Sdim 486218893Sdim MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); 487218893Sdim MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); 488218893Sdim 489193323Sed efx_mcdi_execute(enp, &req); 490218893Sdim 491243830Sdim if (req.emr_rc != 0) { 492193323Sed rc = req.emr_rc; 493193323Sed goto fail2; 494193323Sed } 495193323Sed 496193323Sed if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { 497193323Sed rc = EMSGSIZE; 498193323Sed goto fail3; 499193323Sed } 500193323Sed 501193323Sed if (vi_basep != NULL) 502193323Sed *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); 503193323Sed 504193323Sed if (vi_countp != NULL) 505193323Sed *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); 506193323Sed 507193323Sed return (0); 508193323Sed 509193323Sedfail3: 510193323Sed EFSYS_PROBE(fail3); 511193323Sedfail2: 512193323Sed EFSYS_PROBE(fail2); 513193323Sedfail1: 514218893Sdim EFSYS_PROBE1(fail1, int, rc); 515218893Sdim 516218893Sdim return (rc); 517218893Sdim} 518218893Sdim 519218893Sdim 520218893Sdimstatic __checkReturn int 521218893Sdimefx_mcdi_free_vis( 522218893Sdim __in efx_nic_t *enp) 523218893Sdim{ 524218893Sdim efx_mcdi_req_t req; 525218893Sdim int rc; 526218893Sdim 527218893Sdim EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); 528218893Sdim EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); 529226633Sdim 530226633Sdim req.emr_cmd = MC_CMD_FREE_VIS; 531218893Sdim req.emr_in_buf = NULL; 532218893Sdim req.emr_in_length = 0; 533218893Sdim req.emr_out_buf = NULL; 534218893Sdim req.emr_out_length = 0; 535218893Sdim 536218893Sdim efx_mcdi_execute_quiet(enp, &req); 537218893Sdim 538218893Sdim /* Ignore ELREADY (no allocated VIs, so nothing to free) */ 539218893Sdim if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { 540218893Sdim rc = req.emr_rc; 541218893Sdim goto fail1; 542218893Sdim } 543218893Sdim 544218893Sdim return (0); 545218893Sdim 546218893Sdimfail1: 547218893Sdim EFSYS_PROBE1(fail1, int, rc); 548218893Sdim 549218893Sdim return (rc); 550218893Sdim} 551218893Sdim 552218893Sdim 553218893Sdimstatic __checkReturn int 554218893Sdimefx_mcdi_alloc_piobuf( 555243830Sdim __in efx_nic_t *enp, 556243830Sdim __out efx_piobuf_handle_t *handlep) 557226633Sdim{ 558218893Sdim efx_mcdi_req_t req; 559218893Sdim uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, 560218893Sdim MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; 561218893Sdim int rc; 562218893Sdim 563218893Sdim if (handlep == NULL) { 564226633Sdim rc = EINVAL; 565218893Sdim goto fail1; 566218893Sdim } 567218893Sdim 568218893Sdim (void) memset(payload, 0, sizeof (payload)); 569218893Sdim req.emr_cmd = MC_CMD_ALLOC_PIOBUF; 570218893Sdim req.emr_in_buf = payload; 571218893Sdim req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; 572218893Sdim req.emr_out_buf = payload; 573218893Sdim req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; 574218893Sdim 575218893Sdim efx_mcdi_execute_quiet(enp, &req); 576218893Sdim 577218893Sdim if (req.emr_rc != 0) { 578218893Sdim rc = req.emr_rc; 579218893Sdim goto fail2; 580218893Sdim } 581218893Sdim 582218893Sdim if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { 583218893Sdim rc = EMSGSIZE; 584218893Sdim goto fail3; 585218893Sdim } 586218893Sdim 587218893Sdim *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); 588218893Sdim 589218893Sdim return (0); 590243830Sdim 591218893Sdimfail3: 592218893Sdim EFSYS_PROBE(fail3); 593218893Sdimfail2: 594218893Sdim EFSYS_PROBE(fail2); 595218893Sdimfail1: 596218893Sdim EFSYS_PROBE1(fail1, int, rc); 597218893Sdim 598218893Sdim return (rc); 599218893Sdim} 600218893Sdim 601218893Sdimstatic __checkReturn int 602218893Sdimefx_mcdi_free_piobuf( 603218893Sdim __in efx_nic_t *enp, 604218893Sdim __in efx_piobuf_handle_t handle) 605218893Sdim{ 606218893Sdim efx_mcdi_req_t req; 607218893Sdim uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, 608218893Sdim MC_CMD_FREE_PIOBUF_OUT_LEN)]; 609218893Sdim int rc; 610218893Sdim 611218893Sdim (void) memset(payload, 0, sizeof (payload)); 612218893Sdim req.emr_cmd = MC_CMD_FREE_PIOBUF; 613218893Sdim req.emr_in_buf = payload; 614218893Sdim req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; 615218893Sdim req.emr_out_buf = payload; 616193323Sed req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; 617193323Sed 618193323Sed MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); 619193323Sed 620199989Srdivacky efx_mcdi_execute_quiet(enp, &req); 621199989Srdivacky 622199989Srdivacky if (req.emr_rc != 0) { 623193323Sed rc = req.emr_rc; 624193323Sed goto fail1; 625193323Sed } 626193323Sed 627193323Sed return (0); 628193323Sed 629218893Sdimfail1: 630193323Sed EFSYS_PROBE1(fail1, int, rc); 631198090Srdivacky 632193323Sed return (rc); 633218893Sdim} 634218893Sdim 635218893Sdimstatic __checkReturn int 636218893Sdimefx_mcdi_link_piobuf( 637218893Sdim __in efx_nic_t *enp, 638218893Sdim __in uint32_t vi_index, 639218893Sdim __in efx_piobuf_handle_t handle) 640218893Sdim{ 641218893Sdim efx_mcdi_req_t req; 642218893Sdim uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, 643193323Sed MC_CMD_LINK_PIOBUF_OUT_LEN)]; 644218893Sdim int rc; 645218893Sdim 646218893Sdim (void) memset(payload, 0, sizeof (payload)); 647218893Sdim req.emr_cmd = MC_CMD_LINK_PIOBUF; 648193323Sed req.emr_in_buf = payload; 649218893Sdim req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; 650218893Sdim req.emr_out_buf = payload; 651218893Sdim req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; 652218893Sdim 653193323Sed MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); 654218893Sdim MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); 655198090Srdivacky 656243830Sdim efx_mcdi_execute(enp, &req); 657218893Sdim 658218893Sdim if (req.emr_rc != 0) { 659218893Sdim rc = req.emr_rc; 660218893Sdim goto fail1; 661218893Sdim } 662218893Sdim 663218893Sdim return (0); 664218893Sdim 665218893Sdimfail1: 666198892Srdivacky EFSYS_PROBE1(fail1, int, rc); 667218893Sdim 668226633Sdim return (rc); 669226633Sdim} 670193323Sed 671198090Srdivackystatic __checkReturn int 672193323Sedefx_mcdi_unlink_piobuf( 673193323Sed __in efx_nic_t *enp, 674198090Srdivacky __in uint32_t vi_index) 675193323Sed{ 676193323Sed efx_mcdi_req_t req; 677193323Sed uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, 678193323Sed MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; 679193323Sed int rc; 680193323Sed 681218893Sdim (void) memset(payload, 0, sizeof (payload)); 682218893Sdim req.emr_cmd = MC_CMD_UNLINK_PIOBUF; 683218893Sdim req.emr_in_buf = payload; 684218893Sdim req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; 685218893Sdim req.emr_out_buf = payload; 686218893Sdim req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; 687193323Sed 688193323Sed MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); 689193323Sed 690193323Sed efx_mcdi_execute(enp, &req); 691198090Srdivacky 692193323Sed if (req.emr_rc != 0) { 693218893Sdim rc = req.emr_rc; 694243830Sdim goto fail1; 695243830Sdim } 696226633Sdim 697193323Sed return (0); 698193323Sed 699193323Sedfail1: 700193323Sed EFSYS_PROBE1(fail1, int, rc); 701193323Sed 702193323Sed return (rc); 703226633Sdim} 704218893Sdim 705218893Sdimstatic void 706218893Sdimhunt_nic_alloc_piobufs( 707218893Sdim __in efx_nic_t *enp, 708218893Sdim __in uint32_t max_piobuf_count) 709218893Sdim{ 710193323Sed efx_piobuf_handle_t *handlep; 711193323Sed unsigned int i; 712193323Sed int rc; 713193323Sed 714193323Sed EFSYS_ASSERT3U(max_piobuf_count, <=, 715198090Srdivacky EFX_ARRAY_SIZE(enp->en_u.hunt.enu_piobuf_handle)); 716193323Sed 717193323Sed enp->en_u.hunt.enu_piobuf_count = 0; 718218893Sdim 719193323Sed for (i = 0; i < max_piobuf_count; i++) { 720193323Sed handlep = &enp->en_u.hunt.enu_piobuf_handle[i]; 721226633Sdim 722193323Sed if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) 723202375Srdivacky goto fail1; 724193323Sed 725193323Sed enp->en_u.hunt.enu_pio_alloc_map[i] = 0; 726193323Sed enp->en_u.hunt.enu_piobuf_count++; 727193323Sed } 728193323Sed 729218893Sdim return; 730226633Sdim 731226633Sdimfail1: 732193323Sed for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 733193323Sed handlep = &enp->en_u.hunt.enu_piobuf_handle[i]; 734226633Sdim 735193323Sed efx_mcdi_free_piobuf(enp, *handlep); 736193323Sed *handlep = EFX_PIOBUF_HANDLE_INVALID; 737193323Sed } 738193323Sed enp->en_u.hunt.enu_piobuf_count = 0; 739193323Sed} 740193323Sed 741218893Sdim 742218893Sdimstatic void 743218893Sdimhunt_nic_free_piobufs( 744218893Sdim __in efx_nic_t *enp) 745218893Sdim{ 746218893Sdim efx_piobuf_handle_t *handlep; 747193323Sed unsigned int i; 748193323Sed 749193323Sed for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 750193323Sed handlep = &enp->en_u.hunt.enu_piobuf_handle[i]; 751193323Sed 752193323Sed efx_mcdi_free_piobuf(enp, *handlep); 753193323Sed *handlep = EFX_PIOBUF_HANDLE_INVALID; 754193323Sed } 755193323Sed enp->en_u.hunt.enu_piobuf_count = 0; 756193323Sed} 757226633Sdim 758226633Sdim/* Sub-allocate a block from a piobuf */ 759226633Sdim __checkReturn int 760226633Sdimhunt_nic_pio_alloc( 761226633Sdim __inout efx_nic_t *enp, 762226633Sdim __out uint32_t *bufnump, 763226633Sdim __out efx_piobuf_handle_t *handlep, 764226633Sdim __out uint32_t *blknump, 765226633Sdim __out uint32_t *offsetp, 766226633Sdim __out size_t *sizep) 767226633Sdim{ 768226633Sdim efx_drv_cfg_t *edcp = &enp->en_drv_cfg; 769226633Sdim uint32_t blk_per_buf; 770226633Sdim uint32_t buf, blk; 771226633Sdim int rc; 772193323Sed 773226633Sdim EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 774226633Sdim EFSYS_ASSERT(bufnump); 775226633Sdim EFSYS_ASSERT(handlep); 776226633Sdim EFSYS_ASSERT(blknump); 777226633Sdim EFSYS_ASSERT(offsetp); 778226633Sdim EFSYS_ASSERT(sizep); 779226633Sdim 780226633Sdim if ((edcp->edc_pio_alloc_size == 0) || 781226633Sdim (enp->en_u.hunt.enu_piobuf_count == 0)) { 782226633Sdim rc = ENOMEM; 783226633Sdim goto fail1; 784226633Sdim } 785226633Sdim blk_per_buf = HUNT_PIOBUF_SIZE / edcp->edc_pio_alloc_size; 786226633Sdim 787226633Sdim for (buf = 0; buf < enp->en_u.hunt.enu_piobuf_count; buf++) { 788226633Sdim uint32_t *map = &enp->en_u.hunt.enu_pio_alloc_map[buf]; 789226633Sdim 790226633Sdim if (~(*map) == 0) 791226633Sdim continue; 792226633Sdim 793226633Sdim EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); 794226633Sdim for (blk = 0; blk < blk_per_buf; blk++) { 795226633Sdim if ((*map & (1u << blk)) == 0) { 796226633Sdim *map |= (1u << blk); 797226633Sdim goto done; 798226633Sdim } 799226633Sdim } 800226633Sdim } 801226633Sdim rc = ENOMEM; 802218893Sdim goto fail2; 803193323Sed 804193323Seddone: 805193323Sed *handlep = enp->en_u.hunt.enu_piobuf_handle[buf]; 806193323Sed *bufnump = buf; 807193323Sed *blknump = blk; 808193323Sed *sizep = edcp->edc_pio_alloc_size; 809193323Sed *offsetp = blk * (*sizep); 810193323Sed 811193323Sed return (0); 812198090Srdivacky 813218893Sdimfail2: 814193323Sed EFSYS_PROBE(fail2); 815193323Sedfail1: 816193323Sed EFSYS_PROBE1(fail1, int, rc); 817193323Sed 818193323Sed return (rc); 819193323Sed} 820193323Sed 821193323Sed/* Free a piobuf sub-allocated block */ 822193323Sed __checkReturn int 823198090Srdivackyhunt_nic_pio_free( 824193323Sed __inout efx_nic_t *enp, 825218893Sdim __in uint32_t bufnum, 826218893Sdim __in uint32_t blknum) 827218893Sdim{ 828218893Sdim uint32_t *map; 829218893Sdim int rc; 830218893Sdim 831218893Sdim if ((bufnum >= enp->en_u.hunt.enu_piobuf_count) || 832218893Sdim (blknum >= (8 * sizeof (*map)))) { 833218893Sdim rc = EINVAL; 834193323Sed goto fail1; 835218893Sdim } 836218893Sdim 837218893Sdim map = &enp->en_u.hunt.enu_pio_alloc_map[bufnum]; 838218893Sdim if ((*map & (1u << blknum)) == 0) { 839193323Sed rc = ENOENT; 840218893Sdim goto fail2; 841218893Sdim } 842193323Sed *map &= ~(1u << blknum); 843198090Srdivacky 844193323Sed return (0); 845193323Sed 846193323Sedfail2: 847193323Sed EFSYS_PROBE(fail2); 848193323Sedfail1: 849193323Sed EFSYS_PROBE1(fail1, int, rc); 850202375Srdivacky 851193323Sed return (rc); 852202375Srdivacky} 853193323Sed 854193323Sed __checkReturn int 855193323Sedhunt_nic_pio_link( 856193323Sed __inout efx_nic_t *enp, 857193323Sed __in uint32_t vi_index, 858218893Sdim __in efx_piobuf_handle_t handle) 859218893Sdim{ 860218893Sdim return (efx_mcdi_link_piobuf(enp, vi_index, handle)); 861218893Sdim} 862218893Sdim 863193323Sed __checkReturn int 864193323Sedhunt_nic_pio_unlink( 865193323Sed __inout efx_nic_t *enp, 866193323Sed __in uint32_t vi_index) 867193323Sed{ 868193323Sed return (efx_mcdi_unlink_piobuf(enp, vi_index)); 869193323Sed} 870218893Sdim 871193323Sedstatic __checkReturn int 872218893Sdimhunt_get_datapath_caps( 873193323Sed __in efx_nic_t *enp) 874193323Sed{ 875193323Sed efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 876193323Sed efx_dword_t datapath_capabilities; 877199989Srdivacky int rc; 878199989Srdivacky 879199989Srdivacky if ((rc = efx_mcdi_get_capabilities(enp, &datapath_capabilities)) != 0) 880193323Sed goto fail1; 881193323Sed 882193323Sed /* 883193323Sed * Huntington RXDP firmware inserts a 0 or 14 byte prefix. 884193323Sed * We only support the 14 byte prefix here. 885193323Sed */ 886198090Srdivacky if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 887193323Sed GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14) != 1) { 888218893Sdim rc = ENOTSUP; 889218893Sdim goto fail2; 890218893Sdim } 891218893Sdim encp->enc_rx_prefix_size = 14; 892218893Sdim 893218893Sdim /* Check if the firmware supports TSO */ 894218893Sdim if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 895218893Sdim GET_CAPABILITIES_OUT_TX_TSO) == 1) 896193323Sed encp->enc_fw_assisted_tso_enabled = B_TRUE; 897218893Sdim else 898218893Sdim encp->enc_fw_assisted_tso_enabled = B_FALSE; 899218893Sdim 900218893Sdim /* Check if the firmware has vadapter/vport/vswitch support */ 901193323Sed if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 902218893Sdim GET_CAPABILITIES_OUT_EVB) == 1) 903218893Sdim encp->enc_datapath_cap_evb = B_TRUE; 904218893Sdim else 905193323Sed encp->enc_datapath_cap_evb = B_FALSE; 906198090Srdivacky 907193323Sed /* Check if the firmware supports VLAN insertion */ 908193323Sed if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 909193323Sed GET_CAPABILITIES_OUT_TX_VLAN_INSERTION) == 1) 910193323Sed encp->enc_hw_tx_insert_vlan_enabled = B_TRUE; 911193323Sed else 912193323Sed encp->enc_hw_tx_insert_vlan_enabled = B_FALSE; 913218893Sdim 914218893Sdim /* Check if the firmware supports RX event batching */ 915195340Sed if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities, 916218893Sdim GET_CAPABILITIES_OUT_RX_BATCHING) == 1) { 917218893Sdim encp->enc_rx_batching_enabled = B_TRUE; 918218893Sdim encp->enc_rx_batch_max = 16; 919218893Sdim } else { 920218893Sdim encp->enc_rx_batching_enabled = B_FALSE; 921218893Sdim } 922218893Sdim 923234353Sdim return (0); 924218893Sdim 925218893Sdimfail2: 926218893Sdim EFSYS_PROBE(fail2); 927218893Sdimfail1: 928218893Sdim EFSYS_PROBE1(fail1, int, rc); 929218893Sdim 930218893Sdim return (rc); 931218893Sdim} 932218893Sdim 933195340Sed/* 934195340Sed * The external port mapping is a one-based numbering of the external 935195340Sed * connectors on the board. It does not distinguish off-board separated 936219077Sdim * outputs such as multi-headed cables. 937219077Sdim * The number of ports that map to each external port connector 938219077Sdim * on the board is determined by the chip family and the port modes to 939219077Sdim * which the NIC can be configured. The mapping table lists modes with 940219077Sdim * port numbering requirements in increasing order. 941219077Sdim */ 942219077Sdimstatic struct { 943219077Sdim efx_family_t family; 944219077Sdim uint32_t modes_mask; 945219077Sdim uint32_t stride; 946219077Sdim} __hunt_external_port_mappings[] = { 947219077Sdim /* Supported modes requiring 1 output per port */ 948219077Sdim { 949219077Sdim EFX_FAMILY_HUNTINGTON, 950218893Sdim (1 << TLV_PORT_MODE_10G) | 951198090Srdivacky (1 << TLV_PORT_MODE_10G_10G) | 952193323Sed (1 << TLV_PORT_MODE_10G_10G_10G_10G), 953193323Sed 1 954193323Sed }, 955218893Sdim /* Supported modes requiring 2 outputs per port */ 956218893Sdim { 957193323Sed EFX_FAMILY_HUNTINGTON, 958193323Sed (1 << TLV_PORT_MODE_40G) | 959218893Sdim (1 << TLV_PORT_MODE_40G_40G) | 960193323Sed (1 << TLV_PORT_MODE_40G_10G_10G) | 961193323Sed (1 << TLV_PORT_MODE_10G_10G_40G), 962193323Sed 2 963218893Sdim } 964218893Sdim /* 965218893Sdim * NOTE: Medford modes will require 4 outputs per port: 966218893Sdim * TLV_PORT_MODE_10G_10G_10G_10G_Q 967218893Sdim * TLV_PORT_MODE_10G_10G_10G_10G_Q2 968218893Sdim * The Q2 mode routes outputs to external port 2. Support for this 969193323Sed * will require a new field specifying the number to add after 970218893Sdim * scaling by stride. This is fixed at 1 currently. 971198090Srdivacky */ 972210299Sed}; 973198090Srdivacky 974198090Srdivackystatic __checkReturn int 975198090Srdivackyhunt_external_port_mapping( 976193323Sed __in efx_nic_t *enp, 977193323Sed __in uint32_t port, 978193323Sed __out uint8_t *external_portp) 979193323Sed{ 980193323Sed int rc; 981193323Sed int i; 982193323Sed uint32_t port_modes; 983193323Sed uint32_t matches; 984193323Sed uint32_t stride = 1; /* default 1-1 mapping */ 985218893Sdim 986218893Sdim if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { 987193323Sed /* No port mode information available - use default mapping */ 988193323Sed goto out; 989218893Sdim } 990193323Sed 991218893Sdim /* 992193323Sed * Infer the internal port -> external port mapping from 993193323Sed * the possible port modes for this NIC. 994193323Sed */ 995193323Sed for (i = 0; i < EFX_ARRAY_SIZE(__hunt_external_port_mappings); ++i) { 996193323Sed if (__hunt_external_port_mappings[i].family != 997218893Sdim enp->en_family) 998218893Sdim continue; 999218893Sdim matches = (__hunt_external_port_mappings[i].modes_mask & 1000218893Sdim port_modes); 1001218893Sdim if (matches != 0) { 1002218893Sdim stride = __hunt_external_port_mappings[i].stride; 1003218893Sdim port_modes &= ~matches; 1004218893Sdim } 1005218893Sdim } 1006218893Sdim 1007218893Sdim if (port_modes != 0) { 1008218893Sdim /* Some advertised modes are not supported */ 1009218893Sdim rc = ENOTSUP; 1010218893Sdim goto fail1; 1011218893Sdim } 1012218893Sdim 1013218893Sdimout: 1014218893Sdim /* 1015218893Sdim * Scale as required by last matched mode and then convert to 1016218893Sdim * one-based numbering 1017218893Sdim */ 1018218893Sdim *external_portp = (uint8_t)(port / stride) + 1; 1019218893Sdim return (0); 1020218893Sdim 1021218893Sdimfail1: 1022218893Sdim EFSYS_PROBE1(fail1, int, rc); 1023218893Sdim 1024218893Sdim return (rc); 1025218893Sdim} 1026218893Sdim 1027218893Sdimstatic __checkReturn int 1028218893Sdimhunt_board_cfg( 1029218893Sdim __in efx_nic_t *enp) 1030218893Sdim{ 1031218893Sdim efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1032218893Sdim efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1033218893Sdim uint8_t mac_addr[6]; 1034218893Sdim uint32_t board_type = 0; 1035218893Sdim hunt_link_state_t hls; 1036218893Sdim efx_port_t *epp = &(enp->en_port); 1037218893Sdim uint32_t port; 1038218893Sdim uint32_t pf; 1039218893Sdim uint32_t vf; 1040218893Sdim uint32_t mask; 1041218893Sdim uint32_t flags; 1042218893Sdim uint32_t sysclk; 1043218893Sdim uint32_t base, nvec; 1044218893Sdim int rc; 1045218893Sdim 1046218893Sdim if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0) 1047218893Sdim goto fail1; 1048199989Srdivacky 1049218893Sdim /* 1050218893Sdim * NOTE: The MCDI protocol numbers ports from zero. 1051218893Sdim * The common code MCDI interface numbers ports from one. 1052218893Sdim */ 1053218893Sdim emip->emi_port = port + 1; 1054218893Sdim 1055199989Srdivacky if ((rc = hunt_external_port_mapping(enp, port, 1056199989Srdivacky &encp->enc_external_port)) != 0) 1057199989Srdivacky goto fail2; 1058218893Sdim 1059199989Srdivacky /* 1060218893Sdim * Get PCIe function number from firmware (used for 1061199989Srdivacky * per-function privilege and dynamic config info). 1062193323Sed * - PCIe PF: pf = PF number, vf = 0xffff. 1063193323Sed * - PCIe VF: pf = parent PF, vf = VF number. 1064193323Sed */ 1065193323Sed if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0) 1066193323Sed goto fail3; 1067193323Sed 1068193323Sed encp->enc_pf = pf; 1069193323Sed encp->enc_vf = vf; 1070218893Sdim 1071218893Sdim /* MAC address for this function */ 1072218893Sdim if (EFX_PCI_FUNCTION_IS_PF(encp)) { 1073218893Sdim rc = efx_mcdi_get_mac_address_pf(enp, mac_addr); 1074218893Sdim } else { 1075218893Sdim rc = efx_mcdi_get_mac_address_vf(enp, mac_addr); 1076218893Sdim } 1077218893Sdim if ((rc == 0) && (mac_addr[0] & 0x02)) { 1078193323Sed /* 1079193323Sed * If the static config does not include a global MAC address 1080193323Sed * pool then the board may return a locally administered MAC 1081193323Sed * address (this should only happen on incorrectly programmed 1082193323Sed * boards). 1083193323Sed */ 1084218893Sdim rc = EINVAL; 1085218893Sdim } 1086218893Sdim if (rc != 0) 1087218893Sdim goto fail4; 1088218893Sdim 1089193323Sed EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr); 1090193323Sed 1091193323Sed /* Board configuration */ 1092193323Sed rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL); 1093193323Sed if (rc != 0) { 1094193323Sed /* Unprivileged functions may not be able to read board cfg */ 1095193323Sed if (rc == EACCES) 1096218893Sdim board_type = 0; 1097218893Sdim else 1098218893Sdim goto fail5; 1099218893Sdim } 1100193323Sed 1101193323Sed encp->enc_board_type = board_type; 1102218893Sdim encp->enc_clk_mult = 1; /* not used for Huntington */ 1103218893Sdim 1104218893Sdim /* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */ 1105218893Sdim if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0) 1106193323Sed goto fail6; 1107193323Sed 1108218893Sdim /* Obtain the default PHY advertised capabilities */ 1109218893Sdim if ((rc = hunt_phy_get_link(enp, &hls)) != 0) 1110218893Sdim goto fail7; 1111218893Sdim epp->ep_default_adv_cap_mask = hls.hls_adv_cap_mask; 1112193323Sed epp->ep_adv_cap_mask = hls.hls_adv_cap_mask; 1113193323Sed 1114218893Sdim /* 1115218893Sdim * Enable firmware workarounds for hardware errata. 1116193323Sed * Expected responses are: 1117193323Sed * - 0 (zero): 1118193323Sed * Success: workaround enabled or disabled as requested. 1119193323Sed * - MC_CMD_ERR_ENOSYS (reported as ENOTSUP): 1120193323Sed * Firmware does not support the MC_CMD_WORKAROUND request. 1121193323Sed * (assume that the workaround is not supported). 1122193323Sed * - MC_CMD_ERR_ENOENT (reported as ENOENT): 1123218893Sdim * Firmware does not support the requested workaround. 1124193323Sed * - MC_CMD_ERR_EPERM (reported as EACCES): 1125193323Sed * Unprivileged function cannot enable/disable workarounds. 1126193323Sed * 1127193323Sed * See efx_mcdi_request_errcode() for MCDI error translations. 1128193323Sed */ 1129193323Sed 1130218893Sdim /* 1131218893Sdim * If the bug35388 workaround is enabled, then use an indirect access 1132218893Sdim * method to avoid unsafe EVQ writes. 1133218893Sdim */ 1134218893Sdim rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE, 1135218893Sdim NULL); 1136193323Sed if ((rc == 0) || (rc == EACCES)) 1137218893Sdim encp->enc_bug35388_workaround = B_TRUE; 1138218893Sdim else if ((rc == ENOTSUP) || (rc == ENOENT)) 1139193323Sed encp->enc_bug35388_workaround = B_FALSE; 1140193323Sed else 1141198090Srdivacky goto fail8; 1142193323Sed 1143193323Sed /* 1144193323Sed * If the bug41750 workaround is enabled, then do not test interrupts, 1145218893Sdim * as the test will fail (seen with Greenport controllers). 1146218893Sdim */ 1147218893Sdim rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE, 1148218893Sdim NULL); 1149218893Sdim if (rc == 0) { 1150218893Sdim encp->enc_bug41750_workaround = B_TRUE; 1151218893Sdim } else if (rc == EACCES) { 1152195098Sed /* Assume a controller with 40G ports needs the workaround. */ 1153212904Sdim if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX) 1154212904Sdim encp->enc_bug41750_workaround = B_TRUE; 1155212904Sdim else 1156226633Sdim encp->enc_bug41750_workaround = B_FALSE; 1157195098Sed } else if ((rc == ENOTSUP) || (rc == ENOENT)) { 1158195098Sed encp->enc_bug41750_workaround = B_FALSE; 1159195098Sed } else { 1160195098Sed goto fail9; 1161195098Sed } 1162195098Sed if (EFX_PCI_FUNCTION_IS_VF(encp)) { 1163195098Sed /* Interrupt testing does not work for VFs. See bug50084. */ 1164195098Sed encp->enc_bug41750_workaround = B_TRUE; 1165195098Sed } 1166195098Sed 1167195098Sed /* 1168195098Sed * If the bug26807 workaround is enabled, then firmware has enabled 1169195098Sed * support for chained multicast filters. Firmware will reset (FLR) 1170195098Sed * functions which have filters in the hardware filter table when the 1171195098Sed * workaround is enabled/disabled. 1172195098Sed * 1173218893Sdim * We must recheck if the workaround is enabled after inserting the 1174195340Sed * first hardware filter, in case it has been changed since this check. 1175195340Sed */ 1176195340Sed rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807, 1177198090Srdivacky B_TRUE, &flags); 1178218893Sdim if (rc == 0) { 1179218893Sdim encp->enc_bug26807_workaround = B_TRUE; 1180198090Srdivacky if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) { 1181218893Sdim /* 1182198090Srdivacky * Other functions had installed filters before the 1183198090Srdivacky * workaround was enabled, and they have been reset 1184198090Srdivacky * by firmware. 1185198090Srdivacky */ 1186218893Sdim EFSYS_PROBE(bug26807_workaround_flr_done); 1187221345Sdim /* FIXME: bump MC warm boot count ? */ 1188218893Sdim } 1189199989Srdivacky } else if (rc == EACCES) { 1190199989Srdivacky /* 1191198090Srdivacky * Unprivileged functions cannot enable the workaround in older 1192198090Srdivacky * firmware. 1193198090Srdivacky */ 1194198090Srdivacky encp->enc_bug26807_workaround = B_FALSE; 1195198090Srdivacky } else if ((rc == ENOTSUP) || (rc == ENOENT)) { 1196198090Srdivacky encp->enc_bug26807_workaround = B_FALSE; 1197198090Srdivacky } else { 1198198090Srdivacky goto fail10; 1199198090Srdivacky } 1200195340Sed 1201218893Sdim /* Get sysclk frequency (in MHz). */ 1202198090Srdivacky if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0) 1203198090Srdivacky goto fail11; 1204198090Srdivacky 1205195340Sed /* 1206198090Srdivacky * The timer quantum is 1536 sysclk cycles, documented for the 1207198090Srdivacky * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units. 1208198090Srdivacky */ 1209198090Srdivacky encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */ 1210195340Sed if (encp->enc_bug35388_workaround) { 1211198090Srdivacky encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << 1212198090Srdivacky ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000; 1213198090Srdivacky } else { 1214198090Srdivacky encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << 1215195340Sed FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000; 1216195340Sed } 1217195340Sed 1218195340Sed /* Check capabilities of running datapath firmware */ 1219195340Sed if ((rc = hunt_get_datapath_caps(enp)) != 0) 1220198090Srdivacky goto fail12; 1221198090Srdivacky 1222198090Srdivacky /* Alignment for receive packet DMA buffers */ 1223198090Srdivacky encp->enc_rx_buf_align_start = 1; 1224195340Sed encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */ 1225195340Sed 1226218893Sdim /* Alignment for WPTR updates */ 1227195340Sed encp->enc_rx_push_align = HUNTINGTON_RX_WPTR_ALIGN; 1228198090Srdivacky 1229218893Sdim /* 1230218893Sdim * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use 1231218893Sdim * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available 1232221345Sdim * resources (allocated to this PCIe function), which is zero until 1233218893Sdim * after we have allocated VIs. 1234218893Sdim */ 1235218893Sdim encp->enc_evq_limit = 1024; 1236218893Sdim encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET; 1237198090Srdivacky encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET; 1238218893Sdim 1239218893Sdim encp->enc_buftbl_limit = 0xFFFFFFFF; 1240218893Sdim 1241218893Sdim encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS; 1242218893Sdim encp->enc_piobuf_size = HUNT_PIOBUF_SIZE; 1243195340Sed 1244218893Sdim /* 1245218893Sdim * Get the current privilege mask. Note that this may be modified 1246195340Sed * dynamically, so this value is informational only. DO NOT use 1247195340Sed * the privilege mask to check for sufficient privileges, as that 1248195340Sed * can result in time-of-check/time-of-use bugs. 1249195340Sed */ 1250195340Sed if ((rc = efx_mcdi_privilege_mask(enp, pf, vf, &mask)) != 0) { 1251195340Sed if (rc != ENOTSUP) 1252202375Srdivacky goto fail13; 1253195340Sed 1254202375Srdivacky /* Fallback for old firmware without privilege mask support */ 1255195340Sed if (EFX_PCI_FUNCTION_IS_PF(encp)) { 1256195340Sed /* Assume PF has admin privilege */ 1257195340Sed mask = HUNT_LEGACY_PF_PRIVILEGE_MASK; 1258218893Sdim } else { 1259218893Sdim /* VF is always unprivileged by default */ 1260218893Sdim mask = HUNT_LEGACY_VF_PRIVILEGE_MASK; 1261218893Sdim } 1262218893Sdim } 1263218893Sdim 1264195340Sed encp->enc_privilege_mask = mask; 1265195340Sed 1266195340Sed /* Get interrupt vector limits */ 1267195340Sed if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) { 1268195340Sed if (EFX_PCI_FUNCTION_IS_PF(encp)) 1269218893Sdim goto fail14; 1270195340Sed 1271195340Sed /* Ignore error (cannot query vector limits from a VF). */ 1272198090Srdivacky base = 0; 1273218893Sdim nvec = 1024; 1274198090Srdivacky } 1275198090Srdivacky encp->enc_intr_vec_base = base; 1276198090Srdivacky encp->enc_intr_limit = nvec; 1277198090Srdivacky 1278198090Srdivacky /* 1279198090Srdivacky * Maximum number of bytes into the frame the TCP header can start for 1280198090Srdivacky * firmware assisted TSO to work. 1281198090Srdivacky */ 1282198090Srdivacky encp->enc_tx_tso_tcp_header_offset_limit = 208; 1283195340Sed 1284195340Sed return (0); 1285195340Sed 1286195340Sedfail14: 1287195340Sed EFSYS_PROBE(fail14); 1288195340Sedfail13: 1289195340Sed EFSYS_PROBE(fail13); 1290195340Sedfail12: 1291226633Sdim EFSYS_PROBE(fail12); 1292195340Sedfail11: 1293226633Sdim EFSYS_PROBE(fail11); 1294195340Sedfail10: 1295195340Sed EFSYS_PROBE(fail10); 1296198090Srdivackyfail9: 1297198090Srdivacky EFSYS_PROBE(fail9); 1298195340Sedfail8: 1299195340Sed EFSYS_PROBE(fail8); 1300195340Sedfail7: 1301195340Sed EFSYS_PROBE(fail7); 1302195340Sedfail6: 1303218893Sdim EFSYS_PROBE(fail6); 1304218893Sdimfail5: 1305218893Sdim EFSYS_PROBE(fail5); 1306195340Sedfail4: 1307195340Sed EFSYS_PROBE(fail4); 1308218893Sdimfail3: 1309195340Sed EFSYS_PROBE(fail3); 1310195340Sedfail2: 1311195340Sed EFSYS_PROBE(fail2); 1312198090Srdivackyfail1: 1313198090Srdivacky EFSYS_PROBE1(fail1, int, rc); 1314195340Sed 1315195340Sed return (rc); 1316195340Sed} 1317195340Sed 1318195340Sed 1319195340Sed __checkReturn int 1320195340Sedhunt_nic_probe( 1321193323Sed __in efx_nic_t *enp) 1322193323Sed{ 1323193323Sed efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1324193323Sed efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); 1325193323Sed int rc; 1326202375Srdivacky 1327202375Srdivacky EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1328195340Sed 1329195340Sed /* Read and clear any assertion state */ 1330195340Sed if ((rc = efx_mcdi_read_assertion(enp)) != 0) 1331193323Sed goto fail1; 1332198090Srdivacky 1333195340Sed /* Exit the assertion handler */ 1334195340Sed if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) 1335195340Sed if (rc != EACCES) 1336195340Sed goto fail2; 1337226633Sdim 1338226633Sdim if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) 1339226633Sdim goto fail3; 1340195340Sed 1341226633Sdim if ((rc = hunt_board_cfg(enp)) != 0) 1342226633Sdim if (rc != EACCES) 1343226633Sdim goto fail4; 1344226633Sdim 1345226633Sdim /* 1346226633Sdim * Set default driver config limits (based on board config). 1347226633Sdim * 1348226633Sdim * FIXME: For now allocate a fixed number of VIs which is likely to be 1349226633Sdim * sufficient and small enough to allow multiple functions on the same 1350195340Sed * port. 1351202375Srdivacky */ 1352195340Sed edcp->edc_min_vi_count = edcp->edc_max_vi_count = 1353195340Sed MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); 1354195340Sed 1355195340Sed /* The client driver must configure and enable PIO buffer support */ 1356195340Sed edcp->edc_max_piobuf_count = 0; 1357195340Sed edcp->edc_pio_alloc_size = 0; 1358202375Srdivacky 1359195340Sed#if EFSYS_OPT_MAC_STATS 1360195340Sed /* Wipe the MAC statistics */ 1361195340Sed if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) 1362195340Sed goto fail5; 1363226633Sdim#endif 1364226633Sdim 1365195340Sed#if EFSYS_OPT_LOOPBACK 1366226633Sdim if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) 1367226633Sdim goto fail6; 1368226633Sdim#endif 1369226633Sdim 1370226633Sdim#if EFSYS_OPT_MON_STATS 1371226633Sdim if ((rc = mcdi_mon_cfg_build(enp)) != 0) { 1372226633Sdim /* Unprivileged functions do not have access to sensors */ 1373226633Sdim if (rc != EACCES) 1374195340Sed goto fail7; 1375195340Sed } 1376195340Sed#endif 1377195340Sed 1378195340Sed encp->enc_features = enp->en_features; 1379226633Sdim 1380226633Sdim return (0); 1381226633Sdim 1382226633Sdim#if EFSYS_OPT_MON_STATS 1383226633Sdimfail7: 1384226633Sdim EFSYS_PROBE(fail7); 1385226633Sdim#endif 1386226633Sdim#if EFSYS_OPT_LOOPBACK 1387226633Sdimfail6: 1388226633Sdim EFSYS_PROBE(fail6); 1389226633Sdim#endif 1390226633Sdim#if EFSYS_OPT_MAC_STATS 1391226633Sdimfail5: 1392226633Sdim EFSYS_PROBE(fail5); 1393226633Sdim#endif 1394195340Sedfail4: 1395195340Sed EFSYS_PROBE(fail4); 1396195340Sedfail3: 1397195340Sed EFSYS_PROBE(fail3); 1398195340Sedfail2: 1399202375Srdivacky EFSYS_PROBE(fail2); 1400202375Srdivackyfail1: 1401195340Sed EFSYS_PROBE1(fail1, int, rc); 1402195340Sed 1403195340Sed return (rc); 1404195340Sed} 1405198090Srdivacky 1406195340Sed __checkReturn int 1407195340Sedhunt_nic_set_drv_limits( 1408195340Sed __inout efx_nic_t *enp, 1409195340Sed __in efx_drv_limits_t *edlp) 1410195340Sed{ 1411202375Srdivacky efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1412198090Srdivacky efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); 1413195340Sed uint32_t min_evq_count, max_evq_count; 1414195340Sed uint32_t min_rxq_count, max_rxq_count; 1415195340Sed uint32_t min_txq_count, max_txq_count; 1416195340Sed int rc; 1417195340Sed 1418195340Sed if (edlp == NULL) { 1419195340Sed rc = EINVAL; 1420195340Sed goto fail1; 1421195340Sed } 1422195340Sed 1423195340Sed /* Get minimum required and maximum usable VI limits */ 1424195340Sed min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); 1425195340Sed min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); 1426195340Sed min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); 1427195340Sed 1428195340Sed edcp->edc_min_vi_count = 1429195340Sed MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); 1430195340Sed 1431195340Sed max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); 1432195340Sed max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); 1433195340Sed max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); 1434195340Sed 1435195340Sed edcp->edc_max_vi_count = 1436195340Sed MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); 1437195340Sed 1438195340Sed /* 1439195340Sed * Check limits for sub-allocated piobuf blocks. 1440202375Srdivacky * PIO is optional, so don't fail if the limits are incorrect. 1441198090Srdivacky */ 1442195340Sed if ((encp->enc_piobuf_size == 0) || 1443195340Sed (encp->enc_piobuf_limit == 0) || 1444195340Sed (edlp->edl_min_pio_alloc_size == 0) || 1445195340Sed (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { 1446195340Sed /* Disable PIO */ 1447210299Sed edcp->edc_max_piobuf_count = 0; 1448210299Sed edcp->edc_pio_alloc_size = 0; 1449210299Sed } else { 1450210299Sed uint32_t blk_size, blk_count, blks_per_piobuf; 1451224145Sdim 1452224145Sdim blk_size = 1453210299Sed MAX(edlp->edl_min_pio_alloc_size, HUNT_MIN_PIO_ALLOC_SIZE); 1454210299Sed 1455224145Sdim blks_per_piobuf = encp->enc_piobuf_size / blk_size; 1456224145Sdim EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); 1457210299Sed 1458210299Sed blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); 1459208599Srdivacky 1460208599Srdivacky /* A zero max pio alloc count means unlimited */ 1461198090Srdivacky if ((edlp->edl_max_pio_alloc_count > 0) && 1462198090Srdivacky (edlp->edl_max_pio_alloc_count < blk_count)) { 1463224145Sdim blk_count = edlp->edl_max_pio_alloc_count; 1464208599Srdivacky } 1465208599Srdivacky 1466224145Sdim edcp->edc_pio_alloc_size = blk_size; 1467224145Sdim edcp->edc_max_piobuf_count = 1468198090Srdivacky (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; 1469198090Srdivacky } 1470208599Srdivacky 1471208599Srdivacky return (0); 1472208599Srdivacky 1473208599Srdivackyfail1: 1474224145Sdim EFSYS_PROBE1(fail1, int, rc); 1475208599Srdivacky 1476208599Srdivacky return (rc); 1477224145Sdim} 1478224145Sdim 1479208599Srdivacky 1480208599Srdivacky __checkReturn int 1481210299Sedhunt_nic_reset( 1482210299Sed __in efx_nic_t *enp) 1483210299Sed{ 1484210299Sed efx_mcdi_req_t req; 1485210299Sed uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, 1486224145Sdim MC_CMD_ENTITY_RESET_OUT_LEN)]; 1487224145Sdim int rc; 1488210299Sed 1489210299Sed /* hunt_nic_reset() is called to recover from BADASSERT failures. */ 1490210299Sed if ((rc = efx_mcdi_read_assertion(enp)) != 0) 1491210299Sed goto fail1; 1492224145Sdim if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) 1493224145Sdim goto fail2; 1494224145Sdim 1495210299Sed (void) memset(payload, 0, sizeof (payload)); 1496210299Sed req.emr_cmd = MC_CMD_ENTITY_RESET; 1497208599Srdivacky req.emr_in_buf = payload; 1498208599Srdivacky req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; 1499208599Srdivacky req.emr_out_buf = payload; 1500208599Srdivacky req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; 1501208599Srdivacky 1502224145Sdim MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, 1503208599Srdivacky ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); 1504208599Srdivacky 1505208599Srdivacky efx_mcdi_execute(enp, &req); 1506208599Srdivacky 1507224145Sdim if (req.emr_rc != 0) { 1508224145Sdim rc = req.emr_rc; 1509224145Sdim goto fail3; 1510208599Srdivacky } 1511208599Srdivacky 1512208599Srdivacky /* Clear RX/TX DMA queue errors */ 1513208599Srdivacky enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); 1514208599Srdivacky 1515208599Srdivacky return (0); 1516208599Srdivacky 1517224145Sdimfail3: 1518208599Srdivacky EFSYS_PROBE(fail3); 1519208599Srdivackyfail2: 1520208599Srdivacky EFSYS_PROBE(fail2); 1521208599Srdivackyfail1: 1522224145Sdim EFSYS_PROBE1(fail1, int, rc); 1523224145Sdim 1524224145Sdim return (rc); 1525208599Srdivacky} 1526208599Srdivacky 1527218893Sdim __checkReturn int 1528218893Sdimhunt_nic_init( 1529218893Sdim __in efx_nic_t *enp) 1530218893Sdim{ 1531218893Sdim efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); 1532218893Sdim uint32_t min_vi_count, max_vi_count; 1533218893Sdim uint32_t vi_count, vi_base; 1534218893Sdim uint32_t i; 1535208599Srdivacky int rc; 1536218893Sdim 1537218893Sdim EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1538218893Sdim 1539218893Sdim /* Enable reporting of some events (e.g. link change) */ 1540218893Sdim if ((rc = efx_mcdi_log_ctrl(enp)) != 0) 1541218893Sdim goto fail1; 1542218893Sdim 1543218893Sdim /* Allocate (optional) on-chip PIO buffers */ 1544218893Sdim hunt_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); 1545218893Sdim 1546218893Sdim /* 1547198090Srdivacky * For best performance, PIO writes should use a write-combined 1548198090Srdivacky * (WC) memory mapping. Using a separate WC mapping for the PIO 1549234353Sdim * aperture of each VI would be a burden to drivers (and not 1550234353Sdim * possible if the host page size is >4Kbyte). 1551234353Sdim * 1552234353Sdim * To avoid this we use a single uncached (UC) mapping for VI 1553234353Sdim * register access, and a single WC mapping for extra VIs used 1554234353Sdim * for PIO writes. 1555234353Sdim * 1556234353Sdim * Each piobuf must be linked to a VI in the WC mapping, and to 1557234353Sdim * each VI that is using a sub-allocated block from the piobuf. 1558234353Sdim */ 1559234353Sdim min_vi_count = edcp->edc_min_vi_count; 1560234353Sdim max_vi_count = edcp->edc_max_vi_count + enp->en_u.hunt.enu_piobuf_count; 1561234353Sdim 1562234353Sdim /* Ensure that the previously attached driver's VIs are freed */ 1563234353Sdim if ((rc = efx_mcdi_free_vis(enp)) != 0) 1564234353Sdim goto fail2; 1565234353Sdim 1566234353Sdim /* 1567234353Sdim * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this 1568234353Sdim * fails then retrying the request for fewer VI resources may succeed. 1569234353Sdim */ 1570234353Sdim vi_count = 0; 1571234353Sdim if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, 1572234353Sdim &vi_base, &vi_count)) != 0) 1573234353Sdim goto fail3; 1574234353Sdim 1575234353Sdim EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); 1576234353Sdim 1577234353Sdim if (vi_count < min_vi_count) { 1578234353Sdim rc = ENOMEM; 1579234353Sdim goto fail4; 1580234353Sdim } 1581234353Sdim 1582234353Sdim enp->en_u.hunt.enu_vi_base = vi_base; 1583234353Sdim enp->en_u.hunt.enu_vi_count = vi_count; 1584234353Sdim 1585234353Sdim if (vi_count < min_vi_count + enp->en_u.hunt.enu_piobuf_count) { 1586234353Sdim /* Not enough extra VIs to map piobufs */ 1587234353Sdim hunt_nic_free_piobufs(enp); 1588234353Sdim } 1589234353Sdim 1590234353Sdim enp->en_u.hunt.enu_pio_write_vi_base = 1591234353Sdim vi_count - enp->en_u.hunt.enu_piobuf_count; 1592234353Sdim 1593234353Sdim /* Save UC memory mapping details */ 1594234353Sdim enp->en_u.hunt.enu_uc_mem_map_offset = 0; 1595218893Sdim if (enp->en_u.hunt.enu_piobuf_count > 0) { 1596239462Sdim enp->en_u.hunt.enu_uc_mem_map_size = 1597239462Sdim (ER_DZ_TX_PIOBUF_STEP * 1598239462Sdim enp->en_u.hunt.enu_pio_write_vi_base); 1599206083Srdivacky } else { 1600198090Srdivacky enp->en_u.hunt.enu_uc_mem_map_size = 1601198090Srdivacky (ER_DZ_TX_PIOBUF_STEP * 1602205407Srdivacky enp->en_u.hunt.enu_vi_count); 1603218893Sdim } 1604218893Sdim 1605198090Srdivacky /* Save WC memory mapping details */ 1606198090Srdivacky enp->en_u.hunt.enu_wc_mem_map_offset = 1607198090Srdivacky enp->en_u.hunt.enu_uc_mem_map_offset + 1608198090Srdivacky enp->en_u.hunt.enu_uc_mem_map_size; 1609198090Srdivacky 1610218893Sdim enp->en_u.hunt.enu_wc_mem_map_size = 1611198090Srdivacky (ER_DZ_TX_PIOBUF_STEP * 1612198090Srdivacky enp->en_u.hunt.enu_piobuf_count); 1613198090Srdivacky 1614198090Srdivacky /* Link piobufs to extra VIs in WC mapping */ 1615198090Srdivacky if (enp->en_u.hunt.enu_piobuf_count > 0) { 1616198090Srdivacky for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) { 1617198090Srdivacky rc = efx_mcdi_link_piobuf(enp, 1618198090Srdivacky enp->en_u.hunt.enu_pio_write_vi_base + i, 1619198090Srdivacky enp->en_u.hunt.enu_piobuf_handle[i]); 1620198090Srdivacky if (rc != 0) 1621198090Srdivacky break; 1622198090Srdivacky } 1623198090Srdivacky } 1624198090Srdivacky 1625198090Srdivacky /* Allocate a vAdapter attached to our upstream vPort/pPort */ 1626206083Srdivacky if ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) 1627206083Srdivacky goto fail5; 1628206083Srdivacky 1629198090Srdivacky enp->en_vport_id = EVB_PORT_ID_ASSIGNED; 1630198090Srdivacky 1631212904Sdim return (0); 1632212904Sdim 1633212904Sdimfail5: 1634212904Sdim EFSYS_PROBE(fail5); 1635212904Sdimfail4: 1636212904Sdim EFSYS_PROBE(fail4); 1637212904Sdimfail3: 1638212904Sdim EFSYS_PROBE(fail3); 1639212904Sdimfail2: 1640218893Sdim EFSYS_PROBE(fail2); 1641218893Sdim 1642218893Sdim hunt_nic_free_piobufs(enp); 1643218893Sdim 1644218893Sdimfail1: 1645212904Sdim EFSYS_PROBE1(fail1, int, rc); 1646207618Srdivacky 1647205407Srdivacky return (rc); 1648218893Sdim} 1649218893Sdim 1650208599Srdivacky __checkReturn int 1651218893Sdimhunt_nic_get_vi_pool( 1652218893Sdim __in efx_nic_t *enp, 1653218893Sdim __out uint32_t *vi_countp) 1654218893Sdim{ 1655218893Sdim EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1656218893Sdim 1657218893Sdim /* 1658218893Sdim * Report VIs that the client driver can use. 1659234353Sdim * Do not include VIs used for PIO buffer writes. 1660234353Sdim */ 1661234353Sdim *vi_countp = enp->en_u.hunt.enu_pio_write_vi_base; 1662234353Sdim 1663234353Sdim return (0); 1664234353Sdim} 1665234353Sdim 1666234353Sdim __checkReturn int 1667234353Sdimhunt_nic_get_bar_region( 1668208599Srdivacky __in efx_nic_t *enp, 1669218893Sdim __in efx_nic_region_t region, 1670218893Sdim __out uint32_t *offsetp, 1671218893Sdim __out size_t *sizep) 1672218893Sdim{ 1673198090Srdivacky int rc; 1674198090Srdivacky 1675198090Srdivacky EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON); 1676198090Srdivacky 1677212904Sdim /* 1678198090Srdivacky * TODO: Specify host memory mapping alignment and granularity 1679218893Sdim * in efx_drv_limits_t so that they can be taken into account 1680218893Sdim * when allocating extra VIs for PIO writes. 1681212904Sdim */ 1682212904Sdim switch (region) { 1683212904Sdim case EFX_REGION_VI: 1684218893Sdim /* UC mapped memory BAR region for VI registers */ 1685218893Sdim *offsetp = enp->en_u.hunt.enu_uc_mem_map_offset; 1686212904Sdim *sizep = enp->en_u.hunt.enu_uc_mem_map_size; 1687198090Srdivacky break; 1688198113Srdivacky 1689218893Sdim case EFX_REGION_PIO_WRITE_VI: 1690218893Sdim /* WC mapped memory BAR region for piobuf writes */ 1691218893Sdim *offsetp = enp->en_u.hunt.enu_wc_mem_map_offset; 1692218893Sdim *sizep = enp->en_u.hunt.enu_wc_mem_map_size; 1693218893Sdim break; 1694218893Sdim 1695218893Sdim default: 1696218893Sdim rc = EINVAL; 1697218893Sdim goto fail1; 1698218893Sdim } 1699218893Sdim 1700218893Sdim return (0); 1701218893Sdim 1702218893Sdimfail1: 1703218893Sdim EFSYS_PROBE1(fail1, int, rc); 1704212904Sdim 1705198090Srdivacky return (rc); 1706221345Sdim} 1707221345Sdim 1708221345Sdim void 1709221345Sdimhunt_nic_fini( 1710221345Sdim __in efx_nic_t *enp) 1711218893Sdim{ 1712218893Sdim (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); 1713218893Sdim enp->en_vport_id = 0; 1714218893Sdim 1715218893Sdim /* FIXME: do we need to unlink piobufs ? */ 1716218893Sdim hunt_nic_free_piobufs(enp); 1717218893Sdim 1718218893Sdim (void) efx_mcdi_free_vis(enp); 1719218893Sdim enp->en_u.hunt.enu_vi_count = 0; 1720218893Sdim} 1721218893Sdim 1722218893Sdim void 1723218893Sdimhunt_nic_unprobe( 1724218893Sdim __in efx_nic_t *enp) 1725198090Srdivacky{ 1726198090Srdivacky#if EFSYS_OPT_MON_STATS 1727198090Srdivacky mcdi_mon_cfg_free(enp); 1728218893Sdim#endif /* EFSYS_OPT_MON_STATS */ 1729239462Sdim (void) efx_mcdi_drv_attach(enp, B_FALSE); 1730239462Sdim} 1731239462Sdim 1732210299Sed#if EFSYS_OPT_DIAG 1733198113Srdivacky 1734198113Srdivacky __checkReturn int 1735205407Srdivackyhunt_nic_register_test( 1736218893Sdim __in efx_nic_t *enp) 1737218893Sdim{ 1738218893Sdim int rc; 1739198113Srdivacky 1740198113Srdivacky /* FIXME */ 1741221345Sdim _NOTE(ARGUNUSED(enp)) 1742221345Sdim if (B_FALSE) { 1743221345Sdim rc = ENOTSUP; 1744198113Srdivacky goto fail1; 1745218893Sdim } 1746198113Srdivacky /* FIXME */ 1747218893Sdim 1748198113Srdivacky return (0); 1749198113Srdivacky 1750198113Srdivackyfail1: 1751198113Srdivacky EFSYS_PROBE1(fail1, int, rc); 1752198113Srdivacky 1753198113Srdivacky return (rc); 1754198113Srdivacky} 1755198113Srdivacky 1756198113Srdivacky#endif /* EFSYS_OPT_DIAG */ 1757198113Srdivacky 1758198113Srdivacky 1759198113Srdivacky 1760198113Srdivacky#endif /* EFSYS_OPT_HUNTINGTON */ 1761198113Srdivacky