* Re: IP fragmentation broken in 3.6-rc ?
From: Julian Anastasov @ 2012-08-21 17:18 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Sylvain Munaut, netdev
In-Reply-To: <1345567633.5158.534.camel@edumazet-glaptop>
Hello,
On Tue, 21 Aug 2012, Eric Dumazet wrote:
> On Tue, 2012-08-21 at 19:34 +0300, Julian Anastasov wrote:
> > Hello,
> >
> > On Tue, 21 Aug 2012, Eric Dumazet wrote:
> >
> > > Following patch should help :
> > >
> > > diff --git a/include/net/dst.h b/include/net/dst.h
> > > index 621e351..a04aa37 100644
> > > --- a/include/net/dst.h
> > > +++ b/include/net/dst.h
> > > @@ -435,7 +435,7 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout)
> > > if (expires == 0)
> > > expires = 1;
> > >
> >
> > In theory, restart of PMTUD should not lead to
> > fatal problems, we will get new MTUs. But with such
> > change should be better, not much, because all MTU
> > events will come at same time, later timer will expire
> > and we will get again events from routers. The gain
> > will be an increased period (with milliseconds to seconds)
> > between PMTUD restarts. Compared to the 600-second timer,
> > this should be gain below 1% in reduced traffic for PMTUD.
> > Before now we started timer from first router, now we
> > will start/update timer period after event from last router.
> >
>
> Sorry I dont really understand what you mean
This timer is used only for PMTU, right?
RFC 1191 6.3. Purging stale PMTU information.
> > But ipv4_link_failure and ip6_link_failure want to stop
> > this timer by setting it to NOW (0). May be we have to add
> > also a !timeout check here or to leave the code as before?
> >
> > > - if (dst->expires == 0 || time_before(expires, dst->expires))
> > > + if (dst->expires == 0 || time_after(expires, dst->expires))
> > > dst->expires = expires;
> > > }
> >
> > The original problem should be somewhere else, I think.
>
> This patch fixed the problem for me.
OK, then I'll wait for the patch description
to understand what this change actually does. For me,
it just updates the timer on every MTU event, while
before the change, PMTU timer was started only once and
during the 600-second period it was not updated and also
there was the ability to invalidate the PMTU on link failure
by setting timer to jiffies, i.e. to stop this period
and to start new one with default MTU and possibly
new discovery procedure.
> My first patch was :
>
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index e4ba974..9858714 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -956,6 +956,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
> dst->obsolete = DST_OBSOLETE_KILL;
> } else {
> rt->rt_pmtu = mtu;
> + rt->dst.expires = 0;
> dst_set_expires(&rt->dst, ip_rt_mtu_expires);
This is better, does not break ipv4_link_failure.
There is a little race some ipv4_mtu() user to see
rt_pmtu != 0 and dst.expires = 0 and to fail in time_after_eq
test. May be that is why dst.expires is never set to 0.
But I still don't understand what both changes fix.
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply
* Re: [PATCH] tun: don't zeroize sock->file on detach
From: Neal Cardwell @ 2012-08-21 17:18 UTC (permalink / raw)
To: Stanislav Kinsbursky
Cc: David Miller, dhowells@redhat.com, netdev@vger.kernel.org,
rick.jones2@hp.com, ycheng@google.com,
linux-kernel@vger.kernel.org, mikulas
In-Reply-To: <5033B199.6080305@parallels.com>
On Tue, Aug 21, 2012 at 12:04 PM, Stanislav Kinsbursky
<skinsbursky@parallels.com> wrote:
> 10.08.2012 03:16, David Miller пишет:
>
>> From: Stanislav Kinsbursky <skinsbursky@parallels.com>
>> Date: Thu, 09 Aug 2012 16:50:40 +0400
>>
>>> This is a fix for bug, introduced in 3.4 kernel by commit
>>> 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d, which, among other things,
>>> replaced
>>> simple sock_put() by sk_release_kernel(). Below is sequence, which leads
>>> to
>>> oops for non-persistent devices:
>>>
>>> tun_chr_close()
>>> tun_detach() <== tun->socket.file = NULL
>>> tun_free_netdev()
>>> sk_release_sock()
>>> sock_release(sock->file == NULL)
>>> iput(SOCK_INODE(sock)) <== dereference on NULL pointer
>>>
>>> This patch just removes zeroing of socket's file from __tun_detach().
>>> sock_release() will do this.
>>>
>>> Cc: stable@vger.kernel.org
>>> Reported-by: Ruan Zhijie <ruanzhijie@hotmail.com>
>>> Tested-by: Ruan Zhijie <ruanzhijie@hotmail.com>
>>> Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
>>> Acked-by: Eric Dumazet <edumazet@google.com>
>>> Acked-by: Yuchung Cheng <ycheng@google.com>
>>> Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
>>
>>
>> Applied, thanks.
>>
>
> Hi, David.
> I found out, that this commit: b09e786bd1dd66418b69348cb110f3a64764626a
> was previous attempt to fix the problem.
> I believe this commit have to be dropped.
Have you tried testing with that commit reverted? AFAICT from reading
the code, if you revert b09e786bd1dd66418b69348cb110f3a64764626a then
the sockets_in_use count becomes incorrect, because sock_release()
will be calling this_cpu_sub() for each tun socket teardown when there
was no corresponding this_cpu_add() for the tun socket (because the
tun socket is not allocated with sock_alloc()).
Can you sketch in more detail why that commit should be dropped?
neal
^ permalink raw reply
* Re: IP fragmentation broken in 3.6-rc ?
From: Eric Dumazet @ 2012-08-21 17:23 UTC (permalink / raw)
To: Julian Anastasov; +Cc: Sylvain Munaut, netdev
In-Reply-To: <alpine.LFD.2.00.1208211954380.2149@ja.ssi.bg>
On Tue, 2012-08-21 at 20:18 +0300, Julian Anastasov wrote:
> Hello,
>
> On Tue, 21 Aug 2012, Eric Dumazet wrote:
> > My first patch was :
> >
> > diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> > index e4ba974..9858714 100644
> > --- a/net/ipv4/route.c
> > +++ b/net/ipv4/route.c
> > @@ -956,6 +956,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
> > dst->obsolete = DST_OBSOLETE_KILL;
> > } else {
> > rt->rt_pmtu = mtu;
> > + rt->dst.expires = 0;
> > dst_set_expires(&rt->dst, ip_rt_mtu_expires);
>
> This is better, does not break ipv4_link_failure.
> There is a little race some ipv4_mtu() user to see
> rt_pmtu != 0 and dst.expires = 0 and to fail in time_after_eq
> test. May be that is why dst.expires is never set to 0.
> But I still don't understand what both changes fix.
In fact we re-enter ip_rt_update_pmtu() if we receive a second ICMP,
and rt->rt_pmtu is already set, but dst is expired.
Thats why Sylvain said it was not happening in the 10 minutes following
boot.
So calling again dst_set_expires(&rt->dst, ip_rt_mtu_expires) does
nothing : rt_pmtu is ignored because dst.expires is too old.
Maybe we should just do :
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e4ba974..d0181e2 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -952,7 +952,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
ip_rt_build_flow_key(&fl4, sk, skb);
mtu = __ip_rt_update_pmtu(rt, &fl4, mtu);
- if (!rt->rt_pmtu) {
+ if (!rt->rt_pmtu || time_after_eq(jiffies, rt->dst.expires)) {
dst->obsolete = DST_OBSOLETE_KILL;
} else {
rt->rt_pmtu = mtu;
^ permalink raw reply related
* Re: Do I need to skb_put() Ethernet frames to a minimum of 60 bytes?
From: Arvid Brodin @ 2012-08-21 17:34 UTC (permalink / raw)
To: Nicolas Ferre; +Cc: Ben Hutchings, netdev@vger.kernel.org
In-Reply-To: <1344976557.2690.43.camel@bwh-desktop.uk.solarflarecom.com>
On 2012-08-14 22:35, Ben Hutchings wrote:
> On Tue, 2012-08-14 at 18:53 +0000, Arvid Brodin wrote:
>> Hi,
>>
>> If I create an sk_buff with a payload of less than 28 bytes (ethheader + data),
>> and send it using the cadence/macb (Ethernet) driver, I get
>>
>> eth0: TX underrun, resetting buffers
>>
>> Now I know the minimum Ethernet frame size is 64 bytes (including the 4-byte
>> FCS), but whose responsibility is it to pad the frame to this size if necessary?
>> Mine or the driver's - i.e. should I just skb_put() to the minimum size or
>> should I report the underrun as a driver bug?
>
> If the hardware doesn't pad frames automatically then it's the driver's
> reponsibility to do so.
>
Nicolas, can you take a look at this? At the moment I'm using the following change
in macb.c to avoid TX underruns on short packages:
--- a/drivers/net/ethernet/cadence/macb.c 2012-05-04 19:14:41.927719667 +0200
+++ b/drivers/net/ethernet/cadence/macb.c 2012-08-21 19:22:40.063739049 +0200
@@ -618,6 +618,7 @@ static void macb_poll_controller(struct
}
#endif
+#define MIN_ETHFRAME_LEN 60
static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
@@ -635,6 +636,12 @@ static int macb_start_xmit(struct sk_buf
printk("\n");
#endif
+ if (skb->len < MIN_ETHFRAME_LEN) {
+ /* Pad skb to minium Ethernet frame size */
+ if (skb_tailroom(skb) >= MIN_ETHFRAME_LEN - skb->len)
+ memset(skb_put(skb, MIN_ETHFRAME_LEN - skb->len), 0,
+ MIN_ETHFRAME_LEN - skb->len);
+ }
len = skb->len;
spin_lock_irqsave(&bp->lock, flags);
... but as you can see this is limited to linear skbs which has been allocated with
enough tailroom. Perhaps there are better ways to fix the problem? (Maybe the hardware
is actually doing the padding already and the problem has to do with the way the DMA
transfer is set up?)
--
Arvid Brodin | Consultant (Linux)
XDIN AB | Jan Stenbecks Torg 17 | SE-164 40 Kista | Sweden | xdin.com
^ permalink raw reply
* Re: Do I need to skb_put() Ethernet frames to a minimum of 60 bytes?
From: Eric Dumazet @ 2012-08-21 17:42 UTC (permalink / raw)
To: Arvid Brodin; +Cc: Nicolas Ferre, Ben Hutchings, netdev@vger.kernel.org
In-Reply-To: <5033C6B0.4060508@xdin.com>
On Tue, 2012-08-21 at 17:34 +0000, Arvid Brodin wrote:
> Nicolas, can you take a look at this? At the moment I'm using the following change
> in macb.c to avoid TX underruns on short packages:
>
> --- a/drivers/net/ethernet/cadence/macb.c 2012-05-04 19:14:41.927719667 +0200
> +++ b/drivers/net/ethernet/cadence/macb.c 2012-08-21 19:22:40.063739049 +0200
> @@ -618,6 +618,7 @@ static void macb_poll_controller(struct
> }
> #endif
>
> +#define MIN_ETHFRAME_LEN 60
> static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> struct macb *bp = netdev_priv(dev);
> @@ -635,6 +636,12 @@ static int macb_start_xmit(struct sk_buf
> printk("\n");
> #endif
>
> + if (skb->len < MIN_ETHFRAME_LEN) {
> + /* Pad skb to minium Ethernet frame size */
> + if (skb_tailroom(skb) >= MIN_ETHFRAME_LEN - skb->len)
> + memset(skb_put(skb, MIN_ETHFRAME_LEN - skb->len), 0,
> + MIN_ETHFRAME_LEN - skb->len);
> + }
> len = skb->len;
> spin_lock_irqsave(&bp->lock, flags);
>
>
> ... but as you can see this is limited to linear skbs which has been allocated with
> enough tailroom. Perhaps there are better ways to fix the problem? (Maybe the hardware
> is actually doing the padding already and the problem has to do with the way the DMA
> transfer is set up?)
>
other net drivers use skb_padto() for this ...
^ permalink raw reply
* Re: IP fragmentation broken in 3.6-rc ?
From: Sylvain Munaut @ 2012-08-21 17:44 UTC (permalink / raw)
Cc: netdev
In-Reply-To: <1345560131.5158.500.camel@edumazet-glaptop>
Hi,
> Following patch should help :
>
> diff --git a/include/net/dst.h b/include/net/dst.h
> index 621e351..a04aa37 100644
> --- a/include/net/dst.h
> +++ b/include/net/dst.h
> @@ -435,7 +435,7 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout)
> if (expires == 0)
> expires = 1;
>
> - if (dst->expires == 0 || time_before(expires, dst->expires))
> + if (dst->expires == 0 || time_after(expires, dst->expires))
> dst->expires = expires;
> }
Yes, this fixes it for me too . ( 2h without issues on 2 different machines )
But that line has been in the kernel for _years_ ... so I'm not sure
what's going on there ...
Cheers,
Sylvain
^ permalink raw reply
* Re: Do I need to skb_put() Ethernet frames to a minimum of 60 bytes?
From: Ben Hutchings @ 2012-08-21 18:07 UTC (permalink / raw)
To: Arvid Brodin; +Cc: Nicolas Ferre, netdev@vger.kernel.org
In-Reply-To: <5033C6B0.4060508@xdin.com>
On Tue, 2012-08-21 at 17:34 +0000, Arvid Brodin wrote:
> On 2012-08-14 22:35, Ben Hutchings wrote:
> > On Tue, 2012-08-14 at 18:53 +0000, Arvid Brodin wrote:
> >> Hi,
> >>
> >> If I create an sk_buff with a payload of less than 28 bytes (ethheader + data),
> >> and send it using the cadence/macb (Ethernet) driver, I get
> >>
> >> eth0: TX underrun, resetting buffers
> >>
> >> Now I know the minimum Ethernet frame size is 64 bytes (including the 4-byte
> >> FCS), but whose responsibility is it to pad the frame to this size if necessary?
> >> Mine or the driver's - i.e. should I just skb_put() to the minimum size or
> >> should I report the underrun as a driver bug?
> >
> > If the hardware doesn't pad frames automatically then it's the driver's
> > reponsibility to do so.
> >
>
> Nicolas, can you take a look at this? At the moment I'm using the following change
> in macb.c to avoid TX underruns on short packages:
>
> --- a/drivers/net/ethernet/cadence/macb.c 2012-05-04 19:14:41.927719667 +0200
> +++ b/drivers/net/ethernet/cadence/macb.c 2012-08-21 19:22:40.063739049 +0200
> @@ -618,6 +618,7 @@ static void macb_poll_controller(struct
> }
> #endif
>
> +#define MIN_ETHFRAME_LEN 60
<linux/etherdevice.h> already names this as ETH_ZLEN, by the way.
> static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> struct macb *bp = netdev_priv(dev);
> @@ -635,6 +636,12 @@ static int macb_start_xmit(struct sk_buf
> printk("\n");
> #endif
>
> + if (skb->len < MIN_ETHFRAME_LEN) {
> + /* Pad skb to minium Ethernet frame size */
> + if (skb_tailroom(skb) >= MIN_ETHFRAME_LEN - skb->len)
> + memset(skb_put(skb, MIN_ETHFRAME_LEN - skb->len), 0,
> + MIN_ETHFRAME_LEN - skb->len);
> + }
> len = skb->len;
> spin_lock_irqsave(&bp->lock, flags);
>
>
> ... but as you can see this is limited to linear skbs which has been allocated with
> enough tailroom. Perhaps there are better ways to fix the problem?
skb_padto() should be all you need. Note that it frees the skb on
failure, so you must just return NETDEV_TX_OK then.
Ben.
> (Maybe the hardware
> is actually doing the padding already and the problem has to do with the way the DMA
> transfer is set up?)
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH v6] bonding support for IPv6 transmit hashing
From: Jeremy Brookman @ 2012-08-21 18:11 UTC (permalink / raw)
To: linux, netdev
In-Reply-To: <20120702.224351.1587084404665143719.davem@davemloft.net>
> You should use a mix of tabs, as necessary, to get things to line up
> how I told you they need to line up.
Unless I'm missing something, this change doesn't seem to have made it
through to the kernel tip, but we could really use this bugfix. Is it
in a repository I didn't notice, or not yet through the review? If
it's not through the review, is any help needed to get it there?
Regards,
Jeremy Brookman
^ permalink raw reply
* [PATCH 0/8] netdev/MIPS: Improvements to octeon_mgmt Ethernet driver.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
From: David Daney <david.daney@cavium.com>
Recent additions to the OCTEON SoC family have included enhancements
to the MIX (octeon_mgmt) Ethernet hardware. These include:
o 1Gig support (up from 100M).
o Hardware timestamping for PTP.
Here we add support for these two features as well as some ethtool
improvements and cleanup of the MAC address handling.
Patch 1/8 is a prerequisite for the rest, and lives in the MIPS
architecture part of the tree. Since octeon_mgmt devices are only
found in OCTEON SoCs we could merge the whole set via Ralf's tree, or
get Ralf to affix his Acked-by and have it go via the netdev tree.
Chad Reese (1):
netdev: octeon_mgmt: Add hardware timestamp support.
David Daney (7):
MIPS: Octeon: Add octeon_io_clk_delay() function.
netdev: octeon_mgmt: Add support for 1Gig ports.
netdev: octeon_mgmt: Improve ethtool_ops.
netdev: octeon_mgmt: Set the parent device.
netdev: octeon_mgmt: Cleanup and modernize MAC address handling.
netdev: octeon_mgmt: Remove some useless 'inline'
netdev: octeon_mgmt: Make multi-line comment style consistent.
arch/mips/cavium-octeon/csrc-octeon.c | 93 +++--
arch/mips/cavium-octeon/setup.c | 3 +-
arch/mips/include/asm/octeon/octeon.h | 1 +
drivers/net/ethernet/octeon/octeon_mgmt.c | 554 ++++++++++++++++++++++++------
4 files changed, 512 insertions(+), 139 deletions(-)
--
1.7.11.4
^ permalink raw reply
* [PATCH 1/8] MIPS: Octeon: Add octeon_io_clk_delay() function.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <ddaney@caviumnetworks.com>
Also cleanup and fix octeon_init_cvmcount()
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
arch/mips/cavium-octeon/csrc-octeon.c | 93 ++++++++++++++++++++++++-----------
arch/mips/cavium-octeon/setup.c | 3 +-
arch/mips/include/asm/octeon/octeon.h | 1 +
3 files changed, 66 insertions(+), 31 deletions(-)
diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c
index ce6483a..0219395 100644
--- a/arch/mips/cavium-octeon/csrc-octeon.c
+++ b/arch/mips/cavium-octeon/csrc-octeon.c
@@ -4,7 +4,7 @@
* for more details.
*
* Copyright (C) 2007 by Ralf Baechle
- * Copyright (C) 2009, 2010 Cavium Networks, Inc.
+ * Copyright (C) 2009, 2012 Cavium, Inc.
*/
#include <linux/clocksource.h>
#include <linux/export.h>
@@ -18,6 +18,33 @@
#include <asm/octeon/cvmx-ipd-defs.h>
#include <asm/octeon/cvmx-mio-defs.h>
+
+static u64 f;
+static u64 rdiv;
+static u64 sdiv;
+static u64 octeon_udelay_factor;
+static u64 octeon_ndelay_factor;
+
+void __init octeon_setup_delays(void)
+{
+ octeon_udelay_factor = octeon_get_clock_rate() / 1000000;
+ /*
+ * For __ndelay we divide by 2^16, so the factor is multiplied
+ * by the same amount.
+ */
+ octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull;
+
+ preset_lpj = octeon_get_clock_rate() / HZ;
+
+ if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
+ union cvmx_mio_rst_boot rst_boot;
+ rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
+ rdiv = rst_boot.s.c_mul; /* CPU clock */
+ sdiv = rst_boot.s.pnr_mul; /* I/O clock */
+ f = (0x8000000000000000ull / sdiv) * 2;
+ }
+}
+
/*
* Set the current core's cvmcount counter to the value of the
* IPD_CLK_COUNT. We do this on all cores as they are brought
@@ -30,17 +57,6 @@ void octeon_init_cvmcount(void)
{
unsigned long flags;
unsigned loops = 2;
- u64 f = 0;
- u64 rdiv = 0;
- u64 sdiv = 0;
- if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
- union cvmx_mio_rst_boot rst_boot;
- rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
- rdiv = rst_boot.s.c_mul; /* CPU clock */
- sdiv = rst_boot.s.pnr_mul; /* I/O clock */
- f = (0x8000000000000000ull / sdiv) * 2;
- }
-
/* Clobber loops so GCC will not unroll the following while loop. */
asm("" : "+r" (loops));
@@ -57,9 +73,9 @@ void octeon_init_cvmcount(void)
if (f != 0) {
asm("dmultu\t%[cnt],%[f]\n\t"
"mfhi\t%[cnt]"
- : [cnt] "+r" (ipd_clk_count),
- [f] "=r" (f)
- : : "hi", "lo");
+ : [cnt] "+r" (ipd_clk_count)
+ : [f] "r" (f)
+ : "hi", "lo");
}
}
write_c0_cvmcount(ipd_clk_count);
@@ -109,21 +125,6 @@ void __init plat_time_init(void)
clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());
}
-static u64 octeon_udelay_factor;
-static u64 octeon_ndelay_factor;
-
-void __init octeon_setup_delays(void)
-{
- octeon_udelay_factor = octeon_get_clock_rate() / 1000000;
- /*
- * For __ndelay we divide by 2^16, so the factor is multiplied
- * by the same amount.
- */
- octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull;
-
- preset_lpj = octeon_get_clock_rate() / HZ;
-}
-
void __udelay(unsigned long us)
{
u64 cur, end, inc;
@@ -163,3 +164,35 @@ void __delay(unsigned long loops)
cur = read_c0_cvmcount();
}
EXPORT_SYMBOL(__delay);
+
+
+/**
+ * octeon_io_clk_delay - wait for a given number of io clock cycles to pass.
+ *
+ * We scale the wait by the clock ratio, and then wait for the
+ * corresponding number of core clocks.
+ *
+ * @count: The number of clocks to wait.
+ */
+void octeon_io_clk_delay(unsigned long count)
+{
+ u64 cur, end;
+
+ cur = read_c0_cvmcount();
+ if (rdiv != 0) {
+ end = count * rdiv;
+ if (f != 0) {
+ asm("dmultu\t%[cnt],%[f]\n\t"
+ "mfhi\t%[cnt]"
+ : [cnt] "+r" (end)
+ : [f] "r" (f)
+ : "hi", "lo");
+ }
+ end = cur + end;
+ } else {
+ end = cur + count;
+ }
+ while (end > cur)
+ cur = read_c0_cvmcount();
+}
+EXPORT_SYMBOL(octeon_io_clk_delay);
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 919b0fb..04dd8ff 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -548,6 +548,8 @@ void __init prom_init(void)
}
#endif
+ octeon_setup_delays();
+
/*
* BIST should always be enabled when doing a soft reset. L2
* Cache locking for instance is not cleared unless BIST is
@@ -611,7 +613,6 @@ void __init prom_init(void)
mips_hpt_frequency = octeon_get_clock_rate();
octeon_init_cvmcount();
- octeon_setup_delays();
_machine_restart = octeon_restart;
_machine_halt = octeon_halt;
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
index a31288e..96e58a5 100644
--- a/arch/mips/include/asm/octeon/octeon.h
+++ b/arch/mips/include/asm/octeon/octeon.h
@@ -52,6 +52,7 @@ extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
extern void octeon_init_cvmcount(void);
extern void octeon_setup_delays(void);
+extern void octeon_io_clk_delay(unsigned long);
#define OCTEON_ARGV_MAX_ARGS 64
#define OCTOEN_SERIAL_LEN 20
--
1.7.11.4
^ permalink raw reply related
* [PATCH 2/8] netdev: octeon_mgmt: Add support for 1Gig ports.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
The original hardware only supported 10M and 100M. Later versions
added 1G support. Here we update the driver to make use of this.
Also minor logic clean-ups for testing PHY registration error codes
and TX complete high water marks.
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 328 +++++++++++++++++++++++-------
1 file changed, 255 insertions(+), 73 deletions(-)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index c42bbb1..c4df1ab 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2009 Cavium Networks
+ * Copyright (C) 2009-2012 Cavium, Inc
*/
#include <linux/platform_device.h>
@@ -93,6 +93,7 @@ union mgmt_port_ring_entry {
#define AGL_GMX_RX_ADR_CAM4 0x1a0
#define AGL_GMX_RX_ADR_CAM5 0x1a8
+#define AGL_GMX_TX_CLK 0x208
#define AGL_GMX_TX_STATS_CTL 0x268
#define AGL_GMX_TX_CTL 0x270
#define AGL_GMX_TX_STAT0 0x280
@@ -110,6 +111,7 @@ struct octeon_mgmt {
struct net_device *netdev;
u64 mix;
u64 agl;
+ u64 agl_prt_ctl;
int port;
int irq;
u64 *tx_ring;
@@ -131,6 +133,7 @@ struct octeon_mgmt {
spinlock_t lock;
unsigned int last_duplex;
unsigned int last_link;
+ unsigned int last_speed;
struct device *dev;
struct napi_struct napi;
struct tasklet_struct tx_clean_tasklet;
@@ -140,6 +143,8 @@ struct octeon_mgmt {
resource_size_t mix_size;
resource_size_t agl_phys;
resource_size_t agl_size;
+ resource_size_t agl_prt_ctl_phys;
+ resource_size_t agl_prt_ctl_size;
};
static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable)
@@ -488,7 +493,7 @@ static void octeon_mgmt_reset_hw(struct octeon_mgmt *p)
mix_ctl.s.reset = 1;
cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
cvmx_read_csr(p->mix + MIX_CTL);
- cvmx_wait(64);
+ octeon_io_clk_delay(64);
mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST);
if (mix_bist.u64)
@@ -670,39 +675,148 @@ static int octeon_mgmt_ioctl(struct net_device *netdev,
return phy_mii_ioctl(p->phydev, rq, cmd);
}
+static void octeon_mgmt_disable_link(struct octeon_mgmt *p)
+{
+ union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+
+ /* Disable GMX before we make any changes. */
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
+ prtx_cfg.s.en = 0;
+ prtx_cfg.s.tx_en = 0;
+ prtx_cfg.s.rx_en = 0;
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
+
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+ int i;
+ for (i = 0; i < 10; i++) {
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
+ if (prtx_cfg.s.tx_idle == 1 || prtx_cfg.s.rx_idle == 1)
+ break;
+ mdelay(1);
+ i++;
+ }
+ }
+}
+
+static void octeon_mgmt_enable_link(struct octeon_mgmt *p)
+{
+ union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+
+ /* Restore the GMX enable state only if link is set */
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
+ prtx_cfg.s.tx_en = 1;
+ prtx_cfg.s.rx_en = 1;
+ prtx_cfg.s.en = 1;
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
+}
+
+static void octeon_mgmt_update_link(struct octeon_mgmt *p)
+{
+ union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
+
+ if (!p->phydev->link)
+ prtx_cfg.s.duplex = 1;
+ else
+ prtx_cfg.s.duplex = p->phydev->duplex;
+
+ switch (p->phydev->speed) {
+ case 10:
+ prtx_cfg.s.speed = 0;
+ prtx_cfg.s.slottime = 0;
+
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+ prtx_cfg.s.burst = 1;
+ prtx_cfg.s.speed_msb = 1;
+ }
+ break;
+ case 100:
+ prtx_cfg.s.speed = 0;
+ prtx_cfg.s.slottime = 0;
+
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+ prtx_cfg.s.burst = 1;
+ prtx_cfg.s.speed_msb = 0;
+ }
+ break;
+ case 1000:
+ /* 1000 MBits is only supported on 6XXX chips */
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+ prtx_cfg.s.speed = 1;
+ prtx_cfg.s.speed_msb = 0;
+ /* Only matters for half-duplex */
+ prtx_cfg.s.slottime = 1;
+ prtx_cfg.s.burst = p->phydev->duplex;
+ }
+ break;
+ case 0: /* No link */
+ default:
+ break;
+ }
+
+ /* Write the new GMX setting with the port still disabled. */
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
+
+ /* Read GMX CFG again to make sure the config is completed. */
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
+
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+ union cvmx_agl_gmx_txx_clk agl_clk;
+ union cvmx_agl_prtx_ctl prtx_ctl;
+
+ prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl);
+ agl_clk.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_CLK);
+ /* MII (both speeds) and RGMII 1000 speed. */
+ agl_clk.s.clk_cnt = 1;
+ if (prtx_ctl.s.mode == 0) { /* RGMII mode */
+ if (p->phydev->speed == 10)
+ agl_clk.s.clk_cnt = 50;
+ else if (p->phydev->speed == 100)
+ agl_clk.s.clk_cnt = 5;
+ }
+ cvmx_write_csr(p->agl + AGL_GMX_TX_CLK, agl_clk.u64);
+ }
+}
+
static void octeon_mgmt_adjust_link(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- union cvmx_agl_gmx_prtx_cfg prtx_cfg;
unsigned long flags;
int link_changed = 0;
+ if (!p->phydev)
+ return;
+
spin_lock_irqsave(&p->lock, flags);
- if (p->phydev->link) {
- if (!p->last_link)
- link_changed = 1;
- if (p->last_duplex != p->phydev->duplex) {
- p->last_duplex = p->phydev->duplex;
- prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
- prtx_cfg.s.duplex = p->phydev->duplex;
- cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
- }
- } else {
- if (p->last_link)
- link_changed = -1;
+
+
+ if (!p->phydev->link && p->last_link)
+ link_changed = -1;
+
+ if (p->phydev->link
+ && (p->last_duplex != p->phydev->duplex
+ || p->last_link != p->phydev->link
+ || p->last_speed != p->phydev->speed)) {
+ octeon_mgmt_disable_link(p);
+ link_changed = 1;
+ octeon_mgmt_update_link(p);
+ octeon_mgmt_enable_link(p);
}
+
p->last_link = p->phydev->link;
+ p->last_speed = p->phydev->speed;
+ p->last_duplex = p->phydev->duplex;
+
spin_unlock_irqrestore(&p->lock, flags);
if (link_changed != 0) {
if (link_changed > 0) {
- netif_carrier_on(netdev);
pr_info("%s: Link is up - %d/%s\n", netdev->name,
p->phydev->speed,
DUPLEX_FULL == p->phydev->duplex ?
"Full" : "Half");
} else {
- netif_carrier_off(netdev);
pr_info("%s: Link is down\n", netdev->name);
}
}
@@ -722,12 +836,8 @@ static int octeon_mgmt_init_phy(struct net_device *netdev)
octeon_mgmt_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
- if (IS_ERR(p->phydev)) {
- p->phydev = NULL;
- return -1;
- }
-
- phy_start_aneg(p->phydev);
+ if (p->phydev == NULL)
+ return -ENODEV;
return 0;
}
@@ -735,12 +845,10 @@ static int octeon_mgmt_init_phy(struct net_device *netdev)
static int octeon_mgmt_open(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
union cvmx_mixx_ctl mix_ctl;
union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode;
union cvmx_mixx_oring1 oring1;
union cvmx_mixx_iring1 iring1;
- union cvmx_agl_gmx_prtx_cfg prtx_cfg;
union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl;
union cvmx_mixx_irhwm mix_irhwm;
union cvmx_mixx_orhwm mix_orhwm;
@@ -787,9 +895,31 @@ static int octeon_mgmt_open(struct net_device *netdev)
} while (mix_ctl.s.reset);
}
- agl_gmx_inf_mode.u64 = 0;
- agl_gmx_inf_mode.s.en = 1;
- cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
+ if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
+ agl_gmx_inf_mode.u64 = 0;
+ agl_gmx_inf_mode.s.en = 1;
+ cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
+ }
+ if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
+ || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+ /*
+ * Force compensation values, as they are not
+ * determined properly by HW
+ */
+ union cvmx_agl_gmx_drv_ctl drv_ctl;
+
+ drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL);
+ if (p->port) {
+ drv_ctl.s.byp_en1 = 1;
+ drv_ctl.s.nctl1 = 6;
+ drv_ctl.s.pctl1 = 6;
+ } else {
+ drv_ctl.s.byp_en = 1;
+ drv_ctl.s.nctl = 6;
+ drv_ctl.s.pctl = 6;
+ }
+ cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64);
+ }
oring1.u64 = 0;
oring1.s.obase = p->tx_ring_handle >> 3;
@@ -801,11 +931,6 @@ static int octeon_mgmt_open(struct net_device *netdev)
iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE;
cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64);
- /* Disable packet I/O. */
- prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
- prtx_cfg.s.en = 0;
- cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
-
memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN);
octeon_mgmt_set_mac_address(netdev, &sa);
@@ -821,27 +946,70 @@ static int octeon_mgmt_open(struct net_device *netdev)
mix_ctl.s.nbtarb = 0; /* Arbitration mode */
/* MII CB-request FIFO programmable high watermark */
mix_ctl.s.mrq_hwm = 1;
+#ifdef __LITTLE_ENDIAN
+ mix_ctl.s.lendian = 1;
+#endif
cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
- if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
- || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
- /*
- * Force compensation values, as they are not
- * determined properly by HW
- */
- union cvmx_agl_gmx_drv_ctl drv_ctl;
+ /* Read the PHY to find the mode of the interface. */
+ if (octeon_mgmt_init_phy(netdev)) {
+ dev_err(p->dev, "Cannot initialize PHY on MIX%d.\n", p->port);
+ goto err_noirq;
+ }
- drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL);
- if (port) {
- drv_ctl.s.byp_en1 = 1;
- drv_ctl.s.nctl1 = 6;
- drv_ctl.s.pctl1 = 6;
- } else {
- drv_ctl.s.byp_en = 1;
- drv_ctl.s.nctl = 6;
- drv_ctl.s.pctl = 6;
+ /* Set the mode of the interface, RGMII/MII. */
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && p->phydev) {
+ union cvmx_agl_prtx_ctl agl_prtx_ctl;
+ int rgmii_mode = (p->phydev->supported &
+ (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) != 0;
+
+ agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl);
+ agl_prtx_ctl.s.mode = rgmii_mode ? 0 : 1;
+ cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64);
+
+ /* MII clocks counts are based on the 125Mhz
+ * reference, which has an 8nS period. So our delays
+ * need to be multiplied by this factor.
+ */
+#define NS_PER_PHY_CLK 8
+
+ /* Take the DLL and clock tree out of reset */
+ agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl);
+ agl_prtx_ctl.s.clkrst = 0;
+ if (rgmii_mode) {
+ agl_prtx_ctl.s.dllrst = 0;
+ agl_prtx_ctl.s.clktx_byp = 0;
}
- cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64);
+ cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64);
+ cvmx_read_csr(p->agl_prt_ctl); /* Force write out before wait */
+
+ /* Wait for the DLL to lock. External 125 MHz
+ * reference clock must be stable at this point.
+ */
+ ndelay(256 * NS_PER_PHY_CLK);
+
+ /* Enable the interface */
+ agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl);
+ agl_prtx_ctl.s.enable = 1;
+ cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64);
+
+ /* Read the value back to force the previous write */
+ agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl);
+
+ /* Enable the compensation controller */
+ agl_prtx_ctl.s.comp = 1;
+ agl_prtx_ctl.s.drv_byp = 0;
+ cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64);
+ /* Force write out before wait. */
+ cvmx_read_csr(p->agl_prt_ctl);
+
+ /* For compensation state to lock. */
+ ndelay(1040 * NS_PER_PHY_CLK);
+
+ /* Some Ethernet switches cannot handle standard
+ * Interframe Gap, increase to 16 bytes.
+ */
+ cvmx_write_csr(CVMX_AGL_GMX_TX_IFG, 0x88);
}
octeon_mgmt_rx_fill_ring(netdev);
@@ -872,7 +1040,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
/* Interrupt when we have 1 or more packets to clean. */
mix_orhwm.u64 = 0;
- mix_orhwm.s.orhwm = 1;
+ mix_orhwm.s.orhwm = 0;
cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64);
/* Enable receive and transmit interrupts */
@@ -881,7 +1049,6 @@ static int octeon_mgmt_open(struct net_device *netdev)
mix_intena.s.othena = 1;
cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
-
/* Enable packet I/O. */
rxx_frm_ctl.u64 = 0;
@@ -912,26 +1079,20 @@ static int octeon_mgmt_open(struct net_device *netdev)
rxx_frm_ctl.s.pre_chk = 1;
cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
- /* Enable the AGL block */
- agl_gmx_inf_mode.u64 = 0;
- agl_gmx_inf_mode.s.en = 1;
- cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
-
- /* Configure the port duplex and enables */
- prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
- prtx_cfg.s.tx_en = 1;
- prtx_cfg.s.rx_en = 1;
- prtx_cfg.s.en = 1;
- p->last_duplex = 1;
- prtx_cfg.s.duplex = p->last_duplex;
- cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
+ /* Configure the port duplex, speed and enables */
+ octeon_mgmt_disable_link(p);
+ if (p->phydev)
+ octeon_mgmt_update_link(p);
+ octeon_mgmt_enable_link(p);
p->last_link = 0;
- netif_carrier_off(netdev);
-
- if (octeon_mgmt_init_phy(netdev)) {
- dev_err(p->dev, "Cannot initialize PHY.\n");
- goto err_noirq;
+ p->last_speed = 0;
+ /* PHY is not present in simulator. The carrier is enabled
+ * while initializing the phy for simulator, leave it enabled.
+ */
+ if (p->phydev) {
+ netif_carrier_off(netdev);
+ phy_start_aneg(p->phydev);
}
netif_wake_queue(netdev);
@@ -961,6 +1122,7 @@ static int octeon_mgmt_stop(struct net_device *netdev)
if (p->phydev)
phy_disconnect(p->phydev);
+ p->phydev = NULL;
netif_carrier_off(netdev);
@@ -1033,6 +1195,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Ring the bell. */
cvmx_write_csr(p->mix + MIX_ORING2, 1);
+ netdev->trans_start = jiffies;
rv = NETDEV_TX_OK;
out:
octeon_mgmt_update_tx_stats(netdev);
@@ -1098,9 +1261,9 @@ static const struct net_device_ops octeon_mgmt_ops = {
.ndo_open = octeon_mgmt_open,
.ndo_stop = octeon_mgmt_stop,
.ndo_start_xmit = octeon_mgmt_xmit,
- .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering,
+ .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering,
.ndo_set_mac_address = octeon_mgmt_set_mac_address,
- .ndo_do_ioctl = octeon_mgmt_ioctl,
+ .ndo_do_ioctl = octeon_mgmt_ioctl,
.ndo_change_mtu = octeon_mgmt_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = octeon_mgmt_poll_controller,
@@ -1115,6 +1278,7 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
const u8 *mac;
struct resource *res_mix;
struct resource *res_agl;
+ struct resource *res_agl_prt_ctl;
int len;
int result;
@@ -1161,10 +1325,19 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
goto err;
}
+ res_agl_prt_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (res_agl_prt_ctl == NULL) {
+ dev_err(&pdev->dev, "no 'reg' resource\n");
+ result = -ENXIO;
+ goto err;
+ }
+
p->mix_phys = res_mix->start;
p->mix_size = resource_size(res_mix);
p->agl_phys = res_agl->start;
p->agl_size = resource_size(res_agl);
+ p->agl_prt_ctl_phys = res_agl_prt_ctl->start;
+ p->agl_prt_ctl_size = resource_size(res_agl_prt_ctl);
if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size,
@@ -1183,10 +1356,18 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
goto err;
}
+ if (!devm_request_mem_region(&pdev->dev, p->agl_prt_ctl_phys,
+ p->agl_prt_ctl_size, res_agl_prt_ctl->name)) {
+ result = -ENXIO;
+ dev_err(&pdev->dev, "request_mem_region (%s) failed\n",
+ res_agl_prt_ctl->name);
+ goto err;
+ }
p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size);
p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size);
-
+ p->agl_prt_ctl = (u64)devm_ioremap(&pdev->dev, p->agl_prt_ctl_phys,
+ p->agl_prt_ctl_size);
spin_lock_init(&p->lock);
skb_queue_head_init(&p->tx_list);
@@ -1209,6 +1390,7 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ netif_carrier_off(netdev);
result = register_netdev(netdev);
if (result)
goto err;
--
1.7.11.4
^ permalink raw reply related
* [PATCH 3/8] netdev: octeon_mgmt: Add hardware timestamp support.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev
Cc: linux-kernel, Chad Reese, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: Chad Reese <kreese@caviumnetworks.com>
Octeon cn6XXX models have timestamp support on the mgmt ports, so hook
it up.
Signed-off-by: Chad Reese <kreese@caviumnetworks.com>
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 157 +++++++++++++++++++++++++++++-
1 file changed, 152 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index c4df1ab..687a6a0 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -10,6 +10,7 @@
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/capability.h>
+#include <linux/net_tstamp.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
@@ -114,6 +115,7 @@ struct octeon_mgmt {
u64 agl_prt_ctl;
int port;
int irq;
+ bool has_rx_tstamp;
u64 *tx_ring;
dma_addr_t tx_ring_handle;
unsigned int tx_next;
@@ -238,6 +240,28 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
}
}
+static ktime_t ptp_to_ktime(u64 ptptime)
+{
+ ktime_t ktimebase;
+ u64 ptpbase;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /* Fill the icache with the code */
+ ktime_get_real();
+ /* Flush all pending operations */
+ mb();
+ /* Read the time and PTP clock as close together as
+ * possible. It is important that this sequence take the same
+ * amount of time to reduce jitter
+ */
+ ktimebase = ktime_get_real();
+ ptpbase = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_HI);
+ local_irq_restore(flags);
+
+ return ktime_sub_ns(ktimebase, ptpbase - ptptime);
+}
+
static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
{
union cvmx_mixx_orcnt mix_orcnt;
@@ -277,6 +301,20 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
dma_unmap_single(p->dev, re.s.addr, re.s.len,
DMA_TO_DEVICE);
+
+ /* Read the hardware TX timestamp if one was recorded */
+ if (unlikely(re.s.tstamp)) {
+ struct skb_shared_hwtstamps ts;
+ /* Read the timestamp */
+ u64 ns = cvmx_read_csr(CVMX_MIXX_TSTAMP(p->port));
+ /* Remove the timestamp from the FIFO */
+ cvmx_write_csr(CVMX_MIXX_TSCTL(p->port), 0);
+ /* Tell the kernel about the timestamp */
+ ts.syststamp = ptp_to_ktime(ns);
+ ts.hwtstamp = ns_to_ktime(ns);
+ skb_tstamp_tx(skb, &ts);
+ }
+
dev_kfree_skb_any(skb);
cleaned++;
@@ -377,6 +415,16 @@ static int octeon_mgmt_receive_one(struct octeon_mgmt *p)
/* A good packet, send it up. */
skb_put(skb, re.s.len);
good:
+ /* Process the RX timestamp if it was recorded */
+ if (p->has_rx_tstamp) {
+ /* The first 8 bytes are the timestamp */
+ u64 ns = *(u64 *)skb->data;
+ struct skb_shared_hwtstamps *ts;
+ ts = skb_hwtstamps(skb);
+ ts->hwtstamp = ns_to_ktime(ns);
+ ts->syststamp = ptp_to_ktime(ns);
+ __skb_pull(skb, 8);
+ }
skb->protocol = eth_type_trans(skb, netdev);
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += skb->len;
@@ -661,18 +709,114 @@ static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id)
return IRQ_HANDLED;
}
-static int octeon_mgmt_ioctl(struct net_device *netdev,
- struct ifreq *rq, int cmd)
+static int octeon_mgmt_ioctl_hwtstamp(struct net_device *netdev,
+ struct ifreq *rq, int cmd)
{
struct octeon_mgmt *p = netdev_priv(netdev);
+ struct hwtstamp_config config;
+ union cvmx_mio_ptp_clock_cfg ptp;
+ union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl;
+ bool have_hw_timestamps = false;
+
+ if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
+ return -EFAULT;
- if (!netif_running(netdev))
+ if (config.flags) /* reserved for future extensions */
return -EINVAL;
- if (!p->phydev)
+ /* Check the status of hardware for tiemstamps */
+ if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+ /* Get the current state of the PTP clock */
+ ptp.u64 = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_CFG);
+ if (!ptp.s.ext_clk_en) {
+ /* The clock has not been configured to use an
+ * external source. Program it to use the main clock
+ * reference.
+ */
+ u64 clock_comp = (NSEC_PER_SEC << 32) / octeon_get_io_clock_rate();
+ if (!ptp.s.ptp_en)
+ cvmx_write_csr(CVMX_MIO_PTP_CLOCK_COMP, clock_comp);
+ pr_info("PTP Clock: Using sclk reference at %lld Hz\n",
+ (NSEC_PER_SEC << 32) / clock_comp);
+ } else {
+ /* The clock is already programmed to use a GPIO */
+ u64 clock_comp = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_COMP);
+ pr_info("PTP Clock: Using GPIO %d at %lld Hz\n",
+ ptp.s.ext_clk_in,
+ (NSEC_PER_SEC << 32) / clock_comp);
+ }
+
+ /* Enable the clock if it wasn't done already */
+ if (!ptp.s.ptp_en) {
+ ptp.s.ptp_en = 1;
+ cvmx_write_csr(CVMX_MIO_PTP_CLOCK_CFG, ptp.u64);
+ }
+ have_hw_timestamps = true;
+ }
+
+ if (!have_hw_timestamps)
return -EINVAL;
- return phy_mii_ioctl(p->phydev, rq, cmd);
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ case HWTSTAMP_TX_ON:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ p->has_rx_tstamp = false;
+ rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL);
+ rxx_frm_ctl.s.ptp_mode = 0;
+ cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ p->has_rx_tstamp = have_hw_timestamps;
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ if (p->has_rx_tstamp) {
+ rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL);
+ rxx_frm_ctl.s.ptp_mode = 1;
+ cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
+ }
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (copy_to_user(rq->ifr_data, &config, sizeof(config)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int octeon_mgmt_ioctl(struct net_device *netdev,
+ struct ifreq *rq, int cmd)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ return octeon_mgmt_ioctl_hwtstamp(netdev, rq, cmd);
+ default:
+ if (p->phydev)
+ return phy_mii_ioctl(p->phydev, rq, cmd);
+ return -EINVAL;
+ }
}
static void octeon_mgmt_disable_link(struct octeon_mgmt *p)
@@ -1052,6 +1196,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
/* Enable packet I/O. */
rxx_frm_ctl.u64 = 0;
+ rxx_frm_ctl.s.ptp_mode = p->has_rx_tstamp ? 1 : 0;
rxx_frm_ctl.s.pre_align = 1;
/*
* When set, disables the length check for non-min sized pkts
@@ -1155,6 +1300,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
int rv = NETDEV_TX_BUSY;
re.d64 = 0;
+ re.s.tstamp = ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) != 0);
re.s.len = skb->len;
re.s.addr = dma_map_single(p->dev, skb->data,
skb->len,
@@ -1293,6 +1439,7 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
p->netdev = netdev;
p->dev = &pdev->dev;
+ p->has_rx_tstamp = false;
data = of_get_property(pdev->dev.of_node, "cell-index", &len);
if (data && len == sizeof(*data)) {
--
1.7.11.4
^ permalink raw reply related
* [PATCH 4/8] netdev: octeon_mgmt: Improve ethtool_ops.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
Correctly show no link when the interface is down, and return
-EOPNOTSUPP for things that don't work. This quiets the ethtool
program when run on down interfaces.
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index 687a6a0..cf06cf2 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -1379,7 +1379,7 @@ static int octeon_mgmt_get_settings(struct net_device *netdev,
if (p->phydev)
return phy_ethtool_gset(p->phydev, cmd);
- return -EINVAL;
+ return -EOPNOTSUPP;
}
static int octeon_mgmt_set_settings(struct net_device *netdev,
@@ -1393,14 +1393,28 @@ static int octeon_mgmt_set_settings(struct net_device *netdev,
if (p->phydev)
return phy_ethtool_sset(p->phydev, cmd);
- return -EINVAL;
+ return -EOPNOTSUPP;
+}
+
+static int octeon_mgmt_nway_reset(struct net_device *dev)
+{
+ struct octeon_mgmt *p = netdev_priv(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (p->phydev)
+ return phy_start_aneg(p->phydev);
+
+ return -EOPNOTSUPP;
}
static const struct ethtool_ops octeon_mgmt_ethtool_ops = {
.get_drvinfo = octeon_mgmt_get_drvinfo,
- .get_link = ethtool_op_get_link,
.get_settings = octeon_mgmt_get_settings,
- .set_settings = octeon_mgmt_set_settings
+ .set_settings = octeon_mgmt_set_settings,
+ .nway_reset = octeon_mgmt_nway_reset,
+ .get_link = ethtool_op_get_link,
};
static const struct net_device_ops octeon_mgmt_ops = {
--
1.7.11.4
^ permalink raw reply related
* [PATCH 5/8] netdev: octeon_mgmt: Set the parent device.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
This establishes useful links in sysfs.
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index cf06cf2..3bae01f 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -1446,6 +1446,8 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
if (netdev == NULL)
return -ENOMEM;
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
dev_set_drvdata(&pdev->dev, netdev);
p = netdev_priv(netdev);
netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll,
--
1.7.11.4
^ permalink raw reply related
* [PATCH 6/8] netdev: octeon_mgmt: Cleanup and modernize MAC address handling.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
Use eth_mac_addr(), and generate a random address if none is otherwise
assigned.
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index 3bae01f..9b526da 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -648,12 +648,10 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr)
{
- struct sockaddr *sa = addr;
+ int r = eth_mac_addr(netdev, addr);
- if (!is_valid_ether_addr(sa->sa_data))
- return -EADDRNOTAVAIL;
-
- memcpy(netdev->dev_addr, sa->sa_data, ETH_ALEN);
+ if (r)
+ return r;
octeon_mgmt_set_rx_filtering(netdev);
@@ -1545,8 +1543,12 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
mac = of_get_mac_address(pdev->dev.of_node);
- if (mac)
- memcpy(netdev->dev_addr, mac, 6);
+ if (mac && is_valid_ether_addr(mac)) {
+ memcpy(netdev->dev_addr, mac, ETH_ALEN);
+ netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
+ } else {
+ eth_hw_addr_random(netdev);
+ }
p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
--
1.7.11.4
^ permalink raw reply related
* [PATCH 7/8] netdev: octeon_mgmt: Remove some useless 'inline'
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index 9b526da..ccb1f81 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -173,22 +173,22 @@ static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable)
spin_unlock_irqrestore(&p->lock, flags);
}
-static inline void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p)
+static void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p)
{
octeon_mgmt_set_rx_irq(p, 1);
}
-static inline void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p)
+static void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p)
{
octeon_mgmt_set_rx_irq(p, 0);
}
-static inline void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p)
+static void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p)
{
octeon_mgmt_set_tx_irq(p, 1);
}
-static inline void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p)
+static void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p)
{
octeon_mgmt_set_tx_irq(p, 0);
}
--
1.7.11.4
^ permalink raw reply related
* [PATCH 8/8] netdev: octeon_mgmt: Make multi-line comment style consistent.
From: David Daney @ 2012-08-21 18:45 UTC (permalink / raw)
To: linux-mips, ralf, David S. Miller, netdev; +Cc: linux-kernel, David Daney
In-Reply-To: <1345574712-21444-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
No code changes. Recent patches have used the netdev style multi-line
comment formatting, making the style inconsistent within octeon_mgmt.c
Update the remaining comment blocks to achieve style harmony.
Signed-off-by: David Daney <david.daney@cavium.com>
---
drivers/net/ethernet/octeon/octeon_mgmt.c | 27 +++++++++------------------
1 file changed, 9 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index ccb1f81..5be431c 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -34,8 +34,7 @@
#define OCTEON_MGMT_NAPI_WEIGHT 16
-/*
- * Ring sizes that are powers of two allow for more efficient modulo
+/* Ring sizes that are powers of two allow for more efficient modulo
* opertions.
*/
#define OCTEON_MGMT_RX_RING_SIZE 512
@@ -431,8 +430,7 @@ good:
netif_receive_skb(skb);
rc = 0;
} else if (re.s.code == RING_ENTRY_CODE_MORE) {
- /*
- * Packet split across skbs. This can happen if we
+ /* Packet split across skbs. This can happen if we
* increase the MTU. Buffers that are already in the
* rx ring can then end up being too small. As the rx
* ring is refilled, buffers sized for the new MTU
@@ -462,8 +460,7 @@ good:
} else {
/* Some other error, discard it. */
dev_kfree_skb_any(skb);
- /*
- * Error statistics are accumulated in
+ /* Error statistics are accumulated in
* octeon_mgmt_update_rx_stats.
*/
}
@@ -590,8 +587,7 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
cam_mode = 0;
available_cam_entries = 8;
} else {
- /*
- * One CAM entry for the primary address, leaves seven
+ /* One CAM entry for the primary address, leaves seven
* for the secondary addresses.
*/
available_cam_entries = 7 - netdev->uc.count;
@@ -663,8 +659,7 @@ static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
struct octeon_mgmt *p = netdev_priv(netdev);
int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM;
- /*
- * Limit the MTU to make sure the ethernet packets are between
+ /* Limit the MTU to make sure the ethernet packets are between
* 64 bytes and 16383 bytes.
*/
if (size_without_fcs < 64 || size_without_fcs > 16383) {
@@ -1044,8 +1039,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
}
if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
|| OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
- /*
- * Force compensation values, as they are not
+ /* Force compensation values, as they are not
* determined properly by HW
*/
union cvmx_agl_gmx_drv_ctl drv_ctl;
@@ -1078,8 +1072,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
octeon_mgmt_change_mtu(netdev, netdev->mtu);
- /*
- * Enable the port HW. Packets are not allowed until
+ /* Enable the port HW. Packets are not allowed until
* cvmx_mgmt_port_enable() is called.
*/
mix_ctl.u64 = 0;
@@ -1196,8 +1189,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
rxx_frm_ctl.u64 = 0;
rxx_frm_ctl.s.ptp_mode = p->has_rx_tstamp ? 1 : 0;
rxx_frm_ctl.s.pre_align = 1;
- /*
- * When set, disables the length check for non-min sized pkts
+ /* When set, disables the length check for non-min sized pkts
* with padding in the client data.
*/
rxx_frm_ctl.s.pad_len = 1;
@@ -1215,8 +1207,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
rxx_frm_ctl.s.ctl_drp = 1;
/* Strip off the preamble */
rxx_frm_ctl.s.pre_strp = 1;
- /*
- * This port is configured to send PREAMBLE+SFD to begin every
+ /* This port is configured to send PREAMBLE+SFD to begin every
* frame. GMX checks that the PREAMBLE is sent correctly.
*/
rxx_frm_ctl.s.pre_chk = 1;
--
1.7.11.4
^ permalink raw reply related
* Re: [PATCH v6] bonding support for IPv6 transmit hashing
From: Jay Vosburgh @ 2012-08-21 19:19 UTC (permalink / raw)
To: Jeremy Brookman; +Cc: linux, netdev
In-Reply-To: <CAPc2XZDHBPKEM+WsWTL+9N_sfgVhOZAoiY3LU=v-QTCb9eQObQ@mail.gmail.com>
Jeremy Brookman <jeremy.brookman@gmail.com> wrote:
>> You should use a mix of tabs, as necessary, to get things to line up
>> how I told you they need to line up.
>
>Unless I'm missing something, this change doesn't seem to have made it
>through to the kernel tip, but we could really use this bugfix. Is it
>in a repository I didn't notice, or not yet through the review? If
>it's not through the review, is any help needed to get it there?
The submitter (John Eaglesham) never posted an updated version
that addressed the various comments, nor did his original patch
submission include a Signed-off-by.
I went ahead and updated the patch to address the comments; I've
only compile tested this. Are you (Jeremy or John) able to test this to
confirm that it will hash ipv6 traffic as expected (I can test it, but
it won't be today)?
John, can you post a Signed-off-by for your patch (really, this
updated version of your patch)?
If John signs off and somebody tests this, I'll post a formal
submssion with the full commit message.
-J
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 6b1c711..834c919 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -752,12 +752,23 @@ xmit_hash_policy
protocol information to generate the hash.
Uses XOR of hardware MAC addresses and IP addresses to
- generate the hash. The formula is
+ generate the hash. The IPv4 formula is
(((source IP XOR dest IP) AND 0xffff) XOR
( source MAC XOR destination MAC ))
modulo slave count
+ The IPv6 formula is
+
+ hash =
+ (source ip quad 2 XOR dest IP quad 2) XOR
+ (source ip quad 3 XOR dest IP quad 3) XOR
+ (source ip quad 4 XOR dest IP quad 4)
+
+ (((hash >> 24) XOR (hash >> 16) XOR (hash >> 8) XOR hash)
+ XOR (source MAC XOR destination MAC))
+ modulo slave count
+
This algorithm will place all traffic to a particular
network peer on the same slave. For non-IP traffic,
the formula is the same as for the layer2 transmit
@@ -778,19 +789,30 @@ xmit_hash_policy
slaves, although a single connection will not span
multiple slaves.
- The formula for unfragmented TCP and UDP packets is
+ The formula for unfragmented IPv4 TCP and UDP packets is
((source port XOR dest port) XOR
((source IP XOR dest IP) AND 0xffff)
modulo slave count
- For fragmented TCP or UDP packets and all other IP
- protocol traffic, the source and destination port
+ The formula for unfragmented IPv6 TCP and UDP packets is
+
+ hash =
+ (source ip quad 2 XOR dest IP quad 2) XOR
+ (source ip quad 3 XOR dest IP quad 3) XOR
+ (source ip quad 4 XOR dest IP quad 4)
+
+ ((source port XOR dest port) XOR
+ (hash >> 24) XOR (hash >> 16) XOR (hash >> 8) XOR hash)
+ modulo slave count
+
+ For fragmented TCP or UDP packets and all other IPv4 and
+ IPv6 protocol traffic, the source and destination port
information is omitted. For non-IP traffic, the
formula is the same as for the layer2 transmit hash
policy.
- This policy is intended to mimic the behavior of
+ The IPv4 policy is intended to mimic the behavior of
certain switches, notably Cisco switches with PFC2 as
well as some Foundry and IBM products.
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d95fbc3..4dfe7e3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3354,56 +3354,99 @@ static struct notifier_block bond_netdev_notifier = {
/*---------------------------- Hashing Policies -----------------------------*/
/*
+ * Hash for the output device based upon layer 2 data
+ */
+static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
+{
+ struct ethhdr *data = (struct ethhdr *)skb->data;
+
+ if (skb_headlen(skb) >= offsetof(struct ethhdr, h_proto))
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
+
+ return 0;
+}
+
+/*
* Hash for the output device based upon layer 2 and layer 3 data. If
- * the packet is not IP mimic bond_xmit_hash_policy_l2()
+ * the packet is not IP, fall back on bond_xmit_hash_policy_l2()
*/
static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
{
struct ethhdr *data = (struct ethhdr *)skb->data;
- struct iphdr *iph = ip_hdr(skb);
-
- if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph;
+ struct ipv6hdr *ipv6h;
+ u32 v6hash;
+ __be32 *s, *d;
+
+ if (skb->protocol == htons(ETH_P_IP) &&
+ skb_network_header_len(skb) >= sizeof(struct iphdr)) {
+ iph = ip_hdr(skb);
return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
(data->h_dest[5] ^ data->h_source[5])) % count;
+ } else if (skb->protocol == htons(ETH_P_IPV6) &&
+ skb_network_header_len(skb) >= sizeof(struct ipv6hdr)) {
+ ipv6h = ipv6_hdr(skb);
+ s = &ipv6h->saddr.s6_addr32[0];
+ d = &ipv6h->daddr.s6_addr32[0];
+ v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]);
+ v6hash ^= (v6hash >> 24) ^ (v6hash >> 16) ^ (v6hash >> 8);
+ return (v6hash ^ data->h_dest[5] ^ data->h_source[5]) % count;
}
- return (data->h_dest[5] ^ data->h_source[5]) % count;
+ return bond_xmit_hash_policy_l2(skb, count);
}
/*
* Hash for the output device based upon layer 3 and layer 4 data. If
* the packet is a frag or not TCP or UDP, just use layer 3 data. If it is
- * altogether not IP, mimic bond_xmit_hash_policy_l2()
+ * altogether not IP, fall back on bond_xmit_hash_policy_l2()
*/
static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
{
- struct ethhdr *data = (struct ethhdr *)skb->data;
- struct iphdr *iph = ip_hdr(skb);
- __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
- int layer4_xor = 0;
+ u32 layer4_xor = 0;
+ struct iphdr *iph;
+ struct ipv6hdr *ipv6h;
+ __be32 *s, *d;
+ __be16 *layer4hdr;
if (skb->protocol == htons(ETH_P_IP)) {
+ iph = ip_hdr(skb);
if (!ip_is_fragment(iph) &&
(iph->protocol == IPPROTO_TCP ||
iph->protocol == IPPROTO_UDP)) {
+ if (iph->ihl * sizeof(u32) + sizeof(__be16) * 2 >
+ skb_headlen(skb) - skb_network_offset(skb))
+ goto short_header;
+ layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
+ } else if (skb_network_header_len(skb) < sizeof(struct iphdr)) {
+ goto short_header;
}
return (layer4_xor ^
((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
-
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ ipv6h = ipv6_hdr(skb);
+ if (ipv6h->nexthdr == IPPROTO_TCP ||
+ ipv6h->nexthdr == IPPROTO_UDP) {
+ layer4hdr = (__be16 *)(ipv6h + 1);
+ if (sizeof(struct ipv6hdr) + sizeof(__be16) * 2 >
+ skb_headlen(skb) - skb_network_offset(skb))
+ goto short_header;
+ layer4_xor = (*layer4hdr ^ *(layer4hdr + 1));
+ } else if (skb_network_header_len(skb) <
+ sizeof(struct ipv6hdr)) {
+ goto short_header;
+ }
+ s = &ipv6h->saddr.s6_addr32[0];
+ d = &ipv6h->daddr.s6_addr32[0];
+ layer4_xor ^= (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]);
+ layer4_xor ^= (layer4_xor >> 24) ^ (layer4_xor >> 16) ^
+ (layer4_xor >> 8);
+ return layer4_xor % count;
}
- return (data->h_dest[5] ^ data->h_source[5]) % count;
-}
-
-/*
- * Hash for the output device based upon layer 2 data
- */
-static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
-{
- struct ethhdr *data = (struct ethhdr *)skb->data;
-
- return (data->h_dest[5] ^ data->h_source[5]) % count;
+short_header:
+ return bond_xmit_hash_policy_l2(skb, count);
}
/*-------------------------- Device entry points ----------------------------*/
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
^ permalink raw reply related
* Re: IP fragmentation broken in 3.6-rc ?
From: Julian Anastasov @ 2012-08-21 20:00 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Sylvain Munaut, netdev
In-Reply-To: <1345569824.5158.540.camel@edumazet-glaptop>
Hello,
On Tue, 21 Aug 2012, Eric Dumazet wrote:
> In fact we re-enter ip_rt_update_pmtu() if we receive a second ICMP,
> and rt->rt_pmtu is already set, but dst is expired.
>
> Thats why Sylvain said it was not happening in the 10 minutes following
> boot.
>
> So calling again dst_set_expires(&rt->dst, ip_rt_mtu_expires) does
> nothing : rt_pmtu is ignored because dst.expires is too old.
Oh, well. I thought dst_set_expires was used
before for IPv4, it was not. I didn't expected function
that was old to cause problem. So, you are right that
MTU is not updated second time. But we must check if
such change will harm IPv6, dst_set_expires was/is
used there.
> Maybe we should just do :
>
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index e4ba974..d0181e2 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -952,7 +952,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
> ip_rt_build_flow_key(&fl4, sk, skb);
> mtu = __ip_rt_update_pmtu(rt, &fl4, mtu);
>
> - if (!rt->rt_pmtu) {
> + if (!rt->rt_pmtu || time_after_eq(jiffies, rt->dst.expires)) {
At first look it should not be needed to cause route
relookup here. tcp_v4_mtu_reduced is prepared to use the new
dst_mtu for mss after calling inet_csk_update_pmtu. It seems the
new code expects that every socket that performs PMTU Discovery
will get ICMP error, so tcp_v4_mtu_reduced should be called
for every socket with every new ICMP. If there are 100 sockets
we will get 100 ICMPs. If we set DST_OBSOLETE_KILL as you
propose, all sockets will notice the need to relookup
route and will learn the new PMTU from fnhe exception with less
chances for other ICMP events. At first look, this variant looks
better to me in case if we want single PMTU to be propagated
to all sockets immediately. Can it cause other problems?
Now the rt life with PMTU will be limited to 600 secs.
OTOH, tcp_current_mss() is called often, it will
notice the new dst_mtu, so may be there is no need for
route relookup by setting DST_OBSOLETE_KILL?
Not sure if we still have to support this second
option, to change dst_set_expires to check for timeout=0:
if (dst->expires == 0 || time_after(expires, dst->expires) ||
!timeout)
In IPv4, ip_rt_update_pmtu was the only place that
can extend dst->expires, for the rt_bind_exception case
I assume expires is still 0 before the checks. Not sure if
IPv6 needs to use time_after, may be it prefers the
time_before variant? IPv6 updates MTU in rt6_update_expires
and we call dst_set_expires where the timer will not be
extended. But may be the intention is that MTU only
can reduce the expiration, not to extend it after timer
was set when route was added.
So, another option is to create new function
dst_update_expires and to use it just for IPv4, it will
use time_after because IPv4 uses the timer just for
PMTU while IPv6 uses it in ip6_route_add() to limit
route lifetime due to lft values.
dst_update_expires will be like dst_set_expires
but with this difference (time_after):
if (dst->expires == 0 || time_after(expires, dst->expires) ||
!timeout)
while dst_set_expires will be as before, used by IPv6.
> dst->obsolete = DST_OBSOLETE_KILL;
> } else {
> rt->rt_pmtu = mtu;
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply
* Re: IP fragmentation broken in 3.6-rc ?
From: Eric Dumazet @ 2012-08-21 20:46 UTC (permalink / raw)
To: Julian Anastasov; +Cc: Sylvain Munaut, netdev
In-Reply-To: <alpine.LFD.2.00.1208212102540.2149@ja.ssi.bg>
On Tue, 2012-08-21 at 23:00 +0300, Julian Anastasov wrote:
> Hello,
>
> On Tue, 21 Aug 2012, Eric Dumazet wrote:
>
> > In fact we re-enter ip_rt_update_pmtu() if we receive a second ICMP,
> > and rt->rt_pmtu is already set, but dst is expired.
> >
> > Thats why Sylvain said it was not happening in the 10 minutes following
> > boot.
> >
> > So calling again dst_set_expires(&rt->dst, ip_rt_mtu_expires) does
> > nothing : rt_pmtu is ignored because dst.expires is too old.
>
> Oh, well. I thought dst_set_expires was used
> before for IPv4, it was not. I didn't expected function
> that was old to cause problem. So, you are right that
> MTU is not updated second time. But we must check if
> such change will harm IPv6, dst_set_expires was/is
> used there.
>
> > Maybe we should just do :
> >
> > diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> > index e4ba974..d0181e2 100644
> > --- a/net/ipv4/route.c
> > +++ b/net/ipv4/route.c
> > @@ -952,7 +952,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
> > ip_rt_build_flow_key(&fl4, sk, skb);
> > mtu = __ip_rt_update_pmtu(rt, &fl4, mtu);
> >
> > - if (!rt->rt_pmtu) {
> > + if (!rt->rt_pmtu || time_after_eq(jiffies, rt->dst.expires)) {
>
> At first look it should not be needed to cause route
> relookup here. tcp_v4_mtu_reduced is prepared to use the new
> dst_mtu for mss after calling inet_csk_update_pmtu. It seems the
> new code expects that every socket that performs PMTU Discovery
> will get ICMP error, so tcp_v4_mtu_reduced should be called
> for every socket with every new ICMP. If there are 100 sockets
> we will get 100 ICMPs. If we set DST_OBSOLETE_KILL as you
> propose, all sockets will notice the need to relookup
> route and will learn the new PMTU from fnhe exception with less
> chances for other ICMP events. At first look, this variant looks
> better to me in case if we want single PMTU to be propagated
> to all sockets immediately. Can it cause other problems?
> Now the rt life with PMTU will be limited to 600 secs.
>
> OTOH, tcp_current_mss() is called often, it will
> notice the new dst_mtu, so may be there is no need for
> route relookup by setting DST_OBSOLETE_KILL?
>
> Not sure if we still have to support this second
> option, to change dst_set_expires to check for timeout=0:
>
> if (dst->expires == 0 || time_after(expires, dst->expires) ||
> !timeout)
>
> In IPv4, ip_rt_update_pmtu was the only place that
> can extend dst->expires, for the rt_bind_exception case
> I assume expires is still 0 before the checks. Not sure if
> IPv6 needs to use time_after, may be it prefers the
> time_before variant? IPv6 updates MTU in rt6_update_expires
> and we call dst_set_expires where the timer will not be
> extended. But may be the intention is that MTU only
> can reduce the expiration, not to extend it after timer
> was set when route was added.
>
> So, another option is to create new function
> dst_update_expires and to use it just for IPv4, it will
> use time_after because IPv4 uses the timer just for
> PMTU while IPv6 uses it in ip6_route_add() to limit
> route lifetime due to lft values.
>
> dst_update_expires will be like dst_set_expires
> but with this difference (time_after):
>
> if (dst->expires == 0 || time_after(expires, dst->expires) ||
> !timeout)
Hmm, all these tests are not really needed, what about :
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e4ba974..8d6d320 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -956,7 +956,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
dst->obsolete = DST_OBSOLETE_KILL;
} else {
rt->rt_pmtu = mtu;
- dst_set_expires(&rt->dst, ip_rt_mtu_expires);
+ rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires);
}
}
^ permalink raw reply related
* Re: skb_under_panic bug
From: Xiaochun Lu @ 2012-08-21 20:50 UTC (permalink / raw)
To: Pieper, Jeffrey E; +Cc: netdev@vger.kernel.org
In-Reply-To: <2A35EA60C3C77D438915767F458D65684817FFC9@ORSMSX102.amr.corp.intel.com>
Hi, Jeff:
Have you resolved this one. I see similar issue. But my kernel is
based on 3.0.36. here is the trace:
Aug 20 20:50:51 Ericsson kernel: skb_under_panic:
text:ffffffff8133ea84 len:112 put:14 head:ffff8806187e0a00
data:ffff8806187e09f4 tail:0x64 end:0x80 dev:ethSw0.1
Aug 20 20:50:54 Ericsson kernel: ------------[ cut here ]------------
Aug 20 20:50:54 Ericsson kernel: Kernel BUG at ffffffff8131b73a
[verbose debug info unavailable]
Aug 20 20:50:54 Ericsson kernel: invalid opcode: 0000 [#1] PREEMPT SMP
Aug 20 20:50:54 Ericsson kernel: CPU 0
Aug 20 20:50:54 Ericsson kernel: Modules linked in: cls_u32 sch_htb
uio_pch_smb ixgbe mdio bonding 8021q iflc uio_spanky_shiba uio_phalanx
uio rbn_pci_hotswap msr fuse tipc sctp crc32c libcrc32c rbn_nf_ipacl
rbn_nf_tcp rbn_nf_ips rbn_ctx_kmod ipv6 rbn_ext_ip_so af_isis
af_rbn_netlink af_ipc xcrp rbn_platform loop rbn_swrp_wd igb
Aug 20 20:50:54 Ericsson kernel:
Aug 20 20:50:54 Ericsson kernel: Pid: 3616, comm: pad Not tainted
3.0.36-869-g241f2ae #2 Ericsson Smart Service Router/SWRP
Aug 20 20:50:54 Ericsson kernel: RIP: 0010:[<ffffffff8131b73a>]
[<ffffffff8131b73a>] skb_push+0x7a/0x80
Aug 20 20:50:54 Ericsson kernel: RSP: 0000:ffff88060a1f9a18 EFLAGS: 00010292
Aug 20 20:50:54 Ericsson kernel: RAX: 0000000000000088 RBX:
0000000000000800 RCX: 0000000000000000
Aug 20 20:50:54 Ericsson kernel: RDX: ffff88060a1f8010 RSI:
0000000000000000 RDI: 0000000000000001
Aug 20 20:50:54 Ericsson kernel: RBP: 0000000000000000 R08:
ffff88060a1f8000 R09: 0000000000000000
Aug 20 20:50:54 Ericsson kernel: R10: 0000000000000002 R11:
0000000000000000 R12: ffff8805ea421398
Aug 20 20:50:54 Ericsson kernel: R13: 0000000000000062 R14:
ffff880619089000 R15: ffff88061a814dd8
Aug 20 20:50:54 Ericsson kernel: FS: 0000000000000000(0000)
GS:ffff88063fc00000(0063) knlGS:00000000578d0b90
Aug 20 20:50:54 Ericsson kernel: CS: 0010 DS: 002b ES: 002b CR0:
000000008005003b
Aug 20 20:50:54 Ericsson kernel: CR2: 00002aaaaaae4000 CR3:
00000006162ab000 CR4: 00000000000006f0
Aug 20 20:50:54 Ericsson kernel: DR0: 0000000000000000 DR1:
0000000000000000 DR2: 0000000000000000
Aug 20 20:50:54 Ericsson kernel: DR3: 0000000000000000 DR6:
00000000ffff0ff0 DR7: 0000000000000400
Aug 20 20:50:54 Ericsson kernel: Process pad (pid: 3616, threadinfo
ffff88060a1f8000, task ffff88061abfbd40)
Aug 20 20:50:54 Ericsson kernel: Stack:
Aug 20 20:50:54 Ericsson kernel: 0000000000000064 0000000000000080
ffff880619089000 ffffffff8133ea84
Aug 20 20:50:54 Ericsson kernel: 000000000000017e ffff8805ea421300
ffff8805ea421390 ffff8805ea56d040
Aug 20 20:50:54 Ericsson kernel: ffff8805ea421398 ffffffff8133088e
ffff880619089000 000000000000017a
Aug 20 20:50:54 Ericsson kernel: Call Trace:
Aug 20 20:50:54 Ericsson kernel: [<ffffffff8133ea84>] ? eth_header+0x34/0xe0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff8133088e>] ?
neigh_resolve_output+0x10e/0x320
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81357ae1>] ?
ip_finish_output+0x1f1/0x400
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81356c39>] ? ip_send_skb+0x9/0x60
Aug 20 20:50:54 Ericsson kernel: [<ffffffff8137a525>] ?
udp_send_skb+0x125/0x3c0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff8137cd0a>] ? udp_sendmsg+0x73a/0x870
Aug 20 20:50:54 Ericsson kernel: [<ffffffff810ecde0>] ? __pollwait+0x120/0x120
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81356210>] ?
ip_append_page+0x5e0/0x5e0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81312b50>] ?
sock_sendmsg+0x110/0x130
Aug 20 20:50:54 Ericsson kernel: [<ffffffff813128a7>] ?
sock_recvmsg+0x127/0x140
Aug 20 20:50:54 Ericsson kernel: [<ffffffff813ed091>] ?
_raw_spin_unlock_irq+0x11/0x40
Aug 20 20:50:54 Ericsson kernel: [<ffffffff810358bc>] ?
finish_task_switch+0x5c/0xd0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff8111dd9a>] ?
compat_core_sys_select+0x2ba/0x2d0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff810dbbdf>] ? fget_light+0xbf/0x100
Aug 20 20:50:54 Ericsson kernel: [<ffffffff813132c8>] ? sys_sendto+0x138/0x1a0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81031449>] ? get_parent_ip+0x9/0x20
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81036297>] ?
sub_preempt_count+0x87/0xc0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff813eb4c3>] ?
preempt_schedule_irq+0x43/0x60
Aug 20 20:50:54 Ericsson kernel: [<ffffffff813ed846>] ? retint_kernel+0x26/0x30
Aug 20 20:50:54 Ericsson kernel: [<ffffffff81060b5b>] ? ktime_get_ts+0x6b/0xd0
Aug 20 20:50:54 Ericsson kernel: [<ffffffff8133def5>] ?
compat_sys_socketcall+0x175/0x250
Aug 20 20:50:54 Ericsson kernel: [<ffffffff813eef03>] ? ia32_do_call+0x13/0x13
Aug 20 20:50:54 Ericsson kernel: Code: 8b 57 68 48 89 44 24 10 8b 87
e8 00 00 00 48 89 44 24 08 31 c0 8b bf e4 00 00 00 48 89 3c 24 48 c7
c7 50 61 4d 81 e8 c2 eb 0c 00 <0f> 0b eb fe 66 90 48 83 ec 18 89 f1 44
8b 57 6c 4c 8b 87 f0 00
Aug 20 20:50:54 Ericsson kernel: RIP [<ffffffff8131b73a>] skb_push+0x7a/0x80
Aug 20 20:50:54 Ericsson kernel: RSP <ffff88060a1f9a18>
Aug 20 20:50:54 Ericsson kernel: ---[ end trace 3856d31346ddf680 ]---
Thanks
Shawn Lu
On Tue, May 1, 2012 at 10:08 AM, Pieper, Jeffrey E
<jeffrey.e.pieper@intel.com> wrote:
> I've seen the following stack trace several times recently, and was wondering if anyone else has ran into this. This occurs during bi-directional TCP/UDP traffic (netperf) on multiple platforms/devices. Whatever is occurring also seems to invoke hdparm. I'm running 3.4.0-rc4 (recent net-next pull) with CONFIG_PREEMPT=y:
>
> skb_under_panic: text:ffffffff8130d538 len:120 put:14 head:ffff880128c89800 data:ffff880128c897f4 tail:0x6c end:0xc0 dev:eth0
> ------------[ cut here ]------------
> kernel BUG at net/core/skbuff.c:145!
> invalid opcode: 0000 [#1] PREEMPT SMP
> CPU 4
> Modules linked in: nfsd lockd exportfs sunrpc e1000e [last unloaded: scsi_wait_scan]
>
> Pid: 5030, comm: netperf Not tainted 3.4.0-rc2-net-next-e1000e-queue_20120423 #2 /DQ57TM
> RIP: 0010:[<ffffffff812ef1b4>] [<ffffffff812ef1b4>] skb_push+0x72/0x7b
> RSP: 0018:ffff8801283459d8 EFLAGS: 00010292
> RAX: 0000000000000084 RBX: ffff880127ffc000 RCX: 00000000fffffff3
> RDX: 00000000000000d6 RSI: 0000000000000046 RDI: ffffffff8162375a
> RBP: ffff8801283459f8 R08: 0000000000008d0a R09: ffff88012f019000
> R10: 0000000000000001 R11: 0000000000000078 R12: ffff880128ff6ca0
> R13: 0000000000000800 R14: 0000000000000212 R15: ffff880128ff6c98
> FS: 00007fc4c3feb700(0000) GS:ffff88012fc80000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
> CR2: ffffffffff600400 CR3: 0000000127e81000 CR4: 00000000000007e0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Process netperf (pid: 5030, threadinfo ffff880128344000, task ffff8801279859d0)
> Stack:
> 000000000000006c 00000000000000c0 ffff880127ffc000 ffff880128ff6ca0
> ffff880128345a38 ffffffff8130d538 ffff88010000006a 0000000000000000
> ffffffff81300cd5 ffff88011dfad9c0 ffff880128ff6c00 ffff880127ffc000
> Call Trace:
> [<ffffffff8130d538>] eth_header+0x28/0xb4
> [<ffffffff81300cd5>] ? neigh_resolve_output+0x14d/0x19a
> [<ffffffff81300cd7>] neigh_resolve_output+0x14f/0x19a
> [<ffffffff8131c35a>] ip_finish_output+0x22f/0x271
> [<ffffffff8131c3d9>] ip_output+0x3d/0x3f
> [<ffffffff81319dd4>] ip_local_out+0x62/0x64
> [<ffffffff81319ddf>] ip_send_skb+0x9/0x2c
> [<ffffffff81337a85>] udp_send_skb+0x250/0x2aa
> [<ffffffff81338fa2>] udp_sendmsg+0x4e3/0x6f8
> [<ffffffff8131b345>] ? ip_append_page+0x4b2/0x4b2
> [<ffffffff813a442b>] ? preempt_schedule_irq+0x3c/0x51
> [<ffffffff81049998>] ? __dequeue_entity+0x2e/0x33
> [<ffffffff8133f654>] inet_sendmsg+0x93/0x9c
> [<ffffffff812e741d>] sock_sendmsg+0xbb/0xd4
> [<ffffffff81049998>] ? __dequeue_entity+0x2e/0x33
> [<ffffffff81049998>] ? __dequeue_entity+0x2e/0x33
> [<ffffffff813a442b>] ? preempt_schedule_irq+0x3c/0x51
> [<ffffffff813a5516>] ? retint_kernel+0x26/0x30
> [<ffffffff812e748f>] ? sockfd_lookup_light+0x1b/0x54
> [<ffffffff812e7b3f>] sys_sendto+0xfa/0x122
> [<ffffffff813a442b>] ? preempt_schedule_irq+0x3c/0x51
> [<ffffffff813a97a2>] system_call_fastpath+0x16/0x1b
> Code: 8b 57 68 48 89 44 24 10 8b 87 b0 00 00 00 48 89 44 24 08 31 c0 8b bf ac 00 00 00 48 89 3c 24 48 c7 c7 b7 6d 4c 81 e8 26 37 0b 00 <0f> 0b eb fe 4c 89 c8 c9 c3 55 89 f1 48 89 e5 48 83 ec 20 4c 8b
> RIP [<ffffffff812ef1b4>] skb_push+0x72/0x7b
> RSP <ffff8801283459d8>
> ---[ end trace 35a690c4aebb4bd0 ]---
> hdparm: sending ioctl 330 to a partition!
> hdparm: sending ioctl 330 to a partition!
> hdparm: sending ioctl 330 to a partition!
> hdparm: sending ioctl 330 to a partition!
>
> Thanks in advance,
>
> Jeff Pieper
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: IP fragmentation broken in 3.6-rc ?
From: Julian Anastasov @ 2012-08-21 21:07 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Sylvain Munaut, netdev
In-Reply-To: <1345582019.5158.547.camel@edumazet-glaptop>
Hello,
On Tue, 21 Aug 2012, Eric Dumazet wrote:
> > dst_update_expires will be like dst_set_expires
> > but with this difference (time_after):
> >
> > if (dst->expires == 0 || time_after(expires, dst->expires) ||
> > !timeout)
>
> Hmm, all these tests are not really needed, what about :
>
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index e4ba974..8d6d320 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -956,7 +956,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
> dst->obsolete = DST_OBSOLETE_KILL;
> } else {
> rt->rt_pmtu = mtu;
> - dst_set_expires(&rt->dst, ip_rt_mtu_expires);
> + rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires);
The best solution, I think.
> }
> }
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply
* Re: [PATCH] tcp: fix possible socket refcount problem
From: David Miller @ 2012-08-21 21:43 UTC (permalink / raw)
To: eric.dumazet; +Cc: fengguang.wu, netdev
In-Reply-To: <1345458166.5158.316.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 20 Aug 2012 12:22:46 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> Commit 6f458dfb40 (tcp: improve latencies of timer triggered events)
> added bug leading to following trace :
...
> The bug comes from the fact that timer set in sk_reset_timer() can run
> before we actually do the sock_hold(). socket refcount reaches zero and
> we free the socket too soon.
>
> timer handler is not allowed to reduce socket refcnt if socket is owned
> by the user, or we need to change sk_reset_timer() implementation.
>
> We should take a reference on the socket in case TCP_DELACK_TIMER_DEFERRED
> or TCP_DELACK_TIMER_DEFERRED bit are set in tsq_flags
>
> Also fix a typo in tcp_delack_timer(), where TCP_WRITE_TIMER_DEFERRED
> was used instead of TCP_DELACK_TIMER_DEFERRED.
>
> For consistency, use same socket refcount change for TCP_MTU_REDUCED_DEFERRED,
> even if not fired from a timer.
>
> Reported-by: Fengguang Wu <fengguang.wu@intel.com>
> Tested-by: Fengguang Wu <fengguang.wu@intel.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied, thanks Eric.
^ permalink raw reply
* Re: [PATCH v2] ipv4: Use newinet->inet_opt in inet_csk_route_child_sock()
From: David Miller @ 2012-08-21 21:49 UTC (permalink / raw)
To: christoph.paasch; +Cc: netdev
In-Reply-To: <1345467129-4540-1-git-send-email-christoph.paasch@uclouvain.be>
From: Christoph Paasch <christoph.paasch@uclouvain.be>
Date: Mon, 20 Aug 2012 14:52:09 +0200
> Since 0e734419923bd ("ipv4: Use inet_csk_route_child_sock() in DCCP and
> TCP."), inet_csk_route_child_sock() is called instead of
> inet_csk_route_req().
>
> However, after creating the child-sock in tcp/dccp_v4_syn_recv_sock(),
> ireq->opt is set to NULL, before calling inet_csk_route_child_sock().
> Thus, inside inet_csk_route_child_sock() opt is always NULL and the
> SRR-options are not respected anymore.
> Packets sent by the server won't have the correct destination-IP.
>
> This patch fixes it by accessing newinet->inet_opt instead of ireq->opt
> inside inet_csk_route_child_sock().
>
> Reported-by: Luca Boccassi <luca.boccassi@gmail.com>
> Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] ipv4: fix ip header ident selection in __ip_make_skb()
From: David Miller @ 2012-08-21 21:51 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, shemminger, casteyde.christian
In-Reply-To: <1345483605.5158.345.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 20 Aug 2012 19:26:45 +0200
> From: Eric Dumazet <edumazet@google.com>
>
> Christian Casteyde reported a kmemcheck 32-bit read from uninitialized
> memory in __ip_select_ident().
>
> It turns out that __ip_make_skb() called ip_select_ident() before
> properly initializing iph->daddr.
>
> This is a bug uncovered by commit 1d861aa4b3fb (inet: Minimize use of
> cached route inetpeer.)
>
> Addresses https://bugzilla.kernel.org/show_bug.cgi?id=46131
>
> Reported-by: Christian Casteyde <casteyde.christian@free.fr>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Stephen Hemminger <shemminger@vyatta.com>
Applied, thanks Eric.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox