* [PATCH 2/2] virtio_net: Defer skb allocation in receive path Date: Wed, 13 Jan 2010 12:53:38 -0800
From: Rusty Russell @ 2010-01-29 13:20 UTC (permalink / raw)
To: netdev; +Cc: David Miller, virtualization, Shirley Ma, Michael S. Tsirkin
In-Reply-To: <201001292349.05360.rusty@rustcorp.com.au>
From: Shirley Ma <mashirle@us.ibm.com>
virtio_net receives packets from its pre-allocated vring buffers, then it
delivers these packets to upper layer protocols as skb buffs. So it's not
necessary to pre-allocate skb for each mergable buffer, then frees extra
skbs when buffers are merged into a large packet. This patch has deferred
skb allocation in receiving packets for both big packets and mergeable buffers
to reduce skb pre-allocations and skb frees. It frees unused buffers by calling
detach_unused_buf in vring, so recv skb queue is not needed.
Signed-off-by: Shirley Ma <xma@us.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
drivers/net/virtio_net.c | 427 +++++++++++++++++++++++++++--------------------
1 file changed, 248 insertions(+), 179 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index c708ecc..72b3f21 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -56,8 +56,7 @@ struct virtnet_info
/* Host will merge rx buffers for big packets (shake it! shake it!) */
bool mergeable_rx_bufs;
- /* Receive & send queues. */
- struct sk_buff_head recv;
+ /* Send queue. */
struct sk_buff_head send;
/* Work struct for refilling if we run low on memory. */
@@ -75,34 +74,44 @@ struct skb_vnet_hdr {
unsigned int num_sg;
};
+struct padded_vnet_hdr {
+ struct virtio_net_hdr hdr;
+ /*
+ * virtio_net_hdr should be in a separated sg buffer because of a
+ * QEMU bug, and data sg buffer shares same page with this header sg.
+ * This padding makes next sg 16 byte aligned after virtio_net_hdr.
+ */
+ char padding[6];
+};
+
static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb)
{
return (struct skb_vnet_hdr *)skb->cb;
}
-static void give_a_page(struct virtnet_info *vi, struct page *page)
-{
- page->private = (unsigned long)vi->pages;
- vi->pages = page;
-}
-
-static void trim_pages(struct virtnet_info *vi, 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)
{
- unsigned int i;
+ struct page *end;
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- give_a_page(vi, skb_shinfo(skb)->frags[i].page);
- skb_shinfo(skb)->nr_frags = 0;
- skb->data_len = 0;
+ /* 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;
}
static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask)
{
struct page *p = vi->pages;
- if (p)
+ if (p) {
vi->pages = (struct page *)p->private;
- else
+ /* clear private here, it is used to chain pages */
+ p->private = 0;
+ } else
p = alloc_page(gfp_mask);
return p;
}
@@ -118,99 +127,142 @@ static void skb_xmit_done(struct virtqueue *svq)
netif_wake_queue(vi->dev);
}
-static void receive_skb(struct net_device *dev, struct sk_buff *skb,
- unsigned len)
+static void set_skb_frag(struct sk_buff *skb, struct page *page,
+ unsigned int offset, unsigned int *len)
{
- struct virtnet_info *vi = netdev_priv(dev);
- struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
- int err;
- int i;
-
- if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
- pr_debug("%s: short packet %i\n", dev->name, len);
- dev->stats.rx_length_errors++;
- goto drop;
- }
+ int i = skb_shinfo(skb)->nr_frags;
+ skb_frag_t *f;
+
+ f = &skb_shinfo(skb)->frags[i];
+ f->size = min((unsigned)PAGE_SIZE - offset, *len);
+ f->page_offset = offset;
+ f->page = page;
+
+ skb->data_len += f->size;
+ skb->len += f->size;
+ skb_shinfo(skb)->nr_frags++;
+ *len -= f->size;
+}
- if (vi->mergeable_rx_bufs) {
- unsigned int copy;
- char *p = page_address(skb_shinfo(skb)->frags[0].page);
+static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+ struct page *page, unsigned int len)
+{
+ struct sk_buff *skb;
+ struct skb_vnet_hdr *hdr;
+ unsigned int copy, hdr_len, offset;
+ char *p;
- if (len > PAGE_SIZE)
- len = PAGE_SIZE;
- len -= sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ p = page_address(page);
- memcpy(&hdr->mhdr, p, sizeof(hdr->mhdr));
- p += sizeof(hdr->mhdr);
+ /* copy small packet so we can reuse these pages for small data */
+ skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
+ if (unlikely(!skb))
+ return NULL;
- copy = len;
- if (copy > skb_tailroom(skb))
- copy = skb_tailroom(skb);
+ hdr = skb_vnet_hdr(skb);
- memcpy(skb_put(skb, copy), p, copy);
+ if (vi->mergeable_rx_bufs) {
+ hdr_len = sizeof hdr->mhdr;
+ offset = hdr_len;
+ } else {
+ hdr_len = sizeof hdr->hdr;
+ offset = sizeof(struct padded_vnet_hdr);
+ }
- len -= copy;
+ memcpy(hdr, p, hdr_len);
- if (!len) {
- give_a_page(vi, skb_shinfo(skb)->frags[0].page);
- skb_shinfo(skb)->nr_frags--;
- } else {
- skb_shinfo(skb)->frags[0].page_offset +=
- sizeof(hdr->mhdr) + copy;
- skb_shinfo(skb)->frags[0].size = len;
- skb->data_len += len;
- skb->len += len;
- }
+ len -= hdr_len;
+ p += offset;
- while (--hdr->mhdr.num_buffers) {
- struct sk_buff *nskb;
+ copy = len;
+ if (copy > skb_tailroom(skb))
+ copy = skb_tailroom(skb);
+ memcpy(skb_put(skb, copy), p, copy);
- i = skb_shinfo(skb)->nr_frags;
- if (i >= MAX_SKB_FRAGS) {
- pr_debug("%s: packet too long %d\n", dev->name,
- len);
- dev->stats.rx_length_errors++;
- goto drop;
- }
+ len -= copy;
+ offset += copy;
- nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
- if (!nskb) {
- pr_debug("%s: rx error: %d buffers missing\n",
- dev->name, hdr->mhdr.num_buffers);
- dev->stats.rx_length_errors++;
- goto drop;
- }
+ while (len) {
+ set_skb_frag(skb, page, offset, &len);
+ page = (struct page *)page->private;
+ offset = 0;
+ }
- __skb_unlink(nskb, &vi->recv);
- vi->num--;
+ if (page)
+ give_pages(vi, page);
- skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0];
- skb_shinfo(nskb)->nr_frags = 0;
- kfree_skb(nskb);
+ return skb;
+}
- if (len > PAGE_SIZE)
- len = PAGE_SIZE;
+static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
+{
+ struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
+ struct page *page;
+ int num_buf, i, len;
+
+ num_buf = hdr->mhdr.num_buffers;
+ while (--num_buf) {
+ i = skb_shinfo(skb)->nr_frags;
+ if (i >= MAX_SKB_FRAGS) {
+ pr_debug("%s: packet too long\n", skb->dev->name);
+ skb->dev->stats.rx_length_errors++;
+ return -EINVAL;
+ }
- skb_shinfo(skb)->frags[i].size = len;
- skb_shinfo(skb)->nr_frags++;
- skb->data_len += len;
- skb->len += len;
+ page = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
+ if (!page) {
+ pr_debug("%s: rx error: %d buffers missing\n",
+ skb->dev->name, hdr->mhdr.num_buffers);
+ skb->dev->stats.rx_length_errors++;
+ return -EINVAL;
}
- } else {
- len -= sizeof(hdr->hdr);
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+
+ set_skb_frag(skb, page, 0, &len);
+
+ --vi->num;
+ }
+ return 0;
+}
+
+static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct page *page;
+ struct skb_vnet_hdr *hdr;
- if (len <= MAX_PACKET_LEN)
- trim_pages(vi, skb);
+ if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
+ 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);
+ else
+ dev_kfree_skb(buf);
+ return;
+ }
- err = pskb_trim(skb, len);
- if (err) {
- pr_debug("%s: pskb_trim failed %i %d\n", dev->name,
- len, err);
+ if (!vi->mergeable_rx_bufs && !vi->big_packets) {
+ skb = buf;
+ len -= sizeof(struct virtio_net_hdr);
+ skb_trim(skb, len);
+ } else {
+ page = buf;
+ skb = page_to_skb(vi, page, len);
+ if (unlikely(!skb)) {
dev->stats.rx_dropped++;
- goto drop;
+ give_pages(vi, page);
+ return;
}
+ if (vi->mergeable_rx_bufs)
+ if (receive_mergeable(vi, skb)) {
+ dev_kfree_skb(skb);
+ return;
+ }
}
+ hdr = skb_vnet_hdr(skb);
skb->truesize += skb->data_len;
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
@@ -267,110 +319,119 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
frame_err:
dev->stats.rx_frame_errors++;
-drop:
dev_kfree_skb(skb);
}
-static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
+static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
{
struct sk_buff *skb;
- struct scatterlist sg[2+MAX_SKB_FRAGS];
- int num, err, i;
- bool oom = false;
-
- sg_init_table(sg, 2+MAX_SKB_FRAGS);
- do {
- struct skb_vnet_hdr *hdr;
+ struct skb_vnet_hdr *hdr;
+ struct scatterlist sg[2];
+ int err;
- skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
- if (unlikely(!skb)) {
- oom = true;
- break;
- }
+ skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
+ if (unlikely(!skb))
+ return -ENOMEM;
- skb_put(skb, MAX_PACKET_LEN);
+ skb_put(skb, MAX_PACKET_LEN);
- hdr = skb_vnet_hdr(skb);
- sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
+ hdr = skb_vnet_hdr(skb);
+ sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
- if (vi->big_packets) {
- for (i = 0; i < MAX_SKB_FRAGS; i++) {
- skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- f->page = get_a_page(vi, gfp);
- if (!f->page)
- break;
+ skb_to_sgvec(skb, sg + 1, 0, skb->len);
- f->page_offset = 0;
- f->size = PAGE_SIZE;
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 2, skb);
+ if (err < 0)
+ dev_kfree_skb(skb);
- skb->data_len += PAGE_SIZE;
- skb->len += PAGE_SIZE;
+ return err;
+}
- skb_shinfo(skb)->nr_frags++;
- }
+static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
+{
+ struct scatterlist sg[MAX_SKB_FRAGS + 2];
+ struct page *first, *list = NULL;
+ char *p;
+ int i, err, offset;
+
+ /* page in sg[MAX_SKB_FRAGS + 1] is list tail */
+ for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
+ first = get_a_page(vi, gfp);
+ if (!first) {
+ if (list)
+ give_pages(vi, list);
+ return -ENOMEM;
}
+ sg_set_buf(&sg[i], page_address(first), PAGE_SIZE);
- num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- skb_queue_head(&vi->recv, skb);
+ /* chain new page in list head to match sg */
+ first->private = (unsigned long)list;
+ list = first;
+ }
- err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
- if (err < 0) {
- skb_unlink(skb, &vi->recv);
- trim_pages(vi, skb);
- kfree_skb(skb);
- break;
- }
- vi->num++;
- } while (err >= num);
- if (unlikely(vi->num > vi->max))
- vi->max = vi->num;
- vi->rvq->vq_ops->kick(vi->rvq);
- return !oom;
+ first = get_a_page(vi, gfp);
+ if (!first) {
+ give_pages(vi, list);
+ return -ENOMEM;
+ }
+ p = page_address(first);
+
+ /* sg[0], sg[1] share the same page */
+ /* a separated sg[0] for virtio_net_hdr only during to QEMU bug*/
+ sg_set_buf(&sg[0], p, sizeof(struct virtio_net_hdr));
+
+ /* sg[1] for data packet, from offset */
+ offset = sizeof(struct padded_vnet_hdr);
+ sg_set_buf(&sg[1], p + offset, PAGE_SIZE - offset);
+
+ /* chain first in list head */
+ first->private = (unsigned long)list;
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2,
+ first);
+ if (err < 0)
+ give_pages(vi, first);
+
+ return err;
}
-/* Returns false if we couldn't fill entirely (OOM). */
-static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
+static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
{
- struct sk_buff *skb;
- struct scatterlist sg[1];
+ struct page *page;
+ struct scatterlist sg;
int err;
- bool oom = false;
-
- if (!vi->mergeable_rx_bufs)
- return try_fill_recv_maxbufs(vi, gfp);
- do {
- skb_frag_t *f;
+ page = get_a_page(vi, gfp);
+ if (!page)
+ return -ENOMEM;
- skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
- if (unlikely(!skb)) {
- oom = true;
- break;
- }
+ sg_init_one(&sg, page_address(page), PAGE_SIZE);
- f = &skb_shinfo(skb)->frags[0];
- f->page = get_a_page(vi, gfp);
- if (!f->page) {
- oom = true;
- kfree_skb(skb);
- break;
- }
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, &sg, 0, 1, page);
+ if (err < 0)
+ give_pages(vi, page);
- f->page_offset = 0;
- f->size = PAGE_SIZE;
+ return err;
+}
- skb_shinfo(skb)->nr_frags++;
+/* Returns false if we couldn't fill entirely (OOM). */
+static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
+{
+ int err;
+ bool oom = false;
- sg_init_one(sg, page_address(f->page), PAGE_SIZE);
- skb_queue_head(&vi->recv, skb);
+ do {
+ if (vi->mergeable_rx_bufs)
+ err = add_recvbuf_mergeable(vi, gfp);
+ else if (vi->big_packets)
+ err = add_recvbuf_big(vi, gfp);
+ else
+ err = add_recvbuf_small(vi, gfp);
- err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb);
if (err < 0) {
- skb_unlink(skb, &vi->recv);
- kfree_skb(skb);
+ oom = true;
break;
}
- vi->num++;
+ ++vi->num;
} while (err > 0);
if (unlikely(vi->num > vi->max))
vi->max = vi->num;
@@ -408,15 +469,14 @@ static void refill_work(struct work_struct *work)
static int virtnet_poll(struct napi_struct *napi, int budget)
{
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- struct sk_buff *skb = NULL;
+ void *buf;
unsigned int len, received = 0;
again:
while (received < budget &&
- (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
- __skb_unlink(skb, &vi->recv);
- receive_skb(vi->dev, skb, len);
- vi->num--;
+ (buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
+ receive_buf(vi->dev, buf, len);
+ --vi->num;
received++;
}
@@ -496,9 +556,9 @@ 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(sg, &hdr->mhdr, sizeof(hdr->mhdr));
+ sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr);
else
- sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
+ sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
@@ -916,8 +976,7 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->features |= NETIF_F_HW_VLAN_FILTER;
}
- /* Initialize our empty receive and send queues. */
- skb_queue_head_init(&vi->recv);
+ /* Initialize our empty send queue. */
skb_queue_head_init(&vi->send);
err = register_netdev(dev);
@@ -952,25 +1011,35 @@ free:
return err;
}
+static void free_unused_bufs(struct virtnet_info *vi)
+{
+ void *buf;
+ while (1) {
+ buf = vi->rvq->vq_ops->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;
- struct sk_buff *skb;
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
- /* Free our skbs in send and recv queues, if any. */
- while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
- kfree_skb(skb);
- vi->num--;
- }
+ /* Free our skbs in send queue, if any. */
__skb_queue_purge(&vi->send);
- BUG_ON(vi->num != 0);
-
unregister_netdev(vi->dev);
cancel_delayed_work_sync(&vi->refill);
+ free_unused_bufs(vi);
vdev->config->del_vqs(vi->vdev);
^ permalink raw reply related
* [PATCH 1/2] virtio: Add ability to detach unused buffers from vrings
From: Rusty Russell @ 2010-01-29 13:19 UTC (permalink / raw)
To: netdev; +Cc: David Miller, virtualization, Shirley Ma, Michael S. Tsirkin
In-Reply-To: <201001292346.43675.rusty@rustcorp.com.au>
From: Shirley Ma <mashirle@us.ibm.com>
There's currently no way for a virtio driver to ask for unused
buffers, so it has to keep a list itself to reclaim them at shutdown.
This is redundant, since virtio_ring stores that information. So
add a new hook to do this.
Signed-off-by: Shirley Ma <xma@us.ibm.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
drivers/virtio/virtio_ring.c | 25 +++++++++++++++++++++++++
include/linux/virtio.h | 4 ++++
2 files changed, 29 insertions(+)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index fbd2ecd..71929ee 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -334,6 +334,30 @@ static bool vring_enable_cb(struct virtqueue *_vq)
return true;
}
+static void *vring_detach_unused_buf(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ unsigned int i;
+ void *buf;
+
+ START_USE(vq);
+
+ for (i = 0; i < vq->vring.num; i++) {
+ if (!vq->data[i])
+ continue;
+ /* detach_buf clears data, so grab it now. */
+ buf = vq->data[i];
+ detach_buf(vq, i);
+ END_USE(vq);
+ return buf;
+ }
+ /* That should have freed everything. */
+ BUG_ON(vq->num_free != vq->vring.num);
+
+ END_USE(vq);
+ return NULL;
+}
+
irqreturn_t vring_interrupt(int irq, void *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
@@ -360,6 +384,7 @@ static struct virtqueue_ops vring_vq_ops = {
.kick = vring_kick,
.disable_cb = vring_disable_cb,
.enable_cb = vring_enable_cb,
+ .detach_unused_buf = vring_detach_unused_buf,
};
struct virtqueue *vring_new_virtqueue(unsigned int num,
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 057a2e0..f508c65 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -51,6 +51,9 @@ struct virtqueue {
* This re-enables callbacks; it returns "false" if there are pending
* buffers in the queue, to detect a possible race between the driver
* checking for more work, and enabling callbacks.
+ * @detach_unused_buf: detach first unused buffer
+ * vq: the struct virtqueue we're talking about.
+ * Returns NULL or the "data" token handed to add_buf
*
* Locking rules are straightforward: the driver is responsible for
* locking. No two operations may be invoked simultaneously, with the exception
@@ -71,6 +74,7 @@ struct virtqueue_ops {
void (*disable_cb)(struct virtqueue *vq);
bool (*enable_cb)(struct virtqueue *vq);
+ void *(*detach_unused_buf)(struct virtqueue *vq);
};
/**
^ permalink raw reply related
* [PATCH 0/2] virtio net improvements
From: Rusty Russell @ 2010-01-29 13:16 UTC (permalink / raw)
To: netdev, David Miller; +Cc: virtualization, Shirley Ma, Michael S. Tsirkin
Hi Dave,
Nice driver optimization from Shirley, but requires a new virtio hook.
Do you want to take both? I have nothing else overlapping it.
Cheers,
Rusty.
^ permalink raw reply
* NF_STOLEN and reinsert in to IP stack
From: Susant Sahani @ 2010-01-29 12:38 UTC (permalink / raw)
To: netdev
In-Reply-To: <d81115a61001290434x740c7381v6929d6aea1d354dd@mail.gmail.com>
Hi,
How to reinsert a packet into IP stack after using NF_STOLEN. If I
do a nf_reinject it crashes .
Thanks,
Susant
^ permalink raw reply
* Re: CBQ broken in 2.6
From: Anton Ivanov @ 2010-01-29 12:25 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Jarek Poplawski, David Miller, netdev
In-Reply-To: <1264714062.3380.20.camel@edumazet-laptop>
[snip]
> > Thanks for all the help.
>
> I am using CBQ myself with recent kernels and never found it
> 'borrowing', could you post a copy of your rules, or better, a subset of
> them desmonstrating the problem ?
Actually after going through it several times and looking at the code
Jarek pointed out it doesn't.
Just the stats are very confusing and precision is not particularly
great.
It says "borrowed" while actually it is the child which has borrowed
from this class, not the class itself borrowing. The class has been
borrowed from, not it itself borrowed.
As nobody else has complained about the stats they should be probably
left as is according to the "least surprise" principle.
As far as the precision becoming worse over the last 15 or so minor
revision 2.6.9 to 2.6.26 that cannot be helped. On my hardware it was so
bad that I had it confused with not working at all at some point. I
ended up sticking aggressive RED leafs on the biggest "offenders" and
this has gotten my config to a working state for now. I am not happy
with it, but it is better than no QoS at all.
>
>
>
>
--
Understanding is a three-edged sword:
your side, their side, and the truth. --Kosh Naranek
A. R. Ivanov
E-mail: anton.ivanov@kot-begemot.co.uk
WWW: http://www.kot-begemot.co.uk/
^ permalink raw reply
* Re: [PATCH] tcp: fix ICMP-RTO war
From: Damian Lukowski @ 2010-01-29 12:13 UTC (permalink / raw)
To: Denys Fedoryshchenko; +Cc: Ilpo Järvinen, Netdev, David Miller
In-Reply-To: <201001271556.16156.denys@visp.net.lb>
Denys Fedoryshchenko schrieb:
> On Wednesday 27 January 2010 14:36:18 you wrote:
>> Unless they are for a different connection? We might have to print sk (%p)
>> in all those printouts to be sure which maps to which. If a peer becomes
>> unreachable, it may well have multiple connections open (this was a
>> proxy, iirc?).
>>
> Ok i will try to do that today.
>
> Most probably different connections, on this proxy i have 10-15k established
> connections at peak time.
In total, there are probably multiple sockets involved, but for the pattern
I mentioned, I doubt that. The pattern is all over the place; look at another
sample:
> [ 1497.679255] rto: 200 (0 >> 3 + 0, 21) time: 1197679 sent: 1197679 pen: 1 1198079 rem: 200
> [ 1497.679356] rto: 120000 (18111 >> 3 + 2633, 7) time: 1197679 sent: 1195423 pen: 1 1315423 rem: 117744
> [ 1501.113786] rto: 200 (0 >> 3 + 0, 24) time: 1201113 sent: 1200679 pen: 1 1203879 rem: 0
> [ 1501.116064] rto: 120000 (17704 >> 3 + 4426, 8) time: 1201116 sent: 1198638 pen: 1 1318638 rem: 117522
> [ 1501.116216] rto: 200 (0 >> 3 + 0, 24) time: 1201116 sent: 1201113 pen: 1 1201513 rem: 197
> [ 1504.165953] rto: 200 (0 >> 3 + 0, 27) time: 1204165 sent: 1204113 pen: 1 1207313 rem: 148
> [ 1504.168151] rto: 200 (0 >> 3 + 0, 26) time: 1204168 sent: 1204113 pen: 1 1204313 rem: 145
> [ 1504.168327] rto: 200 (0 >> 3 + 0, 25) time: 1204168 sent: 1204113 pen: 1 1204313 rem: 145
> [ 1507.280096] rto: 200 (0 >> 3 + 0, 28) time: 1207280 sent: 1207113 pen: 1 1210313 rem: 33
> [ 1507.280255] rto: 200 (0 >> 3 + 0, 27) time: 1207280 sent: 1207113 pen: 1 1207313 rem: 33
> [ 1510.974574] rto: 200 (0 >> 3 + 0, 30) time: 1210974 sent: 1210113 pen: 1 1213313 rem: 0
> [ 1510.974766] rto: 200 (0 >> 3 + 0, 30) time: 1210974 sent: 1210974 pen: 1 1211374 rem: 200
> [ 1514.436214] rto: 200 (0 >> 3 + 0, 33) time: 1214436 sent: 1213974 pen: 1 1217174 rem: 0
> [ 1514.436378] rto: 200 (0 >> 3 + 0, 33) time: 1214436 sent: 1214436 pen: 1 1214836 rem: 200
> [ 1514.436525] rto: 200 (0 >> 3 + 0, 32) time: 1214436 sent: 1214436 pen: 1 1214636 rem: 200
> [ 1517.516537] rto: 200 (0 >> 3 + 0, 35) time: 1217516 sent: 1217436 pen: 1 1220636 rem: 120
> [ 1517.520724] rto: 200 (0 >> 3 + 0, 34) time: 1217520 sent: 1217436 pen: 1 1217636 rem: 116
> [ 1517.520919] rto: 200 (0 >> 3 + 0, 33) time: 1217520 sent: 1217436 pen: 1 1217636 rem: 116
> [ 1520.580000] rto: 200 (0 >> 3 + 0, 36) time: 1220579 sent: 1220436 pen: 1 1223636 rem: 57
> [ 1520.580165] rto: 200 (0 >> 3 + 0, 35) time: 1220580 sent: 1220436 pen: 1 1220637 rem: 56
> [ 1520.580744] rto: 200 (0 >> 3 + 0, 34) time: 1220580 sent: 1220436 pen: 1 1220636 rem: 56
The two 120000ms RTOs are a different socket, but the rest is one socket,
I believe. There is the sequence (N+2, N+1, N) for backoff, followed by
3 seconds silence, which I assume, are used for regular RTO retransmissions,
and then again a burst of ICMPs.
The three seconds are enough to fire backed-off retransmissions at
t+0.2, t+0.6, t+1.4 and t+3.0. There is a slight deviation of this pattern
when rem becomes 0.
This pattern is too perfect to be triggered by different sockets, I think.
But we will see, when Denys submits new test outputs.
>
> Also about estimating rtt, maybe there is something wrong in idea. Just what
> will happen if ip visible for proxy have multiple people behind? It can be
> small router for hotspot and 10-20 people behind it, some with very large
> rtt, some with very small.
>
> And some of them getting disconnected (out of range from wireless, for
> example), and thats most probably why host unreachable sent... at same time
> proxy have established and running tcp connections with other people on same
> router (means for proxy same ip).
Sockets are identified on a (src-ip, src-port)::(dst-ip, dst-port) quadruple basis,
so RTT calculation usually is independent even for same ip-pairs, unless
with TCB interdependence. But I don't know if that is implemented and/or enabled
by default.
Regards
Damian
> Sorry, again to Ilpo Järvinen, by default i have reply, instead of reply all.
^ permalink raw reply
* Re: [RFC] [PATCH] Optimize TCP sendmsg in favour of fast devices?
From: Krishna Kumar2 @ 2010-01-29 11:50 UTC (permalink / raw)
To: Herbert Xu; +Cc: David Miller, eric.dumazet, ilpo.jarvinen, netdev
In-Reply-To: <20100129113346.GB1309@gondor.apana.org.au>
Herbert Xu <herbert@gondor.apana.org.au> wrote on 01/29/2010 05:03:46 PM:
>
> > Same 5 runs of single netperf's:
> >
> > 0. Driver unsets F_SG but sets F_GSO:
> > Org (16K): BW: 18180.71 SD: 13.485
> > New (16K): BW: 18113.15 SD: 13.551
> > Org (64K): BW: 21980.28 SD: 10.306
> > New (64K): BW: 21386.59 SD: 10.447
> >
> > 1. Driver unsets F_SG, and with GSO off
> > Org (16K): BW: 10894.62 SD: 26.591
> > New (16K): BW: 7262.10 SD: 35.340
> > Org (64K): BW: 12396.41 SD: 23.357
> > New (64K): BW: 7853.02 SD: 32.405
> >
> >
> > 2. Driver unsets F_SG and uses ethtool to set GSO:
> > Org (16K): BW: 18094.11 SD: 13.603
> > New (16K): BW: 17952.38 SD: 13.743
> > Org (64K): BW: 21540.78 SD: 10.771
> > New (64K): BW: 21818.35 SD: 10.598
>
> Hmm, any idea what is causing case 0 to be different from case 2?
> In particular, the 64K performance in case 0 appears to be a
> regression but in case 2 it's showing up as an improvement.
>
> AFAICS these two cases should produce identical results, or is
> this just jitter across tests?
You are right about the jitter. I have run this many times, most
of the times #0 and #2 are almost identical, but sometimes varies
a bit.
Also about my earlier ethtool comment:
> Yes, an ethtool bug (version 6). The test case #1 above, I
> have written that GSO is off but ethtool "thinks" it is on
> (after a modprobe -r cxgb3; modprobe cxgb3). So for test #2,
> I simply run "ethtool ... gso on", and GSO is now really on
> in the kernel, explaining the better results.
Hmmm, I had a bad ethtool it seems. I built the latest one to
debug this problem but this shows settings correctly.
thanks,
- KK
^ permalink raw reply
* Re: [RFC] [PATCH] Optimize TCP sendmsg in favour of fast devices?
From: Herbert Xu @ 2010-01-29 11:33 UTC (permalink / raw)
To: Krishna Kumar2; +Cc: David Miller, eric.dumazet, ilpo.jarvinen, netdev
In-Reply-To: <OFA813CB35.7FC6144E-ON652576BA.003C3B2C-652576BA.003CB215@in.ibm.com>
On Fri, Jan 29, 2010 at 04:45:01PM +0530, Krishna Kumar2 wrote:
>
> Same 5 runs of single netperf's:
>
> 0. Driver unsets F_SG but sets F_GSO:
> Org (16K): BW: 18180.71 SD: 13.485
> New (16K): BW: 18113.15 SD: 13.551
> Org (64K): BW: 21980.28 SD: 10.306
> New (64K): BW: 21386.59 SD: 10.447
>
> 1. Driver unsets F_SG, and with GSO off
> Org (16K): BW: 10894.62 SD: 26.591
> New (16K): BW: 7262.10 SD: 35.340
> Org (64K): BW: 12396.41 SD: 23.357
> New (64K): BW: 7853.02 SD: 32.405
>
>
> 2. Driver unsets F_SG and uses ethtool to set GSO:
> Org (16K): BW: 18094.11 SD: 13.603
> New (16K): BW: 17952.38 SD: 13.743
> Org (64K): BW: 21540.78 SD: 10.771
> New (64K): BW: 21818.35 SD: 10.598
Hmm, any idea what is causing case 0 to be different from case 2?
In particular, the 64K performance in case 0 appears to be a
regression but in case 2 it's showing up as an improvement.
AFAICS these two cases should produce identical results, or is
this just jitter across tests?
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 3/3] net: macvtap driver
From: Michael S. Tsirkin @ 2010-01-29 11:21 UTC (permalink / raw)
To: Arnd Bergmann
Cc: David Miller, Stephen Hemminger, Patrick McHardy, Herbert Xu,
Or Gerlitz, netdev, bridge, linux-kernel
In-Reply-To: <201001282118.09164.arnd@arndb.de>
On Thu, Jan 28, 2010 at 09:18:08PM +0100, Arnd Bergmann wrote:
> On Thursday 28 January 2010, Michael S. Tsirkin wrote:
> > On Wed, Jan 27, 2010 at 10:09:27PM +0100, Arnd Bergmann wrote:
> > > +static inline struct macvtap_queue *macvtap_file_get_queue(struct file *file)
> > > +{
> > > + rcu_read_lock_bh();
> > > + return rcu_dereference(file->private_data);
> > > +}
> > > +
> > > +static inline void macvtap_file_put_queue(void)
> > > +{
> > > + rcu_read_unlock_bh();
> > > +}
> > > +
> >
> > I find such wrappers around rcu obscure this,
> > already sufficiently complex, pattern.
> > Might be just me.
>
> Obviously I find them useful here, but if more people feel the
> same as you, I'll just open-code them.
>
> > > +static int macvtap_open(struct inode *inode, struct file *file)
> > > +{
> > > + struct net *net = current->nsproxy->net_ns;
> > > + struct net_device *dev = dev_get_by_index(net, iminor(inode));
> > > + struct macvtap_queue *q;
> > > + int err;
> > > +
> >
> > This seems to keep reference to device as long as character device is
> > open, which, if I understand correctly, will start printing error
> > messages to kernel log about once a second if you try to remove the
> > device.
> >
> > I suspect the best way to fix this issue would be to use some kind
> > of notifier so that macvtap can disconnect on device removal.
>
> I think I'm just missing the put in the open function, the code
> already handles the netif and the file disappearing independently.
>
> Thanks for spotting this one, I'll fix that in the next post.
>
> > > + skb_reserve(skb, NET_IP_ALIGN);
> > > + skb_put(skb, count);
> > > +
> > > + if (skb_copy_datagram_from_iovec(skb, 0, iv, 0, len)) {
> > > + macvlan_count_rx(q->vlan, 0, false, false);
> > > + kfree_skb(skb);
> > > + return -EFAULT;
> > > + }
> > > +
> > > + skb_set_network_header(skb, ETH_HLEN);
> > > +
> > > + macvlan_start_xmit(skb, q->vlan->dev);
> > > +
> > > + return count;
> > > +}
> > > +
> >
> > I am surprised there's no GSO support. Would it be a good idea to share
> > code with tun driver? That already has GSO ...
>
> The driver still only does the minimum feature set to get things going.
> GSO is an obvious extension, but I wanted the code to be as simple
> as possible to find all the basic bugs before we do anything fancy.
>
> > Also, network header pointer seems off for vlan packets?
>
> That may well be, I haven't tried vlan. What do you think it should do
> then?
Look at eth_type for a more complete packet parsing.
> > > +/*
> > > + * provide compatibility with generic tun/tap interface
> > > + */
> > > +static long macvtap_ioctl(struct file *file, unsigned int cmd,
> > > + unsigned long arg)
> > > +{
> >
> > All of these seem to be stubs, and tun has many more that you didn't
> > stub out. So, why do you bother to support any ioctls at all?
>
> Again, minimum features to get things going. qemu fails to open
> the device if these ioctls are not implemented, but any of the
> more advanced features are left out.
This is strange, could be application bug. E.g. send buf size is
relatively new and apps should handle failure gracefully. IMO,
returning success and ignoring the value is not a good idea. How about
we just fix qemu? What about other apps?
> Thansk for the review,
>
> Arnd
^ permalink raw reply
* Re: [RFC] [PATCH] Optimize TCP sendmsg in favour of fast devices?
From: Krishna Kumar2 @ 2010-01-29 11:15 UTC (permalink / raw)
To: Herbert Xu; +Cc: David Miller, eric.dumazet, ilpo.jarvinen, netdev
In-Reply-To: <20100129090625.GD23140@gondor.apana.org.au>
> Herbert Xu <herbert@gondor.apana.org.au> wrote on 01/29/2010 02:36:25 PM:
>
> > I ran 5 serial netperf's with 16K and another 5 serial netperfs
> > with 64K I/O sizes, and the aggregate result is:
> >
> > 0. Driver unsets F_SG but sets F_GSO:
> > Original code with 16K: 19471.65
> > New code with 16K: 19409.70
> > Original code with 64K: 21357.23
> > New code with 64K: 22050.42
>
> OK this is more in line with what I was expecting, namely that
> enabling GSO is actually beneficial even without SG.
>
> It would be good to get the CPU utilisation figures so we can
> see the complete picture.
Same 5 runs of single netperf's:
0. Driver unsets F_SG but sets F_GSO:
Org (16K): BW: 18180.71 SD: 13.485
New (16K): BW: 18113.15 SD: 13.551
Org (64K): BW: 21980.28 SD: 10.306
New (64K): BW: 21386.59 SD: 10.447
1. Driver unsets F_SG, and with GSO off
Org (16K): BW: 10894.62 SD: 26.591
New (16K): BW: 7262.10 SD: 35.340
Org (64K): BW: 12396.41 SD: 23.357
New (64K): BW: 7853.02 SD: 32.405
2. Driver unsets F_SG and uses ethtool to set GSO:
Org (16K): BW: 18094.11 SD: 13.603
New (16K): BW: 17952.38 SD: 13.743
Org (64K): BW: 21540.78 SD: 10.771
New (64K): BW: 21818.35 SD: 10.598
> > I should have mentioned this too - if I unset F_SG in the
> > cxgb3 driver and nothing else, ethtool -k still shows GSO
> > is set, and tcpdump shows max packet size is 1448. If I
> > additionally set GSO in driver, then ethtool still has the
> > same output, but tcpdump shows max packet size of 65160.
>
> This sounds like a bug.
Yes, an ethtool bug (version 6). The test case #1 above, I
have written that GSO is off but ethtool "thinks" it is on
(after a modprobe -r cxgb3; modprobe cxgb3). So for test #2,
I simply run "ethtool ... gso on", and GSO is now really on
in the kernel, explaining the better results.
thanks,
- KK
^ permalink raw reply
* Re: PROBLEM: reproducible crash KVM+nf_conntrack all recent 2.6 kernels
From: Jon Masters @ 2010-01-29 10:57 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Patrick McHardy, linux-kernel, netdev, netfilter-devel
In-Reply-To: <1264756232.3184.10.camel@edumazet-laptop>
On Fri, 2010-01-29 at 10:10 +0100, Eric Dumazet wrote:
> Jon, do you have multiple network namespace active on your machine, when
> crash occurs ?
I don't believe so. I just built in Jason's latest kgdb/kdb patches and
am going to give them a whirl to see if I can get anything more out of
this panic than I currently have.
Jon.
^ permalink raw reply
* Re: [2.6.33-rc5] kernel BUG at include/net/netns/generic.h:41!
From: Alexey Dobriyan @ 2010-01-29 10:17 UTC (permalink / raw)
To: Luca Tettamanti; +Cc: linux-kernel, netdev, Eric Dumazet
In-Reply-To: <20100129094822.GA8294@nb-core2.darkstar.lan>
On Fri, Jan 29, 2010 at 11:48 AM, Luca Tettamanti <kronos.it@gmail.com> wrote:
> with recent kernels I'm seeing this BUG - triggered by racoon - at boot:
>
> NET: Registered protocol family 15
> ------------[ cut here ]------------
> kernel BUG at /home/kronos/src/linux-2.6.git/include/net/netns/generic.h:43!
> invalid opcode: 0000 [#1] PREEMPT SMP
> last sysfs file: /sys/kernel/uevent_seqnum
> CPU 1
> Pid: 1941, comm: racoon Not tainted 2.6.33-rc5-00271-gbe8cde8-dirty #238 F3Sa /F3Sa
> RIP: 0010:[<ffffffffa03035be>] [<ffffffffa03035be>] pfkey_create+0x36/0x18b [af_key]
Does it triggers after succesfull boot if you do
rmmod af_key; modprobe af_key
a couple of times?
Post .config, just in case.
^ permalink raw reply
* Re: [PATCH 1/3] net: maintain namespace isolation between vlan and real device
From: Arnd Bergmann @ 2010-01-29 10:12 UTC (permalink / raw)
To: David Miller
Cc: shemminger, kaber, mst, herbert, ogerlitz, netdev, bridge,
linux-kernel
In-Reply-To: <20100128.213344.226776729.davem@davemloft.net>
On Friday 29 January 2010, David Miller wrote:
> From: Arnd Bergmann <arnd@arndb.de>
> Date: Wed, 27 Jan 2010 11:05:15 +0100
>
> > + * skb_dev_set -- assign a buffer to a new device
>
> My english is terrible, but I think this should be
> "assign a new device to a buffer".
Right, that seems clearer.
> If you agree, please fix this up when you resubmit patches #1 and #2
> along with the fix you already plan to make to patch #3.
Ok, will do.
Thanks,
Arnd
^ permalink raw reply
* IPV6_DONTFRAG sockopt etc.
From: Pekka Savola @ 2010-01-29 9:44 UTC (permalink / raw)
To: netdev
Hello,
There appear to be a couple of sockopts in RFC3542 that aren't
implemented yet (they're #if 0'd in the code)
#define IPV6_RECVPATHMTU 60
#define IPV6_PATHMTU 61
#define IPV6_DONTFRAG 62
#define IPV6_USE_MIN_MTU 63
In one particular app, I would have found IPV6_DONTFRAG useful.
--
Pekka Savola "You each name yourselves king, yet the
Netcore Oy kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings
^ permalink raw reply
* Re: [PATCH net-next-2.6] can: add support for CAN interface cards based on the PLX90xx PCI bridge
From: Daniel Baluta @ 2010-01-29 9:55 UTC (permalink / raw)
To: Pavel B. Cheblakov
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1264758309-1632-1-git-send-email-chebl-LmX6Lu7C9G7nhuLbLO4Grw@public.gmane.org>
On Fri, Jan 29, 2010 at 11:45 AM, Pavel B. Cheblakov
<P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org> wrote:
> From: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
>
> This driver is for CAN interface cards based on the PLX90xx PCI bridge.
> Driver supports now:
> - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
> - Adlink PCI-7841/cPCI-7841 SE card
> - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
> - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
>
> Signed-off-by: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
> ---
> drivers/net/can/sja1000/Kconfig | 12 +
> drivers/net/can/sja1000/Makefile | 1 +
> drivers/net/can/sja1000/plx_pci.c | 457 +++++++++++++++++++++++++++++++++++++
> 3 files changed, 470 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/sja1000/plx_pci.c
>
> diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
> index 4c67492..9e277d6 100644
> --- a/drivers/net/can/sja1000/Kconfig
> +++ b/drivers/net/can/sja1000/Kconfig
> @@ -44,4 +44,16 @@ config CAN_KVASER_PCI
> This driver is for the the PCIcanx and PCIcan cards (1, 2 or
> 4 channel) from Kvaser (http://www.kvaser.com).
>
> +config CAN_PLX_PCI
> + tristate "PLX90xx PCI-bridge based Cards"
> + depends on PCI
> + ---help---
> + This driver is for CAN interface cards based on
> + the PLX90xx PCI bridge.
> + Driver supports now:
> + - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
> + - Adlink PCI-7841/cPCI-7841 SE card
> + - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
> + - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
> +
> endif
> diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
> index 9d245ac..ce92455 100644
> --- a/drivers/net/can/sja1000/Makefile
> +++ b/drivers/net/can/sja1000/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
> obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
> obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
> obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
> +obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
>
> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
> new file mode 100644
> index 0000000..4b7a697
> --- /dev/null
> +++ b/drivers/net/can/sja1000/plx_pci.c
> @@ -0,0 +1,457 @@
> +/*
> + * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
> + *
> + * Derived from the ems_pci.c driver:
> + * Copyright (C) 2007 Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
> + * Copyright (C) 2008 Markus Plessing <plessing-zsNKPWJ8Pib6hrUXjxyGrA@public.gmane.org>
> + * Copyright (C) 2008 Sebastian Haas <haas-zsNKPWJ8Pib6hrUXjxyGrA@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the version 2 of the GNU General Public License
> + * as published by the Free Software Foundation
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/netdevice.h>
> +#include <linux/delay.h>
> +#include <linux/pci.h>
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/io.h>
> +
> +#include "sja1000.h"
> +
> +#define DRV_NAME "sja1000_plx_pci"
> +
> +MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>");
> +MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
> + "the SJA1000 chips");
> +MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
> + "Adlink PCI-7841/cPCI-7841 SE, "
> + "Marathon CAN-bus-PCI, "
> + "TEWS TECHNOLOGIES TPMC810");
> +MODULE_LICENSE("GPL v2");
> +
> +#define PLX_PCI_MAX_CHAN 2
> +
> +struct plx_pci_card {
> + int channels; /* detected channels count */
> + struct net_device *net_dev[PLX_PCI_MAX_CHAN];
> + void __iomem *conf_addr;
> +};
> +
> +#define PLX_PCI_CAN_CLOCK (16000000 / 2)
> +
> +/* PLX90xx registers */
> +#define PLX_INTCSR 0x4c /* Interrup Control/Status */
Small type: Interrup -> Interrupt
> +#define PLX_CNTRL 0x50 /* User I/O, Direct Slave Response,
> + * Serial EEPROM, and Initialization
> + * Control register
> + */
> +
> +#define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */
> +#define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */
> +#define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */
> +#define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */
> +
> +/*
> + * The board configuration is probably following:
> + * RX1 is connected to ground.
> + * TX1 is not connected.
> + * CLKO is not connected.
> + * Setting the OCR register to 0xDA is a good idea.
> + * This means normal output mode, push-pull and the correct polarity.
> + */
> +#define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
> +
> +/*
> + * In the CDR register, you should set CBP to 1.
> + * You will probably also want to set the clock divider value to 7
> + * (meaning direct oscillator output) because the second SJA1000 chip
> + * is driven by the first one CLKOUT output.
> + */
> +#define PLX_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
> +
> +#define ADLINK_PCI_VENDOR_ID 0x144A
> +#define ADLINK_PCI_DEVICE_ID 0x7841
> +
> +#define MARATHON_PCI_DEVICE_ID 0x2715
> +
> +#define TEWS_PCI_VENDOR_ID 0x1498
> +#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A
> +
> +static void plx_pci_reset_common(struct pci_dev *pdev);
> +static void plx_pci_reset_marathon(struct pci_dev *pdev);
> +
> +struct plx_pci_channel_map {
> + u32 bar;
> + u32 offset;
> + u32 size; /* 0x00 - auto, e.g. length of entire bar */
> +};
> +
> +struct plx_pci_card_info {
> + const char *name;
> + int channel_count;
> + u32 can_clock;
> + u8 ocr; /* output control register */
> + u8 cdr; /* clock divider register */
> +
> + /* Parameters for mapping local configuration space */
> + struct plx_pci_channel_map conf_map;
> +
> + /* Parameters for mapping the SJA1000 chips */
> + struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
> +
> + /* Pointer to device-dependent reset function */
> + void (*reset_func)(struct pci_dev *pdev);
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
> + "Adlink PCI-7841/cPCI-7841", 2,
> + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> + {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
> + &plx_pci_reset_common
> + /* based on PLX9052 */
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
> + "Adlink PCI-7841/cPCI-7841 SE", 2,
> + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> + {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
> + &plx_pci_reset_common
> + /* based on PLX9052 */
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
> + "Marathon CAN-bus-PCI", 2,
> + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> + {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
> + &plx_pci_reset_marathon
> + /* based on PLX9052 */
> +};
> +
> +static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
> + "TEWS TECHNOLOGIES TPMC810", 2,
> + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
> + {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
> + &plx_pci_reset_common
> + /* based on PLX9030 */
> +};
> +
> +static struct pci_device_id plx_pci_tbl[] = {
> + {
> + /* Adlink PCI-7841/cPCI-7841 */
> + ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
> + PCI_ANY_ID, PCI_ANY_ID,
> + PCI_CLASS_NETWORK_OTHER << 8, ~0,
> + (kernel_ulong_t)&plx_pci_card_info_adlink
> + },
> + {
> + /* Adlink PCI-7841/cPCI-7841 SE */
> + ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
> + PCI_ANY_ID, PCI_ANY_ID,
> + PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
> + (kernel_ulong_t)&plx_pci_card_info_adlink_se
> + },
> + {
> + /* Marathon CAN-bus-PCI card */
> + PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
> + PCI_ANY_ID, PCI_ANY_ID,
> + 0, 0,
> + (kernel_ulong_t)&plx_pci_card_info_marathon
> + },
> + {
> + /* TEWS TECHNOLOGIES TPMC810 card */
> + TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
> + PCI_ANY_ID, PCI_ANY_ID,
> + 0, 0,
> + (kernel_ulong_t)&plx_pci_card_info_tews
> + },
> + { 0,}
> +};
> +MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
> +
> +static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
> +{
> + return ioread8(priv->reg_base + port);
> +}
> +
> +static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
> +{
> + iowrite8(val, priv->reg_base + port);
> +}
> +
> +/*
> + * Check if a CAN controller is present at the specified location
> + * by trying to switch 'em from the Basic mode into the PeliCAN mode.
> + * Also check states of some registers in reset mode.
> + */
> +static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
> +{
> + int flag = 0;
> +
> + /*
> + * Check registers after hardware reset (the Basic mode)
> + * See states on p. 10 of the Datasheet.
> + */
> + if ((priv->read_reg(priv, REG_MOD) & 0xa1) == 0x21 &&
> + (priv->read_reg(priv, REG_SR) == 0x0c) &&
> + (priv->read_reg(priv, REG_IR) == 0xe0))
> + flag = 1;
> +
> + /* Bring the SJA1000 into the PeliCAN mode*/
> + priv->write_reg(priv, REG_CDR, CDR_PELICAN);
> +
> + /*
> + * Check registers after reset in the PeliCAN mode.
> + * See states on p. 23 of the Datasheet.
> + */
> + if ((priv->read_reg(priv, REG_MOD) & 0xf1) == 0x01 &&
> + (priv->read_reg(priv, REG_SR) & 0x37) == 0x34 &&
> + (priv->read_reg(priv, REG_IR) & 0xfb) == 0x00)
> + return flag;
> +
> + return 0;
Perhaps some defines here will increase readability ?
> +}
> +
> +/*
> + * PLX90xx software reset
> + * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
> + * For most cards it's enough for reset the SJA1000 chips.
> + */
> +static void plx_pci_reset_common(struct pci_dev *pdev)
> +{
> + struct plx_pci_card *card = pci_get_drvdata(pdev);
> + u32 cntrl;
> +
> + cntrl = ioread32(card->conf_addr + PLX_CNTRL);
> + cntrl |= PLX_PCI_RESET;
> + iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
> + udelay(100);
> + cntrl ^= PLX_PCI_RESET;
> + iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
> +};
> +
> +/* Special reset function for Marathon card */
> +static void plx_pci_reset_marathon(struct pci_dev *pdev)
> +{
> + void __iomem *reset_addr;
> + int i;
> + int reset_bar[2] = {3, 5};
> +
> + plx_pci_reset_common(pdev);
> +
> + for (i = 0; i < 2; i++) {
> + reset_addr = pci_iomap(pdev, reset_bar[i], 0);
> + if (!reset_addr) {
> + dev_err(&pdev->dev, "Failed to remap reset "
> + "space %d (BAR%d)\n", i, reset_bar[i]);
> + } else {
> + /* reset the SJA1000 chip */
> + iowrite8(0x1, reset_addr);
> + udelay(100);
> + pci_iounmap(pdev, reset_addr);
> + }
> + }
> +}
> +
> +static void plx_pci_del_card(struct pci_dev *pdev)
> +{
> + struct plx_pci_card *card = pci_get_drvdata(pdev);
> + struct net_device *dev;
> + struct sja1000_priv *priv;
> + int i = 0;
> +
> + for (i = 0; i < card->channels; i++) {
> + dev = card->net_dev[i];
> + if (!dev)
> + continue;
> +
> + dev_info(&pdev->dev, "Removing %s\n", dev->name);
> + unregister_sja1000dev(dev);
> + priv = netdev_priv(dev);
> + if (priv->reg_base)
> + pci_iounmap(pdev, priv->reg_base);
> + free_sja1000dev(dev);
> + }
> +
> + plx_pci_reset_common(pdev);
> +
> + /*
> + * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
> + * Local_2 interrupts
> + */
> + iowrite32(0x0, card->conf_addr + PLX_INTCSR);
> +
> + if (card->conf_addr)
> + pci_iounmap(pdev, card->conf_addr);
> +
> + kfree(card);
> +
> + pci_disable_device(pdev);
> + pci_set_drvdata(pdev, NULL);
> +}
> +
> +/*
> + * Probe PLX90xx based device for the SJA1000 chips and register each
> + * available CAN channel to SJA1000 Socket-CAN subsystem.
> + */
> +static int __devinit plx_pci_add_card(struct pci_dev *pdev,
> + const struct pci_device_id *ent)
> +{
> + struct sja1000_priv *priv;
> + struct net_device *dev;
> + struct plx_pci_card *card;
> + struct plx_pci_card_info *ci;
> + int err, i;
> + u32 val;
> + void __iomem *addr;
> +
> + ci = (struct plx_pci_card_info *)ent->driver_data;
> +
> + if (pci_enable_device(pdev) < 0) {
> + dev_err(&pdev->dev, "Failed to enable PCI device\n");
> + return -ENODEV;
> + }
> +
> + dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
> + ci->name, PCI_SLOT(pdev->devfn));
> +
> + /* Allocate card structures to hold addresses, ... */
> + card = kzalloc(sizeof(*card), GFP_KERNEL);
> + if (!card) {
> + dev_err(&pdev->dev, "Unable to allocate memory\n");
> + pci_disable_device(pdev);
> + return -ENOMEM;
> + }
> +
> + pci_set_drvdata(pdev, card);
> +
> + card->channels = 0;
> +
> + /* Remap PLX90xx configuration space */
> + addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
> + if (!addr) {
> + err = -ENOMEM;
> + dev_err(&pdev->dev, "Failed to remap configuration space "
> + "(BAR%d)\n", ci->conf_map.bar);
> + goto failure_cleanup;
> + }
> + card->conf_addr = addr + ci->conf_map.offset;
> +
> + ci->reset_func(pdev);
> +
> + /* Detect available channels */
> + for (i = 0; i < ci->channel_count; i++) {
> + struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
> +
> + dev = alloc_sja1000dev(0);
> + if (!dev) {
> + err = -ENOMEM;
> + goto failure_cleanup;
> + }
> +
> + card->net_dev[i] = dev;
> + priv = netdev_priv(dev);
> + priv->priv = card;
> + priv->irq_flags = IRQF_SHARED;
> +
> + dev->irq = pdev->irq;
> +
> + /*
> + * Remap IO space of the SJA1000 chips
> + * This is device-dependent mapping
> + */
> + addr = pci_iomap(pdev, cm->bar, cm->size);
> + if (!addr) {
> + err = -ENOMEM;
> + dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
> + goto failure_cleanup;
> + }
> +
> + priv->reg_base = addr + cm->offset;
> + priv->read_reg = plx_pci_read_reg;
> + priv->write_reg = plx_pci_write_reg;
> +
> + /* Check if channel is present */
> + if (plx_pci_check_sja1000(priv)) {
> + priv->can.clock.freq = ci->can_clock;
> + priv->ocr = ci->ocr;
> + priv->cdr = ci->cdr;
> +
> + SET_NETDEV_DEV(dev, &pdev->dev);
> +
> + /* Register SJA1000 device */
> + err = register_sja1000dev(dev);
> + if (err) {
> + dev_err(&pdev->dev, "Registering device failed "
> + "(err=%d)\n", err);
> + free_sja1000dev(dev);
> + goto failure_cleanup;
> + }
> +
> + card->channels++;
> +
> + dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
> + "registered as %s\n", i + 1, priv->reg_base,
> + dev->irq, dev->name);
> + } else {
> + dev_err(&pdev->dev, "Channel #%d not detected\n",
> + i + 1);
> + free_sja1000dev(dev);
> + }
> + }
> +
> + if (!card->channels) {
> + err = -ENODEV;
> + goto failure_cleanup;
> + }
> +
> + /*
> + * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
> + * Local_2 interrupts from the SJA1000 chips
> + */
> + val = ioread32(card->conf_addr + PLX_INTCSR);
> + val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
> + iowrite32(val, card->conf_addr + PLX_INTCSR);
> +
> + return 0;
> +
> +failure_cleanup:
> + dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
> +
> + plx_pci_del_card(pdev);
> +
> + return err;
> +}
> +
> +static struct pci_driver plx_pci_driver = {
> + .name = DRV_NAME,
> + .id_table = plx_pci_tbl,
> + .probe = plx_pci_add_card,
> + .remove = plx_pci_del_card,
> +};
> +
> +static int __init plx_pci_init(void)
> +{
> + return pci_register_driver(&plx_pci_driver);
> +}
> +
> +static void __exit plx_pci_exit(void)
> +{
> + pci_unregister_driver(&plx_pci_driver);
> +}
> +
> +module_init(plx_pci_init);
> +module_exit(plx_pci_exit);
> --
> 1.6.0.6
>
> _______________________________________________
> Socketcan-core mailing list
> Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
> https://lists.berlios.de/mailman/listinfo/socketcan-core
>
^ permalink raw reply
* [2.6.33-rc5] kernel BUG at include/net/netns/generic.h:41!
From: Luca Tettamanti @ 2010-01-29 9:48 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, Eric Dumazet
Hello,
with recent kernels I'm seeing this BUG - triggered by racoon - at boot:
NET: Registered protocol family 15
------------[ cut here ]------------
kernel BUG at /home/kronos/src/linux-2.6.git/include/net/netns/generic.h:43!
invalid opcode: 0000 [#1] PREEMPT SMP
last sysfs file: /sys/kernel/uevent_seqnum
CPU 1
Pid: 1941, comm: racoon Not tainted 2.6.33-rc5-00271-gbe8cde8-dirty #238 F3Sa /F3Sa
RIP: 0010:[<ffffffffa03035be>] [<ffffffffa03035be>] pfkey_create+0x36/0x18b [af_key]
RSP: 0018:ffff88013ddebe98 EFLAGS: 00010246
RAX: ffff88013f894480 RBX: ffff88013f44de40 RCX: 0000000000000000
RDX: 0000000000000002 RSI: ffff88013f44de40 RDI: 0000000000000001
RBP: ffff88013ddebeb8 R08: ffff88013ddea000 R09: dead000000200200
R10: dead000000100100 R11: ffff88013ddebd80 R12: 0000000000000000
R13: ffffffff81771860 R14: 0000000000000002 R15: 0000000000000000
FS: 00007f02c3e1f710(0000) GS:ffff880028300000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000794f38 CR3: 000000013d98d000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process racoon (pid: 1941, threadinfo ffff88013ddea000, task ffff88013dffd880)
Stack:
000000000000000f ffff88013f44de40 0000000000000003 ffffffffa0304a80
<0> ffff88013ddebf28 ffffffff81220802 ffff88013ddebee8 00007f02c3a22e80
<0> ffffffff00000001 ffff88013ddebf60 ffffffff81771860 0000000200000001
Call Trace:
[<ffffffff81220802>] __sock_create+0x242/0x3dd
[<ffffffff812209e9>] sock_create+0x2b/0x2d
[<ffffffff81220b91>] sys_socket+0x26/0x57
[<ffffffff8129fe0f>] ? page_fault+0x1f/0x30
[<ffffffff81002a2b>] system_call_fastpath+0x16/0x1b
Code: 49 89 fd 41 54 bf 01 00 00 00 53 44 8b 25 27 19 00 00 48 89 f3 e8 4f f1 f9 e0 49 8b 85 48 08 00 00 45 85 e4 74 05 44 3b 20 76 04 <0f> 0b eb fe 4d 63 e4 4e 8b 64 e0 10 bf 01 00 00 00 e8 aa f0 f9
RIP [<ffffffffa03035be>] pfkey_create+0x36/0x18b [af_key]
RSP <ffff88013ddebe98>
---[ end trace 78cabe73779ec9df ]---
note: racoon[1941] exited with preempt_count 1
It looks like a bug I reported a while ago[1] and which was fixed by Eric. The
fix is still in place, but the bug has resurfaced recently, probably in .33.
It's quiet elusive, i.e. it happens maybe once every 5 boots; restarting racoon
doesn't seem to trigger it...
Luca
[1] http://bugzilla.kernel.org/show_bug.cgi?id=13838
^ permalink raw reply
* [PATCH net-next-2.6] can: add support for CAN interface cards based on the PLX90xx PCI bridge
From: Pavel B. Cheblakov @ 2010-01-29 9:45 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w
From: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
This driver is for CAN interface cards based on the PLX90xx PCI bridge.
Driver supports now:
- Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
- Adlink PCI-7841/cPCI-7841 SE card
- Marathon CAN-bus-PCI card (http://www.marathon.ru/)
- TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
Signed-off-by: Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
---
drivers/net/can/sja1000/Kconfig | 12 +
drivers/net/can/sja1000/Makefile | 1 +
drivers/net/can/sja1000/plx_pci.c | 457 +++++++++++++++++++++++++++++++++++++
3 files changed, 470 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/sja1000/plx_pci.c
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 4c67492..9e277d6 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -44,4 +44,16 @@ config CAN_KVASER_PCI
This driver is for the the PCIcanx and PCIcan cards (1, 2 or
4 channel) from Kvaser (http://www.kvaser.com).
+config CAN_PLX_PCI
+ tristate "PLX90xx PCI-bridge based Cards"
+ depends on PCI
+ ---help---
+ This driver is for CAN interface cards based on
+ the PLX90xx PCI bridge.
+ Driver supports now:
+ - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
+ - Adlink PCI-7841/cPCI-7841 SE card
+ - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
+ - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+
endif
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 9d245ac..ce92455 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
new file mode 100644
index 0000000..4b7a697
--- /dev/null
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>
+ *
+ * Derived from the ems_pci.c driver:
+ * Copyright (C) 2007 Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
+ * Copyright (C) 2008 Markus Plessing <plessing-zsNKPWJ8Pib6hrUXjxyGrA@public.gmane.org>
+ * Copyright (C) 2008 Sebastian Haas <haas-zsNKPWJ8Pib6hrUXjxyGrA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME "sja1000_plx_pci"
+
+MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov-tHBF8D5G73F4OK5fxMSSsQ@public.gmane.org>");
+MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
+ "the SJA1000 chips");
+MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
+ "Adlink PCI-7841/cPCI-7841 SE, "
+ "Marathon CAN-bus-PCI, "
+ "TEWS TECHNOLOGIES TPMC810");
+MODULE_LICENSE("GPL v2");
+
+#define PLX_PCI_MAX_CHAN 2
+
+struct plx_pci_card {
+ int channels; /* detected channels count */
+ struct net_device *net_dev[PLX_PCI_MAX_CHAN];
+ void __iomem *conf_addr;
+};
+
+#define PLX_PCI_CAN_CLOCK (16000000 / 2)
+
+/* PLX90xx registers */
+#define PLX_INTCSR 0x4c /* Interrup Control/Status */
+#define PLX_CNTRL 0x50 /* User I/O, Direct Slave Response,
+ * Serial EEPROM, and Initialization
+ * Control register
+ */
+
+#define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */
+#define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */
+#define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */
+#define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode, push-pull and the correct polarity.
+ */
+#define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define PLX_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
+
+#define ADLINK_PCI_VENDOR_ID 0x144A
+#define ADLINK_PCI_DEVICE_ID 0x7841
+
+#define MARATHON_PCI_DEVICE_ID 0x2715
+
+#define TEWS_PCI_VENDOR_ID 0x1498
+#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A
+
+static void plx_pci_reset_common(struct pci_dev *pdev);
+static void plx_pci_reset_marathon(struct pci_dev *pdev);
+
+struct plx_pci_channel_map {
+ u32 bar;
+ u32 offset;
+ u32 size; /* 0x00 - auto, e.g. length of entire bar */
+};
+
+struct plx_pci_card_info {
+ const char *name;
+ int channel_count;
+ u32 can_clock;
+ u8 ocr; /* output control register */
+ u8 cdr; /* clock divider register */
+
+ /* Parameters for mapping local configuration space */
+ struct plx_pci_channel_map conf_map;
+
+ /* Parameters for mapping the SJA1000 chips */
+ struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
+
+ /* Pointer to device-dependent reset function */
+ void (*reset_func)(struct pci_dev *pdev);
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+ "Adlink PCI-7841/cPCI-7841", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+ "Adlink PCI-7841/cPCI-7841 SE", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+ "Marathon CAN-bus-PCI", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
+ &plx_pci_reset_marathon
+ /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+ "TEWS TECHNOLOGIES TPMC810", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9030 */
+};
+
+static struct pci_device_id plx_pci_tbl[] = {
+ {
+ /* Adlink PCI-7841/cPCI-7841 */
+ ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_NETWORK_OTHER << 8, ~0,
+ (kernel_ulong_t)&plx_pci_card_info_adlink
+ },
+ {
+ /* Adlink PCI-7841/cPCI-7841 SE */
+ ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
+ (kernel_ulong_t)&plx_pci_card_info_adlink_se
+ },
+ {
+ /* Marathon CAN-bus-PCI card */
+ PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_marathon
+ },
+ {
+ /* TEWS TECHNOLOGIES TPMC810 card */
+ TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_tews
+ },
+ { 0,}
+};
+MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
+
+static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return ioread8(priv->reg_base + port);
+}
+
+static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+{
+ iowrite8(val, priv->reg_base + port);
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to switch 'em from the Basic mode into the PeliCAN mode.
+ * Also check states of some registers in reset mode.
+ */
+static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
+{
+ int flag = 0;
+
+ /*
+ * Check registers after hardware reset (the Basic mode)
+ * See states on p. 10 of the Datasheet.
+ */
+ if ((priv->read_reg(priv, REG_MOD) & 0xa1) == 0x21 &&
+ (priv->read_reg(priv, REG_SR) == 0x0c) &&
+ (priv->read_reg(priv, REG_IR) == 0xe0))
+ flag = 1;
+
+ /* Bring the SJA1000 into the PeliCAN mode*/
+ priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+
+ /*
+ * Check registers after reset in the PeliCAN mode.
+ * See states on p. 23 of the Datasheet.
+ */
+ if ((priv->read_reg(priv, REG_MOD) & 0xf1) == 0x01 &&
+ (priv->read_reg(priv, REG_SR) & 0x37) == 0x34 &&
+ (priv->read_reg(priv, REG_IR) & 0xfb) == 0x00)
+ return flag;
+
+ return 0;
+}
+
+/*
+ * PLX90xx software reset
+ * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
+ * For most cards it's enough for reset the SJA1000 chips.
+ */
+static void plx_pci_reset_common(struct pci_dev *pdev)
+{
+ struct plx_pci_card *card = pci_get_drvdata(pdev);
+ u32 cntrl;
+
+ cntrl = ioread32(card->conf_addr + PLX_CNTRL);
+ cntrl |= PLX_PCI_RESET;
+ iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+ udelay(100);
+ cntrl ^= PLX_PCI_RESET;
+ iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+};
+
+/* Special reset function for Marathon card */
+static void plx_pci_reset_marathon(struct pci_dev *pdev)
+{
+ void __iomem *reset_addr;
+ int i;
+ int reset_bar[2] = {3, 5};
+
+ plx_pci_reset_common(pdev);
+
+ for (i = 0; i < 2; i++) {
+ reset_addr = pci_iomap(pdev, reset_bar[i], 0);
+ if (!reset_addr) {
+ dev_err(&pdev->dev, "Failed to remap reset "
+ "space %d (BAR%d)\n", i, reset_bar[i]);
+ } else {
+ /* reset the SJA1000 chip */
+ iowrite8(0x1, reset_addr);
+ udelay(100);
+ pci_iounmap(pdev, reset_addr);
+ }
+ }
+}
+
+static void plx_pci_del_card(struct pci_dev *pdev)
+{
+ struct plx_pci_card *card = pci_get_drvdata(pdev);
+ struct net_device *dev;
+ struct sja1000_priv *priv;
+ int i = 0;
+
+ for (i = 0; i < card->channels; i++) {
+ dev = card->net_dev[i];
+ if (!dev)
+ continue;
+
+ dev_info(&pdev->dev, "Removing %s\n", dev->name);
+ unregister_sja1000dev(dev);
+ priv = netdev_priv(dev);
+ if (priv->reg_base)
+ pci_iounmap(pdev, priv->reg_base);
+ free_sja1000dev(dev);
+ }
+
+ plx_pci_reset_common(pdev);
+
+ /*
+ * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
+ * Local_2 interrupts
+ */
+ iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+
+ if (card->conf_addr)
+ pci_iounmap(pdev, card->conf_addr);
+
+ kfree(card);
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * Probe PLX90xx based device for the SJA1000 chips and register each
+ * available CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit plx_pci_add_card(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct sja1000_priv *priv;
+ struct net_device *dev;
+ struct plx_pci_card *card;
+ struct plx_pci_card_info *ci;
+ int err, i;
+ u32 val;
+ void __iomem *addr;
+
+ ci = (struct plx_pci_card_info *)ent->driver_data;
+
+ if (pci_enable_device(pdev) < 0) {
+ dev_err(&pdev->dev, "Failed to enable PCI device\n");
+ return -ENODEV;
+ }
+
+ dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
+ ci->name, PCI_SLOT(pdev->devfn));
+
+ /* Allocate card structures to hold addresses, ... */
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
+ if (!card) {
+ dev_err(&pdev->dev, "Unable to allocate memory\n");
+ pci_disable_device(pdev);
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, card);
+
+ card->channels = 0;
+
+ /* Remap PLX90xx configuration space */
+ addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
+ if (!addr) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to remap configuration space "
+ "(BAR%d)\n", ci->conf_map.bar);
+ goto failure_cleanup;
+ }
+ card->conf_addr = addr + ci->conf_map.offset;
+
+ ci->reset_func(pdev);
+
+ /* Detect available channels */
+ for (i = 0; i < ci->channel_count; i++) {
+ struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
+
+ dev = alloc_sja1000dev(0);
+ if (!dev) {
+ err = -ENOMEM;
+ goto failure_cleanup;
+ }
+
+ card->net_dev[i] = dev;
+ priv = netdev_priv(dev);
+ priv->priv = card;
+ priv->irq_flags = IRQF_SHARED;
+
+ dev->irq = pdev->irq;
+
+ /*
+ * Remap IO space of the SJA1000 chips
+ * This is device-dependent mapping
+ */
+ addr = pci_iomap(pdev, cm->bar, cm->size);
+ if (!addr) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
+ goto failure_cleanup;
+ }
+
+ priv->reg_base = addr + cm->offset;
+ priv->read_reg = plx_pci_read_reg;
+ priv->write_reg = plx_pci_write_reg;
+
+ /* Check if channel is present */
+ if (plx_pci_check_sja1000(priv)) {
+ priv->can.clock.freq = ci->can_clock;
+ priv->ocr = ci->ocr;
+ priv->cdr = ci->cdr;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ /* Register SJA1000 device */
+ err = register_sja1000dev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Registering device failed "
+ "(err=%d)\n", err);
+ free_sja1000dev(dev);
+ goto failure_cleanup;
+ }
+
+ card->channels++;
+
+ dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
+ "registered as %s\n", i + 1, priv->reg_base,
+ dev->irq, dev->name);
+ } else {
+ dev_err(&pdev->dev, "Channel #%d not detected\n",
+ i + 1);
+ free_sja1000dev(dev);
+ }
+ }
+
+ if (!card->channels) {
+ err = -ENODEV;
+ goto failure_cleanup;
+ }
+
+ /*
+ * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
+ * Local_2 interrupts from the SJA1000 chips
+ */
+ val = ioread32(card->conf_addr + PLX_INTCSR);
+ val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
+ iowrite32(val, card->conf_addr + PLX_INTCSR);
+
+ return 0;
+
+failure_cleanup:
+ dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
+
+ plx_pci_del_card(pdev);
+
+ return err;
+}
+
+static struct pci_driver plx_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = plx_pci_tbl,
+ .probe = plx_pci_add_card,
+ .remove = plx_pci_del_card,
+};
+
+static int __init plx_pci_init(void)
+{
+ return pci_register_driver(&plx_pci_driver);
+}
+
+static void __exit plx_pci_exit(void)
+{
+ pci_unregister_driver(&plx_pci_driver);
+}
+
+module_init(plx_pci_init);
+module_exit(plx_pci_exit);
--
1.6.0.6
^ permalink raw reply related
* Re: [RFC] [PATCH] Optimize TCP sendmsg in favour of fast devices?
From: Herbert Xu @ 2010-01-29 9:06 UTC (permalink / raw)
To: Krishna Kumar2; +Cc: David Miller, eric.dumazet, ilpo.jarvinen, netdev
In-Reply-To: <OF7EA723DA.DC2FF4FC-ON652576B8.002064CB-652576B8.00267739@in.ibm.com>
On Wed, Jan 27, 2010 at 12:42:12PM +0530, Krishna Kumar2 wrote:
>
> OK, I unset F_SG and set F_GSO (in driver). With this, tcpdump shows
> GSO is enabled - the tcp packet sizes builds up to 65160 bytes.
>
> I ran 5 serial netperf's with 16K and another 5 serial netperfs
> with 64K I/O sizes, and the aggregate result is:
>
> 0. Driver unsets F_SG but sets F_GSO:
> Original code with 16K: 19471.65
> New code with 16K: 19409.70
> Original code with 64K: 21357.23
> New code with 64K: 22050.42
OK this is more in line with what I was expecting, namely that
enabling GSO is actually beneficial even without SG.
It would be good to get the CPU utilisation figures so we can
see the complete picture.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [RFC] [PATCH] Optimize TCP sendmsg in favour of fast devices?
From: Herbert Xu @ 2010-01-29 9:07 UTC (permalink / raw)
To: Krishna Kumar2; +Cc: David Miller, eric.dumazet, ilpo.jarvinen, netdev
In-Reply-To: <OFC641141C.812873FC-ON652576B8.003216B6-652576B8.003440CC@in.ibm.com>
On Wed, Jan 27, 2010 at 03:12:48PM +0530, Krishna Kumar2 wrote:
>
> I should have mentioned this too - if I unset F_SG in the
> cxgb3 driver and nothing else, ethtool -k still shows GSO
> is set, and tcpdump shows max packet size is 1448. If I
> additionally set GSO in driver, then ethtool still has the
> same output, but tcpdump shows max packet size of 65160.
This sounds like a bug.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: PROBLEM: reproducible crash KVM+nf_conntrack all recent 2.6 kernels
From: Eric Dumazet @ 2010-01-29 9:10 UTC (permalink / raw)
To: Jon Masters; +Cc: Patrick McHardy, linux-kernel, netdev, netfilter-devel
In-Reply-To: <1264754565.2793.405.camel@tonnant>
Le vendredi 29 janvier 2010 à 03:42 -0500, Jon Masters a écrit :
> Hi,
>
> So I did some poking (still trying to figure out netfilter a little
> internally) and looked over the handling of connection tracking. The
> oops reports I have been getting generally lie in __nf_conntrack_find,
> specifically within a hlist iterator that looks up the information for
> the current connection in a per-net namespace hashtable (under RCU, it's
> been locked already by the time we get in here). Here's the piece:
>
> hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
> hnnode) {
> if (nf_ct_tuple_equal(tuple, &h->tuple)) {
> NF_CT_STAT_INC(net, found);
> local_bh_enable();
> return h;
> }
> NF_CT_STAT_INC(net, searched);
> }
>
> Instrumenting the kernel at the moment and then setting up more of a
> debugging environment to poke at what goes wrong here. Perhaps there's
> some broken RCU assumption - I just spent the last few hours reading
> over netfilter source and Paul's RCU docs again to brush up.
>
> Perhaps you netdev folks can let me know if there's a handy netfilter
> debugging guide somewhere.
>
> Jon.
>
>
Jon, do you have multiple network namespace active on your machine, when
crash occurs ?
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" 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: 0% cpu usasge after fresh boot or net restart but 10% CPU if kernel flush route cache
From: Eric Dumazet @ 2010-01-29 9:06 UTC (permalink / raw)
To: cold cold; +Cc: netdev
In-Reply-To: <41ac0f9e1001282338n76217590u61877f181c05dc06@mail.gmail.com>
Le vendredi 29 janvier 2010 à 09:38 +0200, cold cold a écrit :
> I'm totally agree with you there must be some scheduler to release
> route cache over the time.
> So far i see garbage collector do this, but it cost a lot of CPU
> probably its is a bug or design problem don't know
> for this i make this 2 test to compare CPU usage with and without GC.
>
>
> / secret_interval 10 min, 1300000 route entries in cash ofter 10 min,
> 7k new route on empty cache 2k on 1300000 /
> all route cache parameters default. I try also with gc_elasticity from
> 8 to 2 and gc_interval from 60 to 1 but don't have
> too much difference.
>
> What I'm trying to say is that flush cash is almost instant ( less
> then second on 1 CPU) so releasing of cash is not so heavy job
> ( you are right can have a big impact on dropped frames because of
> cpu/ram congestion ) but my point is why GC need 5-6min
> 10% no 4 CPU to do same job ?
> --
Once again, 'flushing cache' is immediate, it only increments a global
variable (aka a generation number)
Then, later, when ip routing hits an entry with an old generation
number, this entry is discarded. This slows down processing, and your
router might drop packets during 5 to 60 seconds, while stale entries
are eliminated.
This delays the real cost of 'flush cache' in a smooth way, depending
on trafic you have.
Releasing 1.300.000 dst entries is expensive, no matter how you trigger
the release, because it has to go through RCU queueing, spinlocks,
kernel memory allocator logic, and touch a lot of memory.
In your previous "perf top" results, we saw most of kernel cpu cycles
were consumed outside of network stack, you might investigate why.
Using HPET time keeping is probably not very good for your machine...
^ permalink raw reply
* Device only sends out one packet. Problem with netif queues?
From: Amit Uttamchandani @ 2010-01-29 9:00 UTC (permalink / raw)
To: netdev
I've been modifying drivers/net/ethoc.c for my specific application.
At this point, I get one packet to come out of the device (A DHCP
packet since udhcpc is started on boot). However, after that no other
packets are being sent out.
Could this be a problem in the way I've set up the queues? Or is there
another area in the code I should look at (e.g. napi stuff, phy
related, etc)?
This could be because I am not getting a 'transmit done' interrupt from my
hardware which I am still trying to fix. But I thought it should still
be sending out the packets right? Even though it doesn't receive an ack
from hardware?
Thanks for any help.
^ permalink raw reply
* [PATCH] IPv6:Send an ICMPv6 "Fragment Reassembly Timeout" message when enabling connection track
From: Shan Wei @ 2010-01-29 8:58 UTC (permalink / raw)
To: David Miller, Patrick McHardy, Yasuyuki KOZAKAI
Cc: eric.dumazet, randy.dunlap, mst, johannes, kuznet, pekkas,
jmorris, yoshfuji, pablo, ebiederm, adobriyan, brian.haley,
shemminger, akpm, netfilter-devel, netdev@vger.kernel.org
I have made a patch for an end host with IPv4 connection track enable
to send an ICMP "Fragment Reassembly Timeout" message when defaging timeout.
So add same changes for IPv6 connection track according to the section 4.5
in RFC2460.
Quote Begin:
Section 4.5 in RFC2460.
If insufficient fragments are received to complete reassembly of a
packet within 60 seconds of the reception of the first-arriving
fragment of that packet, reassembly of that packet must be
abandoned and all the fragments that have been received for that
packet must be discarded. If the first fragment (i.e., the one
with a Fragment Offset of zero) has been received, an ICMP Time
Exceeded -- Fragment Reassembly Time Exceeded message should be
sent to the source of that fragment.
Quote End.
I have tested the patch on both host type and route type.
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
---
include/linux/skbuff.h | 5 ++++
net/ipv6/netfilter/nf_conntrack_reasm.c | 34 ++++++++++++++++++++++++++++++-
net/ipv6/route.c | 1 +
3 files changed, 39 insertions(+), 1 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index ae836fd..33a1784 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -431,6 +431,11 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb)
return (struct rtable *)skb_dst(skb);
}
+static inline struct rt6_info *skb_r6table(const struct sk_buff *skb)
+{
+ return (struct rt6_info *)skb_dst(skb);
+}
+
extern void kfree_skb(struct sk_buff *skb);
extern void consume_skb(struct sk_buff *skb);
extern void __kfree_skb(struct sk_buff *skb);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 312c20a..2be0edc 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -27,10 +27,12 @@
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/random.h>
+#include <linux/ipv6_route.h>
#include <net/sock.h>
#include <net/snmp.h>
#include <net/inet_frag.h>
+#include <net/ip6_route.h>
#include <net/ipv6.h>
#include <net/protocol.h>
@@ -160,6 +162,33 @@ static void nf_ct_frag6_expire(unsigned long data)
fq_kill(fq);
+ /* Don't send error if the first segment did not arrive. */
+ if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments)
+ goto out;
+
+ /*
+ * Only search router table for the head fragment,
+ * when defraging timeout at PRE_ROUTING HOOK.
+ */
+ if (fq->user == IP6_DEFRAG_CONNTRACK_IN) {
+ struct sk_buff *head = fq->q.fragments;
+
+ ip6_route_input(head);
+ if (!skb_dst(head))
+ goto out;
+
+ /*
+ * Only an end host needs to send an ICMP "Fragment Reassembly
+ * Timeout" message, per section 4.5 of RFC2460.
+ */
+ if (!(skb_r6table(head)->rt6i_flags & RTF_LOCAL))
+ goto out;
+
+ /* Send an ICMP "Fragment Reassembly Timeout" message. */
+ icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
+ head->dev);
+ }
+
out:
spin_unlock(&fq->q.lock);
fq_put(fq);
@@ -349,17 +378,20 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
else
fq->q.fragments = skb;
- skb->dev = NULL;
fq->q.stamp = skb->tstamp;
fq->q.meat += skb->len;
atomic_add(skb->truesize, &nf_init_frags.mem);
/* The first fragment.
* nhoffset is obtained from the first fragment, of course.
+ * Reserve dev for sending an ICMP "Fragment Reassembly Timeout"
+ * message.
*/
if (offset == 0) {
fq->nhoffset = nhoff;
fq->q.last_in |= INET_FRAG_FIRST_IN;
+ } else {
+ skb->dev = NULL;
}
write_lock(&nf_frags.lock);
list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c2bd74c..0980d6c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -802,6 +802,7 @@ void ip6_route_input(struct sk_buff *skb)
skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input));
}
+EXPORT_SYMBOL(ip6_route_input);
static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
struct flowi *fl, int flags)
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH net-next-2.6] packet: Add GSO/checksum offload support to af_packet sockets
From: Herbert Xu @ 2010-01-29 8:53 UTC (permalink / raw)
To: Sridhar Samudrala; +Cc: David Miller, Rusty Russell, Michael S. Tsirkin, netdev
In-Reply-To: <1264537819.24933.122.camel@w-sridhar.beaverton.ibm.com>
On Tue, Jan 26, 2010 at 12:30:19PM -0800, Sridhar Samudrala wrote:
>
> + if (po->vnet_hdr) {
> + err = -EINVAL;
> + if (dev->type != ARPHRD_ETHER)
> + goto out_unlock;
We shouldn't have Ethernet-specific code in AF_PACKET. What's
more, just because the device type is Ethernet it doesn't mean
that the packet is going to have an Ethernet header.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: PROBLEM: reproducible crash KVM+nf_conntrack all recent 2.6 kernels
From: Jon Masters @ 2010-01-29 8:42 UTC (permalink / raw)
To: Patrick McHardy; +Cc: linux-kernel, netdev, netfilter-devel
In-Reply-To: <1264727492.2793.207.camel@tonnant>
Hi,
So I did some poking (still trying to figure out netfilter a little
internally) and looked over the handling of connection tracking. The
oops reports I have been getting generally lie in __nf_conntrack_find,
specifically within a hlist iterator that looks up the information for
the current connection in a per-net namespace hashtable (under RCU, it's
been locked already by the time we get in here). Here's the piece:
hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
hnnode) {
if (nf_ct_tuple_equal(tuple, &h->tuple)) {
NF_CT_STAT_INC(net, found);
local_bh_enable();
return h;
}
NF_CT_STAT_INC(net, searched);
}
Instrumenting the kernel at the moment and then setting up more of a
debugging environment to poke at what goes wrong here. Perhaps there's
some broken RCU assumption - I just spent the last few hours reading
over netfilter source and Paul's RCU docs again to brush up.
Perhaps you netdev folks can let me know if there's a handy netfilter
debugging guide somewhere.
Jon.
^ 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