1986e7b92SArtur Rojek /*- 2986e7b92SArtur Rojek * SPDX-License-Identifier: BSD-2-Clause 3986e7b92SArtur Rojek * 4*8d6806cdSOsama Abboud * Copyright (c) 2015-2024 Amazon.com, Inc. or its affiliates. 5986e7b92SArtur Rojek * All rights reserved. 6986e7b92SArtur Rojek * 7986e7b92SArtur Rojek * Redistribution and use in source and binary forms, with or without 8986e7b92SArtur Rojek * modification, are permitted provided that the following conditions 9986e7b92SArtur Rojek * are met: 10986e7b92SArtur Rojek * 11986e7b92SArtur Rojek * 1. Redistributions of source code must retain the above copyright 12986e7b92SArtur Rojek * notice, this list of conditions and the following disclaimer. 13986e7b92SArtur Rojek * 14986e7b92SArtur Rojek * 2. Redistributions in binary form must reproduce the above copyright 15986e7b92SArtur Rojek * notice, this list of conditions and the following disclaimer in the 16986e7b92SArtur Rojek * documentation and/or other materials provided with the distribution. 17986e7b92SArtur Rojek * 18986e7b92SArtur Rojek * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19986e7b92SArtur Rojek * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20986e7b92SArtur Rojek * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21986e7b92SArtur Rojek * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22986e7b92SArtur Rojek * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23986e7b92SArtur Rojek * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24986e7b92SArtur Rojek * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25986e7b92SArtur Rojek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26986e7b92SArtur Rojek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27986e7b92SArtur Rojek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28986e7b92SArtur Rojek * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29986e7b92SArtur Rojek * 30986e7b92SArtur Rojek */ 31986e7b92SArtur Rojek 32986e7b92SArtur Rojek #include <sys/cdefs.h> 33986e7b92SArtur Rojek #include "opt_rss.h" 34986e7b92SArtur Rojek 35986e7b92SArtur Rojek #include "ena_rss.h" 36986e7b92SArtur Rojek 37986e7b92SArtur Rojek /* 38986e7b92SArtur Rojek * This function should generate unique key for the whole driver. 39986e7b92SArtur Rojek * If the key was already genereated in the previous call (for example 40986e7b92SArtur Rojek * for another adapter), then it should be returned instead. 41986e7b92SArtur Rojek */ 42986e7b92SArtur Rojek void 43986e7b92SArtur Rojek ena_rss_key_fill(void *key, size_t size) 44986e7b92SArtur Rojek { 45986e7b92SArtur Rojek static bool key_generated; 46986e7b92SArtur Rojek static uint8_t default_key[ENA_HASH_KEY_SIZE]; 47986e7b92SArtur Rojek 4882e558eaSDawid Gorecki KASSERT(size <= ENA_HASH_KEY_SIZE, 4982e558eaSDawid Gorecki ("Requested more bytes than ENA RSS key can hold")); 50986e7b92SArtur Rojek 51986e7b92SArtur Rojek if (!key_generated) { 52986e7b92SArtur Rojek arc4random_buf(default_key, ENA_HASH_KEY_SIZE); 53986e7b92SArtur Rojek key_generated = true; 54986e7b92SArtur Rojek } 55986e7b92SArtur Rojek 56986e7b92SArtur Rojek memcpy(key, default_key, size); 57986e7b92SArtur Rojek } 58986e7b92SArtur Rojek 596d1ef2abSArtur Rojek /* 606d1ef2abSArtur Rojek * ENA HW expects the key to be in reverse-byte order. 616d1ef2abSArtur Rojek */ 626d1ef2abSArtur Rojek static void 636d1ef2abSArtur Rojek ena_rss_reorder_hash_key(u8 *reordered_key, const u8 *key, size_t key_size) 646d1ef2abSArtur Rojek { 656d1ef2abSArtur Rojek int i; 666d1ef2abSArtur Rojek 676d1ef2abSArtur Rojek key = key + key_size - 1; 686d1ef2abSArtur Rojek 696d1ef2abSArtur Rojek for (i = 0; i < key_size; ++i) 706d1ef2abSArtur Rojek *reordered_key++ = *key--; 716d1ef2abSArtur Rojek } 726d1ef2abSArtur Rojek 7382e558eaSDawid Gorecki int 7482e558eaSDawid Gorecki ena_rss_set_hash(struct ena_com_dev *ena_dev, const u8 *key) 756d1ef2abSArtur Rojek { 766d1ef2abSArtur Rojek enum ena_admin_hash_functions ena_func = ENA_ADMIN_TOEPLITZ; 776d1ef2abSArtur Rojek u8 hw_key[ENA_HASH_KEY_SIZE]; 786d1ef2abSArtur Rojek 796d1ef2abSArtur Rojek ena_rss_reorder_hash_key(hw_key, key, ENA_HASH_KEY_SIZE); 806d1ef2abSArtur Rojek 816d1ef2abSArtur Rojek return (ena_com_fill_hash_function(ena_dev, ena_func, hw_key, 826d1ef2abSArtur Rojek ENA_HASH_KEY_SIZE, 0x0)); 836d1ef2abSArtur Rojek } 846d1ef2abSArtur Rojek 8582e558eaSDawid Gorecki int 8682e558eaSDawid Gorecki ena_rss_get_hash_key(struct ena_com_dev *ena_dev, u8 *key) 876d1ef2abSArtur Rojek { 886d1ef2abSArtur Rojek u8 hw_key[ENA_HASH_KEY_SIZE]; 896d1ef2abSArtur Rojek int rc; 906d1ef2abSArtur Rojek 916d1ef2abSArtur Rojek rc = ena_com_get_hash_key(ena_dev, hw_key); 926d1ef2abSArtur Rojek if (rc != 0) 936d1ef2abSArtur Rojek return rc; 946d1ef2abSArtur Rojek 956d1ef2abSArtur Rojek ena_rss_reorder_hash_key(key, hw_key, ENA_HASH_KEY_SIZE); 966d1ef2abSArtur Rojek 976d1ef2abSArtur Rojek return (0); 986d1ef2abSArtur Rojek } 996d1ef2abSArtur Rojek 100986e7b92SArtur Rojek static int 101986e7b92SArtur Rojek ena_rss_init_default(struct ena_adapter *adapter) 102986e7b92SArtur Rojek { 103986e7b92SArtur Rojek struct ena_com_dev *ena_dev = adapter->ena_dev; 104986e7b92SArtur Rojek device_t dev = adapter->pdev; 105986e7b92SArtur Rojek int qid, rc, i; 106986e7b92SArtur Rojek 107986e7b92SArtur Rojek rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE); 108986e7b92SArtur Rojek if (unlikely(rc != 0)) { 109986e7b92SArtur Rojek ena_log(dev, ERR, "Cannot init indirect table\n"); 110986e7b92SArtur Rojek return (rc); 111986e7b92SArtur Rojek } 112986e7b92SArtur Rojek 113986e7b92SArtur Rojek for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) { 1146d1ef2abSArtur Rojek #ifdef RSS 1156d1ef2abSArtur Rojek qid = rss_get_indirection_to_bucket(i) % adapter->num_io_queues; 1166d1ef2abSArtur Rojek #else 117986e7b92SArtur Rojek qid = i % adapter->num_io_queues; 1186d1ef2abSArtur Rojek #endif 119986e7b92SArtur Rojek rc = ena_com_indirect_table_fill_entry(ena_dev, i, 120986e7b92SArtur Rojek ENA_IO_RXQ_IDX(qid)); 121986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) { 122986e7b92SArtur Rojek ena_log(dev, ERR, "Cannot fill indirect table\n"); 123986e7b92SArtur Rojek goto err_rss_destroy; 124986e7b92SArtur Rojek } 125986e7b92SArtur Rojek } 126986e7b92SArtur Rojek 127986e7b92SArtur Rojek 128986e7b92SArtur Rojek #ifdef RSS 129986e7b92SArtur Rojek uint8_t rss_algo = rss_gethashalgo(); 130986e7b92SArtur Rojek if (rss_algo == RSS_HASH_TOEPLITZ) { 131986e7b92SArtur Rojek uint8_t hash_key[RSS_KEYSIZE]; 132986e7b92SArtur Rojek 133986e7b92SArtur Rojek rss_getkey(hash_key); 1346d1ef2abSArtur Rojek rc = ena_rss_set_hash(ena_dev, hash_key); 135986e7b92SArtur Rojek } else 136986e7b92SArtur Rojek #endif 13782e558eaSDawid Gorecki rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, 13882e558eaSDawid Gorecki NULL, ENA_HASH_KEY_SIZE, 0x0); 139986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) { 140986e7b92SArtur Rojek ena_log(dev, ERR, "Cannot fill hash function\n"); 141986e7b92SArtur Rojek goto err_rss_destroy; 142986e7b92SArtur Rojek } 143986e7b92SArtur Rojek 144986e7b92SArtur Rojek rc = ena_com_set_default_hash_ctrl(ena_dev); 145986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) { 146986e7b92SArtur Rojek ena_log(dev, ERR, "Cannot fill hash control\n"); 147986e7b92SArtur Rojek goto err_rss_destroy; 148986e7b92SArtur Rojek } 149986e7b92SArtur Rojek 1506d1ef2abSArtur Rojek rc = ena_rss_indir_init(adapter); 1516d1ef2abSArtur Rojek 1526d1ef2abSArtur Rojek return (rc == EOPNOTSUPP ? 0 : rc); 153986e7b92SArtur Rojek 154986e7b92SArtur Rojek err_rss_destroy: 155986e7b92SArtur Rojek ena_com_rss_destroy(ena_dev); 156986e7b92SArtur Rojek return (rc); 157986e7b92SArtur Rojek } 158986e7b92SArtur Rojek 159986e7b92SArtur Rojek /* Configure the Rx forwarding */ 160986e7b92SArtur Rojek int 161986e7b92SArtur Rojek ena_rss_configure(struct ena_adapter *adapter) 162986e7b92SArtur Rojek { 163986e7b92SArtur Rojek struct ena_com_dev *ena_dev = adapter->ena_dev; 164986e7b92SArtur Rojek int rc; 165986e7b92SArtur Rojek 166986e7b92SArtur Rojek /* In case the RSS table was destroyed */ 167986e7b92SArtur Rojek if (!ena_dev->rss.tbl_log_size) { 168986e7b92SArtur Rojek rc = ena_rss_init_default(adapter); 169986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) { 170986e7b92SArtur Rojek ena_log(adapter->pdev, ERR, 171986e7b92SArtur Rojek "WARNING: RSS was not properly re-initialized," 172986e7b92SArtur Rojek " it will affect bandwidth\n"); 173986e7b92SArtur Rojek ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_RSS_ACTIVE, adapter); 174986e7b92SArtur Rojek return (rc); 175986e7b92SArtur Rojek } 176986e7b92SArtur Rojek } 177986e7b92SArtur Rojek 178986e7b92SArtur Rojek /* Set indirect table */ 179986e7b92SArtur Rojek rc = ena_com_indirect_table_set(ena_dev); 180986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) 181986e7b92SArtur Rojek return (rc); 182986e7b92SArtur Rojek 183986e7b92SArtur Rojek /* Configure hash function (if supported) */ 184986e7b92SArtur Rojek rc = ena_com_set_hash_function(ena_dev); 185986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) 186986e7b92SArtur Rojek return (rc); 187986e7b92SArtur Rojek 188986e7b92SArtur Rojek /* Configure hash inputs (if supported) */ 189986e7b92SArtur Rojek rc = ena_com_set_hash_ctrl(ena_dev); 190986e7b92SArtur Rojek if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) 191986e7b92SArtur Rojek return (rc); 192986e7b92SArtur Rojek 193986e7b92SArtur Rojek return (0); 194986e7b92SArtur Rojek } 195986e7b92SArtur Rojek 196986e7b92SArtur Rojek static void 197986e7b92SArtur Rojek ena_rss_init_default_deferred(void *arg) 198986e7b92SArtur Rojek { 199986e7b92SArtur Rojek struct ena_adapter *adapter; 200986e7b92SArtur Rojek devclass_t dc; 201986e7b92SArtur Rojek int max; 202986e7b92SArtur Rojek int rc; 203986e7b92SArtur Rojek 204986e7b92SArtur Rojek dc = devclass_find("ena"); 205986e7b92SArtur Rojek if (unlikely(dc == NULL)) { 206986e7b92SArtur Rojek ena_log_raw(ERR, "SYSINIT: %s: No devclass ena\n", __func__); 207986e7b92SArtur Rojek return; 208986e7b92SArtur Rojek } 209986e7b92SArtur Rojek 210986e7b92SArtur Rojek max = devclass_get_maxunit(dc); 211986e7b92SArtur Rojek while (max-- >= 0) { 212986e7b92SArtur Rojek adapter = devclass_get_softc(dc, max); 213986e7b92SArtur Rojek if (adapter != NULL) { 214986e7b92SArtur Rojek rc = ena_rss_init_default(adapter); 215986e7b92SArtur Rojek ENA_FLAG_SET_ATOMIC(ENA_FLAG_RSS_ACTIVE, adapter); 216986e7b92SArtur Rojek if (unlikely(rc != 0)) { 217986e7b92SArtur Rojek ena_log(adapter->pdev, WARN, 218986e7b92SArtur Rojek "WARNING: RSS was not properly initialized," 219986e7b92SArtur Rojek " it will affect bandwidth\n"); 22082e558eaSDawid Gorecki ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_RSS_ACTIVE, 22182e558eaSDawid Gorecki adapter); 222986e7b92SArtur Rojek } 223986e7b92SArtur Rojek } 224986e7b92SArtur Rojek } 225986e7b92SArtur Rojek } 22682e558eaSDawid Gorecki SYSINIT(ena_rss_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_SECOND, 22782e558eaSDawid Gorecki ena_rss_init_default_deferred, NULL); 2286d1ef2abSArtur Rojek 2296d1ef2abSArtur Rojek int 2306d1ef2abSArtur Rojek ena_rss_indir_get(struct ena_adapter *adapter, uint32_t *table) 2316d1ef2abSArtur Rojek { 2326d1ef2abSArtur Rojek int rc, i; 2336d1ef2abSArtur Rojek 2346d1ef2abSArtur Rojek rc = ena_com_indirect_table_get(adapter->ena_dev, table); 2356d1ef2abSArtur Rojek if (rc != 0) { 2366d1ef2abSArtur Rojek if (rc == EOPNOTSUPP) 2376d1ef2abSArtur Rojek device_printf(adapter->pdev, 2386d1ef2abSArtur Rojek "Reading from indirection table not supported\n"); 2396d1ef2abSArtur Rojek else 2406d1ef2abSArtur Rojek device_printf(adapter->pdev, 2416d1ef2abSArtur Rojek "Unable to get indirection table\n"); 2426d1ef2abSArtur Rojek return (rc); 2436d1ef2abSArtur Rojek } 2446d1ef2abSArtur Rojek 2456d1ef2abSArtur Rojek for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; ++i) 2466d1ef2abSArtur Rojek table[i] = ENA_IO_RXQ_IDX_TO_COMBINED_IDX(table[i]); 2476d1ef2abSArtur Rojek 2486d1ef2abSArtur Rojek return (0); 2496d1ef2abSArtur Rojek } 2506d1ef2abSArtur Rojek 2516d1ef2abSArtur Rojek int 2526d1ef2abSArtur Rojek ena_rss_indir_set(struct ena_adapter *adapter, uint32_t *table) 2536d1ef2abSArtur Rojek { 2546d1ef2abSArtur Rojek int rc, i; 2556d1ef2abSArtur Rojek 2566d1ef2abSArtur Rojek for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; ++i) { 2576d1ef2abSArtur Rojek rc = ena_com_indirect_table_fill_entry(adapter->ena_dev, i, 2586d1ef2abSArtur Rojek ENA_IO_RXQ_IDX(table[i])); 2596d1ef2abSArtur Rojek if (rc != 0) { 2606d1ef2abSArtur Rojek device_printf(adapter->pdev, 2616d1ef2abSArtur Rojek "Cannot fill indirection table entry %d\n", i); 2626d1ef2abSArtur Rojek return (rc); 2636d1ef2abSArtur Rojek } 2646d1ef2abSArtur Rojek } 2656d1ef2abSArtur Rojek 2666d1ef2abSArtur Rojek rc = ena_com_indirect_table_set(adapter->ena_dev); 2676d1ef2abSArtur Rojek if (rc == EOPNOTSUPP) 2686d1ef2abSArtur Rojek device_printf(adapter->pdev, 2696d1ef2abSArtur Rojek "Writing to indirection table not supported\n"); 2706d1ef2abSArtur Rojek else if (rc != 0) 27182e558eaSDawid Gorecki device_printf(adapter->pdev, "Cannot set indirection table\n"); 2726d1ef2abSArtur Rojek 2736d1ef2abSArtur Rojek return (rc); 2746d1ef2abSArtur Rojek } 2756d1ef2abSArtur Rojek 2766d1ef2abSArtur Rojek int 2776d1ef2abSArtur Rojek ena_rss_indir_init(struct ena_adapter *adapter) 2786d1ef2abSArtur Rojek { 2796d1ef2abSArtur Rojek struct ena_indir *indir = adapter->rss_indir; 2806d1ef2abSArtur Rojek int rc; 2816d1ef2abSArtur Rojek 28251971340SZhenlei Huang if (indir == NULL) 2836d1ef2abSArtur Rojek adapter->rss_indir = indir = malloc(sizeof(struct ena_indir), 2846d1ef2abSArtur Rojek M_DEVBUF, M_WAITOK | M_ZERO); 2856d1ef2abSArtur Rojek 2866d1ef2abSArtur Rojek rc = ena_rss_indir_get(adapter, indir->table); 2876d1ef2abSArtur Rojek if (rc != 0) { 2886d1ef2abSArtur Rojek free(adapter->rss_indir, M_DEVBUF); 2896d1ef2abSArtur Rojek adapter->rss_indir = NULL; 2906d1ef2abSArtur Rojek 2916d1ef2abSArtur Rojek return (rc); 2926d1ef2abSArtur Rojek } 2936d1ef2abSArtur Rojek 2946d1ef2abSArtur Rojek ena_rss_copy_indir_buf(indir->sysctl_buf, indir->table); 2956d1ef2abSArtur Rojek 2966d1ef2abSArtur Rojek return (0); 2976d1ef2abSArtur Rojek } 298