From 4facb13a80f45510d3f70ac1b471e87a781aa219 Mon Sep 17 00:00:00 2001
From: Grygorii Strashko <grygorii.strashko@ti.com>
Date: Thu, 29 Apr 2021 18:13:32 +0300
Subject: [PATCH] net: ethernet: ti: icss_iep: improve icss_iep_gettime

There are few issues with icss_iep_gettime():
- it has to be very fast, but it's not protected from interruption
- it uses regmap which is very slow for time critial code

hence, improve it:
- protect it by local_irq_save/restore to avoid interruption and work for
both RT/non-RT kernels
- replace regmap with readl()

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
---
 drivers/net/ethernet/ti/icss_iep.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/ti/icss_iep.c b/drivers/net/ethernet/ti/icss_iep.c
index ead1e7c94021..cbec01328a71 100644
--- a/drivers/net/ethernet/ti/icss_iep.c
+++ b/drivers/net/ethernet/ti/icss_iep.c
@@ -126,6 +126,11 @@ struct icss_iep {
 	struct hrtimer sync_timer;
 };
 
+static u32 icss_iep_readl(struct icss_iep *iep, int reg)
+{
+	return readl(iep->base + iep->plat_data->reg_offs[reg]);
+}
+
 /**
  * icss_iep_get_count_hi() - Get the upper 32 bit IEP counter
  * @iep: Pointer to structure representing IEP.
@@ -193,20 +198,24 @@ static void icss_iep_settime(struct icss_iep *iep, u64 ns)
 
 static u64 icss_iep_gettime(struct icss_iep *iep)
 {
-	u64 val;
-	u32 tmp;
+	u32 ts_hi = 0, ts_lo;
+	unsigned long flags;
 
 	if (iep->ops && iep->ops->gettime)
 		return iep->ops->gettime(iep->clockops_data);
 
-	regmap_read(iep->map, ICSS_IEP_COUNT_REG0, &tmp);
-	val = tmp;
-	if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) {
-		regmap_read(iep->map, ICSS_IEP_COUNT_REG1, &tmp);
-		val |= (u64)tmp << 32;
-	}
+	/* use local_irq_x() to make it work for both RT/non-RT */
+	local_irq_save(flags);
 
-	return val;
+	/* no need to play with hi-lo, hi is latched when lo is read */
+	ts_lo = icss_iep_readl(iep, ICSS_IEP_COUNT_REG0);
+
+	if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+		ts_hi = icss_iep_readl(iep, ICSS_IEP_COUNT_REG1);
+
+	local_irq_restore(flags);
+
+	return (u64)ts_lo | (u64)ts_hi << 32;
 }
 
 static void icss_iep_enable(struct icss_iep *iep)
