RE: [PATCH net-next 2/3] net: ethernet: mediatek: add ethtool functions to configure RX flows of HW LRO

2016-09-13 Thread Nelson Chang
(resend)

Thanks Florian for the review!
I will add ndo_fix_features hook in v2 to prevent the case that a user
wants to turn off NETIF_F_LRO but RX flow is programmed.
If any programmed RX flow exists, NETIF_F_LRO cannot be turned off.

-Original Message-
From: Florian Fainelli [mailto:f.faine...@gmail.com]
Sent: Wednesday, September 14, 2016 2:27 AM
To: Nelson Chang (張家祥); j...@phrozen.org; da...@davemloft.net
Cc: n...@openwrt.org; netdev@vger.kernel.org;
linux-media...@lists.infradead.org; nelsonch...@gmail.com
Subject: Re: [PATCH net-next 2/3] net: ethernet: mediatek: add ethtool
functions to configure RX flows of HW LRO

On 09/13/2016 06:54 AM, Nelson Chang wrote:
> The codes add ethtool functions to set RX flows for HW LRO. Because 
> the HW LRO hardware can only recognize the destination IP of TCP/IP
RX 
> flows, the ethtool command to add HW LRO flow is as below:
> ethtool -N [devname] flow-type tcp4 dst-ip [ip_addr] loc [0~1]
> 
> Otherwise, cause the hardware can set total four destination IPs,
each 
> GMAC (GMAC1/GMAC2) can set two IPs separately at most.
> 
> Signed-off-by: Nelson Chang 
> ---

> +
> +static int mtk_set_features(struct net_device *dev, netdev_features_t
> +features) {
> + int err = 0;
> +
> + if (!((dev->features ^ features) & NETIF_F_LRO))
> + return 0;
> +
> + if (!(features & NETIF_F_LRO))
> + mtk_hwlro_netdev_disable(dev);

you may want to implement a fix_features ndo operations which makes sure
that NETIF_F_LRO is turned on in case a RX flow is programmed,
otherwise, it may be confusing to the user that a flow was programmed,
but no offload is happening.
--
Florian




Re: [PATCH net-next 2/3] net: ethernet: mediatek: add ethtool functions to configure RX flows of HW LRO

2016-09-13 Thread Florian Fainelli
On 09/13/2016 06:54 AM, Nelson Chang wrote:
> The codes add ethtool functions to set RX flows for HW LRO. Because the
> HW LRO hardware can only recognize the destination IP of TCP/IP RX flows,
> the ethtool command to add HW LRO flow is as below:
> ethtool -N [devname] flow-type tcp4 dst-ip [ip_addr] loc [0~1]
> 
> Otherwise, cause the hardware can set total four destination IPs, each
> GMAC (GMAC1/GMAC2) can set two IPs separately at most.
> 
> Signed-off-by: Nelson Chang 
> ---

> +
> +static int mtk_set_features(struct net_device *dev, netdev_features_t 
> features)
> +{
> + int err = 0;
> +
> + if (!((dev->features ^ features) & NETIF_F_LRO))
> + return 0;
> +
> + if (!(features & NETIF_F_LRO))
> + mtk_hwlro_netdev_disable(dev);

you may want to implement a fix_features ndo operations which makes sure
that NETIF_F_LRO is turned on in case a RX flow is programmed,
otherwise, it may be confusing to the user that a flow was programmed,
but no offload is happening.
-- 
Florian


[PATCH net-next 2/3] net: ethernet: mediatek: add ethtool functions to configure RX flows of HW LRO

2016-09-13 Thread Nelson Chang
The codes add ethtool functions to set RX flows for HW LRO. Because the
HW LRO hardware can only recognize the destination IP of TCP/IP RX flows,
the ethtool command to add HW LRO flow is as below:
ethtool -N [devname] flow-type tcp4 dst-ip [ip_addr] loc [0~1]

Otherwise, cause the hardware can set total four destination IPs, each
GMAC (GMAC1/GMAC2) can set two IPs separately at most.

Signed-off-by: Nelson Chang 
---
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 218 
 1 file changed, 218 insertions(+)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c 
b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index ed35e0f..8245841 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1344,6 +1344,165 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
 }
 
+static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
+{
+   u32 reg_val;
+
+   reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+
+   /* invalidate the IP setting */
+   mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+
+   mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));
+
+   /* validate the IP setting */
+   mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+}
+
+static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
+{
+   u32 reg_val;
+
+   reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+
+   /* invalidate the IP setting */
+   mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+
+   mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
+}
+
+static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
+{
+   int cnt = 0;
+   int i;
+
+   for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+   if (mac->hwlro_ip[i])
+   cnt++;
+   }
+
+   return cnt;
+}
+
+static int mtk_hwlro_add_ipaddr(struct net_device *dev,
+   struct ethtool_rxnfc *cmd)
+{
+   struct ethtool_rx_flow_spec *fsp =
+   (struct ethtool_rx_flow_spec *)&cmd->fs;
+   struct mtk_mac *mac = netdev_priv(dev);
+   struct mtk_eth *eth = mac->hw;
+   int hwlro_idx;
+
+   if ((fsp->flow_type != TCP_V4_FLOW) ||
+   (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
+   (fsp->location > 1))
+   return -EINVAL;
+
+   mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+   hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+
+   mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
+
+   mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
+
+   return 0;
+}
+
+static int mtk_hwlro_del_ipaddr(struct net_device *dev,
+   struct ethtool_rxnfc *cmd)
+{
+   struct ethtool_rx_flow_spec *fsp =
+   (struct ethtool_rx_flow_spec *)&cmd->fs;
+   struct mtk_mac *mac = netdev_priv(dev);
+   struct mtk_eth *eth = mac->hw;
+   int hwlro_idx;
+
+   if (fsp->location > 1)
+   return -EINVAL;
+
+   mac->hwlro_ip[fsp->location] = 0;
+   hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+
+   mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
+
+   mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
+
+   return 0;
+}
+
+static void mtk_hwlro_netdev_disable(struct net_device *dev)
+{
+   struct mtk_mac *mac = netdev_priv(dev);
+   struct mtk_eth *eth = mac->hw;
+   int i, hwlro_idx;
+
+   for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+   mac->hwlro_ip[i] = 0;
+   hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
+
+   mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
+   }
+
+   mac->hwlro_ip_cnt = 0;
+}
+
+static int mtk_hwlro_get_fdir_entry(struct net_device *dev,
+   struct ethtool_rxnfc *cmd)
+{
+   struct mtk_mac *mac = netdev_priv(dev);
+   struct ethtool_rx_flow_spec *fsp =
+   (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+   /* only tcp dst ipv4 is meaningful, others are meaningless */
+   fsp->flow_type = TCP_V4_FLOW;
+   fsp->h_u.tcp_ip4_spec.ip4dst = ntohl(mac->hwlro_ip[fsp->location]);
+   fsp->m_u.tcp_ip4_spec.ip4dst = 0;
+
+   fsp->h_u.tcp_ip4_spec.ip4src = 0;
+   fsp->m_u.tcp_ip4_spec.ip4src = 0x;
+   fsp->h_u.tcp_ip4_spec.psrc = 0;
+   fsp->m_u.tcp_ip4_spec.psrc = 0x;
+   fsp->h_u.tcp_ip4_spec.pdst = 0;
+   fsp->m_u.tcp_ip4_spec.pdst = 0x;
+   fsp->h_u.tcp_ip4_spec.tos = 0;
+   fsp->m_u.tcp_ip4_spec.tos = 0xff;
+
+   return 0;
+}
+
+static int mtk_hwlro_get_fdir_all(struct net_device *dev,
+ struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+   struct mtk_mac *mac = netdev_priv(dev);
+   int cnt = 0;
+   int i;
+
+   for (i = 0; i < MTK_MAX_LRO_IP_CNT; i