From 88aef2f51c9e3640268aca04a256b8f26cf6bdff Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Tue, 17 Oct 2017 07:33:56 +0000 Subject: [PATCH 1/6] net: ena: improve ENA driver boot time. The ena admin commands timeout is in resolutions of 100ms. Therefore, When the driver works in polling mode, it sleeps for 100ms each time. The overall boot time of the ENA driver is ~1.5 sec. To reduce the boot time, This change modifies the granularity of the sleeps to 5ms. This change improves the boot time to 220ms. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index ded29af648c9..bf2de5298005 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -63,6 +63,8 @@ #define ENA_REGS_ADMIN_INTR_MASK 1 +#define ENA_POLL_MS 5 + /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ @@ -533,7 +535,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c goto err; } - msleep(100); + msleep(ENA_POLL_MS); } if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) { @@ -746,6 +748,9 @@ static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, { u32 val, i; + /* Convert timeout from resolution of 100ms to ENA_POLL_MS */ + timeout = (timeout * 100) / ENA_POLL_MS; + for (i = 0; i < timeout; i++) { val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); @@ -758,8 +763,7 @@ static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, exp_state) return 0; - /* The resolution of the timeout is 100ms */ - msleep(100); + msleep(ENA_POLL_MS); } return -ETIME; @@ -1253,7 +1257,7 @@ void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) spin_lock_irqsave(&admin_queue->q_lock, flags); while (atomic_read(&admin_queue->outstanding_cmds) != 0) { spin_unlock_irqrestore(&admin_queue->q_lock, flags); - msleep(20); + msleep(ENA_POLL_MS); spin_lock_irqsave(&admin_queue->q_lock, flags); } spin_unlock_irqrestore(&admin_queue->q_lock, flags); From dbeaf1e3c24f0e87c8047fc8dcbd8163ab82c8e7 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Tue, 17 Oct 2017 07:33:57 +0000 Subject: [PATCH 2/6] net: ena: remove legacy suspend suspend/resume support Remove ena_device_io_suspend/resume() methods Those methods were intend to be used by the device to trigger suspend/resume but eventually it was dropped. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 2 - drivers/net/ethernet/amazon/ena/ena_netdev.c | 50 ------------------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 4 -- 3 files changed, 56 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index b1212debc2e1..27b8f4618103 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -60,8 +60,6 @@ struct ena_stats { static const struct ena_stats ena_stats_global_strings[] = { ENA_STAT_GLOBAL_ENTRY(tx_timeout), - ENA_STAT_GLOBAL_ENTRY(io_suspend), - ENA_STAT_GLOBAL_ENTRY(io_resume), ENA_STAT_GLOBAL_ENTRY(wd_expired), ENA_STAT_GLOBAL_ENTRY(interface_up), ENA_STAT_GLOBAL_ENTRY(interface_down), diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index f7dc22f65d9f..6d8e1f1325e9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2361,38 +2361,6 @@ static const struct net_device_ops ena_netdev_ops = { #endif /* CONFIG_NET_POLL_CONTROLLER */ }; -static void ena_device_io_suspend(struct work_struct *work) -{ - struct ena_adapter *adapter = - container_of(work, struct ena_adapter, suspend_io_task); - struct net_device *netdev = adapter->netdev; - - /* ena_napi_disable_all disables only the IO handling. - * We are still subject to AENQ keep alive watchdog. - */ - u64_stats_update_begin(&adapter->syncp); - adapter->dev_stats.io_suspend++; - u64_stats_update_begin(&adapter->syncp); - ena_napi_disable_all(adapter); - netif_tx_lock(netdev); - netif_device_detach(netdev); - netif_tx_unlock(netdev); -} - -static void ena_device_io_resume(struct work_struct *work) -{ - struct ena_adapter *adapter = - container_of(work, struct ena_adapter, resume_io_task); - struct net_device *netdev = adapter->netdev; - - u64_stats_update_begin(&adapter->syncp); - adapter->dev_stats.io_resume++; - u64_stats_update_end(&adapter->syncp); - - netif_device_attach(netdev); - ena_napi_enable_all(adapter); -} - static int ena_device_validate_params(struct ena_adapter *adapter, struct ena_com_dev_get_features_ctx *get_feat_ctx) { @@ -3275,8 +3243,6 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_rss; } - INIT_WORK(&adapter->suspend_io_task, ena_device_io_suspend); - INIT_WORK(&adapter->resume_io_task, ena_device_io_resume); INIT_WORK(&adapter->reset_task, ena_fw_reset_device); adapter->last_keep_alive_jiffies = jiffies; @@ -3310,8 +3276,6 @@ err_free_msix: err_worker_destroy: ena_com_destroy_interrupt_moderation(ena_dev); del_timer(&adapter->timer_service); - cancel_work_sync(&adapter->suspend_io_task); - cancel_work_sync(&adapter->resume_io_task); err_netdev_destroy: free_netdev(netdev); err_device_destroy: @@ -3381,10 +3345,6 @@ static void ena_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->reset_task); - cancel_work_sync(&adapter->suspend_io_task); - - cancel_work_sync(&adapter->resume_io_task); - /* Reset the device only if the device is running. */ if (test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)) ena_com_dev_reset(ena_dev, adapter->reset_reason); @@ -3503,16 +3463,6 @@ static void ena_notification(void *adapter_data, ENA_ADMIN_NOTIFICATION); switch (aenq_e->aenq_common_desc.syndrom) { - case ENA_ADMIN_SUSPEND: - /* Suspend just the IO queues. - * We deliberately don't suspend admin so the timer and - * the keep_alive events should remain. - */ - queue_work(ena_wq, &adapter->suspend_io_task); - break; - case ENA_ADMIN_RESUME: - queue_work(ena_wq, &adapter->resume_io_task); - break; case ENA_ADMIN_UPDATE_HINTS: hints = (struct ena_admin_ena_hw_hints *) (&aenq_e->inline_data_w4); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 29bb5704260b..fb0c98bb9290 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -257,8 +257,6 @@ struct ena_ring { struct ena_stats_dev { u64 tx_timeout; - u64 io_suspend; - u64 io_resume; u64 wd_expired; u64 interface_up; u64 interface_down; @@ -326,8 +324,6 @@ struct ena_adapter { /* timer service */ struct work_struct reset_task; - struct work_struct suspend_io_task; - struct work_struct resume_io_task; struct timer_list timer_service; bool wd_state; From 8c5c7abdeb2dfe4b4b28a48702c2cfa83fac15c9 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Tue, 17 Oct 2017 07:33:58 +0000 Subject: [PATCH 3/6] net: ena: add power management ops to the ENA driver Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 2 + drivers/net/ethernet/amazon/ena/ena_netdev.c | 119 +++++++++++++----- drivers/net/ethernet/amazon/ena/ena_netdev.h | 3 + 3 files changed, 96 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 27b8f4618103..897e638a014a 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -60,6 +60,8 @@ struct ena_stats { static const struct ena_stats ena_stats_global_strings[] = { ENA_STAT_GLOBAL_ENTRY(tx_timeout), + ENA_STAT_GLOBAL_ENTRY(suspend), + ENA_STAT_GLOBAL_ENTRY(resume), ENA_STAT_GLOBAL_ENTRY(wd_expired), ENA_STAT_GLOBAL_ENTRY(interface_up), ENA_STAT_GLOBAL_ENTRY(interface_down), diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 6d8e1f1325e9..adc3957df3ab 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2529,38 +2529,31 @@ err_disable_msix: return rc; } -static void ena_fw_reset_device(struct work_struct *work) +static void ena_destroy_device(struct ena_adapter *adapter) { - struct ena_com_dev_get_features_ctx get_feat_ctx; - struct ena_adapter *adapter = - container_of(work, struct ena_adapter, reset_task); struct net_device *netdev = adapter->netdev; struct ena_com_dev *ena_dev = adapter->ena_dev; - struct pci_dev *pdev = adapter->pdev; - bool dev_up, wd_state; - int rc; - - if (unlikely(!test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) { - dev_err(&pdev->dev, - "device reset schedule while reset bit is off\n"); - return; - } + bool dev_up; netif_carrier_off(netdev); del_timer_sync(&adapter->timer_service); - rtnl_lock(); - dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags); + adapter->dev_up_before_reset = dev_up; + ena_com_set_admin_running_state(ena_dev, false); - /* After calling ena_close the tx queues and the napi - * are disabled so no one can interfere or touch the - * data structures - */ ena_close(netdev); + /* Before releasing the ENA resources, a device reset is required. + * (to prevent the device from accessing them). + * In case the reset flag is set and the device is up, ena_close + * already perform the reset, so it can be skipped. + */ + if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up)) + ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason); + ena_free_mgmnt_irq(adapter); ena_disable_msix(adapter); @@ -2574,9 +2567,17 @@ static void ena_fw_reset_device(struct work_struct *work) ena_com_mmio_reg_read_request_destroy(ena_dev); adapter->reset_reason = ENA_REGS_RESET_NORMAL; - clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); - /* Finish with the destroy part. Start the init part */ + clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); +} + +static int ena_restore_device(struct ena_adapter *adapter) +{ + struct ena_com_dev_get_features_ctx get_feat_ctx; + struct ena_com_dev *ena_dev = adapter->ena_dev; + struct pci_dev *pdev = adapter->pdev; + bool wd_state; + int rc; rc = ena_device_init(ena_dev, adapter->pdev, &get_feat_ctx, &wd_state); if (rc) { @@ -2598,7 +2599,7 @@ static void ena_fw_reset_device(struct work_struct *work) goto err_device_destroy; } /* If the interface was up before the reset bring it up */ - if (dev_up) { + if (adapter->dev_up_before_reset) { rc = ena_up(adapter); if (rc) { dev_err(&pdev->dev, "Failed to create I/O queues\n"); @@ -2607,24 +2608,38 @@ static void ena_fw_reset_device(struct work_struct *work) } mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ)); - - rtnl_unlock(); - dev_err(&pdev->dev, "Device reset completed successfully\n"); - return; + return rc; err_disable_msix: ena_free_mgmnt_irq(adapter); ena_disable_msix(adapter); err_device_destroy: ena_com_admin_destroy(ena_dev); err: - rtnl_unlock(); - clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags); dev_err(&pdev->dev, "Reset attempt failed. Can not reset the device\n"); + + return rc; +} + +static void ena_fw_reset_device(struct work_struct *work) +{ + struct ena_adapter *adapter = + container_of(work, struct ena_adapter, reset_task); + struct pci_dev *pdev = adapter->pdev; + + if (unlikely(!test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) { + dev_err(&pdev->dev, + "device reset schedule while reset bit is off\n"); + return; + } + rtnl_lock(); + ena_destroy_device(adapter); + ena_restore_device(adapter); + rtnl_unlock(); } static int check_missing_comp_in_queue(struct ena_adapter *adapter, @@ -3378,11 +3393,59 @@ static void ena_remove(struct pci_dev *pdev) vfree(ena_dev); } +#ifdef CONFIG_PM +/* ena_suspend - PM suspend callback + * @pdev: PCI device information struct + * @state:power state + */ +static int ena_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ena_adapter *adapter = pci_get_drvdata(pdev); + + u64_stats_update_begin(&adapter->syncp); + adapter->dev_stats.suspend++; + u64_stats_update_end(&adapter->syncp); + + rtnl_lock(); + if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) { + dev_err(&pdev->dev, + "ignoring device reset request as the device is being suspended\n"); + clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); + } + ena_destroy_device(adapter); + rtnl_unlock(); + return 0; +} + +/* ena_resume - PM resume callback + * @pdev: PCI device information struct + * + */ +static int ena_resume(struct pci_dev *pdev) +{ + struct ena_adapter *adapter = pci_get_drvdata(pdev); + int rc; + + u64_stats_update_begin(&adapter->syncp); + adapter->dev_stats.resume++; + u64_stats_update_end(&adapter->syncp); + + rtnl_lock(); + rc = ena_restore_device(adapter); + rtnl_unlock(); + return rc; +} +#endif + static struct pci_driver ena_pci_driver = { .name = DRV_MODULE_NAME, .id_table = ena_pci_tbl, .probe = ena_probe, .remove = ena_remove, +#ifdef CONFIG_PM + .suspend = ena_suspend, + .resume = ena_resume, +#endif .sriov_configure = ena_sriov_configure, }; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index fb0c98bb9290..7b07bfbf0fe4 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -257,6 +257,8 @@ struct ena_ring { struct ena_stats_dev { u64 tx_timeout; + u64 suspend; + u64 resume; u64 wd_expired; u64 interface_up; u64 interface_down; @@ -327,6 +329,7 @@ struct ena_adapter { struct timer_list timer_service; bool wd_state; + bool dev_up_before_reset; unsigned long last_keep_alive_jiffies; struct u64_stats_sync syncp; From 11095fdb712b1aaa7ffd6ccd86d0c45d29732eec Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Tue, 17 Oct 2017 07:33:59 +0000 Subject: [PATCH 4/6] net: ena: add statistics for missed tx packets Add a new statistic to ethtool stats that show the number of packets without transmit acknowledgement from ENA device. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 1 + drivers/net/ethernet/amazon/ena/ena_netdev.c | 30 +++++++++++-------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 1 + 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 897e638a014a..0d97311a1b26 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -81,6 +81,7 @@ static const struct ena_stats ena_stats_tx_strings[] = { ENA_STAT_TX_ENTRY(doorbells), ENA_STAT_TX_ENTRY(prepare_ctx_err), ENA_STAT_TX_ENTRY(bad_req_id), + ENA_STAT_TX_ENTRY(missed_tx), }; static const struct ena_stats ena_stats_rx_strings[] = { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index adc3957df3ab..47bdbf9bdefb 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2648,7 +2648,7 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, struct ena_tx_buffer *tx_buf; unsigned long last_jiffies; u32 missed_tx = 0; - int i; + int i, rc = 0; for (i = 0; i < tx_ring->ring_size; i++) { tx_buf = &tx_ring->tx_buffer_info[i]; @@ -2662,21 +2662,25 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, tx_buf->print_once = 1; missed_tx++; - - if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) { - netif_err(adapter, tx_err, adapter->netdev, - "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", - missed_tx, - adapter->missing_tx_completion_threshold); - adapter->reset_reason = - ENA_REGS_RESET_MISS_TX_CMPL; - set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); - return -EIO; - } } } - return 0; + if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) { + netif_err(adapter, tx_err, adapter->netdev, + "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", + missed_tx, + adapter->missing_tx_completion_threshold); + adapter->reset_reason = + ENA_REGS_RESET_MISS_TX_CMPL; + set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); + rc = -EIO; + } + + u64_stats_update_begin(&tx_ring->syncp); + tx_ring->tx_stats.missed_tx = missed_tx; + u64_stats_update_end(&tx_ring->syncp); + + return rc; } static void check_for_missing_tx_completions(struct ena_adapter *adapter) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 7b07bfbf0fe4..eafc5774dd49 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -185,6 +185,7 @@ struct ena_stats_tx { u64 tx_poll; u64 doorbells; u64 bad_req_id; + u64 missed_tx; }; struct ena_stats_rx { From 58894d5219c5d3fdd72d4166f007df5004817e84 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Tue, 17 Oct 2017 07:34:00 +0000 Subject: [PATCH 5/6] net: ena: add new admin define for future support of IPv6 RSS Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_admin_defs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h index 305dc1996b4e..4532e574ebcd 100644 --- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h @@ -627,6 +627,12 @@ enum ena_admin_flow_hash_proto { ENA_ADMIN_RSS_NOT_IP = 7, + /* TCPv6 with extension header */ + ENA_ADMIN_RSS_TCP6_EX = 8, + + /* IPv6 with extension header */ + ENA_ADMIN_RSS_IP6_EX = 9, + ENA_ADMIN_RSS_PROTO_NUM = 16, }; From 046b30718928d616f7decc79c272fdd4f42cc61d Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Tue, 17 Oct 2017 07:34:01 +0000 Subject: [PATCH 6/6] net: ena: increase ena driver version to 1.3.0 Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index eafc5774dd49..ed8bd0a579c4 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -44,7 +44,7 @@ #include "ena_eth_com.h" #define DRV_MODULE_VER_MAJOR 1 -#define DRV_MODULE_VER_MINOR 2 +#define DRV_MODULE_VER_MINOR 3 #define DRV_MODULE_VER_SUBMINOR 0 #define DRV_MODULE_NAME "ena" @@ -52,7 +52,7 @@ #define DRV_MODULE_VERSION \ __stringify(DRV_MODULE_VER_MAJOR) "." \ __stringify(DRV_MODULE_VER_MINOR) "." \ - __stringify(DRV_MODULE_VER_SUBMINOR) "k" + __stringify(DRV_MODULE_VER_SUBMINOR) "K" #endif #define DEVICE_NAME "Elastic Network Adapter (ENA)"