From: Dmitry Bezrukov <dmitry.bezrukov@xxxxxxxxxxxx> Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@xxxxxxxxxxxx> Signed-off-by: Igor Russkikh <igor.russkikh@xxxxxxxxxxxx> --- drivers/net/usb/aqc111.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 23 +++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c index fc068e731335..5967f7adeab4 100644 --- a/drivers/net/usb/aqc111.c +++ b/drivers/net/usb/aqc111.c @@ -537,6 +537,26 @@ static void aqc111_configure_rx(struct usbnet *dev, netdev_info(dev->net, "Link Speed %d, USB %d", link_speed, usb_host); } +static void aqc111_configure_csum_offload(struct usbnet *dev) +{ + u8 reg8 = 0; + + if (dev->net->features & NETIF_F_RXCSUM) { + reg8 |= SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | + SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6; + } + aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); + + reg8 = 0; + if (dev->net->features & NETIF_F_IP_CSUM) + reg8 |= SFR_TXCOE_IP | SFR_TXCOE_TCP | SFR_TXCOE_UDP; + + if (dev->net->features & NETIF_F_IPV6_CSUM) + reg8 |= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; + + aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); +} + static int aqc111_link_reset(struct usbnet *dev) { u8 reg8 = 0; @@ -580,6 +600,8 @@ static int aqc111_link_reset(struct usbnet *dev) aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 2, 2, ®16); + aqc111_configure_csum_offload(dev); + aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 2, 2, ®16); @@ -713,6 +735,21 @@ static int aqc111_stop(struct usbnet *dev) return 0; } +static void aqc111_rx_checksum(struct sk_buff *skb, void *pkt_hdr) +{ + struct aq_rx_packet_desc *hdr = (struct aq_rx_packet_desc *)pkt_hdr; + + skb->ip_summed = CHECKSUM_NONE; + /* checksum error bit is set */ + if (hdr->l4_err || hdr->l3_err) + return; + + /* It must be a TCP or UDP packet with a valid checksum */ + if (hdr->l4_pkt_type == AQ_RXHDR_L4_TYPE_TCP || + hdr->l4_pkt_type == AQ_RXHDR_L4_TYPE_UDP) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { struct sk_buff *new_skb = NULL; @@ -788,6 +825,7 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_set_tail_pointer(new_skb, new_skb->len); new_skb->truesize = new_skb->len + sizeof(struct sk_buff); + aqc111_rx_checksum(new_skb, &pkt_desc); usbnet_skb_return(dev, new_skb); if (pkt_count == 0) diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h index 679ca9f992f7..1632e78ebe9b 100644 --- a/drivers/net/usb/aqc111.h +++ b/drivers/net/usb/aqc111.h @@ -63,8 +63,11 @@ #define AQ_USB_SET_TIMEOUT 4000 /* Feature. ********************************************/ -#define AQ_SUPPORT_FEATURE (NETIF_F_SG) -#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG) +#define AQ_SUPPORT_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM) + +#define AQ_SUPPORT_HW_FEATURE (NETIF_F_SG | NETIF_F_IP_CSUM |\ + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM) /* SFR Reg. ********************************************/ @@ -230,6 +233,22 @@ struct aqc111_int_data { #define AQ_INT_SPEED_1G 0x11 #define AQ_INT_SPEED_100M 0x13 +#define AQ_RXHDR_L4_ERR BIT(8) +#define AQ_RXHDR_L3_ERR BIT(9) + +#define AQ_RXHDR_L4_TYPE_ICMP 0x02 +#define AQ_RXHDR_L4_TYPE_IGMP 0x03 +#define AQ_RXHDR_L4_TYPE_TCMPV6 0x05 + +#define AQ_RXHDR_L3_TYPE_IP 0x01 +#define AQ_RXHDR_L3_TYPE_IPV6 0x02 + +#define AQ_RXHDR_L4_TYPE_MASK 0x1c +#define AQ_RXHDR_L4_TYPE_UDP 0x04 +#define AQ_RXHDR_L4_TYPE_TCP 0x10 +#define AQ_RXHDR_L3CSUM_ERR 0x02 +#define AQ_RXHDR_L4CSUM_ERR 0x01 + #define AQ_RX_HW_PAD 0x02 struct aq_tx_packet_desc { -- 2.7.4