diff options
Diffstat (limited to 'drivers/net/ibmveth.c')
-rw-r--r-- | drivers/net/ibmveth.c | 59 |
1 files changed, 48 insertions, 11 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ab80d8fcccbf..25cf7e0476d0 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
51 | #include <linux/in.h> | 51 | #include <linux/in.h> |
52 | #include <linux/ip.h> | 52 | #include <linux/ip.h> |
53 | #include <linux/ipv6.h> | ||
53 | #include <linux/slab.h> | 54 | #include <linux/slab.h> |
54 | #include <net/net_namespace.h> | 55 | #include <net/net_namespace.h> |
55 | #include <asm/hvcall.h> | 56 | #include <asm/hvcall.h> |
@@ -148,6 +149,8 @@ struct ibmveth_stat ibmveth_stats[] = { | |||
148 | { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, | 149 | { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, |
149 | { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, | 150 | { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, |
150 | { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, | 151 | { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, |
152 | { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) }, | ||
153 | { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) }, | ||
151 | }; | 154 | }; |
152 | 155 | ||
153 | /* simple methods of getting data from the current rxq entry */ | 156 | /* 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) | |||
773 | */ | 776 | */ |
774 | adapter->rx_csum = 0; | 777 | adapter->rx_csum = 0; |
775 | dev->features &= ~NETIF_F_IP_CSUM; | 778 | dev->features &= ~NETIF_F_IP_CSUM; |
779 | dev->features &= ~NETIF_F_IPV6_CSUM; | ||
776 | } | 780 | } |
777 | } | 781 | } |
778 | 782 | ||
@@ -781,10 +785,15 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) | |||
781 | struct ibmveth_adapter *adapter = netdev_priv(dev); | 785 | struct ibmveth_adapter *adapter = netdev_priv(dev); |
782 | 786 | ||
783 | if (data) { | 787 | if (data) { |
784 | dev->features |= NETIF_F_IP_CSUM; | 788 | if (adapter->fw_ipv4_csum_support) |
789 | dev->features |= NETIF_F_IP_CSUM; | ||
790 | if (adapter->fw_ipv6_csum_support) | ||
791 | dev->features |= NETIF_F_IPV6_CSUM; | ||
785 | adapter->rx_csum = 1; | 792 | adapter->rx_csum = 1; |
786 | } else | 793 | } else { |
787 | dev->features &= ~NETIF_F_IP_CSUM; | 794 | dev->features &= ~NETIF_F_IP_CSUM; |
795 | dev->features &= ~NETIF_F_IPV6_CSUM; | ||
796 | } | ||
788 | } | 797 | } |
789 | 798 | ||
790 | static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, | 799 | 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, | |||
792 | { | 801 | { |
793 | struct ibmveth_adapter *adapter = netdev_priv(dev); | 802 | struct ibmveth_adapter *adapter = netdev_priv(dev); |
794 | unsigned long set_attr, clr_attr, ret_attr; | 803 | unsigned long set_attr, clr_attr, ret_attr; |
795 | long ret; | 804 | unsigned long set_attr6, clr_attr6; |
805 | long ret, ret6; | ||
796 | int rc1 = 0, rc2 = 0; | 806 | int rc1 = 0, rc2 = 0; |
797 | int restart = 0; | 807 | int restart = 0; |
798 | 808 | ||
@@ -806,10 +816,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, | |||
806 | set_attr = 0; | 816 | set_attr = 0; |
807 | clr_attr = 0; | 817 | clr_attr = 0; |
808 | 818 | ||
809 | if (data) | 819 | if (data) { |
810 | set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; | 820 | set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; |
811 | else | 821 | set_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM; |
822 | } else { | ||
812 | clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; | 823 | clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; |
824 | clr_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM; | ||
825 | } | ||
813 | 826 | ||
814 | ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); | 827 | ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); |
815 | 828 | ||
@@ -820,14 +833,33 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, | |||
820 | set_attr, &ret_attr); | 833 | set_attr, &ret_attr); |
821 | 834 | ||
822 | if (ret != H_SUCCESS) { | 835 | if (ret != H_SUCCESS) { |
823 | rc1 = -EIO; | 836 | ibmveth_error_printk("unable to change IPv4 checksum " |
824 | ibmveth_error_printk("unable to change checksum offload settings." | 837 | "offload settings. %d rc=%ld\n", |
825 | " %d rc=%ld\n", data, ret); | 838 | data, ret); |
826 | 839 | ||
827 | ret = h_illan_attributes(adapter->vdev->unit_address, | 840 | ret = h_illan_attributes(adapter->vdev->unit_address, |
828 | set_attr, clr_attr, &ret_attr); | 841 | set_attr, clr_attr, &ret_attr); |
829 | } else | 842 | } else |
843 | adapter->fw_ipv4_csum_support = data; | ||
844 | |||
845 | ret6 = h_illan_attributes(adapter->vdev->unit_address, | ||
846 | clr_attr6, set_attr6, &ret_attr); | ||
847 | |||
848 | if (ret6 != H_SUCCESS) { | ||
849 | ibmveth_error_printk("unable to change IPv6 checksum " | ||
850 | "offload settings. %d rc=%ld\n", | ||
851 | data, ret); | ||
852 | |||
853 | ret = h_illan_attributes(adapter->vdev->unit_address, | ||
854 | set_attr6, clr_attr6, | ||
855 | &ret_attr); | ||
856 | } else | ||
857 | adapter->fw_ipv6_csum_support = data; | ||
858 | |||
859 | if (ret == H_SUCCESS || ret6 == H_SUCCESS) | ||
830 | done(dev, data); | 860 | done(dev, data); |
861 | else | ||
862 | rc1 = -EIO; | ||
831 | } else { | 863 | } else { |
832 | rc1 = -EIO; | 864 | rc1 = -EIO; |
833 | ibmveth_error_printk("unable to change checksum offload settings." | 865 | 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) | |||
855 | struct ibmveth_adapter *adapter = netdev_priv(dev); | 887 | struct ibmveth_adapter *adapter = netdev_priv(dev); |
856 | int rc = 0; | 888 | int rc = 0; |
857 | 889 | ||
858 | if (data && (dev->features & NETIF_F_IP_CSUM)) | 890 | if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) |
859 | return 0; | 891 | return 0; |
860 | if (!data && !(dev->features & NETIF_F_IP_CSUM)) | 892 | if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) |
861 | return 0; | 893 | return 0; |
862 | 894 | ||
863 | if (data && !adapter->rx_csum) | 895 | if (data && !adapter->rx_csum) |
@@ -975,7 +1007,12 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, | |||
975 | 1007 | ||
976 | /* veth can't checksum offload UDP */ | 1008 | /* veth can't checksum offload UDP */ |
977 | if (skb->ip_summed == CHECKSUM_PARTIAL && | 1009 | if (skb->ip_summed == CHECKSUM_PARTIAL && |
978 | ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { | 1010 | ((skb->protocol == htons(ETH_P_IP) && |
1011 | ip_hdr(skb)->protocol != IPPROTO_TCP) || | ||
1012 | (skb->protocol == htons(ETH_P_IPV6) && | ||
1013 | ipv6_hdr(skb)->nexthdr != IPPROTO_TCP)) && | ||
1014 | skb_checksum_help(skb)) { | ||
1015 | |||
979 | ibmveth_error_printk("tx: failed to checksum packet\n"); | 1016 | ibmveth_error_printk("tx: failed to checksum packet\n"); |
980 | netdev->stats.tx_dropped++; | 1017 | netdev->stats.tx_dropped++; |
981 | goto out; | 1018 | goto out; |