diff mbox

[4/6] net/macb: add RX checksum offload feature

Message ID f29965fee23dc0de99b388373017efeffa1aac10.1405689937.git.cyrille.pitchen@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Cyrille Pitchen July 18, 2014, 2:21 p.m. UTC
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
 drivers/net/ethernet/cadence/macb.h |  2 ++
 2 files changed, 30 insertions(+), 1 deletion(-)

Comments

Eric Dumazet July 18, 2014, 3:36 p.m. UTC | #1
On Fri, 2014-07-18 at 16:21 +0200, Cyrille Pitchen wrote:
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
> ---
>  drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
>  drivers/net/ethernet/cadence/macb.h |  2 ++
>  2 files changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> index 9bdcd1b..6acd6e2 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -766,6 +766,8 @@ static int gem_rx(struct macb *bp, int budget)
>  
>  		skb->protocol = eth_type_trans(skb, bp->dev);
>  		skb_checksum_none_assert(skb);
> +		if (bp->dev->features & NETIF_F_RXCSUM)
> +			skb->ip_summed = CHECKSUM_UNNECESSARY;
>  


Really ?

If this is what you meant, this deserves a big and fat comment.
Cyrille Pitchen July 22, 2014, 4:27 p.m. UTC | #2
Le 18/07/2014 17:36, Eric Dumazet a écrit :
> On Fri, 2014-07-18 at 16:21 +0200, Cyrille Pitchen wrote:
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
>> ---
>>  drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
>>  drivers/net/ethernet/cadence/macb.h |  2 ++
>>  2 files changed, 30 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
>> index 9bdcd1b..6acd6e2 100644
>> --- a/drivers/net/ethernet/cadence/macb.c
>> +++ b/drivers/net/ethernet/cadence/macb.c
>> @@ -766,6 +766,8 @@ static int gem_rx(struct macb *bp, int budget)
>>  
>>  		skb->protocol = eth_type_trans(skb, bp->dev);
>>  		skb_checksum_none_assert(skb);
>> +		if (bp->dev->features & NETIF_F_RXCSUM)
>> +			skb->ip_summed = CHECKSUM_UNNECESSARY;
>>  
> 
> 
> Really ?
> 
> If this is what you meant, this deserves a big and fat comment.
> 
> 
> 
Hi Eric,

Isn't it the proper way to do? According to Cadence documentation about RX checksum offload:
"If any of the checksums (IP, TCP or UDP) are verified incorrect by the GEM, the packet is discarded."

If I understand, when RX checksum offload is enabled setting bit 24 of the Network Configuration Register, the driver only receives RX frames with correct checksum. Then it tells the kernel that there's no need to verify the checksum again in software. This is done setting skb->ip_summed to CHECKSUM_UNNECESSARY. Intel e1000 driver does the same in e1000_rx_checksum() function.

Also bit 24 of the Network Configuration Register is updated by macb_open() and macb_set_features() so it always matches the state of NETIF_F_RXCSUM flag in dev->features, once the network interface is up. That's why I'd rather read from dev->features than read from register.

Did I make a mistake? Is it the kind of comment you expect to be added?

Regards,

Cyrille
Florian Fainelli July 22, 2014, 4:39 p.m. UTC | #3
2014-07-22 9:27 GMT-07:00 Cyrille Pitchen <cyrille.pitchen@atmel.com>:
> Le 18/07/2014 17:36, Eric Dumazet a écrit :
>> On Fri, 2014-07-18 at 16:21 +0200, Cyrille Pitchen wrote:
>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
>>> ---
>>>  drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
>>>  drivers/net/ethernet/cadence/macb.h |  2 ++
>>>  2 files changed, 30 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
>>> index 9bdcd1b..6acd6e2 100644
>>> --- a/drivers/net/ethernet/cadence/macb.c
>>> +++ b/drivers/net/ethernet/cadence/macb.c
>>> @@ -766,6 +766,8 @@ static int gem_rx(struct macb *bp, int budget)
>>>
>>>              skb->protocol = eth_type_trans(skb, bp->dev);
>>>              skb_checksum_none_assert(skb);
>>> +            if (bp->dev->features & NETIF_F_RXCSUM)
>>> +                    skb->ip_summed = CHECKSUM_UNNECESSARY;
>>>
>>
>>
>> Really ?
>>
>> If this is what you meant, this deserves a big and fat comment.
>>
>>
>>
> Hi Eric,
>
> Isn't it the proper way to do? According to Cadence documentation about RX checksum offload:
> "If any of the checksums (IP, TCP or UDP) are verified incorrect by the GEM, the packet is discarded."
>
> If I understand, when RX checksum offload is enabled setting bit 24 of the Network Configuration Register, the driver only receives RX frames with correct checksum. Then it tells the kernel that there's no need to verify the checksum again in software. This is done setting skb->ip_summed to CHECKSUM_UNNECESSARY. Intel e1000 driver does the same in e1000_rx_checksum() function.

This is not the same thing as what the e1000 driver is doing, the
e1000 driver is checking a per-packet status mask which tells it
whether a given packet had its protocol level checksum computed by the
HW.

I think there might be some slight confusion here between the Ethernet
frame Frame Control Checksum which is at the Ethernet level, and will
(with most adapters not supporting RX_FCS_ERR) cause the Ethernet
controller to drop frames at the MAC level, and the higher level
protocol checksums such as the TCP or UDP checksum.

>
> Also bit 24 of the Network Configuration Register is updated by macb_open() and macb_set_features() so it always matches the state of NETIF_F_RXCSUM flag in dev->features, once the network interface is up. That's why I'd rather read from dev->features than read from register.

I don't think the Cadence GEM Ethernet controller is any different
than other hardware out there, there must be a per-packet status bit
which tells whether the TCP/UDP or other protocol checksum was
successfully validated by the hardware. One of the reason for that, is
that depending on the type of traffic your receive (e.g: ARP), there
might be no protocol-level checksum at all in the packet, and the
hardware should know about that.

>
> Did I make a mistake? Is it the kind of comment you expect to be added?
>
> Regards,
>
> Cyrille
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Eric Dumazet July 22, 2014, 10:58 p.m. UTC | #4
On Tue, 2014-07-22 at 18:27 +0200, Cyrille Pitchen wrote:
> Le 18/07/2014 17:36, Eric Dumazet a écrit :
> > On Fri, 2014-07-18 at 16:21 +0200, Cyrille Pitchen wrote:
> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
> >> ---
> >>  drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
> >>  drivers/net/ethernet/cadence/macb.h |  2 ++
> >>  2 files changed, 30 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> >> index 9bdcd1b..6acd6e2 100644
> >> --- a/drivers/net/ethernet/cadence/macb.c
> >> +++ b/drivers/net/ethernet/cadence/macb.c
> >> @@ -766,6 +766,8 @@ static int gem_rx(struct macb *bp, int budget)
> >>  
> >>  		skb->protocol = eth_type_trans(skb, bp->dev);
> >>  		skb_checksum_none_assert(skb);
> >> +		if (bp->dev->features & NETIF_F_RXCSUM)
> >> +			skb->ip_summed = CHECKSUM_UNNECESSARY;
> >>  
> > 
> > 
> > Really ?
> > 
> > If this is what you meant, this deserves a big and fat comment.
> > 
> > 
> > 
> Hi Eric,
> 
> Isn't it the proper way to do? According to Cadence documentation
> about RX checksum offload:
> "If any of the checksums (IP, TCP or UDP) are verified incorrect by
> the GEM, the packet is discarded."
> 
> If I understand, when RX checksum offload is enabled setting bit 24 of
> the Network Configuration Register, the driver only receives RX frames
> with correct checksum. Then it tells the kernel that there's no need
> to verify the checksum again in software. This is done setting
> skb->ip_summed to CHECKSUM_UNNECESSARY. Intel e1000 driver does the
> same in e1000_rx_checksum() function.
> 
> Also bit 24 of the Network Configuration Register is updated by
> macb_open() and macb_set_features() so it always matches the state of
> NETIF_F_RXCSUM flag in dev->features, once the network interface is
> up. That's why I'd rather read from dev->features than read from
> register.
> 
> Did I make a mistake? Is it the kind of comment you expect to be
> added?
> 
> Regards,

Usually, frames are not discarded, and a bit is present in rx descriptor
to tell us if (TCP) checksum was validated by the NIC

We want tcpdump to get a copy of corrupted TCP frames, even if TCP stack
drops them later.

If this NIC drops incorrect frames, I am afraid we cant use this RX
offload at all.
Cyrille Pitchen July 24, 2014, 11:59 a.m. UTC | #5
Le 23/07/2014 00:58, Eric Dumazet a écrit :
> On Tue, 2014-07-22 at 18:27 +0200, Cyrille Pitchen wrote:
>> Le 18/07/2014 17:36, Eric Dumazet a écrit :
>>> On Fri, 2014-07-18 at 16:21 +0200, Cyrille Pitchen wrote:
>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
>>>> ---
>>>>  drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
>>>>  drivers/net/ethernet/cadence/macb.h |  2 ++
>>>>  2 files changed, 30 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
>>>> index 9bdcd1b..6acd6e2 100644
>>>> --- a/drivers/net/ethernet/cadence/macb.c
>>>> +++ b/drivers/net/ethernet/cadence/macb.c
>>>> @@ -766,6 +766,8 @@ static int gem_rx(struct macb *bp, int budget)
>>>>  
>>>>  		skb->protocol = eth_type_trans(skb, bp->dev);
>>>>  		skb_checksum_none_assert(skb);
>>>> +		if (bp->dev->features & NETIF_F_RXCSUM)
>>>> +			skb->ip_summed = CHECKSUM_UNNECESSARY;
>>>>  
>>>
>>>
>>> Really ?
>>>
>>> If this is what you meant, this deserves a big and fat comment.
>>>
>>>
>>>
>> Hi Eric,
>>
>> Isn't it the proper way to do? According to Cadence documentation
>> about RX checksum offload:
>> "If any of the checksums (IP, TCP or UDP) are verified incorrect by
>> the GEM, the packet is discarded."
>>
>> If I understand, when RX checksum offload is enabled setting bit 24 of
>> the Network Configuration Register, the driver only receives RX frames
>> with correct checksum. Then it tells the kernel that there's no need
>> to verify the checksum again in software. This is done setting
>> skb->ip_summed to CHECKSUM_UNNECESSARY. Intel e1000 driver does the
>> same in e1000_rx_checksum() function.
>>
>> Also bit 24 of the Network Configuration Register is updated by
>> macb_open() and macb_set_features() so it always matches the state of
>> NETIF_F_RXCSUM flag in dev->features, once the network interface is
>> up. That's why I'd rather read from dev->features than read from
>> register.
>>
>> Did I make a mistake? Is it the kind of comment you expect to be
>> added?
>>
>> Regards,
> 
> Usually, frames are not discarded, and a bit is present in rx descriptor
> to tell us if (TCP) checksum was validated by the NIC
> 
> We want tcpdump to get a copy of corrupted TCP frames, even if TCP stack
> drops them later.
> 
> If this NIC drops incorrect frames, I am afraid we cant use this RX
> offload at all.
> 
> 
> 
OK thanks for your comments. In the next series of patches I'll allow RX 
checksum offload only when promiscuous mode is disabled. Also I'll check the
status returned by the GEM through the buffer descriptor.

Regards,

Cyrille
diff mbox

Patch

diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 9bdcd1b..6acd6e2 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -766,6 +766,8 @@  static int gem_rx(struct macb *bp, int budget)
 
 		skb->protocol = eth_type_trans(skb, bp->dev);
 		skb_checksum_none_assert(skb);
+		if (bp->dev->features & NETIF_F_RXCSUM)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
 
 		bp->stats.rx_packets++;
 		bp->stats.rx_bytes += skb->len;
@@ -1506,6 +1508,18 @@  static u32 macb_dbw(struct macb *bp)
 }
 
 /*
+ * Configure the RX checksum offload
+ */
+static u32 macb_rxcsum(struct macb *bp)
+{
+	if (macb_is_gem(bp) &&
+	    (bp->dev->features & NETIF_F_RXCSUM))
+		return GEM_BIT(RXCOEN);
+
+	return 0;
+}
+
+/*
  * Configure the receive DMA engine
  * - use the correct receive buffer size
  * - set best burst length for DMA operations
@@ -1550,6 +1564,7 @@  static void macb_init_hw(struct macb *bp)
 	if (!(bp->dev->flags & IFF_BROADCAST))
 		config |= MACB_BIT(NBC);	/* No BroadCast */
 	config |= macb_dbw(bp);
+	config |= macb_rxcsum(bp);
 	macb_writel(bp, NCFGR, config);
 	bp->speed = SPEED_10;
 	bp->duplex = DUPLEX_HALF;
@@ -1945,6 +1960,18 @@  static int macb_set_features(struct net_device *netdev,
 		gem_writel(bp, DMACFG, dmacfg);
 	}
 
+	/* RX checksum offload */
+	if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) {
+		u32 netcfg;
+
+		netcfg = gem_readl(bp, NCFGR);
+		if (features & NETIF_F_RXCSUM)
+			netcfg |= GEM_BIT(RXCOEN);
+		else
+			netcfg &= ~GEM_BIT(RXCOEN);
+		gem_writel(bp, NCFGR, netcfg);
+	}
+
 	return 0;
 }
 
@@ -2146,7 +2173,7 @@  static int __init macb_probe(struct platform_device *pdev)
 	dev->hw_features = NETIF_F_SG;
 	if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) {
 		/* Checksum offload is only available on packet buffer design */
-		dev->hw_features |= NETIF_F_HW_CSUM;
+		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
 	}
 	if (bp->caps & MACB_CAPS_SG_DISABLED)
 		dev->hw_features &= ~NETIF_F_SG;
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 7bf8285..3678b83 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -164,6 +164,8 @@ 
 #define GEM_CLK_SIZE				3
 #define GEM_DBW_OFFSET				21
 #define GEM_DBW_SIZE				2
+#define GEM_RXCOEN_OFFSET			24
+#define GEM_RXCOEN_SIZE				1
 
 /* Constants for data bus width. */
 #define GEM_DBW32				0