diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2010-04-08 00:01:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-08 00:01:41 -0400 |
commit | 5e01d2f91df62be4d6f282149bc2a8858992ceca (patch) | |
tree | 8124dc2ba305c27bc59c9bba3cb0810b77c14761 /drivers/net/virtio_net.c | |
parent | b681ee77f8ad248b0fdcec2e5e8c4df6e757eba3 (diff) |
virtio-net: move sg off stack
Move sg structure off stack and into virtnet_info structure.
This helps remove extra sg_init_table calls as well as reduce
stack usage.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Tested-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 52 |
1 files changed, 25 insertions, 27 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index ecec9a8527f3..b81e452d4ba2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -39,8 +39,7 @@ module_param(gso, bool, 0444); | |||
39 | 39 | ||
40 | #define VIRTNET_SEND_COMMAND_SG_MAX 2 | 40 | #define VIRTNET_SEND_COMMAND_SG_MAX 2 |
41 | 41 | ||
42 | struct virtnet_info | 42 | struct virtnet_info { |
43 | { | ||
44 | struct virtio_device *vdev; | 43 | struct virtio_device *vdev; |
45 | struct virtqueue *rvq, *svq, *cvq; | 44 | struct virtqueue *rvq, *svq, *cvq; |
46 | struct net_device *dev; | 45 | struct net_device *dev; |
@@ -61,6 +60,10 @@ struct virtnet_info | |||
61 | 60 | ||
62 | /* Chain pages by the private ptr. */ | 61 | /* Chain pages by the private ptr. */ |
63 | struct page *pages; | 62 | struct page *pages; |
63 | |||
64 | /* fragments + linear part + virtio header */ | ||
65 | struct scatterlist rx_sg[MAX_SKB_FRAGS + 2]; | ||
66 | struct scatterlist tx_sg[MAX_SKB_FRAGS + 2]; | ||
64 | }; | 67 | }; |
65 | 68 | ||
66 | struct skb_vnet_hdr { | 69 | struct skb_vnet_hdr { |
@@ -323,10 +326,8 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) | |||
323 | { | 326 | { |
324 | struct sk_buff *skb; | 327 | struct sk_buff *skb; |
325 | struct skb_vnet_hdr *hdr; | 328 | struct skb_vnet_hdr *hdr; |
326 | struct scatterlist sg[2]; | ||
327 | int err; | 329 | int err; |
328 | 330 | ||
329 | sg_init_table(sg, 2); | ||
330 | skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN); | 331 | skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN); |
331 | if (unlikely(!skb)) | 332 | if (unlikely(!skb)) |
332 | return -ENOMEM; | 333 | return -ENOMEM; |
@@ -334,11 +335,11 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) | |||
334 | skb_put(skb, MAX_PACKET_LEN); | 335 | skb_put(skb, MAX_PACKET_LEN); |
335 | 336 | ||
336 | hdr = skb_vnet_hdr(skb); | 337 | hdr = skb_vnet_hdr(skb); |
337 | sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr); | 338 | sg_set_buf(vi->rx_sg, &hdr->hdr, sizeof hdr->hdr); |
338 | 339 | ||
339 | skb_to_sgvec(skb, sg + 1, 0, skb->len); | 340 | skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len); |
340 | 341 | ||
341 | err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 2, skb); | 342 | err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 2, skb); |
342 | if (err < 0) | 343 | if (err < 0) |
343 | dev_kfree_skb(skb); | 344 | dev_kfree_skb(skb); |
344 | 345 | ||
@@ -347,13 +348,11 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) | |||
347 | 348 | ||
348 | static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) | 349 | static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) |
349 | { | 350 | { |
350 | struct scatterlist sg[MAX_SKB_FRAGS + 2]; | ||
351 | struct page *first, *list = NULL; | 351 | struct page *first, *list = NULL; |
352 | char *p; | 352 | char *p; |
353 | int i, err, offset; | 353 | int i, err, offset; |
354 | 354 | ||
355 | sg_init_table(sg, MAX_SKB_FRAGS + 2); | 355 | /* page in vi->rx_sg[MAX_SKB_FRAGS + 1] is list tail */ |
356 | /* page in sg[MAX_SKB_FRAGS + 1] is list tail */ | ||
357 | for (i = MAX_SKB_FRAGS + 1; i > 1; --i) { | 356 | for (i = MAX_SKB_FRAGS + 1; i > 1; --i) { |
358 | first = get_a_page(vi, gfp); | 357 | first = get_a_page(vi, gfp); |
359 | if (!first) { | 358 | if (!first) { |
@@ -361,7 +360,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) | |||
361 | give_pages(vi, list); | 360 | give_pages(vi, list); |
362 | return -ENOMEM; | 361 | return -ENOMEM; |
363 | } | 362 | } |
364 | sg_set_buf(&sg[i], page_address(first), PAGE_SIZE); | 363 | sg_set_buf(&vi->rx_sg[i], page_address(first), PAGE_SIZE); |
365 | 364 | ||
366 | /* chain new page in list head to match sg */ | 365 | /* chain new page in list head to match sg */ |
367 | first->private = (unsigned long)list; | 366 | first->private = (unsigned long)list; |
@@ -375,17 +374,17 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) | |||
375 | } | 374 | } |
376 | p = page_address(first); | 375 | p = page_address(first); |
377 | 376 | ||
378 | /* sg[0], sg[1] share the same page */ | 377 | /* vi->rx_sg[0], vi->rx_sg[1] share the same page */ |
379 | /* a separated sg[0] for virtio_net_hdr only during to QEMU bug*/ | 378 | /* a separated vi->rx_sg[0] for virtio_net_hdr only due to QEMU bug */ |
380 | sg_set_buf(&sg[0], p, sizeof(struct virtio_net_hdr)); | 379 | sg_set_buf(&vi->rx_sg[0], p, sizeof(struct virtio_net_hdr)); |
381 | 380 | ||
382 | /* sg[1] for data packet, from offset */ | 381 | /* vi->rx_sg[1] for data packet, from offset */ |
383 | offset = sizeof(struct padded_vnet_hdr); | 382 | offset = sizeof(struct padded_vnet_hdr); |
384 | sg_set_buf(&sg[1], p + offset, PAGE_SIZE - offset); | 383 | sg_set_buf(&vi->rx_sg[1], p + offset, PAGE_SIZE - offset); |
385 | 384 | ||
386 | /* chain first in list head */ | 385 | /* chain first in list head */ |
387 | first->private = (unsigned long)list; | 386 | first->private = (unsigned long)list; |
388 | err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2, | 387 | err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, |
389 | first); | 388 | first); |
390 | if (err < 0) | 389 | if (err < 0) |
391 | give_pages(vi, first); | 390 | give_pages(vi, first); |
@@ -396,16 +395,15 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) | |||
396 | static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) | 395 | static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) |
397 | { | 396 | { |
398 | struct page *page; | 397 | struct page *page; |
399 | struct scatterlist sg; | ||
400 | int err; | 398 | int err; |
401 | 399 | ||
402 | page = get_a_page(vi, gfp); | 400 | page = get_a_page(vi, gfp); |
403 | if (!page) | 401 | if (!page) |
404 | return -ENOMEM; | 402 | return -ENOMEM; |
405 | 403 | ||
406 | sg_init_one(&sg, page_address(page), PAGE_SIZE); | 404 | sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE); |
407 | 405 | ||
408 | err = vi->rvq->vq_ops->add_buf(vi->rvq, &sg, 0, 1, page); | 406 | err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 1, page); |
409 | if (err < 0) | 407 | if (err < 0) |
410 | give_pages(vi, page); | 408 | give_pages(vi, page); |
411 | 409 | ||
@@ -514,12 +512,9 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi) | |||
514 | 512 | ||
515 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | 513 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) |
516 | { | 514 | { |
517 | struct scatterlist sg[2+MAX_SKB_FRAGS]; | ||
518 | struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); | 515 | struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); |
519 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; | 516 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; |
520 | 517 | ||
521 | sg_init_table(sg, 2+MAX_SKB_FRAGS); | ||
522 | |||
523 | pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); | 518 | pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); |
524 | 519 | ||
525 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 520 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
@@ -553,12 +548,13 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | |||
553 | 548 | ||
554 | /* Encode metadata header at front. */ | 549 | /* Encode metadata header at front. */ |
555 | if (vi->mergeable_rx_bufs) | 550 | if (vi->mergeable_rx_bufs) |
556 | sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr); | 551 | sg_set_buf(vi->tx_sg, &hdr->mhdr, sizeof hdr->mhdr); |
557 | else | 552 | else |
558 | sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr); | 553 | sg_set_buf(vi->tx_sg, &hdr->hdr, sizeof hdr->hdr); |
559 | 554 | ||
560 | hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; | 555 | hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1; |
561 | return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb); | 556 | return vi->svq->vq_ops->add_buf(vi->svq, vi->tx_sg, hdr->num_sg, |
557 | 0, skb); | ||
562 | } | 558 | } |
563 | 559 | ||
564 | static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) | 560 | static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) |
@@ -940,6 +936,8 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
940 | vdev->priv = vi; | 936 | vdev->priv = vi; |
941 | vi->pages = NULL; | 937 | vi->pages = NULL; |
942 | INIT_DELAYED_WORK(&vi->refill, refill_work); | 938 | INIT_DELAYED_WORK(&vi->refill, refill_work); |
939 | sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg)); | ||
940 | sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg)); | ||
943 | 941 | ||
944 | /* If we can receive ANY GSO packets, we must allocate large ones. */ | 942 | /* If we can receive ANY GSO packets, we must allocate large ones. */ |
945 | if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || | 943 | if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || |