aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
authorKY Srinivasan <kys@microsoft.com>2014-03-08 22:23:14 -0500
committerDavid S. Miller <davem@davemloft.net>2014-03-10 15:51:37 -0400
commit8a00251a3682a23649cef36949c8019f8589c021 (patch)
tree1419e8e548d3d61696e6618f2aabcf33773ecf47 /drivers/net/hyperv
parent54a7357f7ac408be4ef4ca82900bd24cb6789f36 (diff)
Drivers: net: hyperv: Cleanup the send path
In preparation for enabling offloads, cleanup the send path. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r--drivers/net/hyperv/hyperv_net.h7
-rw-r--r--drivers/net/hyperv/netvsc_drv.c88
-rw-r--r--drivers/net/hyperv/rndis_filter.c66
3 files changed, 71 insertions, 90 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 39fc230f5c20..694bf7cada90 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -73,7 +73,7 @@ struct hv_netvsc_packet {
73 } completion; 73 } completion;
74 74
75 /* This points to the memory after page_buf */ 75 /* This points to the memory after page_buf */
76 void *extension; 76 struct rndis_message *rndis_msg;
77 77
78 u32 total_data_buflen; 78 u32 total_data_buflen;
79 /* Points to the send/receive buffer where the ethernet frame is */ 79 /* Points to the send/receive buffer where the ethernet frame is */
@@ -126,11 +126,6 @@ void rndis_filter_device_remove(struct hv_device *dev);
126int rndis_filter_receive(struct hv_device *dev, 126int rndis_filter_receive(struct hv_device *dev,
127 struct hv_netvsc_packet *pkt); 127 struct hv_netvsc_packet *pkt);
128 128
129
130
131int rndis_filter_send(struct hv_device *dev,
132 struct hv_netvsc_packet *pkt);
133
134int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); 129int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
135int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); 130int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
136 131
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 1f7b12f9e6fb..7010c0630d24 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -128,6 +128,27 @@ static int netvsc_close(struct net_device *net)
128 return ret; 128 return ret;
129} 129}
130 130
131static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
132 int pkt_type)
133{
134 struct rndis_packet *rndis_pkt;
135 struct rndis_per_packet_info *ppi;
136
137 rndis_pkt = &msg->msg.pkt;
138 rndis_pkt->data_offset += ppi_size;
139
140 ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt +
141 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len);
142
143 ppi->size = ppi_size;
144 ppi->type = pkt_type;
145 ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
146
147 rndis_pkt->per_pkt_info_len += ppi_size;
148
149 return ppi;
150}
151
131static void netvsc_xmit_completion(void *context) 152static void netvsc_xmit_completion(void *context)
132{ 153{
133 struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; 154 struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
@@ -174,8 +195,8 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
174 return j + 1; 195 return j + 1;
175} 196}
176 197
177static void init_page_array(void *hdr, u32 len, struct sk_buff *skb, 198static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
178 struct hv_page_buffer *pb) 199 struct hv_page_buffer *pb)
179{ 200{
180 u32 slots_used = 0; 201 u32 slots_used = 0;
181 char *data = skb->data; 202 char *data = skb->data;
@@ -203,6 +224,7 @@ static void init_page_array(void *hdr, u32 len, struct sk_buff *skb,
203 frag->page_offset, 224 frag->page_offset,
204 skb_frag_size(frag), &pb[slots_used]); 225 skb_frag_size(frag), &pb[slots_used]);
205 } 226 }
227 return slots_used;
206} 228}
207 229
208static int count_skb_frag_slots(struct sk_buff *skb) 230static int count_skb_frag_slots(struct sk_buff *skb)
@@ -240,14 +262,19 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
240 struct net_device_context *net_device_ctx = netdev_priv(net); 262 struct net_device_context *net_device_ctx = netdev_priv(net);
241 struct hv_netvsc_packet *packet; 263 struct hv_netvsc_packet *packet;
242 int ret; 264 int ret;
243 unsigned int num_data_pages; 265 unsigned int num_data_pgs;
266 struct rndis_message *rndis_msg;
267 struct rndis_packet *rndis_pkt;
268 u32 rndis_msg_size;
269 bool isvlan;
270 struct rndis_per_packet_info *ppi;
244 271
245 /* We will atmost need two pages to describe the rndis 272 /* We will atmost need two pages to describe the rndis
246 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number 273 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
247 * of pages in a single packet. 274 * of pages in a single packet.
248 */ 275 */
249 num_data_pages = netvsc_get_slots(skb) + 2; 276 num_data_pgs = netvsc_get_slots(skb) + 2;
250 if (num_data_pages > MAX_PAGE_BUFFER_COUNT) { 277 if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
251 netdev_err(net, "Packet too big: %u\n", skb->len); 278 netdev_err(net, "Packet too big: %u\n", skb->len);
252 dev_kfree_skb(skb); 279 dev_kfree_skb(skb);
253 net->stats.tx_dropped++; 280 net->stats.tx_dropped++;
@@ -256,7 +283,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
256 283
257 /* Allocate a netvsc packet based on # of frags. */ 284 /* Allocate a netvsc packet based on # of frags. */
258 packet = kzalloc(sizeof(struct hv_netvsc_packet) + 285 packet = kzalloc(sizeof(struct hv_netvsc_packet) +
259 (num_data_pages * sizeof(struct hv_page_buffer)) + 286 (num_data_pgs * sizeof(struct hv_page_buffer)) +
260 sizeof(struct rndis_message) + 287 sizeof(struct rndis_message) +
261 NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); 288 NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
262 if (!packet) { 289 if (!packet) {
@@ -270,26 +297,51 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
270 297
271 packet->vlan_tci = skb->vlan_tci; 298 packet->vlan_tci = skb->vlan_tci;
272 299
273 packet->extension = (void *)(unsigned long)packet + 300 packet->is_data_pkt = true;
274 sizeof(struct hv_netvsc_packet) +
275 (num_data_pages * sizeof(struct hv_page_buffer));
276
277 /* If the rndis msg goes beyond 1 page, we will add 1 later */
278 packet->page_buf_cnt = num_data_pages - 1;
279
280 /* Initialize it from the skb */
281 packet->total_data_buflen = skb->len; 301 packet->total_data_buflen = skb->len;
282 302
283 /* Start filling in the page buffers starting after RNDIS buffer. */ 303 packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
284 init_page_array(NULL, 0, skb, &packet->page_buf[1]); 304 sizeof(struct hv_netvsc_packet) +
305 (num_data_pgs * sizeof(struct hv_page_buffer)));
285 306
286 /* Set the completion routine */ 307 /* Set the completion routine */
287 packet->completion.send.send_completion = netvsc_xmit_completion; 308 packet->completion.send.send_completion = netvsc_xmit_completion;
288 packet->completion.send.send_completion_ctx = packet; 309 packet->completion.send.send_completion_ctx = packet;
289 packet->completion.send.send_completion_tid = (unsigned long)skb; 310 packet->completion.send.send_completion_tid = (unsigned long)skb;
290 311
291 ret = rndis_filter_send(net_device_ctx->device_ctx, 312 isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
292 packet); 313
314 /* Add the rndis header */
315 rndis_msg = packet->rndis_msg;
316 rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
317 rndis_msg->msg_len = packet->total_data_buflen;
318 rndis_pkt = &rndis_msg->msg.pkt;
319 rndis_pkt->data_offset = sizeof(struct rndis_packet);
320 rndis_pkt->data_len = packet->total_data_buflen;
321 rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
322
323 rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
324
325 if (isvlan) {
326 struct ndis_pkt_8021q_info *vlan;
327
328 rndis_msg_size += NDIS_VLAN_PPI_SIZE;
329 ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE,
330 IEEE_8021Q_INFO);
331 vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
332 ppi->ppi_offset);
333 vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
334 vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
335 VLAN_PRIO_SHIFT;
336 }
337
338 /* Start filling in the page buffers with the rndis hdr */
339 rndis_msg->msg_len += rndis_msg_size;
340 packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
341 skb, &packet->page_buf[0]);
342
343 ret = netvsc_send(net_device_ctx->device_ctx, packet);
344
293 if (ret == 0) { 345 if (ret == 0) {
294 net->stats.tx_bytes += skb->len; 346 net->stats.tx_bytes += skb->len;
295 net->stats.tx_packets++; 347 net->stats.tx_packets++;
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index f0cc8ef21e1c..eaa149950af7 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -891,69 +891,3 @@ int rndis_filter_close(struct hv_device *dev)
891 891
892 return rndis_filter_close_device(nvdev->extension); 892 return rndis_filter_close_device(nvdev->extension);
893} 893}
894
895int rndis_filter_send(struct hv_device *dev,
896 struct hv_netvsc_packet *pkt)
897{
898 struct rndis_message *rndis_msg;
899 struct rndis_packet *rndis_pkt;
900 u32 rndis_msg_size;
901 bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
902
903 /* Add the rndis header */
904 rndis_msg = (struct rndis_message *)pkt->extension;
905
906 rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
907 if (isvlan)
908 rndis_msg_size += NDIS_VLAN_PPI_SIZE;
909
910 rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
911 rndis_msg->msg_len = pkt->total_data_buflen +
912 rndis_msg_size;
913
914 rndis_pkt = &rndis_msg->msg.pkt;
915 rndis_pkt->data_offset = sizeof(struct rndis_packet);
916 if (isvlan)
917 rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
918 rndis_pkt->data_len = pkt->total_data_buflen;
919
920 if (isvlan) {
921 struct rndis_per_packet_info *ppi;
922 struct ndis_pkt_8021q_info *vlan;
923
924 rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
925 rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
926
927 ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
928 rndis_pkt->per_pkt_info_offset);
929 ppi->size = NDIS_VLAN_PPI_SIZE;
930 ppi->type = IEEE_8021Q_INFO;
931 ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
932
933 vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
934 ppi->ppi_offset);
935 vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
936 vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
937 }
938
939 pkt->is_data_pkt = true;
940 pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
941 pkt->page_buf[0].offset =
942 (unsigned long)rndis_msg & (PAGE_SIZE-1);
943 pkt->page_buf[0].len = rndis_msg_size;
944
945 /* Add one page_buf if the rndis msg goes beyond page boundary */
946 if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) {
947 int i;
948 for (i = pkt->page_buf_cnt; i > 1; i--)
949 pkt->page_buf[i] = pkt->page_buf[i-1];
950 pkt->page_buf_cnt++;
951 pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
952 pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
953 rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT;
954 pkt->page_buf[1].offset = 0;
955 pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len;
956 }
957
958 return netvsc_send(dev, pkt);
959}