diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ab80d8fcccbf1b8ac6b5d6bdea27fac8e0518585..25cf7e0476d0a00c993e9fc85b7738464c9461cb 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +149,8 @@ struct ibmveth_stat ibmveth_stats[] = { { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, + { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) }, + { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) }, }; /* simple methods of getting data from the current rxq entry */ @@ -773,6 +776,7 @@ static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) */ adapter->rx_csum = 0; dev->features &= ~NETIF_F_IP_CSUM; + dev->features &= ~NETIF_F_IPV6_CSUM; } } @@ -781,10 +785,15 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) struct ibmveth_adapter *adapter = netdev_priv(dev); if (data) { - dev->features |= NETIF_F_IP_CSUM; + if (adapter->fw_ipv4_csum_support) + dev->features |= NETIF_F_IP_CSUM; + if (adapter->fw_ipv6_csum_support) + dev->features |= NETIF_F_IPV6_CSUM; adapter->rx_csum = 1; - } else + } else { dev->features &= ~NETIF_F_IP_CSUM; + dev->features &= ~NETIF_F_IPV6_CSUM; + } } static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, @@ -792,7 +801,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, { struct ibmveth_adapter *adapter = netdev_priv(dev); unsigned long set_attr, clr_attr, ret_attr; - long ret; + unsigned long set_attr6, clr_attr6; + long ret, ret6; int rc1 = 0, rc2 = 0; int restart = 0; @@ -806,10 +816,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, set_attr = 0; clr_attr = 0; - if (data) + if (data) { set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; - else + set_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM; + } else { clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; + clr_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM; + } ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); @@ -820,14 +833,33 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, set_attr, &ret_attr); if (ret != H_SUCCESS) { - rc1 = -EIO; - ibmveth_error_printk("unable to change checksum offload settings." - " %d rc=%ld\n", data, ret); + ibmveth_error_printk("unable to change IPv4 checksum " + "offload settings. %d rc=%ld\n", + data, ret); ret = h_illan_attributes(adapter->vdev->unit_address, set_attr, clr_attr, &ret_attr); } else + adapter->fw_ipv4_csum_support = data; + + ret6 = h_illan_attributes(adapter->vdev->unit_address, + clr_attr6, set_attr6, &ret_attr); + + if (ret6 != H_SUCCESS) { + ibmveth_error_printk("unable to change IPv6 checksum " + "offload settings. %d rc=%ld\n", + data, ret); + + ret = h_illan_attributes(adapter->vdev->unit_address, + set_attr6, clr_attr6, + &ret_attr); + } else + adapter->fw_ipv6_csum_support = data; + + if (ret == H_SUCCESS || ret6 == H_SUCCESS) done(dev, data); + else + rc1 = -EIO; } else { rc1 = -EIO; ibmveth_error_printk("unable to change checksum offload settings." @@ -855,9 +887,9 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) struct ibmveth_adapter *adapter = netdev_priv(dev); int rc = 0; - if (data && (dev->features & NETIF_F_IP_CSUM)) + if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) return 0; - if (!data && !(dev->features & NETIF_F_IP_CSUM)) + if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) return 0; if (data && !adapter->rx_csum) @@ -975,7 +1007,12 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, /* veth can't checksum offload UDP */ if (skb->ip_summed == CHECKSUM_PARTIAL && - ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { + ((skb->protocol == htons(ETH_P_IP) && + ip_hdr(skb)->protocol != IPPROTO_TCP) || + (skb->protocol == htons(ETH_P_IPV6) && + ipv6_hdr(skb)->nexthdr != IPPROTO_TCP)) && + skb_checksum_help(skb)) { + ibmveth_error_printk("tx: failed to checksum packet\n"); netdev->stats.tx_dropped++; goto out; diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index d5651c79e19996ecaf1daef4e40d89e71ca1b167..84e4ab224124435c1d9d9179c30c216baaa672f0 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -149,6 +149,8 @@ struct ibmveth_adapter { void *bounce_buffer; dma_addr_t bounce_buffer_dma; + u64 fw_ipv6_csum_support; + u64 fw_ipv4_csum_support; /* adapter specific stats */ u64 replenish_task_cycles; u64 replenish_no_mem;