1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright (c) 2017-2018 Solarflare Communications Inc. 4 * All rights reserved. 5 * 6 * This software was jointly developed between OKTET Labs (under contract 7 * for Solarflare) and Solarflare Communications, Inc. 8 */ 9 10 #ifndef _SFC_EF10_H 11 #define _SFC_EF10_H 12 13 #ifdef __cplusplus 14 extern "C" { 15 #endif 16 17 /* Number of events in one cache line */ 18 #define SFC_EF10_EV_PER_CACHE_LINE \ 19 (RTE_CACHE_LINE_SIZE / sizeof(efx_qword_t)) 20 21 #define SFC_EF10_EV_QCLEAR_MASK (~(SFC_EF10_EV_PER_CACHE_LINE - 1)) 22 23 #if defined(SFC_EF10_EV_QCLEAR_USE_EFX) 24 static inline void 25 sfc_ef10_ev_qclear_cache_line(void *ptr) 26 { 27 efx_qword_t *entry = ptr; 28 unsigned int i; 29 30 for (i = 0; i < SFC_EF10_EV_PER_CACHE_LINE; ++i) 31 EFX_SET_QWORD(entry[i]); 32 } 33 #else 34 /* 35 * It is possible to do it using AVX2 and AVX512F, but it shows less 36 * performance. 37 */ 38 static inline void 39 sfc_ef10_ev_qclear_cache_line(void *ptr) 40 { 41 const __m128i val = _mm_set1_epi64x(UINT64_MAX); 42 __m128i *addr = ptr; 43 unsigned int i; 44 45 RTE_BUILD_BUG_ON(sizeof(val) > RTE_CACHE_LINE_SIZE); 46 RTE_BUILD_BUG_ON(RTE_CACHE_LINE_SIZE % sizeof(val) != 0); 47 48 for (i = 0; i < RTE_CACHE_LINE_SIZE / sizeof(val); ++i) 49 _mm_store_si128(&addr[i], val); 50 } 51 #endif 52 53 static inline void 54 sfc_ef10_ev_qclear(efx_qword_t *hw_ring, unsigned int ptr_mask, 55 unsigned int old_read_ptr, unsigned int read_ptr) 56 { 57 const unsigned int clear_ptr = read_ptr & SFC_EF10_EV_QCLEAR_MASK; 58 unsigned int old_clear_ptr = old_read_ptr & SFC_EF10_EV_QCLEAR_MASK; 59 60 while (old_clear_ptr != clear_ptr) { 61 sfc_ef10_ev_qclear_cache_line( 62 &hw_ring[old_clear_ptr & ptr_mask]); 63 old_clear_ptr += SFC_EF10_EV_PER_CACHE_LINE; 64 } 65 66 /* 67 * No barriers here. 68 * Functions which push doorbell should care about correct 69 * ordering: store instructions which fill in EvQ ring should be 70 * retired from CPU and DMA sync before doorbell which will allow 71 * to use these event entries. 72 */ 73 } 74 75 static inline bool 76 sfc_ef10_ev_present(const efx_qword_t ev) 77 { 78 return ~EFX_QWORD_FIELD(ev, EFX_DWORD_0) | 79 ~EFX_QWORD_FIELD(ev, EFX_DWORD_1); 80 } 81 82 83 /** 84 * Alignment requirement for value written to RX WPTR: 85 * the WPTR must be aligned to an 8 descriptor boundary. 86 */ 87 #define SFC_EF10_RX_WPTR_ALIGN 8u 88 89 static inline void 90 sfc_ef10_rx_qpush(volatile void *doorbell, unsigned int added, 91 unsigned int ptr_mask) 92 { 93 efx_dword_t dword; 94 95 /* Hardware has alignment restriction for WPTR */ 96 RTE_BUILD_BUG_ON(SFC_RX_REFILL_BULK % SFC_EF10_RX_WPTR_ALIGN != 0); 97 SFC_ASSERT(RTE_ALIGN(added, SFC_EF10_RX_WPTR_ALIGN) == added); 98 99 EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, added & ptr_mask); 100 101 /* DMA sync to device is not required */ 102 103 /* 104 * rte_write32() has rte_io_wmb() which guarantees that the STORE 105 * operations (i.e. Rx and event descriptor updates) that precede 106 * the rte_io_wmb() call are visible to NIC before the STORE 107 * operations that follow it (i.e. doorbell write). 108 */ 109 rte_write32(dword.ed_u32[0], doorbell); 110 } 111 112 static inline void 113 sfc_ef10_ev_qprime(volatile void *qprime, unsigned int read_ptr, 114 unsigned int ptr_mask) 115 { 116 efx_dword_t dword; 117 118 EFX_POPULATE_DWORD_1(dword, ERF_DZ_EVQ_RPTR, read_ptr & ptr_mask); 119 120 rte_write32_relaxed(dword.ed_u32[0], qprime); 121 rte_wmb(); 122 } 123 124 125 const uint32_t * sfc_ef10_supported_ptypes_get(uint32_t tunnel_encaps); 126 127 128 #ifdef __cplusplus 129 } 130 #endif 131 #endif /* _SFC_EF10_H */ 132