mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 16:41:39 +00:00
Merge branch 'Bug-fixes-for-ENA-Ethernet-driver'
Sameeh Jubran says: ==================== Bug fixes for ENA Ethernet driver Difference from V1: * Started using netdev_rss_key_fill() * Dropped superflous changes that are not related to bug fixes as requested by Jakub ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b44beb8ae5
@ -200,6 +200,11 @@ static void comp_ctxt_release(struct ena_com_admin_queue *queue,
|
|||||||
static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue,
|
static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue,
|
||||||
u16 command_id, bool capture)
|
u16 command_id, bool capture)
|
||||||
{
|
{
|
||||||
|
if (unlikely(!queue->comp_ctx)) {
|
||||||
|
pr_err("Completion context is NULL\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(command_id >= queue->q_depth)) {
|
if (unlikely(command_id >= queue->q_depth)) {
|
||||||
pr_err("command id is larger than the queue size. cmd_id: %u queue size %d\n",
|
pr_err("command id is larger than the queue size. cmd_id: %u queue size %d\n",
|
||||||
command_id, queue->q_depth);
|
command_id, queue->q_depth);
|
||||||
@ -1041,9 +1046,41 @@ static int ena_com_get_feature(struct ena_com_dev *ena_dev,
|
|||||||
feature_ver);
|
feature_ver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ena_com_get_current_hash_function(struct ena_com_dev *ena_dev)
|
||||||
|
{
|
||||||
|
return ena_dev->rss.hash_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ena_com_hash_key_fill_default_key(struct ena_com_dev *ena_dev)
|
||||||
|
{
|
||||||
|
struct ena_admin_feature_rss_flow_hash_control *hash_key =
|
||||||
|
(ena_dev->rss).hash_key;
|
||||||
|
|
||||||
|
netdev_rss_key_fill(&hash_key->key, sizeof(hash_key->key));
|
||||||
|
/* The key is stored in the device in u32 array
|
||||||
|
* as well as the API requires the key to be passed in this
|
||||||
|
* format. Thus the size of our array should be divided by 4
|
||||||
|
*/
|
||||||
|
hash_key->keys_num = sizeof(hash_key->key) / sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev)
|
static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev)
|
||||||
{
|
{
|
||||||
struct ena_rss *rss = &ena_dev->rss;
|
struct ena_rss *rss = &ena_dev->rss;
|
||||||
|
struct ena_admin_feature_rss_flow_hash_control *hash_key;
|
||||||
|
struct ena_admin_get_feat_resp get_resp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
hash_key = (ena_dev->rss).hash_key;
|
||||||
|
|
||||||
|
rc = ena_com_get_feature_ex(ena_dev, &get_resp,
|
||||||
|
ENA_ADMIN_RSS_HASH_FUNCTION,
|
||||||
|
ena_dev->rss.hash_key_dma_addr,
|
||||||
|
sizeof(ena_dev->rss.hash_key), 0);
|
||||||
|
if (unlikely(rc)) {
|
||||||
|
hash_key = NULL;
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
rss->hash_key =
|
rss->hash_key =
|
||||||
dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key),
|
dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key),
|
||||||
@ -1254,30 +1291,6 @@ static int ena_com_ind_tbl_convert_to_device(struct ena_com_dev *ena_dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ena_com_ind_tbl_convert_from_device(struct ena_com_dev *ena_dev)
|
|
||||||
{
|
|
||||||
u16 dev_idx_to_host_tbl[ENA_TOTAL_NUM_QUEUES] = { (u16)-1 };
|
|
||||||
struct ena_rss *rss = &ena_dev->rss;
|
|
||||||
u8 idx;
|
|
||||||
u16 i;
|
|
||||||
|
|
||||||
for (i = 0; i < ENA_TOTAL_NUM_QUEUES; i++)
|
|
||||||
dev_idx_to_host_tbl[ena_dev->io_sq_queues[i].idx] = i;
|
|
||||||
|
|
||||||
for (i = 0; i < 1 << rss->tbl_log_size; i++) {
|
|
||||||
if (rss->rss_ind_tbl[i].cq_idx > ENA_TOTAL_NUM_QUEUES)
|
|
||||||
return -EINVAL;
|
|
||||||
idx = (u8)rss->rss_ind_tbl[i].cq_idx;
|
|
||||||
|
|
||||||
if (dev_idx_to_host_tbl[idx] > ENA_TOTAL_NUM_QUEUES)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
rss->host_rss_ind_tbl[i] = dev_idx_to_host_tbl[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev,
|
static void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev,
|
||||||
u16 intr_delay_resolution)
|
u16 intr_delay_resolution)
|
||||||
{
|
{
|
||||||
@ -2297,15 +2310,16 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,
|
|||||||
|
|
||||||
switch (func) {
|
switch (func) {
|
||||||
case ENA_ADMIN_TOEPLITZ:
|
case ENA_ADMIN_TOEPLITZ:
|
||||||
if (key_len > sizeof(hash_key->key)) {
|
if (key) {
|
||||||
pr_err("key len (%hu) is bigger than the max supported (%zu)\n",
|
if (key_len != sizeof(hash_key->key)) {
|
||||||
key_len, sizeof(hash_key->key));
|
pr_err("key len (%hu) doesn't equal the supported size (%zu)\n",
|
||||||
return -EINVAL;
|
key_len, sizeof(hash_key->key));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
memcpy(hash_key->key, key, key_len);
|
||||||
|
rss->hash_init_val = init_val;
|
||||||
|
hash_key->keys_num = key_len >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(hash_key->key, key, key_len);
|
|
||||||
rss->hash_init_val = init_val;
|
|
||||||
hash_key->keys_num = key_len >> 2;
|
|
||||||
break;
|
break;
|
||||||
case ENA_ADMIN_CRC32:
|
case ENA_ADMIN_CRC32:
|
||||||
rss->hash_init_val = init_val;
|
rss->hash_init_val = init_val;
|
||||||
@ -2342,7 +2356,11 @@ int ena_com_get_hash_function(struct ena_com_dev *ena_dev,
|
|||||||
if (unlikely(rc))
|
if (unlikely(rc))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rss->hash_func = get_resp.u.flow_hash_func.selected_func;
|
/* ffs() returns 1 in case the lsb is set */
|
||||||
|
rss->hash_func = ffs(get_resp.u.flow_hash_func.selected_func);
|
||||||
|
if (rss->hash_func)
|
||||||
|
rss->hash_func--;
|
||||||
|
|
||||||
if (func)
|
if (func)
|
||||||
*func = rss->hash_func;
|
*func = rss->hash_func;
|
||||||
|
|
||||||
@ -2606,10 +2624,6 @@ int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl)
|
|||||||
if (!ind_tbl)
|
if (!ind_tbl)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rc = ena_com_ind_tbl_convert_from_device(ena_dev);
|
|
||||||
if (unlikely(rc))
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
for (i = 0; i < (1 << rss->tbl_log_size); i++)
|
for (i = 0; i < (1 << rss->tbl_log_size); i++)
|
||||||
ind_tbl[i] = rss->host_rss_ind_tbl[i];
|
ind_tbl[i] = rss->host_rss_ind_tbl[i];
|
||||||
|
|
||||||
@ -2626,9 +2640,15 @@ int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 indr_tbl_log_size)
|
|||||||
if (unlikely(rc))
|
if (unlikely(rc))
|
||||||
goto err_indr_tbl;
|
goto err_indr_tbl;
|
||||||
|
|
||||||
|
/* The following function might return unsupported in case the
|
||||||
|
* device doesn't support setting the key / hash function. We can safely
|
||||||
|
* ignore this error and have indirection table support only.
|
||||||
|
*/
|
||||||
rc = ena_com_hash_key_allocate(ena_dev);
|
rc = ena_com_hash_key_allocate(ena_dev);
|
||||||
if (unlikely(rc))
|
if (unlikely(rc) && rc != -EOPNOTSUPP)
|
||||||
goto err_hash_key;
|
goto err_hash_key;
|
||||||
|
else if (rc != -EOPNOTSUPP)
|
||||||
|
ena_com_hash_key_fill_default_key(ena_dev);
|
||||||
|
|
||||||
rc = ena_com_hash_ctrl_init(ena_dev);
|
rc = ena_com_hash_ctrl_init(ena_dev);
|
||||||
if (unlikely(rc))
|
if (unlikely(rc))
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
|
||||||
#include "ena_common_defs.h"
|
#include "ena_common_defs.h"
|
||||||
#include "ena_admin_defs.h"
|
#include "ena_admin_defs.h"
|
||||||
@ -655,6 +656,14 @@ int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 log_size);
|
|||||||
*/
|
*/
|
||||||
void ena_com_rss_destroy(struct ena_com_dev *ena_dev);
|
void ena_com_rss_destroy(struct ena_com_dev *ena_dev);
|
||||||
|
|
||||||
|
/* ena_com_get_current_hash_function - Get RSS hash function
|
||||||
|
* @ena_dev: ENA communication layer struct
|
||||||
|
*
|
||||||
|
* Return the current hash function.
|
||||||
|
* @return: 0 or one of the ena_admin_hash_functions values.
|
||||||
|
*/
|
||||||
|
int ena_com_get_current_hash_function(struct ena_com_dev *ena_dev);
|
||||||
|
|
||||||
/* ena_com_fill_hash_function - Fill RSS hash function
|
/* ena_com_fill_hash_function - Fill RSS hash function
|
||||||
* @ena_dev: ENA communication layer struct
|
* @ena_dev: ENA communication layer struct
|
||||||
* @func: The hash function (Toeplitz or crc)
|
* @func: The hash function (Toeplitz or crc)
|
||||||
|
@ -636,6 +636,28 @@ static u32 ena_get_rxfh_key_size(struct net_device *netdev)
|
|||||||
return ENA_HASH_KEY_SIZE;
|
return ENA_HASH_KEY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ena_indirection_table_get(struct ena_adapter *adapter, u32 *indir)
|
||||||
|
{
|
||||||
|
struct ena_com_dev *ena_dev = adapter->ena_dev;
|
||||||
|
int i, rc;
|
||||||
|
|
||||||
|
if (!indir)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = ena_com_indirect_table_get(ena_dev, indir);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Our internal representation of the indices is: even indices
|
||||||
|
* for Tx and uneven indices for Rx. We need to convert the Rx
|
||||||
|
* indices to be consecutive
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++)
|
||||||
|
indir[i] = ENA_IO_RXQ_IDX_TO_COMBINED_IDX(indir[i]);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||||
u8 *hfunc)
|
u8 *hfunc)
|
||||||
{
|
{
|
||||||
@ -644,11 +666,25 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
|||||||
u8 func;
|
u8 func;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = ena_com_indirect_table_get(adapter->ena_dev, indir);
|
rc = ena_indirection_table_get(adapter, indir);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/* We call this function in order to check if the device
|
||||||
|
* supports getting/setting the hash function.
|
||||||
|
*/
|
||||||
rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func, key);
|
rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func, key);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
if (rc == -EOPNOTSUPP) {
|
||||||
|
key = NULL;
|
||||||
|
hfunc = NULL;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -657,7 +693,7 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
|||||||
func = ETH_RSS_HASH_TOP;
|
func = ETH_RSS_HASH_TOP;
|
||||||
break;
|
break;
|
||||||
case ENA_ADMIN_CRC32:
|
case ENA_ADMIN_CRC32:
|
||||||
func = ETH_RSS_HASH_XOR;
|
func = ETH_RSS_HASH_CRC32;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
netif_err(adapter, drv, netdev,
|
netif_err(adapter, drv, netdev,
|
||||||
@ -700,10 +736,13 @@ static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (hfunc) {
|
switch (hfunc) {
|
||||||
|
case ETH_RSS_HASH_NO_CHANGE:
|
||||||
|
func = ena_com_get_current_hash_function(ena_dev);
|
||||||
|
break;
|
||||||
case ETH_RSS_HASH_TOP:
|
case ETH_RSS_HASH_TOP:
|
||||||
func = ENA_ADMIN_TOEPLITZ;
|
func = ENA_ADMIN_TOEPLITZ;
|
||||||
break;
|
break;
|
||||||
case ETH_RSS_HASH_XOR:
|
case ETH_RSS_HASH_CRC32:
|
||||||
func = ENA_ADMIN_CRC32;
|
func = ENA_ADMIN_CRC32;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -814,6 +853,7 @@ static const struct ethtool_ops ena_ethtool_ops = {
|
|||||||
.set_channels = ena_set_channels,
|
.set_channels = ena_set_channels,
|
||||||
.get_tunable = ena_get_tunable,
|
.get_tunable = ena_get_tunable,
|
||||||
.set_tunable = ena_set_tunable,
|
.set_tunable = ena_set_tunable,
|
||||||
|
.get_ts_info = ethtool_op_get_ts_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
void ena_set_ethtool_ops(struct net_device *netdev)
|
void ena_set_ethtool_ops(struct net_device *netdev)
|
||||||
|
@ -3706,8 +3706,8 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter)
|
|||||||
if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
|
if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies +
|
keep_alive_expired = adapter->last_keep_alive_jiffies +
|
||||||
adapter->keep_alive_timeout);
|
adapter->keep_alive_timeout;
|
||||||
if (unlikely(time_is_before_jiffies(keep_alive_expired))) {
|
if (unlikely(time_is_before_jiffies(keep_alive_expired))) {
|
||||||
netif_err(adapter, drv, adapter->netdev,
|
netif_err(adapter, drv, adapter->netdev,
|
||||||
"Keep alive watchdog timeout.\n");
|
"Keep alive watchdog timeout.\n");
|
||||||
@ -3809,7 +3809,7 @@ static void ena_timer_service(struct timer_list *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the timer */
|
/* Reset the timer */
|
||||||
mod_timer(&adapter->timer_service, jiffies + HZ);
|
mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ena_calc_max_io_queue_num(struct pci_dev *pdev,
|
static int ena_calc_max_io_queue_num(struct pci_dev *pdev,
|
||||||
|
@ -130,6 +130,8 @@
|
|||||||
|
|
||||||
#define ENA_IO_TXQ_IDX(q) (2 * (q))
|
#define ENA_IO_TXQ_IDX(q) (2 * (q))
|
||||||
#define ENA_IO_RXQ_IDX(q) (2 * (q) + 1)
|
#define ENA_IO_RXQ_IDX(q) (2 * (q) + 1)
|
||||||
|
#define ENA_IO_TXQ_IDX_TO_COMBINED_IDX(q) ((q) / 2)
|
||||||
|
#define ENA_IO_RXQ_IDX_TO_COMBINED_IDX(q) (((q) - 1) / 2)
|
||||||
|
|
||||||
#define ENA_MGMNT_IRQ_IDX 0
|
#define ENA_MGMNT_IRQ_IDX 0
|
||||||
#define ENA_IO_IRQ_FIRST_IDX 1
|
#define ENA_IO_IRQ_FIRST_IDX 1
|
||||||
|
Loading…
Reference in New Issue
Block a user