@@ -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)
@@ -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 {