Commit 82ef30f1 authored by Netanel Belgazal's avatar Netanel Belgazal Committed by David S. Miller

net: ena: add hardware hints capability to the driver

With this patch, ENA device can update the ena driver about
the desired timeout values:
These values are part of the "hardware hints" which are transmitted
to the driver as Asynchronous event through ENA async
event notification queue.

In case the ENA device does not support this capability,
the driver will use its own default values.
Signed-off-by: default avatarNetanel Belgazal <netanel@amazon.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d1497638
...@@ -70,6 +70,8 @@ enum ena_admin_aq_feature_id { ...@@ -70,6 +70,8 @@ enum ena_admin_aq_feature_id {
ENA_ADMIN_MAX_QUEUES_NUM = 2, ENA_ADMIN_MAX_QUEUES_NUM = 2,
ENA_ADMIN_HW_HINTS = 3,
ENA_ADMIN_RSS_HASH_FUNCTION = 10, ENA_ADMIN_RSS_HASH_FUNCTION = 10,
ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11, ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11,
...@@ -749,6 +751,31 @@ struct ena_admin_feature_rss_ind_table { ...@@ -749,6 +751,31 @@ struct ena_admin_feature_rss_ind_table {
struct ena_admin_rss_ind_table_entry inline_entry; struct ena_admin_rss_ind_table_entry inline_entry;
}; };
/* When hint value is 0, driver should use it's own predefined value */
struct ena_admin_ena_hw_hints {
/* value in ms */
u16 mmio_read_timeout;
/* value in ms */
u16 driver_watchdog_timeout;
/* Per packet tx completion timeout. value in ms */
u16 missing_tx_completion_timeout;
u16 missed_tx_completion_count_threshold_to_reset;
/* value in ms */
u16 admin_completion_tx_timeout;
u16 netdev_wd_timeout;
u16 max_tx_sgl_size;
u16 max_rx_sgl_size;
u16 reserved[8];
};
struct ena_admin_get_feat_cmd { struct ena_admin_get_feat_cmd {
struct ena_admin_aq_common_desc aq_common_descriptor; struct ena_admin_aq_common_desc aq_common_descriptor;
...@@ -782,6 +809,8 @@ struct ena_admin_get_feat_resp { ...@@ -782,6 +809,8 @@ struct ena_admin_get_feat_resp {
struct ena_admin_feature_rss_ind_table ind_table; struct ena_admin_feature_rss_ind_table ind_table;
struct ena_admin_feature_intr_moder_desc intr_moderation; struct ena_admin_feature_intr_moder_desc intr_moderation;
struct ena_admin_ena_hw_hints hw_hints;
} u; } u;
}; };
...@@ -857,6 +886,8 @@ enum ena_admin_aenq_notification_syndrom { ...@@ -857,6 +886,8 @@ enum ena_admin_aenq_notification_syndrom {
ENA_ADMIN_SUSPEND = 0, ENA_ADMIN_SUSPEND = 0,
ENA_ADMIN_RESUME = 1, ENA_ADMIN_RESUME = 1,
ENA_ADMIN_UPDATE_HINTS = 2,
}; };
struct ena_admin_aenq_entry { struct ena_admin_aenq_entry {
......
...@@ -511,7 +511,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c ...@@ -511,7 +511,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c
unsigned long flags, timeout; unsigned long flags, timeout;
int ret; int ret;
timeout = jiffies + ADMIN_CMD_TIMEOUT_US; timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout);
while (1) { while (1) {
spin_lock_irqsave(&admin_queue->q_lock, flags); spin_lock_irqsave(&admin_queue->q_lock, flags);
...@@ -561,7 +561,8 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com ...@@ -561,7 +561,8 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com
int ret; int ret;
wait_for_completion_timeout(&comp_ctx->wait_event, wait_for_completion_timeout(&comp_ctx->wait_event,
usecs_to_jiffies(ADMIN_CMD_TIMEOUT_US)); usecs_to_jiffies(
admin_queue->completion_timeout));
/* In case the command wasn't completed find out the root cause. /* In case the command wasn't completed find out the root cause.
* There might be 2 kinds of errors * There might be 2 kinds of errors
...@@ -601,12 +602,15 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) ...@@ -601,12 +602,15 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp = volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp =
mmio_read->read_resp; mmio_read->read_resp;
u32 mmio_read_reg, ret; u32 mmio_read_reg, ret, i;
unsigned long flags; unsigned long flags;
int i; u32 timeout = mmio_read->reg_read_to;
might_sleep(); might_sleep();
if (timeout == 0)
timeout = ENA_REG_READ_TIMEOUT;
/* If readless is disabled, perform regular read */ /* If readless is disabled, perform regular read */
if (!mmio_read->readless_supported) if (!mmio_read->readless_supported)
return readl(ena_dev->reg_bar + offset); return readl(ena_dev->reg_bar + offset);
...@@ -627,14 +631,14 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) ...@@ -627,14 +631,14 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF); writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF);
for (i = 0; i < ENA_REG_READ_TIMEOUT; i++) { for (i = 0; i < timeout; i++) {
if (read_resp->req_id == mmio_read->seq_num) if (read_resp->req_id == mmio_read->seq_num)
break; break;
udelay(1); udelay(1);
} }
if (unlikely(i == ENA_REG_READ_TIMEOUT)) { if (unlikely(i == timeout)) {
pr_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n", pr_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n",
mmio_read->seq_num, offset, read_resp->req_id, mmio_read->seq_num, offset, read_resp->req_id,
read_resp->reg_off); read_resp->reg_off);
...@@ -1730,6 +1734,20 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, ...@@ -1730,6 +1734,20 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
memcpy(&get_feat_ctx->offload, &get_resp.u.offload, memcpy(&get_feat_ctx->offload, &get_resp.u.offload,
sizeof(get_resp.u.offload)); sizeof(get_resp.u.offload));
/* Driver hints isn't mandatory admin command. So in case the
* command isn't supported set driver hints to 0
*/
rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS);
if (!rc)
memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints,
sizeof(get_resp.u.hw_hints));
else if (rc == -EOPNOTSUPP)
memset(&get_feat_ctx->hw_hints, 0x0,
sizeof(get_feat_ctx->hw_hints));
else
return rc;
return 0; return 0;
} }
...@@ -1855,6 +1873,14 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev) ...@@ -1855,6 +1873,14 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev)
return rc; return rc;
} }
timeout = (cap & ENA_REGS_CAPS_ADMIN_CMD_TO_MASK) >>
ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT;
if (timeout)
/* the resolution of timeout reg is 100ms */
ena_dev->admin_queue.completion_timeout = timeout * 100000;
else
ena_dev->admin_queue.completion_timeout = ADMIN_CMD_TIMEOUT_US;
return 0; return 0;
} }
......
...@@ -97,6 +97,8 @@ ...@@ -97,6 +97,8 @@
#define ENA_INTR_MODER_LEVEL_STRIDE 2 #define ENA_INTR_MODER_LEVEL_STRIDE 2
#define ENA_INTR_BYTE_COUNT_NOT_SUPPORTED 0xFFFFFF #define ENA_INTR_BYTE_COUNT_NOT_SUPPORTED 0xFFFFFF
#define ENA_HW_HINTS_NO_TIMEOUT 0xFFFF
enum ena_intr_moder_level { enum ena_intr_moder_level {
ENA_INTR_MODER_LOWEST = 0, ENA_INTR_MODER_LOWEST = 0,
ENA_INTR_MODER_LOW, ENA_INTR_MODER_LOW,
...@@ -232,7 +234,9 @@ struct ena_com_stats_admin { ...@@ -232,7 +234,9 @@ struct ena_com_stats_admin {
struct ena_com_admin_queue { struct ena_com_admin_queue {
void *q_dmadev; void *q_dmadev;
spinlock_t q_lock; /* spinlock for the admin queue */ spinlock_t q_lock; /* spinlock for the admin queue */
struct ena_comp_ctx *comp_ctx; struct ena_comp_ctx *comp_ctx;
u32 completion_timeout;
u16 q_depth; u16 q_depth;
struct ena_com_admin_cq cq; struct ena_com_admin_cq cq;
struct ena_com_admin_sq sq; struct ena_com_admin_sq sq;
...@@ -267,6 +271,7 @@ struct ena_com_aenq { ...@@ -267,6 +271,7 @@ struct ena_com_aenq {
struct ena_com_mmio_read { struct ena_com_mmio_read {
struct ena_admin_ena_mmio_req_read_less_resp *read_resp; struct ena_admin_ena_mmio_req_read_less_resp *read_resp;
dma_addr_t read_resp_dma_addr; dma_addr_t read_resp_dma_addr;
u32 reg_read_to; /* in us */
u16 seq_num; u16 seq_num;
bool readless_supported; bool readless_supported;
/* spin lock to ensure a single outstanding read */ /* spin lock to ensure a single outstanding read */
...@@ -336,6 +341,7 @@ struct ena_com_dev_get_features_ctx { ...@@ -336,6 +341,7 @@ struct ena_com_dev_get_features_ctx {
struct ena_admin_device_attr_feature_desc dev_attr; struct ena_admin_device_attr_feature_desc dev_attr;
struct ena_admin_feature_aenq_desc aenq; struct ena_admin_feature_aenq_desc aenq;
struct ena_admin_feature_offload_desc offload; struct ena_admin_feature_offload_desc offload;
struct ena_admin_ena_hw_hints hw_hints;
}; };
struct ena_com_create_io_ctx { struct ena_com_create_io_ctx {
......
...@@ -2577,7 +2577,7 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, ...@@ -2577,7 +2577,7 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter,
tx_buf = &tx_ring->tx_buffer_info[i]; tx_buf = &tx_ring->tx_buffer_info[i];
last_jiffies = tx_buf->last_jiffies; last_jiffies = tx_buf->last_jiffies;
if (unlikely(last_jiffies && if (unlikely(last_jiffies &&
time_is_before_jiffies(last_jiffies + TX_TIMEOUT))) { time_is_before_jiffies(last_jiffies + adapter->missing_tx_completion_to))) {
if (!tx_buf->print_once) if (!tx_buf->print_once)
netif_notice(adapter, tx_err, adapter->netdev, netif_notice(adapter, tx_err, adapter->netdev,
"Found a Tx that wasn't completed on time, qid %d, index %d.\n", "Found a Tx that wasn't completed on time, qid %d, index %d.\n",
...@@ -2586,10 +2586,11 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, ...@@ -2586,10 +2586,11 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter,
tx_buf->print_once = 1; tx_buf->print_once = 1;
missed_tx++; missed_tx++;
if (unlikely(missed_tx > MAX_NUM_OF_TIMEOUTED_PACKETS)) { if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) {
netif_err(adapter, tx_err, adapter->netdev, netif_err(adapter, tx_err, adapter->netdev,
"The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n",
missed_tx, MAX_NUM_OF_TIMEOUTED_PACKETS); missed_tx,
adapter->missing_tx_completion_threshold);
set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
return -EIO; return -EIO;
} }
...@@ -2613,6 +2614,9 @@ static void check_for_missing_tx_completions(struct ena_adapter *adapter) ...@@ -2613,6 +2614,9 @@ static void check_for_missing_tx_completions(struct ena_adapter *adapter)
if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
return; return;
if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT)
return;
budget = ENA_MONITORED_TX_QUEUES; budget = ENA_MONITORED_TX_QUEUES;
for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) { for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) {
...@@ -2690,8 +2694,11 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter) ...@@ -2690,8 +2694,11 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter)
if (!adapter->wd_state) if (!adapter->wd_state)
return; return;
keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
+ ENA_DEVICE_KALIVE_TIMEOUT); return;
keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies +
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");
...@@ -2714,6 +2721,44 @@ static void check_for_admin_com_state(struct ena_adapter *adapter) ...@@ -2714,6 +2721,44 @@ static void check_for_admin_com_state(struct ena_adapter *adapter)
} }
} }
static void ena_update_hints(struct ena_adapter *adapter,
struct ena_admin_ena_hw_hints *hints)
{
struct net_device *netdev = adapter->netdev;
if (hints->admin_completion_tx_timeout)
adapter->ena_dev->admin_queue.completion_timeout =
hints->admin_completion_tx_timeout * 1000;
if (hints->mmio_read_timeout)
/* convert to usec */
adapter->ena_dev->mmio_read.reg_read_to =
hints->mmio_read_timeout * 1000;
if (hints->missed_tx_completion_count_threshold_to_reset)
adapter->missing_tx_completion_threshold =
hints->missed_tx_completion_count_threshold_to_reset;
if (hints->missing_tx_completion_timeout) {
if (hints->missing_tx_completion_timeout == ENA_HW_HINTS_NO_TIMEOUT)
adapter->missing_tx_completion_to = ENA_HW_HINTS_NO_TIMEOUT;
else
adapter->missing_tx_completion_to =
msecs_to_jiffies(hints->missing_tx_completion_timeout);
}
if (hints->netdev_wd_timeout)
netdev->watchdog_timeo = msecs_to_jiffies(hints->netdev_wd_timeout);
if (hints->driver_watchdog_timeout) {
if (hints->driver_watchdog_timeout == ENA_HW_HINTS_NO_TIMEOUT)
adapter->keep_alive_timeout = ENA_HW_HINTS_NO_TIMEOUT;
else
adapter->keep_alive_timeout =
msecs_to_jiffies(hints->driver_watchdog_timeout);
}
}
static void ena_update_host_info(struct ena_admin_host_info *host_info, static void ena_update_host_info(struct ena_admin_host_info *host_info,
struct net_device *netdev) struct net_device *netdev)
{ {
...@@ -3136,6 +3181,11 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -3136,6 +3181,11 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, ena_fw_reset_device); INIT_WORK(&adapter->reset_task, ena_fw_reset_device);
adapter->last_keep_alive_jiffies = jiffies; adapter->last_keep_alive_jiffies = jiffies;
adapter->keep_alive_timeout = ENA_DEVICE_KALIVE_TIMEOUT;
adapter->missing_tx_completion_to = TX_TIMEOUT;
adapter->missing_tx_completion_threshold = MAX_NUM_OF_TIMEOUTED_PACKETS;
ena_update_hints(adapter, &get_feat_ctx.hw_hints);
setup_timer(&adapter->timer_service, ena_timer_service, setup_timer(&adapter->timer_service, ena_timer_service,
(unsigned long)adapter); (unsigned long)adapter);
...@@ -3337,6 +3387,7 @@ static void ena_notification(void *adapter_data, ...@@ -3337,6 +3387,7 @@ static void ena_notification(void *adapter_data,
struct ena_admin_aenq_entry *aenq_e) struct ena_admin_aenq_entry *aenq_e)
{ {
struct ena_adapter *adapter = (struct ena_adapter *)adapter_data; struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
struct ena_admin_ena_hw_hints *hints;
WARN(aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION, WARN(aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION,
"Invalid group(%x) expected %x\n", "Invalid group(%x) expected %x\n",
...@@ -3354,6 +3405,11 @@ static void ena_notification(void *adapter_data, ...@@ -3354,6 +3405,11 @@ static void ena_notification(void *adapter_data,
case ENA_ADMIN_RESUME: case ENA_ADMIN_RESUME:
queue_work(ena_wq, &adapter->resume_io_task); queue_work(ena_wq, &adapter->resume_io_task);
break; break;
case ENA_ADMIN_UPDATE_HINTS:
hints = (struct ena_admin_ena_hw_hints *)
(&aenq_e->inline_data_w4);
ena_update_hints(adapter, hints);
break;
default: default:
netif_err(adapter, drv, adapter->netdev, netif_err(adapter, drv, adapter->netdev,
"Invalid aenq notification link state %d\n", "Invalid aenq notification link state %d\n",
......
...@@ -280,6 +280,8 @@ struct ena_adapter { ...@@ -280,6 +280,8 @@ struct ena_adapter {
int msix_vecs; int msix_vecs;
u32 missing_tx_completion_threshold;
u32 tx_usecs, rx_usecs; /* interrupt moderation */ u32 tx_usecs, rx_usecs; /* interrupt moderation */
u32 tx_frames, rx_frames; /* interrupt moderation */ u32 tx_frames, rx_frames; /* interrupt moderation */
...@@ -293,6 +295,9 @@ struct ena_adapter { ...@@ -293,6 +295,9 @@ struct ena_adapter {
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
unsigned long keep_alive_timeout;
unsigned long missing_tx_completion_to;
char name[ENA_NAME_MAX_LEN]; char name[ENA_NAME_MAX_LEN];
unsigned long flags; unsigned long flags;
......
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e #define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e
#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8 #define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8
#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00 #define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00
#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16
#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000
/* aq_caps register */ /* aq_caps register */
#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff #define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment