diff mbox series

[net-next,v2,7/7] net: axienet: add coalesce timer ethtool configuration

Message ID 20220305002305.1710462-8-robert.hancock@calian.com (mailing list archive)
State New, archived
Headers show
Series NAPI/GRO support for axienet driver | expand

Commit Message

Robert Hancock March 5, 2022, 12:23 a.m. UTC
Add the ability to configure the RX/TX coalesce timer with ethtool.
Change default setting to scale with the clock rate rather than being a
fixed number of clock cycles.

Signed-off-by: Robert Hancock <robert.hancock@calian.com>
---
 drivers/net/ethernet/xilinx/xilinx_axienet.h  |  8 +--
 .../net/ethernet/xilinx/xilinx_axienet_main.c | 51 +++++++++++++++----
 2 files changed, 45 insertions(+), 14 deletions(-)

Comments

Robert Hancock March 5, 2022, 2:20 a.m. UTC | #1
On Fri, 2022-03-04 at 18:23 -0600, Robert Hancock wrote:
> Add the ability to configure the RX/TX coalesce timer with ethtool.
> Change default setting to scale with the clock rate rather than being a
> fixed number of clock cycles.
> 
> Signed-off-by: Robert Hancock <robert.hancock@calian.com>
> ---
>  drivers/net/ethernet/xilinx/xilinx_axienet.h  |  8 +--
>  .../net/ethernet/xilinx/xilinx_axienet_main.c | 51 +++++++++++++++----
>  2 files changed, 45 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h
> b/drivers/net/ethernet/xilinx/xilinx_axienet.h
> index 6f0f13b4fb1a..f6d365cb57de 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
> @@ -119,11 +119,11 @@
>  #define XAXIDMA_IRQ_ERROR_MASK		0x00004000 /* Error interrupt
> */
>  #define XAXIDMA_IRQ_ALL_MASK		0x00007000 /* All interrupts */
>  
> -/* Default TX/RX Threshold and waitbound values for SGDMA mode */
> +/* Default TX/RX Threshold and delay timer values for SGDMA mode */
>  #define XAXIDMA_DFT_TX_THRESHOLD	24
> -#define XAXIDMA_DFT_TX_WAITBOUND	254
> +#define XAXIDMA_DFT_TX_USEC		50
>  #define XAXIDMA_DFT_RX_THRESHOLD	1
> -#define XAXIDMA_DFT_RX_WAITBOUND	254
> +#define XAXIDMA_DFT_RX_USEC		50
>  
>  #define XAXIDMA_BD_CTRL_TXSOF_MASK	0x08000000 /* First tx packet */
>  #define XAXIDMA_BD_CTRL_TXEOF_MASK	0x04000000 /* Last tx packet */
> @@ -482,7 +482,9 @@ struct axienet_local {
>  	int csum_offload_on_rx_path;
>  
>  	u32 coalesce_count_rx;
> +	u32 coalesce_usec_rx;
>  	u32 coalesce_count_tx;
> +	u32 coalesce_usec_tx;

Forgot the kerneldoc for these - another rev coming..

>  };
>  
>  /**
> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> index 860ff0447f71..a51a8228e1b7 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> @@ -33,7 +33,7 @@
>  #include <linux/of_irq.h>
>  #include <linux/of_address.h>
>  #include <linux/skbuff.h>
> -#include <linux/spinlock.h>
> +#include <linux/math64.h>
>  #include <linux/phy.h>
>  #include <linux/mii.h>
>  #include <linux/ethtool.h>
> @@ -226,6 +226,28 @@ static void axienet_dma_bd_release(struct net_device
> *ndev)
>  			  lp->rx_bd_p);
>  }
>  
> +/**
> + * axienet_usec_to_timer - Calculate IRQ delay timer value
> + * @lp:		Pointer to the axienet_local structure
> + * @coalesce_usec: Microseconds to convert into timer value
> + */
> +static u32 axienet_usec_to_timer(struct axienet_local *lp, u32
> coalesce_usec)
> +{
> +	u32 result;
> +	u64 clk_rate = 125000000; /* arbitrary guess if no clock rate set */
> +
> +	if (lp->axi_clk)
> +		clk_rate = clk_get_rate(lp->axi_clk);
> +
> +	/* 1 Timeout Interval = 125 * (clock period of SG clock) */
> +	result = DIV64_U64_ROUND_CLOSEST((u64)coalesce_usec * clk_rate,
> +					 (u64)125000000);
> +	if (result > 255)
> +		result = 255;
> +
> +	return result;
> +}
> +
>  /**
>   * axienet_dma_start - Set up DMA registers and start DMA operation
>   * @lp:		Pointer to the axienet_local structure
> @@ -241,7 +263,8 @@ static void axienet_dma_start(struct axienet_local *lp)
>  	 * the first RX packet. Otherwise leave at 0 to disable delay
> interrupt.
>  	 */
>  	if (lp->coalesce_count_rx > 1)
> -		lp->rx_dma_cr |= (XAXIDMA_DFT_RX_WAITBOUND <<
> XAXIDMA_DELAY_SHIFT) |
> +		lp->rx_dma_cr |= (axienet_usec_to_timer(lp, lp-
> >coalesce_usec_rx)
> +					<< XAXIDMA_DELAY_SHIFT) |
>  				 XAXIDMA_IRQ_DELAY_MASK;
>  	axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, lp->rx_dma_cr);
>  
> @@ -252,7 +275,8 @@ static void axienet_dma_start(struct axienet_local *lp)
>  	 * the first TX packet. Otherwise leave at 0 to disable delay
> interrupt.
>  	 */
>  	if (lp->coalesce_count_tx > 1)
> -		tx_cr |= (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT) |
> +		tx_cr |= (axienet_usec_to_timer(lp, lp->coalesce_usec_tx)
> +				<< XAXIDMA_DELAY_SHIFT) |
>  			 XAXIDMA_IRQ_DELAY_MASK;
>  	axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, tx_cr);
>  
> @@ -1488,14 +1512,12 @@ axienet_ethtools_get_coalesce(struct net_device
> *ndev,
>  			      struct kernel_ethtool_coalesce *kernel_coal,
>  			      struct netlink_ext_ack *extack)
>  {
> -	u32 regval = 0;
>  	struct axienet_local *lp = netdev_priv(ndev);
> -	regval = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
> -	ecoalesce->rx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK)
> -					     >> XAXIDMA_COALESCE_SHIFT;
> -	regval = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
> -	ecoalesce->tx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK)
> -					     >> XAXIDMA_COALESCE_SHIFT;
> +
> +	ecoalesce->rx_max_coalesced_frames = lp->coalesce_count_rx;
> +	ecoalesce->rx_coalesce_usecs = lp->coalesce_usec_rx;
> +	ecoalesce->tx_max_coalesced_frames = lp->coalesce_count_tx;
> +	ecoalesce->tx_coalesce_usecs = lp->coalesce_usec_tx;
>  	return 0;
>  }
>  
> @@ -1528,8 +1550,12 @@ axienet_ethtools_set_coalesce(struct net_device *ndev,
>  
>  	if (ecoalesce->rx_max_coalesced_frames)
>  		lp->coalesce_count_rx = ecoalesce->rx_max_coalesced_frames;
> +	if (ecoalesce->rx_coalesce_usecs)
> +		lp->coalesce_usec_rx = ecoalesce->rx_coalesce_usecs;
>  	if (ecoalesce->tx_max_coalesced_frames)
>  		lp->coalesce_count_tx = ecoalesce->tx_max_coalesced_frames;
> +	if (ecoalesce->tx_coalesce_usecs)
> +		lp->coalesce_usec_tx = ecoalesce->tx_coalesce_usecs;
>  
>  	return 0;
>  }
> @@ -1560,7 +1586,8 @@ static int axienet_ethtools_nway_reset(struct
> net_device *dev)
>  }
>  
>  static const struct ethtool_ops axienet_ethtool_ops = {
> -	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
> +	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |
> +				     ETHTOOL_COALESCE_USECS,
>  	.get_drvinfo    = axienet_ethtools_get_drvinfo,
>  	.get_regs_len   = axienet_ethtools_get_regs_len,
>  	.get_regs       = axienet_ethtools_get_regs,
> @@ -2047,7 +2074,9 @@ static int axienet_probe(struct platform_device *pdev)
>  	}
>  
>  	lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
> +	lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC;
>  	lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
> +	lp->coalesce_usec_tx = XAXIDMA_DFT_TX_USEC;
>  
>  	/* Reset core now that clocks are enabled, prior to accessing MDIO */
>  	ret = __axienet_device_reset(lp);
Jakub Kicinski March 5, 2022, 2:59 a.m. UTC | #2
On Sat, 5 Mar 2022 02:20:38 +0000 Robert Hancock wrote:
> > @@ -482,7 +482,9 @@ struct axienet_local {
> >  	int csum_offload_on_rx_path;
> >  
> >  	u32 coalesce_count_rx;
> > +	u32 coalesce_usec_rx;
> >  	u32 coalesce_count_tx;
> > +	u32 coalesce_usec_tx;  
> 
> Forgot the kerneldoc for these - another rev coming..

The mailing list is not for build testing patches. Please be more
careful, and leave at least 24 hours between posts so reviewers get
a chance to share additional comments.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 6f0f13b4fb1a..f6d365cb57de 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -119,11 +119,11 @@ 
 #define XAXIDMA_IRQ_ERROR_MASK		0x00004000 /* Error interrupt */
 #define XAXIDMA_IRQ_ALL_MASK		0x00007000 /* All interrupts */
 
-/* Default TX/RX Threshold and waitbound values for SGDMA mode */
+/* Default TX/RX Threshold and delay timer values for SGDMA mode */
 #define XAXIDMA_DFT_TX_THRESHOLD	24
-#define XAXIDMA_DFT_TX_WAITBOUND	254
+#define XAXIDMA_DFT_TX_USEC		50
 #define XAXIDMA_DFT_RX_THRESHOLD	1
-#define XAXIDMA_DFT_RX_WAITBOUND	254
+#define XAXIDMA_DFT_RX_USEC		50
 
 #define XAXIDMA_BD_CTRL_TXSOF_MASK	0x08000000 /* First tx packet */
 #define XAXIDMA_BD_CTRL_TXEOF_MASK	0x04000000 /* Last tx packet */
@@ -482,7 +482,9 @@  struct axienet_local {
 	int csum_offload_on_rx_path;
 
 	u32 coalesce_count_rx;
+	u32 coalesce_usec_rx;
 	u32 coalesce_count_tx;
+	u32 coalesce_usec_tx;
 };
 
 /**
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 860ff0447f71..a51a8228e1b7 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -33,7 +33,7 @@ 
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/skbuff.h>
-#include <linux/spinlock.h>
+#include <linux/math64.h>
 #include <linux/phy.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
@@ -226,6 +226,28 @@  static void axienet_dma_bd_release(struct net_device *ndev)
 			  lp->rx_bd_p);
 }
 
+/**
+ * axienet_usec_to_timer - Calculate IRQ delay timer value
+ * @lp:		Pointer to the axienet_local structure
+ * @coalesce_usec: Microseconds to convert into timer value
+ */
+static u32 axienet_usec_to_timer(struct axienet_local *lp, u32 coalesce_usec)
+{
+	u32 result;
+	u64 clk_rate = 125000000; /* arbitrary guess if no clock rate set */
+
+	if (lp->axi_clk)
+		clk_rate = clk_get_rate(lp->axi_clk);
+
+	/* 1 Timeout Interval = 125 * (clock period of SG clock) */
+	result = DIV64_U64_ROUND_CLOSEST((u64)coalesce_usec * clk_rate,
+					 (u64)125000000);
+	if (result > 255)
+		result = 255;
+
+	return result;
+}
+
 /**
  * axienet_dma_start - Set up DMA registers and start DMA operation
  * @lp:		Pointer to the axienet_local structure
@@ -241,7 +263,8 @@  static void axienet_dma_start(struct axienet_local *lp)
 	 * the first RX packet. Otherwise leave at 0 to disable delay interrupt.
 	 */
 	if (lp->coalesce_count_rx > 1)
-		lp->rx_dma_cr |= (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT) |
+		lp->rx_dma_cr |= (axienet_usec_to_timer(lp, lp->coalesce_usec_rx)
+					<< XAXIDMA_DELAY_SHIFT) |
 				 XAXIDMA_IRQ_DELAY_MASK;
 	axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, lp->rx_dma_cr);
 
@@ -252,7 +275,8 @@  static void axienet_dma_start(struct axienet_local *lp)
 	 * the first TX packet. Otherwise leave at 0 to disable delay interrupt.
 	 */
 	if (lp->coalesce_count_tx > 1)
-		tx_cr |= (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT) |
+		tx_cr |= (axienet_usec_to_timer(lp, lp->coalesce_usec_tx)
+				<< XAXIDMA_DELAY_SHIFT) |
 			 XAXIDMA_IRQ_DELAY_MASK;
 	axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, tx_cr);
 
@@ -1488,14 +1512,12 @@  axienet_ethtools_get_coalesce(struct net_device *ndev,
 			      struct kernel_ethtool_coalesce *kernel_coal,
 			      struct netlink_ext_ack *extack)
 {
-	u32 regval = 0;
 	struct axienet_local *lp = netdev_priv(ndev);
-	regval = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
-	ecoalesce->rx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK)
-					     >> XAXIDMA_COALESCE_SHIFT;
-	regval = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
-	ecoalesce->tx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK)
-					     >> XAXIDMA_COALESCE_SHIFT;
+
+	ecoalesce->rx_max_coalesced_frames = lp->coalesce_count_rx;
+	ecoalesce->rx_coalesce_usecs = lp->coalesce_usec_rx;
+	ecoalesce->tx_max_coalesced_frames = lp->coalesce_count_tx;
+	ecoalesce->tx_coalesce_usecs = lp->coalesce_usec_tx;
 	return 0;
 }
 
@@ -1528,8 +1550,12 @@  axienet_ethtools_set_coalesce(struct net_device *ndev,
 
 	if (ecoalesce->rx_max_coalesced_frames)
 		lp->coalesce_count_rx = ecoalesce->rx_max_coalesced_frames;
+	if (ecoalesce->rx_coalesce_usecs)
+		lp->coalesce_usec_rx = ecoalesce->rx_coalesce_usecs;
 	if (ecoalesce->tx_max_coalesced_frames)
 		lp->coalesce_count_tx = ecoalesce->tx_max_coalesced_frames;
+	if (ecoalesce->tx_coalesce_usecs)
+		lp->coalesce_usec_tx = ecoalesce->tx_coalesce_usecs;
 
 	return 0;
 }
@@ -1560,7 +1586,8 @@  static int axienet_ethtools_nway_reset(struct net_device *dev)
 }
 
 static const struct ethtool_ops axienet_ethtool_ops = {
-	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
+	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |
+				     ETHTOOL_COALESCE_USECS,
 	.get_drvinfo    = axienet_ethtools_get_drvinfo,
 	.get_regs_len   = axienet_ethtools_get_regs_len,
 	.get_regs       = axienet_ethtools_get_regs,
@@ -2047,7 +2074,9 @@  static int axienet_probe(struct platform_device *pdev)
 	}
 
 	lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
+	lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC;
 	lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
+	lp->coalesce_usec_tx = XAXIDMA_DFT_TX_USEC;
 
 	/* Reset core now that clocks are enabled, prior to accessing MDIO */
 	ret = __axienet_device_reset(lp);