]>
Commit | Line | Data |
---|---|---|
a7b0967d MT |
1 | From a4ec4f58017b456281ee17c35fb82dfe4eab2193 Mon Sep 17 00:00:00 2001 |
2 | From: KY Srinivasan <kys@microsoft.com> | |
3 | Date: Sat, 8 Mar 2014 19:23:18 -0800 | |
4 | Subject: [PATCH 10/25] Drivers: net: hyperv: Enable large send offload | |
5 | ||
6 | Enable segmentation offload. | |
7 | ||
8 | Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> | |
9 | Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> | |
10 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
11 | --- | |
12 | drivers/net/hyperv/hyperv_net.h | 40 ++++++++++++++++++++++++++++++++++++++++ | |
13 | drivers/net/hyperv/netvsc_drv.c | 38 ++++++++++++++++++++++++++++++++++---- | |
14 | 2 files changed, 74 insertions(+), 4 deletions(-) | |
15 | ||
16 | diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h | |
17 | index 4cf238234321..7d06b4959383 100644 | |
18 | --- a/drivers/net/hyperv/hyperv_net.h | |
19 | +++ b/drivers/net/hyperv/hyperv_net.h | |
20 | @@ -742,6 +742,10 @@ struct ndis_oject_header { | |
21 | #define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 | |
22 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 | |
23 | ||
24 | +#define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1 | |
25 | +#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 | |
26 | +#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 | |
27 | + | |
28 | /* | |
29 | * New offload OIDs for NDIS 6 | |
30 | */ | |
31 | @@ -804,12 +808,48 @@ struct ndis_tcp_ip_checksum_info { | |
32 | }; | |
33 | }; | |
34 | ||
35 | +struct ndis_tcp_lso_info { | |
36 | + union { | |
37 | + struct { | |
38 | + u32 unused:30; | |
39 | + u32 type:1; | |
40 | + u32 reserved2:1; | |
41 | + } transmit; | |
42 | + struct { | |
43 | + u32 mss:20; | |
44 | + u32 tcp_header_offset:10; | |
45 | + u32 type:1; | |
46 | + u32 reserved2:1; | |
47 | + } lso_v1_transmit; | |
48 | + struct { | |
49 | + u32 tcp_payload:30; | |
50 | + u32 type:1; | |
51 | + u32 reserved2:1; | |
52 | + } lso_v1_transmit_complete; | |
53 | + struct { | |
54 | + u32 mss:20; | |
55 | + u32 tcp_header_offset:10; | |
56 | + u32 type:1; | |
57 | + u32 ip_version:1; | |
58 | + } lso_v2_transmit; | |
59 | + struct { | |
60 | + u32 reserved:30; | |
61 | + u32 type:1; | |
62 | + u32 reserved2:1; | |
63 | + } lso_v2_transmit_complete; | |
64 | + u32 value; | |
65 | + }; | |
66 | +}; | |
67 | + | |
68 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | |
69 | sizeof(struct ndis_pkt_8021q_info)) | |
70 | ||
71 | #define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | |
72 | sizeof(struct ndis_tcp_ip_checksum_info)) | |
73 | ||
74 | +#define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | |
75 | + sizeof(struct ndis_tcp_lso_info)) | |
76 | + | |
77 | /* Format of Information buffer passed in a SetRequest for the OID */ | |
78 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ | |
79 | struct rndis_config_parameter_info { | |
80 | diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c | |
81 | index 2fab69ac61ef..5baa1fa7e692 100644 | |
82 | --- a/drivers/net/hyperv/netvsc_drv.c | |
83 | +++ b/drivers/net/hyperv/netvsc_drv.c | |
84 | @@ -299,6 +299,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |
85 | bool isvlan; | |
86 | struct rndis_per_packet_info *ppi; | |
87 | struct ndis_tcp_ip_checksum_info *csum_info; | |
88 | + struct ndis_tcp_lso_info *lso_info; | |
89 | int hdr_offset; | |
90 | u32 net_trans_info; | |
91 | ||
92 | @@ -378,7 +379,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |
93 | * GSO packet. | |
94 | */ | |
95 | if (skb_is_gso(skb)) | |
96 | - goto do_send; | |
97 | + goto do_lso; | |
98 | ||
99 | rndis_msg_size += NDIS_CSUM_PPI_SIZE; | |
100 | ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, | |
101 | @@ -398,6 +399,35 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |
102 | } else if (net_trans_info & INFO_UDP) { | |
103 | csum_info->transmit.udp_checksum = 1; | |
104 | } | |
105 | + goto do_send; | |
106 | + | |
107 | +do_lso: | |
108 | + rndis_msg_size += NDIS_LSO_PPI_SIZE; | |
109 | + ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE, | |
110 | + TCP_LARGESEND_PKTINFO); | |
111 | + | |
112 | + lso_info = (struct ndis_tcp_lso_info *)((void *)ppi + | |
113 | + ppi->ppi_offset); | |
114 | + | |
115 | + lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; | |
116 | + if (net_trans_info & (INFO_IPV4 << 16)) { | |
117 | + lso_info->lso_v2_transmit.ip_version = | |
118 | + NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; | |
119 | + ip_hdr(skb)->tot_len = 0; | |
120 | + ip_hdr(skb)->check = 0; | |
121 | + tcp_hdr(skb)->check = | |
122 | + ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | |
123 | + ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); | |
124 | + } else { | |
125 | + lso_info->lso_v2_transmit.ip_version = | |
126 | + NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; | |
127 | + ipv6_hdr(skb)->payload_len = 0; | |
128 | + tcp_hdr(skb)->check = | |
129 | + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | |
130 | + &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); | |
131 | + } | |
132 | + lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; | |
133 | + lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; | |
134 | ||
135 | do_send: | |
136 | /* Start filling in the page buffers with the rndis hdr */ | |
137 | @@ -655,10 +685,10 @@ static int netvsc_probe(struct hv_device *dev, | |
138 | ||
139 | net->netdev_ops = &device_ops; | |
140 | ||
141 | - /* TODO: Add GSO and Checksum offload */ | |
142 | - net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; | |
143 | + net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM | | |
144 | + NETIF_F_TSO; | |
145 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | | |
146 | - NETIF_F_IP_CSUM; | |
147 | + NETIF_F_IP_CSUM | NETIF_F_TSO; | |
148 | ||
149 | SET_ETHTOOL_OPS(net, ðtool_ops); | |
150 | SET_NETDEV_DEV(net, &dev->device); | |
151 | -- | |
152 | 2.4.3 | |
153 |