* Re: [PATCH] drivers/net/can/sja1000/plx_pci.c: eliminate double free
From: David Miller @ 2011-08-14 1:01 UTC (permalink / raw)
To: julia; +Cc: wg, kernel-janitors, joe, netdev, linux-kernel
In-Reply-To: <1312820931-28230-1-git-send-email-julia@diku.dk>
From: Julia Lawall <julia@diku.dk>
Date: Mon, 8 Aug 2011 18:28:50 +0200
> From: Julia Lawall <julia@diku.dk>
>
> In this code, the failure_cleanup label calls the function
> plx_pci_del_card, which frees everything in the card->net_dev array. dev
> is placed in this array immediately after allocation, so the two subsequent
> jumps to failure_cleanup should not also call free_sja1000dev, but the
> second one does.
>
> If plx_pci_check_sja1000 fails, then free_sja1000dev is also called on
> dev. Because dev is already in the card->net_dev array, this implies that
> when plx_pci_del_card is later called, it may get freed again. So that
> entry is reset to NULL after the free.
>
> Finally, if there is a problem with one channel, there will be a hole in the
> array. card->channels counts the number of channels that have succeeded,
> and does not keep track of the index of the largest element in the array
> that is valid. So the loop in plx_pci_del_card is changed to go up to
> PLX_PCI_MAX_CHAN, which is only 2.
>
> Signed-off-by: Julia Lawall <julia@diku.dk>
Applied.
^ permalink raw reply
* Re: [PATCH RESEND] gianfar: reduce stack usage in gianfar_ethtool.c
From: David Miller @ 2011-08-14 1:01 UTC (permalink / raw)
To: stufever; +Cc: linux-kernel, netdev, sebastian.poehn, wangshaoyan.pt
In-Reply-To: <1313118445-25594-1-git-send-email-wangshaoyan.pt@taobao.com>
From: stufever@gmail.com
Date: Fri, 12 Aug 2011 11:07:25 +0800
> From: Wang Shaoyan <wangshaoyan.pt@taobao.com>
>
> drivers/net/gianfar_ethtool.c:765: warning: the frame size of 2048 bytes is larger than 1024 bytes
>
> Signed-off-by: Wang Shaoyan <wangshaoyan.pt@taobao.com>
> Reviewed-and-tested-by: Sebastian Pöhn <sebastian.poehn@belden.com>
Applied.
^ permalink raw reply
* Re: BUG: Bisected Gianfar in bridge not forwarding packets
From: David Miller @ 2011-08-14 1:02 UTC (permalink / raw)
To: jpirko; +Cc: mguntsche, shemminger, sebastian.belden, netdev, linux-kernel
In-Reply-To: <20110810111947.GC1909@minipsycho.brq.redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Wed, 10 Aug 2011 13:19:48 +0200
> Subject: [patch net-2.6] gianfar: prevent buggy hw rx vlan tagging
>
> On some buggy chips, "vlan tag present" flag is set which causes packet
> loss. Fix this by checking if rx vlan accel is enabled in features.
>
> Reported-by: Michael Guntsche <mguntsche@gmail.com>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH] net: sh_eth: Fix build by forgot including linux/interrupt.h
From: David Miller @ 2011-08-14 1:02 UTC (permalink / raw)
To: nobuhiro.iwamatsu.yj; +Cc: netdev, adobriyan
In-Reply-To: <1312956950-32598-1-git-send-email-nobuhiro.iwamatsu.yj@renesas.com>
From: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Date: Wed, 10 Aug 2011 15:15:50 +0900
> By a6b7a407865aab9f849dd99a71072b7cd1175116, remove interrupt.h
> from netdevice.h. But this forget to revise sh_eth.
>
> This fix the build failure.
>
> error: expected '=', ',', ';', 'asm' or '__attribute__' before 'sh_eth_interrupt'
> error: implicit declaration of function 'request_irq'
> error: 'sh_eth_interrupt' undeclared (first use in this function)
> error: (Each undeclared identifier is reported only once
> drivers/net/sh_eth.c:1386: error: for each function it appears in.)
> error: 'IRQF_SHARED' undeclared (first use in this function)
> error: implicit declaration of function 'free_irq'
>
> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
> CC: Alexey Dobriyan <adobriyan@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH 00/02] small changes to Documentation/networking/00-INDEX and scaling.txt
From: David Miller @ 2011-08-14 1:03 UTC (permalink / raw)
To: willemb; +Cc: rick.jones2, rdunlap, linux-doc, netdev, therbert
In-Reply-To: <4E44752D.1080905@google.com>
Both applied, thanks.
^ permalink raw reply
* Re: [net-next 10/12] tile: Move the Tilera driver
From: Chris Metcalf @ 2011-08-13 12:15 UTC (permalink / raw)
To: Jeff Kirsher; +Cc: davem, netdev, gospo, sassmann
In-Reply-To: <1313222196-10074-11-git-send-email-jeffrey.t.kirsher@intel.com>
On 8/13/2011 3:56 AM, Jeff Kirsher wrote:
> Move the Tilera driver into drivers/net/ethernet/tile and
> make the necessary Kconfig and Makefile changes.
>
> Updated the Kconfig so that the options defualt to y if TILE kernel.
>
> CC: Chris Metcalf <cmetcalf@tilera.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: Chris Metcalf <cmetcalf@tilera.com>
But note commit typo, "defualt" not "default" :-)
--
Chris Metcalf, Tilera Corp.
http://www.tilera.com
^ permalink raw reply
* Re: [PATCH] virtio-net: Read MAC only after initializing MSI-X
From: Rusty Russell @ 2011-08-14 2:53 UTC (permalink / raw)
To: Sasha Levin, linux-kernel
Cc: Sasha Levin, Michael S. Tsirkin, virtualization, netdev, kvm
In-Reply-To: <1313225461-24458-1-git-send-email-levinsasha928@gmail.com>
On Sat, 13 Aug 2011 11:51:01 +0300, Sasha Levin <levinsasha928@gmail.com> wrote:
> The MAC of a virtio-net device is located at the first field of the device
> specific header. This header is located at offset 20 if the device doesn't
> support MSI-X or offset 24 if it does.
Erk. This means, in general, we have to do virtio_find_single_vq or
config->find_vqs before we examine any config options.
Look at virtio_blk, which has the same error.
Solutions in order of best to worst:
(1) Enable MSI-X before calling device probe. This means reserving two
vectors in virtio_pci_probe to ensure we *can* do this, I think. Michael?
(2) Ensure ordering of "find_vqs then access config space" statically. This
probably means handing the vqs array to virtio_config_val, so noone
can call it before they have their virtqueues.
(3) Ensure ordering dynamically, ie. BUG_ON() if they haven't done
find_vqs when they call the config accessors.
If (1) is too invasive for -stable, then we should rearrange the drivers
in separate patches (and cc: -stable), then fix it properly.
Good catch Sasha!
Cheers,
Rusty.
^ permalink raw reply
* Re: [PATCH] Proportional Rate Reduction for TCP.
From: Andi Kleen @ 2011-08-14 5:05 UTC (permalink / raw)
To: Nandita Dukkipati
Cc: David S. Miller, netdev, Tom Herbert, Yuchung Cheng, Matt Mathis
In-Reply-To: <1313134197-5082-1-git-send-email-nanditad@google.com>
Nandita Dukkipati <nanditad@google.com> writes:
> +
> + if (tcp_packets_in_flight(tp) > tp->snd_ssthresh) {
> + if (WARN_ON(!tp->prr_cwnd))
> + tp->prr_cwnd = 1;
> + sndcnt = DIV_ROUND_UP(tp->prr_delivered * tp->snd_ssthresh,
> + tp->prr_cwnd) - tp->prr_out;
> + } else {
> + sndcnt = min_t(int, delta,
> + max_t(int, tp->prr_delivered -
> tp->prr_out,
u32s here? This will likely do bad things with large enough windows.
The rest looks good to me as code, but I don't claim to fully understand the
algorithm. Perhaps a sysctl to turn it off and a linux mib counter when
it triggers would be useful in addition.
-Andi
--
ak@linux.intel.com -- Speaking for myself only
^ permalink raw reply
* Re: [net-next RFC PATCH 7/7] virtio-net changes
From: Jason Wang @ 2011-08-14 5:59 UTC (permalink / raw)
To: Sasha Levin
Cc: krkumar2, kvm, mst, qemu-devel, netdev, rusty, linux-kernel,
virtualization, mirq-linux, davem
In-Reply-To: <1313140156.3651.1.camel@lappy>
----- Original Message -----
> On Fri, 2011-08-12 at 09:55 +0800, Jason Wang wrote:
> > From: Krishna Kumar <krkumar2@in.ibm.com>
> >
> > Implement mq virtio-net driver.
> >
> > Though struct virtio_net_config changes, it works with the old
> > qemu since the last element is not accessed unless qemu sets
> > VIRTIO_NET_F_MULTIQUEUE.
> >
> > Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
>
> Could these changes be documented to virtio-spec as well?
Yes, definitely.
>
> > drivers/net/virtio_net.c | 578
> > +++++++++++++++++++++++++++++++-------------
> > include/linux/virtio_net.h | 3
> > 2 files changed, 411 insertions(+), 170 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index 0c7321c..03a199d 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -49,16 +49,48 @@ struct virtnet_stats {
> > u64 rx_packets;
> > };
> >
> > -struct virtnet_info {
> > - struct virtio_device *vdev;
> > - struct virtqueue *rvq, *svq, *cvq;
> > - struct net_device *dev;
> > +/* Internal representation of a send virtqueue */
> > +struct send_queue {
> > + /* Virtqueue associated with this send _queue */
> > + struct virtqueue *svq;
> > +
> > + /* TX: fragments + linear part + virtio header */
> > + struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
> > +};
> > +
> > +/* Internal representation of a receive virtqueue */
> > +struct receive_queue {
> > + /* Virtqueue associated with this receive_queue */
> > + struct virtqueue *rvq;
> > +
> > + /* Back pointer to the virtnet_info */
> > + struct virtnet_info *vi;
> > +
> > struct napi_struct napi;
> > - unsigned int status;
> >
> > /* Number of input buffers, and max we've ever had. */
> > unsigned int num, max;
> >
> > + /* Work struct for refilling if we run low on memory. */
> > + struct delayed_work refill;
> > +
> > + /* Chain pages by the private ptr. */
> > + struct page *pages;
> > +
> > + /* RX: fragments + linear part + virtio header */
> > + struct scatterlist rx_sg[MAX_SKB_FRAGS + 2];
> > +};
> > +
> > +struct virtnet_info {
> > + struct send_queue **sq;
> > + struct receive_queue **rq;
> > +
> > + int numtxqs; /* # of rxqs/txqs */
> > + struct virtio_device *vdev;
> > + struct virtqueue *cvq;
> > + struct net_device *dev;
> > + unsigned int status;
> > +
> > /* I like... big packets and I cannot lie! */
> > bool big_packets;
> >
> > @@ -67,16 +99,6 @@ struct virtnet_info {
> >
> > /* Active statistics */
> > struct virtnet_stats __percpu *stats;
> > -
> > - /* Work struct for refilling if we run low on memory. */
> > - struct delayed_work refill;
> > -
> > - /* Chain pages by the private ptr. */
> > - struct page *pages;
> > -
> > - /* fragments + linear part + virtio header */
> > - struct scatterlist rx_sg[MAX_SKB_FRAGS + 2];
> > - struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
> > };
> >
> > struct skb_vnet_hdr {
> > @@ -106,22 +128,22 @@ static inline struct skb_vnet_hdr
> > *skb_vnet_hdr(struct sk_buff *skb)
> > * private is used to chain pages for big packets, put the whole
> > * most recent used list in the beginning for reuse
> > */
> > -static void give_pages(struct virtnet_info *vi, struct page *page)
> > +static void give_pages(struct receive_queue *rq, struct page *page)
> > {
> > struct page *end;
> >
> > /* Find end of list, sew whole thing into vi->pages. */
> > for (end = page; end->private; end = (struct page *)end->private);
> > - end->private = (unsigned long)vi->pages;
> > - vi->pages = page;
> > + end->private = (unsigned long)rq->pages;
> > + rq->pages = page;
> > }
> >
> > -static struct page *get_a_page(struct virtnet_info *vi, gfp_t
> > gfp_mask)
> > +static struct page *get_a_page(struct receive_queue *rq, gfp_t
> > gfp_mask)
> > {
> > - struct page *p = vi->pages;
> > + struct page *p = rq->pages;
> >
> > if (p) {
> > - vi->pages = (struct page *)p->private;
> > + rq->pages = (struct page *)p->private;
> > /* clear private here, it is used to chain pages */
> > p->private = 0;
> > } else
> > @@ -132,12 +154,13 @@ static struct page *get_a_page(struct
> > virtnet_info *vi, gfp_t gfp_mask)
> > static void skb_xmit_done(struct virtqueue *svq)
> > {
> > struct virtnet_info *vi = svq->vdev->priv;
> > + int qnum = svq->queue_index / 2; /* RX/TX vqs are allocated in
> > pairs */
> >
> > /* Suppress further interrupts. */
> > virtqueue_disable_cb(svq);
> >
> > /* We were probably waiting for more output buffers. */
> > - netif_wake_queue(vi->dev);
> > + netif_wake_subqueue(vi->dev, qnum);
> > }
> >
> > static void set_skb_frag(struct sk_buff *skb, struct page *page,
> > @@ -157,9 +180,10 @@ static void set_skb_frag(struct sk_buff *skb,
> > struct page *page,
> > *len -= f->size;
> > }
> >
> > -static struct sk_buff *page_to_skb(struct virtnet_info *vi,
> > +static struct sk_buff *page_to_skb(struct receive_queue *rq,
> > struct page *page, unsigned int len)
> > {
> > + struct virtnet_info *vi = rq->vi;
> > struct sk_buff *skb;
> > struct skb_vnet_hdr *hdr;
> > unsigned int copy, hdr_len, offset;
> > @@ -202,12 +226,12 @@ static struct sk_buff *page_to_skb(struct
> > virtnet_info *vi,
> > }
> >
> > if (page)
> > - give_pages(vi, page);
> > + give_pages(rq, page);
> >
> > return skb;
> > }
> >
> > -static int receive_mergeable(struct virtnet_info *vi, struct
> > sk_buff *skb)
> > +static int receive_mergeable(struct receive_queue *rq, struct
> > sk_buff *skb)
> > {
> > struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
> > struct page *page;
> > @@ -221,7 +245,8 @@ static int receive_mergeable(struct virtnet_info
> > *vi, struct sk_buff *skb)
> > skb->dev->stats.rx_length_errors++;
> > return -EINVAL;
> > }
> > - page = virtqueue_get_buf(vi->rvq, &len);
> > +
> > + page = virtqueue_get_buf(rq->rvq, &len);
> > if (!page) {
> > pr_debug("%s: rx error: %d buffers missing\n",
> > skb->dev->name, hdr->mhdr.num_buffers);
> > @@ -234,13 +259,14 @@ static int receive_mergeable(struct
> > virtnet_info *vi, struct sk_buff *skb)
> >
> > set_skb_frag(skb, page, 0, &len);
> >
> > - --vi->num;
> > + --rq->num;
> > }
> > return 0;
> > }
> >
> > -static void receive_buf(struct net_device *dev, void *buf, unsigned
> > int len)
> > +static void receive_buf(struct receive_queue *rq, void *buf,
> > unsigned int len)
> > {
> > + struct net_device *dev = rq->vi->dev;
> > struct virtnet_info *vi = netdev_priv(dev);
> > struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
> > struct sk_buff *skb;
> > @@ -251,7 +277,7 @@ static void receive_buf(struct net_device *dev,
> > void *buf, unsigned int len)
> > pr_debug("%s: short packet %i\n", dev->name, len);
> > dev->stats.rx_length_errors++;
> > if (vi->mergeable_rx_bufs || vi->big_packets)
> > - give_pages(vi, buf);
> > + give_pages(rq, buf);
> > else
> > dev_kfree_skb(buf);
> > return;
> > @@ -263,14 +289,14 @@ static void receive_buf(struct net_device
> > *dev, void *buf, unsigned int len)
> > skb_trim(skb, len);
> > } else {
> > page = buf;
> > - skb = page_to_skb(vi, page, len);
> > + skb = page_to_skb(rq, page, len);
> > if (unlikely(!skb)) {
> > dev->stats.rx_dropped++;
> > - give_pages(vi, page);
> > + give_pages(rq, page);
> > return;
> > }
> > if (vi->mergeable_rx_bufs)
> > - if (receive_mergeable(vi, skb)) {
> > + if (receive_mergeable(rq, skb)) {
> > dev_kfree_skb(skb);
> > return;
> > }
> > @@ -341,184 +367,200 @@ frame_err:
> > dev_kfree_skb(skb);
> > }
> >
> > -static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
> > +static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp)
> > {
> > struct sk_buff *skb;
> > struct skb_vnet_hdr *hdr;
> > int err;
> >
> > - skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
> > + skb = netdev_alloc_skb_ip_align(rq->vi->dev, MAX_PACKET_LEN);
> > if (unlikely(!skb))
> > return -ENOMEM;
> >
> > skb_put(skb, MAX_PACKET_LEN);
> >
> > hdr = skb_vnet_hdr(skb);
> > - sg_set_buf(vi->rx_sg, &hdr->hdr, sizeof hdr->hdr);
> > + sg_set_buf(rq->rx_sg, &hdr->hdr, sizeof hdr->hdr);
> >
> > - skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
> > + skb_to_sgvec(skb, rq->rx_sg + 1, 0, skb->len);
> >
> > - err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
> > + err = virtqueue_add_buf_gfp(rq->rvq, rq->rx_sg, 0, 2, skb, gfp);
> > if (err < 0)
> > dev_kfree_skb(skb);
> >
> > return err;
> > }
> >
> > -static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
> > +static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp)
> > {
> > struct page *first, *list = NULL;
> > char *p;
> > int i, err, offset;
> >
> > - /* page in vi->rx_sg[MAX_SKB_FRAGS + 1] is list tail */
> > + /* page in rq->rx_sg[MAX_SKB_FRAGS + 1] is list tail */
> > for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
> > - first = get_a_page(vi, gfp);
> > + first = get_a_page(rq, gfp);
> > if (!first) {
> > if (list)
> > - give_pages(vi, list);
> > + give_pages(rq, list);
> > return -ENOMEM;
> > }
> > - sg_set_buf(&vi->rx_sg[i], page_address(first), PAGE_SIZE);
> > + sg_set_buf(&rq->rx_sg[i], page_address(first), PAGE_SIZE);
> >
> > /* chain new page in list head to match sg */
> > first->private = (unsigned long)list;
> > list = first;
> > }
> >
> > - first = get_a_page(vi, gfp);
> > + first = get_a_page(rq, gfp);
> > if (!first) {
> > - give_pages(vi, list);
> > + give_pages(rq, list);
> > return -ENOMEM;
> > }
> > p = page_address(first);
> >
> > - /* vi->rx_sg[0], vi->rx_sg[1] share the same page */
> > - /* a separated vi->rx_sg[0] for virtio_net_hdr only due to QEMU
> > bug */
> > - sg_set_buf(&vi->rx_sg[0], p, sizeof(struct virtio_net_hdr));
> > + /* rq->rx_sg[0], rq->rx_sg[1] share the same page */
> > + /* a separated rq->rx_sg[0] for virtio_net_hdr only due to QEMU
> > bug */
> > + sg_set_buf(&rq->rx_sg[0], p, sizeof(struct virtio_net_hdr));
> >
> > - /* vi->rx_sg[1] for data packet, from offset */
> > + /* rq->rx_sg[1] for data packet, from offset */
> > offset = sizeof(struct padded_vnet_hdr);
> > - sg_set_buf(&vi->rx_sg[1], p + offset, PAGE_SIZE - offset);
> > + sg_set_buf(&rq->rx_sg[1], p + offset, PAGE_SIZE - offset);
> >
> > /* chain first in list head */
> > first->private = (unsigned long)list;
> > - err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS +
> > 2,
> > + err = virtqueue_add_buf_gfp(rq->rvq, rq->rx_sg, 0, MAX_SKB_FRAGS +
> > 2,
> > first, gfp);
> > if (err < 0)
> > - give_pages(vi, first);
> > + give_pages(rq, first);
> >
> > return err;
> > }
> >
> > -static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t
> > gfp)
> > +static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t
> > gfp)
> > {
> > struct page *page;
> > int err;
> >
> > - page = get_a_page(vi, gfp);
> > + page = get_a_page(rq, gfp);
> > if (!page)
> > return -ENOMEM;
> >
> > - sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
> > + sg_init_one(rq->rx_sg, page_address(page), PAGE_SIZE);
> >
> > - err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
> > + err = virtqueue_add_buf_gfp(rq->rvq, rq->rx_sg, 0, 1, page, gfp);
> > if (err < 0)
> > - give_pages(vi, page);
> > + give_pages(rq, page);
> >
> > return err;
> > }
> >
> > /* Returns false if we couldn't fill entirely (OOM). */
> > -static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
> > +static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
> > {
> > + struct virtnet_info *vi = rq->vi;
> > int err;
> > bool oom;
> >
> > do {
> > if (vi->mergeable_rx_bufs)
> > - err = add_recvbuf_mergeable(vi, gfp);
> > + err = add_recvbuf_mergeable(rq, gfp);
> > else if (vi->big_packets)
> > - err = add_recvbuf_big(vi, gfp);
> > + err = add_recvbuf_big(rq, gfp);
> > else
> > - err = add_recvbuf_small(vi, gfp);
> > + err = add_recvbuf_small(rq, gfp);
> >
> > oom = err == -ENOMEM;
> > if (err < 0)
> > break;
> > - ++vi->num;
> > + ++rq->num;
> > } while (err > 0);
> > - if (unlikely(vi->num > vi->max))
> > - vi->max = vi->num;
> > - virtqueue_kick(vi->rvq);
> > + if (unlikely(rq->num > rq->max))
> > + rq->max = rq->num;
> > + virtqueue_kick(rq->rvq);
> > return !oom;
> > }
> >
> > static void skb_recv_done(struct virtqueue *rvq)
> > {
> > + int qnum = rvq->queue_index / 2; /* RX/TX vqs are allocated in
> > pairs */
> > struct virtnet_info *vi = rvq->vdev->priv;
> > + struct napi_struct *napi = &vi->rq[qnum]->napi;
> > +
> > /* Schedule NAPI, Suppress further interrupts if successful. */
> > - if (napi_schedule_prep(&vi->napi)) {
> > + if (napi_schedule_prep(napi)) {
> > virtqueue_disable_cb(rvq);
> > - __napi_schedule(&vi->napi);
> > + __napi_schedule(napi);
> > }
> > }
> >
> > -static void virtnet_napi_enable(struct virtnet_info *vi)
> > +static void virtnet_napi_enable(struct receive_queue *rq)
> > {
> > - napi_enable(&vi->napi);
> > + napi_enable(&rq->napi);
> >
> > /* If all buffers were filled by other side before we
> > napi_enabled, we
> > * won't get another interrupt, so process any outstanding packets
> > * now. virtnet_poll wants re-enable the queue, so we disable
> > here.
> > * We synchronize against interrupts via NAPI_STATE_SCHED */
> > - if (napi_schedule_prep(&vi->napi)) {
> > - virtqueue_disable_cb(vi->rvq);
> > - __napi_schedule(&vi->napi);
> > + if (napi_schedule_prep(&rq->napi)) {
> > + virtqueue_disable_cb(rq->rvq);
> > + __napi_schedule(&rq->napi);
> > }
> > }
> >
> > +static void virtnet_napi_enable_all_queues(struct virtnet_info *vi)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < vi->numtxqs; i++)
> > + virtnet_napi_enable(vi->rq[i]);
> > +}
> > +
> > static void refill_work(struct work_struct *work)
> > {
> > - struct virtnet_info *vi;
> > + struct napi_struct *napi;
> > + struct receive_queue *rq;
> > bool still_empty;
> >
> > - vi = container_of(work, struct virtnet_info, refill.work);
> > - napi_disable(&vi->napi);
> > - still_empty = !try_fill_recv(vi, GFP_KERNEL);
> > - virtnet_napi_enable(vi);
> > + rq = container_of(work, struct receive_queue, refill.work);
> > + napi = &rq->napi;
> > +
> > + napi_disable(napi);
> > + still_empty = !try_fill_recv(rq, GFP_KERNEL);
> > + virtnet_napi_enable(rq);
> >
> > /* In theory, this can happen: if we don't get any buffers in
> > * we will *never* try to fill again. */
> > if (still_empty)
> > - schedule_delayed_work(&vi->refill, HZ/2);
> > + schedule_delayed_work(&rq->refill, HZ/2);
> > }
> >
> > static int virtnet_poll(struct napi_struct *napi, int budget)
> > {
> > - struct virtnet_info *vi = container_of(napi, struct virtnet_info,
> > napi);
> > + struct receive_queue *rq = container_of(napi, struct
> > receive_queue,
> > + napi);
> > void *buf;
> > unsigned int len, received = 0;
> >
> > again:
> > while (received < budget &&
> > - (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
> > - receive_buf(vi->dev, buf, len);
> > - --vi->num;
> > + (buf = virtqueue_get_buf(rq->rvq, &len)) != NULL) {
> > + receive_buf(rq, buf, len);
> > + --rq->num;
> > received++;
> > }
> >
> > - if (vi->num < vi->max / 2) {
> > - if (!try_fill_recv(vi, GFP_ATOMIC))
> > - schedule_delayed_work(&vi->refill, 0);
> > + if (rq->num < rq->max / 2) {
> > + if (!try_fill_recv(rq, GFP_ATOMIC))
> > + schedule_delayed_work(&rq->refill, 0);
> > }
> >
> > /* Out of packets? */
> > if (received < budget) {
> > napi_complete(napi);
> > - if (unlikely(!virtqueue_enable_cb(vi->rvq)) &&
> > + if (unlikely(!virtqueue_enable_cb(rq->rvq)) &&
> > napi_schedule_prep(napi)) {
> > - virtqueue_disable_cb(vi->rvq);
> > + virtqueue_disable_cb(rq->rvq);
> > __napi_schedule(napi);
> > goto again;
> > }
> > @@ -527,13 +569,14 @@ again:
> > return received;
> > }
> >
> > -static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
> > +static unsigned int free_old_xmit_skbs(struct virtnet_info *vi,
> > + struct virtqueue *svq)
> > {
> > struct sk_buff *skb;
> > unsigned int len, tot_sgs = 0;
> > struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
> >
> > - while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
> > + while ((skb = virtqueue_get_buf(svq, &len)) != NULL) {
> > pr_debug("Sent skb %p\n", skb);
> >
> > u64_stats_update_begin(&stats->syncp);
> > @@ -547,7 +590,8 @@ static unsigned int free_old_xmit_skbs(struct
> > virtnet_info *vi)
> > return tot_sgs;
> > }
> >
> > -static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
> > +static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb,
> > + struct virtqueue *svq, struct scatterlist *tx_sg)
> > {
> > struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
> > const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
> > @@ -585,12 +629,12 @@ static int xmit_skb(struct virtnet_info *vi,
> > struct sk_buff *skb)
> >
> > /* Encode metadata header at front. */
> > if (vi->mergeable_rx_bufs)
> > - sg_set_buf(vi->tx_sg, &hdr->mhdr, sizeof hdr->mhdr);
> > + sg_set_buf(tx_sg, &hdr->mhdr, sizeof hdr->mhdr);
> > else
> > - sg_set_buf(vi->tx_sg, &hdr->hdr, sizeof hdr->hdr);
> > + sg_set_buf(tx_sg, &hdr->hdr, sizeof hdr->hdr);
> >
> > - hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
> > - return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
> > + hdr->num_sg = skb_to_sgvec(skb, tx_sg + 1, 0, skb->len) + 1;
> > + return virtqueue_add_buf(svq, tx_sg, hdr->num_sg,
> > 0, skb);
> > }
> >
> > @@ -598,31 +642,34 @@ static netdev_tx_t start_xmit(struct sk_buff
> > *skb, struct net_device *dev)
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> > int capacity;
> > + int qnum = skb_get_queue_mapping(skb);
> > + struct virtqueue *svq = vi->sq[qnum]->svq;
> >
> > /* Free up any pending old buffers before queueing new ones. */
> > - free_old_xmit_skbs(vi);
> > + free_old_xmit_skbs(vi, svq);
> >
> > /* Try to transmit */
> > - capacity = xmit_skb(vi, skb);
> > + capacity = xmit_skb(vi, skb, svq, vi->sq[qnum]->tx_sg);
> >
> > /* This can happen with OOM and indirect buffers. */
> > if (unlikely(capacity < 0)) {
> > if (net_ratelimit()) {
> > if (likely(capacity == -ENOMEM)) {
> > dev_warn(&dev->dev,
> > - "TX queue failure: out of memory\n");
> > + "TXQ (%d) failure: out of memory\n",
> > + qnum);
> > } else {
> > dev->stats.tx_fifo_errors++;
> > dev_warn(&dev->dev,
> > - "Unexpected TX queue failure: %d\n",
> > - capacity);
> > + "Unexpected TXQ (%d) failure: %d\n",
> > + qnum, capacity);
> > }
> > }
> > dev->stats.tx_dropped++;
> > kfree_skb(skb);
> > return NETDEV_TX_OK;
> > }
> > - virtqueue_kick(vi->svq);
> > + virtqueue_kick(svq);
> >
> > /* Don't wait up for transmitted skbs to be freed. */
> > skb_orphan(skb);
> > @@ -631,13 +678,13 @@ static netdev_tx_t start_xmit(struct sk_buff
> > *skb, struct net_device *dev)
> > /* Apparently nice girls don't return TX_BUSY; stop the queue
> > * before it gets out of hand. Naturally, this wastes entries. */
> > if (capacity < 2+MAX_SKB_FRAGS) {
> > - netif_stop_queue(dev);
> > - if (unlikely(!virtqueue_enable_cb_delayed(vi->svq))) {
> > + netif_stop_subqueue(dev, qnum);
> > + if (unlikely(!virtqueue_enable_cb_delayed(svq))) {
> > /* More just got used, free them then recheck. */
> > - capacity += free_old_xmit_skbs(vi);
> > + capacity += free_old_xmit_skbs(vi, svq);
> > if (capacity >= 2+MAX_SKB_FRAGS) {
> > - netif_start_queue(dev);
> > - virtqueue_disable_cb(vi->svq);
> > + netif_start_subqueue(dev, qnum);
> > + virtqueue_disable_cb(svq);
> > }
> > }
> > }
> > @@ -700,8 +747,10 @@ static struct rtnl_link_stats64
> > *virtnet_stats(struct net_device *dev,
> > static void virtnet_netpoll(struct net_device *dev)
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> > + int i;
> >
> > - napi_schedule(&vi->napi);
> > + for (i = 0; i < vi->numtxqs; i++)
> > + napi_schedule(&vi->rq[i]->napi);
> > }
> > #endif
> >
> > @@ -709,7 +758,7 @@ static int virtnet_open(struct net_device *dev)
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> >
> > - virtnet_napi_enable(vi);
> > + virtnet_napi_enable_all_queues(vi);
> > return 0;
> > }
> >
> > @@ -761,8 +810,10 @@ static bool virtnet_send_command(struct
> > virtnet_info *vi, u8 class, u8 cmd,
> > static int virtnet_close(struct net_device *dev)
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> > + int i;
> >
> > - napi_disable(&vi->napi);
> > + for (i = 0; i < vi->numtxqs; i++)
> > + napi_disable(&vi->rq[i]->napi);
> >
> > return 0;
> > }
> > @@ -919,10 +970,10 @@ static void virtnet_update_status(struct
> > virtnet_info *vi)
> >
> > if (vi->status & VIRTIO_NET_S_LINK_UP) {
> > netif_carrier_on(vi->dev);
> > - netif_wake_queue(vi->dev);
> > + netif_tx_wake_all_queues(vi->dev);
> > } else {
> > netif_carrier_off(vi->dev);
> > - netif_stop_queue(vi->dev);
> > + netif_tx_stop_all_queues(vi->dev);
> > }
> > }
> >
> > @@ -933,18 +984,222 @@ static void virtnet_config_changed(struct
> > virtio_device *vdev)
> > virtnet_update_status(vi);
> > }
> >
> > +static void free_receive_bufs(struct virtnet_info *vi)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < vi->numtxqs; i++) {
> > + BUG_ON(vi->rq[i] == NULL);
> > + while (vi->rq[i]->pages)
> > + __free_pages(get_a_page(vi->rq[i], GFP_KERNEL), 0);
> > + }
> > +}
> > +
> > +/* Free memory allocated for send and receive queues */
> > +static void free_rq_sq(struct virtnet_info *vi)
> > +{
> > + int i;
> > +
> > + if (vi->rq) {
> > + for (i = 0; i < vi->numtxqs; i++)
> > + kfree(vi->rq[i]);
> > + kfree(vi->rq);
> > + }
> > +
> > + if (vi->sq) {
> > + for (i = 0; i < vi->numtxqs; i++)
> > + kfree(vi->sq[i]);
> > + kfree(vi->sq);
> > + }
> > +}
> > +
> > +static void free_unused_bufs(struct virtnet_info *vi)
> > +{
> > + void *buf;
> > + int i;
> > +
> > + for (i = 0; i < vi->numtxqs; i++) {
> > + struct virtqueue *svq = vi->sq[i]->svq;
> > +
> > + while (1) {
> > + buf = virtqueue_detach_unused_buf(svq);
> > + if (!buf)
> > + break;
> > + dev_kfree_skb(buf);
> > + }
> > + }
> > +
> > + for (i = 0; i < vi->numtxqs; i++) {
> > + struct virtqueue *rvq = vi->rq[i]->rvq;
> > +
> > + while (1) {
> > + buf = virtqueue_detach_unused_buf(rvq);
> > + if (!buf)
> > + break;
> > + if (vi->mergeable_rx_bufs || vi->big_packets)
> > + give_pages(vi->rq[i], buf);
> > + else
> > + dev_kfree_skb(buf);
> > + --vi->rq[i]->num;
> > + }
> > + BUG_ON(vi->rq[i]->num != 0);
> > + }
> > +}
> > +
> > +#define MAX_DEVICE_NAME 16
> > +static int initialize_vqs(struct virtnet_info *vi, int numtxqs)
> > +{
> > + vq_callback_t **callbacks;
> > + struct virtqueue **vqs;
> > + int i, err = -ENOMEM;
> > + int totalvqs;
> > + char **names;
> > +
> > + /* Allocate receive queues */
> > + vi->rq = kcalloc(numtxqs, sizeof(*vi->rq), GFP_KERNEL);
> > + if (!vi->rq)
> > + goto out;
> > + for (i = 0; i < numtxqs; i++) {
> > + vi->rq[i] = kzalloc(sizeof(*vi->rq[i]), GFP_KERNEL);
> > + if (!vi->rq[i])
> > + goto out;
> > + }
> > +
> > + /* Allocate send queues */
> > + vi->sq = kcalloc(numtxqs, sizeof(*vi->sq), GFP_KERNEL);
> > + if (!vi->sq)
> > + goto out;
> > + for (i = 0; i < numtxqs; i++) {
> > + vi->sq[i] = kzalloc(sizeof(*vi->sq[i]), GFP_KERNEL);
> > + if (!vi->sq[i])
> > + goto out;
> > + }
> > +
> > + /* setup initial receive and send queue parameters */
> > + for (i = 0; i < numtxqs; i++) {
> > + vi->rq[i]->vi = vi;
> > + vi->rq[i]->pages = NULL;
> > + INIT_DELAYED_WORK(&vi->rq[i]->refill, refill_work);
> > + netif_napi_add(vi->dev, &vi->rq[i]->napi, virtnet_poll,
> > + napi_weight);
> > +
> > + sg_init_table(vi->rq[i]->rx_sg, ARRAY_SIZE(vi->rq[i]->rx_sg));
> > + sg_init_table(vi->sq[i]->tx_sg, ARRAY_SIZE(vi->sq[i]->tx_sg));
> > + }
> > +
> > + /*
> > + * We expect 1 RX virtqueue followed by 1 TX virtqueues, followed
> > + * by the same 'numtxqs-1' times, and optionally one control
> > virtqueue.
> > + */
> > + totalvqs = numtxqs * 2 +
> > + virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ);
> > +
> > + /* Allocate space for find_vqs parameters */
> > + vqs = kmalloc(totalvqs * sizeof(*vqs), GFP_KERNEL);
> > + callbacks = kmalloc(totalvqs * sizeof(*callbacks), GFP_KERNEL);
> > + names = kzalloc(totalvqs * sizeof(*names), GFP_KERNEL);
> > + if (!vqs || !callbacks || !names)
> > + goto free_params;
> > +
> > +#if 1
> > + /* Allocate/initialize parameters for recv/send virtqueues */
> > + for (i = 0; i < numtxqs * 2; i++) {
> > + names[i] = kmalloc(MAX_DEVICE_NAME * sizeof(*names[i]),
> > + GFP_KERNEL);
> > + if (!names[i])
> > + goto free_params;
> > +
> > + if (!(i & 1)) { /* RX */
> > + callbacks[i] = skb_recv_done;
> > + sprintf(names[i], "input.%d", i / 2);
> > + } else {
> > + callbacks[i] = skb_xmit_done;
> > + sprintf(names[i], "output.%d", i / 2);
> > + }
> > + }
> > +
> > + /* Parameters for control virtqueue, if any */
> > + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
> > + callbacks[i] = NULL;
> > + names[i] = "control";
> > + }
> > +#else
> > + /* Allocate/initialize parameters for recv virtqueues */
> > + for (i = 0; i < numtxqs * 2; i += 2) {
> > + callbacks[i] = skb_recv_done;
> > + names[i] = kmalloc(MAX_DEVICE_NAME * sizeof(*names[i]),
> > + GFP_KERNEL);
> > + if (!names[i])
> > + goto free_params;
> > + sprintf(names[i], "input.%d", i / 2);
> > + }
> > +
> > + /* Allocate/initialize parameters for send virtqueues */
> > + for (i = 1; i < numtxqs * 2; i += 2) {
> > + callbacks[i] = skb_xmit_done;
> > + names[i] = kmalloc(MAX_DEVICE_NAME * sizeof(*names[i]),
> > + GFP_KERNEL);
> > + if (!names[i])
> > + goto free_params;
> > + sprintf(names[i], "output.%d", i / 2);
> > + }
> > +
> > + /* Parameters for control virtqueue, if any */
> > + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
> > + callbacks[i - 1] = NULL;
> > + names[i - 1] = "control";
> > + }
> > +#endif
> > +
> > + err = vi->vdev->config->find_vqs(vi->vdev, totalvqs, vqs,
> > callbacks,
> > + (const char **)names);
> > + if (err)
> > + goto free_params;
> > +
> > + /* Assign the allocated vqs alternatively for RX/TX */
> > + for (i = 0; i < numtxqs * 2; i += 2) {
> > + vi->rq[i/2]->rvq = vqs[i];
> > + vi->sq[i/2]->svq = vqs[i + 1];
> > + }
> > +
> > + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
> > + vi->cvq = vqs[i];
> > +
> > +free_params:
> > + if (names) {
> > + for (i = 0; i < numtxqs * 2; i++)
> > + kfree(names[i]);
> > + kfree(names);
> > + }
> > +
> > + kfree(callbacks);
> > + kfree(vqs);
> > +
> > +out:
> > + if (err)
> > + free_rq_sq(vi);
> > +
> > + return err;
> > +}
> > +
> > static int virtnet_probe(struct virtio_device *vdev)
> > {
> > - int err;
> > + int i, err;
> > + u16 numtxqs;
> > + u16 num_queue_pairs = 2;
> > struct net_device *dev;
> > struct virtnet_info *vi;
> > - struct virtqueue *vqs[3];
> > - vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done,
> > NULL};
> > - const char *names[] = { "input", "output", "control" };
> > - int nvqs;
> > +
> > + /* Find if host supports MULTIQUEUE */
> > + err = virtio_config_val(vdev, VIRTIO_NET_F_MULTIQUEUE,
> > + offsetof(struct virtio_net_config,
> > + num_queue_pairs), &num_queue_pairs);
> > + numtxqs = num_queue_pairs / 2;
> > + if (!numtxqs)
> > + numtxqs = 1;
> >
> > /* Allocate ourselves a network device with room for our info */
> > - dev = alloc_etherdev(sizeof(struct virtnet_info));
> > + dev = alloc_etherdev_mq(sizeof(struct virtnet_info), numtxqs);
> > if (!dev)
> > return -ENOMEM;
> >
> > @@ -991,19 +1246,14 @@ static int virtnet_probe(struct virtio_device
> > *vdev)
> >
> > /* Set up our device-specific information */
> > vi = netdev_priv(dev);
> > - netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight);
> > vi->dev = dev;
> > vi->vdev = vdev;
> > vdev->priv = vi;
> > - vi->pages = NULL;
> > vi->stats = alloc_percpu(struct virtnet_stats);
> > err = -ENOMEM;
> > if (vi->stats == NULL)
> > goto free;
> > -
> > - INIT_DELAYED_WORK(&vi->refill, refill_work);
> > - sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
> > - sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
> > + vi->numtxqs = numtxqs;
> >
> > /* If we can receive ANY GSO packets, we must allocate large ones.
> > */
> > if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
> > @@ -1014,23 +1264,14 @@ static int virtnet_probe(struct
> > virtio_device *vdev)
> > if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
> > vi->mergeable_rx_bufs = true;
> >
> > - /* We expect two virtqueues, receive then send,
> > - * and optionally control. */
> > - nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
> > -
> > - err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
> > + /* Initialize our rx/tx queue parameters, and invoke find_vqs */
> > + err = initialize_vqs(vi, numtxqs);
> > if (err)
> > goto free_stats;
> >
> > - vi->rvq = vqs[0];
> > - vi->svq = vqs[1];
> > -
> > - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
> > - vi->cvq = vqs[2];
> > -
> > - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
> > - dev->features |= NETIF_F_HW_VLAN_FILTER;
> > - }
> > + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) &&
> > + virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
> > + dev->features |= NETIF_F_HW_VLAN_FILTER;
> >
> > err = register_netdev(dev);
> > if (err) {
> > @@ -1039,14 +1280,21 @@ static int virtnet_probe(struct
> > virtio_device *vdev)
> > }
> >
> > /* Last of all, set up some receive buffers. */
> > - try_fill_recv(vi, GFP_KERNEL);
> > -
> > - /* If we didn't even get one input buffer, we're useless. */
> > - if (vi->num == 0) {
> > - err = -ENOMEM;
> > - goto unregister;
> > + for (i = 0; i < numtxqs; i++) {
> > + try_fill_recv(vi->rq[i], GFP_KERNEL);
> > +
> > + /* If we didn't even get one input buffer, we're useless. */
> > + if (vi->rq[i]->num == 0) {
> > + if (i)
> > + free_unused_bufs(vi);
> > + err = -ENOMEM;
> > + goto free_recv_bufs;
> > + }
> > }
> >
> > + dev_info(&dev->dev, "(virtio-net) Allocated %d RX & TX vq's\n",
> > + numtxqs);
> > +
> > /* Assume link up if device can't report link status,
> > otherwise get link status from config. */
> > if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
> > @@ -1057,61 +1305,51 @@ static int virtnet_probe(struct
> > virtio_device *vdev)
> > netif_carrier_on(dev);
> > }
> >
> > - pr_debug("virtnet: registered device %s\n", dev->name);
> > + pr_debug("virtnet: registered device %s with %d RX and TX vq's\n",
> > + dev->name, numtxqs);
> > return 0;
> >
> > -unregister:
> > +free_recv_bufs:
> > + free_receive_bufs(vi);
> > unregister_netdev(dev);
> > - cancel_delayed_work_sync(&vi->refill);
> > +
> > free_vqs:
> > + for (i = 0; i < numtxqs; i++)
> > + cancel_delayed_work_sync(&vi->rq[i]->refill);
> > vdev->config->del_vqs(vdev);
> > + free_rq_sq(vi);
> > +
> > free_stats:
> > free_percpu(vi->stats);
> > +
> > free:
> > free_netdev(dev);
> > return err;
> > }
> >
> > -static void free_unused_bufs(struct virtnet_info *vi)
> > -{
> > - void *buf;
> > - while (1) {
> > - buf = virtqueue_detach_unused_buf(vi->svq);
> > - if (!buf)
> > - break;
> > - dev_kfree_skb(buf);
> > - }
> > - while (1) {
> > - buf = virtqueue_detach_unused_buf(vi->rvq);
> > - if (!buf)
> > - break;
> > - if (vi->mergeable_rx_bufs || vi->big_packets)
> > - give_pages(vi, buf);
> > - else
> > - dev_kfree_skb(buf);
> > - --vi->num;
> > - }
> > - BUG_ON(vi->num != 0);
> > -}
> > -
> > static void __devexit virtnet_remove(struct virtio_device *vdev)
> > {
> > struct virtnet_info *vi = vdev->priv;
> > + int i;
> >
> > /* Stop all the virtqueues. */
> > vdev->config->reset(vdev);
> >
> >
> > unregister_netdev(vi->dev);
> > - cancel_delayed_work_sync(&vi->refill);
> > +
> > + for (i = 0; i < vi->numtxqs; i++)
> > + cancel_delayed_work_sync(&vi->rq[i]->refill);
> >
> > /* Free unused buffers in both send and recv, if any. */
> > free_unused_bufs(vi);
> >
> > vdev->config->del_vqs(vi->vdev);
> >
> > - while (vi->pages)
> > - __free_pages(get_a_page(vi, GFP_KERNEL), 0);
> > + free_receive_bufs(vi);
> > +
> > + /* Free memory for send and receive queues */
> > + free_rq_sq(vi);
> >
> > free_percpu(vi->stats);
> > free_netdev(vi->dev);
> > @@ -1129,7 +1367,7 @@ static unsigned int features[] = {
> > VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4,
> > VIRTIO_NET_F_GUEST_TSO6,
> > VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
> > VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
> > - VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
> > + VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
> > VIRTIO_NET_F_MULTIQUEUE,
> > };
> >
> > static struct virtio_driver virtio_net_driver = {
> > diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> > index 970d5a2..fa85ac3 100644
> > --- a/include/linux/virtio_net.h
> > +++ b/include/linux/virtio_net.h
> > @@ -49,6 +49,7 @@
> > #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support
> > */
> > #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering
> > */
> > #define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control
> > support */
> > +#define VIRTIO_NET_F_MULTIQUEUE 21 /* Device supports multiple
> > TXQ/RXQ */
> >
> > #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
> >
> > @@ -57,6 +58,8 @@ struct virtio_net_config {
> > __u8 mac[6];
> > /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
> > __u16 status;
> > + /* total number of RX/TX queues */
> > + __u16 num_queue_pairs;
> > } __attribute__((packed));
> >
> > /* This is the first element of the scatter-gather list. If you
> > don't
> >
> >
>
> --
>
> Sasha.
^ permalink raw reply
* Re: [net-next RFC PATCH 4/7] tuntap: multiqueue support
From: Jason Wang @ 2011-08-14 6:05 UTC (permalink / raw)
To: Eric Dumazet
Cc: krkumar2, kvm, mst, qemu-devel, netdev, rusty, linux-kernel,
virtualization, mirq-linux, davem
In-Reply-To: <1313159376.2354.26.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>
----- Original Message -----
> Le vendredi 12 août 2011 à 09:55 +0800, Jason Wang a écrit :
>
> >+ rxq = skb_get_rxhash(skb);
> >+ if (rxq) {
> >+ tfile = rcu_dereference(tun->tfiles[rxq % numqueues]);
> >+ if (tfile)
> >+ goto out;
> >+ }
>
> You can avoid an expensive divide with following trick :
>
> u32 idx = ((u64)rxq * numqueues) >> 32;
>
Sure.
>
>
> > -static struct tun_struct *tun_get(struct file *file)
> > +static void tun_detach_all(struct net_device *dev)
> > {
> > - return __tun_get(file->private_data);
> > + struct tun_struct *tun = netdev_priv(dev);
> > + struct tun_file *tfile, *tfile_list[MAX_TAP_QUEUES];
> > + int i, j = 0;
> > +
> > + spin_lock(&tun_lock);
> > +
> > + for (i = 0; i < MAX_TAP_QUEUES && tun->numqueues; i++) {
> > + tfile = rcu_dereference_protected(tun->tfiles[i],
> > + lockdep_is_held(&tun_lock));
> > + if (tfile) {
> > + wake_up_all(&tfile->wq.wait);
> > + tfile_list[i++] = tfile;
>
> typo here, you want tfile_list[j++] = tfile;
>
Yes, thanks for catching this.
> > + rcu_assign_pointer(tun->tfiles[i], NULL);
> > + rcu_assign_pointer(tfile->tun, NULL);
> > + --tun->numqueues;
> > + }
> > + }
> > + BUG_ON(tun->numqueues != 0);
> > + spin_unlock(&tun_lock);
> > +
> > + synchronize_rcu();
> > + for(--j; j >= 0; j--)
> > + sock_put(&tfile_list[j]->sk);
> > }
> >
>
> Could you take a look at net/packet/af_packet.c, to check how David
> did
> the whole fanout thing ?
>
> __fanout_unlink()
>
> Trick is to not leave NULL entries in the tun->tfiles[] array.
>
> It makes things easier in hot path.
Sure I would go to take a look at this.
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [net-next RFC PATCH 4/7] tuntap: multiqueue support
From: Jason Wang @ 2011-08-14 6:07 UTC (permalink / raw)
To: paulmck
Cc: krkumar2, kvm, mst, qemu-devel, netdev, rusty, linux-kernel,
virtualization, mirq-linux, davem
In-Reply-To: <20110812232131.GU2395@linux.vnet.ibm.com>
----- Original Message -----
> On Fri, Aug 12, 2011 at 09:55:20AM +0800, Jason Wang wrote:
> > With the abstraction that each socket were a backend of a
> > queue for userspace, this patch adds multiqueue support for
> > tap device by allowing multiple sockets to be attached to a
> > tap device. Then we could parallize the transmission by put
> > them into different socket.
> >
> > As queue related information were stored in private_data of
> > file new, we could simply implement the multiqueue support
> > by add an array of pointers to sockets were stored in the
> > tap device. Then ioctls may be added to manipulate those
> > pointers for adding or removing queues.
> >
> > In order to let tx path lockless, NETIF_F_LLTX were used for
> > multiqueue tap device. And RCU is used for doing
> > synchronization between packet handling and system calls
> > such as removing queues.
> >
> > Currently, multiqueue support is limited for tap , but it's
> > easy also enable it for tun if we find it was also helpful.
>
> Question below about calls to tun_get_slot().
>
> Thanx, Paul
>
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
> > drivers/net/tun.c | 376
> > ++++++++++++++++++++++++++++++++++-------------------
> > 1 files changed, 243 insertions(+), 133 deletions(-)
> >
> > diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> > index 4cd292a..8bc6dff 100644
> > --- a/drivers/net/tun.c
> > +++ b/drivers/net/tun.c
> > @@ -108,6 +108,8 @@ struct tap_filter {
> > unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN];
> > };
> >
> > +#define MAX_TAP_QUEUES (NR_CPUS < 16 ? NR_CPUS : 16)
> > +
> > struct tun_file {
> > struct sock sk;
> > struct socket socket;
> > @@ -115,7 +117,7 @@ struct tun_file {
> > int vnet_hdr_sz;
> > struct tap_filter txflt;
> > atomic_t count;
> > - struct tun_struct *tun;
> > + struct tun_struct __rcu *tun;
> > struct net *net;
> > struct fasync_struct *fasync;
> > unsigned int flags;
> > @@ -124,7 +126,8 @@ struct tun_file {
> > struct tun_sock;
> >
> > struct tun_struct {
> > - struct tun_file *tfile;
> > + struct tun_file *tfiles[MAX_TAP_QUEUES];
> > + unsigned int numqueues;
> > unsigned int flags;
> > uid_t owner;
> > gid_t group;
> > @@ -139,80 +142,183 @@ struct tun_struct {
> > #endif
> > };
> >
> > -static int tun_attach(struct tun_struct *tun, struct file *file)
> > +static DEFINE_SPINLOCK(tun_lock);
> > +
> > +/*
> > + * get_slot: return a [unused/occupied] slot in tun->tfiles[]:
> > + * - if 'f' is NULL, return the first empty slot;
> > + * - otherwise, return the slot this pointer occupies.
> > + */
> > +static int tun_get_slot(struct tun_struct *tun, struct tun_file
> > *tfile)
> > {
> > - struct tun_file *tfile = file->private_data;
> > - int err;
> > + int i;
> >
> > - ASSERT_RTNL();
> > + for (i = 0; i < MAX_TAP_QUEUES; i++) {
> > + if (rcu_dereference(tun->tfiles[i]) == tfile)
> > + return i;
> > + }
> >
> > - netif_tx_lock_bh(tun->dev);
> > + /* Should never happen */
> > + BUG_ON(1);
> > +}
> >
> > - err = -EINVAL;
> > - if (tfile->tun)
> > - goto out;
> > +/*
> > + * tun_get_queue(): calculate the queue index
> > + * - if skbs comes from mq nics, we can just borrow
> > + * - if not, calculate from the hash
> > + */
> > +static struct tun_file *tun_get_queue(struct net_device *dev,
> > + struct sk_buff *skb)
> > +{
> > + struct tun_struct *tun = netdev_priv(dev);
> > + struct tun_file *tfile = NULL;
> > + int numqueues = tun->numqueues;
> > + __u32 rxq;
> >
> > - err = -EBUSY;
> > - if (tun->tfile)
> > + BUG_ON(!rcu_read_lock_held());
> > +
> > + if (!numqueues)
> > goto out;
> >
> > - err = 0;
> > - tfile->tun = tun;
> > - tun->tfile = tfile;
> > - netif_carrier_on(tun->dev);
> > - dev_hold(tun->dev);
> > - sock_hold(&tfile->sk);
> > - atomic_inc(&tfile->count);
> > + if (likely(skb_rx_queue_recorded(skb))) {
> > + rxq = skb_get_rx_queue(skb);
> > +
> > + while (unlikely(rxq >= numqueues))
> > + rxq -= numqueues;
> > +
> > + tfile = rcu_dereference(tun->tfiles[rxq]);
> > + if (tfile)
> > + goto out;
> > + }
> > +
> > + /* Check if we can use flow to select a queue */
> > + rxq = skb_get_rxhash(skb);
> > + if (rxq) {
> > + tfile = rcu_dereference(tun->tfiles[rxq % numqueues]);
> > + if (tfile)
> > + goto out;
> > + }
> > +
> > + /* Everything failed - find first available queue */
> > + for (rxq = 0; rxq < MAX_TAP_QUEUES; rxq++) {
> > + tfile = rcu_dereference(tun->tfiles[rxq]);
> > + if (tfile)
> > + break;
> > + }
> >
> > out:
> > - netif_tx_unlock_bh(tun->dev);
> > - return err;
> > + return tfile;
> > }
> >
> > -static void __tun_detach(struct tun_struct *tun)
> > +static int tun_detach(struct tun_file *tfile, bool clean)
> > {
> > - struct tun_file *tfile = tun->tfile;
> > - /* Detach from net device */
> > - netif_tx_lock_bh(tun->dev);
> > - netif_carrier_off(tun->dev);
> > - tun->tfile = NULL;
> > - netif_tx_unlock_bh(tun->dev);
> > -
> > - /* Drop read queue */
> > - skb_queue_purge(&tfile->socket.sk->sk_receive_queue);
> > -
> > - /* Drop the extra count on the net device */
> > - dev_put(tun->dev);
> > -}
> > + struct tun_struct *tun;
> > + struct net_device *dev = NULL;
> > + bool destroy = false;
> >
> > -static void tun_detach(struct tun_struct *tun)
> > -{
> > - rtnl_lock();
> > - __tun_detach(tun);
> > - rtnl_unlock();
> > -}
> > + spin_lock(&tun_lock);
> >
> > -static struct tun_struct *__tun_get(struct tun_file *tfile)
> > -{
> > - struct tun_struct *tun = NULL;
> > + tun = rcu_dereference_protected(tfile->tun,
> > + lockdep_is_held(&tun_lock));
> > + if (tun) {
> > + int index = tun_get_slot(tun, tfile);
>
> Don't we need to be in an RCU read-side critical section in order to
> safely call tun_get_slot()?
>
> Or is the fact that we are calling with tun_lock held sufficient?
> If the latter, then the rcu_dereference() in tun_get_slot() should
> use rcu_dereference_protected() rather than rcu_dereference().
>
Nice catch. The latter, tun_lock held is sufficient. Thanks.
^ permalink raw reply
* Re: [net-next RFC PATCH 0/7] multiqueue support for tun/tap
From: Jason Wang @ 2011-08-14 6:19 UTC (permalink / raw)
To: Sridhar Samudrala
Cc: krkumar2, kvm, mst, qemu-devel, netdev, rusty, linux-kernel,
virtualization, mirq-linux, davem
In-Reply-To: <1313196390.28682.14.camel@w-sridhar.beaverton.ibm.com>
----- Original Message -----
> On Fri, 2011-08-12 at 09:54 +0800, Jason Wang wrote:
> > As multi-queue nics were commonly used for high-end servers,
> > current single queue based tap can not satisfy the
> > requirement of scaling guest network performance as the
> > numbers of vcpus increase. So the following series
> > implements multiple queue support in tun/tap.
> >
> > In order to take advantages of this, a multi-queue capable
> > driver and qemu were also needed. I just rebase the latest
> > version of Krishna's multi-queue virtio-net driver into this
> > series to simplify the test. And for multiqueue supported
> > qemu, you can refer the patches I post in
> > http://www.spinics.net/lists/kvm/msg52808.html. Vhost is
> > also a must to achieve high performance and its code could
> > be used for multi-queue without modification. Alternatively,
> > this series can be also used for Krishna's M:N
> > implementation of multiqueue but I didn't test it.
> >
> > The idea is simple: each socket were abstracted as a queue
> > for tun/tap, and userspace may open as many files as
> > required and then attach them to the devices. In order to
> > keep the ABI compatibility, device creation were still
> > finished in TUNSETIFF, and two new ioctls TUNATTACHQUEUE and
> > TUNDETACHQUEUE were added for user to manipulate the numbers
> > of queues for the tun/tap.
>
> Is it possible to have tap create these queues automatically when
> TUNSETIFF is called instead of having userspace to do the new
> ioctls. I am just wondering if it is possible to get multi-queue
> to be enabled without any changes to qemu. I guess the number of
> queues
> could be based on the number of vhost threads/guest virtio-net queues.
It's possible but we need at least pass the number of queues
through TUNSETIFF which may break the ABI? And this method
is not flexible as adding new ioctls, consider we may
disable some queues for some reaons such as running a single
queue guest or pxe on an multiple virtio-net backened.
>
> Also, is it possible to enable multi-queue on the host alone without
> any guest virtio-net changes?
If we use current driver without changes, it can run on host
that multiqueu enabled. But it can not make use all of the
queues.
>
> Have you done any multiple TCP_RR/UDP_RR testing with small packet
> sizes? 256byte request/response with 50-100 instances?
Not yet, I would do it after I was back from KVM Forum.
>
> >
> > I've done some basic performance testing of multi queue
> > tap. For tun, I just test it through vpnc.
> >
> > Notes:
> > - Test shows improvement when receving packets from
> > local/external host to guest, and send big packet from guest
> > to local/external host.
> > - Current multiqueue based virtio-net/tap introduce a
> > regression of send small packet (512 byte) from guest to
> > local/external host. I suspect it's the issue of queue
> > selection in both guest driver and tap. Would continue to
> > investigate.
> > - I would post the perforamnce numbers as a reply of this
> > mail.
> >
> > TODO:
> > - solve the issue of packet transmission of small packets.
> > - addressing the comments of virtio-net driver
> > - performance tunning
> >
> > Please review and comment it, Thanks.
> >
> > ---
> >
> > Jason Wang (5):
> > tuntap: move socket/sock related structures to tun_file
> > tuntap: categorize ioctl
> > tuntap: introduce multiqueue related flags
> > tuntap: multiqueue support
> > tuntap: add ioctls to attach or detach a file form tap device
> >
> > Krishna Kumar (2):
> > Change virtqueue structure
> > virtio-net changes
> >
> >
> > drivers/net/tun.c | 738 ++++++++++++++++++++++++++-----------------
> > drivers/net/virtio_net.c | 578 ++++++++++++++++++++++++----------
> > drivers/virtio/virtio_pci.c | 10 -
> > include/linux/if_tun.h | 5
> > include/linux/virtio.h | 1
> > include/linux/virtio_net.h | 3
> > 6 files changed, 867 insertions(+), 468 deletions(-)
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Linux ipsec and dynamic routing
From: hachi @ 2011-08-14 8:58 UTC (permalink / raw)
To: netdev
Hello heroes!
I am after an eventual goal of dynamic routing (BGP) via the linux kernel using ipsec tunneling and no inner tunnel (gre or others). On the way to this goal I've done some light source diving of source and talked a little theory with others to hunt down as much as I could to get closer. I have a lot of questions here, so thanks for any answers or suggestions you may give.
All of my testing is done using openswan, and debian stable (linux 2.6.32, iproute 20100519)
* Are there any existing methods of implementing dynamic routed ipsec armored ip forwarding?
I haven't been able to find anyone who has a working setup in this regard. My goal is very similar to the exposed routing setup of Amazon's VPC ipsec connections. I'm trying to implement one or both ends in linux successfully and haven't found any docs on the subject.
* The ip xfrm policy selector syntax has a 'dev' argument that can be supplied. I was unable to figure out what the intention of this argument is via source, and I never found any docs or samples of its use. Can anyone enlighten me?
* Are there any plans or generally accepted patches to expand the rules that may be used to select what frames are transformed?
Currently the rules I can use are source address, destination address, and the mysterious 'dev' setting. I think the ultimate solution for me would be able to select frames for forwarding based on the gateway defined in the normal routing tables.
* Do ip xfrm policy rules bypass normal routing policy?
I'm relatively certain the answer to this is 'yes'. However I may not have the full story.
I ran a simple test of two /24 exposed at either end of an ipsec tunnel. The left end is 10.24.2.0/24, the right is 10.24.3.0/24, and the transit is being done via 10.24.1.0/30. I configured this test using openswan and after setting up and checking to see if the boxes can pass frames I examined the policy list and the routing table.
src 10.24.3.0/24 dst 10.24.2.0/24
dir fwd priority 2344 ptype main
tmpl src 10.24.1.2 dst 10.24.1.1
proto esp reqid 16385 mode tunnel
10.24.1.0/30 dev eth1 proto kernel scope link src 10.24.1.1
10.24.2.0/24 dev eth0 proto kernel scope link src 10.24.2.2
172.16.3.0/24 dev eth0 proto kernel scope link src 172.16.3.16
default via 172.16.3.1 dev eth0
The opposite end is appropriately reversed, and there are two more policies for 'in' and 'out', but they are appropriately similar.
What I notice is that despite not having a route for the exposed subnet on the other end of the tunnel linux happily forwards the frames and encodes them to the other end, and visa versa.
I can watch the frames passing across eth1 and they are appropriately encrypted as specified, and if I turn the ipsec tunnel off on both sides the forwarding capability does indeed shut down. If I add routes for the opposing ends then the kernel starts forwarding frames as expected.
* If I need to dive into this more to seek an implementation, does anyone know if the general theory should be the dynamic routing daemon in userspace should expand its code to update xfrm policies, or is the fact that xfrm policy is taking precedence over routing an oversight of the kernel code that should be fixed/updated/etc. ?
* Is there any hope for policy routing table support to extend into this as well?
I hope I'm reaching out to the proper group for this inquiry, please let me know if this was wrong :)
--hachi
^ permalink raw reply
* r8169 hard-freezes the system on big network loads
From: Kjun Chen @ 2011-08-14 11:08 UTC (permalink / raw)
To: netdev; +Cc: romieu, nic_swsd
Hi,
as I have mentioned to linux-kernel, this is perfectly reproducible: receiving
70 MB/s or more freezes my laptop (Dell Vostro, amd64, 6 GB RAM, 8x Intel Core
i7 CPU Q 740 @ 1.73GHz) completely, sometimes within seconds, sometimes only
after a minute.
Watching the normal console I get loads of
r8169 0000:13:00.0: eth0: link up
r8169 0000:13:00.0: eth0: link up
[...]
one message about every 1-2 seconds (sometimes even 2 per second) while
network is active on 2.6.37.6. Up to the latest kernel (3.0.1) this freeze
happens. However, 2.6.32.28 works with no problems, and it doesn't show those
"eth0: link up" messages. I haven't tried kernels between .32 and .37.
lspci says:
13:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI
Express Gigabit Ethernet controller (rev 03)
The solution with 2.6.37 and above: use the r8168 module from the realtek
website. I have tested it with >30 GB at rates of 112 MB/s and experienced no
freezes anymore.
If you need any other information or help, please let me know.
cheers,
Michael
--
Sambodha: The Return of True Self-Knowledge
^ permalink raw reply
* PROTECTED PROJECT!!
From: KimJr @ 2011-08-14 8:49 UTC (permalink / raw)
I want to discuss an important issue with you .
I write to know if this is your valid email. Please,
let me know if your email is still valid. My valid Email:
lkimyu@9.cn KimJr
^ permalink raw reply
* sch_generic: warning: the comparison will always evaluate as ‘true’ for the address of ‘noop_qdisc’ will never be NULL
From: Kevin Winchester @ 2011-08-14 13:44 UTC (permalink / raw)
To: hadi, davem; +Cc: netdev, LKML
With:
gcc (GCC) 4.6.1
I noticed the following warning appearing in my build:
net/sched/sch_generic.c: In function ‘dev_graft_qdisc’:
net/sched/sch_generic.c:678:2: warning: the comparison will always
evaluate as ‘true’ for the address of ‘noop_qdisc’ will never be NULL
[-Waddress]
The code in question runs:
/* ... and graft new one */
if (qdisc == NULL)
qdisc = &noop_qdisc;
dev_queue->qdisc_sleeping = qdisc;
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
where rcu_assign_pointer has a null check that does not apply to
noop_qdisc, which will never be null.
My question is, should that really be assigning &noop_qdisc in there?
It seems odd to assign &noop_qdisc to qdisc only if qdisc is null, and
then unconditionally assign &noop_qdisc into dev_queue->qdisc.
Should the line be:
rcu_assign_pointer(dev_queue->qdisc, qdisc);
instead?
Just curious,
--
Kevin Winchester
^ permalink raw reply
* Re: [PATCH] virtio-net: Read MAC only after initializing MSI-X
From: Sasha Levin @ 2011-08-14 13:57 UTC (permalink / raw)
To: Rusty Russell
Cc: linux-kernel, Michael S. Tsirkin, virtualization, netdev, kvm
In-Reply-To: <878vqw9007.fsf@rustcorp.com.au>
On Sun, 2011-08-14 at 12:23 +0930, Rusty Russell wrote:
> On Sat, 13 Aug 2011 11:51:01 +0300, Sasha Levin <levinsasha928@gmail.com> wrote:
> > The MAC of a virtio-net device is located at the first field of the device
> > specific header. This header is located at offset 20 if the device doesn't
> > support MSI-X or offset 24 if it does.
>
> Erk. This means, in general, we have to do virtio_find_single_vq or
> config->find_vqs before we examine any config options.
>
> Look at virtio_blk, which has the same error.
>
> Solutions in order of best to worst:
> (1) Enable MSI-X before calling device probe. This means reserving two
> vectors in virtio_pci_probe to ensure we *can* do this, I think. Michael?
Do you mean reserving the vectors even before we probed the device for
MSI-X support? Wouldn't we need 3 vectors then? (config, input, output).
> (2) Ensure ordering of "find_vqs then access config space" statically. This
> probably means handing the vqs array to virtio_config_val, so noone
> can call it before they have their virtqueues.
Just noticed that only virtio-blk uses virtio_config_val(), while the
others are still doing 'if(virtio_has_feature()) vdev->config->get()',
I'll send patches to fix that regardless of what we end up doing here.
Did you want to pass the vq array to virtio_config_val() just to check
that they were already found?
> (3) Ensure ordering dynamically, ie. BUG_ON() if they haven't done
> find_vqs when they call the config accessors.
>
> If (1) is too invasive for -stable, then we should rearrange the drivers
> in separate patches (and cc: -stable), then fix it properly.
>
> Good catch Sasha!
>
> Cheers,
> Rusty.
--
Sasha.
^ permalink raw reply
* [RFC PATCH v2] net: dm9000: add support for device tree probing
From: Daniel Morsing @ 2011-08-14 17:34 UTC (permalink / raw)
To: devicetree-discuss
Cc: Grant Likely, David S. Miller, netdev, Mark Brown, Ben Dooks,
Daniel Morsing
This patch adds support for probing the dm9000 driver through device
trees.
The patch works by supplying its own platform_data struct when probed
via device tree. This allows us to rely on the existing options parsing
in the driver and avoid ifdeffery in the probe function.
Signed-off-by: Daniel Morsing <daniel.morsing@gmail.com>
---
Currently there are no users of this functionality, but once support for
DT on OMAP3 matures, I plan to migrate the devkit8000 board to DT.
Changes since v1:
- Changed the binding with input from Grant Likely.
- Make explicit what the bindings do instead of refering
to linux specific flags.
- Length check the mac address read so we don't copy random data.
- simplify parsing of the device tree.
- Add relevant driver maintainers to CC (sorry about that)
Documentation/devicetree/bindings/net/dm9000.txt | 42 +++++++++++
drivers/net/dm9000.c | 83 +++++++++++++++++++++-
2 files changed, 122 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/dm9000.txt
diff --git a/Documentation/devicetree/bindings/net/dm9000.txt b/Documentation/devicetree/bindings/net/dm9000.txt
new file mode 100644
index 0000000..cbbdb3d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dm9000.txt
@@ -0,0 +1,42 @@
+Davicom DM9000 ethernet controller
+
+Required properties:
+
+ - compatible : Should be "davicom,dm9000"
+
+ - interrupts : Interrupt controller specific encoding, which specifies 1
+ or 2 interrupts. The first interrupt is for rx/tx and is required by the
+ driver to function. The second interrupt is for wake on lan support
+ and is optional.
+
+ - reg : 2 Physical address specifiers, where the first specifies the address
+ register of device, and the second specifies the data register of the device
+
+Optional properties:
+
+ - local-mac-address : Binary data specifying a mac address override
+
+ - reg-io-width : one cell specifying the width of IO operations in bits.
+ valid values are 8, 16, and 32. If this property is not specified, or has
+ an invalid value, the driver will default to 32 bits.
+
+ - phy-handle : phandle to external phy.
+
+ - no-eeprom : Empty property specifying that no EEPROM is attached to the
+ device.
+
+ - simple-phy : Empty property specifying that the driver should use the simple
+ phy polling mode
+
+Example:
+
+ethernet@2c000000 {
+ compatible = "davicom,dm9000";
+ reg = <0x2c000000 0x04>,
+ <0x2c000400 0x04>;
+ interrupts = <185 1>;
+ local-mac-address = [02 65 16 01 c0 09];
+ reg-io-width = <16>
+ phy-handle = <&phy0>
+ no-eeprom;
+};
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 8ef31dc..81273b7 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -35,6 +35,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <asm/delay.h>
#include <asm/irq.h>
@@ -1164,10 +1165,13 @@ dm9000_open(struct net_device *dev)
if (netif_msg_ifup(db))
dev_dbg(db->dev, "enabling %s\n", dev->name);
- /* If there is no IRQ type specified, default to something that
- * may work, and tell the user that this is a problem */
+ /*
+ * If there is no IRQ type specified, tell the user that this is a
+ * problem. If we were probed with device tree, we can assume that
+ * the IRQ type is already set up, so don't emit the warning.
+ */
- if (irqflags == IRQF_TRIGGER_NONE)
+ if (!db->dev->of_node && irqflags == IRQF_TRIGGER_NONE)
dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
irqflags |= IRQF_SHARED;
@@ -1350,6 +1354,66 @@ static const struct net_device_ops dm9000_netdev_ops = {
#endif
};
+#ifdef CONFIG_OF
+static const struct of_device_id dm9000_of_match[] = {
+ { .compatible = "davicom,dm9000" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dm9000_of_match);
+
+static int __devinit
+dm9000_dt_fill_platdata(struct platform_device *pdev,
+ struct dm9000_plat_data *pdata)
+{
+ struct device_node *of_node = pdev->dev.of_node, *phy_node;
+ const u8 *mac_addr;
+ u32 io_width;
+ int mac_len;
+
+ if (!of_property_read_u32(of_node, "reg-io-width", &io_width)) {
+ switch (io_width) {
+ case 8:
+ pdata->flags |= DM9000_PLATF_8BITONLY;
+ break;
+ case 16:
+ pdata->flags |= DM9000_PLATF_16BITONLY;
+ break;
+ default:
+ dev_warn(&pdev->dev,
+ "Invalid value passed in reg-io-width. Defaulting to 32 bit I/O accesses\n");
+ case 32:
+ pdata->flags |= DM9000_PLATF_32BITONLY;
+ break;
+ }
+ }
+
+ phy_node = of_parse_phandle(of_node, "phy-handle", 0);
+ if (phy_node) {
+ pdata->flags |= DM9000_PLATF_EXT_PHY;
+ of_node_put(phy_node);
+ }
+
+ if (of_find_property(of_node, "no-eeprom", NULL))
+ pdata->flags |= DM9000_PLATF_NO_EEPROM;
+ if (of_find_property(of_node, "simple-phy", NULL))
+ pdata->flags |= DM9000_PLATF_SIMPLE_PHY;
+
+ mac_addr = of_get_property(of_node, "local-mac-address", &mac_len);
+ if (mac_addr && mac_len == 6)
+ memcpy(pdata->dev_addr, mac_addr, 6);
+
+ return 0;
+}
+
+#else
+#define dm9000_of_match NULL
+static inline int dm9000_dt_fill_platdata(struct platform_device *pdev,
+ struct dm9000_plat_data *pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
/*
* Search DM9000 board, allocate space and register it
*/
@@ -1359,12 +1423,24 @@ dm9000_probe(struct platform_device *pdev)
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
struct board_info *db; /* Point a board information structure */
struct net_device *ndev;
+ struct dm9000_plat_data pdata_of;
const unsigned char *mac_src;
int ret = 0;
int iosize;
int i;
u32 id_val;
+ if (pdev->dev.of_node) {
+ if (!pdata) {
+ memset(&pdata_of, 0, sizeof(pdata_of));
+ pdata = &pdata_of;
+ }
+
+ ret = dm9000_dt_fill_platdata(pdev, pdata);
+ if (ret < 0)
+ return ret;
+ }
+
/* Init network device */
ndev = alloc_etherdev(sizeof(struct board_info));
if (!ndev) {
@@ -1677,6 +1753,7 @@ static struct platform_driver dm9000_driver = {
.name = "dm9000",
.owner = THIS_MODULE,
.pm = &dm9000_drv_pm_ops,
+ .of_match_table = dm9000_of_match,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
--
1.7.6
^ permalink raw reply related
* Re: sch_generic: warning: the comparison will always evaluate as ‘true’ for the address of ‘noop_qdisc’ will never be NULL
From: Eric Dumazet @ 2011-08-14 17:39 UTC (permalink / raw)
To: Kevin Winchester; +Cc: hadi, davem, netdev, LKML, Paul E. McKenney
In-Reply-To: <CAELBVzA-ArFvp9MRp5ZvgsEpi4ikt9Nq=zHsNSLAOiD=TqZC=w@mail.gmail.com>
Le dimanche 14 août 2011 à 10:44 -0300, Kevin Winchester a écrit :
> With:
>
> gcc (GCC) 4.6.1
>
> I noticed the following warning appearing in my build:
>
> net/sched/sch_generic.c: In function ‘dev_graft_qdisc’:
> net/sched/sch_generic.c:678:2: warning: the comparison will always
> evaluate as ‘true’ for the address of ‘noop_qdisc’ will never be NULL
> [-Waddress]
>
> The code in question runs:
>
>
> /* ... and graft new one */
> if (qdisc == NULL)
> qdisc = &noop_qdisc;
> dev_queue->qdisc_sleeping = qdisc;
> rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
>
> where rcu_assign_pointer has a null check that does not apply to
> noop_qdisc, which will never be null.
>
gcc is a bit stupid here. Of course we know &noop_qdisc cannot be NULL.
> My question is, should that really be assigning &noop_qdisc in there?
> It seems odd to assign &noop_qdisc to qdisc only if qdisc is null, and
> then unconditionally assign &noop_qdisc into dev_queue->qdisc.
>
> Should the line be:
>
> rcu_assign_pointer(dev_queue->qdisc, qdisc);
>
> instead?
>
> Just curious,
>
This was already taken into account, the trick is to make rcu_assign()
not trying to be smart, and use RCU_INIT_POINTER() in places we want to
assign NULL pointers.
So one patch is carried by Paul McKenney (RCU maintainer) for next
kernel, and other one in net-next :
http://git2.kernel.org/?p=linux/kernel/git/paulmck/linux-2.6-rcu.git;a=commitdiff;h=a7590ddfc2c855e75111ef18147a86578fe136e4
http://git2.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=a9b3cd7f323b2e57593e7215362a7b02fc933e3a
^ permalink raw reply
* PROTECTED PROJECT!!
From: KimJr @ 2011-08-14 17:58 UTC (permalink / raw)
--
I want to discuss an important issue with you .
I write to know if this is your valid email.
Please, let me know if your email is still valid.
My valid Email: lkimyu@9.cn
KimJr
^ permalink raw reply
* Re: [PATCH 1/3] drivers/staging/rtl8187se: Don't pass huge struct by value
From: Jesper Juhl @ 2011-08-14 18:32 UTC (permalink / raw)
To: Stephen Rothwell
Cc: Greg Kroah-Hartman, devel, linux-kernel, Andrea Merello,
Andre Nogueira, Lucas De Marchi, David S. Miller, Larry Finger,
Stefan Weil, Ilia Mirkin, netdev
In-Reply-To: <20110813180531.34a47d9bf4851f8c1e9a227c@canb.auug.org.au>
On Sat, 13 Aug 2011, Stephen Rothwell wrote:
> Hi all,
>
> On Sat, 13 Aug 2011 01:04:36 +0200 (CEST) Jesper Juhl <jj@chaosbits.net> wrote:
> >
> > From: Jesper Juhl <jj@chaosbits.net>
> > Date: Sat, 13 Aug 2011 00:51:40 +0200
> >
> > struct ieee80211_network is fairly large (more than half a kilobyte),
> > so let's pass a pointer instead of passing the entire structure by
> > value when ieee80211_is_54g() and ieee80211_is_shortslot() need to
> > look at a few members.
> > Also remove parentheses around the values being returned from those
> > two functions - 'return' is not a function.
>
> Also, is there some reason that they are not "static inline bool"
> functions defined directlt in ieee80211.h?
>
I agree to the bool return type, I should have done that.
the "static inline" and defined in the header bits I didn't do because I
was afraid that that was not valid in combination with EXPORT_SYMBOL().
--
Jesper Juhl <jj@chaosbits.net> http://www.chaosbits.net/
Don't top-post http://www.catb.org/jargon/html/T/top-post.html
Plain text mails only, please.
^ permalink raw reply
* 3.1-rc1-git9: Reported regressions 2.6.39 -> 3.0
From: Rafael J. Wysocki @ 2011-08-14 19:02 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Maciej Rutecki, Florian Mickler, Andrew Morton, Linus Torvalds,
Kernel Testers List, Network Development, Linux ACPI,
Linux PM List, Linux SCSI List, Linux Wireless List, DRI
[NOTE:
We already have a bug entry for tracking regressions from 3.0:
http://bugzilla.kernel.org/show_bug.cgi?id=40982
but there are no reports linked to it, mostly because Maciej is on vacation,
but also because the frequency of reporting regressions has been low
recently. So, if you're seeing a regression from 3.0, please let us know.]
This message contains a list of some post-2.6.39 regressions introduced before
3.0, for which there are no fixes in the mainline known to the tracking team.
If any of them have been fixed already, please let us know.
If you know of any other unresolved post-2.6.39 regressions, please let us know
either and we'll add them to the list. Also, please let us know if any
of the entries below are invalid.
Each entry from the list will be sent additionally in an automatic reply to
this message with CCs to the people involved in reporting and handling the
issue.
Listed regressions statistics:
Date Total Pending Unresolved
----------------------------------------
2011-08-14 63 22 19
Unresolved regressions
----------------------
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=40282
Subject : IP forwarding regression since 3.0-rc6
Submitter : Stephan Seitz <stse+lkml-S0d6l+6kcjrOGKtSYHEJQ9HuzzzSOjJt@public.gmane.org>
Date : 2011-07-25 12:51 (21 days old)
Message-ID : <20110725T141145.GA.2ae38.stse-S0d6l+6kcjrOGKtSYHEJQ9HuzzzSOjJt@public.gmane.org>
References : http://marc.info/?l=linux-kernel&m=131159880004908&w=2
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=40172
Subject : lockdep trace from post 3.0.
Submitter : Dave Jones <davej-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Date : 2011-07-24 1:32 (22 days old)
Message-ID : <20110724013257.GA6777-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
References : http://marc.info/?l=linux-kernel&m=131147120206819&w=2
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=40092
Subject : RCU stall in linux-3.0.0
Submitter : Philip Armstrong <phil-awZZuG094qgqdlJmJB21zg@public.gmane.org>
Date : 2011-07-25 21:44 (21 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=40072
Subject : suspend/resume problems w/ kernel 3.0 and a *docked* ThinkPad T400, unless iwlagn unloaded
Submitter : Toralf Förster <toralf.foerster-Mmb7MZpHnFY@public.gmane.org>
Date : 2011-07-23 19:27 (23 days old)
Message-ID : <201107232127.34255.toralf.foerster-Mmb7MZpHnFY@public.gmane.org>
References : http://marc.info/?l=linux-kernel&m=131144928023465&w=2
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39972
Subject : [regression] Radeon multi-screen
Submitter : Robert Piasek <dagger-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
Date : 2011-07-25 14:04 (21 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39922
Subject : WIFI becomes EXTREMELY slow ( ath9k ) making the connection unusable
Submitter : Lukasz Olszewski <lcpak-tIkWECEXGi3VItvQsEIGlw@public.gmane.org>
Date : 2011-07-24 09:20 (22 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39912
Subject : WARNING: at drivers/tty/tty_ldisc.c:766 tty_ldisc_reinit+0x7d/0x90()
Submitter : Vegard Nossum <vegard.nossum-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date : 2011-07-19 11:33 (27 days old)
Message-ID : <CAOMGZ=HS2EPkYD=5HfkSPpwPqHB5V3q0vaFmoZ8Hh+pMM9phrQ@mail.gmail.com>
References : http://marc.info/?l=linux-kernel&m=131107522914558&w=2
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39902
Subject : ath: Unable to reset channel (2412 MHz), reset status -5
Submitter : Justin P. Mattock <justinmattock-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date : 2011-07-19 6:13 (27 days old)
Message-ID : <4E252076.1050309-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
References : http://marc.info/?l=linux-kernel&m=131105603428323&w=2
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39832
Subject : HDA ATI HDMI: no sound with 3.0 - 2.6.39.3 works
Submitter : Andreas Steinmetz <ast-sy9/ueDX/ME@public.gmane.org>
Date : 2011-07-23 01:36 (23 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39732
Subject : JBD: Spotted dirty metadata buffer (dev = dm-2, blocknr = 2512725). There's a risk of filesystem corruption in case of system crash.
Submitter : Witold Baryluk <baryluk-W6Hso+/wx31C2Nf1M/Lcnw@public.gmane.org>
Date : 2011-07-22 04:22 (24 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39412
Subject : Win Vista and Win2K8 guests' network breaks down
Submitter : Jay Ren <yongjie.ren-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Date : 2011-07-15 15:31 (31 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39342
Subject : [3.0.0-rc6-git7] possible recursive locking at cache_alloc_refill
Submitter : Tetsuo Handa <penguin-kernel-1yMVhJb1mP/7nzcFbJAaVXf5DAMn2ifp@public.gmane.org>
Date : 2011-07-11 12:37 (35 days old)
Message-ID : <201107112137.FAD00545.SHtLOFOJOMFQFV-JPay3/Yim36HaxMnTkn67Xf5DAMn2ifp@public.gmane.org>
References : http://marc.info/?l=linux-kernel&m=131038788902151&w=2
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39192
Subject : firmware_install fails with parallel make
Submitter : Ambroz Bizjak <ambrop7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date : 2011-07-12 09:35 (34 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39132
Subject : Starting with 3.0.0-rc6, masquerading seems to be broken.
Submitter : David Hill <hilld-HTiBYHdybX7UkGsOFmftXw@public.gmane.org>
Date : 2011-07-10 19:45 (36 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=38922
Subject : Lenovo T420 (Sandy Bridge) Crashes on SD Card gpt partition writing and io errors on insert
Submitter : Peter Vollmer <vollmerpeter-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Date : 2011-07-07 17:33 (39 days old)
First-Bad-Commit: http://git.kernel.org/linus/a3c7778f8153b9e4eceea6738973280b9e63c618
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=38622
Subject : [radeon cayman regresion] artefacts on screen
Submitter : Marek Hobler, 'neutrinus' <kernellist@neutrinus.com>
Date : 2011-07-01 09:35 (45 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=38612
Subject : Boot time warnings in APIC
Submitter : Bill Huey <bill.huey-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date : 2011-07-01 06:44 (45 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=38582
Subject : T510 43495KG won't resume with 32bit installation
Submitter : Marc Koschewski <marc-e1Wt+8K1Ta8ZEwqihLH0+Q@public.gmane.org>
Date : 2011-06-30 22:39 (46 days old)
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=37432
Subject : sdhci-pci fails on 3.0.0-rc1 on Dell E6510
Submitter : Oliver Hartkopp <socketcan-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
Date : 2011-06-07 20:06 (69 days old)
First-Bad-Commit: http://git.kernel.org/linus/da7822e5ad71ec9b745b412639f1e5e0ba795a20
References : http://article.gmane.org/gmane.linux.kernel.mmc/8442
https://lkml.org/lkml/2011/6/23/660
Regressions with patches
------------------------
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=40062
Subject : USB related "unable to handle kernel paging request" in 3.0.0-rc7
Submitter : Tino Keitel <tino.keitel-rAwCM5oiXHA@public.gmane.org>
Date : 2011-07-22 19:27 (24 days old)
Message-ID : <20110722192722.GA9369-dW8JlKMZij8@public.gmane.org>
References : http://marc.info/?l=linux-kernel&m=131136334621623&w=2
Patch : https://lkml.org/lkml/2011/8/2/174
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=39882
Subject : Kernel oops when turning bluetooth mouse on
Submitter : Lamarque V. Souza <lamarque-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date : 2011-07-24 02:09 (22 days old)
Patch : https://bugzilla.kernel.org/attachment.cgi?id=66632
Bug-Entry : http://bugzilla.kernel.org/show_bug.cgi?id=37872
Subject : CPU lockup during boot
Submitter : Bruno Wolff III <bruno-bdMChIhFSYk@public.gmane.org>
Date : 2011-06-19 15:00 (57 days old)
Patch : https://bugzilla.kernel.org/show_bug.cgi?id=37872#c16
For details, please visit the bug entries and follow the links given in
references.
As you can see, there is a Bugzilla entry for each of the listed regressions.
There also is a Bugzilla entry used for tracking the regressions introduced
between 2.6.39 and 3.0, unresolved as well as resolved, at:
http://bugzilla.kernel.org/show_bug.cgi?id=36912
Please let the tracking team know if there are any Bugzilla entries that
should be added to the list in there.
Thanks!
^ permalink raw reply
* Congratulation!!!
From: BBC NATIONAL PROMO @ 2011-08-14 19:36 UTC (permalink / raw)
BBC E-MAIL PROMOTION WINNERS NOTICE,
WINNING NOTIFICATION !!!
BBC NATIONAL LOTTERY PROMO
UK HEAD OFFICE.
SUITES 23-30,LION TOWERS
CENTRAL LONDON
ENGLAND
http://www.bbc.co.uk/lottery/
Your Email Address was selected thereby Winning for you,£1.000,000 (one
million pounds) in the British Broadcasting corporation (BBC) Online Promo
Held on this month of August 2011, and you are to acknowledge the receipt of
this mail with the details below to.
CLAIMS DIRECTOR BBC ONLINE PROMOTION.
1.Full name:
2.Tel:
3.Country :
Sincerely,
Mr. Scott Carson
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
^ permalink raw reply
* Re: [net-next 06/10] xscale: Move the Intel XScale IXP drivers
From: Krzysztof Halasa @ 2011-08-14 20:25 UTC (permalink / raw)
To: Jeff Kirsher; +Cc: davem, netdev, gospo, sassmann, Lennert Buytenhek
In-Reply-To: <1313105998-2859-7-git-send-email-jeffrey.t.kirsher@intel.com>
Jeff Kirsher <jeffrey.t.kirsher@intel.com> writes:
> Move the Intel XScale IXP drivers into drivers/net/ethernet/xscale/
> and make the necessary Kconfig and Makefile changes.
> rename drivers/net/{arm => ethernet/xscale}/ixp4xx_eth.c (100%)
To be honest I don't care if the driver is in the old or new dir.
If this changes anything:
Acked-by: Krzysztof Hałasa <khc@pm.waw.pl>
--
Krzysztof Halasa
^ permalink raw reply
* Congratulation!!!
From: BBC NATIONAL PROMO @ 2011-08-14 19:49 UTC (permalink / raw)
BBC E-MAIL PROMOTION WINNERS NOTICE,
WINNING NOTIFICATION !!!
BBC NATIONAL LOTTERY PROMO
UK HEAD OFFICE.
SUITES 23-30,LION TOWERS
CENTRAL LONDON
ENGLAND
http://www.bbc.co.uk/lottery/
Your Email Address was selected thereby Winning for you,£1.000,000 (one
million pounds) in the British Broadcasting corporation (BBC) Online Promo
Held on this month of August 2011, and you are to acknowledge the receipt of
this mail with the details below to.
CLAIMS DIRECTOR BBC ONLINE PROMOTION.
1.Full name:
2.Tel:
3.Country :
Sincerely,
Mr. Scott Carson
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox