* linux-next: manual merge of the rr tree with the net tree
From: Stephen Rothwell @ 2010-04-27 1:58 UTC (permalink / raw)
To: Rusty Russell
Cc: linux-next, linux-kernel, Michael S. Tsirkin, David Miller,
netdev
Hi Rusty,
Today's linux-next merge of the rr tree got a conflict in
drivers/net/virtio_net.c between commit
5e01d2f91df62be4d6f282149bc2a8858992ceca ("virtio-net: move sg off
stack") from the net tree and commit
7f62a724a65f864d84f50857bbfd36c240155c8f ("virtio_net: use virtqueue_xxx
wrappers") from the rr tree.
I fixed it up (see below) and can carry the fix as necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc drivers/net/virtio_net.c
index b0a85d0,91738d8..0000000
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@@ -336,11 -335,11 +336,11 @@@ static int add_recvbuf_small(struct vir
skb_put(skb, MAX_PACKET_LEN);
hdr = skb_vnet_hdr(skb);
- sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
+ sg_set_buf(vi->rx_sg, &hdr->hdr, sizeof hdr->hdr);
- skb_to_sgvec(skb, sg + 1, 0, skb->len);
+ skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
- err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
- err = virtqueue_add_buf(vi->rvq, sg, 0, 2, skb);
++ err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
if (err < 0)
dev_kfree_skb(skb);
@@@ -385,7 -386,7 +385,7 @@@ static int add_recvbuf_big(struct virtn
/* chain first in list head */
first->private = (unsigned long)list;
- err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
- err = virtqueue_add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2,
++ err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
first);
if (err < 0)
give_pages(vi, first);
@@@ -402,9 -404,9 +402,9 @@@ static int add_recvbuf_mergeable(struc
if (!page)
return -ENOMEM;
- sg_init_one(&sg, page_address(page), PAGE_SIZE);
+ sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
- err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
- err = virtqueue_add_buf(vi->rvq, &sg, 0, 1, page);
++ err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
if (err < 0)
give_pages(vi, page);
@@@ -549,13 -554,12 +549,12 @@@ static int xmit_skb(struct virtnet_inf
/* Encode metadata header at front. */
if (vi->mergeable_rx_bufs)
- sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr);
+ sg_set_buf(vi->tx_sg, &hdr->mhdr, sizeof hdr->mhdr);
else
- sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
+ sg_set_buf(vi->tx_sg, &hdr->hdr, sizeof hdr->hdr);
- hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- return virtqueue_add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
+ hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
- return vi->svq->vq_ops->add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
- 0, skb);
++ return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg, 0, skb);
}
static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
^ permalink raw reply
* Re: [patch v2] bluetooth: handle l2cap_create_connless_pdu() errors
From: Marcel Holtmann @ 2010-04-27 2:05 UTC (permalink / raw)
To: David Miller
Cc: gustavo-THi1TnShQwVAfugRpC6u6w, error27-Re5JQEeQqe8AvxtiuMwx3w,
andrei.emeltchenko-xNZwKgViW5gAvxtiuMwx3w,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
kernel-janitors-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100426.111259.112594696.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Hi Dave,
> > * Dan Carpenter <error27-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> [2010-04-26 13:36:27 +0200]:
> >
> >> l2cap_create_connless_pdu() can sometimes return ERR_PTR(-ENOMEM) or
> >> ERR_PTR(-EFAULT).
> >>
> >> Signed-off-by: Dan Carpenter <error27-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> ---
> >> In v2 I wrote the patch on top of Gustavo Padovon's devel tree
>
> This is the kind of bug that could cause a crash if the path actually
> executes.
>
> Therefore it tires me that that submitter was told to regenerate this
> patch against some devel tree that is -next bound, when in fact this
> is the kind of fix that warrants inclusion right now into net-2.6
>
> Marcel, please do whatever magic you need to so I can get this into
> Linus's tree as I did the rest of the ERR_PTR() fixes from Dan already.
> No reason to treat Bluetooth special and defer these fixes to -next.
my bad here. I looked at the patch and thought it was only an issue
inside the development tree. So was letting Gustavo sort this out. You
are 100% right, this needs to be fixed right away. If you wanna take
this directly, then
Acked-by: Marcel Holtmann <marcel-kz+m5ild9QBg9hUCZPvPmw@public.gmane.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] cxgb3: Wait longer for control packets on initialization
From: Divy Le Ray @ 2010-04-27 2:16 UTC (permalink / raw)
To: Andre Detsch; +Cc: netdev
In-Reply-To: <201004261238.27919.adetsch@br.ibm.com>
Andre Detsch wrote:
> In some Power7 platforms, when using VIOS (Virtual I/O Server), we
> need to wait longer for control packets to finish transfer during
> initialization.
> Without this change, initialization may fail prematurely.
>
> Signed-off-by: Wen Xiong <wenxiong@us.ibm.com>
> Signed-off-by: Andre Detsch <adetsch@br.ibm.com>
>
Acked-by: Divy Le Ray <divy@chelsio.com>
> Index: linux-2.6.34-rc5/drivers/net/cxgb3/cxgb3_main.c
> ===================================================================
> --- linux-2.6.34-rc5.orig/drivers/net/cxgb3/cxgb3_main.c 2010-04-23 18:59:43.000000000 -0300
> +++ linux-2.6.34-rc5/drivers/net/cxgb3/cxgb3_main.c 2010-04-23 18:59:55.000000000 -0300
> @@ -439,7 +439,7 @@ static void free_irq_resources(struct ad
> static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
> unsigned long n)
> {
> - int attempts = 5;
> + int attempts = 10;
>
> while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
> if (!--attempts)
>
^ permalink raw reply
* linux-next: manual merge of the tty tree with the net tree
From: Stephen Rothwell @ 2010-04-27 3:57 UTC (permalink / raw)
To: Greg KH
Cc: linux-next, linux-kernel, Sjur Braendeland, David Miller, netdev,
Pavan Savoy
[-- Attachment #1: Type: text/plain, Size: 552 bytes --]
Hi Greg,
Today's linux-next merge of the tty tree got a conflict in
include/linux/tty.h between commit
9b27105b4a44c54bf91ecd7d0315034ae75684f7 ("net-caif-driver: add CAIF
serial driver (ldisc)") from the net tree and commit
f3150d54db0e0caa1871f66b2424f463a34a7e7b ("serial: TTY: new ldiscs for
staging") from the tty tree.
I fixed it up (they both changed NR_LDISCS - I used the higher number) and
can carry the fix as necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: linux-next: manual merge of the rr tree with the net tree
From: Michael S. Tsirkin @ 2010-04-27 4:09 UTC (permalink / raw)
To: Stephen Rothwell
Cc: Rusty Russell, linux-next, linux-kernel, David Miller, netdev
In-Reply-To: <20100427115852.9f4cbb0f.sfr@canb.auug.org.au>
On Tue, Apr 27, 2010 at 11:58:52AM +1000, Stephen Rothwell wrote:
> Hi Rusty,
>
> Today's linux-next merge of the rr tree got a conflict in
> drivers/net/virtio_net.c between commit
> 5e01d2f91df62be4d6f282149bc2a8858992ceca ("virtio-net: move sg off
> stack") from the net tree and commit
> 7f62a724a65f864d84f50857bbfd36c240155c8f ("virtio_net: use virtqueue_xxx
> wrappers") from the rr tree.
>
> I fixed it up (see below) and can carry the fix as necessary.
Hmm, Rusty, do you intend for the patches to go through netdev this
time? If you do, it might be simplest to just ask Dave to merge
them in net-next-2.6 now. I can prepare and send them if you like.
> --
> Cheers,
> Stephen Rothwell sfr@canb.auug.org.au
>
> diff --cc drivers/net/virtio_net.c
> index b0a85d0,91738d8..0000000
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@@ -336,11 -335,11 +336,11 @@@ static int add_recvbuf_small(struct vir
> skb_put(skb, MAX_PACKET_LEN);
>
> hdr = skb_vnet_hdr(skb);
> - sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
> + sg_set_buf(vi->rx_sg, &hdr->hdr, sizeof hdr->hdr);
>
> - skb_to_sgvec(skb, sg + 1, 0, skb->len);
> + skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
>
> - err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
> - err = virtqueue_add_buf(vi->rvq, sg, 0, 2, skb);
> ++ err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
> if (err < 0)
> dev_kfree_skb(skb);
>
> @@@ -385,7 -386,7 +385,7 @@@ static int add_recvbuf_big(struct virtn
>
> /* chain first in list head */
> first->private = (unsigned long)list;
> - err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
> - err = virtqueue_add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2,
> ++ err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
> first);
> if (err < 0)
> give_pages(vi, first);
> @@@ -402,9 -404,9 +402,9 @@@ static int add_recvbuf_mergeable(struc
> if (!page)
> return -ENOMEM;
>
> - sg_init_one(&sg, page_address(page), PAGE_SIZE);
> + sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
>
> - err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
> - err = virtqueue_add_buf(vi->rvq, &sg, 0, 1, page);
> ++ err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
> if (err < 0)
> give_pages(vi, page);
>
> @@@ -549,13 -554,12 +549,12 @@@ static int xmit_skb(struct virtnet_inf
>
> /* Encode metadata header at front. */
> if (vi->mergeable_rx_bufs)
> - sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr);
> + sg_set_buf(vi->tx_sg, &hdr->mhdr, sizeof hdr->mhdr);
> else
> - sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
> + sg_set_buf(vi->tx_sg, &hdr->hdr, sizeof hdr->hdr);
>
> - hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
> - return virtqueue_add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
> + hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
> - return vi->svq->vq_ops->add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
> - 0, skb);
> ++ return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg, 0, skb);
> }
>
> static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
^ permalink raw reply
* linux-next: manual merge of the staging-next tree with the net tree
From: Stephen Rothwell @ 2010-04-27 4:26 UTC (permalink / raw)
To: Greg KH
Cc: linux-next, linux-kernel, Jiri Pirko, David Miller, netdev,
John Sheehan
Hi Greg,
Today's linux-next merge of the staging-next tree got a conflict in
drivers/staging/arlan/arlan-main.c between commit
22bedad3ce112d5ca1eaf043d4990fa2ed698c87 ("net: convert multicast list to
list_head") from the net tree and commit
8db2022b08e232bb237b2162f03ff5f6e7c0c35e ("staging: arlan: fix errors
reported by checkpatch.pl tool") from the staging-next tree.
I fixed it up (see below) and can carry the fix as necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc drivers/staging/arlan/arlan-main.c
index 8028452,58deb96..0000000
--- a/drivers/staging/arlan/arlan-main.c
+++ b/drivers/staging/arlan/arlan-main.c
@@@ -1438,105 -1336,99 +1336,99 @@@ static void arlan_rx_interrupt(struct n
priv->in_time10 = jiffies;
}
DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char);
- switch (rxStatus)
+ switch (rxStatus) {
+ case 1:
+ case 2:
+ case 3:
{
- case 1:
- case 2:
- case 3:
- {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
- DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short);
- DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char);
- DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char);
+ DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short);
+ DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char);
+ DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char);
- /* here we do multicast filtering to avoid slow 8-bit memcopy */
+ /* here we do multicast filtering to avoid slow 8-bit memcopy */
#ifdef ARLAN_MULTICAST
- if (!(dev->flags & IFF_ALLMULTI) &&
- !(dev->flags & IFF_PROMISC) &&
- !netdev_mc_empty(dev))
- {
- char hw_dst_addr[6];
- struct netdev_hw_addr *ha;
- int i;
-
- memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6);
- if (hw_dst_addr[0] == 0x01)
- {
- if (mdebug)
- if (hw_dst_addr[1] == 0x00)
- printk(KERN_ERR "%s mcast 0x0100 \n", dev->name);
- else if (hw_dst_addr[1] == 0x40)
- printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
- netdev_for_each_mc_entry(ha, dev) {
- if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
- printk(KERN_ERR "%s mcl %pM\n",
- dev->name,
- ha->addr);
- for (i = 0; i < 6; i++)
- if (ha->addr[i] != hw_dst_addr[i])
- break;
- if (i == 6)
+ if (!(dev->flags & IFF_ALLMULTI) &&
+ !(dev->flags & IFF_PROMISC) &&
+ !netdev_mc_empty(dev)) {
+ char hw_dst_addr[6];
- struct dev_mc_list *dmi;
++ struct netdev_hw_addr *ha;
+ int i;
+
+ memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6);
+ if (hw_dst_addr[0] == 0x01) {
+ if (mdebug)
+ if (hw_dst_addr[1] == 0x00)
+ printk(KERN_ERR "%s mcast 0x0100 \n", dev->name);
+ else if (hw_dst_addr[1] == 0x40)
+ printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
- netdev_for_each_mc_entry(dmi, dev) {
++ netdev_for_each_mc_entry(ha, dev) {
+ if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
+ printk(KERN_ERR "%s mcl %pM\n",
- dev->name, dmi->dmi_addr);
++ dev->name, ha->addr);
+ for (i = 0; i < 6; i++)
- if (dmi->dmi_addr[i] != hw_dst_addr[i])
++ if (ha->addr[i] != hw_dst_addr[i])
break;
- }
- /* we reach here if multicast filtering is on and packet
- * is multicast and not for receive */
- goto end_of_interrupt;
+ if (i == 6)
+ break;
}
+ /* we reach here if multicast filtering is on and packet */
+ /* is multicast and not for receive */
+ goto end_of_interrupt;
}
- #endif // ARLAN_MULTICAST
- /* multicast filtering ends here */
- pkt_len += ARLAN_FAKE_HDR_LEN;
-
- skb = dev_alloc_skb(pkt_len + 4);
- if (skb == NULL)
- {
- printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- break;
- }
- skb_reserve(skb, 2);
- skbtmp = skb_put(skb, pkt_len);
+ }
+ #endif /* ARLAN_MULTICAST */
+ /* multicast filtering ends here */
+ pkt_len += ARLAN_FAKE_HDR_LEN;
+
+ skb = dev_alloc_skb(pkt_len + 4);
+ if (skb == NULL) {
+ printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
+ dev->stats.rx_dropped++;
+ break;
+ }
+ skb_reserve(skb, 2);
+ skbtmp = skb_put(skb, pkt_len);
- memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN);
- memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6);
- memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6);
- WRITESHMB(arlan->rxStatus, 0x00);
- arlan_command(dev, ARLAN_COMMAND_RX);
+ memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN);
+ memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6);
+ memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6);
+ WRITESHMB(arlan->rxStatus, 0x00);
+ arlan_command(dev, ARLAN_COMMAND_RX);
- IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
- {
- char immedDestAddress[6];
- char immedSrcAddress[6];
- memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
- memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
-
- printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n",
- dev->name, skbtmp,
- &skbtmp[6],
- immedDestAddress,
- immedSrcAddress);
- }
- skb->protocol = eth_type_trans(skb, dev);
- IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
- if (skb->protocol != 0x608 && skb->protocol != 0x8)
- {
- for (i = 0; i <= 22; i++)
- printk("%02x:", (u_char) skbtmp[i + 12]);
- printk(KERN_ERR "\n");
- printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol);
- }
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
+ IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+ {
+ char immedDestAddress[6];
+ char immedSrcAddress[6];
+ memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
+ memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
+
+ printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n",
+ dev->name, skbtmp,
+ &skbtmp[6],
+ immedDestAddress,
+ immedSrcAddress);
}
+ skb->protocol = eth_type_trans(skb, dev);
+ IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
+ if (skb->protocol != 0x608 && skb->protocol != 0x8) {
+ for (i = 0; i <= 22; i++)
+ printk("%02x:", (u_char) skbtmp[i + 12]);
+ printk(KERN_ERR "\n");
+ printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol);
+ }
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "arlan intr: received unknown status\n");
+ dev->stats.rx_crc_errors++;
break;
-
- default:
- printk(KERN_ERR "arlan intr: received unknown status\n");
- dev->stats.rx_crc_errors++;
- break;
}
ARLAN_DEBUG_EXIT("arlan_rx_interrupt");
}
^ permalink raw reply
* Re: [PATCH] RCU: don't turn off lockdep when find suspicious rcu_dereference_check() usage
From: Paul E. McKenney @ 2010-04-27 4:27 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Miles Lane, Vivek Goyal, Eric Paris, Lai Jiangshan, Ingo Molnar,
Peter Zijlstra, LKML, nauman, eric.dumazet, netdev, Jens Axboe,
Gui Jianfeng, Li Zefan, Johannes Berg
In-Reply-To: <m1hbmydpup.fsf@fess.ebiederm.org>
On Mon, Apr 26, 2010 at 11:35:10AM -0700, Eric W. Biederman wrote:
> "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> writes:
>
> > Eric Dumazet traced these down to a commit from Eric Biederman.
> >
> > If I don't hear from Eric Biederman in a few days, I will attempt a
> > patch, but it would be more likely to be correct coming from someone
> > with a better understanding of the code. ;-)
>
> I already replied.
>
> http://lkml.org/lkml/2010/4/21/420
You did indeed!!! This experience is giving me an even better appreciation
of the maintainers' ability to keep all their patches straight!
I will put together something based on your suggestion.
Thanx, Paul
^ permalink raw reply
* [PATCH v4] TCP: avoid to send keepalive probes if receiving data
From: Flavio Leitner @ 2010-04-27 4:33 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Ilpo, Eric Dumazet, Flavio Leitner
In-Reply-To: <20100426.112422.246526700.davem@davemloft.net>
RFC 1122 says the following:
...
Keep-alive packets MUST only be sent when no data or
acknowledgement packets have been received for the
connection within an interval.
...
The acknowledgement packet is reseting the keepalive
timer but the data packet isn't. This patch fixes it by
checking the timestamp of the last received data packet
too when the keepalive timer expires.
Signed-off-by: Flavio Leitner <fleitner@redhat.com>
---
include/net/tcp.h | 8 ++++++++
net/ipv4/tcp.c | 2 +-
net/ipv4/tcp_timer.c | 4 ++--
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 75be5a2..305810e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1032,6 +1032,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
}
+static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
+{
+ const struct inet_connection_sock *icsk = &tp->inet_conn;
+
+ return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+ tcp_time_stamp - tp->rcv_tstamp);
+}
+
static inline int tcp_fin_time(const struct sock *sk)
{
int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0f8caf6..48a6f33 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (sock_flag(sk, SOCK_KEEPOPEN) &&
!((1 << sk->sk_state) &
(TCPF_CLOSE | TCPF_LISTEN))) {
- __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+ u32 elapsed = keepalive_time_elapsed(tp);
if (tp->keepalive_time > elapsed)
elapsed = tp->keepalive_time - elapsed;
else
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 8a0ab29..a9155f9 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
struct sock *sk = (struct sock *) data;
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- __u32 elapsed;
+ u32 elapsed;
/* Only process if socket is not in use. */
bh_lock_sock(sk);
@@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
if (tp->packets_out || tcp_send_head(sk))
goto resched;
- elapsed = tcp_time_stamp - tp->rcv_tstamp;
+ elapsed = keepalive_time_elapsed(tp);
if (elapsed >= keepalive_time_when(tp)) {
if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
--
1.5.5.6
^ permalink raw reply related
* Re: [PATCH v4] TCP: avoid to send keepalive probes if receiving data
From: Eric Dumazet @ 2010-04-27 5:06 UTC (permalink / raw)
To: Flavio Leitner; +Cc: netdev, David Miller, Ilpo
In-Reply-To: <1272342807-13379-1-git-send-email-fleitner@redhat.com>
Le mardi 27 avril 2010 à 01:33 -0300, Flavio Leitner a écrit :
> RFC 1122 says the following:
> ...
> Keep-alive packets MUST only be sent when no data or
> acknowledgement packets have been received for the
> connection within an interval.
> ...
>
> The acknowledgement packet is reseting the keepalive
> timer but the data packet isn't. This patch fixes it by
> checking the timestamp of the last received data packet
> too when the keepalive timer expires.
>
> Signed-off-by: Flavio Leitner <fleitner@redhat.com>
> ---
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> include/net/tcp.h | 8 ++++++++
> net/ipv4/tcp.c | 2 +-
> net/ipv4/tcp_timer.c | 4 ++--
> 3 files changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 75be5a2..305810e 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -1032,6 +1032,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
> return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
> }
>
> +static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
> +{
> + const struct inet_connection_sock *icsk = &tp->inet_conn;
> +
> + return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
> + tcp_time_stamp - tp->rcv_tstamp);
> +}
> +
> static inline int tcp_fin_time(const struct sock *sk)
> {
> int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 0f8caf6..48a6f33 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
> if (sock_flag(sk, SOCK_KEEPOPEN) &&
> !((1 << sk->sk_state) &
> (TCPF_CLOSE | TCPF_LISTEN))) {
> - __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
> + u32 elapsed = keepalive_time_elapsed(tp);
> if (tp->keepalive_time > elapsed)
> elapsed = tp->keepalive_time - elapsed;
> else
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index 8a0ab29..a9155f9 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
> struct sock *sk = (struct sock *) data;
> struct inet_connection_sock *icsk = inet_csk(sk);
> struct tcp_sock *tp = tcp_sk(sk);
> - __u32 elapsed;
> + u32 elapsed;
>
> /* Only process if socket is not in use. */
> bh_lock_sock(sk);
> @@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
> if (tp->packets_out || tcp_send_head(sk))
> goto resched;
>
> - elapsed = tcp_time_stamp - tp->rcv_tstamp;
> + elapsed = keepalive_time_elapsed(tp);
>
> if (elapsed >= keepalive_time_when(tp)) {
> if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
^ permalink raw reply
* linux-next: build failure after merge of the final tree (net tree related)
From: Stephen Rothwell @ 2010-04-27 5:25 UTC (permalink / raw)
To: David Miller, netdev; +Cc: linux-next, linux-kernel, YOSHIFUJI Hideaki
[-- Attachment #1: Type: text/plain, Size: 766 bytes --]
Hi Dave,
After merging the bkl-ioctl tree, today's linux-next build (powerpc
ppc44x_defconfig) failed like this:
net/bridge/br_multicast.c: In function 'br_ip6_multicast_alloc_query':
net/bridge/br_multicast.c:469: error: implicit declaration of function 'csum_ipv6_magic'
Introduced by commit 08b202b6726459626c73ecfa08fcdc8c3efc76c2 ("bridge
br_multicast: IPv6 MLD support") from the net tree.
csum_ipv6_magic is declared in net/ip6_checksum.h ...
I have reverted this commit (and 1fafc7a9353ef68e1b8d4bb130cb6402cf7dfd5a
"bridge br_multicast: Ensure to initialize BR_INPUT_SKB_CB
(skb)->mrouters_only" which depended on it) for today.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH v4] TCP: avoid to send keepalive probes if receiving data
From: Ilpo Järvinen @ 2010-04-27 6:08 UTC (permalink / raw)
To: Flavio Leitner; +Cc: Netdev, David Miller, Eric Dumazet
In-Reply-To: <1272342807-13379-1-git-send-email-fleitner@redhat.com>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 2797 bytes --]
On Tue, 27 Apr 2010, Flavio Leitner wrote:
> RFC 1122 says the following:
> ...
> Keep-alive packets MUST only be sent when no data or
> acknowledgement packets have been received for the
> connection within an interval.
> ...
>
> The acknowledgement packet is reseting the keepalive
> timer but the data packet isn't. This patch fixes it by
> checking the timestamp of the last received data packet
> too when the keepalive timer expires.
>
> Signed-off-by: Flavio Leitner <fleitner@redhat.com>
> ---
> include/net/tcp.h | 8 ++++++++
> net/ipv4/tcp.c | 2 +-
> net/ipv4/tcp_timer.c | 4 ++--
> 3 files changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 75be5a2..305810e 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -1032,6 +1032,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
> return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
> }
>
> +static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
> +{
> + const struct inet_connection_sock *icsk = &tp->inet_conn;
> +
> + return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
> + tcp_time_stamp - tp->rcv_tstamp);
> +}
> +
> static inline int tcp_fin_time(const struct sock *sk)
> {
> int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 0f8caf6..48a6f33 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
> if (sock_flag(sk, SOCK_KEEPOPEN) &&
> !((1 << sk->sk_state) &
> (TCPF_CLOSE | TCPF_LISTEN))) {
> - __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
> + u32 elapsed = keepalive_time_elapsed(tp);
> if (tp->keepalive_time > elapsed)
> elapsed = tp->keepalive_time - elapsed;
> else
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index 8a0ab29..a9155f9 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
> struct sock *sk = (struct sock *) data;
> struct inet_connection_sock *icsk = inet_csk(sk);
> struct tcp_sock *tp = tcp_sk(sk);
> - __u32 elapsed;
> + u32 elapsed;
>
> /* Only process if socket is not in use. */
> bh_lock_sock(sk);
> @@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
> if (tp->packets_out || tcp_send_head(sk))
> goto resched;
>
> - elapsed = tcp_time_stamp - tp->rcv_tstamp;
> + elapsed = keepalive_time_elapsed(tp);
>
> if (elapsed >= keepalive_time_when(tp)) {
> if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
Thanks. Looks very nice now.
Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
--
i.
^ permalink raw reply
* [PATCH net-next-2.6] net: fix a lockdep rcu warning in __sk_dst_set()
From: Eric Dumazet @ 2010-04-27 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev
__sk_dst_set() might be called while no state can be integrated in a
rcu_dereference_check() condition.
So use rcu_dereference_raw() to shutup lockdep warnings (if
CONFIG_PROVE_RCU is set)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
diff --git a/include/net/sock.h b/include/net/sock.h
index 86a8ca1..94dbdbc 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1236,8 +1236,11 @@ __sk_dst_set(struct sock *sk, struct dst_entry *dst)
struct dst_entry *old_dst;
sk_tx_queue_clear(sk);
- old_dst = rcu_dereference_check(sk->sk_dst_cache,
- lockdep_is_held(&sk->sk_dst_lock));
+ /*
+ * This can be called while sk is owned by the caller only,
+ * with no state that can be checked in a rcu_dereference_check() cond
+ */
+ old_dst = rcu_dereference_raw(sk->sk_dst_cache);
rcu_assign_pointer(sk->sk_dst_cache, dst);
dst_release(old_dst);
}
^ permalink raw reply related
* [v4 Patch 1/3] netpoll: add generic support for bridge and bonding devices
From: Amerigo Wang @ 2010-04-27 7:55 UTC (permalink / raw)
To: linux-kernel
Cc: Matt Mackall, netdev, bridge, Andy Gospodarek, Neil Horman,
Amerigo Wang, Jeff Moyer, Stephen Hemminger, bonding-devel,
Jay Vosburgh, David Miller
V4:
Use "unlikely" to mark netpoll call path, suggested by Stephen.
Handle NETDEV_GOING_DOWN case.
V3:
Update to latest Linus' tree.
Fix deadlocks when releasing slaves of bonding devices.
Thanks to Andy.
V2:
Fix some bugs of previous version.
Remove ->netpoll_setup and ->netpoll_xmit, they are not necessary.
Don't poll all underlying devices, poll ->real_dev in struct netpoll.
Thanks to David for suggesting above.
------------>
This whole patchset is for adding netpoll support to bridge and bonding
devices. I already tested it for bridge, bonding, bridge over bonding,
and bonding over bridge. It looks fine now.
To make bridge and bonding support netpoll, we need to adjust
some netpoll generic code. This patch does the following things:
1) introduce two new priv_flags for struct net_device:
IFF_IN_NETPOLL which identifies we are processing a netpoll;
IFF_DISABLE_NETPOLL is used to disable netpoll support for a device
at run-time;
2) introduce one new method for netdev_ops:
->ndo_netpoll_cleanup() is used to clean up netpoll when a device is
removed.
3) introduce netpoll_poll_dev() which takes a struct net_device * parameter;
export netpoll_send_skb() and netpoll_poll_dev() which will be used later;
4) hide a pointer to struct netpoll in struct netpoll_info, ditto.
5) introduce ->real_dev for struct netpoll.
6) introduce a new status NETDEV_BONDING_DESLAE, which is used to disable
netconsole before releasing a slave, to avoid deadlocks.
Cc: David Miller <davem@davemloft.net>
Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: WANG Cong <amwang@redhat.com>
---
Index: linux-2.6/include/linux/if.h
===================================================================
--- linux-2.6.orig/include/linux/if.h
+++ linux-2.6/include/linux/if.h
@@ -71,6 +71,8 @@
* release skb->dst
*/
#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
+#define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */
+#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
Index: linux-2.6/include/linux/netdevice.h
===================================================================
--- linux-2.6.orig/include/linux/netdevice.h
+++ linux-2.6/include/linux/netdevice.h
@@ -667,6 +667,7 @@ struct net_device_ops {
unsigned short vid);
#ifdef CONFIG_NET_POLL_CONTROLLER
void (*ndo_poll_controller)(struct net_device *dev);
+ void (*ndo_netpoll_cleanup)(struct net_device *dev);
#endif
int (*ndo_set_vf_mac)(struct net_device *dev,
int queue, u8 *mac);
Index: linux-2.6/include/linux/netpoll.h
===================================================================
--- linux-2.6.orig/include/linux/netpoll.h
+++ linux-2.6/include/linux/netpoll.h
@@ -14,6 +14,7 @@
struct netpoll {
struct net_device *dev;
+ struct net_device *real_dev;
char dev_name[IFNAMSIZ];
const char *name;
void (*rx_hook)(struct netpoll *, int, char *, int);
@@ -36,8 +37,11 @@ struct netpoll_info {
struct sk_buff_head txq;
struct delayed_work tx_work;
+
+ struct netpoll *netpoll;
};
+void netpoll_poll_dev(struct net_device *dev);
void netpoll_poll(struct netpoll *np);
void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
void netpoll_print_options(struct netpoll *np);
@@ -47,6 +51,7 @@ int netpoll_trap(void);
void netpoll_set_trap(int trap);
void netpoll_cleanup(struct netpoll *np);
int __netpoll_rx(struct sk_buff *skb);
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
#ifdef CONFIG_NETPOLL
Index: linux-2.6/net/core/netpoll.c
===================================================================
--- linux-2.6.orig/net/core/netpoll.c
+++ linux-2.6/net/core/netpoll.c
@@ -179,9 +179,8 @@ static void service_arp_queue(struct net
}
}
-void netpoll_poll(struct netpoll *np)
+void netpoll_poll_dev(struct net_device *dev)
{
- struct net_device *dev = np->dev;
const struct net_device_ops *ops;
if (!dev || !netif_running(dev))
@@ -201,6 +200,11 @@ void netpoll_poll(struct netpoll *np)
zap_completion_queue();
}
+void netpoll_poll(struct netpoll *np)
+{
+ netpoll_poll_dev(np->dev);
+}
+
static void refill_skbs(void)
{
struct sk_buff *skb;
@@ -282,7 +286,7 @@ static int netpoll_owner_active(struct n
return 0;
}
-static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
{
int status = NETDEV_TX_BUSY;
unsigned long tries;
@@ -308,7 +312,9 @@ static void netpoll_send_skb(struct netp
tries > 0; --tries) {
if (__netif_tx_trylock(txq)) {
if (!netif_tx_queue_stopped(txq)) {
+ dev->priv_flags |= IFF_IN_NETPOLL;
status = ops->ndo_start_xmit(skb, dev);
+ dev->priv_flags &= ~IFF_IN_NETPOLL;
if (status == NETDEV_TX_OK)
txq_trans_update(txq);
}
@@ -756,7 +762,10 @@ int netpoll_setup(struct netpoll *np)
atomic_inc(&npinfo->refcnt);
}
- if (!ndev->netdev_ops->ndo_poll_controller) {
+ npinfo->netpoll = np;
+
+ if (ndev->priv_flags & IFF_DISABLE_NETPOLL
+ || !ndev->netdev_ops->ndo_poll_controller) {
printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
np->name, np->dev_name);
err = -ENOTSUPP;
@@ -878,6 +887,7 @@ void netpoll_cleanup(struct netpoll *np)
}
if (atomic_dec_and_test(&npinfo->refcnt)) {
+ const struct net_device_ops *ops;
skb_queue_purge(&npinfo->arp_tx);
skb_queue_purge(&npinfo->txq);
cancel_rearming_delayed_work(&npinfo->tx_work);
@@ -885,7 +895,11 @@ void netpoll_cleanup(struct netpoll *np)
/* clean after last, unfinished work */
__skb_queue_purge(&npinfo->txq);
kfree(npinfo);
- np->dev->npinfo = NULL;
+ ops = np->dev->netdev_ops;
+ if (ops->ndo_netpoll_cleanup)
+ ops->ndo_netpoll_cleanup(np->dev);
+ else
+ np->dev->npinfo = NULL;
}
}
@@ -908,6 +922,7 @@ void netpoll_set_trap(int trap)
atomic_dec(&trapped);
}
+EXPORT_SYMBOL(netpoll_send_skb);
EXPORT_SYMBOL(netpoll_set_trap);
EXPORT_SYMBOL(netpoll_trap);
EXPORT_SYMBOL(netpoll_print_options);
@@ -915,4 +930,5 @@ EXPORT_SYMBOL(netpoll_parse_options);
EXPORT_SYMBOL(netpoll_setup);
EXPORT_SYMBOL(netpoll_cleanup);
EXPORT_SYMBOL(netpoll_send_udp);
+EXPORT_SYMBOL(netpoll_poll_dev);
EXPORT_SYMBOL(netpoll_poll);
Index: linux-2.6/drivers/net/netconsole.c
===================================================================
--- linux-2.6.orig/drivers/net/netconsole.c
+++ linux-2.6/drivers/net/netconsole.c
@@ -665,7 +665,8 @@ static int netconsole_netdev_event(struc
struct netconsole_target *nt;
struct net_device *dev = ptr;
- if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER))
+ if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
+ event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN))
goto done;
spin_lock_irqsave(&target_list_lock, flags);
@@ -677,19 +678,21 @@ static int netconsole_netdev_event(struc
strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
break;
case NETDEV_UNREGISTER:
- if (!nt->enabled)
- break;
netpoll_cleanup(&nt->np);
+ /* Fall through */
+ case NETDEV_GOING_DOWN:
+ case NETDEV_BONDING_DESLAVE:
nt->enabled = 0;
- printk(KERN_INFO "netconsole: network logging stopped"
- ", interface %s unregistered\n",
- dev->name);
break;
}
}
netconsole_target_put(nt);
}
spin_unlock_irqrestore(&target_list_lock, flags);
+ if (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE)
+ printk(KERN_INFO "netconsole: network logging stopped, "
+ "interface %s %s\n", dev->name,
+ event == NETDEV_UNREGISTER ? "unregistered" : "released slaves");
done:
return NOTIFY_DONE;
Index: linux-2.6/include/linux/notifier.h
===================================================================
--- linux-2.6.orig/include/linux/notifier.h
+++ linux-2.6/include/linux/notifier.h
@@ -203,6 +203,7 @@ static inline int notifier_to_errno(int
#define NETDEV_BONDING_NEWTYPE 0x000F
#define NETDEV_POST_INIT 0x0010
#define NETDEV_UNREGISTER_BATCH 0x0011
+#define NETDEV_BONDING_DESLAVE 0x0012
#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
^ permalink raw reply
* [v4 Patch 2/3] bridge: make bridge support netpoll
From: Amerigo Wang @ 2010-04-27 7:55 UTC (permalink / raw)
To: linux-kernel
Cc: Stephen Hemminger, netdev, bridge, Andy Gospodarek, Neil Horman,
Amerigo Wang, Jeff Moyer, Matt Mackall, bonding-devel,
Jay Vosburgh, David Miller
In-Reply-To: <20100427075937.4908.18468.sendpatchset@localhost.localdomain>
Based on the previous patch, make bridge support netpoll by:
1) implement the 2 methods to support netpoll for bridge;
2) modify netpoll during forwarding packets via bridge;
3) disable netpoll support of bridge when a netpoll-unabled device
is added to bridge;
4) enable netpoll support when all underlying devices support netpoll.
Cc: David Miller <davem@davemloft.net>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Stephen Hemminger <shemminger@linux-foundation.org>
Cc: Matt Mackall <mpm@selenic.com>
Signed-off-by: WANG Cong <amwang@redhat.com>
---
Index: linux-2.6/net/bridge/br_device.c
===================================================================
--- linux-2.6.orig/net/bridge/br_device.c
+++ linux-2.6/net/bridge/br_device.c
@@ -13,8 +13,10 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/netpoll.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
+#include <linux/list.h>
#include <asm/uaccess.h>
#include "br_private.h"
@@ -162,6 +164,59 @@ static int br_set_tx_csum(struct net_dev
return 0;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+bool br_devices_support_netpoll(struct net_bridge *br)
+{
+ struct net_bridge_port *p;
+ bool ret = true;
+ int count = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&br->lock, flags);
+ list_for_each_entry(p, &br->port_list, list) {
+ count++;
+ if (p->dev->priv_flags & IFF_DISABLE_NETPOLL
+ || !p->dev->netdev_ops->ndo_poll_controller)
+ ret = false;
+ }
+ spin_unlock_irqrestore(&br->lock, flags);
+ return count != 0 && ret;
+}
+
+static void br_poll_controller(struct net_device *br_dev)
+{
+ struct netpoll *np = br_dev->npinfo->netpoll;
+
+ if (np->real_dev != br_dev)
+ netpoll_poll_dev(np->real_dev);
+}
+
+void br_netpoll_cleanup(struct net_device *br_dev)
+{
+ struct net_bridge *br = netdev_priv(br_dev);
+ struct net_bridge_port *p, *n;
+ const struct net_device_ops *ops;
+
+ br->dev->npinfo = NULL;
+ list_for_each_entry_safe(p, n, &br->port_list, list) {
+ if (p->dev) {
+ ops = p->dev->netdev_ops;
+ if (ops->ndo_netpoll_cleanup)
+ ops->ndo_netpoll_cleanup(p->dev);
+ else
+ p->dev->npinfo = NULL;
+ }
+ }
+}
+
+#else
+
+void br_netpoll_cleanup(struct net_device *br_dev)
+{
+}
+
+#endif
+
static const struct ethtool_ops br_ethtool_ops = {
.get_drvinfo = br_getinfo,
.get_link = ethtool_op_get_link,
@@ -184,6 +239,10 @@ static const struct net_device_ops br_ne
.ndo_set_multicast_list = br_dev_set_multicast_list,
.ndo_change_mtu = br_change_mtu,
.ndo_do_ioctl = br_dev_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_netpoll_cleanup = br_netpoll_cleanup,
+ .ndo_poll_controller = br_poll_controller,
+#endif
};
void br_dev_setup(struct net_device *dev)
Index: linux-2.6/net/bridge/br_forward.c
===================================================================
--- linux-2.6.orig/net/bridge/br_forward.c
+++ linux-2.6/net/bridge/br_forward.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/netpoll.h>
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/netfilter_bridge.h>
@@ -50,7 +51,13 @@ int br_dev_queue_push_xmit(struct sk_buf
else {
skb_push(skb, ETH_HLEN);
- dev_queue_xmit(skb);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (unlikely(skb->dev->priv_flags & IFF_IN_NETPOLL)) {
+ netpoll_send_skb(skb->dev->npinfo->netpoll, skb);
+ skb->dev->priv_flags &= ~IFF_IN_NETPOLL;
+ } else
+#endif
+ dev_queue_xmit(skb);
}
}
@@ -66,9 +73,23 @@ int br_forward_finish(struct sk_buff *sk
static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ struct net_bridge *br = to->br;
+ if (unlikely(br->dev->priv_flags & IFF_IN_NETPOLL)) {
+ struct netpoll *np;
+ to->dev->npinfo = skb->dev->npinfo;
+ np = skb->dev->npinfo->netpoll;
+ np->real_dev = np->dev = to->dev;
+ to->dev->priv_flags |= IFF_IN_NETPOLL;
+ }
+#endif
skb->dev = to->dev;
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
br_forward_finish);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (skb->dev->npinfo)
+ skb->dev->npinfo->netpoll->dev = br->dev;
+#endif
}
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
Index: linux-2.6/net/bridge/br_if.c
===================================================================
--- linux-2.6.orig/net/bridge/br_if.c
+++ linux-2.6/net/bridge/br_if.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/netpoll.h>
#include <linux/ethtool.h>
#include <linux/if_arp.h>
#include <linux/module.h>
@@ -153,6 +154,14 @@ static void del_nbp(struct net_bridge_po
kobject_uevent(&p->kobj, KOBJ_REMOVE);
kobject_del(&p->kobj);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (br_devices_support_netpoll(br))
+ br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ if (dev->netdev_ops->ndo_netpoll_cleanup)
+ dev->netdev_ops->ndo_netpoll_cleanup(dev);
+ else
+ dev->npinfo = NULL;
+#endif
call_rcu(&p->rcu, destroy_nbp_rcu);
}
@@ -165,6 +174,8 @@ static void del_br(struct net_bridge *br
del_nbp(p);
}
+ br_netpoll_cleanup(br->dev);
+
del_timer_sync(&br->gc_timer);
br_sysfs_delbr(br->dev);
@@ -438,6 +449,20 @@ int br_add_if(struct net_bridge *br, str
kobject_uevent(&p->kobj, KOBJ_ADD);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (br_devices_support_netpoll(br)) {
+ br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ if (br->dev->npinfo)
+ dev->npinfo = br->dev->npinfo;
+ } else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) {
+ br->dev->priv_flags |= IFF_DISABLE_NETPOLL;
+ printk(KERN_INFO "New device %s does not support netpoll\n",
+ dev->name);
+ printk(KERN_INFO "Disabling netpoll for %s\n",
+ br->dev->name);
+ }
+#endif
+
return 0;
err2:
br_fdb_delete_by_port(br, p, 1);
Index: linux-2.6/net/bridge/br_private.h
===================================================================
--- linux-2.6.orig/net/bridge/br_private.h
+++ linux-2.6/net/bridge/br_private.h
@@ -233,6 +233,8 @@ static inline int br_is_root_bridge(cons
extern void br_dev_setup(struct net_device *dev);
extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
struct net_device *dev);
+extern bool br_devices_support_netpoll(struct net_bridge *br);
+extern void br_netpoll_cleanup(struct net_device *br_dev);
/* br_fdb.c */
extern int br_fdb_init(void);
^ permalink raw reply
* [v4 Patch 3/3] bonding: make bonding support netpoll
From: Amerigo Wang @ 2010-04-27 7:56 UTC (permalink / raw)
To: linux-kernel
Cc: Matt Mackall, netdev, bridge, Andy Gospodarek, Neil Horman,
Amerigo Wang, Jeff Moyer, Stephen Hemminger, bonding-devel,
Jay Vosburgh, David Miller
In-Reply-To: <20100427075937.4908.18468.sendpatchset@localhost.localdomain>
Based on Andy's work, but I modified a lot.
Similar to the patch for bridge, this patch does:
1) implement the 2 methods to support netpoll for bonding;
2) modify netpoll during forwarding packets via bonding;
3) disable netpoll support of bonding when a netpoll-unabled device
is added to bonding;
4) enable netpoll support when all underlying devices support netpoll.
Cc: Andy Gospodarek <gospo@redhat.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Matt Mackall <mpm@selenic.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Jay Vosburgh <fubar@us.ibm.com>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: WANG Cong <amwang@redhat.com>
---
Index: linux-2.6/drivers/net/bonding/bond_main.c
===================================================================
--- linux-2.6.orig/drivers/net/bonding/bond_main.c
+++ linux-2.6/drivers/net/bonding/bond_main.c
@@ -59,6 +59,7 @@
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
+#include <linux/netpoll.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/etherdevice.h>
@@ -430,7 +431,18 @@ int bond_dev_queue_xmit(struct bonding *
}
skb->priority = 1;
- dev_queue_xmit(skb);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
+ struct netpoll *np = bond->dev->npinfo->netpoll;
+ slave_dev->npinfo = bond->dev->npinfo;
+ np->real_dev = np->dev = skb->dev;
+ slave_dev->priv_flags |= IFF_IN_NETPOLL;
+ netpoll_send_skb(np, skb);
+ slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
+ np->dev = bond->dev;
+ } else
+#endif
+ dev_queue_xmit(skb);
return 0;
}
@@ -1329,6 +1341,61 @@ static void bond_detach_slave(struct bon
bond->slave_cnt--;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * You must hold read lock on bond->lock before calling this.
+ */
+static bool slaves_support_netpoll(struct net_device *bond_dev)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i = 0;
+ bool ret = true;
+
+ bond_for_each_slave(bond, slave, i) {
+ if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL)
+ || !slave->dev->netdev_ops->ndo_poll_controller)
+ ret = false;
+ }
+ return i != 0 && ret;
+}
+
+static void bond_poll_controller(struct net_device *bond_dev)
+{
+ struct net_device *dev = bond_dev->npinfo->netpoll->real_dev;
+ if (dev != bond_dev)
+ netpoll_poll_dev(dev);
+}
+
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ const struct net_device_ops *ops;
+ int i;
+
+ read_lock(&bond->lock);
+ bond_dev->npinfo = NULL;
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->dev) {
+ ops = slave->dev->netdev_ops;
+ if (ops->ndo_netpoll_cleanup)
+ ops->ndo_netpoll_cleanup(slave->dev);
+ else
+ slave->dev->npinfo = NULL;
+ }
+ }
+ read_unlock(&bond->lock);
+}
+
+#else
+
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+}
+
+#endif
+
/*---------------------------------- IOCTL ----------------------------------*/
static int bond_sethwaddr(struct net_device *bond_dev,
@@ -1735,6 +1802,18 @@ int bond_enslave(struct net_device *bond
bond_set_carrier(bond);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (slaves_support_netpoll(bond_dev)) {
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ if (bond_dev->npinfo)
+ slave_dev->npinfo = bond_dev->npinfo;
+ } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
+ bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
+ pr_info("New slave device %s does not support netpoll\n",
+ slave_dev->name);
+ pr_info("Disabling netpoll support for %s\n", bond_dev->name);
+ }
+#endif
read_unlock(&bond->lock);
res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1801,6 +1880,7 @@ int bond_release(struct net_device *bond
return -EINVAL;
}
+ netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE);
write_lock_bh(&bond->lock);
slave = bond_get_slave_by_dev(bond, slave_dev);
@@ -1929,6 +2009,17 @@ int bond_release(struct net_device *bond
netdev_set_master(slave_dev, NULL);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ read_lock_bh(&bond->lock);
+ if (slaves_support_netpoll(bond_dev))
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ read_unlock_bh(&bond->lock);
+ if (slave_dev->netdev_ops->ndo_netpoll_cleanup)
+ slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev);
+ else
+ slave_dev->npinfo = NULL;
+#endif
+
/* close slave before restoring its mac address */
dev_close(slave_dev);
@@ -4448,6 +4539,10 @@ static const struct net_device_ops bond_
.ndo_vlan_rx_register = bond_vlan_rx_register,
.ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_netpoll_cleanup = bond_netpoll_cleanup,
+ .ndo_poll_controller = bond_poll_controller,
+#endif
};
static void bond_destructor(struct net_device *bond_dev)
@@ -4541,6 +4636,8 @@ static void bond_uninit(struct net_devic
{
struct bonding *bond = netdev_priv(bond_dev);
+ bond_netpoll_cleanup(bond_dev);
+
/* Release the bonded slaves */
bond_release_all(bond_dev);
^ permalink raw reply
* Re: Intel Pro1000 on CN5020, hangs Uboot
From: Jack Daniel @ 2010-04-27 8:59 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <y2pf6b367b71004140118s93d7b47rfa88399bfbe5b91b@mail.gmail.com>
Just an update that "Intel Pro/1000 MT Desktop Adapter" have problems
booting on an Octeon 5xxx. The "GT" and "PT" adapters seem to work
fine.
Regards,
Jack
On Wed, Apr 14, 2010 at 1:48 PM, Jack Daniel <wanders.thirst@gmail.com> wrote:
> Hi,
>
> I have a OCTEON CN5020, on which I tried plugging in an Intel Pro 1000
> PCI NIC. But Uboot hangs with a trap exception. Uboot has no problems
> with a Realtek RTL8139 NIC PCI card that supports 100MBps. Could
> someone tell me the reason for such a behaviour?
>
> Regards,
> Jack
>
>
> Uboot Version (as reported by Uboot) : U-Boot 1.1.1 (Development
> build, svnversion: u-boot:47725, exec:47725)
> Uboot start up message:
> PAL rev: 1.01, MCU rev: 1.07, CPU voltage: 1.20
> DRAM: 512 MB
> Clearing DRAM....... done
> Flash: 8 MB
> BIST check passed.
> Starting PCI
> PCI Status: PCI 32-bit
> Reg: 0x0 0x0
> Reg: 0x1 0x62
> Reg: 0x2 0x0
> Reg: 0x3 0x0
> Reg: 0x4 0x0
> Reg: 0x5 0xE
> Reg: 0x6 0x1
> Reg: 0x7 0xFFFFFFFFC00D5C70
> Reg: 0x8 0x800119040000000E
> Reg: 0x9 0x61784
> Reg: 0xA 0xFFFFFFFFC0000A4C
> Reg: 0xB 0xFFFFFFFFC0062208
> Reg: 0xC 0xFFFFFFFFC0062550
> Reg: 0xD 0xFFFFFFFFC005E4A0
> Reg: 0xE 0x20
> Reg: 0xF 0x0
> Reg: 0x10 0xFFFFFFFFC00D5CA0
> Reg: 0x11 0xFFFFFFFFC008F490
> Reg: 0x12 0x0
> Reg: 0x13 0x0
> Reg: 0x14 0x0
> Reg: 0x15 0x0
> Reg: 0x16 0xFF00
> Reg: 0x17 0xFFFFFFFFC00D5CA6
> Reg: 0x18 0xFFFFFFFFC0062550
> Reg: 0x19 0xFFFFFFFFC0038E24
> Reg: 0x1A 0xFFFFFFFFFFFF8000
> Reg: 0x1B 0x30
> Reg: 0x1C 0xFFFFFFFFBFC621D0
> Reg: 0x1D 0xFFFFFFFFFFFF97F8
> Reg: 0x1E 0xFFFFFFFFC00D5CA4
> Reg: 0x1F 0xFFFFFFFFBFC00AE0
> status: 0x504000E7
> cause: 0x4000801C
> epc: 0xFFFFFFFFC0038EC8
> badvaddr: 0x0
>
^ permalink raw reply
* [PATCH 0/3] [RFC] ptp: IEEE 1588 clock support
From: Richard Cochran @ 2010-04-27 9:13 UTC (permalink / raw)
To: netdev
Now and again there has been some talk on this list of adding PTP
support into Linux. One part of the picture is already in place, the
SO_TIMESTAMPING API for hardware time stamping. It has been pointed
out that this API is not perfect, however, it is good enough for many
real world uses of IEEE 1588. The second needed part has not, AFAICT,
ever been addressed.
Here I offer an early draft of an idea how to bring the missing
functionality into Linux. I don't yet have all of the features
implemented, as described below. Still I would like to get your
feedback concerning this idea before getting too far into it. I do
have all of the hardware mentioned at hand, so I have a good idea that
the proposed API covers the features of those clocks.
Thanks in advance for your comments,
Richard
* PTP infrastructure for Linux
This patch set introduces support for IEEE 1588 PTP clocks in
Linux. Together with the SO_TIMESTAMPING socket options, this
presents standardized method for developing PTP user space programs,
synchronizing Linux with external clocks, and using the ancillary
features of PTP hardware clocks.
A new class driver exports a kernel interface for specific clock
drivers and a user space interface. The infrastructure supports a
complete set of PTP functionality.
+ Basic clock operations
- Set time
- Get time
- Shift the clock by a given offset atomically
- Adjust clock frequency
+ Ancillary clock features
- One short or periodic alarms, with signal delivery to user program
- Time stamp external events
- Period output signals configurable from user space
- Synchronization of the Linux system time via the PPS subsystem
** PTP kernel API
A PTP clock driver registers itself with the class driver. The
class driver handles all of the dealings with user space. The
author of a clock driver need only implement the details of
programming the clock hardware. The clock driver notifies the class
driver of asynchronous events (alarms and external time stamps) via
a simple message passing interface.
The class driver supports multiple PTP clock drivers. In normal use
cases, only one PTP clock is needed. However, for testing and
development, it can be useful to have more than one clock in a
single system, in order to allow performance comparisons.
** PTP user space API
The class driver creates a character device for each registered PTP
clock. User space programs may control the clock via standardized
ioctls. A program may query, enable, configure, and disable the
ancillary clock features. User space can receive time stamped
events via blocking read() and poll(). One shot and periodic
signals may be configured via an ioctl API with similar semantics
to the POSIX timer_settime() system call.
** Supported hardware
+ Standard Linux system timer
- No special PTP features
- For use with software time stamping
+ Freescale eTSEC gianfar
- 2 Time stamp external triggers, programmable polarity (opt. interrupt)
- 2 Alarm registers (optional interrupt)
- 3 Periodic signals (optional interrupt)
+ National DP83640
- 6 GPIOs programmable as inputs or outputs
- 6 GPIOs with dedicated functions (LED/JTAG/clock) can also be
used as general inputs or outputs
- GPIO inputs can time stamp external triggers
- GPIO outputs can produce periodic signals
- 1 interrupt pin
+ Intel IXP465
- Auxiliary Slave/Master Mode Snapshot (optional interrupt)
- Target Time (optional interrupt)
Richard Cochran (3):
ptp: Added a brand new class driver for ptp clocks.
ptp: Added a clock that uses the Linux system time.
ptp: Added a clock that uses the eTSEC found on the MPC85xx.
Documentation/ptp/testptp.c | 130 +++++++++++++++++
Documentation/ptp/testptp.mk | 33 +++++
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/net/Makefile | 1 +
drivers/net/gianfar_ptp.c | 269 +++++++++++++++++++++++++++++++++++
drivers/net/gianfar_ptp_reg.h | 107 ++++++++++++++
drivers/ptp/Kconfig | 51 +++++++
drivers/ptp/Makefile | 6 +
drivers/ptp/ptp_clock.c | 287 ++++++++++++++++++++++++++++++++++++++
drivers/ptp/ptp_linux.c | 119 ++++++++++++++++
include/linux/Kbuild | 1 +
include/linux/ptp_clock.h | 37 +++++
include/linux/ptp_clock_kernel.h | 132 +++++++++++++++++
kernel/time/ntp.c | 2 +
15 files changed, 1178 insertions(+), 0 deletions(-)
create mode 100644 Documentation/ptp/testptp.c
create mode 100644 Documentation/ptp/testptp.mk
create mode 100644 drivers/net/gianfar_ptp.c
create mode 100644 drivers/net/gianfar_ptp_reg.h
create mode 100644 drivers/ptp/Kconfig
create mode 100644 drivers/ptp/Makefile
create mode 100644 drivers/ptp/ptp_clock.c
create mode 100644 drivers/ptp/ptp_linux.c
create mode 100644 include/linux/ptp_clock.h
create mode 100644 include/linux/ptp_clock_kernel.h
^ permalink raw reply
* [PATCH 1/3] ptp: Added a brand new class driver for ptp clocks.
From: Richard Cochran @ 2010-04-27 9:14 UTC (permalink / raw)
To: netdev
This patch adds an infrastructure for hardware clocks that implement
IEEE 1588, the Precision Time Protocol (PTP). A class driver offers a
registration method to particular hardware clock drivers. Each clock is
exposed to user space as a character device with ioctls that allow tuning
of the PTP clock.
Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
---
Documentation/ptp/testptp.c | 130 +++++++++++++++++
Documentation/ptp/testptp.mk | 33 +++++
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/ptp/Kconfig | 26 ++++
drivers/ptp/Makefile | 5 +
drivers/ptp/ptp_clock.c | 287 ++++++++++++++++++++++++++++++++++++++
include/linux/Kbuild | 1 +
include/linux/ptp_clock.h | 37 +++++
include/linux/ptp_clock_kernel.h | 132 +++++++++++++++++
10 files changed, 654 insertions(+), 0 deletions(-)
create mode 100644 Documentation/ptp/testptp.c
create mode 100644 Documentation/ptp/testptp.mk
create mode 100644 drivers/ptp/Kconfig
create mode 100644 drivers/ptp/Makefile
create mode 100644 drivers/ptp/ptp_clock.c
create mode 100644 include/linux/ptp_clock.h
create mode 100644 include/linux/ptp_clock_kernel.h
diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c
new file mode 100644
index 0000000..d3ad918
--- /dev/null
+++ b/Documentation/ptp/testptp.c
@@ -0,0 +1,130 @@
+/*
+ * PTP 1588 clock support - User space test program
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/ptp_clock.h>
+
+static void usage (char* progname)
+{
+ fprintf(stderr,
+ "usage: %s [options] \n"
+ " -d name device to open \n"
+ " -f val adjust the ptp clock frequency by 'val' PPB \n"
+ " -g get the ptp clock time \n"
+ " -h prints this message \n"
+ " -s set the ptp clock time from the system time \n"
+ " -t val shift the ptp clock time by 'val' seconds \n"
+ " -v query the ptp clock api version \n"
+ ,progname);
+}
+
+int main(int argc,char *argv[])
+{
+ struct timespec ts;
+ char *progname;
+ int c, fd, val=0;
+
+ char *device = "/dev/ptp_clock_0";
+ int adjfreq=0x7fffffff;
+ int adjtime=0;
+ int gettime=0;
+ int settime=0;
+ int version=0;
+
+ progname = strrchr(argv[0],'/');
+ progname = progname ? 1+progname : argv[0];
+ while (EOF != (c = getopt(argc, argv, "d:f:ghst:v"))) {
+ switch (c) {
+ case 'd': device = optarg; break;
+ case 'f': adjfreq = atoi(optarg); break;
+ case 'g': gettime = 1; break;
+ case 's': settime = 1; break;
+ case 't': adjtime = atoi(optarg); break;
+ case 'v': version = 1; break;
+ case 'h': usage(progname); return 0;
+ case '?': usage(progname); return -1;
+ default: usage(progname); return -1;
+ }
+ }
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr,"cannot open %s: %s", device, strerror(errno));
+ return -1;
+ }
+
+ if (version) {
+ if (ioctl(fd, PTP_CLOCK_APIVERS, &val)) {
+ perror("PTP_CLOCK_APIVERS");
+ } else {
+ printf("version = 0x%08x \n",val);
+ }
+ }
+
+ if (0x7fffffff != adjfreq) {
+ if (ioctl(fd, PTP_CLOCK_ADJFREQ, adjfreq)) {
+ perror("PTP_CLOCK_ADJFREQ");
+ } else {
+ puts("frequency adjustment okay");
+ }
+ }
+
+ if (adjtime) {
+ ts.tv_sec = adjtime;
+ ts.tv_nsec = 0;
+ if (ioctl(fd, PTP_CLOCK_ADJTIME, &ts)) {
+ perror("PTP_CLOCK_ADJTIME");
+ } else {
+ puts("time shift okay");
+ }
+ }
+
+ if (gettime) {
+ if (ioctl(fd, PTP_CLOCK_GETTIME, &ts)) {
+ perror("PTP_CLOCK_GETTIME");
+ } else {
+ printf("clock time: %ld.%09ld or %s",
+ ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
+ }
+ }
+
+ if (settime) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ if (ioctl(fd, PTP_CLOCK_SETTIME, &ts)) {
+ perror("PTP_CLOCK_SETTIME");
+ } else {
+ puts("set time okay");
+ }
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/ptp/testptp.mk b/Documentation/ptp/testptp.mk
new file mode 100644
index 0000000..4ef2d97
--- /dev/null
+++ b/Documentation/ptp/testptp.mk
@@ -0,0 +1,33 @@
+# PTP 1588 clock support - User space test program
+#
+# Copyright (C) 2010 OMICRON electronics GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+CC = $(CROSS_COMPILE)gcc
+INC = -I$(KBUILD_OUTPUT)/usr/include
+CFLAGS = -Wall $(INC)
+LDLIBS = -lrt
+PROGS = testptp
+
+all: $(PROGS)
+
+testptp: testptp.o
+
+clean:
+ rm -f testptp.o
+
+distclean: clean
+ rm -f $(PROGS)
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a2b902f..774fbd7 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@ source "drivers/spi/Kconfig"
source "drivers/pps/Kconfig"
+source "drivers/ptp/Kconfig"
+
source "drivers/gpio/Kconfig"
source "drivers/w1/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 34f1e10..7dea7c8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-y += i2c/ media/
obj-$(CONFIG_PPS) += pps/
+obj-$(CONFIG_PTP_1588_CLOCK) += ptp/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
new file mode 100644
index 0000000..458d0fe
--- /dev/null
+++ b/drivers/ptp/Kconfig
@@ -0,0 +1,26 @@
+#
+# PTP clock support configuration
+#
+
+menu "PTP clock support"
+
+config PTP_1588_CLOCK
+ tristate "PTP clock support"
+ depends on EXPERIMENTAL
+ help
+ The IEEE 1588 standard defines a method to precisely
+ synchronize distributed clocks over Ethernet networks. The
+ standard defines a Precision Time Protocol (PTP), which can
+ be used to achieve synchronization within a few dozen
+ microseconds. In addition, with the help of special hardware
+ time stamping units, it can be possible to achieve
+ synchronization to within a few hundred nanoseconds.
+
+ This driver adds support for PTP clocks as character
+ devices. If you want to use a PTP clock, then you should
+ also enable at least one clock driver as well.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ptp_clock.ko.
+
+endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
new file mode 100644
index 0000000..b86695c
--- /dev/null
+++ b/drivers/ptp/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for PTP 1588 clock support.
+#
+
+obj-$(CONFIG_PTP_1588_CLOCK) += ptp_clock.o
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
new file mode 100644
index 0000000..a1c3846
--- /dev/null
+++ b/drivers/ptp/ptp_clock.c
@@ -0,0 +1,287 @@
+/*
+ * PTP 1588 clock support
+ *
+ * Partially adapted from the Linux PPS driver.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_clock.h>
+
+#define PTP_MAX_CLOCKS 4
+
+struct ptp_clock {
+ struct cdev cdev;
+ struct device *dev;
+ struct ptp_clock_info *info;
+ dev_t devid;
+ int index; /* index into clocks[], also the minor number */
+ struct semaphore mux; /* one process at a time on a device */
+};
+
+
+/* private globals */
+
+static const struct file_operations ptp_fops;
+static dev_t ptp_devt;
+static struct class *ptp_class;
+struct ptp_clock *clocks[PTP_MAX_CLOCKS];
+DEFINE_SPINLOCK(clocks_lock);
+
+/* public interface */
+
+int ptp_clock_register(struct ptp_clock_info *info)
+{
+ struct ptp_clock *ptp;
+ int err, i, index, major = MAJOR(ptp_devt);
+ unsigned long flags;
+
+ /* Find a free clock slot and reserve it. */
+ spin_lock_irqsave(&clocks_lock, flags);
+ for (i = 0; i < PTP_MAX_CLOCKS; i++) {
+ if (!clocks[i]) {
+ clocks[i] = (struct ptp_clock*)1;
+ break;
+ }
+ }
+ index = i < PTP_MAX_CLOCKS ? i : -1;
+ spin_unlock_irqrestore(&clocks_lock, flags);
+ if (-1 == index)
+ return -EBUSY;
+
+ /* Initialize a clock structure. */
+ err = -ENOMEM;
+ ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
+ if (ptp == NULL)
+ goto no_clock;
+
+ clocks[index] = ptp;
+
+ ptp->info = info;
+ ptp->devid = MKDEV(major, index);
+ ptp->index = index;
+ init_MUTEX(&ptp->mux);
+
+ /* Create a new device in our class. */
+ ptp->dev = device_create(ptp_class, NULL, ptp->devid, ptp,
+ "ptp_clock_%d", ptp->index);
+ if (IS_ERR(ptp->dev))
+ goto no_device;
+ dev_set_drvdata(ptp->dev, ptp);
+
+ /* Register a character device. */
+ cdev_init(&ptp->cdev, &ptp_fops);
+ ptp->cdev.owner = info->owner;
+ err = cdev_add(&ptp->cdev, ptp->devid, 1);
+ if (err)
+ goto no_cdev;
+
+ return 0;
+
+no_cdev:
+ device_destroy(ptp_class, ptp->devid);
+no_device:
+ kfree(ptp);
+no_clock:
+ clocks[index] = NULL;
+ return err;
+}
+EXPORT_SYMBOL(ptp_clock_register);
+
+int ptp_clock_unregister(struct ptp_clock_info *info)
+{
+ struct ptp_clock *ptp = NULL;
+ int i;
+
+ for (i = 0; i < PTP_MAX_CLOCKS; i++) {
+ if (clocks[i] && !strcmp(clocks[i]->info->name, info->name)) {
+ ptp = clocks[i];
+ break;
+ }
+ }
+ if (!ptp)
+ return -EINVAL;
+
+ cdev_del(&ptp->cdev);
+ device_destroy(ptp_class, ptp->devid);
+ kfree(ptp);
+ clocks[i] = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(ptp_clock_unregister);
+
+void ptp_clock_event(struct ptp_clock_event event)
+{
+}
+EXPORT_SYMBOL(ptp_clock_event);
+
+/* character device operations */
+
+static int ptp_ioctl(struct inode *node, struct file *fp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ptp_clock *ptp = fp->private_data;
+ struct ptp_clock_info *ops = ptp->info;
+ void *priv = ops->priv;
+ struct timespec ts;
+ int err = 0;
+
+ switch (cmd) {
+
+ case PTP_CLOCK_APIVERS:
+ err = put_user(PTP_CLOCK_VERSION, (u32 __user*)arg);
+ break;
+
+ case PTP_CLOCK_ADJFREQ:
+ err = ops->adjfreq(priv, arg);
+ break;
+
+ case PTP_CLOCK_ADJTIME:
+ if (copy_from_user(&ts, (void __user*)arg, sizeof(ts)))
+ err = -EFAULT;
+ else
+ err = ops->adjtime(priv, &ts);
+ break;
+
+ case PTP_CLOCK_GETTIME:
+ err = ops->gettime(priv, &ts);
+ if (err)
+ break;
+ err = copy_to_user((void __user*)arg, &ts, sizeof(ts));
+ break;
+
+ case PTP_CLOCK_SETTIME:
+ if (copy_from_user(&ts, (void __user*)arg, sizeof(ts)))
+ err = -EFAULT;
+ else
+ err = ops->settime(priv, &ts);
+ break;
+
+ default:
+ err = -ENOTTY;
+ break;
+ }
+ return err;
+}
+
+static int ptp_open(struct inode *inode, struct file *fp)
+{
+ struct ptp_clock *ptp;
+ ptp = container_of(inode->i_cdev, struct ptp_clock, cdev);
+
+ if (down_interruptible(&ptp->mux))
+ return -ERESTARTSYS;
+
+ fp->private_data = ptp;
+
+ return 0;
+}
+
+static unsigned int ptp_poll(struct file *fp, poll_table *wait)
+{
+ return 0;
+}
+
+static int ptp_release(struct inode *inode, struct file *fp)
+{
+ struct ptp_clock *ptp = fp->private_data;
+ up(&ptp->mux);
+ return 0;
+}
+
+static const struct file_operations ptp_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = ptp_ioctl,
+ .open = ptp_open,
+ .poll = ptp_poll,
+ .release = ptp_release,
+};
+
+/* sysfs */
+
+static ssize_t ptp_show_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ return sprintf(buf,
+ "maximum adjustment: %d\n"
+ "programmable alarms: %d\n"
+ "external timestamps: %d\n"
+ "periodic outputs: %d\n"
+ "has pps: %d\n"
+ "device index: %d\n"
+ ,ptp->info->max_adj
+ ,ptp->info->n_alarm
+ ,ptp->info->n_ext_ts
+ ,ptp->info->n_per_out
+ ,ptp->info->pps
+ ,ptp->index);
+}
+
+struct device_attribute ptp_attrs[] = {
+ __ATTR(capabilities, S_IRUGO, ptp_show_status, NULL),
+ __ATTR_NULL,
+};
+
+/* module operations */
+
+static void __exit ptp_exit(void)
+{
+ class_destroy(ptp_class);
+ unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
+}
+
+static int __init ptp_init(void)
+{
+ int err;
+
+ ptp_class = class_create(THIS_MODULE, "ptp");
+ if (!ptp_class) {
+ printk(KERN_ERR "ptp: failed to allocate class\n");
+ return -ENOMEM;
+ }
+ ptp_class->dev_attrs = ptp_attrs;
+
+ err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
+ if (err < 0) {
+ printk(KERN_ERR "ptp: failed to allocate char device region\n");
+ goto no_region;
+ }
+
+ pr_info("PTP clock support registered\n");
+ return 0;
+
+no_region:
+ class_destroy(ptp_class);
+ return err;
+}
+
+subsys_initcall(ptp_init);
+module_exit(ptp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clocks support");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2fc8e14..2d616cb 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -318,6 +318,7 @@ unifdef-y += poll.h
unifdef-y += ppp_defs.h
unifdef-y += ppp-comp.h
unifdef-y += pps.h
+unifdef-y += ptp_clock.h
unifdef-y += ptrace.h
unifdef-y += quota.h
unifdef-y += random.h
diff --git a/include/linux/ptp_clock.h b/include/linux/ptp_clock.h
new file mode 100644
index 0000000..5064b19
--- /dev/null
+++ b/include/linux/ptp_clock.h
@@ -0,0 +1,37 @@
+/*
+ * PTP 1588 clock support - user space interface
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PTP_CLOCK_H_
+#define _PTP_CLOCK_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define PTP_CLOCK_VERSION 0x00000001
+
+#define PTP_CLK_MAGIC '='
+
+#define PTP_CLOCK_APIVERS _IOR (PTP_CLK_MAGIC, 1, __u32)
+#define PTP_CLOCK_ADJFREQ _IO (PTP_CLK_MAGIC, 2)
+#define PTP_CLOCK_ADJTIME _IOW (PTP_CLK_MAGIC, 3, struct timespec)
+#define PTP_CLOCK_GETTIME _IOR (PTP_CLK_MAGIC, 4, struct timespec)
+#define PTP_CLOCK_SETTIME _IOW (PTP_CLK_MAGIC, 5, struct timespec)
+
+#endif
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
new file mode 100644
index 0000000..fd80969
--- /dev/null
+++ b/include/linux/ptp_clock_kernel.h
@@ -0,0 +1,132 @@
+/*
+ * PTP 1588 clock support
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PTP_CLOCK_KERNEL_H_
+#define _PTP_CLOCK_KERNEL_H_
+
+enum ptp_clock_events {
+ PTP_CLOCK_ALARM,
+ PTP_CLOCK_EXTTS,
+ PTP_CLOCK_PEROUT,
+ PTP_CLOCK_PPS,
+};
+
+/**
+ * struct ptp_clock_request - parameter for the enable() operation
+ *
+ * @type: One of the ptp_clock_events enumeration values.
+ * @index: Selects one resource of the given type.
+ * @ts: Desired one shot or recurring period for alarms and output signals.
+ */
+
+struct ptp_clock_request {
+ int type;
+ int index;
+ struct itimerspec ts;
+};
+
+/**
+ * struct ptp_clock_info - decribes a PTP hardware clock
+ *
+ * @owner: The clock driver should set to THIS_MODULE.
+ * @name: A short name to identify the clock.
+ * @max_adj: The maximum possible frequency adjustment, in parts per billon.
+ * @n_alarm: The number of programmable alarms.
+ * @n_ext_ts: The number of external time stamp channels.
+ * @n_per_out: The number of programmable periodic signals.
+ * @pps: Indicates whether the clock supports a PPS callback.
+ * @priv: Passed to the clock operations, for the driver's private use.
+ *
+ * clock operations
+ *
+ * @adjfreq: Adjusts the frequency of the hardware clock.
+ * parameter delta: Desired period change in parts per billion.
+ *
+ * @adjtime: Shifts the time of the hardware clock.
+ * parameter ts: Desired change in seconds and nanoseconds.
+ *
+ * @gettime: Reads the current time from the hardware clock.
+ * parameter ts: Holds the result.
+ *
+ * @settime: Set the current time on the hardware clock.
+ * parameter ts: Time value to set.
+ *
+ * @enable: Request driver to enable or disable an ancillary feature.
+ * parameter request: Desired resource to enable or disable.
+ * parameter on: Caller passes one to enable or zero to disable.
+ *
+ * The callbacks must all return zero on success, non-zero otherwise.
+ */
+
+struct ptp_clock_info {
+ struct module *owner;
+ char name[16];
+ s32 max_adj;
+ int n_alarm;
+ int n_ext_ts;
+ int n_per_out;
+ int pps;
+ void *priv;
+ int (*adjfreq)(void *priv, s32 delta);
+ int (*adjtime)(void *priv, struct timespec *ts);
+ int (*gettime)(void *priv, struct timespec *ts);
+ int (*settime)(void *priv, struct timespec *ts);
+ int (*enable) (void *priv, struct ptp_clock_request request, int on);
+};
+
+/**
+ * ptp_clock_register() - register a PTP hardware clock driver
+ *
+ * @info: Structure describing the new clock.
+ */
+
+extern int ptp_clock_register(struct ptp_clock_info *info);
+
+/**
+ * ptp_clock_unregister() - unregister a PTP hardware clock driver
+ *
+ * @info: The clock to remove from service.
+ */
+
+extern int ptp_clock_unregister(struct ptp_clock_info *info);
+
+/**
+ * struct ptp_clock_event - decribes a PTP hardware clock event
+ *
+ * @type: One of the ptp_clock_events enumeration values.
+ * @index: Identifies the source of the event.
+ * @timestamp: When the event occured.
+ */
+
+struct ptp_clock_event {
+ int type;
+ int index;
+ u64 timestamp;
+};
+
+/**
+ * ptp_clock_event() - notify the PTP layer about an event
+ *
+ * @event: Message structure describing the event.
+ */
+
+extern void ptp_clock_event(struct ptp_clock_event event);
+
+#endif
--
1.6.0.4
^ permalink raw reply related
* [PATCH 2/3] ptp: Added a clock that uses the Linux system time.
From: Richard Cochran @ 2010-04-27 9:14 UTC (permalink / raw)
To: netdev
This PTP clock simply uses the NTP time adjustment system calls. The
driver can be used in systems that lack a special hardware PTP clock.
Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
---
drivers/ptp/Kconfig | 12 +++++
drivers/ptp/Makefile | 1 +
drivers/ptp/ptp_linux.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++
kernel/time/ntp.c | 2 +
4 files changed, 134 insertions(+), 0 deletions(-)
create mode 100644 drivers/ptp/ptp_linux.c
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 458d0fe..7113bef 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -23,4 +23,16 @@ config PTP_1588_CLOCK
To compile this driver as a module, choose M here: the module
will be called ptp_clock.ko.
+config PTP_1588_CLOCK_LINUX
+ tristate "Linux system timer as PTP clock"
+ depends on PTP_1588_CLOCK
+ help
+ This driver adds support for using the standard Linux time
+ source as a PTP clock. This clock is only useful if your PTP
+ programs are using software time stamps for the PTP Ethernet
+ packets.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ptp_linux.ko.
+
endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index b86695c..1651d52 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_PTP_1588_CLOCK) += ptp_clock.o
+obj-$(CONFIG_PTP_1588_CLOCK_LINUX) += ptp_linux.o
diff --git a/drivers/ptp/ptp_linux.c b/drivers/ptp/ptp_linux.c
new file mode 100644
index 0000000..0eaa6c3
--- /dev/null
+++ b/drivers/ptp/ptp_linux.c
@@ -0,0 +1,119 @@
+/*
+ * PTP 1588 clock using the Linux system clock
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timex.h>
+
+#include <linux/ptp_clock_kernel.h>
+
+DEFINE_SPINLOCK(adjtime_lock);
+
+static int ptp_linux_adjfreq(void *priv, s32 delta)
+{
+ struct timex txc;
+ s64 tmp = delta;
+ int err;
+ txc.freq = div_s64(tmp<<16, 1000);
+ txc.modes = ADJ_FREQUENCY;
+ err = do_adjtimex(&txc);
+ return err < 0 ? err : 0;
+}
+
+static int ptp_linux_adjtime(void *priv, struct timespec *ts)
+{
+ s64 delta;
+ ktime_t now;
+ struct timespec t2;
+ unsigned long flags;
+ int err;
+
+ delta = 1000000000LL * ts->tv_sec + ts->tv_nsec;
+
+ spin_lock_irqsave(&adjtime_lock, flags);
+
+ now = ktime_get_real();
+
+ now = delta < 0 ? ktime_sub_ns(now,-delta) : ktime_add_ns(now,delta);
+
+ t2 = ktime_to_timespec(now);
+
+ err = do_settimeofday(&t2);
+
+ spin_unlock_irqrestore(&adjtime_lock, flags);
+
+ return err;
+}
+
+static int ptp_linux_gettime(void *priv, struct timespec *ts)
+{
+ getnstimeofday(ts);
+ return 0;
+}
+
+static int ptp_linux_settime(void *priv, struct timespec *ts)
+{
+ return do_settimeofday(ts);
+}
+
+static int ptp_linux_enable(void *priv, struct ptp_clock_request rq, int on)
+{
+ /* We do not offer any ancillary features at all. */
+ return -EINVAL;
+}
+
+struct ptp_clock_info ptp_linux_caps = {
+ .owner = THIS_MODULE,
+ .name = "Linux timer",
+ .max_adj = 512000,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .priv = NULL,
+ .adjfreq = ptp_linux_adjfreq,
+ .adjtime = ptp_linux_adjtime,
+ .gettime = ptp_linux_gettime,
+ .settime = ptp_linux_settime,
+ .enable = ptp_linux_enable,
+};
+
+/* module operations */
+
+static void __exit ptp_linux_exit(void)
+{
+ ptp_clock_unregister(&ptp_linux_caps);
+}
+
+static int __init ptp_linux_init(void)
+{
+ int err;
+ err = ptp_clock_register(&ptp_linux_caps);
+ return err;
+}
+
+subsys_initcall(ptp_linux_init);
+module_exit(ptp_linux_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the Linux system timer");
+MODULE_LICENSE("GPL");
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 7c0f180..efd1ff8 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -14,6 +14,7 @@
#include <linux/timex.h>
#include <linux/time.h>
#include <linux/mm.h>
+#include <linux/module.h>
/*
* NTP timekeeping variables:
@@ -535,6 +536,7 @@ int do_adjtimex(struct timex *txc)
return result;
}
+EXPORT_SYMBOL(do_adjtimex);
static int __init ntp_tick_adj_setup(char *str)
{
--
1.6.0.4
^ permalink raw reply related
* [PATCH 3/3] ptp: Added a clock that uses the eTSEC found on the MPC85xx.
From: Richard Cochran @ 2010-04-27 9:14 UTC (permalink / raw)
To: netdev
The eTSEC includes a PTP clock with quite a few features. This patch adds
support for the basic clock adjustment functions.
Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
---
drivers/net/Makefile | 1 +
drivers/net/gianfar_ptp.c | 269 +++++++++++++++++++++++++++++++++++++++++
drivers/net/gianfar_ptp_reg.h | 107 ++++++++++++++++
drivers/ptp/Kconfig | 13 ++
4 files changed, 390 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/gianfar_ptp.c
create mode 100644 drivers/net/gianfar_ptp_reg.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ebf80b9..8f2c2ff 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_ATL2) += atlx/
obj-$(CONFIG_ATL1E) += atl1e/
obj-$(CONFIG_ATL1C) += atl1c/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
obj-$(CONFIG_TEHUTI) += tehuti.o
obj-$(CONFIG_ENIC) += enic/
obj-$(CONFIG_JME) += jme.o
diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c
new file mode 100644
index 0000000..eed3246
--- /dev/null
+++ b/drivers/net/gianfar_ptp.c
@@ -0,0 +1,269 @@
+/*
+ * PTP 1588 clock using the eTSEC
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timex.h>
+#include <asm/io.h>
+
+#include <linux/ptp_clock_kernel.h>
+
+#include "gianfar_ptp_reg.h"
+
+/*
+ *
+ * TODO - get the following from device tree
+ *
+ */
+#define TMR_BASE_KERNEL 0xe0024e00 // CONFIG_PPC_85xx 0xffe24e00
+#define TIMER_OSC 166666666
+#define TCLK_PERIOD 10
+#define NOMINAL_FREQ 100000000
+#define DEF_TMR_PRSC 100
+#define DEF_TMR_ADD 0x999999A4
+#define DEFAULT_CKSEL 1
+
+#define REG_SIZE (4 + TMR_ETTS2_L)
+
+struct etsects {
+ void *regs;
+ u32 timer_osc; /* Hz */
+ u32 tclk_period; /* nanoseconds */
+ s64 nominal_freq; /* Hz */
+ u32 tmr_prsc;
+ u32 tmr_add;
+ u32 cksel;
+};
+
+/* Private globals */
+static struct etsects the_clock;
+DEFINE_SPINLOCK(adjtime_lock);
+
+/*
+ * Register access functions
+ */
+
+static inline u32 reg_read(struct etsects *etsects, unsigned long offset)
+{
+ return in_be32(etsects->regs + offset);
+}
+
+static inline void reg_write(struct etsects *etsects,
+ unsigned long offset, u32 val)
+{
+ out_be32(etsects->regs + offset, val);
+}
+
+static u64 tmr_cnt_read(struct etsects *etsects)
+{
+ u64 ns;
+ u32 lo, hi;
+ lo = reg_read(etsects, TMR_CNT_L);
+ hi = reg_read(etsects, TMR_CNT_H);
+ ns = ((u64) hi) << 32;
+ ns |= lo;
+ return ns;
+}
+
+static void tmr_cnt_write(struct etsects *etsects, u64 ns)
+{
+ u32 hi = ns >> 32;
+ u32 lo = ns & 0xffffffff;
+ reg_write(etsects, TMR_CNT_L, lo);
+ reg_write(etsects, TMR_CNT_H, hi);
+}
+
+static void set_alarm(struct etsects *etsects)
+{
+ u64 ns;
+ u32 lo, hi;
+ ns = tmr_cnt_read(etsects) + 1500000000ULL;
+ ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
+ ns -= etsects->tclk_period;
+ hi = ns >> 32;
+ lo = ns & 0xffffffff;
+ reg_write(etsects, TMR_ALARM1_L, lo);
+ reg_write(etsects, TMR_ALARM1_H, hi);
+}
+
+static void set_fipers(struct etsects *etsects)
+{
+ u32 tmr_ctrl = reg_read(etsects, TMR_CTRL);
+
+ reg_write(etsects, TMR_CTRL, tmr_ctrl & (~TE));
+ reg_write(etsects, TMR_PRSC, etsects->tmr_prsc);
+ reg_write(etsects, TMR_FIPER1, 0x3B9AC9F6);
+ reg_write(etsects, TMR_FIPER2, 0x00018696);
+ set_alarm(etsects);
+ reg_write(etsects, TMR_CTRL, tmr_ctrl|TE);
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_gianfar_adjfreq(void *priv, s32 ppb)
+{
+ u64 adj;
+ u32 diff, tmr_add;
+ int neg_adj = 0;
+ struct etsects *etsects = priv;
+
+ if (!ppb)
+ return 0;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+ tmr_add = etsects->tmr_add;
+ adj = tmr_add;
+ adj *= ppb;
+ diff = div_u64(adj, 1000000000ULL);
+
+ tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
+
+ reg_write(etsects, TMR_ADD, tmr_add);
+
+ return 0;
+}
+
+static int ptp_gianfar_adjtime(void *priv, struct timespec *ts)
+{
+ s64 delta, now;
+ unsigned long flags;
+ struct etsects *etsects = priv;
+
+ delta = 1000000000LL * ts->tv_sec;
+ delta += ts->tv_nsec;
+
+ spin_lock_irqsave(&adjtime_lock, flags);
+
+ now = tmr_cnt_read(etsects);
+ now += delta;
+ tmr_cnt_write(etsects, now);
+
+ spin_unlock_irqrestore(&adjtime_lock, flags);
+
+ set_fipers(etsects);
+
+ return 0;
+}
+
+static int ptp_gianfar_gettime(void *priv, struct timespec *ts)
+{
+ u64 ns;
+ u32 remainder;
+ struct etsects *etsects = priv;
+ ns = tmr_cnt_read(etsects);
+ ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+ ts->tv_nsec = remainder;
+ return 0;
+}
+
+static int ptp_gianfar_settime(void *priv, struct timespec *ts)
+{
+ u64 ns;
+ struct etsects *etsects = priv;
+ ns = ts->tv_sec * 1000000000ULL;
+ ns += ts->tv_nsec;
+ tmr_cnt_write(etsects, ns);
+ set_fipers(etsects);
+ return 0;
+}
+
+static int ptp_gianfar_enable(void *priv, struct ptp_clock_request rq, int on)
+{
+ /* We do not (yet) offer any ancillary features. */
+ return -EINVAL;
+}
+
+struct ptp_clock_info ptp_gianfar_caps = {
+ .owner = THIS_MODULE,
+ .name = "gianfar clock",
+ .max_adj = 512000,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .priv = &the_clock,
+ .adjfreq = ptp_gianfar_adjfreq,
+ .adjtime = ptp_gianfar_adjtime,
+ .gettime = ptp_gianfar_gettime,
+ .settime = ptp_gianfar_settime,
+ .enable = ptp_gianfar_enable,
+};
+
+/* module operations */
+
+static void __exit ptp_gianfar_exit(void)
+{
+ ptp_clock_unregister(&ptp_gianfar_caps);
+ iounmap(the_clock.regs);
+}
+
+static int __init ptp_gianfar_init(void)
+{
+ struct etsects *etsects = &the_clock;
+ struct timespec now;
+ phys_addr_t reg_addr = TMR_BASE_KERNEL;
+ unsigned long reg_size = REG_SIZE;
+ u32 tmr_ctrl;
+ int err;
+
+ etsects->regs = ioremap(reg_addr, reg_size);
+ if (!etsects->regs) {
+ pr_err("ioremap ptp registers failed\n");
+ return -EINVAL;
+ }
+ etsects->timer_osc = TIMER_OSC;
+ etsects->tclk_period = TCLK_PERIOD;
+ etsects->nominal_freq = NOMINAL_FREQ;
+ etsects->tmr_prsc = DEF_TMR_PRSC;
+ etsects->tmr_add = DEF_TMR_ADD;
+ etsects->cksel = DEFAULT_CKSEL;
+
+ tmr_ctrl =
+ (etsects->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
+ (etsects->cksel & CKSEL_MASK) << CKSEL_SHIFT;
+
+ getnstimeofday(&now);
+ ptp_gianfar_settime(etsects, &now);
+
+ reg_write(etsects, TMR_CTRL, tmr_ctrl);
+ reg_write(etsects, TMR_ADD, etsects->tmr_add);
+ reg_write(etsects, TMR_PRSC, etsects->tmr_prsc);
+ reg_write(etsects, TMR_FIPER1, 0x3B9AC9F6);
+ reg_write(etsects, TMR_FIPER2, 0x00018696);
+ set_alarm(etsects);
+ reg_write(etsects, TMR_CTRL, tmr_ctrl|FS|RTPE|TE);
+
+ err = ptp_clock_register(&ptp_gianfar_caps);
+ return err;
+}
+
+subsys_initcall(ptp_gianfar_init);
+module_exit(ptp_gianfar_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the eTSEC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/gianfar_ptp_reg.h b/drivers/net/gianfar_ptp_reg.h
new file mode 100644
index 0000000..9c94677
--- /dev/null
+++ b/drivers/net/gianfar_ptp_reg.h
@@ -0,0 +1,107 @@
+/* gianfar_ptp_reg.h
+ * Generated by regen.tcl on Thu Apr 15 02:21:02 PM CEST 2010
+ *
+ * PTP 1588 clock using the gianfar eTSEC
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _GIANFAR_PTP_REG_H_
+#define _GIANFAR_PTP_REG_H_
+
+#define TMR_CTRL 0x00000000 /* Timer control register */
+#define TMR_TEVENT 0x00000004 /* Timestamp event register */
+#define TMR_TEMASK 0x00000008 /* Timer event mask register */
+#define TMR_PEVENT 0x0000000c /* Timestamp event register */
+#define TMR_PEMASK 0x00000010 /* Timer event mask register */
+#define TMR_STAT 0x00000014 /* Timestamp status register */
+#define TMR_CNT_H 0x00000018 /* Timer counter high register */
+#define TMR_CNT_L 0x0000001c /* Timer counter low register */
+#define TMR_ADD 0x00000020 /* Timer drift compensation addend register */
+#define TMR_ACC 0x00000024 /* Timer accumulator register */
+#define TMR_PRSC 0x00000028 /* Timer prescale */
+#define TMROFF_H 0x00000030 /* Timer offset high */
+#define TMROFF_L 0x00000034 /* Timer offset low */
+#define TMR_ALARM1_H 0x00000040 /* Timer alarm 1 high register */
+#define TMR_ALARM1_L 0x00000044 /* Timer alarm 1 high register */
+#define TMR_ALARM2_H 0x00000048 /* Timer alarm 2 high register */
+#define TMR_ALARM2_L 0x0000004c /* Timer alarm 2 high register */
+#define TMR_FIPER1 0x00000080 /* Timer fixed period interval */
+#define TMR_FIPER2 0x00000084 /* Timer fixed period interval */
+#define TMR_FIPER3 0x00000088 /* Timer fixed period interval */
+#define TMR_ETTS1_H 0x000000a0 /* Timestamp of general purpose external trigger */
+#define TMR_ETTS1_L 0x000000a4 /* Timestamp of general purpose external trigger */
+#define TMR_ETTS2_H 0x000000a8 /* Timestamp of general purpose external trigger */
+#define TMR_ETTS2_L 0x000000ac /* Timestamp of general purpose external trigger */
+
+/* Bit definitions for the TMR_CTRL register */
+#define ALM1P (1<<31) /* Alarm1 output polarity */
+#define ALM2P (1<<30) /* Alarm2 output polarity */
+#define FS (1<<28) /* FIPER start indication */
+#define PP1L (1<<27) /* Fiper1 pulse loopback mode enabled. */
+#define PP2L (1<<26) /* Fiper2 pulse loopback mode enabled. */
+#define TCLK_PERIOD_SHIFT (16) /* 1588 timer reference clock period. */
+#define TCLK_PERIOD_MASK (0x3ff)
+#define RTPE (1<<15) /* Record Tx Timestamp to PAL Enable. */
+#define FRD (1<<14) /* FIPER Realignment Disable */
+#define ESFDP (1<<11) /* External Tx/Rx SFD Polarity. */
+#define ESFDE (1<<10) /* External Tx/Rx SFD Enable. */
+#define ETEP2 (1<<9) /* External trigger 2 edge polarity */
+#define ETEP1 (1<<8) /* External trigger 1 edge polarity */
+#define COPH (1<<7) /* Generated clock (TSEC_1588_GCLK) output phase. */
+#define CIPH (1<<6) /* External oscillator input clock phase. */
+#define TMSR (1<<5) /* Timer soft reset. When enabled, it resets all the timer registers and state machines. */
+#define BYP (1<<3) /* Bypass drift compensated clock */
+#define TE (1<<2) /* 1588 timer enable. If not enabled, all the timer registers and state machines are disabled. */
+#define CKSEL_SHIFT (0) /* 1588 Timer reference clock source select. */
+#define CKSEL_MASK (0x3)
+
+/* Bit definitions for the TMR_TEVENT register */
+#define ETS2 (1<<25) /* External trigger 2 timestamp sampled */
+#define ETS1 (1<<24) /* External trigger 1 timestamp sampled */
+#define ALM2 (1<<17) /* Current time equaled alarm time register 2 */
+#define ALM1 (1<<16) /* Current time equaled alarm time register 1 */
+#define PP1 (1<<7) /* Indicates that a periodic pulse has been generated based on FIPER1 register */
+#define PP2 (1<<6) /* Indicates that a periodic pulse has been generated based on FIPER2 register */
+#define PP3 (1<<5) /* Indicates that a periodic pulse has been generated based on FIPER3 register */
+
+/* Bit definitions for the TMR_TEMASK register */
+#define ETS2EN (1<<25) /* External trigger 2 timestamp sample event enable */
+#define ETS1EN (1<<24) /* External trigger 1 timestamp sample event enable */
+#define ALM2EN (1<<17) /* Timer ALM2 event enable */
+#define ALM1EN (1<<16) /* Timer ALM1 event enable */
+#define PP1EN (1<<7) /* Periodic pulse event 1 enable */
+#define PP2EN (1<<6) /* Periodic pulse event 2 enable */
+
+/* Bit definitions for the TMR_PEVENT register */
+#define TXP2 (1<<9) /* Indicates that a PTP frame has been transmitted and its timestamp is stored in TXTS2 register */
+#define TXP1 (1<<8) /* Indicates that a PTP frame has been transmitted and its timestamp is stored in TXTS1 register */
+#define RXP (1<<0) /* Indicates that a PTP frame has been received */
+
+/* Bit definitions for the TMR_PEMASK register */
+#define TXP2EN (1<<9) /* Transmit PTP packet event 2 enable */
+#define TXP1EN (1<<8) /* Transmit PTP packet event 1 enable */
+#define RXPEN (1<<0) /* Receive PTP packet event enable */
+
+/* Bit definitions for the TMR_STAT register */
+#define STAT_VEC_SHIFT (0) /* Timer general purpose status vector */
+#define STAT_VEC_MASK (0x3f)
+
+/* Bit definitions for the TMR_PRSC register */
+#define PRSC_OCK_SHIFT (0) /* Output clock division/prescale factor. */
+#define PRSC_OCK_MASK (0xffff)
+
+#endif
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 7113bef..2f8ab67 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -35,4 +35,17 @@ config PTP_1588_CLOCK_LINUX
To compile this driver as a module, choose M here: the module
will be called ptp_linux.ko.
+config PTP_1588_CLOCK_GIANFAR
+ tristate "Freescale eTSEC as PTP clock"
+ depends on PTP_1588_CLOCK
+ depends on GIANFAR
+ help
+ This driver adds support for using the eTSEC as a PTP
+ clock. This clock is only useful if your PTP programs are
+ getting hardware time stamps on the PTP Ethernet packets
+ using the SO_TIMESTAMPING API.
+
+ To compile this driver as a module, choose M here: the module
+ will be called gianfar_ptp.ko.
+
endmenu
--
1.6.0.4
^ permalink raw reply related
* [patch] ipheth: potential null dereferences on error path
From: Dan Carpenter @ 2010-04-27 9:20 UTC (permalink / raw)
To: Diego Giagio
Cc: David S. Miller, L. Alberto Giménez, netdev, kernel-janitors
The calls to usb_free_buffer() dereference rx_urb and tx_urb in the
parameter list but those could be NULL.
Signed-off-by: Dan Carpenter <error27@gmail.com>
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index fd10331..418825d 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -122,25 +122,25 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (tx_urb == NULL)
- goto error;
+ goto error_nomem;
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (rx_urb == NULL)
- goto error;
+ goto free_tx_urb;
tx_buf = usb_buffer_alloc(iphone->udev,
IPHETH_BUF_SIZE,
GFP_KERNEL,
&tx_urb->transfer_dma);
if (tx_buf == NULL)
- goto error;
+ goto free_rx_urb;
rx_buf = usb_buffer_alloc(iphone->udev,
IPHETH_BUF_SIZE,
GFP_KERNEL,
&rx_urb->transfer_dma);
if (rx_buf == NULL)
- goto error;
+ goto free_tx_buf;
iphone->tx_urb = tx_urb;
@@ -149,13 +149,14 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
iphone->rx_buf = rx_buf;
return 0;
-error:
- usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, rx_buf,
- rx_urb->transfer_dma);
+free_tx_buf:
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
tx_urb->transfer_dma);
+free_rx_urb:
usb_free_urb(rx_urb);
+free_tx_urb:
usb_free_urb(tx_urb);
+error_nomem:
return -ENOMEM;
}
^ permalink raw reply related
* [PATCH v2] net: reimplement softnet_data.output_queue as a FIFO queue
From: Changli Gao @ 2010-04-27 9:06 UTC (permalink / raw)
To: David S. Miller; +Cc: Eric Dumazet, netdev, Changli Gao
reimplement softnet_data.output_queue as a FIFO queue.
reimplement softnet_data.output_queue as a FIFO queue to keep the fairness among
the qdiscs rescheduled.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
include/linux/netdevice.h | 1 +
net/core/dev.c | 22 ++++++++++++----------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3c5ed5f..c04ca24 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1385,6 +1385,7 @@ static inline int unregister_gifconf(unsigned int family)
*/
struct softnet_data {
struct Qdisc *output_queue;
+ struct Qdisc **output_queue_tailp;
struct list_head poll_list;
struct sk_buff *completion_queue;
diff --git a/net/core/dev.c b/net/core/dev.c
index 4d43f1a..3d31491 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1557,8 +1557,9 @@ static inline void __netif_reschedule(struct Qdisc *q)
local_irq_save(flags);
sd = &__get_cpu_var(softnet_data);
- q->next_sched = sd->output_queue;
- sd->output_queue = q;
+ q->next_sched = NULL;
+ *sd->output_queue_tailp = q;
+ sd->output_queue_tailp = &q->next_sched;
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_restore(flags);
}
@@ -2529,6 +2530,7 @@ static void net_tx_action(struct softirq_action *h)
local_irq_disable();
head = sd->output_queue;
sd->output_queue = NULL;
+ sd->output_queue_tailp = &sd->output_queue;
local_irq_enable();
while (head) {
@@ -5594,7 +5596,6 @@ static int dev_cpu_callback(struct notifier_block *nfb,
void *ocpu)
{
struct sk_buff **list_skb;
- struct Qdisc **list_net;
struct sk_buff *skb;
unsigned int cpu, oldcpu = (unsigned long)ocpu;
struct softnet_data *sd, *oldsd;
@@ -5615,13 +5616,13 @@ static int dev_cpu_callback(struct notifier_block *nfb,
*list_skb = oldsd->completion_queue;
oldsd->completion_queue = NULL;
- /* Find end of our output_queue. */
- list_net = &sd->output_queue;
- while (*list_net)
- list_net = &(*list_net)->next_sched;
/* Append output queue from offline CPU. */
- *list_net = oldsd->output_queue;
- oldsd->output_queue = NULL;
+ if (oldsd->output_queue) {
+ *sd->output_queue_tailp = oldsd->output_queue;
+ sd->output_queue_tailp = oldsd->output_queue_tailp;
+ oldsd->output_queue = NULL;
+ oldsd->output_queue_tailp = &oldsd->output_queue;
+ }
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_enable();
@@ -5851,7 +5852,8 @@ static int __init net_dev_init(void)
skb_queue_head_init(&sd->input_pkt_queue);
sd->completion_queue = NULL;
INIT_LIST_HEAD(&sd->poll_list);
-
+ sd->output_queue = NULL;
+ sd->output_queue_tailp = &sd->output_queue;
#ifdef CONFIG_RPS
sd->csd.func = rps_trigger_softirq;
sd->csd.info = sd;
^ permalink raw reply related
* Re: [PATCH 0/3] [RFC] ptp: IEEE 1588 clock support
From: Richard Cochran @ 2010-04-27 10:20 UTC (permalink / raw)
To: netdev
In-Reply-To: <20100427091344.GA5086@riccoc20.at.omicron.at>
BTW,
To show how the API works from the user space, I also patches For the
popular ptpd program to that project.
https://sourceforge.net/tracker/?func=detail&aid=2992845&group_id=139814&atid=744634
Richard
^ permalink raw reply
* [net-2.6 PATCH] ixgbe: Properly display 1 gig downshift warning for backplane
From: Jeff Kirsher @ 2010-04-27 10:37 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Anjali Singhai, Jeff Kirsher
From: Anjali Singhai <anjali.singhai@intel.com>
Description: When using Intel smartspeed, the patch displays a
warning when the link down shifts to 1 Gig.
Signed-off-by: Anjali Singhai <anjali.singhai@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ixgbe/ixgbe_82599.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index b405a00..217237c 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -608,6 +608,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
s32 i, j;
bool link_up = false;
u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ struct ixgbe_adapter *adapter = hw->back;
hw_dbg(hw, "ixgbe_setup_mac_link_smartspeed.\n");
@@ -692,6 +693,10 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
autoneg_wait_to_complete);
out:
+ if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
+ netif_info(adapter, hw, adapter->netdev, "Smartspeed has"
+ " downgraded the link speed from the maximum"
+ " advertised\n");
return status;
}
^ permalink raw reply related
* [net-2.6 PATCH] ixgbe: Power down PHY during driver resets
From: Jeff Kirsher @ 2010-04-27 10:38 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Peter P Waskiewicz Jr, Jeff Kirsher
From: Peter Waskiewicz <peter.p.waskiewicz.jr@intel.com>
The PHY laser is still on during driver init. It's allowing
garbage to hit our FIFO, which eventually can cause the entire
device to die. Power down the laser while setting up the device,
and re-enable the laser before getting link.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ixgbe/ixgbe_82599.c | 62 ++++++++++++++++++++++++++++++---------
drivers/net/ixgbe/ixgbe_main.c | 22 ++++++++------
drivers/net/ixgbe/ixgbe_type.h | 2 +
3 files changed, 62 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index 217237c..78da45d 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -39,6 +39,8 @@
#define IXGBE_82599_MC_TBL_SIZE 128
#define IXGBE_82599_VFT_TBL_SIZE 128
+void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
+void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
@@ -69,8 +71,14 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
if (hw->phy.multispeed_fiber) {
/* Set up dual speed SFP+ support */
mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
+ mac->ops.disable_tx_laser =
+ &ixgbe_disable_tx_laser_multispeed_fiber;
+ mac->ops.enable_tx_laser =
+ &ixgbe_enable_tx_laser_multispeed_fiber;
mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber;
} else {
+ mac->ops.disable_tx_laser = NULL;
+ mac->ops.enable_tx_laser = NULL;
mac->ops.flap_tx_laser = NULL;
if ((mac->ops.get_media_type(hw) ==
ixgbe_media_type_backplane) &&
@@ -415,6 +423,44 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
return status;
}
+ /**
+ * ixgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser
+ * @hw: pointer to hardware structure
+ *
+ * The base drivers may require better control over SFP+ module
+ * PHY states. This includes selectively shutting down the Tx
+ * laser on the PHY, effectively halting physical link.
+ **/
+void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
+{
+ u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
+
+ /* Disable tx laser; allow 100us to go dark per spec */
+ esdp_reg |= IXGBE_ESDP_SDP3;
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+ IXGBE_WRITE_FLUSH(hw);
+ udelay(100);
+}
+
+/**
+ * ixgbe_enable_tx_laser_multispeed_fiber - Enable Tx laser
+ * @hw: pointer to hardware structure
+ *
+ * The base drivers may require better control over SFP+ module
+ * PHY states. This includes selectively turning on the Tx
+ * laser on the PHY, effectively starting physical link.
+ **/
+void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
+{
+ u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
+
+ /* Enable tx laser; allow 100ms to light up */
+ esdp_reg &= ~IXGBE_ESDP_SDP3;
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+ IXGBE_WRITE_FLUSH(hw);
+ msleep(100);
+}
+
/**
* ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser
* @hw: pointer to hardware structure
@@ -429,23 +475,11 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
**/
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
- u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
-
hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n");
if (hw->mac.autotry_restart) {
- /* Disable tx laser; allow 100us to go dark per spec */
- esdp_reg |= IXGBE_ESDP_SDP3;
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
- IXGBE_WRITE_FLUSH(hw);
- udelay(100);
-
- /* Enable tx laser; allow 100ms to light up */
- esdp_reg &= ~IXGBE_ESDP_SDP3;
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
- IXGBE_WRITE_FLUSH(hw);
- msleep(100);
-
+ ixgbe_disable_tx_laser_multispeed_fiber(hw);
+ ixgbe_enable_tx_laser_multispeed_fiber(hw);
hw->mac.autotry_restart = false;
}
}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 8f677cb..6c00ee4 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -2982,6 +2982,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
else
ixgbe_configure_msi_and_legacy(adapter);
+ /* enable the optics */
+ if (hw->phy.multispeed_fiber)
+ hw->mac.ops.enable_tx_laser(hw);
+
clear_bit(__IXGBE_DOWN, &adapter->state);
ixgbe_napi_enable_all(adapter);
@@ -3243,6 +3247,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* signal that we are down to the interrupt handler */
set_bit(__IXGBE_DOWN, &adapter->state);
+ /* power down the optics */
+ if (hw->phy.multispeed_fiber)
+ hw->mac.ops.disable_tx_laser(hw);
+
/* disable receive for all VFs and wait one second */
if (adapter->num_vfs) {
/* ping all the active vfs to let them know we are going down */
@@ -6253,6 +6261,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_eeprom;
}
+ /* power down the optics */
+ if (hw->phy.multispeed_fiber)
+ hw->mac.ops.disable_tx_laser(hw);
+
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &ixgbe_watchdog;
adapter->watchdog_timer.data = (unsigned long)adapter;
@@ -6400,16 +6412,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
del_timer_sync(&adapter->sfp_timer);
cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->sfp_task);
- if (adapter->hw.phy.multispeed_fiber) {
- struct ixgbe_hw *hw = &adapter->hw;
- /*
- * Restart clause 37 autoneg, disable and re-enable
- * the tx laser, to clear & alert the link partner
- * that it needs to restart autotry
- */
- hw->mac.autotry_restart = true;
- hw->mac.ops.flap_tx_laser(hw);
- }
cancel_work_sync(&adapter->multispeed_fiber_task);
cancel_work_sync(&adapter->sfp_config_module_task);
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index 4ec6dc1..534affc 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -2398,6 +2398,8 @@ struct ixgbe_mac_operations {
s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);
/* Link */
+ void (*disable_tx_laser)(struct ixgbe_hw *);
+ void (*enable_tx_laser)(struct ixgbe_hw *);
void (*flap_tx_laser)(struct ixgbe_hw *);
s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
^ permalink raw reply related
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