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 <nannaiah@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2497217
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com>
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
nannaiah
2021-03-11 11:09:17 -08:00
committed by Revanth Kumar Uppala
parent f4d30eb89b
commit 8c8eceeeb7
3 changed files with 33 additions and 11 deletions

View File

@@ -760,7 +760,7 @@ static void ether_start_ivc(struct ether_priv_data *pdata)
} }
ictxt->ivc_state = 1; ictxt->ivc_state = 1;
// initialize // initialize
raw_spin_lock_init(&ictxt->ivck_lock); spin_lock_init(&ictxt->ivck_lock);
} }
} }

View File

@@ -128,6 +128,23 @@
*/ */
#define ETHER_TX_MAX_FRAME_SIZE GSO_MAX_SIZE #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. * @brief Check if Tx data buffer length is within bounds.
* *
@@ -241,7 +258,7 @@ struct ether_ivc_ctxt {
/** ivc cookie */ /** ivc cookie */
struct tegra_hv_ivc_cookie *ivck; struct tegra_hv_ivc_cookie *ivck;
/** ivc lock */ /** ivc lock */
raw_spinlock_t ivck_lock; spinlock_t ivck_lock;
/** ivc work */ /** ivc work */
struct work_struct ivc_work; struct work_struct ivc_work;
/** wait for event */ /** wait for event */

View File

@@ -17,8 +17,6 @@
#include "ether_linux.h" #include "ether_linux.h"
#include <ivc_core.h> #include <ivc_core.h>
#define IVC_WAIT_TIMEOUT (msecs_to_jiffies(1000))
/** /**
* @brief Adds delay in micro seconds. * @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 ether_ivc_ctxt *ictxt = &pdata->ictxt;
struct tegra_hv_ivc_cookie *ivck = struct tegra_hv_ivc_cookie *ivck =
(struct tegra_hv_ivc_cookie *) ictxt->ivck; (struct tegra_hv_ivc_cookie *) ictxt->ivck;
int dcnt = 50; int dcnt = IVC_CHANNEL_TIMEOUT_CNT;
int is_atomic = 0; int is_atomic = 0;
if (len > ETHER_MAX_IVC_BUF) { if (len > ETHER_MAX_IVC_BUF) {
dev_err(pdata->dev, "Invalid IVC len\n"); 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; ivc_buf->status = -1;
raw_spin_lock_irqsave(&ictxt->ivck_lock, flags); spin_lock_irqsave(&ictxt->ivck_lock, flags);
if (in_atomic()) { if (in_atomic()) {
preempt_enable(); preempt_enable();
is_atomic = 1; is_atomic = 1;
@@ -458,7 +456,7 @@ int osd_ivc_send_cmd(void *priv, void *data, unsigned int len)
osd_msleep(1); osd_msleep(1);
dcnt--; dcnt--;
if (!dcnt) { if (!dcnt) {
pr_err("IVC recv timeout\n"); dev_err(pdata->dev, "IVC channel timeout\n");
goto fail; goto fail;
} }
} }
@@ -470,19 +468,26 @@ int osd_ivc_send_cmd(void *priv, void *data, unsigned int len)
len, ret, ivc_buf->cmd); len, ret, ivc_buf->cmd);
goto fail; 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); 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); ret = tegra_hv_ivc_read(ivck, ivc_buf, len);
if (ret < 0) { if (ret < 0) {
dev_err(pdata->dev, "IVC read failed: %d\n", ret); dev_err(pdata->dev, "IVC read failed: %d\n", ret);
} }
ret = ivc_buf->status;
fail:
if (is_atomic) { if (is_atomic) {
preempt_disable(); preempt_disable();
} }
ret = ivc_buf->status; spin_unlock_irqrestore(&ictxt->ivck_lock, flags);
fail:
raw_spin_unlock_irqrestore(&ictxt->ivck_lock, flags);
return ret; return ret;
} }