1283514Sarybchik/*- 2300607Sarybchik * Copyright (c) 2012-2016 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4283514Sarybchik * 5283514Sarybchik * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7283514Sarybchik * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29283514Sarybchik */ 30283514Sarybchik 31283514Sarybchik#include <sys/cdefs.h> 32283514Sarybchik__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/ef10_rx.c 350411 2019-07-29 10:42:21Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efx.h" 35283514Sarybchik#include "efx_impl.h" 36283514Sarybchik 37283514Sarybchik 38299604Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 39283514Sarybchik 40283514Sarybchik 41291436Sarybchikstatic __checkReturn efx_rc_t 42283514Sarybchikefx_mcdi_init_rxq( 43283514Sarybchik __in efx_nic_t *enp, 44283514Sarybchik __in uint32_t size, 45283514Sarybchik __in uint32_t target_evq, 46283514Sarybchik __in uint32_t label, 47283514Sarybchik __in uint32_t instance, 48291747Sarybchik __in efsys_mem_t *esmp, 49291747Sarybchik __in boolean_t disable_scatter) 50283514Sarybchik{ 51283514Sarybchik efx_mcdi_req_t req; 52342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, 53342445Sarybchik MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)), 54342445Sarybchik MC_CMD_INIT_RXQ_OUT_LEN); 55283514Sarybchik int npages = EFX_RXQ_NBUFS(size); 56283514Sarybchik int i; 57283514Sarybchik efx_qword_t *dma_addr; 58283514Sarybchik uint64_t addr; 59291436Sarybchik efx_rc_t rc; 60283514Sarybchik 61300847Sarybchik /* If this changes, then the payload size might need to change. */ 62300847Sarybchik EFSYS_ASSERT3U(MC_CMD_INIT_RXQ_OUT_LEN, ==, 0); 63283514Sarybchik EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS); 64283514Sarybchik 65283514Sarybchik req.emr_cmd = MC_CMD_INIT_RXQ; 66283514Sarybchik req.emr_in_buf = payload; 67283514Sarybchik req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages); 68283514Sarybchik req.emr_out_buf = payload; 69283514Sarybchik req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN; 70283514Sarybchik 71283514Sarybchik MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size); 72283514Sarybchik MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq); 73283514Sarybchik MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label); 74283514Sarybchik MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance); 75291747Sarybchik MCDI_IN_POPULATE_DWORD_6(req, INIT_RXQ_IN_FLAGS, 76291747Sarybchik INIT_RXQ_IN_FLAG_BUFF_MODE, 0, 77291747Sarybchik INIT_RXQ_IN_FLAG_HDR_SPLIT, 0, 78291747Sarybchik INIT_RXQ_IN_FLAG_TIMESTAMP, 0, 79291747Sarybchik INIT_RXQ_IN_CRC_MODE, 0, 80291747Sarybchik INIT_RXQ_IN_FLAG_PREFIX, 1, 81291747Sarybchik INIT_RXQ_IN_FLAG_DISABLE_SCATTER, disable_scatter); 82283514Sarybchik MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0); 83283514Sarybchik MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); 84283514Sarybchik 85283514Sarybchik dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); 86283514Sarybchik addr = EFSYS_MEM_ADDR(esmp); 87283514Sarybchik 88283514Sarybchik for (i = 0; i < npages; i++) { 89283514Sarybchik EFX_POPULATE_QWORD_2(*dma_addr, 90283514Sarybchik EFX_DWORD_1, (uint32_t)(addr >> 32), 91283514Sarybchik EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); 92283514Sarybchik 93283514Sarybchik dma_addr++; 94283514Sarybchik addr += EFX_BUF_SIZE; 95283514Sarybchik } 96283514Sarybchik 97283514Sarybchik efx_mcdi_execute(enp, &req); 98283514Sarybchik 99283514Sarybchik if (req.emr_rc != 0) { 100283514Sarybchik rc = req.emr_rc; 101283514Sarybchik goto fail1; 102283514Sarybchik } 103283514Sarybchik 104283514Sarybchik return (0); 105283514Sarybchik 106283514Sarybchikfail1: 107291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 108283514Sarybchik 109283514Sarybchik return (rc); 110283514Sarybchik} 111283514Sarybchik 112291436Sarybchikstatic __checkReturn efx_rc_t 113283514Sarybchikefx_mcdi_fini_rxq( 114283514Sarybchik __in efx_nic_t *enp, 115283514Sarybchik __in uint32_t instance) 116283514Sarybchik{ 117283514Sarybchik efx_mcdi_req_t req; 118342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_RXQ_IN_LEN, 119342445Sarybchik MC_CMD_FINI_RXQ_OUT_LEN); 120291436Sarybchik efx_rc_t rc; 121283514Sarybchik 122283514Sarybchik req.emr_cmd = MC_CMD_FINI_RXQ; 123283514Sarybchik req.emr_in_buf = payload; 124283514Sarybchik req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN; 125283514Sarybchik req.emr_out_buf = payload; 126283514Sarybchik req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN; 127283514Sarybchik 128283514Sarybchik MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance); 129283514Sarybchik 130299925Sarybchik efx_mcdi_execute_quiet(enp, &req); 131283514Sarybchik 132342412Sarybchik if (req.emr_rc != 0) { 133283514Sarybchik rc = req.emr_rc; 134283514Sarybchik goto fail1; 135283514Sarybchik } 136283514Sarybchik 137283514Sarybchik return (0); 138283514Sarybchik 139283514Sarybchikfail1: 140342412Sarybchik /* 141342412Sarybchik * EALREADY is not an error, but indicates that the MC has rebooted and 142342412Sarybchik * that the RXQ has already been destroyed. 143342412Sarybchik */ 144342412Sarybchik if (rc != EALREADY) 145342412Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 146283514Sarybchik 147283514Sarybchik return (rc); 148283514Sarybchik} 149283514Sarybchik 150283514Sarybchik#if EFSYS_OPT_RX_SCALE 151291436Sarybchikstatic __checkReturn efx_rc_t 152283514Sarybchikefx_mcdi_rss_context_alloc( 153283514Sarybchik __in efx_nic_t *enp, 154293772Sarybchik __in efx_rx_scale_support_t scale_support, 155293772Sarybchik __in uint32_t num_queues, 156283514Sarybchik __out uint32_t *rss_contextp) 157283514Sarybchik{ 158283514Sarybchik efx_mcdi_req_t req; 159342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN, 160342445Sarybchik MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN); 161283514Sarybchik uint32_t rss_context; 162293772Sarybchik uint32_t context_type; 163291436Sarybchik efx_rc_t rc; 164283514Sarybchik 165293772Sarybchik if (num_queues > EFX_MAXRSS) { 166293772Sarybchik rc = EINVAL; 167293772Sarybchik goto fail1; 168293772Sarybchik } 169293772Sarybchik 170293772Sarybchik switch (scale_support) { 171293772Sarybchik case EFX_RX_SCALE_EXCLUSIVE: 172293772Sarybchik context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE; 173293772Sarybchik break; 174293772Sarybchik case EFX_RX_SCALE_SHARED: 175293772Sarybchik context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED; 176293772Sarybchik break; 177293772Sarybchik default: 178293772Sarybchik rc = EINVAL; 179293772Sarybchik goto fail2; 180293772Sarybchik } 181293772Sarybchik 182283514Sarybchik req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC; 183283514Sarybchik req.emr_in_buf = payload; 184283514Sarybchik req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN; 185283514Sarybchik req.emr_out_buf = payload; 186283514Sarybchik req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN; 187283514Sarybchik 188283514Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID, 189283514Sarybchik EVB_PORT_ID_ASSIGNED); 190293772Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type); 191283514Sarybchik /* NUM_QUEUES is only used to validate indirection table offsets */ 192293772Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues); 193283514Sarybchik 194283514Sarybchik efx_mcdi_execute(enp, &req); 195283514Sarybchik 196283514Sarybchik if (req.emr_rc != 0) { 197283514Sarybchik rc = req.emr_rc; 198293772Sarybchik goto fail3; 199283514Sarybchik } 200283514Sarybchik 201283514Sarybchik if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) { 202283514Sarybchik rc = EMSGSIZE; 203293772Sarybchik goto fail4; 204283514Sarybchik } 205283514Sarybchik 206283514Sarybchik rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); 207293754Sarybchik if (rss_context == EF10_RSS_CONTEXT_INVALID) { 208283514Sarybchik rc = ENOENT; 209293772Sarybchik goto fail5; 210283514Sarybchik } 211283514Sarybchik 212283514Sarybchik *rss_contextp = rss_context; 213283514Sarybchik 214283514Sarybchik return (0); 215283514Sarybchik 216293772Sarybchikfail5: 217293772Sarybchik EFSYS_PROBE(fail5); 218293772Sarybchikfail4: 219293772Sarybchik EFSYS_PROBE(fail4); 220283514Sarybchikfail3: 221283514Sarybchik EFSYS_PROBE(fail3); 222283514Sarybchikfail2: 223283514Sarybchik EFSYS_PROBE(fail2); 224283514Sarybchikfail1: 225291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 226283514Sarybchik 227283514Sarybchik return (rc); 228283514Sarybchik} 229283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 230283514Sarybchik 231283514Sarybchik#if EFSYS_OPT_RX_SCALE 232291436Sarybchikstatic efx_rc_t 233283514Sarybchikefx_mcdi_rss_context_free( 234283514Sarybchik __in efx_nic_t *enp, 235283514Sarybchik __in uint32_t rss_context) 236283514Sarybchik{ 237283514Sarybchik efx_mcdi_req_t req; 238342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_FREE_IN_LEN, 239342445Sarybchik MC_CMD_RSS_CONTEXT_FREE_OUT_LEN); 240291436Sarybchik efx_rc_t rc; 241283514Sarybchik 242293754Sarybchik if (rss_context == EF10_RSS_CONTEXT_INVALID) { 243283514Sarybchik rc = EINVAL; 244283514Sarybchik goto fail1; 245283514Sarybchik } 246283514Sarybchik 247283514Sarybchik req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE; 248283514Sarybchik req.emr_in_buf = payload; 249283514Sarybchik req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN; 250283514Sarybchik req.emr_out_buf = payload; 251283514Sarybchik req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN; 252283514Sarybchik 253283514Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context); 254283514Sarybchik 255299925Sarybchik efx_mcdi_execute_quiet(enp, &req); 256283514Sarybchik 257283514Sarybchik if (req.emr_rc != 0) { 258283514Sarybchik rc = req.emr_rc; 259283514Sarybchik goto fail2; 260283514Sarybchik } 261283514Sarybchik 262283514Sarybchik return (0); 263283514Sarybchik 264283514Sarybchikfail2: 265283514Sarybchik EFSYS_PROBE(fail2); 266283514Sarybchikfail1: 267291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 268283514Sarybchik 269283514Sarybchik return (rc); 270283514Sarybchik} 271283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 272283514Sarybchik 273283514Sarybchik#if EFSYS_OPT_RX_SCALE 274291436Sarybchikstatic efx_rc_t 275283514Sarybchikefx_mcdi_rss_context_set_flags( 276283514Sarybchik __in efx_nic_t *enp, 277283514Sarybchik __in uint32_t rss_context, 278283514Sarybchik __in efx_rx_hash_type_t type) 279283514Sarybchik{ 280283514Sarybchik efx_mcdi_req_t req; 281342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN, 282342445Sarybchik MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN); 283291436Sarybchik efx_rc_t rc; 284283514Sarybchik 285293754Sarybchik if (rss_context == EF10_RSS_CONTEXT_INVALID) { 286283514Sarybchik rc = EINVAL; 287283514Sarybchik goto fail1; 288283514Sarybchik } 289283514Sarybchik 290283514Sarybchik req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS; 291283514Sarybchik req.emr_in_buf = payload; 292283514Sarybchik req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN; 293283514Sarybchik req.emr_out_buf = payload; 294283514Sarybchik req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN; 295283514Sarybchik 296283514Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID, 297283514Sarybchik rss_context); 298283514Sarybchik 299283514Sarybchik MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS, 300283514Sarybchik RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN, 301311023Sarybchik (type & EFX_RX_HASH_IPV4) ? 1 : 0, 302283514Sarybchik RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN, 303311023Sarybchik (type & EFX_RX_HASH_TCPIPV4) ? 1 : 0, 304283514Sarybchik RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN, 305311023Sarybchik (type & EFX_RX_HASH_IPV6) ? 1 : 0, 306283514Sarybchik RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN, 307311023Sarybchik (type & EFX_RX_HASH_TCPIPV6) ? 1 : 0); 308283514Sarybchik 309283514Sarybchik efx_mcdi_execute(enp, &req); 310283514Sarybchik 311283514Sarybchik if (req.emr_rc != 0) { 312283514Sarybchik rc = req.emr_rc; 313283514Sarybchik goto fail2; 314283514Sarybchik } 315283514Sarybchik 316283514Sarybchik return (0); 317283514Sarybchik 318283514Sarybchikfail2: 319283514Sarybchik EFSYS_PROBE(fail2); 320283514Sarybchikfail1: 321291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 322283514Sarybchik 323283514Sarybchik return (rc); 324283514Sarybchik} 325283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 326283514Sarybchik 327283514Sarybchik#if EFSYS_OPT_RX_SCALE 328291436Sarybchikstatic efx_rc_t 329283514Sarybchikefx_mcdi_rss_context_set_key( 330283514Sarybchik __in efx_nic_t *enp, 331283514Sarybchik __in uint32_t rss_context, 332283514Sarybchik __in_ecount(n) uint8_t *key, 333283514Sarybchik __in size_t n) 334283514Sarybchik{ 335283514Sarybchik efx_mcdi_req_t req; 336342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN, 337342445Sarybchik MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN); 338291436Sarybchik efx_rc_t rc; 339283514Sarybchik 340293754Sarybchik if (rss_context == EF10_RSS_CONTEXT_INVALID) { 341283514Sarybchik rc = EINVAL; 342283514Sarybchik goto fail1; 343283514Sarybchik } 344283514Sarybchik 345283514Sarybchik req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY; 346283514Sarybchik req.emr_in_buf = payload; 347283514Sarybchik req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN; 348283514Sarybchik req.emr_out_buf = payload; 349283514Sarybchik req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN; 350283514Sarybchik 351283514Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID, 352283514Sarybchik rss_context); 353283514Sarybchik 354283514Sarybchik EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); 355283514Sarybchik if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) { 356283514Sarybchik rc = EINVAL; 357283514Sarybchik goto fail2; 358283514Sarybchik } 359283514Sarybchik 360283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY), 361283514Sarybchik key, n); 362283514Sarybchik 363283514Sarybchik efx_mcdi_execute(enp, &req); 364283514Sarybchik 365283514Sarybchik if (req.emr_rc != 0) { 366283514Sarybchik rc = req.emr_rc; 367283514Sarybchik goto fail3; 368283514Sarybchik } 369283514Sarybchik 370283514Sarybchik return (0); 371283514Sarybchik 372283514Sarybchikfail3: 373283514Sarybchik EFSYS_PROBE(fail3); 374283514Sarybchikfail2: 375283514Sarybchik EFSYS_PROBE(fail2); 376283514Sarybchikfail1: 377291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 378283514Sarybchik 379283514Sarybchik return (rc); 380283514Sarybchik} 381283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 382283514Sarybchik 383283514Sarybchik#if EFSYS_OPT_RX_SCALE 384291436Sarybchikstatic efx_rc_t 385283514Sarybchikefx_mcdi_rss_context_set_table( 386283514Sarybchik __in efx_nic_t *enp, 387283514Sarybchik __in uint32_t rss_context, 388283514Sarybchik __in_ecount(n) unsigned int *table, 389283514Sarybchik __in size_t n) 390283514Sarybchik{ 391283514Sarybchik efx_mcdi_req_t req; 392342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN, 393342445Sarybchik MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN); 394283514Sarybchik uint8_t *req_table; 395283514Sarybchik int i, rc; 396283514Sarybchik 397293754Sarybchik if (rss_context == EF10_RSS_CONTEXT_INVALID) { 398283514Sarybchik rc = EINVAL; 399283514Sarybchik goto fail1; 400283514Sarybchik } 401283514Sarybchik 402283514Sarybchik req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE; 403283514Sarybchik req.emr_in_buf = payload; 404283514Sarybchik req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN; 405283514Sarybchik req.emr_out_buf = payload; 406283514Sarybchik req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN; 407283514Sarybchik 408283514Sarybchik MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID, 409283514Sarybchik rss_context); 410283514Sarybchik 411283514Sarybchik req_table = 412283514Sarybchik MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE); 413283514Sarybchik 414283514Sarybchik for (i = 0; 415283514Sarybchik i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN; 416283514Sarybchik i++) { 417283514Sarybchik req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0; 418283514Sarybchik } 419283514Sarybchik 420283514Sarybchik efx_mcdi_execute(enp, &req); 421283514Sarybchik 422283514Sarybchik if (req.emr_rc != 0) { 423283514Sarybchik rc = req.emr_rc; 424283514Sarybchik goto fail2; 425283514Sarybchik } 426283514Sarybchik 427283514Sarybchik return (0); 428283514Sarybchik 429283514Sarybchikfail2: 430283514Sarybchik EFSYS_PROBE(fail2); 431283514Sarybchikfail1: 432291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 433283514Sarybchik 434283514Sarybchik return (rc); 435283514Sarybchik} 436283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 437283514Sarybchik 438283514Sarybchik 439291436Sarybchik __checkReturn efx_rc_t 440293754Sarybchikef10_rx_init( 441283514Sarybchik __in efx_nic_t *enp) 442283514Sarybchik{ 443283514Sarybchik#if EFSYS_OPT_RX_SCALE 444283514Sarybchik 445293772Sarybchik if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS, 446293772Sarybchik &enp->en_rss_context) == 0) { 447283514Sarybchik /* 448283514Sarybchik * Allocated an exclusive RSS context, which allows both the 449283514Sarybchik * indirection table and key to be modified. 450283514Sarybchik */ 451283514Sarybchik enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE; 452283514Sarybchik enp->en_hash_support = EFX_RX_HASH_AVAILABLE; 453283514Sarybchik } else { 454283514Sarybchik /* 455283514Sarybchik * Failed to allocate an exclusive RSS context. Continue 456283514Sarybchik * operation without support for RSS. The pseudo-header in 457283514Sarybchik * received packets will not contain a Toeplitz hash value. 458283514Sarybchik */ 459283514Sarybchik enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE; 460283514Sarybchik enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE; 461283514Sarybchik } 462283514Sarybchik 463283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 464283514Sarybchik 465283514Sarybchik return (0); 466283514Sarybchik} 467283514Sarybchik 468283514Sarybchik#if EFSYS_OPT_RX_SCATTER 469291436Sarybchik __checkReturn efx_rc_t 470293754Sarybchikef10_rx_scatter_enable( 471283514Sarybchik __in efx_nic_t *enp, 472283514Sarybchik __in unsigned int buf_size) 473283514Sarybchik{ 474283514Sarybchik _NOTE(ARGUNUSED(enp, buf_size)) 475283514Sarybchik return (0); 476283514Sarybchik} 477283514Sarybchik#endif /* EFSYS_OPT_RX_SCATTER */ 478283514Sarybchik 479283514Sarybchik#if EFSYS_OPT_RX_SCALE 480291436Sarybchik __checkReturn efx_rc_t 481293754Sarybchikef10_rx_scale_mode_set( 482283514Sarybchik __in efx_nic_t *enp, 483283514Sarybchik __in efx_rx_hash_alg_t alg, 484283514Sarybchik __in efx_rx_hash_type_t type, 485283514Sarybchik __in boolean_t insert) 486283514Sarybchik{ 487291436Sarybchik efx_rc_t rc; 488283514Sarybchik 489283514Sarybchik EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ); 490283514Sarybchik EFSYS_ASSERT3U(insert, ==, B_TRUE); 491283514Sarybchik 492283514Sarybchik if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) { 493283514Sarybchik rc = EINVAL; 494283514Sarybchik goto fail1; 495283514Sarybchik } 496283514Sarybchik 497283514Sarybchik if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { 498283514Sarybchik rc = ENOTSUP; 499283514Sarybchik goto fail2; 500283514Sarybchik } 501283514Sarybchik 502283514Sarybchik if ((rc = efx_mcdi_rss_context_set_flags(enp, 503283514Sarybchik enp->en_rss_context, type)) != 0) 504283514Sarybchik goto fail3; 505283514Sarybchik 506283514Sarybchik return (0); 507283514Sarybchik 508283514Sarybchikfail3: 509283514Sarybchik EFSYS_PROBE(fail3); 510283514Sarybchikfail2: 511283514Sarybchik EFSYS_PROBE(fail2); 512283514Sarybchikfail1: 513291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 514283514Sarybchik 515283514Sarybchik return (rc); 516283514Sarybchik} 517283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 518283514Sarybchik 519283514Sarybchik#if EFSYS_OPT_RX_SCALE 520291436Sarybchik __checkReturn efx_rc_t 521293754Sarybchikef10_rx_scale_key_set( 522283514Sarybchik __in efx_nic_t *enp, 523283514Sarybchik __in_ecount(n) uint8_t *key, 524283514Sarybchik __in size_t n) 525283514Sarybchik{ 526291436Sarybchik efx_rc_t rc; 527283514Sarybchik 528283514Sarybchik if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { 529283514Sarybchik rc = ENOTSUP; 530283514Sarybchik goto fail1; 531283514Sarybchik } 532283514Sarybchik 533283514Sarybchik if ((rc = efx_mcdi_rss_context_set_key(enp, 534283514Sarybchik enp->en_rss_context, key, n)) != 0) 535283514Sarybchik goto fail2; 536283514Sarybchik 537283514Sarybchik return (0); 538283514Sarybchik 539283514Sarybchikfail2: 540283514Sarybchik EFSYS_PROBE(fail2); 541283514Sarybchikfail1: 542291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 543283514Sarybchik 544283514Sarybchik return (rc); 545283514Sarybchik} 546283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 547283514Sarybchik 548283514Sarybchik#if EFSYS_OPT_RX_SCALE 549291436Sarybchik __checkReturn efx_rc_t 550293754Sarybchikef10_rx_scale_tbl_set( 551283514Sarybchik __in efx_nic_t *enp, 552283514Sarybchik __in_ecount(n) unsigned int *table, 553283514Sarybchik __in size_t n) 554283514Sarybchik{ 555291436Sarybchik efx_rc_t rc; 556283514Sarybchik 557283514Sarybchik if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { 558283514Sarybchik rc = ENOTSUP; 559283514Sarybchik goto fail1; 560283514Sarybchik } 561283514Sarybchik 562283514Sarybchik if ((rc = efx_mcdi_rss_context_set_table(enp, 563283514Sarybchik enp->en_rss_context, table, n)) != 0) 564283514Sarybchik goto fail2; 565283514Sarybchik 566283514Sarybchik return (0); 567283514Sarybchik 568283514Sarybchikfail2: 569283514Sarybchik EFSYS_PROBE(fail2); 570283514Sarybchikfail1: 571291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 572283514Sarybchik 573283514Sarybchik return (rc); 574283514Sarybchik} 575283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 576283514Sarybchik 577293807Sarybchik 578293807Sarybchik/* 579293807Sarybchik * EF10 RX pseudo-header 580293807Sarybchik * --------------------- 581293807Sarybchik * 582293807Sarybchik * Receive packets are prefixed by an (optional) 14 byte pseudo-header: 583293807Sarybchik * 584293807Sarybchik * +00: Toeplitz hash value. 585293807Sarybchik * (32bit little-endian) 586293807Sarybchik * +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag. 587293807Sarybchik * (16bit big-endian) 588293807Sarybchik * +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag. 589293807Sarybchik * (16bit big-endian) 590293807Sarybchik * +08: Packet Length. Zero if the RX datapath was in cut-through mode. 591293807Sarybchik * (16bit little-endian) 592293807Sarybchik * +10: MAC timestamp. Zero if timestamping is not enabled. 593293807Sarybchik * (32bit little-endian) 594293807Sarybchik * 595293807Sarybchik * See "The RX Pseudo-header" in SF-109306-TC. 596293807Sarybchik */ 597293807Sarybchik 598293807Sarybchik __checkReturn efx_rc_t 599293807Sarybchikef10_rx_prefix_pktlen( 600293807Sarybchik __in efx_nic_t *enp, 601293807Sarybchik __in uint8_t *buffer, 602293807Sarybchik __out uint16_t *lengthp) 603293807Sarybchik{ 604300840Sarybchik _NOTE(ARGUNUSED(enp)) 605300840Sarybchik 606293807Sarybchik /* 607293807Sarybchik * The RX pseudo-header contains the packet length, excluding the 608293807Sarybchik * pseudo-header. If the hardware receive datapath was operating in 609293807Sarybchik * cut-through mode then the length in the RX pseudo-header will be 610293807Sarybchik * zero, and the packet length must be obtained from the DMA length 611293807Sarybchik * reported in the RX event. 612293807Sarybchik */ 613293807Sarybchik *lengthp = buffer[8] | (buffer[9] << 8); 614293807Sarybchik return (0); 615293807Sarybchik} 616293807Sarybchik 617293807Sarybchik#if EFSYS_OPT_RX_SCALE 618293807Sarybchik __checkReturn uint32_t 619293807Sarybchikef10_rx_prefix_hash( 620293807Sarybchik __in efx_nic_t *enp, 621293807Sarybchik __in efx_rx_hash_alg_t func, 622293807Sarybchik __in uint8_t *buffer) 623293807Sarybchik{ 624300840Sarybchik _NOTE(ARGUNUSED(enp)) 625300840Sarybchik 626293807Sarybchik switch (func) { 627293807Sarybchik case EFX_RX_HASHALG_TOEPLITZ: 628293807Sarybchik return (buffer[0] | 629293807Sarybchik (buffer[1] << 8) | 630293807Sarybchik (buffer[2] << 16) | 631293807Sarybchik (buffer[3] << 24)); 632293807Sarybchik 633293807Sarybchik default: 634293807Sarybchik EFSYS_ASSERT(0); 635293807Sarybchik return (0); 636293807Sarybchik } 637293807Sarybchik} 638293807Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 639293807Sarybchik 640283514Sarybchik void 641293754Sarybchikef10_rx_qpost( 642283514Sarybchik __in efx_rxq_t *erp, 643283514Sarybchik __in_ecount(n) efsys_dma_addr_t *addrp, 644283514Sarybchik __in size_t size, 645283514Sarybchik __in unsigned int n, 646283514Sarybchik __in unsigned int completed, 647283514Sarybchik __in unsigned int added) 648283514Sarybchik{ 649283514Sarybchik efx_qword_t qword; 650283514Sarybchik unsigned int i; 651283514Sarybchik unsigned int offset; 652283514Sarybchik unsigned int id; 653283514Sarybchik 654342430Sarybchik _NOTE(ARGUNUSED(completed)) 655342430Sarybchik 656283514Sarybchik /* The client driver must not overfill the queue */ 657283514Sarybchik EFSYS_ASSERT3U(added - completed + n, <=, 658283514Sarybchik EFX_RXQ_LIMIT(erp->er_mask + 1)); 659283514Sarybchik 660283514Sarybchik id = added & (erp->er_mask); 661283514Sarybchik for (i = 0; i < n; i++) { 662283514Sarybchik EFSYS_PROBE4(rx_post, unsigned int, erp->er_index, 663283514Sarybchik unsigned int, id, efsys_dma_addr_t, addrp[i], 664283514Sarybchik size_t, size); 665283514Sarybchik 666283514Sarybchik EFX_POPULATE_QWORD_3(qword, 667283514Sarybchik ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size), 668283514Sarybchik ESF_DZ_RX_KER_BUF_ADDR_DW0, 669283514Sarybchik (uint32_t)(addrp[i] & 0xffffffff), 670283514Sarybchik ESF_DZ_RX_KER_BUF_ADDR_DW1, 671283514Sarybchik (uint32_t)(addrp[i] >> 32)); 672283514Sarybchik 673283514Sarybchik offset = id * sizeof (efx_qword_t); 674283514Sarybchik EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword); 675283514Sarybchik 676283514Sarybchik id = (id + 1) & (erp->er_mask); 677283514Sarybchik } 678283514Sarybchik} 679283514Sarybchik 680283514Sarybchik void 681293754Sarybchikef10_rx_qpush( 682283514Sarybchik __in efx_rxq_t *erp, 683283514Sarybchik __in unsigned int added, 684283514Sarybchik __inout unsigned int *pushedp) 685283514Sarybchik{ 686283514Sarybchik efx_nic_t *enp = erp->er_enp; 687283514Sarybchik unsigned int pushed = *pushedp; 688283514Sarybchik uint32_t wptr; 689283514Sarybchik efx_dword_t dword; 690283514Sarybchik 691283514Sarybchik /* Hardware has alignment restriction for WPTR */ 692350411Sarybchik wptr = EFX_P2ALIGN(unsigned int, added, EF10_RX_WPTR_ALIGN); 693283514Sarybchik if (pushed == wptr) 694283514Sarybchik return; 695283514Sarybchik 696283514Sarybchik *pushedp = wptr; 697283514Sarybchik 698283514Sarybchik /* Push the populated descriptors out */ 699283514Sarybchik wptr &= erp->er_mask; 700283514Sarybchik 701283514Sarybchik EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr); 702283514Sarybchik 703283514Sarybchik /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ 704283514Sarybchik EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1, 705283514Sarybchik wptr, pushed & erp->er_mask); 706283514Sarybchik EFSYS_PIO_WRITE_BARRIER(); 707283514Sarybchik EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG, 708283514Sarybchik erp->er_index, &dword, B_FALSE); 709283514Sarybchik} 710283514Sarybchik 711291436Sarybchik __checkReturn efx_rc_t 712293754Sarybchikef10_rx_qflush( 713283514Sarybchik __in efx_rxq_t *erp) 714283514Sarybchik{ 715283514Sarybchik efx_nic_t *enp = erp->er_enp; 716291436Sarybchik efx_rc_t rc; 717283514Sarybchik 718283514Sarybchik if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0) 719283514Sarybchik goto fail1; 720283514Sarybchik 721283514Sarybchik return (0); 722283514Sarybchik 723283514Sarybchikfail1: 724342412Sarybchik /* 725342412Sarybchik * EALREADY is not an error, but indicates that the MC has rebooted and 726342412Sarybchik * that the RXQ has already been destroyed. Callers need to know that 727342412Sarybchik * the RXQ flush has completed to avoid waiting until timeout for a 728342412Sarybchik * flush done event that will not be delivered. 729342412Sarybchik */ 730342412Sarybchik if (rc != EALREADY) 731342412Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 732283514Sarybchik 733283514Sarybchik return (rc); 734283514Sarybchik} 735283514Sarybchik 736283514Sarybchik void 737293754Sarybchikef10_rx_qenable( 738283514Sarybchik __in efx_rxq_t *erp) 739283514Sarybchik{ 740283514Sarybchik /* FIXME */ 741283514Sarybchik _NOTE(ARGUNUSED(erp)) 742283514Sarybchik /* FIXME */ 743283514Sarybchik} 744283514Sarybchik 745291436Sarybchik __checkReturn efx_rc_t 746293754Sarybchikef10_rx_qcreate( 747283514Sarybchik __in efx_nic_t *enp, 748283514Sarybchik __in unsigned int index, 749283514Sarybchik __in unsigned int label, 750283514Sarybchik __in efx_rxq_type_t type, 751283514Sarybchik __in efsys_mem_t *esmp, 752283514Sarybchik __in size_t n, 753283514Sarybchik __in uint32_t id, 754283514Sarybchik __in efx_evq_t *eep, 755283514Sarybchik __in efx_rxq_t *erp) 756283514Sarybchik{ 757283514Sarybchik efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 758291436Sarybchik efx_rc_t rc; 759291747Sarybchik boolean_t disable_scatter; 760283514Sarybchik 761300840Sarybchik _NOTE(ARGUNUSED(id, erp)) 762283514Sarybchik 763283514Sarybchik EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH)); 764283514Sarybchik EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS); 765283514Sarybchik EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit); 766283514Sarybchik 767283514Sarybchik EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS)); 768283514Sarybchik EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS)); 769283514Sarybchik 770283514Sarybchik if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) { 771283514Sarybchik rc = EINVAL; 772283514Sarybchik goto fail1; 773283514Sarybchik } 774283514Sarybchik if (index >= encp->enc_rxq_limit) { 775283514Sarybchik rc = EINVAL; 776283514Sarybchik goto fail2; 777283514Sarybchik } 778283514Sarybchik 779291747Sarybchik /* Scatter can only be disabled if the firmware supports doing so */ 780311018Sarybchik if (type == EFX_RXQ_TYPE_SCATTER) 781291747Sarybchik disable_scatter = B_FALSE; 782311018Sarybchik else 783311018Sarybchik disable_scatter = encp->enc_rx_disable_scatter_supported; 784291747Sarybchik 785283514Sarybchik if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index, 786291747Sarybchik esmp, disable_scatter)) != 0) 787283514Sarybchik goto fail3; 788283514Sarybchik 789283514Sarybchik erp->er_eep = eep; 790283514Sarybchik erp->er_label = label; 791283514Sarybchik 792293752Sarybchik ef10_ev_rxlabel_init(eep, erp, label); 793283514Sarybchik 794283514Sarybchik return (0); 795283514Sarybchik 796283514Sarybchikfail3: 797283514Sarybchik EFSYS_PROBE(fail3); 798283514Sarybchikfail2: 799283514Sarybchik EFSYS_PROBE(fail2); 800283514Sarybchikfail1: 801291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 802283514Sarybchik 803283514Sarybchik return (rc); 804283514Sarybchik} 805283514Sarybchik 806283514Sarybchik void 807293754Sarybchikef10_rx_qdestroy( 808283514Sarybchik __in efx_rxq_t *erp) 809283514Sarybchik{ 810283514Sarybchik efx_nic_t *enp = erp->er_enp; 811283514Sarybchik efx_evq_t *eep = erp->er_eep; 812283514Sarybchik unsigned int label = erp->er_label; 813283514Sarybchik 814293752Sarybchik ef10_ev_rxlabel_fini(eep, label); 815283514Sarybchik 816283514Sarybchik EFSYS_ASSERT(enp->en_rx_qcount != 0); 817283514Sarybchik --enp->en_rx_qcount; 818283514Sarybchik 819283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp); 820283514Sarybchik} 821283514Sarybchik 822283514Sarybchik void 823293754Sarybchikef10_rx_fini( 824283514Sarybchik __in efx_nic_t *enp) 825283514Sarybchik{ 826283514Sarybchik#if EFSYS_OPT_RX_SCALE 827283514Sarybchik if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) { 828283514Sarybchik (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context); 829283514Sarybchik } 830283514Sarybchik enp->en_rss_context = 0; 831283514Sarybchik enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE; 832283514Sarybchik#else 833283514Sarybchik _NOTE(ARGUNUSED(enp)) 834283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */ 835283514Sarybchik} 836283514Sarybchik 837299604Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 838