1227569Sphilip/*- 2301388Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc. 3284555Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6284555Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8284555Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9284555Sarybchik * this list of conditions and the following disclaimer. 10284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11284555Sarybchik * this list of conditions and the following disclaimer in the documentation 12284555Sarybchik * and/or other materials provided with the distribution. 13284555Sarybchik * 14284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15284555Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16284555Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17284555Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18284555Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19284555Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20284555Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21284555Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22284555Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23284555Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24284555Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25284555Sarybchik * 26284555Sarybchik * The views and conclusions contained in the software and documentation are 27284555Sarybchik * those of the authors and should not be interpreted as representing official 28284555Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD$"); 33228078Sphilip 34227569Sphilip#include "efx.h" 35227569Sphilip#include "efx_impl.h" 36227569Sphilip 37293927Sarybchik __checkReturn efx_rc_t 38227569Sphilipefx_sram_buf_tbl_set( 39227569Sphilip __in efx_nic_t *enp, 40227569Sphilip __in uint32_t id, 41227569Sphilip __in efsys_mem_t *esmp, 42227569Sphilip __in size_t n) 43227569Sphilip{ 44227569Sphilip efx_qword_t qword; 45227569Sphilip uint32_t start = id; 46227569Sphilip uint32_t stop = start + n; 47227569Sphilip efsys_dma_addr_t addr; 48227569Sphilip efx_oword_t oword; 49227569Sphilip unsigned int count; 50293927Sarybchik efx_rc_t rc; 51227569Sphilip 52227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 53227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 54227569Sphilip 55293984Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 56293984Sarybchik if (enp->en_family == EFX_FAMILY_HUNTINGTON || 57293984Sarybchik enp->en_family == EFX_FAMILY_MEDFORD) { 58284555Sarybchik /* 59284555Sarybchik * FIXME: the efx_sram_buf_tbl_*() functionality needs to be 60284555Sarybchik * pulled inside the Falcon/Siena queue create/destroy code, 61284555Sarybchik * and then the original functions can be removed (see bug30834 62284555Sarybchik * comment #1). But, for now, we just ensure that they are 63293984Sarybchik * no-ops for EF10, to allow bringing up existing drivers 64284555Sarybchik * without modification. 65284555Sarybchik */ 66284555Sarybchik 67284555Sarybchik return (0); 68284555Sarybchik } 69293984Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 70284555Sarybchik 71227569Sphilip if (stop >= EFX_BUF_TBL_SIZE) { 72227569Sphilip rc = EFBIG; 73227569Sphilip goto fail1; 74227569Sphilip } 75227569Sphilip 76227569Sphilip /* Add the entries into the buffer table */ 77227569Sphilip addr = EFSYS_MEM_ADDR(esmp); 78227569Sphilip for (id = start; id != stop; id++) { 79227569Sphilip EFX_POPULATE_QWORD_5(qword, 80227569Sphilip FRF_AZ_IP_DAT_BUF_SIZE, 0, FRF_AZ_BUF_ADR_REGION, 0, 81227569Sphilip FRF_AZ_BUF_ADR_FBUF_DW0, 82227569Sphilip (uint32_t)((addr >> 12) & 0xffffffff), 83227569Sphilip FRF_AZ_BUF_ADR_FBUF_DW1, 84227569Sphilip (uint32_t)((addr >> 12) >> 32), 85227569Sphilip FRF_AZ_BUF_OWNER_ID_FBUF, 0); 86227569Sphilip 87227569Sphilip EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_FULL_TBL, 88227569Sphilip id, &qword); 89227569Sphilip 90227569Sphilip addr += EFX_BUF_SIZE; 91227569Sphilip } 92227569Sphilip 93227569Sphilip EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1); 94227569Sphilip 95227569Sphilip /* Flush the write buffer */ 96227569Sphilip EFX_POPULATE_OWORD_2(oword, FRF_AZ_BUF_UPD_CMD, 1, 97227569Sphilip FRF_AZ_BUF_CLR_CMD, 0); 98227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword); 99227569Sphilip 100227569Sphilip /* Poll for the last entry being written to the buffer table */ 101227569Sphilip EFSYS_ASSERT3U(id, ==, stop); 102227569Sphilip addr -= EFX_BUF_SIZE; 103227569Sphilip 104227569Sphilip count = 0; 105227569Sphilip do { 106227569Sphilip EFSYS_PROBE1(wait, unsigned int, count); 107227569Sphilip 108227569Sphilip /* Spin for 1 ms */ 109227569Sphilip EFSYS_SPIN(1000); 110227569Sphilip 111227569Sphilip EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_FULL_TBL, 112227569Sphilip id - 1, &qword); 113227569Sphilip 114227569Sphilip if (EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW0) == 115227569Sphilip (uint32_t)((addr >> 12) & 0xffffffff) && 116227569Sphilip EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW1) == 117227569Sphilip (uint32_t)((addr >> 12) >> 32)) 118227569Sphilip goto verify; 119227569Sphilip 120227569Sphilip } while (++count < 100); 121227569Sphilip 122227569Sphilip rc = ETIMEDOUT; 123227569Sphilip goto fail2; 124227569Sphilip 125227569Sphilipverify: 126227569Sphilip /* Verify the rest of the entries in the buffer table */ 127227569Sphilip while (--id != start) { 128227569Sphilip addr -= EFX_BUF_SIZE; 129227569Sphilip 130227569Sphilip /* Read the buffer table entry */ 131227569Sphilip EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_FULL_TBL, 132227569Sphilip id - 1, &qword); 133227569Sphilip 134227569Sphilip if (EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW0) != 135227569Sphilip (uint32_t)((addr >> 12) & 0xffffffff) || 136227569Sphilip EFX_QWORD_FIELD(qword, FRF_AZ_BUF_ADR_FBUF_DW1) != 137227569Sphilip (uint32_t)((addr >> 12) >> 32)) { 138227569Sphilip rc = EFAULT; 139227569Sphilip goto fail3; 140227569Sphilip } 141227569Sphilip } 142227569Sphilip 143227569Sphilip return (0); 144227569Sphilip 145227569Sphilipfail3: 146227569Sphilip EFSYS_PROBE(fail3); 147227569Sphilip 148227569Sphilip id = stop; 149227569Sphilip 150227569Sphilipfail2: 151227569Sphilip EFSYS_PROBE(fail2); 152227569Sphilip 153227569Sphilip EFX_POPULATE_OWORD_4(oword, FRF_AZ_BUF_UPD_CMD, 0, 154227569Sphilip FRF_AZ_BUF_CLR_CMD, 1, FRF_AZ_BUF_CLR_END_ID, id - 1, 155227569Sphilip FRF_AZ_BUF_CLR_START_ID, start); 156227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword); 157227569Sphilip 158227569Sphilipfail1: 159293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 160227569Sphilip 161227569Sphilip return (rc); 162227569Sphilip} 163227569Sphilip 164227569Sphilip void 165227569Sphilipefx_sram_buf_tbl_clear( 166227569Sphilip __in efx_nic_t *enp, 167227569Sphilip __in uint32_t id, 168227569Sphilip __in size_t n) 169227569Sphilip{ 170227569Sphilip efx_oword_t oword; 171227569Sphilip uint32_t start = id; 172227569Sphilip uint32_t stop = start + n; 173227569Sphilip 174227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 175227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 176227569Sphilip 177293984Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 178293984Sarybchik if (enp->en_family == EFX_FAMILY_HUNTINGTON || 179293984Sarybchik enp->en_family == EFX_FAMILY_MEDFORD) { 180284555Sarybchik /* 181284555Sarybchik * FIXME: the efx_sram_buf_tbl_*() functionality needs to be 182284555Sarybchik * pulled inside the Falcon/Siena queue create/destroy code, 183284555Sarybchik * and then the original functions can be removed (see bug30834 184284555Sarybchik * comment #1). But, for now, we just ensure that they are 185293984Sarybchik * no-ops for EF10, to allow bringing up existing drivers 186284555Sarybchik * without modification. 187284555Sarybchik */ 188284555Sarybchik 189284555Sarybchik return; 190284555Sarybchik } 191293984Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 192284555Sarybchik 193227569Sphilip EFSYS_ASSERT3U(stop, <, EFX_BUF_TBL_SIZE); 194227569Sphilip 195227569Sphilip EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1); 196227569Sphilip 197227569Sphilip EFX_POPULATE_OWORD_4(oword, FRF_AZ_BUF_UPD_CMD, 0, 198227569Sphilip FRF_AZ_BUF_CLR_CMD, 1, FRF_AZ_BUF_CLR_END_ID, stop - 1, 199227569Sphilip FRF_AZ_BUF_CLR_START_ID, start); 200227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_UPD_REG, &oword); 201227569Sphilip} 202227569Sphilip 203227569Sphilip 204227569Sphilip#if EFSYS_OPT_DIAG 205227569Sphilip 206227569Sphilipstatic void 207227569Sphilipefx_sram_byte_increment_set( 208227569Sphilip __in size_t row, 209227569Sphilip __in boolean_t negate, 210227569Sphilip __out efx_qword_t *eqp) 211227569Sphilip{ 212227569Sphilip size_t offset = row * FR_AZ_SRM_DBG_REG_STEP; 213227569Sphilip unsigned int index; 214227569Sphilip 215227569Sphilip _NOTE(ARGUNUSED(negate)) 216227569Sphilip 217227569Sphilip for (index = 0; index < sizeof (efx_qword_t); index++) 218227569Sphilip eqp->eq_u8[index] = offset + index; 219227569Sphilip} 220227569Sphilip 221227569Sphilipstatic void 222227569Sphilipefx_sram_all_the_same_set( 223227569Sphilip __in size_t row, 224227569Sphilip __in boolean_t negate, 225227569Sphilip __out efx_qword_t *eqp) 226227569Sphilip{ 227227569Sphilip _NOTE(ARGUNUSED(row)) 228227569Sphilip 229227569Sphilip if (negate) 230227569Sphilip EFX_SET_QWORD(*eqp); 231227569Sphilip else 232227569Sphilip EFX_ZERO_QWORD(*eqp); 233227569Sphilip} 234227569Sphilip 235227569Sphilipstatic void 236227569Sphilipefx_sram_bit_alternate_set( 237227569Sphilip __in size_t row, 238227569Sphilip __in boolean_t negate, 239227569Sphilip __out efx_qword_t *eqp) 240227569Sphilip{ 241227569Sphilip _NOTE(ARGUNUSED(row)) 242227569Sphilip 243227569Sphilip EFX_POPULATE_QWORD_2(*eqp, 244227569Sphilip EFX_DWORD_0, (negate) ? 0x55555555 : 0xaaaaaaaa, 245227569Sphilip EFX_DWORD_1, (negate) ? 0x55555555 : 0xaaaaaaaa); 246227569Sphilip} 247227569Sphilip 248227569Sphilipstatic void 249227569Sphilipefx_sram_byte_alternate_set( 250227569Sphilip __in size_t row, 251227569Sphilip __in boolean_t negate, 252227569Sphilip __out efx_qword_t *eqp) 253227569Sphilip{ 254227569Sphilip _NOTE(ARGUNUSED(row)) 255227569Sphilip 256227569Sphilip EFX_POPULATE_QWORD_2(*eqp, 257227569Sphilip EFX_DWORD_0, (negate) ? 0x00ff00ff : 0xff00ff00, 258227569Sphilip EFX_DWORD_1, (negate) ? 0x00ff00ff : 0xff00ff00); 259227569Sphilip} 260227569Sphilip 261227569Sphilipstatic void 262227569Sphilipefx_sram_byte_changing_set( 263227569Sphilip __in size_t row, 264227569Sphilip __in boolean_t negate, 265227569Sphilip __out efx_qword_t *eqp) 266227569Sphilip{ 267227569Sphilip size_t offset = row * FR_AZ_SRM_DBG_REG_STEP; 268227569Sphilip unsigned int index; 269227569Sphilip 270227569Sphilip for (index = 0; index < sizeof (efx_qword_t); index++) { 271227569Sphilip uint8_t byte; 272227569Sphilip 273227569Sphilip if (offset / 256 == 0) 274227569Sphilip byte = (uint8_t)((offset % 257) % 256); 275227569Sphilip else 276227569Sphilip byte = (uint8_t)(~((offset - 8) % 257) % 256); 277227569Sphilip 278227569Sphilip eqp->eq_u8[index] = (negate) ? ~byte : byte; 279227569Sphilip } 280227569Sphilip} 281227569Sphilip 282227569Sphilipstatic void 283227569Sphilipefx_sram_bit_sweep_set( 284227569Sphilip __in size_t row, 285227569Sphilip __in boolean_t negate, 286227569Sphilip __out efx_qword_t *eqp) 287227569Sphilip{ 288227569Sphilip size_t offset = row * FR_AZ_SRM_DBG_REG_STEP; 289227569Sphilip 290227569Sphilip if (negate) { 291227569Sphilip EFX_SET_QWORD(*eqp); 292227569Sphilip EFX_CLEAR_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64); 293227569Sphilip } else { 294227569Sphilip EFX_ZERO_QWORD(*eqp); 295227569Sphilip EFX_SET_QWORD_BIT(*eqp, (offset / sizeof (efx_qword_t)) % 64); 296227569Sphilip } 297227569Sphilip} 298227569Sphilip 299284555Sarybchikefx_sram_pattern_fn_t __efx_sram_pattern_fns[] = { 300227569Sphilip efx_sram_byte_increment_set, 301227569Sphilip efx_sram_all_the_same_set, 302227569Sphilip efx_sram_bit_alternate_set, 303227569Sphilip efx_sram_byte_alternate_set, 304227569Sphilip efx_sram_byte_changing_set, 305227569Sphilip efx_sram_bit_sweep_set 306227569Sphilip}; 307227569Sphilip 308293927Sarybchik __checkReturn efx_rc_t 309227569Sphilipefx_sram_test( 310227569Sphilip __in efx_nic_t *enp, 311227569Sphilip __in efx_pattern_type_t type) 312227569Sphilip{ 313227569Sphilip efx_sram_pattern_fn_t func; 314227569Sphilip 315227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 316227569Sphilip 317227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 318227569Sphilip 319227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 320227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 321227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 322227569Sphilip 323301336Sarybchik /* SRAM testing is only available on Siena. */ 324301336Sarybchik if (enp->en_family != EFX_FAMILY_SIENA) 325301336Sarybchik return (0); 326301336Sarybchik 327227569Sphilip /* Select pattern generator */ 328227569Sphilip EFSYS_ASSERT3U(type, <, EFX_PATTERN_NTYPES); 329227569Sphilip func = __efx_sram_pattern_fns[type]; 330227569Sphilip 331301336Sarybchik return (siena_sram_test(enp, func)); 332227569Sphilip} 333227569Sphilip 334227569Sphilip#endif /* EFSYS_OPT_DIAG */ 335