[PATCH 3/3] net: macb: Receive Side Coalescing (RSC) feature added.
From: Rafal Ozieblo
Date: Sat Apr 14 2018 - 16:55:22 EST
This is basically the same as Large Receive Offload (LRO)
in Linux framework.
Signed-off-by: Rafal Ozieblo <rafalo@xxxxxxxxxxx>
---
drivers/net/ethernet/cadence/macb.h | 6 +++
drivers/net/ethernet/cadence/macb_main.c | 70 +++++++++++++++++++++++++++++++-
2 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index a2cb805..9ebdde7 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -83,6 +83,7 @@
#define GEM_USRIO 0x000c /* User IO */
#define GEM_DMACFG 0x0010 /* DMA Configuration */
#define GEM_JML 0x0048 /* Jumbo Max Length */
+#define GEM_RSC 0x0058 /* RSC Control */
#define GEM_HRB 0x0080 /* Hash Bottom */
#define GEM_HRT 0x0084 /* Hash Top */
#define GEM_SA1B 0x0088 /* Specific1 Bottom */
@@ -318,6 +319,11 @@
#define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */
#define GEM_ADDR64_SIZE 1
+/* Bitfields in RSC control */
+#define GEM_RSCCTRL_OFFSET 1 /* RSC control */
+#define GEM_RSCCTRL_SIZE 15
+#define GEM_CLRMSK_OFFSET 16 /* RSC clear mask */
+#define GEM_CLRMSK_SIZE 1
/* Bitfields in NSR */
#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 27c406c..92bdcf1 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2377,6 +2377,8 @@ static int macb_open(struct net_device *dev)
if (!(bp->dev->hw_features & NETIF_F_LRO))
bufsz += NET_IP_ALIGN;
+ else
+ bufsz = 0xFF * 64; // For RSC Buffer Sizes must be set to 16K.
/* RX buffers initialization */
macb_init_rx_buffer_size(bp, bufsz);
@@ -2801,6 +2803,62 @@ static int macb_get_ts_info(struct net_device *netdev,
return ethtool_op_get_ts_info(netdev, info);
}
+static void gem_enable_hdr_data_split(struct macb *bp, bool enable)
+{
+ u32 dmacfg;
+
+ dmacfg = gem_readl(bp, DMACFG);
+ if (enable)
+ dmacfg |= GEM_BIT(HDRS);
+ else
+ dmacfg &= ~GEM_BIT(HDRS);
+ gem_writel(bp, DMACFG, dmacfg);
+}
+
+static void gem_update_rsc_state(struct macb *bp, netdev_features_t feature)
+{
+ u32 rsc_control, rsc_control_new, queue, rsc;
+ bool enable, jumbo, any_enabled = false;
+ struct ethtool_rx_fs_item *item;
+ unsigned long flags;
+ u32 ncfgr;
+
+ enable = (!!(feature & NETIF_F_NTUPLE) && !!(feature & NETIF_F_LRO));
+ rsc = gem_readl(bp, RSC);
+ rsc_control = GEM_BFEXT(RSCCTRL, rsc);
+ rsc_control_new = 0;
+ if (enable) {
+ list_for_each_entry(item, &bp->rx_fs_list.list, list) {
+ queue = item->fs.ring_cookie;
+ rsc_control_new |= (1 << (queue - 1));
+ any_enabled = true;
+ netdev_dbg(bp->dev, "RSC %sabled for queue %u\n",
+ enable ? "en" : "dis", queue);
+ }
+ }
+ if (rsc_control_new != rsc_control) {
+ rsc = GEM_BFINS(RSCCTRL, rsc_control_new, rsc);
+ gem_writel(bp, RSC, rsc);
+ }
+ if (bp->caps & MACB_CAPS_JUMBO) {
+ /* Don't enable jumbo mode for RSC:
+ * disable unless not RSC and large MTU
+ */
+ ncfgr = gem_readl(bp, NCFGR);
+ enable = !any_enabled;
+ jumbo = !!MACB_BFEXT(JFRAME, ncfgr);
+ /* and don't touch if already in the state we want */
+ if ((jumbo && !enable) || (!jumbo && enable)) {
+ ncfgr = MACB_BFINS(JFRAME, enable, ncfgr);
+ spin_lock_irqsave(&bp->lock, flags);
+ gem_writel(bp, NCFGR, ncfgr);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ }
+ }
+ /* Need to enable header-data splitting also */
+ gem_enable_hdr_data_split(bp, any_enabled);
+}
+
static void gem_enable_flow_filters(struct macb *bp, bool enable)
{
struct ethtool_rx_fs_item *item;
@@ -2969,6 +3027,8 @@ static int gem_add_flow_filter(struct net_device *netdev,
if (netdev->features & NETIF_F_NTUPLE)
gem_enable_flow_filters(bp, 1);
+ /* enable RSC if LRO & NTUPLE on */
+ gem_update_rsc_state(bp, netdev->features);
spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
return 0;
@@ -3009,6 +3069,7 @@ static int gem_del_flow_filter(struct net_device *netdev,
return 0;
}
}
+ gem_update_rsc_state(bp, netdev->features);
spin_unlock_irqrestore(&bp->rx_fs_lock, flags);
return -EINVAL;
@@ -3191,7 +3252,12 @@ static int macb_set_features(struct net_device *netdev,
bool turn_on = features & NETIF_F_NTUPLE;
gem_enable_flow_filters(bp, turn_on);
+ gem_update_rsc_state(bp, features);
}
+
+ /* LRO (Large Receive Offload) aka RSC (Receive Side Coalescing) */
+ if ((changed & NETIF_F_LRO) && macb_is_gem(bp))
+ gem_update_rsc_state(bp, features);
return 0;
}
@@ -3449,8 +3515,10 @@ static int macb_init(struct platform_device *pdev)
dev->hw_features |= MACB_NETIF_LSO;
/* Check RSC capability */
- if (GEM_BFEXT(PBUF_RSC, gem_readl(bp, DCFG6)))
+ if (GEM_BFEXT(PBUF_RSC, gem_readl(bp, DCFG6))) {
dev->hw_features |= NETIF_F_LRO;
+ gem_writel(bp, RSC, GEM_BIT(CLRMSK));
+ }
/* Checksum offload is only available on gem with packet buffer */
if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE))
--
2.4.5