diff options
-rw-r--r-- | drivers/net/ibmveth.c | 53 | ||||
-rw-r--r-- | drivers/net/ibmveth.h | 41 |
2 files changed, 92 insertions, 2 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0c35d72f5f8d..9353890dcda0 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -47,6 +47,8 @@ | |||
47 | #include <linux/mm.h> | 47 | #include <linux/mm.h> |
48 | #include <linux/ethtool.h> | 48 | #include <linux/ethtool.h> |
49 | #include <linux/proc_fs.h> | 49 | #include <linux/proc_fs.h> |
50 | #include <linux/in.h> | ||
51 | #include <linux/ip.h> | ||
50 | #include <net/net_namespace.h> | 52 | #include <net/net_namespace.h> |
51 | #include <asm/semaphore.h> | 53 | #include <asm/semaphore.h> |
52 | #include <asm/hvcall.h> | 54 | #include <asm/hvcall.h> |
@@ -132,6 +134,11 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) | |||
132 | return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); | 134 | return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); |
133 | } | 135 | } |
134 | 136 | ||
137 | static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter) | ||
138 | { | ||
139 | return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good); | ||
140 | } | ||
141 | |||
135 | /* setup the initial settings for a buffer pool */ | 142 | /* setup the initial settings for a buffer pool */ |
136 | static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) | 143 | static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) |
137 | { | 144 | { |
@@ -695,6 +702,24 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
695 | desc[0].fields.length, DMA_TO_DEVICE); | 702 | desc[0].fields.length, DMA_TO_DEVICE); |
696 | desc[0].fields.valid = 1; | 703 | desc[0].fields.valid = 1; |
697 | 704 | ||
705 | if (skb->ip_summed == CHECKSUM_PARTIAL && | ||
706 | ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { | ||
707 | ibmveth_error_printk("tx: failed to checksum packet\n"); | ||
708 | tx_dropped++; | ||
709 | goto out; | ||
710 | } | ||
711 | |||
712 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
713 | unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; | ||
714 | |||
715 | desc[0].fields.no_csum = 1; | ||
716 | desc[0].fields.csum_good = 1; | ||
717 | |||
718 | /* Need to zero out the checksum */ | ||
719 | buf[0] = 0; | ||
720 | buf[1] = 0; | ||
721 | } | ||
722 | |||
698 | if(dma_mapping_error(desc[0].fields.address)) { | 723 | if(dma_mapping_error(desc[0].fields.address)) { |
699 | ibmveth_error_printk("tx: unable to map initial fragment\n"); | 724 | ibmveth_error_printk("tx: unable to map initial fragment\n"); |
700 | tx_map_failed++; | 725 | tx_map_failed++; |
@@ -713,6 +738,10 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
713 | frag->size, DMA_TO_DEVICE); | 738 | frag->size, DMA_TO_DEVICE); |
714 | desc[curfrag+1].fields.length = frag->size; | 739 | desc[curfrag+1].fields.length = frag->size; |
715 | desc[curfrag+1].fields.valid = 1; | 740 | desc[curfrag+1].fields.valid = 1; |
741 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
742 | desc[curfrag+1].fields.no_csum = 1; | ||
743 | desc[curfrag+1].fields.csum_good = 1; | ||
744 | } | ||
716 | 745 | ||
717 | if(dma_mapping_error(desc[curfrag+1].fields.address)) { | 746 | if(dma_mapping_error(desc[curfrag+1].fields.address)) { |
718 | ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); | 747 | ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); |
@@ -801,7 +830,11 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) | |||
801 | } else { | 830 | } else { |
802 | int length = ibmveth_rxq_frame_length(adapter); | 831 | int length = ibmveth_rxq_frame_length(adapter); |
803 | int offset = ibmveth_rxq_frame_offset(adapter); | 832 | int offset = ibmveth_rxq_frame_offset(adapter); |
833 | int csum_good = ibmveth_rxq_csum_good(adapter); | ||
834 | |||
804 | skb = ibmveth_rxq_get_buffer(adapter); | 835 | skb = ibmveth_rxq_get_buffer(adapter); |
836 | if (csum_good) | ||
837 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
805 | 838 | ||
806 | ibmveth_rxq_harvest_buffer(adapter); | 839 | ibmveth_rxq_harvest_buffer(adapter); |
807 | 840 | ||
@@ -962,8 +995,10 @@ static void ibmveth_poll_controller(struct net_device *dev) | |||
962 | static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) | 995 | static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) |
963 | { | 996 | { |
964 | int rc, i; | 997 | int rc, i; |
998 | long ret; | ||
965 | struct net_device *netdev; | 999 | struct net_device *netdev; |
966 | struct ibmveth_adapter *adapter; | 1000 | struct ibmveth_adapter *adapter; |
1001 | union ibmveth_illan_attributes set_attr, ret_attr; | ||
967 | 1002 | ||
968 | unsigned char *mac_addr_p; | 1003 | unsigned char *mac_addr_p; |
969 | unsigned int *mcastFilterSize_p; | 1004 | unsigned int *mcastFilterSize_p; |
@@ -1057,6 +1092,24 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ | |||
1057 | 1092 | ||
1058 | ibmveth_debug_printk("registering netdev...\n"); | 1093 | ibmveth_debug_printk("registering netdev...\n"); |
1059 | 1094 | ||
1095 | ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc); | ||
1096 | |||
1097 | if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && | ||
1098 | !ret_attr.fields.trunk_priority && | ||
1099 | ret_attr.fields.csum_offload_padded_pkt_support) { | ||
1100 | set_attr.desc = 0; | ||
1101 | set_attr.fields.tcp_csum_offload_ipv4 = 1; | ||
1102 | |||
1103 | ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, | ||
1104 | &ret_attr.desc); | ||
1105 | |||
1106 | if (ret == H_SUCCESS) | ||
1107 | netdev->features |= NETIF_F_IP_CSUM; | ||
1108 | else | ||
1109 | ret = h_illan_attributes(dev->unit_address, set_attr.desc, | ||
1110 | 0, &ret_attr.desc); | ||
1111 | } | ||
1112 | |||
1060 | rc = register_netdev(netdev); | 1113 | rc = register_netdev(netdev); |
1061 | 1114 | ||
1062 | if(rc) { | 1115 | if(rc) { |
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index e05694126f85..3f10f0f4447a 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h | |||
@@ -67,6 +67,21 @@ static inline long h_send_logical_lan(unsigned long unit_address, | |||
67 | return rc; | 67 | return rc; |
68 | } | 68 | } |
69 | 69 | ||
70 | static inline long h_illan_attributes(unsigned long unit_address, | ||
71 | unsigned long reset_mask, unsigned long set_mask, | ||
72 | unsigned long *ret_attributes) | ||
73 | { | ||
74 | long rc; | ||
75 | unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; | ||
76 | |||
77 | rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address, | ||
78 | reset_mask, set_mask); | ||
79 | |||
80 | *ret_attributes = retbuf[0]; | ||
81 | |||
82 | return rc; | ||
83 | } | ||
84 | |||
70 | #define h_multicast_ctrl(ua, cmd, mac) \ | 85 | #define h_multicast_ctrl(ua, cmd, mac) \ |
71 | plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac) | 86 | plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac) |
72 | 87 | ||
@@ -142,7 +157,9 @@ struct ibmveth_adapter { | |||
142 | struct ibmveth_buf_desc_fields { | 157 | struct ibmveth_buf_desc_fields { |
143 | u32 valid : 1; | 158 | u32 valid : 1; |
144 | u32 toggle : 1; | 159 | u32 toggle : 1; |
145 | u32 reserved : 6; | 160 | u32 reserved : 4; |
161 | u32 no_csum : 1; | ||
162 | u32 csum_good : 1; | ||
146 | u32 length : 24; | 163 | u32 length : 24; |
147 | u32 address; | 164 | u32 address; |
148 | }; | 165 | }; |
@@ -152,10 +169,30 @@ union ibmveth_buf_desc { | |||
152 | struct ibmveth_buf_desc_fields fields; | 169 | struct ibmveth_buf_desc_fields fields; |
153 | }; | 170 | }; |
154 | 171 | ||
172 | struct ibmveth_illan_attributes_fields { | ||
173 | u32 reserved; | ||
174 | u32 reserved2 : 18; | ||
175 | u32 csum_offload_padded_pkt_support : 1; | ||
176 | u32 reserved3 : 1; | ||
177 | u32 trunk_priority : 4; | ||
178 | u32 reserved4 : 5; | ||
179 | u32 tcp_csum_offload_ipv6 : 1; | ||
180 | u32 tcp_csum_offload_ipv4 : 1; | ||
181 | u32 active_trunk : 1; | ||
182 | }; | ||
183 | |||
184 | union ibmveth_illan_attributes { | ||
185 | u64 desc; | ||
186 | struct ibmveth_illan_attributes_fields fields; | ||
187 | }; | ||
188 | |||
155 | struct ibmveth_rx_q_entry { | 189 | struct ibmveth_rx_q_entry { |
156 | u16 toggle : 1; | 190 | u16 toggle : 1; |
157 | u16 valid : 1; | 191 | u16 valid : 1; |
158 | u16 reserved : 14; | 192 | u16 reserved : 4; |
193 | u16 no_csum : 1; | ||
194 | u16 csum_good : 1; | ||
195 | u16 reserved2 : 8; | ||
159 | u16 offset; | 196 | u16 offset; |
160 | u32 length; | 197 | u32 length; |
161 | u64 correlator; | 198 | u64 correlator; |