From: Dmitry Bezrukov <dmitry.bezru...@aquantia.com> Signed-off-by: Dmitry Bezrukov <dmitry.bezru...@aquantia.com> Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com> --- drivers/net/usb/aqc111.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- drivers/net/usb/aqc111.h | 1 + 2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c index 134cfc632584..6efd9a9ad44e 100644 --- a/drivers/net/usb/aqc111.c +++ b/drivers/net/usb/aqc111.c @@ -332,6 +332,46 @@ static int aqc111_set_mac_addr(struct net_device *net, void *p) ETH_ALEN, net->dev_addr); } +static int aqc111_set_features(struct net_device *net, + netdev_features_t features) +{ + u8 reg8 = 0; + struct usbnet *dev = netdev_priv(net); + struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0]; + netdev_features_t changed = net->features ^ features; + + if (changed & NETIF_F_IP_CSUM) { + aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); + reg8 ^= SFR_TXCOE_TCP | SFR_TXCOE_UDP; + aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, + 1, 1, ®8); + } + + if (changed & NETIF_F_IPV6_CSUM) { + aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, 1, 1, ®8); + reg8 ^= SFR_TXCOE_TCPV6 | SFR_TXCOE_UDPV6; + aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_TXCOE_CTL, + 1, 1, ®8); + } + + if (changed & NETIF_F_RXCSUM) { + aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_RXCOE_CTL, 1, 1, ®8); + if (features & NETIF_F_RXCSUM) { + aqc111_data->rx_checksum = 1; + reg8 &= ~(SFR_RXCOE_IP | SFR_RXCOE_TCP | SFR_RXCOE_UDP | + SFR_RXCOE_TCPV6 | SFR_RXCOE_UDPV6); + } else { + aqc111_data->rx_checksum = 0; + 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); + } + return 0; +} + static const struct net_device_ops aqc111_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, @@ -341,6 +381,7 @@ static const struct net_device_ops aqc111_netdev_ops = { .ndo_change_mtu = aqc111_change_mtu, .ndo_set_mac_address = aqc111_set_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_set_features = aqc111_set_features, }; static int aqc111_get_mac(struct usbnet *dev, u8 *buf) @@ -814,6 +855,7 @@ static void aqc111_rx_checksum(struct sk_buff *skb, void *pkt_hdr) static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { struct sk_buff *new_skb = NULL; + struct aqc111_data *aqc111_data = (struct aqc111_data *)dev->data[0]; u32 skb_len = 0; u32 desc_offset = 0; /*RX Header Offset*/ u32 start_of_descs = 0; @@ -886,7 +928,8 @@ 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); + if (aqc111_data->rx_checksum) + 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 1632e78ebe9b..0be2e4cbb00a 100644 --- a/drivers/net/usb/aqc111.h +++ b/drivers/net/usb/aqc111.h @@ -205,6 +205,7 @@ struct aqc111_phy_options { }; struct aqc111_data { + u8 rx_checksum; u8 link_speed; u8 link; u8 autoneg; -- 2.7.4