From 8c8eceeeb71e02875697cd00d72af4f012cec34f Mon Sep 17 00:00:00 2001 From: nannaiah Date: Thu, 11 Mar 2021 11:09:17 -0800 Subject: [PATCH] nvethernet: Add IVC fix Issue: rt_spinlock causes IVC failures. Fix: 1. Change rt_spinlock to spinlock. 2. Add timeout to ivc_can_read. Bug 2694285 Change-Id: Ib603c304e750a33262e8509ed3f869030b934958 Signed-off-by: Nagaraj Annaiah Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2497217 Tested-by: mobile promotions Reviewed-by: Srinivas Ramachandran Reviewed-by: Ashutosh Jha Reviewed-by: mobile promotions GVS: Gerrit_Virtual_Submit --- .../ethernet/nvidia/nvethernet/ether_linux.c | 2 +- .../ethernet/nvidia/nvethernet/ether_linux.h | 19 ++++++++++++++- drivers/net/ethernet/nvidia/nvethernet/osd.c | 23 +++++++++++-------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index bccdc8f6..9553d470 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -760,7 +760,7 @@ static void ether_start_ivc(struct ether_priv_data *pdata) } ictxt->ivc_state = 1; // initialize - raw_spin_lock_init(&ictxt->ivck_lock); + spin_lock_init(&ictxt->ivck_lock); } } diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h index a936fc86..6629bf3a 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.h @@ -128,6 +128,23 @@ */ #define ETHER_TX_MAX_FRAME_SIZE GSO_MAX_SIZE +/** + * @brief IVC wait timeout. + */ +#define IVC_WAIT_TIMEOUT (msecs_to_jiffies(100)) + +/** + * @brief IVC read timeout cnt. + * used as 20*IVC_WAIT_TIMEOUT hence Max is 2 sec timeout. + */ +#define IVC_READ_TIMEOUT_CNT 20 + +/** + * @brief IVC channel timeout. + * Used with 1 millisec so max timeout is 50 ms. + */ +#define IVC_CHANNEL_TIMEOUT_CNT 50 + /** * @brief Check if Tx data buffer length is within bounds. * @@ -241,7 +258,7 @@ struct ether_ivc_ctxt { /** ivc cookie */ struct tegra_hv_ivc_cookie *ivck; /** ivc lock */ - raw_spinlock_t ivck_lock; + spinlock_t ivck_lock; /** ivc work */ struct work_struct ivc_work; /** wait for event */ diff --git a/drivers/net/ethernet/nvidia/nvethernet/osd.c b/drivers/net/ethernet/nvidia/nvethernet/osd.c index 14ee8316..88654fc9 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/osd.c +++ b/drivers/net/ethernet/nvidia/nvethernet/osd.c @@ -17,8 +17,6 @@ #include "ether_linux.h" #include -#define IVC_WAIT_TIMEOUT (msecs_to_jiffies(1000)) - /** * @brief Adds delay in micro seconds. * @@ -439,7 +437,7 @@ int osd_ivc_send_cmd(void *priv, void *data, unsigned int len) struct ether_ivc_ctxt *ictxt = &pdata->ictxt; struct tegra_hv_ivc_cookie *ivck = (struct tegra_hv_ivc_cookie *) ictxt->ivck; - int dcnt = 50; + int dcnt = IVC_CHANNEL_TIMEOUT_CNT; int is_atomic = 0; if (len > ETHER_MAX_IVC_BUF) { dev_err(pdata->dev, "Invalid IVC len\n"); @@ -447,7 +445,7 @@ int osd_ivc_send_cmd(void *priv, void *data, unsigned int len) } ivc_buf->status = -1; - raw_spin_lock_irqsave(&ictxt->ivck_lock, flags); + spin_lock_irqsave(&ictxt->ivck_lock, flags); if (in_atomic()) { preempt_enable(); is_atomic = 1; @@ -458,7 +456,7 @@ int osd_ivc_send_cmd(void *priv, void *data, unsigned int len) osd_msleep(1); dcnt--; if (!dcnt) { - pr_err("IVC recv timeout\n"); + dev_err(pdata->dev, "IVC channel timeout\n"); goto fail; } } @@ -470,19 +468,26 @@ int osd_ivc_send_cmd(void *priv, void *data, unsigned int len) len, ret, ivc_buf->cmd); goto fail; } - while (!tegra_hv_ivc_can_read(ictxt->ivck)) { + + dcnt = IVC_READ_TIMEOUT_CNT; + while ((!tegra_hv_ivc_can_read(ictxt->ivck))) { wait_for_completion_timeout(&ictxt->msg_complete, IVC_WAIT_TIMEOUT); + dcnt--; + if (!dcnt) { + dev_err(pdata->dev, "IVC read timeout\n"); + break; + } } ret = tegra_hv_ivc_read(ivck, ivc_buf, len); if (ret < 0) { dev_err(pdata->dev, "IVC read failed: %d\n", ret); } + ret = ivc_buf->status; +fail: if (is_atomic) { preempt_disable(); } - ret = ivc_buf->status; -fail: - raw_spin_unlock_irqrestore(&ictxt->ivck_lock, flags); + spin_unlock_irqrestore(&ictxt->ivck_lock, flags); return ret; }