* Re: Flow Control and Port Mirroring Revisited
From: Michael S. Tsirkin @ 2011-01-22 21:57 UTC (permalink / raw)
To: Simon Horman
Cc: Rick Jones, Jesse Gross, Rusty Russell, virtualization, dev,
virtualization, netdev, kvm
In-Reply-To: <20110121231149.GI2195@verge.net.au>
On Sat, Jan 22, 2011 at 10:11:52AM +1100, Simon Horman wrote:
> On Fri, Jan 21, 2011 at 11:59:30AM +0200, Michael S. Tsirkin wrote:
> > On Thu, Jan 20, 2011 at 05:38:33PM +0900, Simon Horman wrote:
> > > [ Trimmed Eric from CC list as vger was complaining that it is too long ]
> > >
> > > On Tue, Jan 18, 2011 at 11:41:22AM -0800, Rick Jones wrote:
> > > > >So it won't be all that simple to implement well, and before we try,
> > > > >I'd like to know whether there are applications that are helped
> > > > >by it. For example, we could try to measure latency at various
> > > > >pps and see whether the backpressure helps. netperf has -b, -w
> > > > >flags which might help these measurements.
> > > >
> > > > Those options are enabled when one adds --enable-burst to the
> > > > pre-compilation ./configure of netperf (one doesn't have to
> > > > recompile netserver). However, if one is also looking at latency
> > > > statistics via the -j option in the top-of-trunk, or simply at the
> > > > histogram with --enable-histogram on the ./configure and a verbosity
> > > > level of 2 (global -v 2) then one wants the very top of trunk
> > > > netperf from:
> > >
> > > Hi,
> > >
> > > I have constructed a test where I run an un-paced UDP_STREAM test in
> > > one guest and a paced omni rr test in another guest at the same time.
> >
> > Hmm, what is this supposed to measure? Basically each time you run an
> > un-paced UDP_STREAM you get some random load on the network.
> > You can't tell what it was exactly, only that it was between
> > the send and receive throughput.
>
> Rick mentioned in another email that I messed up my test parameters a bit,
> so I will re-run the tests, incorporating his suggestions.
>
> What I was attempting to measure was the effect of an unpaced UDP_STREAM
> on the latency of more moderated traffic. Because I am interested in
> what effect an abusive guest has on other guests and how that my be
> mitigated.
>
> Could you suggest some tests that you feel are more appropriate?
Yes. To refraze my concern in these terms, besides the malicious guest
you have another software in host (netperf) that interferes with
the traffic, and it cooperates with the malicious guest.
Right?
IMO for a malicious guest you would send
UDP packets that then get dropped by the host.
For example block netperf in host so that
it does not consume packets from the socket.
^ permalink raw reply
* Re: Problems with /proc/net/tcp6 - possible bug - ipv6
From: Eric Dumazet @ 2011-01-22 21:40 UTC (permalink / raw)
To: PK; +Cc: linux-kernel, netdev, David Miller
In-Reply-To: <1295731235.2651.66.camel@edumazet-laptop>
Le samedi 22 janvier 2011 à 22:20 +0100, Eric Dumazet a écrit :
> Le samedi 22 janvier 2011 à 11:42 -0800, PK a écrit :
> > Eric Dumazet wrote:
> > >
> > > I had some incidents, after hours of testing...
> > >
> > > After following patch, I could not reproduce it.
> >
> >
> > Looks like that patch solved the /proc/net/tcp6 problem. The causal commit was
> > the one you identified... confirmed with bisect.
> >
> > These warnings show up when I run the script (or I presume any tcp6 connection
> > flooder) with /proc/sys/net/tcp/ipv4/tcp_tw_recycle enabled. There's textual
> > corruption of the traces a lot of the time. Here's a sample trace that doesn't
> > appear to be corrupt. All the warnings I've seen are from route.c:209, and I
> > don't see how that would cause memory corruption.
>
> Thats a different isse, already reported, under investigation.
>
> David did some changes recently
>
> http://comments.gmane.org/gmane.linux.network/179874
>
>
>
In my testings, I even have crashes in cleanup_once() if I
enable /proc/sys/net/ipv4/tcp_tw_recycle
^ permalink raw reply
* [PATCH] SUNRPC: Remove resource leak in svc_rdma_send_error()
From: Jesper Juhl @ 2011-01-22 21:40 UTC (permalink / raw)
To: linux-nfs
Cc: netdev, linux-kernel, Pavel Emelyanov, Chuck Lever, Tejun Heo,
Tom Tucker, David S. Miller, Trond Myklebust, Neil Brown,
J. Bruce Fields
We leak the memory allocated to 'ctxt' when we return after
'ib_dma_mapping_error()' returns !=0.
Signed-off-by: Jesper Juhl <jj@chaosbits.net>
---
svc_rdma_transport.c | 1 +
1 file changed, 1 insertion(+)
compile tested only
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 9df1ead..1a10dcd 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -1335,6 +1335,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
p, 0, length, DMA_FROM_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
put_page(p);
+ svc_rdma_put_context(ctxt, 1);
return;
}
atomic_inc(&xprt->sc_dma_used);
--
Jesper Juhl <jj@chaosbits.net> http://www.chaosbits.net/
Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html
Plain text mails only, please.
^ permalink raw reply related
* Re: Problems with /proc/net/tcp6 - possible bug - ipv6
From: Eric Dumazet @ 2011-01-22 21:20 UTC (permalink / raw)
To: PK; +Cc: linux-kernel, netdev, David Miller
In-Reply-To: <115440.16148.qm@web63902.mail.re1.yahoo.com>
Le samedi 22 janvier 2011 à 11:42 -0800, PK a écrit :
> Eric Dumazet wrote:
> >
> > I had some incidents, after hours of testing...
> >
> > After following patch, I could not reproduce it.
>
>
> Looks like that patch solved the /proc/net/tcp6 problem. The causal commit was
> the one you identified... confirmed with bisect.
>
> These warnings show up when I run the script (or I presume any tcp6 connection
> flooder) with /proc/sys/net/tcp/ipv4/tcp_tw_recycle enabled. There's textual
> corruption of the traces a lot of the time. Here's a sample trace that doesn't
> appear to be corrupt. All the warnings I've seen are from route.c:209, and I
> don't see how that would cause memory corruption.
Thats a different isse, already reported, under investigation.
David did some changes recently
http://comments.gmane.org/gmane.linux.network/179874
^ permalink raw reply
* Re: Problems with /proc/net/tcp6 - possible bug - ipv6
From: PK @ 2011-01-22 19:42 UTC (permalink / raw)
To: Eric Dumazet; +Cc: linux-kernel, netdev
In-Reply-To: <1295709344.2651.55.camel@edumazet-laptop>
Eric Dumazet wrote:
>
> I had some incidents, after hours of testing...
>
> After following patch, I could not reproduce it.
Looks like that patch solved the /proc/net/tcp6 problem. The causal commit was
the one you identified... confirmed with bisect.
These warnings show up when I run the script (or I presume any tcp6 connection
flooder) with /proc/sys/net/tcp/ipv4/tcp_tw_recycle enabled. There's textual
corruption of the traces a lot of the time. Here's a sample trace that doesn't
appear to be corrupt. All the warnings I've seen are from route.c:209, and I
don't see how that would cause memory corruption.
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629431] ------------[ cut here
]------------
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629435] WARNING: at
net/ipv6/route.c:209 rt6_bind_peer+0x74/0x80()
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629436] Hardware name: VirtualBox
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629437] Modules linked in: nls_utf8
isofs fuse snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_rawmidi
snd_seq_midi_eve
nt snd_seq snd_timer snd_seq_device snd psmouse e1000 i2c_piix4 soundcore
snd_page_alloc
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629446] Pid: 1741, comm: ruby Tainted:
G W 2.6.38-rc2+ #15
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629447] Call Trace:
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629448] <IRQ> [<ffffffff81048b7f>] ?
warn_slowpath_common+0x7f/0xc0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629452] [<ffffffff81048bda>] ?
warn_slowpath_null+0x1a/0x20
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629454] [<ffffffff814534a4>] ?
rt6_bind_peer+0x74/0x80
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629456] [<ffffffff8146aa2d>] ?
tcp_v6_get_peer+0xbd/0xd0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629458] [<ffffffff8140c6f7>] ?
tcp_time_wait+0x287/0x300
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629460] [<ffffffff813fd089>] ?
tcp_fin+0x119/0x1f0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629462] [<ffffffff813fd8de>] ?
tcp_data_queue+0x77e/0xc60
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629464] [<ffffffff814017f9>] ?
tcp_rcv_state_process+0x6f9/0xa40
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629466] [<ffffffff81400e25>] ?
tcp_rcv_established+0x345/0x620
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629468] [<ffffffff8146b0ee>] ?
tcp_v6_do_rcv+0x18e/0x540
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629470] [<ffffffff8146c468>] ?
tcp_v6_rcv+0x728/0x7e0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629473] [<ffffffff81447bdd>] ?
ip6_input_finish+0x17d/0x3a0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629475] [<ffffffff81447e58>] ?
ip6_input+0x58/0x60
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629477] [<ffffffff81447651>] ?
ip6_rcv_finish+0x21/0x50
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629488] [<ffffffff81447998>] ?
ipv6_rcv+0x318/0x3e0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629491] [<ffffffff813b3e7a>] ?
__netif_receive_skb+0x40a/0x690
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629493] [<ffffffff813b420a>] ?
process_backlog+0x10a/0x210
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629496] [<ffffffff814996b5>] ?
_raw_spin_lock_irq+0x15/0x20
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629498] [<ffffffff813b9612>] ?
net_rx_action+0x112/0x2f0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629500] [<ffffffff8104f85b>] ?
__do_softirq+0xab/0x200
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629502] [<ffffffff81003e7c>] ?
call_softirq+0x1c/0x30
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629503] <EOI> [<ffffffff81005505>] ?
do_softirq+0x65/0xa0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629506] [<ffffffff8104f354>] ?
local_bh_enable+0x94/0xa0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629508] [<ffffffff813b8372>] ?
dev_queue_xmit+0x1c2/0x620
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629510] [<ffffffff814452c6>] ?
ip6_finish_output2+0xb6/0x370
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629512] [<ffffffff8113d1c0>] ?
__pollwait+0x0/0xf0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629514] [<ffffffff81446770>] ?
ip6_finish_output+0x90/0xc0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629516] [<ffffffff81446818>] ?
ip6_output+0x78/0xf0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629518] [<ffffffff81443804>] ?
dst_output+0x14/0x20
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629520] [<ffffffff81446c88>] ?
ip6_xmit+0x3f8/0x4c0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629523] [<ffffffff814729f8>] ?
inet6_csk_xmit+0x268/0x2e0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629525] [<ffffffff8149968f>] ?
_raw_spin_lock_irqsave+0x2f/0x40
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629527] [<ffffffff814029a7>] ?
tcp_transmit_skb+0x407/0x8f0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629529] [<ffffffff81405197>] ?
tcp_write_xmit+0x1e7/0x9d0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629531] [<ffffffff81405c27>] ?
tcp_send_fin+0xa7/0x1d0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629533] [<ffffffff81405b06>] ?
__tcp_push_pending_frames+0x26/0xa0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629535] [<ffffffff81405bed>] ?
tcp_send_fin+0x6d/0x1d0
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629536] [<ffffffff813f64e9>] ?
tcp_close+0x109/0x440
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629539] [<ffffffff8141a9de>] ?
inet_release+0x5e/0x80
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629541] [<ffffffff8144226f>] ?
inet6_release+0x3f/0x50
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629548] [<ffffffff813a1559>] ?
sock_release+0x29/0x90
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629549] [<ffffffff813a15d7>] ?
sock_close+0x17/0x30
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629551] [<ffffffff8112cc0a>] ?
fput+0xea/0x260
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629553] [<ffffffff8112928d>] ?
filp_close+0x5d/0x90
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629555] [<ffffffff81129377>] ?
sys_close+0xb7/0x120
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629558] [<ffffffff81002f82>] ?
system_call_fastpath+0x16/0x1b
Jan 22 11:09:08 vbox-alpha kernel: [ 907.629559] ---[ end trace
e63dd54cc0b51607 ]---
^ permalink raw reply
* Re: [PATCH net-next-2.6 v5 1/1] can: c_can: Added support for Bosch C_CAN controller
From: Wolfgang Grandegger @ 2011-01-22 19:26 UTC (permalink / raw)
To: Bhupesh Sharma
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1295515238-481-1-git-send-email-bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
Hi Bhupesh,
at a closer look, I realized one more issue, apart from some minor ones...
On 01/20/2011 10:20 AM, Bhupesh Sharma wrote:
> Bosch C_CAN controller is a full-CAN implementation which is compliant
> to CAN protocol version 2.0 part A and B. Bosch C_CAN user manual can be
> obtained from:
> http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
> c_can/users_manual_c_can.pdf
>
> This patch adds the support for this controller.
> The following are the design choices made while writing the controller
> driver:
> 1. Interface Register set IF1 has be used only in the current design.
> 2. Out of the 32 Message objects available, 16 are kept aside for RX
> purposes and the rest for TX purposes.
> 3. NAPI implementation is such that both the TX and RX paths function
> in polling mode.
>
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
> ---
> Changes since V4:
> 1. Insured correct ISR implementation to allow shared IRQs.
> 2. To ensure better understanding of message object numbers
> and thierusage modified C_CAN_MSG_OBJ_RX_FIRST value from 0
Typo!
> to 1.
> 3. Corrected coding style globally.
> 4. Renamed Interface registers as *ifregs*.
>
> drivers/net/can/Kconfig | 2 +
> drivers/net/can/Makefile | 1 +
> drivers/net/can/c_can/Kconfig | 15 +
> drivers/net/can/c_can/Makefile | 8 +
> drivers/net/can/c_can/c_can.c | 958 ++++++++++++++++++++++++++++++++
> drivers/net/can/c_can/c_can.h | 229 ++++++++
> drivers/net/can/c_can/c_can_platform.c | 207 +++++++
> 7 files changed, 1420 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/c_can/Kconfig
> create mode 100644 drivers/net/can/c_can/Makefile
> create mode 100644 drivers/net/can/c_can/c_can.c
> create mode 100644 drivers/net/can/c_can/c_can.h
> create mode 100644 drivers/net/can/c_can/c_can_platform.c
>
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index 9d9e453..50549b5 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -86,6 +86,8 @@ source "drivers/net/can/mscan/Kconfig"
>
> source "drivers/net/can/sja1000/Kconfig"
>
> +source "drivers/net/can/c_can/Kconfig"
> +
> source "drivers/net/can/usb/Kconfig"
>
> config CAN_DEBUG_DEVICES
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 0057537..c3efeb3 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -11,6 +11,7 @@ obj-y += usb/
>
> obj-$(CONFIG_CAN_SJA1000) += sja1000/
> obj-$(CONFIG_CAN_MSCAN) += mscan/
> +obj-$(CONFIG_CAN_C_CAN) += c_can/
> obj-$(CONFIG_CAN_AT91) += at91_can.o
> obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
> obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
> diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
> new file mode 100644
> index 0000000..ffb9773
> --- /dev/null
> +++ b/drivers/net/can/c_can/Kconfig
> @@ -0,0 +1,15 @@
> +menuconfig CAN_C_CAN
> + tristate "Bosch C_CAN devices"
> + depends on CAN_DEV && HAS_IOMEM
> +
> +if CAN_C_CAN
> +
> +config CAN_C_CAN_PLATFORM
> + tristate "Generic Platform Bus based C_CAN driver"
> + ---help---
> + This driver adds support for the C_CAN chips connected to
> + the "platform bus" (Linux abstraction for directly to the
> + processor attached devices) which can be found on various
> + boards from ST Microelectronics (http://www.st.com)
> + like the SPEAr1310 and SPEAr320 evaluation boards.
> +endif
> diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
> new file mode 100644
> index 0000000..9273f6d
> --- /dev/null
> +++ b/drivers/net/can/c_can/Makefile
> @@ -0,0 +1,8 @@
> +#
> +# Makefile for the Bosch C_CAN controller drivers.
> +#
> +
> +obj-$(CONFIG_CAN_C_CAN) += c_can.o
> +obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
> +
> +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
> new file mode 100644
> index 0000000..66a400b
> --- /dev/null
> +++ b/drivers/net/can/c_can/c_can.c
...
> +static void c_can_handle_lost_msg_obj(struct net_device *dev,
> + int iface, int objno)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct sk_buff *skb;
> + struct can_frame *frame;
> +
> + netdev_err(dev, "msg lost in buffer %d\n", objno);
> +
> + c_can_object_get(dev, iface, objno, IF_COMM_ALL &
> + ~IF_COMM_TXRQST);
Does fit on one line.
...
> +static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, 0);
> + priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, 0);
> + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, 0);
> +
> + c_can_object_put(dev, iface, objno,
> + IF_COMM_ARB | IF_COMM_CONTROL);
Ditto
...
> +static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
> +{
> + return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
> + (priv->current_status & STATUS_LEC_MASK);
> +}
> +
> +static int c_can_err(struct net_device *dev,
> + enum c_can_bus_error_types error_type,
> + enum c_can_lec_type lec_type)
> +{
> + unsigned int reg_err_counter;
> + unsigned int rx_err_passive;
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + struct can_berr_counter bec;
> +
> + /* propogate the error condition to the CAN stack */
> + skb = alloc_can_err_skb(dev, &cf);
> + if (unlikely(!skb))
> + return 0;
> +
> + c_can_get_berr_counter(dev, &bec);
> + reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt);
> + rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
> + ERR_CNT_RP_SHIFT;
> +
> + if (error_type & C_CAN_ERROR_WARNING) {
> + /* error warning state */
> + priv->can.can_stats.error_warning++;
> + priv->can.state = CAN_STATE_ERROR_WARNING;
> + cf->can_id |= CAN_ERR_CRTL;
> + if (bec.rxerr > 96)
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + if (bec.txerr > 96)
> + cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
> + }
> + if (error_type & C_CAN_ERROR_PASSIVE) {
> + /* error passive state */
> + priv->can.can_stats.error_passive++;
> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
> + cf->can_id |= CAN_ERR_CRTL;
> + if (rx_err_passive)
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + if (bec.txerr > 127)
> + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> + }
> + if (error_type & C_CAN_BUS_OFF) {
> + /* bus-off state */
> + priv->can.state = CAN_STATE_BUS_OFF;
> + cf->can_id |= CAN_ERR_BUSOFF;
> + /*
> + * disable all interrupts in bus-off mode to ensure that
> + * the CPU is not hogged down
> + */
> + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
> + can_bus_off(dev);
> + }
> +
> + /*
> + * check for 'last error code' which tells us the
> + * type of the last error to occur on the CAN bus
> + */
> +
> + /* common for all type of bus errors */
> + priv->can.can_stats.bus_error++;
Does a state change always come together with a bus error?
> + stats->rx_errors++;
> + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> + cf->data[2] |= CAN_ERR_PROT_UNSPEC;
> +
> + switch (lec_type) {
> + case LEC_STUFF_ERROR:
> + netdev_dbg(dev, "stuff error\n");
> + cf->data[2] |= CAN_ERR_PROT_STUFF;
> + break;
> +
> + case LEC_FORM_ERROR:
> + netdev_dbg(dev, "form error\n");
> + cf->data[2] |= CAN_ERR_PROT_FORM;
> + break;
> +
> + case LEC_ACK_ERROR:
> + netdev_dbg(dev, "ack error\n");
> + cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
> + CAN_ERR_PROT_LOC_ACK_DEL);
> + break;
> +
> + case LEC_BIT1_ERROR:
> + netdev_dbg(dev, "bit1 error\n");
> + cf->data[2] |= CAN_ERR_PROT_BIT1;
> + break;
> +
> + case LEC_BIT0_ERROR:
> + netdev_dbg(dev, "bit0 error\n");
> + cf->data[2] |= CAN_ERR_PROT_BIT0;
> + break;
> +
> + case LEC_CRC_ERROR:
> + netdev_dbg(dev, "CRC error\n");
> + cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> + CAN_ERR_PROT_LOC_CRC_DEL);
> + break;
> + }
>From the C_CAN manual:
"The LEC field holds a code which indicates the type of the last error
to occur on the CAN bus. This field will be cleared to ‘0’ when a
message has been transferred (reception or transmission) without error.
The unused code ‘7’ may be written by the CPU to check for updates."
Not sure if it's necessary to reset the lec at init and after an error
to 0x7 and check it. More below...
> + netif_receive_skb(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +
> + return 1;
> +}
> +
> +static int c_can_poll(struct napi_struct *napi, int quota)
> +{
> + u16 irqstatus;
> + int lec_type = 0;
> + int work_done = 0;
> + struct net_device *dev = napi->dev;
> + struct c_can_priv *priv = netdev_priv(dev);
> + enum c_can_bus_error_types error_type = C_CAN_NO_ERROR;
> +
> + irqstatus = priv->read_reg(priv, &priv->regs->interrupt);
> + if (!irqstatus)
> + goto end;
> +
> + /* status events have the highest priority */
> + if (irqstatus == STATUS_INTERRUPT) {
> + priv->current_status = priv->read_reg(priv,
> + &priv->regs->status);
> +
> + /* handle Tx/Rx events */
> + if (priv->current_status & STATUS_TXOK)
> + priv->write_reg(priv, &priv->regs->status,
> + priv->current_status & ~STATUS_TXOK);
> +
> + if (priv->current_status & STATUS_RXOK)
> + priv->write_reg(priv, &priv->regs->status,
> + priv->current_status & ~STATUS_RXOK);
> +
> + /* handle bus error events */
> + if (priv->current_status & STATUS_EWARN) {
> + netdev_dbg(dev,
> + "entered error warning state\n");
Does fit on one line.
> + error_type = C_CAN_ERROR_WARNING;
> + }
> + if ((priv->current_status & STATUS_EPASS) &&
> + (!(priv->last_status & STATUS_EPASS))) {
> + netdev_dbg(dev,
> + "entered error passive state\n");
Ditto.
> + error_type = C_CAN_ERROR_PASSIVE;
> + }
> + if ((priv->current_status & STATUS_BOFF) &&
> + (!(priv->last_status & STATUS_BOFF))) {
> + netdev_dbg(dev,
> + "entered bus off state\n");
Ditto.
> + error_type = C_CAN_BUS_OFF;
> + }
> +
> + /* handle bus recovery events */
> + if ((!(priv->current_status & STATUS_EPASS)) &&
> + (priv->last_status & STATUS_EPASS)) {
> + netdev_dbg(dev,
> + "left error passive state\n");
Ditto.
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> + if ((!(priv->current_status & STATUS_BOFF)) &&
> + (priv->last_status & STATUS_BOFF)) {
> + netdev_dbg(dev,
> + "left bus off state\n");
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> +
> + priv->last_status = priv->current_status;
> +
> + /* handle error on the bus */
> + lec_type = c_can_has_and_handle_berr(priv);
> + if (lec_type && (error_type != C_CAN_NO_ERROR))
> + work_done += c_can_err(dev, error_type, lec_type);
State changes are only reported if berr_reporting is enabled and a bus
error occured. This needs to be fixed.
Feel free to send the output of "candump any,0:0,#FFFFFFFF" when sending
messages without cable connected and with a bus error provocuted.
Apart form that the patch looks really good.
Wolfgang.
^ permalink raw reply
* Re: [PATCH 1/2] linux-firmware: bnx2: Update firmware to 6.0.x.
From: David Woodhouse @ 2011-01-22 17:40 UTC (permalink / raw)
To: Michael Chan; +Cc: netdev
In-Reply-To: <1295473811-17443-1-git-send-email-mchan@broadcom.com>
On Wed, 2011-01-19 at 13:50 -0800, Michael Chan wrote:
> upstream kernel commit 22fa159d37efbfe781bbb99279efe83f58b87d29
>
> - Improved flow control and simplified interface
> - Use hardware RSS indirection table instead of the slower firmware-
> based table
> - Lower latency interrupt on 5709
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> Reviewed-by: Benjamin Li <benli@broadcom.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> bnx2/bnx2-mips-06-6.0.15.fw | Bin 0 -> 92780 bytes
> bnx2/bnx2-mips-09-6.0.17.fw | Bin 0 -> 103488 bytes
> bnx2/bnx2-rv2p-06-6.0.15.fw | Bin 0 -> 5696 bytes
> bnx2/bnx2-rv2p-09-6.0.17.fw | Bin 0 -> 6104 bytes
> bnx2/bnx2-rv2p-09ax-6.0.17.fw | Bin 0 -> 6616 bytes
> 5 files changed, 0 insertions(+), 0 deletions(-)
> create mode 100644 bnx2/bnx2-mips-06-6.0.15.fw
> create mode 100644 bnx2/bnx2-mips-09-6.0.17.fw
> create mode 100644 bnx2/bnx2-rv2p-06-6.0.15.fw
> create mode 100644 bnx2/bnx2-rv2p-09-6.0.17.fw
> create mode 100644 bnx2/bnx2-rv2p-09ax-6.0.17.fw
Please could you update the WHENCE file accordingly?
--
dwmw2
^ permalink raw reply
* Re: [GIT PULL nf-next-2.6] IPVS updates for v2.6.38-rc1
From: Patrick McHardy @ 2011-01-22 17:04 UTC (permalink / raw)
To: Simon Horman
Cc: lvs-devel, netfilter-devel, netdev, Changli Gao, Hans Schillstrom,
Julian Anastasov
In-Reply-To: <1295665835-8708-1-git-send-email-horms@verge.net.au>
On 22.01.2011 04:10, Simon Horman wrote:
> Hi Patrick, please consider pulling
> git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git for-patrick
>
> This includes bugfixes by Changli Gao and Hans Schillstrom.
>
> Changli Gao (1):
> netfilter: ipvs: fix compiler warnings
>
> Simon Horman (1):
> IPVS: Change sock_create_kernel() to __sock_create()
Pulled, thanks Simon.
^ permalink raw reply
* Re: [PATCH net-next-2.6 1/5] genirq: Add IRQ affinity notifiers
From: Thomas Gleixner @ 2011-01-22 16:38 UTC (permalink / raw)
To: David Miller; +Cc: bhutchings, netdev, linux-net-drivers, therbert
In-Reply-To: <20110119.134812.123988295.davem@davemloft.net>
B1;2401;0cOn Wed, 19 Jan 2011, David Miller wrote:
> You said you had stuff before Ben's patches, and that's why you needed
> to provide me with an -rc1 relative version of his commits.
I hope a rc2 relative version works as well :)
> If that's not the case, then yes it would work just fine.
>
> Just give me the URL to pull from, thanks!
git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git irq/numa
@Ben: Your patch was pretty white space damaged. Please be more
careful next time.
Thanks,
tglx
^ permalink raw reply
* Re: Problems with /proc/net/tcp6 - possible bug - ipv6
From: Eric Dumazet @ 2011-01-22 15:15 UTC (permalink / raw)
To: PK, David Miller; +Cc: linux-kernel, netdev, Tom Herbert
In-Reply-To: <1295686781.2609.37.camel@edumazet-laptop>
Le samedi 22 janvier 2011 à 09:59 +0100, Eric Dumazet a écrit :
> Le vendredi 21 janvier 2011 à 22:30 -0800, PK a écrit :
> > Creating many ipv6 connections hits a ceiling on connections/fds ; okay, fine.
> >
> > But in my case I'm seeing millions of entries spring up within a few seconds and
> > then vanish within a few minutes, in /proc/net/tcp6 (vanish due to garbage
> > collection?)
> >
> > Furthermore I can trigger this easily on vanilla kernels from 2.6.36 to
> > 2.6.38-rc1-next-20110121 inside a ubuntu 10.10 amd64 vm, causing the kernel to
> > spew warnings. There is also some corruption in the logs (see kernel-sample.log
> > line 296), but that may be unrelated.
> >
> > More explanation, kernel config of the primary machine I saw this on, sample
> > ruby script to reproduce (inside the ubuntu VMs I apt-get and use ruby-1.9.1),
> > are located at
> > https://github.com/runningdogx/net6-bug
> >
> > Seems to only affect 64-bit. So far I have not been able to reproduce on 32-bit
> > ubuntu VMs of any kernel version.
> > Seems to only affect IPv6. So far I have not been able to reproduce using IPv4
> > connections (and watching /proc/net/tcp of course).
> > Does not trigger the bug if the connections are made to ::1. Only externally
> > routable local and global IPv6 addresses seem to cause problems.
> > Seems to have been introduced between 2.6.35 and 2.6.36 (see README on github
> > for more kernels I've tried)
> >
> > All the tested Ubuntu VMs are stock 10.10 userland, with vanilla kernels (the
> > latest ubuntu kernel is 2.6.35-something, and my initial test didn't show it
> > suffering from this problem)
> >
> > Originally noticed on separate Gentoo 64-bit non-vm system when doing web
> > benchmarking.
> >
> > not subscribed, so please keep me in cc although I'll try to follow the thread
> >
> >
I had some incidents, after hours of testing...
After following patch, I could not reproduce it.
I cant believe this bug was not noticed before today.
Thanks !
[PATCH] tcp: fix bug in listening_get_next()
commit a8b690f98baf9fb19 (tcp: Fix slowness in read /proc/net/tcp)
introduced a bug in handling of SYN_RECV sockets.
st->offset represents number of sockets found since beginning of
listening_hash[st->bucket].
We should not reset st->offset when iterating through
syn_table[st->sbucket], or else if more than ~25 sockets (if
PAGE_SIZE=4096) are in SYN_RECV state, we exit from listening_get_next()
with a too small st->offset
Next time we enter tcp_seek_last_pos(), we are not able to seek past
already found sockets.
Reported-by: PK <runningdoglackey@yahoo.com>
CC: Tom Herbert <therbert@google.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/ipv4/tcp_ipv4.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 856f684..02f583b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1994,7 +1994,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
}
req = req->dl_next;
}
- st->offset = 0;
if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
break;
get_req:
^ permalink raw reply related
* Re: [PATCH 1/4] e1000e: convert to stats64
From: Flavio Leitner @ 2011-01-22 13:42 UTC (permalink / raw)
To: Jeff Kirsher; +Cc: David Miller, netdev, gospo, bphilips, Eric Dumazet
In-Reply-To: <1295697376-2984-2-git-send-email-jeffrey.t.kirsher@intel.com>
On Sat, Jan 22, 2011 at 03:56:13AM -0800, Jeff Kirsher wrote:
> Based on the patch provided by Flavio Leitner <fleitner@redhat.com>
> Provides accurate stats at the time user reads them.
>
> v2: fixed whitespace/merging issues (by Jeff Kirsher)
> v3: fixed namespacing issues (by Bruce Allan)
>
> CC: Flavio Leitner <fleitner@redhat.com>
> CC: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
> ---
> drivers/net/e1000e/e1000.h | 5 ++-
> drivers/net/e1000e/ethtool.c | 37 +++++++++++----------
> drivers/net/e1000e/netdev.c | 72 +++++++++++++++++++++++++++++++++---------
> 3 files changed, 80 insertions(+), 34 deletions(-)
Signed-off-by: Flavio Leitner <fleitner@redhat.com>
thanks,
Flavio
^ permalink raw reply
* [PATCH v5 15/27] rds: use little-endian bitops
From: Akinobu Mita @ 2011-01-22 13:13 UTC (permalink / raw)
To: linux-kernel, linux-arch, akpm
Cc: Akinobu Mita, Andy Grover, rds-devel, David S. Miller, netdev
In-Reply-To: <1295702039-23186-1-git-send-email-akinobu.mita@gmail.com>
As a preparation for removing ext2 non-atomic bit operations from
asm/bitops.h. This converts ext2 non-atomic bit operations to
little-endian bit operations.
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Andy Grover <andy.grover@oracle.com>
Cc: rds-devel@oss.oracle.com
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
---
Change from v4:
- splitted into two patches to fix a bisection hole
The whole series is available in the git branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/mita/linux-2.6.git le-bitops-v5
net/rds/cong.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/rds/cong.c b/net/rds/cong.c
index 8cc322b..6daaa49 100644
--- a/net/rds/cong.c
+++ b/net/rds/cong.c
@@ -284,7 +284,7 @@ void rds_cong_set_bit(struct rds_cong_map *map, __be16 port)
i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
- ext2_set_bit(off, (void *)map->m_page_addrs[i]);
+ __set_bit_le(off, (void *)map->m_page_addrs[i]);
}
void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
@@ -298,7 +298,7 @@ void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
- ext2_clear_bit(off, (void *)map->m_page_addrs[i]);
+ __clear_bit_le(off, (void *)map->m_page_addrs[i]);
}
static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
@@ -309,7 +309,7 @@ static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
- return ext2_test_bit(off, (void *)map->m_page_addrs[i]);
+ return test_bit_le(off, (void *)map->m_page_addrs[i]);
}
void rds_cong_add_socket(struct rds_sock *rs)
--
1.7.3.4
^ permalink raw reply related
* [PATCH v5 02/27] rds: stop including asm-generic/bitops/le.h directly
From: Akinobu Mita @ 2011-01-22 13:13 UTC (permalink / raw)
To: linux-kernel, linux-arch, akpm
Cc: Akinobu Mita, Andy Grover, rds-devel, David S. Miller, netdev
In-Reply-To: <1295702039-23186-1-git-send-email-akinobu.mita@gmail.com>
asm-generic/bitops/le.h is only intended to be included directly from
asm-generic/bitops/ext2-non-atomic.h or asm-generic/bitops/minix-le.h
which implements generic ext2 or minix bit operations.
This stops including asm-generic/bitops/le.h directly and use ext2
non-atomic bit operations instead.
It seems odd to use ext2_*_bit() on rds, but it will replaced with
__{set,clear,test}_bit_le() after introducing little endian bit operations
for all architectures. This indirect step is necessary to maintain
bisectability for some architectures which have their own little-endian
bit operations.
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Andy Grover <andy.grover@oracle.com>
Cc: rds-devel@oss.oracle.com
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
---
Change from v4:
- splitted into two patches to fix a bisection hole
The whole series is available in the git branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/mita/linux-2.6.git le-bitops-v5
net/rds/cong.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/net/rds/cong.c b/net/rds/cong.c
index 75ea686..8cc322b 100644
--- a/net/rds/cong.c
+++ b/net/rds/cong.c
@@ -33,8 +33,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/rbtree.h>
-
-#include <asm-generic/bitops/le.h>
+#include <linux/bitops.h>
#include "rds.h"
@@ -285,7 +284,7 @@ void rds_cong_set_bit(struct rds_cong_map *map, __be16 port)
i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
- generic___set_le_bit(off, (void *)map->m_page_addrs[i]);
+ ext2_set_bit(off, (void *)map->m_page_addrs[i]);
}
void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
@@ -299,7 +298,7 @@ void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
- generic___clear_le_bit(off, (void *)map->m_page_addrs[i]);
+ ext2_clear_bit(off, (void *)map->m_page_addrs[i]);
}
static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
@@ -310,7 +309,7 @@ static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
- return generic_test_le_bit(off, (void *)map->m_page_addrs[i]);
+ return ext2_test_bit(off, (void *)map->m_page_addrs[i]);
}
void rds_cong_add_socket(struct rds_sock *rs)
--
1.7.3.4
^ permalink raw reply related
* Re: [PATCH] bonding: added 802.3ad round-robin hashing policy for single TCP session balancing
From: Nicolas de Pesloüan @ 2011-01-22 12:48 UTC (permalink / raw)
To: Oleg V. Ukhno; +Cc: Jay Vosburgh, John Fastabend, netdev@vger.kernel.org
In-Reply-To: <4D399062.3060004@yandex-team.ru>
Le 21/01/2011 14:55, Oleg V. Ukhno a écrit :
> On 01/19/2011 11:12 PM, Nicolas de Pesloüan wrote:
>
>> If you have time for that, then yes, please, do the same test using
>> balance-rr+vlan to segregate path. With those results, we whould have
>> the opportunity to enhance the documentation with some well tested cases
>> of TCP load balancing on a LAN, not limited to 802.3ad automatic setup.
>> Both setups make sense, and assuming the results would be similar is
>> probably true, but not reliable enough to assert it into the
>> documentation.
>>
>> Thanks,
>>
>> Nicolas.
>>
> Nicolas,
> I've ran similar tests for VLAN tunneling scenario. Results are
> identical, as I expected. The only significat difference is link failure
> handling. 802.3ad mode allows almost painless load reditribution,
> balance-rr causes packet loss.
Oleg,
Thanks for doing the tests.
What link failure mode did you use for those tests ? miimon or arp monitoring ?
Nicolas.
^ permalink raw reply
* Re: [PATCH V9 08/13] posix clocks: cleanup the CLOCK_DISPTACH macro
From: Thomas Gleixner @ 2011-01-22 12:42 UTC (permalink / raw)
To: Richard Cochran
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
Alan Cox, Arnd Bergmann, Christoph Lameter, David Miller,
John Stultz, Krzysztof Halasa, Peter Zijlstra, Rodolfo Giometti
In-Reply-To: <20110122123840.GA30830-7KxsofuKt4IfAd9E5cN8NEzG7cXyKsk/@public.gmane.org>
On Sat, 22 Jan 2011, Richard Cochran wrote:
> On Thu, Jan 13, 2011 at 06:03:24PM +0100, Thomas Gleixner wrote:
> > On Thu, 13 Jan 2011, Richard Cochran wrote:
> > > int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *ts);
> > > int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *ts);
> > > -int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts);
> > > +int posix_cpu_clock_set(const clockid_t which_clock, struct timespec *ts);
> >
> > Shouldn't we change the clock_set function to have *ts const in all places ?
>
> The common_clock_set function calls:
>
> do_sys_settimeofday
> security_settime
> cap_settime
> do_settimeofday
>
> so all their signatures must also change.
>
> Should I add that into my patch set?
Yes please as a separate patch.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH V9 08/13] posix clocks: cleanup the CLOCK_DISPTACH macro
From: Richard Cochran @ 2011-01-22 12:38 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-kernel, linux-api, netdev, Alan Cox, Arnd Bergmann,
Christoph Lameter, David Miller, John Stultz, Krzysztof Halasa,
Peter Zijlstra, Rodolfo Giometti
In-Reply-To: <alpine.LFD.2.00.1101131745400.2678@localhost6.localdomain6>
On Thu, Jan 13, 2011 at 06:03:24PM +0100, Thomas Gleixner wrote:
> On Thu, 13 Jan 2011, Richard Cochran wrote:
> > int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *ts);
> > int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *ts);
> > -int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts);
> > +int posix_cpu_clock_set(const clockid_t which_clock, struct timespec *ts);
>
> Shouldn't we change the clock_set function to have *ts const in all places ?
The common_clock_set function calls:
do_sys_settimeofday
security_settime
cap_settime
do_settimeofday
so all their signatures must also change.
Should I add that into my patch set?
Thanks,
Richard
^ permalink raw reply
* [PATCH 3/4] e1000e: Use kmemdup rather than duplicating its implementation
From: Jeff Kirsher @ 2011-01-22 11:56 UTC (permalink / raw)
To: David Miller, davem; +Cc: Bruce Allan, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1295697376-2984-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Bruce Allan <bruce.w.allan@intel.com>
The semantic patch that makes this output is available
in scripts/coccinelle/api/memdup.cocci.
More information about semantic patching is available at
http://coccinelle.lip6.fr/
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/e1000e/ethtool.c | 11 ++---------
1 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 323fd12..daa7fe4 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -684,20 +684,13 @@ static int e1000_set_ringparam(struct net_device *netdev,
rx_old = adapter->rx_ring;
err = -ENOMEM;
- tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ tx_ring = kmemdup(tx_old, sizeof(struct e1000_ring), GFP_KERNEL);
if (!tx_ring)
goto err_alloc_tx;
- /*
- * use a memcpy to save any previously configured
- * items like napi structs from having to be
- * reinitialized
- */
- memcpy(tx_ring, tx_old, sizeof(struct e1000_ring));
- rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ rx_ring = kmemdup(rx_old, sizeof(struct e1000_ring), GFP_KERNEL);
if (!rx_ring)
goto err_alloc_rx;
- memcpy(rx_ring, rx_old, sizeof(struct e1000_ring));
adapter->tx_ring = tx_ring;
adapter->rx_ring = rx_ring;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 4/4] igb: Add support for i340 Quad Port Fiber Adapter
From: Jeff Kirsher @ 2011-01-22 11:56 UTC (permalink / raw)
To: David Miller, davem
Cc: Carolyn Wyborny, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1295697376-2984-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Carolyn Wyborny <carolyn.wyborny@intel.com>
This patch enables support for Intel i340 Quad Port Fiber Adapter.
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/igb/e1000_82575.c | 1 +
drivers/net/igb/e1000_hw.h | 1 +
drivers/net/igb/igb_main.c | 1 +
3 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 0a2368f..c1552b6 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -129,6 +129,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82580_COPPER:
case E1000_DEV_ID_82580_FIBER:
+ case E1000_DEV_ID_82580_QUAD_FIBER:
case E1000_DEV_ID_82580_SERDES:
case E1000_DEV_ID_82580_SGMII:
case E1000_DEV_ID_82580_COPPER_DUAL:
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index e2638af..281324e 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -54,6 +54,7 @@ struct e1000_hw;
#define E1000_DEV_ID_82580_SERDES 0x1510
#define E1000_DEV_ID_82580_SGMII 0x1511
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 58c665b..200cc32 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -68,6 +68,7 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
--
1.7.3.4
^ permalink raw reply related
* [PATCH 2/4] e1000e: reduce scope of some variables, remove unnecessary ones
From: Jeff Kirsher @ 2011-01-22 11:56 UTC (permalink / raw)
To: David Miller, davem; +Cc: Bruce Allan, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1295697376-2984-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Bruce Allan <bruce.w.allan@intel.com>
Static analysis of the driver code found some variables for which the scope
can be reduced, or remove the variable altogether.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/e1000e/ethtool.c | 4 +--
drivers/net/e1000e/ich8lan.c | 3 +-
drivers/net/e1000e/lib.c | 4 +-
drivers/net/e1000e/netdev.c | 45 ++++++++++++++++++++---------------------
drivers/net/e1000e/phy.c | 8 +++---
5 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index dfa44de..323fd12 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -1255,7 +1255,6 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl_reg = 0;
- u32 stat_reg = 0;
u16 phy_reg = 0;
s32 ret_val = 0;
@@ -1363,8 +1362,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
* Set the ILOS bit on the fiber Nic if half duplex link is
* detected.
*/
- stat_reg = er32(STATUS);
- if ((stat_reg & E1000_STATUS_FD) == 0)
+ if ((er32(STATUS) & E1000_STATUS_FD) == 0)
ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
}
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index fb46974..232b42b 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -2104,7 +2104,6 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
{
union ich8_hws_flash_status hsfsts;
s32 ret_val = -E1000_ERR_NVM;
- s32 i = 0;
hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
@@ -2140,6 +2139,8 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
ret_val = 0;
} else {
+ s32 i = 0;
+
/*
* Otherwise poll for sometime so the current
* cycle has a chance to end before giving up.
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 68aa174..96921de 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -1978,15 +1978,15 @@ static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
{
struct e1000_nvm_info *nvm = &hw->nvm;
u32 eecd = er32(EECD);
- u16 timeout = 0;
u8 spi_stat_reg;
if (nvm->type == e1000_nvm_eeprom_spi) {
+ u16 timeout = NVM_MAX_RETRY_SPI;
+
/* Clear SK and CS */
eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
ew32(EECD, eecd);
udelay(1);
- timeout = NVM_MAX_RETRY_SPI;
/*
* Read "Status Register" repeatedly until the LSB is cleared.
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 1c2f33d..5b916b0 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2720,7 +2720,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 rctl, rfctl;
- u32 psrctl = 0;
u32 pages = 0;
/* Workaround Si errata on 82579 - configure jumbo frame flow */
@@ -2819,6 +2818,8 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
adapter->rx_ps_pages = 0;
if (adapter->rx_ps_pages) {
+ u32 psrctl = 0;
+
/* Configure extra packet-split registers */
rfctl = er32(RFCTL);
rfctl |= E1000_RFCTL_EXTEN;
@@ -3020,7 +3021,6 @@ static void e1000_set_multi(struct net_device *netdev)
struct netdev_hw_addr *ha;
u8 *mta_list;
u32 rctl;
- int i;
/* Check for Promiscuous and All Multicast modes */
@@ -3043,12 +3043,13 @@ static void e1000_set_multi(struct net_device *netdev)
ew32(RCTL, rctl);
if (!netdev_mc_empty(netdev)) {
+ int i = 0;
+
mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
if (!mta_list)
return;
/* prepare a packed array of only addresses. */
- i = 0;
netdev_for_each_mc_addr(ha, netdev)
memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
@@ -3999,10 +4000,11 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct e1000_phy_regs *phy = &adapter->phy_regs;
- int ret_val;
if ((er32(STATUS) & E1000_STATUS_LU) &&
(adapter->hw.phy.media_type == e1000_media_type_copper)) {
+ int ret_val;
+
ret_val = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr);
ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr);
ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise);
@@ -4148,7 +4150,6 @@ static void e1000_watchdog_task(struct work_struct *work)
struct e1000_ring *tx_ring = adapter->tx_ring;
struct e1000_hw *hw = &adapter->hw;
u32 link, tctl;
- int tx_pending = 0;
link = e1000e_has_link(adapter);
if ((netif_carrier_ok(netdev)) && link) {
@@ -4302,21 +4303,18 @@ link_up:
e1000e_update_adaptive(&adapter->hw);
- if (!netif_carrier_ok(netdev)) {
- tx_pending = (e1000_desc_unused(tx_ring) + 1 <
- tx_ring->count);
- if (tx_pending) {
- /*
- * We've lost link, so the controller stops DMA,
- * but we've got queued Tx work that's never going
- * to get done, so reset controller to flush Tx.
- * (Do the reset outside of interrupt context).
- */
- adapter->tx_timeout_count++;
- schedule_work(&adapter->reset_task);
- /* return immediately since reset is imminent */
- return;
- }
+ if (!netif_carrier_ok(netdev) &&
+ (e1000_desc_unused(tx_ring) + 1 < tx_ring->count)) {
+ /*
+ * We've lost link, so the controller stops DMA,
+ * but we've got queued Tx work that's never going
+ * to get done, so reset controller to flush Tx.
+ * (Do the reset outside of interrupt context).
+ */
+ adapter->tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+ /* return immediately since reset is imminent */
+ return;
}
/* Simple mode for Interrupt Throttle Rate (ITR) */
@@ -4387,13 +4385,13 @@ static int e1000_tso(struct e1000_adapter *adapter,
u32 cmd_length = 0;
u16 ipcse = 0, tucse, mss;
u8 ipcss, ipcso, tucss, tucso, hdr_len;
- int err;
if (!skb_is_gso(skb))
return 0;
if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ int err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+
if (err)
return err;
}
@@ -5518,9 +5516,10 @@ static irqreturn_t e1000_intr_msix(int irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
- int vector, msix_irq;
if (adapter->msix_entries) {
+ int vector, msix_irq;
+
vector = 0;
msix_irq = adapter->msix_entries[vector].vector;
disable_irq(msix_irq);
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 6bea051..6ae31fc 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -2409,9 +2409,7 @@ static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg)
s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
{
s32 ret_val;
- u32 page_select = 0;
u32 page = offset >> IGP_PAGE_SHIFT;
- u32 page_shift = 0;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
@@ -2427,6 +2425,8 @@ s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ u32 page_shift, page_select;
+
/*
* Page select is register 31 for phy address 1 and 22 for
* phy address 2 and 3. Page select is shifted only for
@@ -2468,9 +2468,7 @@ out:
s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
{
s32 ret_val;
- u32 page_select = 0;
u32 page = offset >> IGP_PAGE_SHIFT;
- u32 page_shift = 0;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
@@ -2486,6 +2484,8 @@ s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ u32 page_shift, page_select;
+
/*
* Page select is register 31 for phy address 1 and 22 for
* phy address 2 and 3. Page select is shifted only for
--
1.7.3.4
^ permalink raw reply related
* [PATCH 1/4] e1000e: convert to stats64
From: Jeff Kirsher @ 2011-01-22 11:56 UTC (permalink / raw)
To: David Miller, davem
Cc: Jeff Kirsher, netdev, gospo, bphilips, Flavio Leitner,
Eric Dumazet
In-Reply-To: <1295697376-2984-1-git-send-email-jeffrey.t.kirsher@intel.com>
Based on the patch provided by Flavio Leitner <fleitner@redhat.com>
Provides accurate stats at the time user reads them.
v2: fixed whitespace/merging issues (by Jeff Kirsher)
v3: fixed namespacing issues (by Bruce Allan)
CC: Flavio Leitner <fleitner@redhat.com>
CC: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
---
drivers/net/e1000e/e1000.h | 5 ++-
drivers/net/e1000e/ethtool.c | 37 +++++++++++----------
drivers/net/e1000e/netdev.c | 72 +++++++++++++++++++++++++++++++++---------
3 files changed, 80 insertions(+), 34 deletions(-)
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index e610e13..00bf595 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -364,6 +364,7 @@ struct e1000_adapter {
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
+ spinlock_t stats64_lock;
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
@@ -494,7 +495,9 @@ extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter);
extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
-extern void e1000e_update_stats(struct e1000_adapter *adapter);
+extern struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64
+ *stats);
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_get_hw_control(struct e1000_adapter *adapter);
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index fa08b63..dfa44de 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -46,15 +46,15 @@ struct e1000_stats {
};
#define E1000_STAT(str, m) { \
- .stat_string = str, \
- .type = E1000_STATS, \
- .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \
- .stat_offset = offsetof(struct e1000_adapter, m) }
+ .stat_string = str, \
+ .type = E1000_STATS, \
+ .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \
+ .stat_offset = offsetof(struct e1000_adapter, m) }
#define E1000_NETDEV_STAT(str, m) { \
- .stat_string = str, \
- .type = NETDEV_STATS, \
- .sizeof_stat = sizeof(((struct net_device *)0)->m), \
- .stat_offset = offsetof(struct net_device, m) }
+ .stat_string = str, \
+ .type = NETDEV_STATS, \
+ .sizeof_stat = sizeof(((struct rtnl_link_stats64 *)0)->m), \
+ .stat_offset = offsetof(struct rtnl_link_stats64, m) }
static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("rx_packets", stats.gprc),
@@ -65,21 +65,21 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("tx_broadcast", stats.bptc),
E1000_STAT("rx_multicast", stats.mprc),
E1000_STAT("tx_multicast", stats.mptc),
- E1000_NETDEV_STAT("rx_errors", stats.rx_errors),
- E1000_NETDEV_STAT("tx_errors", stats.tx_errors),
- E1000_NETDEV_STAT("tx_dropped", stats.tx_dropped),
+ E1000_NETDEV_STAT("rx_errors", rx_errors),
+ E1000_NETDEV_STAT("tx_errors", tx_errors),
+ E1000_NETDEV_STAT("tx_dropped", tx_dropped),
E1000_STAT("multicast", stats.mprc),
E1000_STAT("collisions", stats.colc),
- E1000_NETDEV_STAT("rx_length_errors", stats.rx_length_errors),
- E1000_NETDEV_STAT("rx_over_errors", stats.rx_over_errors),
+ E1000_NETDEV_STAT("rx_length_errors", rx_length_errors),
+ E1000_NETDEV_STAT("rx_over_errors", rx_over_errors),
E1000_STAT("rx_crc_errors", stats.crcerrs),
- E1000_NETDEV_STAT("rx_frame_errors", stats.rx_frame_errors),
+ E1000_NETDEV_STAT("rx_frame_errors", rx_frame_errors),
E1000_STAT("rx_no_buffer_count", stats.rnbc),
E1000_STAT("rx_missed_errors", stats.mpc),
E1000_STAT("tx_aborted_errors", stats.ecol),
E1000_STAT("tx_carrier_errors", stats.tncrs),
- E1000_NETDEV_STAT("tx_fifo_errors", stats.tx_fifo_errors),
- E1000_NETDEV_STAT("tx_heartbeat_errors", stats.tx_heartbeat_errors),
+ E1000_NETDEV_STAT("tx_fifo_errors", tx_fifo_errors),
+ E1000_NETDEV_STAT("tx_heartbeat_errors", tx_heartbeat_errors),
E1000_STAT("tx_window_errors", stats.latecol),
E1000_STAT("tx_abort_late_coll", stats.latecol),
E1000_STAT("tx_deferred_ok", stats.dc),
@@ -1982,14 +1982,15 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
u64 *data)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct rtnl_link_stats64 net_stats;
int i;
char *p = NULL;
- e1000e_update_stats(adapter);
+ e1000e_get_stats64(netdev, &net_stats);
for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
switch (e1000_gstrings_stats[i].type) {
case NETDEV_STATS:
- p = (char *) netdev +
+ p = (char *) &net_stats +
e1000_gstrings_stats[i].stat_offset;
break;
case E1000_STATS:
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 1c18f26..1c2f33d 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -900,8 +900,6 @@ next_desc:
adapter->total_rx_bytes += total_rx_bytes;
adapter->total_rx_packets += total_rx_packets;
- netdev->stats.rx_bytes += total_rx_bytes;
- netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -1057,8 +1055,6 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
}
adapter->total_tx_bytes += total_tx_bytes;
adapter->total_tx_packets += total_tx_packets;
- netdev->stats.tx_bytes += total_tx_bytes;
- netdev->stats.tx_packets += total_tx_packets;
return count < tx_ring->count;
}
@@ -1245,8 +1241,6 @@ next_desc:
adapter->total_rx_bytes += total_rx_bytes;
adapter->total_rx_packets += total_rx_packets;
- netdev->stats.rx_bytes += total_rx_bytes;
- netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -1426,8 +1420,6 @@ next_desc:
adapter->total_rx_bytes += total_rx_bytes;
adapter->total_rx_packets += total_rx_packets;
- netdev->stats.rx_bytes += total_rx_bytes;
- netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -3338,6 +3330,8 @@ int e1000e_up(struct e1000_adapter *adapter)
return 0;
}
+static void e1000e_update_stats(struct e1000_adapter *adapter);
+
void e1000e_down(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -3372,6 +3366,11 @@ void e1000e_down(struct e1000_adapter *adapter)
del_timer_sync(&adapter->phy_info_timer);
netif_carrier_off(netdev);
+
+ spin_lock(&adapter->stats64_lock);
+ e1000e_update_stats(adapter);
+ spin_unlock(&adapter->stats64_lock);
+
adapter->link_speed = 0;
adapter->link_duplex = 0;
@@ -3413,6 +3412,8 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+ spin_lock_init(&adapter->stats64_lock);
+
e1000e_set_interrupt_capability(adapter);
if (e1000_alloc_queues(adapter))
@@ -3886,7 +3887,7 @@ release:
* e1000e_update_stats - Update the board statistics counters
* @adapter: board private structure
**/
-void e1000e_update_stats(struct e1000_adapter *adapter)
+static void e1000e_update_stats(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
@@ -4285,7 +4286,9 @@ static void e1000_watchdog_task(struct work_struct *work)
}
link_up:
+ spin_lock(&adapter->stats64_lock);
e1000e_update_stats(adapter);
+ spin_unlock(&adapter->stats64_lock);
mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
adapter->tpt_old = adapter->stats.tpt;
@@ -4897,16 +4900,55 @@ static void e1000_reset_task(struct work_struct *work)
}
/**
- * e1000_get_stats - Get System Network Statistics
+ * e1000_get_stats64 - Get System Network Statistics
* @netdev: network interface device structure
+ * @stats: rtnl_link_stats64 pointer
*
* Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
**/
-static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
+struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
{
- /* only return the current stats */
- return &netdev->stats;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ memset(stats, 0, sizeof(struct rtnl_link_stats64));
+ spin_lock(&adapter->stats64_lock);
+ e1000e_update_stats(adapter);
+ /* Fill out the OS statistics structure */
+ stats->rx_bytes = adapter->stats.gorc;
+ stats->rx_packets = adapter->stats.gprc;
+ stats->tx_bytes = adapter->stats.gotc;
+ stats->tx_packets = adapter->stats.gptc;
+ stats->multicast = adapter->stats.mprc;
+ stats->collisions = adapter->stats.colc;
+
+ /* Rx Errors */
+
+ /*
+ * RLEC on some newer hardware can be incorrect so build
+ * our own version based on RUC and ROC
+ */
+ stats->rx_errors = adapter->stats.rxerrc +
+ adapter->stats.crcerrs + adapter->stats.algnerrc +
+ adapter->stats.ruc + adapter->stats.roc +
+ adapter->stats.cexterr;
+ stats->rx_length_errors = adapter->stats.ruc +
+ adapter->stats.roc;
+ stats->rx_crc_errors = adapter->stats.crcerrs;
+ stats->rx_frame_errors = adapter->stats.algnerrc;
+ stats->rx_missed_errors = adapter->stats.mpc;
+
+ /* Tx Errors */
+ stats->tx_errors = adapter->stats.ecol +
+ adapter->stats.latecol;
+ stats->tx_aborted_errors = adapter->stats.ecol;
+ stats->tx_window_errors = adapter->stats.latecol;
+ stats->tx_carrier_errors = adapter->stats.tncrs;
+
+ /* Tx Dropped needs to be maintained elsewhere */
+
+ spin_unlock(&adapter->stats64_lock);
+ return stats;
}
/**
@@ -5675,7 +5717,7 @@ static const struct net_device_ops e1000e_netdev_ops = {
.ndo_open = e1000_open,
.ndo_stop = e1000_close,
.ndo_start_xmit = e1000_xmit_frame,
- .ndo_get_stats = e1000_get_stats,
+ .ndo_get_stats64 = e1000e_get_stats64,
.ndo_set_multicast_list = e1000_set_multi,
.ndo_set_mac_address = e1000_set_mac,
.ndo_change_mtu = e1000_change_mtu,
--
1.7.3.4
^ permalink raw reply related
* [net-next 0/4][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2011-01-22 11:56 UTC (permalink / raw)
To: David Miller, davem; +Cc: Jeff Kirsher, netdev, gospo, bphilips
The following series contains cleanups for e1000e and addition support
for the i340 adapter in igb.
The following are changes since commit bb134d2298b49f50cf6d9388410fba96272905dc:
net: netif_setup_tc() is static
and are available in the git repository at:
master.kernel.org:/pub/scm/linux/kernel/git/jkirsher/net-next-2.6 master
Bruce Allan (2):
e1000e: reduce scope of some variables, remove unnecessary ones
e1000e: Use kmemdup rather than duplicating its implementation
Carolyn Wyborny (1):
igb: Add support for i340 Quad Port Fiber Adapter
Jeff Kirsher (1):
e1000e: convert to stats64
drivers/net/e1000e/e1000.h | 5 ++-
drivers/net/e1000e/ethtool.c | 52 ++++++++-----------
drivers/net/e1000e/ich8lan.c | 3 +-
drivers/net/e1000e/lib.c | 4 +-
drivers/net/e1000e/netdev.c | 117 +++++++++++++++++++++++++++-------------
drivers/net/e1000e/phy.c | 8 ++--
drivers/net/igb/e1000_82575.c | 1 +
drivers/net/igb/e1000_hw.h | 1 +
drivers/net/igb/igb_main.c | 1 +
9 files changed, 116 insertions(+), 76 deletions(-)
--
1.7.3.4
^ permalink raw reply
* [PATCH] unicore32: add nic/mac driver for PKUnity SoC
From: Guan Xuetao @ 2011-01-22 11:09 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel
From: Guan Xuetao <gxt@mprc.pku.edu.cn>
This patch adds nic/mac driver for PKUnity SoC.
Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
---
drivers/net/Kconfig | 6 +
drivers/net/Makefile | 1 +
drivers/net/puv3_mac.c | 2066 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 2073 insertions(+), 0 deletions(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4f1755b..cc99bc3 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2014,6 +2014,12 @@ config BCM63XX_ENET
This driver supports the ethernet MACs in the Broadcom 63xx
MIPS chipset family (BCM63XX).
+config PUV3_MAC
+ tristate "PKUnity v3 UMAL Gigabit Network Adapter support"
+ depends on UNICORE32 && ARCH_PUV3
+ select MII
+ select PHYLIB
+
source "drivers/net/fs_enet/Kconfig"
source "drivers/net/octeon/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90738d..9533b62 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -147,6 +147,7 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_AX88796) += ax88796.o
obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_PUV3_MAC) += puv3_mac.o
obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
diff --git a/drivers/net/puv3_mac.c b/drivers/net/puv3_mac.c
new file mode 100644
index 0000000..b96c10c
--- /dev/null
+++ b/drivers/net/puv3_mac.c
@@ -0,0 +1,2066 @@
+/*
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ * Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bug.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/cache.h>
+#include <linux/io.h>
+
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <mach/hardware.h>
+
+MODULE_DESCRIPTION("PKUNITY-3 SOC Ethernet driver");
+MODULE_LICENSE("GPL v2");
+
+/**********************************************************************
+ * Globals
+ ********************************************************************* */
+
+static const char umal_string[] = "PKUnity-v3-UMAL";
+static const char umal_mdio_string[] = "umal-mdio";
+
+struct eth_addr {
+ u8 addr[6];
+};
+
+struct eth_addr hw_addr[1] = {
+ { {0x00, 0x25, 0x9b, 0xff, 0x00, 0x00} }
+};
+
+/**********************************************************************
+ * Simple types
+ ********************************************************************* */
+
+enum umal_speed {
+ umal_speed_none = 0,
+ umal_speed_10 = SPEED_10,
+ umal_speed_100 = SPEED_100,
+ umal_speed_1000 = SPEED_1000,
+};
+
+enum umal_duplex {
+ umal_duplex_none = -1,
+ umal_duplex_half = DUPLEX_HALF,
+ umal_duplex_full = DUPLEX_FULL,
+};
+
+enum umal_fc {
+ umal_fc_none,
+ umal_fc_disabled,
+ umal_fc_frame,
+ umal_fc_collision,
+ umal_fc_carrier,
+};
+
+enum umal_state {
+ umal_state_uninit,
+ umal_state_off,
+ umal_state_on,
+ umal_state_broken,
+};
+
+/**********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define UMALDMA_NEXTBUF(d, f) ((((d)->f+1) == (d)->umaldma_dscrtable_end) ? \
+ (d)->umaldma_dscrtable : (d)->f+1)
+
+#define DMA_RX 0
+#define DMA_TX 1
+
+#define UMAL_MAX_TXDESCR 256
+#define UMAL_MAX_RXDESCR 256
+
+#define ETHER_ADDR_LEN 6
+#define ENET_PACKET_SIZE 1518
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (2*HZ)
+
+/**********************************************************************
+ * DMA Descriptor structure
+ ********************************************************************* */
+
+struct umaldmadscr {
+ dma_addr_t PacketStartAddr;
+ int PacketSize;
+ dma_addr_t NextDescriptor;
+ struct umaldmadscr *NextDescriptor_Virt;
+};
+
+/**********************************************************************
+ * DMA Controller structure
+ ********************************************************************* */
+
+struct umaldma {
+ /*
+ * This stuff is used to identify the channel and the registers
+ * associated with it.
+ */
+ /* back pointer to associated MAC */
+ struct umal_softc *umaldma_eth;
+ /* direction (1=transmit) */
+ int umaldma_txdir;
+ /* total # of descriptors in ring */
+ int umaldma_maxdescr;
+ /*
+ * This stuff is for maintenance of the ring
+ */
+ /* base of descriptor table */
+ struct umaldmadscr *umaldma_dscrtable;
+ void *umaldma_dscrtable_unaligned;
+ /* and also the phys addr */
+ dma_addr_t umaldma_dscrtable_phys;
+ /* and also the phys addr */
+ dma_addr_t umaldma_dscrtable_phys_unaligned;
+ /* end of descriptor table */
+ struct umaldmadscr *umaldma_dscrtable_end;
+ /* context table, one per descr */
+ struct sk_buff **umaldma_ctxtable;
+ /* next dscr for sw to add */
+ struct umaldmadscr *umaldma_addptr;
+ /* next dscr for sw to remove */
+ struct umaldmadscr *umaldma_remptr;
+};
+
+/**********************************************************************
+ * Ethernet softc structure
+ ********************************************************************* */
+
+struct umal_softc {
+
+ /*
+ * Linux-specific things
+ */
+ struct net_device *umal_dev; /* pointer to linux device */
+ int umal_idx;
+ struct phy_device *phy_dev; /* the associated PHY device */
+ struct mii_bus *mii_bus; /* the MII bus */
+ int phy_irq[PHY_MAX_ADDR];
+ spinlock_t umal_lock; /* spin lock */
+ int umal_devflags; /* current device flags */
+
+ /*
+ * Controller-specific things
+ */
+ enum umal_state umal_state; /* current state */
+ unsigned char umal_hwaddr[ETHER_ADDR_LEN];
+
+ enum umal_speed umal_speed; /* current speed */
+ enum umal_duplex umal_duplex; /* current duplex */
+ enum umal_fc umal_fc; /* cur. flow control setting */
+ int umal_pause; /* current pause setting */
+ int umal_link; /* current link state */
+
+ struct umaldma umal_rxdma; /* rx dma channel */
+ struct umaldma umal_txdma; /* tx dma channel */
+};
+
+/**********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static int umal_mii_reset(struct mii_bus *bus);
+static int umal_mii_read(struct mii_bus *bus, int phyaddr, int regidx);
+static int umal_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+ u16 val);
+static int umal_mii_probe(struct net_device *dev);
+
+static void umaldma_initctx(struct umaldma *d, struct umal_softc *s,
+ int rxtx, int maxdescr);
+static void umaldma_uninitctx(struct umaldma *d);
+static void umaldma_channel_start(struct umaldma *d, int rxtx);
+static void umaldma_channel_stop(struct umaldma *d);
+static int umaldma_add_rcvbuffer(struct umal_softc *sc, struct umaldma *d,
+ struct sk_buff *m);
+static int umaldma_add_txbuffer(struct umaldma *d, struct sk_buff *m);
+static void umaldma_emptyring(struct umaldma *d);
+static void umaldma_fillring(struct umal_softc *sc, struct umaldma *d);
+static int umaldma_rx_process(struct umal_softc *sc, struct umaldma *d,
+ int work_to_do, int poll);
+static void umaldma_tx_process(struct umal_softc *sc, struct umaldma *d,
+ int poll);
+
+static int umal_initctx(struct umal_softc *s);
+static void umal_uninitctx(struct umal_softc *s);
+static void umal_channel_start(struct umal_softc *s);
+static void umal_channel_stop(struct umal_softc *s);
+static enum umal_state umal_set_channel_state(struct umal_softc *,
+ enum umal_state);
+
+static int umal_init(struct platform_device *pldev, long long base);
+static int umal_open(struct net_device *dev);
+static int umal_close(struct net_device *dev);
+static int umal_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static irqreturn_t umal_intr(int irq, void *dev_instance);
+static void umal_clr_intr(struct net_device *dev);
+static int umal_start_tx(struct sk_buff *skb, struct net_device *dev);
+static void umal_tx_timeout(struct net_device *dev);
+static void umal_set_rx_mode(struct net_device *dev);
+static void umal_promiscuous_mode(struct umal_softc *sc, int onoff);
+static void umal_setmulti(struct umal_softc *sc);
+static int umal_set_speed(struct umal_softc *s, enum umal_speed speed);
+static int umal_set_duplex(struct umal_softc *s, enum umal_duplex duplex,
+ enum umal_fc fc);
+static int umal_change_mtu(struct net_device *_dev, int new_mtu);
+static void umal_miipoll(struct net_device *dev);
+
+/**********************************************************************
+ * MII Bus functions for PAL (phy abstraction layer)
+ ********************************************************************* */
+
+/**********************************************************************
+ * UMAL_MII_RESET(bus)
+ *
+ * Reset MII bus.
+ *
+ * Input parameters:
+ * bus - MDIO bus handle
+ *
+ * Return value:
+ * 0 if ok
+ ********************************************************************* */
+static int umal_mii_reset(struct mii_bus *bus)
+{
+ UMAL_MIICFG = UMAL_MIICFG_RESET; /* reset the MII management */
+ UMAL_MIICFG = 0x0; /* enable the MII management */
+ UMAL_MIICFG |= 0x7; /* source clock division = 28 */
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL_MII_READ(bus, phyaddr, regidx)
+ * Read a PHY register.
+ *
+ * Input parameters:
+ * bus - MDIO bus handle
+ * phyaddr - PHY's address
+ * regnum - index of register to read
+ *
+ * Return value:
+ * value read, or 0xffff if an error occurred.
+ ********************************************************************* */
+static int umal_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
+{
+ int tmp = 0;
+
+ UMAL_MIIADDR = (phyaddr<<8) | regidx;
+ UMAL_MIICMD = UMAL_MIICMD_READ;
+
+ tmp = UMAL_MIIIDCT;
+ while (tmp & UMAL_MIIIDCT_BUSY)
+ tmp = UMAL_MIIIDCT;
+
+ if (tmp & UMAL_MIIIDCT_NOTVALID)
+ return 0xffff;
+
+ UMAL_MIICMD = 0;
+
+ tmp = UMAL_MIISTATUS;
+ return tmp;
+}
+
+/**********************************************************************
+ * UMAL_MII_WRITE(bus, phyaddr, regidx, regval)
+ *
+ * Write a value to a PHY register.
+ *
+ * Input parameters:
+ * bus - MDIO bus handle
+ * phyaddr - PHY to use
+ * regidx - register within the PHY
+ * regval - data to write to register
+ *
+ * Return value:
+ * 0 if ok
+ ********************************************************************* */
+static int umal_mii_write(struct mii_bus *bus, int phyaddr, int regidx, u16 val)
+{
+ int tmp = 0;
+
+ UMAL_MIIADDR = (phyaddr<<8) | regidx;
+ UMAL_MIICTRL = val;
+
+ tmp = UMAL_MIIIDCT;
+ while (tmp & UMAL_MIIIDCT_BUSY)
+ tmp = UMAL_MIIIDCT;
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL_MII_PROBE(dev)
+ *
+ * Write a value to a PHY register.
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * 0 if ok
+ ********************************************************************* */
+static int umal_mii_probe(struct net_device *dev)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+ struct phy_device *phy_dev;
+ int i;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ phy_dev = sc->mii_bus->phy_map[i];
+ if (phy_dev)
+ break;
+ }
+ if (!phy_dev) {
+ printk(KERN_ERR "%s: no PHY found\n", dev->name);
+ return -ENXIO;
+ }
+
+ phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &umal_miipoll, 0,
+ PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phy_dev)) {
+ printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
+ return PTR_ERR(phy_dev);
+ }
+
+ /* Remove any features not supported by the controller */
+ phy_dev->supported &= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_MII;
+ phy_dev->advertising = phy_dev->supported;
+
+ pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+ dev->name, phy_dev->drv->name,
+ dev_name(&phy_dev->dev), phy_dev->irq);
+
+ sc->phy_dev = phy_dev;
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL DMA functions
+ ********************************************************************* */
+
+/**********************************************************************
+ * UMALDMA_INITCTX(d,s,txrx,maxdescr)
+ *
+ * Initialize a DMA channel context. Since there are potentially
+ * eight DMA channels per MAC, it's nice to do this in a standard
+ * way.
+ *
+ * Input parameters:
+ * d - struct umaldma (DMA channel context)
+ * s - struct umal_softc (pointer to a MAC)
+ * txrx - Identifies DMA_TX or DMA_RX for channel direction
+ * maxdescr - number of descriptors
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umaldma_initctx(struct umaldma *d, struct umal_softc *s, int rxtx,
+ int maxdescr)
+{
+ struct umaldmadscr *dscr_item;
+ int idx;
+
+ /*
+ * Save away interesting stuff in the structure
+ */
+
+ d->umaldma_eth = s;
+ d->umaldma_txdir = rxtx;
+ d->umaldma_maxdescr = maxdescr;
+
+ /*
+ * Allocate memory for the ring
+ */
+
+ d->umaldma_dscrtable_unaligned = dma_alloc_coherent(NULL,
+ sizeof(*d->umaldma_dscrtable),
+ &d->umaldma_dscrtable_phys_unaligned,
+ GFP_KERNEL | GFP_DMA);
+
+ dma_cache_sync(NULL, d->umaldma_dscrtable_unaligned,
+ sizeof(*d->umaldma_dscrtable), DMA_BIDIRECTIONAL);
+
+ /*
+ * The descriptor table must be aligned to at least 16 bytes or the
+ * MAC will corrupt it.
+ */
+
+ d->umaldma_dscrtable = (struct umaldmadscr *)
+ ALIGN((unsigned long)d->umaldma_dscrtable_unaligned,
+ sizeof(*d->umaldma_dscrtable));
+
+ d->umaldma_dscrtable_end = d->umaldma_dscrtable + d->umaldma_maxdescr;
+
+ d->umaldma_dscrtable_phys = ALIGN((unsigned long)
+ d->umaldma_dscrtable_phys_unaligned,
+ sizeof(*d->umaldma_dscrtable));
+
+ for (idx = 0; idx < d->umaldma_maxdescr; idx++) {
+ dscr_item = d->umaldma_dscrtable + idx;
+ dscr_item->PacketStartAddr = 0;
+ dscr_item->PacketSize = UMAL_DESC_PACKETSIZE_EMPTY;
+ dscr_item->NextDescriptor = (dma_addr_t)(
+ (struct umaldmadscr *)d->umaldma_dscrtable_phys
+ + (idx+1));
+ dscr_item->NextDescriptor_Virt = d->umaldma_dscrtable + (idx+1);
+ }
+ dscr_item = d->umaldma_dscrtable +
+ (d->umaldma_maxdescr - 1);
+ dscr_item->NextDescriptor = d->umaldma_dscrtable_phys;
+ dscr_item->NextDescriptor_Virt = d->umaldma_dscrtable;
+
+ d->umaldma_addptr = d->umaldma_dscrtable;
+ d->umaldma_remptr = d->umaldma_dscrtable;
+
+ /*
+ * And context table
+ */
+
+ d->umaldma_ctxtable = kcalloc(d->umaldma_maxdescr,
+ sizeof(*d->umaldma_ctxtable), GFP_KERNEL);
+}
+
+/**********************************************************************
+ * UMALDMA_UNINITCTX(d)
+ *
+ * Uninitialize a DMA channel context.
+ *
+ * Input parameters:
+ * d - struct umaldma (DMA channel context)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umaldma_uninitctx(struct umaldma *d)
+{
+ if (d->umaldma_dscrtable_unaligned) {
+ dma_free_coherent(NULL,
+ sizeof(*d->umaldma_dscrtable),
+ d->umaldma_dscrtable_unaligned,
+ d->umaldma_dscrtable_phys_unaligned);
+ d->umaldma_dscrtable_unaligned = d->umaldma_dscrtable = NULL;
+ d->umaldma_dscrtable_phys_unaligned = 0;
+ d->umaldma_dscrtable_phys = 0;
+ }
+
+ kfree(d->umaldma_ctxtable);
+ d->umaldma_ctxtable = NULL;
+}
+
+/**********************************************************************
+ * UMALDMA_CHANNEL_START(d)
+ *
+ * Open a DMA channel.
+ *
+ * Input parameters:
+ * d - DMA channel to init (context must be previously init'd)
+ * rxtx - DMA_RX or DMA_TX depending on what type of channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umaldma_channel_start(struct umaldma *d, int rxtx)
+{
+ /*
+ * Turn on the DMA channel
+ */
+
+ if (rxtx == DMA_TX) {
+ UMAL_DMATxDescriptor = d->umaldma_dscrtable_phys;
+ UMAL_DMATxCtrl = UMAL_DMA_Enable;
+ } else {
+ UMAL_DMARxDescriptor = d->umaldma_dscrtable_phys;
+ UMAL_DMARxCtrl = UMAL_DMA_Enable;
+ }
+}
+
+/**********************************************************************
+ * UMALDMA_CHANNEL_STOP(d)
+ *
+ * Close DMA channel.
+ *
+ * Input parameters:
+ * d - DMA channel to init (context must be previously init'd
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umaldma_channel_stop(struct umaldma *d)
+{
+ /*
+ * Turn off the DMA channel
+ */
+
+ if (d->umaldma_txdir == DMA_TX) {
+ UMAL_DMATxCtrl = 0;
+ UMAL_DMATxDescriptor = 0;
+ } else {
+ UMAL_DMARxCtrl = 0;
+ UMAL_DMARxDescriptor = 0;
+ }
+
+ /*
+ * Zero ring pointers
+ */
+
+ d->umaldma_addptr = d->umaldma_dscrtable;
+ d->umaldma_remptr = d->umaldma_dscrtable;
+}
+
+/**********************************************************************
+ * UMALDMA_ADD_RCVBUFFER(d,sb)
+ *
+ * Add a buffer to the specified DMA channel.
+ * For receive channels, this queues a buffer for inbound packets.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel descriptor
+ * sb - sk_buff to add, or NULL if we should allocate one
+ *
+ * Return value:
+ * 0 if buffer could not be added (ring is full)
+ * 1 if buffer added successfully
+ ********************************************************************* */
+static int umaldma_add_rcvbuffer(struct umal_softc *sc, struct umaldma *d,
+ struct sk_buff *sb)
+{
+ struct net_device *dev = sc->umal_dev;
+ struct umaldmadscr *dsc;
+ struct umaldmadscr *nextdsc;
+ struct sk_buff *sb_new = NULL;
+
+ /* get pointer to our current place in the ring */
+
+ dsc = d->umaldma_addptr;
+ nextdsc = UMALDMA_NEXTBUF(d, umaldma_addptr);
+
+ /*
+ * figure out if the ring is full - if the next descriptor
+ * is the same as the one that we're going to remove from
+ * the ring, the ring is full
+ */
+
+ if (nextdsc == d->umaldma_remptr)
+ return -ENOSPC;
+
+ /*
+ * Allocate a sk_buff if we don't already have one.
+ * If we do have an sk_buff, reset it so that it's empty.
+ *
+ * Note: sk_buffs don't seem to be guaranteed to have any sort
+ * of alignment when they are allocated. Therefore, allocate enough
+ * extra space to make sure that:
+ *
+ * 1. the data does not start in the middle of a cache line.
+ * 2. The data does not end in the middle of a cache line
+ * 3. The buffer can be aligned such that the IP addresses are
+ * naturally aligned.
+ *
+ * Remember, the SOCs MAC writes whole cache lines at a time,
+ * without reading the old contents first. So, if the sk_buff's
+ * data portion starts in the middle of a cache line, the SOC
+ * DMA will trash the beginning (and ending) portions.
+ */
+
+ if (sb == NULL) {
+ sb_new = netdev_alloc_skb(dev, ENET_PACKET_SIZE +
+ SMP_CACHE_BYTES * 2 +
+ NET_IP_ALIGN);
+ if (sb_new == NULL) {
+ pr_info("%s: sk_buff allocation failed\n",
+ d->umaldma_eth->umal_dev->name);
+ return -ENOBUFS;
+ }
+ skb_reserve(sb_new, 2);
+ } else {
+ sb_new = sb;
+ /*
+ * nothing special to reinit buffer, it's already aligned
+ * and sb->data already points to a good place.
+ */
+ }
+
+ /*
+ * fill in the descriptor
+ */
+
+ dsc->PacketStartAddr = virt_to_phys(sb_new->data);
+ dsc->PacketSize = UMAL_DESC_PACKETSIZE_EMPTY;
+
+ /*
+ * fill in the context
+ */
+
+ d->umaldma_ctxtable[dsc-d->umaldma_dscrtable] = sb_new;
+
+ /*
+ * point at next packet
+ */
+
+ d->umaldma_addptr = nextdsc;
+
+ return 0; /* we did it */
+}
+
+/**********************************************************************
+ * UMALDMA_ADD_TXBUFFER(d,sb)
+ *
+ * Add a transmit buffer to the specified DMA channel, causing a
+ * transmit to start.
+ *
+ * Input parameters:
+ * d - DMA channel descriptor
+ * sb - sk_buff to add
+ *
+ * Return value:
+ * 0 transmit queued successfully
+ * otherwise error code
+ ********************************************************************* */
+static int umaldma_add_txbuffer(struct umaldma *d, struct sk_buff *sb)
+{
+ struct umaldmadscr *dsc;
+ struct umaldmadscr *nextdsc;
+
+ /* get pointer to our current place in the ring */
+
+ dsc = d->umaldma_addptr;
+ nextdsc = UMALDMA_NEXTBUF(d, umaldma_addptr);
+
+ /*
+ * figure out if the ring is full - if the next descriptor
+ * is the same as the one that we're going to remove from
+ * the ring, the ring is full
+ */
+ if (nextdsc == d->umaldma_remptr)
+ return -ENOSPC;
+
+ /*
+ * fill in the descriptor. Note that the number of cache
+ * blocks in the descriptor is the number of blocks
+ * *spanned*, so we need to add in the offset (if any)
+ * while doing the calculation.
+ */
+ dsc->PacketStartAddr = virt_to_phys(sb->data);
+ dsc->PacketSize = sb->len | UMAL_DESC_PACKETSIZE_NONEMPTY;
+
+ dma_map_single(NULL, sb->data, sb->len, DMA_BIDIRECTIONAL);
+ dma_cache_sync(NULL, sb->data, sb->len, DMA_BIDIRECTIONAL);
+
+ /*
+ * fill in the context
+ */
+ d->umaldma_ctxtable[dsc-d->umaldma_dscrtable] = sb;
+
+ /*
+ * point at next packet
+ */
+ d->umaldma_addptr = nextdsc;
+
+ return 0; /* we did it */
+}
+
+/**********************************************************************
+ * UMALDMA_EMPTYRING(d)
+ *
+ * Free all allocated sk_buffs on the specified DMA channel;
+ *
+ * Input parameters:
+ * d - DMA channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umaldma_emptyring(struct umaldma *d)
+{
+ int idx;
+ struct sk_buff *sb;
+
+ for (idx = 0; idx < d->umaldma_maxdescr; idx++) {
+ sb = d->umaldma_ctxtable[idx];
+ if (sb) {
+ dev_kfree_skb(sb);
+ d->umaldma_ctxtable[idx] = NULL;
+ }
+ }
+}
+
+/**********************************************************************
+ * UMALDMA_FILLRING(sc,d)
+ *
+ * Fill the specified DMA channel (must be receive channel)
+ * with sk_buffs
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umaldma_fillring(struct umal_softc *sc, struct umaldma *d)
+{
+ int idx;
+ for (idx = 0; idx < UMAL_MAX_RXDESCR - 1; idx++) {
+ if (umaldma_add_rcvbuffer(sc, d, NULL) != 0)
+ break;
+ }
+}
+
+/**********************************************************************
+ * UMALDMA_RX_PROCESS(sc,d,work_to_do,poll)
+ *
+ * Process "completed" receive buffers on the specified DMA channel.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel context
+ * work_to_do - no. of packets to process before enabling interrupt
+ * again (for NAPI)
+ * poll - 1: using polling (for NAPI)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static int umaldma_rx_process(struct umal_softc *sc, struct umaldma *d,
+ int work_to_do, int poll)
+{
+ struct net_device *dev = sc->umal_dev;
+ int curidx;
+ int hwidx;
+ struct umaldmadscr *dsc;
+ struct sk_buff *sb;
+ int len;
+ int work_done = 0;
+ int dropped = 0;
+ unsigned int int_status;
+
+ if (!netif_device_present(dev))
+ return 0;
+
+ int_status = UMAL_DMAInterrupt;
+
+ if (int_status & INT_RX_BUS_ERR) {
+ UMAL_DMARxStatus = CLR_RX_BUS_ERR;
+ UMAL_DMARxCtrl |= UMAL_DMA_Enable;
+ }
+
+ if (int_status & INT_RX_OVERFLOW) {
+ UMAL_DMARxStatus = CLR_RX_OVERFLOW;
+ UMAL_DMARxCtrl |= UMAL_DMA_Enable;
+ }
+
+ if (int_status & INT_RX_PKT) {
+ while (work_to_do-- > 0) {
+
+ /*
+ * figure out where we are (as an index) and where
+ * the hardware is (also as an index)
+ *
+ * This could be done faster if (for example) the
+ * descriptor table was page-aligned and contiguous in
+ * both virtual and physical memory -- you could then
+ * just compare the low-order bits of the virtual
+ * address (sbdma_remptr) and the physical address
+ * (sbdma_curdscr CSR)
+ */
+
+ dsc = d->umaldma_remptr;
+ curidx = dsc - d->umaldma_dscrtable;
+
+ hwidx = (struct umaldmadscr *)UMAL_DMARxDescriptor -
+ (struct umaldmadscr *)d->umaldma_dscrtable_phys;
+
+ UMAL_DMARxStatus = CLR_RX_PKT;
+
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one
+ * that the hardware is working on right now.
+ */
+ if (curidx == hwidx)
+ goto done;
+
+ /*
+ * Otherwise, get the packet's sk_buff ptr back
+ */
+ sb = d->umaldma_ctxtable[curidx];
+ len = dsc->PacketSize & 0xfff;
+ d->umaldma_ctxtable[curidx] = NULL;
+
+ /*
+ * .. and advance to the next buffer.
+ */
+ d->umaldma_remptr = UMALDMA_NEXTBUF(d, umaldma_remptr);
+
+ /*
+ * Check packet status. If good, process it.
+ * If not, silently drop it and put it back on the
+ * receive ring.
+ */
+ if (likely(!(dsc->PacketSize &
+ UMAL_DESC_PACKETSIZE_EMPTY))) {
+ /*
+ * Add a new buffer to replace the old one.
+ * If we fail to allocate a buffer, we're going
+ * to drop this packet and put it right back on
+ * the receive ring.
+ */
+ if (unlikely(umaldma_add_rcvbuffer(sc, d, NULL)
+ == -ENOBUFS)) {
+ dev->stats.rx_dropped++;
+ /* Re-add old buffer */
+ umaldma_add_rcvbuffer(sc, d, sb);
+ /* No point in continuing */
+ printk(KERN_ERR "dropped packet (1)\n");
+ d->umaldma_remptr = UMALDMA_NEXTBUF(d,
+ umaldma_remptr);
+ goto done;
+ } else {
+ /*
+ * Set length into the packet
+ */
+ skb_put(sb, len + 4);
+
+ /*
+ * Buffer has been replaced on the
+ * receive ring. Pass the buffer to
+ * the kernel
+ */
+ sb->protocol = eth_type_trans(sb,
+ d->umaldma_eth->umal_dev);
+ /*
+ * Check hw IPv4/TCP checksum
+ * if supported
+ */
+ skb_checksum_none_assert(sb);
+
+ if (poll)
+ dropped = netif_receive_skb(sb);
+ else
+ dropped = netif_rx(sb);
+
+ if (dropped == NET_RX_DROP) {
+ dev->stats.rx_dropped++;
+ d->umaldma_remptr =
+ UMALDMA_NEXTBUF(d,
+ umaldma_remptr);
+ goto done;
+ } else {
+ dev->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ }
+ }
+ } else {
+ /*
+ * Packet was mangled somehow. Just drop it and
+ * put it back on the receive ring.
+ */
+ dev->stats.rx_errors++;
+ umaldma_add_rcvbuffer(sc, d, sb);
+ }
+ work_done++;
+ }
+ }
+done:
+ return work_done;
+}
+
+/**********************************************************************
+ * UMALDMA_TX_PROCESS(sc,d,poll)
+ *
+ * Process "completed" transmit buffers on the specified DMA channel.
+ * This is normally called within the interrupt service routine.
+ * Note that this isn't really ideal for priority channels, since
+ * it processes all of the packets on a given channel before
+ * returning.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel context
+ * poll - 1: using polling (for NAPI)
+ *
+ * Return value:
+ * nothing
+ **********************************************************************/
+static void umaldma_tx_process(struct umal_softc *sc, struct umaldma *d,
+ int poll)
+{
+ struct net_device *dev = sc->umal_dev;
+ int curidx;
+ int hwidx;
+ struct umaldmadscr *dsc;
+ struct sk_buff *sb;
+ unsigned long flags;
+ int packets_handled = 0;
+ unsigned int int_status;
+
+ spin_lock_irqsave(&(sc->umal_lock), flags);
+
+ if (!netif_device_present(dev))
+ return;
+
+ int_status = UMAL_DMAInterrupt;
+
+
+ if (int_status & INT_TX_BUS_ERR)
+ UMAL_DMATxStatus = CLR_TX_BUS_ERR;
+
+ if (int_status & INT_TX_UNDERRUN)
+ UMAL_DMATxStatus = CLR_TX_UNDERRUN;
+
+ if (int_status & INT_TX_PKT) {
+ hwidx = (struct umaldmadscr *)UMAL_DMATxDescriptor -
+ (struct umaldmadscr *)d->umaldma_dscrtable_phys;
+
+ if (d->umaldma_remptr == d->umaldma_addptr)
+ goto end_unlock;
+
+ for (;;) {
+ /*
+ * figure out where we are (as an index) and where
+ * the hardware is (also as an index)
+ *
+ * This could be done faster if (for example) the
+ * descriptor table was page-aligned and contiguous in
+ * both virtual and physical memory -- you could then
+ * just compare the low-order bits of the virtual
+ * address (sbdma_remptr) and the physical address
+ * (sbdma_curdscr CSR)
+ */
+ curidx = d->umaldma_remptr - d->umaldma_dscrtable;
+
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one
+ * that the hardware is working on right now.
+ */
+ if (curidx == hwidx)
+ break;
+
+ /*
+ * Otherwise, get the packet's sk_buff ptr back
+ */
+ dsc = &(d->umaldma_dscrtable[curidx]);
+ sb = d->umaldma_ctxtable[curidx];
+
+ /*
+ * Stats
+ */
+ dev->stats.tx_bytes += sb->len;
+ dev->stats.tx_packets++;
+
+ /*
+ * for transmits, we just free buffers.
+ */
+ dev_kfree_skb_irq(sb);
+ d->umaldma_ctxtable[curidx] = NULL;
+ UMAL_DMATxStatus = CLR_TX_PKT;
+
+ /*
+ * .. and advance to the next buffer.
+ */
+ d->umaldma_remptr = UMALDMA_NEXTBUF(d, umaldma_remptr);
+ packets_handled++;
+ }
+
+ /*
+ * Decide if we should wake up the protocol or not.
+ * Other drivers seem to do this when we reach a low
+ * watermark on the transmit queue.
+ */
+ if (packets_handled)
+ netif_wake_queue(d->umaldma_eth->umal_dev);
+ }
+
+end_unlock:
+ spin_unlock_irqrestore(&(sc->umal_lock), flags);
+}
+
+/**********************************************************************
+ * UMAL Channel functions
+ ********************************************************************* */
+
+/**********************************************************************
+ * UMAL_INITCTX(s)
+ *
+ * Initialize an Ethernet context structure - this is called
+ * once per MAC. Memory is allocated here, so don't
+ * call it again from inside the ioctl routines that bring the
+ * interface up/down
+ *
+ * Input parameters:
+ * s - umal context structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+static int umal_initctx(struct umal_softc *s)
+{
+ /*
+ * Initialize the DMA channels.
+ * Note: Only do this _once_, as it allocates memory from the kernel!
+ */
+
+ umaldma_initctx(&(s->umal_txdma), s, DMA_TX, UMAL_MAX_TXDESCR);
+ umaldma_initctx(&(s->umal_rxdma), s, DMA_RX, UMAL_MAX_RXDESCR);
+
+ /*
+ * initial state is OFF
+ */
+
+ s->umal_state = umal_state_off;
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL_UNINITCTX(s)
+ *
+ * Initialize an Ethernet context structure - this is called
+ * once per MAC on the 1250. Memory is allocated here, so don't
+ * call it again from inside the ioctl routines that bring the
+ * interface up/down
+ *
+ * Input parameters:
+ * s - umal context structure
+ *
+ * Return value:
+ * Nothing
+ ********************************************************************* */
+static void umal_uninitctx(struct umal_softc *s)
+{
+ umaldma_uninitctx(&(s->umal_txdma));
+ umaldma_uninitctx(&(s->umal_rxdma));
+}
+
+/**********************************************************************
+ * UMAL_CHANNEL_START(s)
+ *
+ * Start packet processing on this MAC.
+ *
+ * Input parameters:
+ * s - umal context structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_channel_start(struct umal_softc *s)
+{
+ /*
+ * Don't do this if running
+ */
+ if (s->umal_state == umal_state_on)
+ return;
+
+ /* don't accept any packets, disable all interrupts */
+ umaldma_channel_stop(&(s->umal_rxdma));
+ umaldma_channel_stop(&(s->umal_txdma));
+
+ UMAL_DMAIntrMask = 0;
+ umal_clr_intr(s->umal_dev);
+
+ /*
+ * Program the hardware address. It goes into the hardware-address
+ * register as well as the first filter register.
+ */
+ UMAL_STADDR1 = s->umal_hwaddr[0]<<24 | s->umal_hwaddr[1]<<16 |
+ s->umal_hwaddr[2]<<8 | s->umal_hwaddr[3];
+ UMAL_STADDR2 = s->umal_hwaddr[4]<<24 | s->umal_hwaddr[5]<<16;
+
+ /*
+ * Configure the speed, duplex, and flow control
+ */
+ umal_set_speed(s, s->umal_speed);
+ umal_set_duplex(s, s->umal_duplex, s->umal_fc);
+
+ /*
+ * Program multicast addresses
+ */
+ umal_setmulti(s);
+
+ /*
+ * If channel was in promiscuous mode before, turn that on
+ */
+ if (s->umal_devflags & IFF_PROMISC)
+ umal_promiscuous_mode(s, 1);
+
+ /*
+ * Fill the receive ring
+ */
+ umaldma_fillring(s, &(s->umal_rxdma));
+
+ umaldma_channel_start(&(s->umal_rxdma), DMA_RX);
+ umaldma_channel_start(&(s->umal_txdma), DMA_TX);
+
+ s->umal_state = umal_state_on;
+
+ /*
+ * Initialize DMA channels (rings should be ok now)
+ */
+ UMAL_DMAIntrMask = INT_RX_BUS_ERR | INT_RX_OVERFLOW |
+ INT_RX_PKT | INT_TX_BUS_ERR |
+ INT_TX_UNDERRUN | INT_TX_PKT |
+ UMAL_DMAIntrMask_ENABLEHALFWORD;
+
+ /*
+ * we're running now.
+ */
+ UMAL_CFG1 |= UMAL_CFG1_RXENABLE | UMAL_CFG1_TXENABLE;
+}
+
+/**********************************************************************
+ * UMAL_CHANNEL_STOP(s)
+ *
+ * Stop packet processing on this MAC.
+ *
+ * Input parameters:
+ * s - umal context structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_channel_stop(struct umal_softc *s)
+{
+ /* don't do this if already stopped */
+ if (s->umal_state == umal_state_off)
+ return;
+
+ /* don't accept any packets, disable all interrupts */
+ UMAL_DMAIntrMask = 0;
+ umal_clr_intr(s->umal_dev);
+
+ /* turn off receiver and transmitter */
+ UMAL_CFG1 = UMAL_CFG1_RESET; /* reset MAC */
+ UMAL_CFG1 = 0;
+
+ /* We're stopped now. */
+ s->umal_state = umal_state_off;
+
+ /*
+ * Stop DMA channels (rings should be ok now)
+ */
+ umaldma_channel_stop(&(s->umal_rxdma));
+ umaldma_channel_stop(&(s->umal_txdma));
+
+ /* Empty the receive and transmit rings */
+ umaldma_emptyring(&(s->umal_rxdma));
+ umaldma_emptyring(&(s->umal_txdma));
+}
+
+/**********************************************************************
+ * UMAL_SET_CHANNEL_STATE(s,state)
+ *
+ * Set the channel's state ON or OFF
+ *
+ * Input parameters:
+ * s - umal context structure
+ * state - new state
+ *
+ * Return value:
+ * old state
+ ********************************************************************* */
+static enum umal_state umal_set_channel_state(struct umal_softc *s,
+ enum umal_state state)
+{
+ enum umal_state oldstate = s->umal_state;
+
+ /*
+ * If same as previous state, return
+ */
+ if (state == oldstate)
+ return oldstate;
+
+ /*
+ * If new state is ON, turn channel on
+ */
+ if (state == umal_state_on)
+ umal_channel_start(s);
+ else
+ umal_channel_stop(s);
+
+ /*
+ * Return previous state
+ */
+ return oldstate;
+}
+
+/**********************************************************************
+ * UMAL functions
+ ********************************************************************* */
+static const struct net_device_ops umal_netdev_ops = {
+ .ndo_open = umal_open,
+ .ndo_stop = umal_close,
+ .ndo_start_xmit = umal_start_tx,
+ .ndo_set_multicast_list = umal_set_rx_mode,
+ .ndo_tx_timeout = umal_tx_timeout,
+ .ndo_do_ioctl = umal_mii_ioctl,
+ .ndo_change_mtu = umal_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+/**********************************************************************
+ * UMAL_INIT(dev)
+ *
+ * Attach routine - init hardware and hook ourselves into linux
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * 0 if ok
+ ********************************************************************* */
+static int umal_init(struct platform_device *pldev, long long base)
+{
+ struct net_device *dev = dev_get_drvdata(&pldev->dev);
+ int idx = pldev->id;
+ struct umal_softc *sc = netdev_priv(dev);
+ unsigned char *eaddr;
+ int i;
+ int err;
+
+ sc->umal_dev = dev;
+ sc->umal_idx = idx;
+
+ eaddr = sc->umal_hwaddr;
+#ifdef CONFIG_CMDLINE_FORCE
+ for (i = 0; i < 6; i++)
+ eaddr[i] = hw_addr[0].addr[i];
+#endif
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = eaddr[i];
+
+ /*
+ * Set up Linux device callins
+ */
+
+ spin_lock_init(&(sc->umal_lock));
+
+ dev->netdev_ops = &umal_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ dev->irq = IRQ_UMAL;
+
+ sc->mii_bus = mdiobus_alloc();
+ if (sc->mii_bus == NULL) {
+ err = -ENOMEM;
+ goto uninit_ctx;
+ }
+
+ sc->mii_bus->name = umal_mdio_string;
+ snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
+ sc->mii_bus->priv = sc;
+ sc->mii_bus->read = umal_mii_read;
+ sc->mii_bus->write = umal_mii_write;
+ sc->mii_bus->reset = umal_mii_reset;
+ sc->mii_bus->irq = sc->phy_irq;
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ sc->mii_bus->irq[i] = PHY_POLL;
+
+ sc->mii_bus->parent = &pldev->dev;
+
+ /*
+ * Probe PHY address
+ */
+ err = mdiobus_register(sc->mii_bus);
+ if (err) {
+ printk(KERN_ERR "%s: unable to register MDIO bus\n",
+ dev->name);
+ goto free_mdio;
+ }
+ dev_set_drvdata(&pldev->dev, sc->mii_bus);
+
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR "%s.%d: unable to register netdev\n",
+ umal_string, idx);
+ goto unreg_mdio;
+ }
+
+ pr_info("%s.%d: registered as %s\n", umal_string, idx, dev->name);
+
+ /*
+ * Initialize context (get pointers to registers and stuff), then
+ * allocate the memory for the descriptor tables.
+ */
+ dev->dev.coherent_dma_mask = 0xFFFFFFFF;
+ umal_initctx(sc);
+
+ /*
+ * Display Ethernet address (this is called during the config
+ * process so we need to finish off the config message that
+ * was being displayed)
+ */
+ pr_info("%s: UMAL Ethernet at 0x%08Lx, address: %pM\n",
+ dev->name, base, eaddr);
+
+ return 0;
+unreg_mdio:
+ mdiobus_unregister(sc->mii_bus);
+ dev_set_drvdata(&pldev->dev, NULL);
+free_mdio:
+ mdiobus_free(sc->mii_bus);
+uninit_ctx:
+ umal_uninitctx(sc);
+ return err;
+}
+
+/**********************************************************************
+ * UMAL_OPEN(dev)
+ *
+ * Open umal device
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * 0 if ok
+ * otherwise error
+ ********************************************************************* */
+static int umal_open(struct net_device *dev)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+ int err;
+
+ sc->umal_speed = umal_speed_none;
+ sc->umal_duplex = umal_duplex_none;
+ sc->umal_fc = umal_fc_none;
+ sc->umal_pause = -1;
+ sc->umal_link = 0;
+
+ /* reset mac and interface */
+ UMAL_CFG1 = UMAL_CFG1_RESET; /* reset MAC */
+ UMAL_CFG1 = 0; /* clear the reset bit of MAC */
+ UMAL_IFCTRL = UMAL_IFCTRL_RESET; /* reset the MAC Interface */
+ UMAL_DMAIntrMask = 0;
+
+ /*
+ * Attach to the PHY
+ */
+ err = umal_mii_probe(dev);
+ if (err)
+ goto out_unregister;
+
+ /*
+ * Turn on the channel
+ */
+ phy_start(sc->phy_dev);
+
+ /* config fifo */
+ UMAL_FIFOCFG0 = 0x000000ff; /* reset FIFO */
+ UMAL_FIFOCFG1 = 0x0fff0fff; /* request enable modules in fifo */
+ UMAL_FIFOCFG2 = 0x0aaa0555; /* request enable modules in fifo */
+ UMAL_FIFOCFG3 = 0x02800fff; /* set water mark register */
+ UMAL_FIFOCFG4 = 0x00000070;
+ UMAL_FIFOCFG5 = 0x0007ff8f;
+ UMAL_FIFOCFG0 = 0x0000ff00; /* request enable modules in fifo */
+
+ UMAL_CFG2 = 0x7016;
+
+ /*
+ * map/route interrupt (clear status first, in case something
+ * weird is pending; we haven't initialized the mac registers
+ * yet)
+ */
+ umal_clr_intr(dev);
+
+ err = request_irq(dev->irq, umal_intr, IRQF_SHARED, dev->name, dev);
+ if (err) {
+ printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
+ dev->irq);
+ goto out_err;
+ }
+
+ umal_set_channel_state(sc, umal_state_on);
+
+ netif_start_queue(dev);
+
+ umal_set_rx_mode(dev);
+
+ return 0;
+
+out_unregister:
+ free_irq(dev->irq, dev);
+out_err:
+ return err;
+}
+
+/**********************************************************************
+ * UMAL_CLSOE(dev)
+ *
+ * Close umal device
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * 0 if ok
+ ********************************************************************* */
+static int umal_close(struct net_device *dev)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+
+ phy_stop(sc->phy_dev);
+
+ umal_set_channel_state(sc, umal_state_off);
+
+ netif_stop_queue(dev);
+
+ phy_disconnect(sc->phy_dev);
+ sc->phy_dev = NULL;
+
+ free_irq(dev->irq, dev);
+
+ umaldma_emptyring(&(sc->umal_rxdma));
+ umaldma_emptyring(&(sc->umal_txdma));
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL_MII_IOCTL(dev,rq,cmd)
+ *
+ * Umal device ioctrl routine
+ *
+ * Input parameters:
+ * dev - net_device structure
+ * rq - interface request structure
+ * cmd - ioctrl command
+ *
+ * Return value:
+ * ioctrl command result
+ ********************************************************************* */
+static int umal_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+
+ if (!netif_running(dev) || !sc->phy_dev)
+ return -EINVAL;
+
+ return phy_mii_ioctl(sc->phy_dev, rq, cmd);
+}
+
+/**********************************************************************
+ * UMAL_INTR(irq,dev_instance)
+ *
+ * Interrupt handler for MAC interrupts
+ *
+ * Input parameters:
+ * irq - irq number
+ * dev_instance - net_device structure
+ *
+ * Return value:
+ * irq handling result
+ ********************************************************************* */
+static irqreturn_t umal_intr(int irq, void *dev_instance)
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct umal_softc *sc = netdev_priv(dev);
+ uint64_t isr;
+ int handled = 0;
+
+ /*
+ * Read the ISR (this clears the bits in the real
+ * register, except for counter addr)
+ */
+ isr = UMAL_DMAInterrupt;
+ if (isr == 0)
+ return IRQ_RETVAL(0);
+
+ if (sc->umal_state != umal_state_on) {
+ umal_clr_intr(dev);
+ return IRQ_RETVAL(0);
+ }
+ handled = 1;
+
+ /*
+ * Transmits on channel 0
+ */
+ if (isr & INT_TX_MASK)
+ umaldma_tx_process(sc, &(sc->umal_txdma), 0);
+ if (isr & INT_RX_MASK)
+ umaldma_rx_process(sc, &(sc->umal_rxdma),
+ UMAL_MAX_RXDESCR * 2, 0);
+
+ return IRQ_RETVAL(handled);
+}
+
+/**********************************************************************
+ * UMAL_CLR_INTR(dev)
+ *
+ * Clear all interrupt of umal
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_clr_intr(struct net_device *dev)
+{
+ unsigned int int_status;
+
+ if (!netif_device_present(dev))
+ return;
+ int_status = UMAL_DMAInterrupt;
+ if (int_status & INT_RX_PKT)
+ UMAL_DMARxStatus = CLR_RX_PKT;
+
+ if (int_status & INT_RX_BUS_ERR)
+ UMAL_DMARxStatus = CLR_RX_BUS_ERR;
+
+ if (int_status & INT_RX_OVERFLOW)
+ UMAL_DMARxStatus = CLR_RX_OVERFLOW;
+
+ if (int_status & INT_TX_PKT)
+ UMAL_DMATxStatus = CLR_TX_PKT;
+
+ if (int_status & INT_TX_BUS_ERR)
+ UMAL_DMATxStatus = CLR_TX_BUS_ERR;
+
+ if (int_status & INT_TX_UNDERRUN)
+ UMAL_DMATxStatus = CLR_TX_UNDERRUN;
+}
+
+/**********************************************************************
+ * UMAL_START_TX(skb,dev)
+ *
+ * Start output on the specified interface. Basically, we
+ * queue as many buffers as we can until the ring fills up, or
+ * we run off the end of the queue, whichever comes first.
+ *
+ * Input parameters:
+ * skb - sk_buff structure
+ * dev - net_device structure
+ *
+ * Return value:
+ * 0 if ok
+ * otherwise error
+ ********************************************************************* */
+static int umal_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+ unsigned long flags;
+
+ /* lock eth irq */
+ spin_lock_irqsave(&sc->umal_lock, flags);
+
+ /*
+ * Put the buffer on the transmit ring. If we
+ * don't have room, stop the queue.
+ */
+ if (umaldma_add_txbuffer(&(sc->umal_txdma), skb)) {
+ /* XXX save skb that we could not send */
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&sc->umal_lock, flags);
+
+ return NETDEV_TX_BUSY;
+ }
+
+ UMAL_CFG1 |= UMAL_CFG1_TXENABLE;
+ UMAL_DMATxCtrl |= UMAL_DMA_Enable;
+
+ spin_unlock_irqrestore(&sc->umal_lock, flags);
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL_TX_TIMEOUT(dev)
+ *
+ * Tx timeout, update statistic structure
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_tx_timeout(struct net_device *dev)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->umal_lock, flags);
+
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ dev->stats.tx_errors++;
+
+ spin_unlock_irqrestore(&sc->umal_lock, flags);
+
+ printk(KERN_WARNING "%s: Transmit timed out\n", dev->name);
+}
+
+/**********************************************************************
+ * UMAL_SET_RX_MODE(dev)
+ *
+ * Set promiscuous mode and multicast list
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_set_rx_mode(struct net_device *dev)
+{
+ unsigned long flags;
+ struct umal_softc *sc = netdev_priv(dev);
+
+ spin_lock_irqsave(&sc->umal_lock, flags);
+ if ((dev->flags ^ sc->umal_devflags) & IFF_PROMISC) {
+ /*
+ * Promiscuous changed.
+ */
+ if (dev->flags & IFF_PROMISC)
+ umal_promiscuous_mode(sc, 1);
+ else
+ umal_promiscuous_mode(sc, 0);
+ }
+ spin_unlock_irqrestore(&sc->umal_lock, flags);
+
+ /*
+ * Program the multicasts. Do this every time.
+ */
+ umal_setmulti(sc);
+}
+
+/**********************************************************************
+ * UMAL_PROMISCUOUS_MODE(sc,onoff)
+ *
+ * Turn on or off promiscuous mode
+ *
+ * Input parameters:
+ * sc - softc
+ * onoff - 1 to turn on, 0 to turn off
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_promiscuous_mode(struct umal_softc *sc, int onoff)
+{
+ if (onoff) {
+ UMAL_FIFOCFG4 &= ~0x40000;
+ UMAL_FIFOCFG5 |= 0x40000;
+ } else {
+ UMAL_FIFOCFG4 |= 0x40000;
+ UMAL_FIFOCFG5 &= ~0x40000;
+ }
+}
+
+/**********************************************************************
+ * UMAL_SETMULTI(sc)
+ *
+ * Reprogram the multicast table into the hardware, given
+ * the list of multicasts associated with the interface
+ * structure.
+ *
+ * Input parameters:
+ * sc - softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_setmulti(struct umal_softc *sc)
+{
+}
+
+/**********************************************************************
+ * UMAL_SET_SPEED(s,speed)
+ *
+ * Configure LAN speed for the specified MAC.
+ * Warning: must be called when MAC is off!
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * speed - speed to set MAC to (see enum sbmac_speed)
+ *
+ * Return value:
+ * 1 if successful
+ * 0 indicates invalid parameters
+ ********************************************************************* */
+static int umal_set_speed(struct umal_softc *s, enum umal_speed speed)
+{
+ unsigned int cfg;
+
+ /*
+ * Save new current values
+ */
+ s->umal_speed = speed;
+
+ if (s->umal_state == umal_state_on)
+ return 0; /* save for next restart */
+
+ /*
+ * Read current register values
+ */
+ cfg = UMAL_CFG2;
+
+ /*
+ * Mask out the stuff we want to change
+ */
+ cfg &= ~(UMAL_CFG2_MODEMASK);
+
+ /*
+ * Now add in the new bits
+ */
+ switch (speed) {
+ case umal_speed_10:
+ cfg |= UMAL_CFG2_NIBBLEMODE;
+ break;
+
+ case umal_speed_100:
+ cfg |= UMAL_CFG2_NIBBLEMODE;
+ break;
+
+ default:
+ return 0;
+ }
+
+ /*
+ * Send the bits back to the hardware
+ */
+ UMAL_CFG2 = cfg;
+
+ return 1;
+}
+
+/**********************************************************************
+ * UMAL_SET_DUPLEX(s,duplex,fc)
+ *
+ * Set Ethernet duplex and flow control options for this MAC
+ * Warning: must be called when MAC is off!
+ *
+ * Input parameters:
+ * s - umal structure
+ * duplex - duplex setting (see enum sbmac_duplex)
+ * fc - flow control setting (see enum sbmac_fc)
+ *
+ * Return value:
+ * 1 if ok
+ * 0 if an invalid parameter combination was specified
+ ********************************************************************* */
+static int umal_set_duplex(struct umal_softc *s, enum umal_duplex duplex,
+ enum umal_fc fc)
+{
+ unsigned int cfg1, cfg2;
+ int err = 0;
+
+ /*
+ * Save new current values
+ */
+ s->umal_duplex = duplex;
+ s->umal_fc = fc;
+
+ if (s->umal_state == umal_state_on)
+ return 0; /* save for next restart */
+
+ /*
+ * Read current register values
+ */
+ cfg1 = UMAL_CFG1;
+ cfg2 = UMAL_CFG2;
+
+ /*
+ * Mask off the stuff we're about to change
+ */
+ cfg1 &= ~(UMAL_CFG1_TXFLOWCTL | UMAL_CFG1_RXFLOWCTL);
+ cfg2 &= ~(UMAL_CFG2_FULLDUPLEX);
+
+ err = 0;
+ switch (duplex) {
+ case umal_duplex_half:
+ break;
+
+ case umal_duplex_full:
+ cfg2 |= UMAL_CFG2_FULLDUPLEX;
+ break;
+
+ default:
+ err = 1;
+ }
+ if (!err)
+ UMAL_CFG2 = cfg2;
+
+ err = 0;
+ switch (fc) {
+ case umal_fc_disabled:
+ break;
+
+ case umal_fc_collision:
+ break;
+
+ case umal_fc_carrier:
+ break;
+
+ case umal_fc_frame:
+ cfg1 |= UMAL_CFG1_TXFLOWCTL | UMAL_CFG1_RXFLOWCTL;
+ break;
+
+ default:
+ err = 1;
+ }
+
+ if (!err)
+ UMAL_CFG1 = cfg1;
+
+ /*
+ * Send the bits back to the hardware
+ */
+ return 1;
+}
+
+/**********************************************************************
+ * UMAL_CHANGE_MTU(dev,new_mtu)
+ *
+ * Change MTU value
+ *
+ * Input parameters:
+ * dev - net_device structure
+ * new_mtu - new mtu value
+ *
+ * Return value:
+ * 1 if ok
+ ********************************************************************* */
+static int umal_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu > ENET_PACKET_SIZE)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+
+ pr_info("changing the mtu to %d\n", new_mtu);
+
+ return 0;
+}
+
+/**********************************************************************
+ * UMAL_MIIPOLL(dev)
+ *
+ * Phy statemachine call back routine for link change
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void umal_miipoll(struct net_device *dev)
+{
+ struct umal_softc *sc = netdev_priv(dev);
+ struct phy_device *phy_dev = sc->phy_dev;
+ unsigned long flags;
+ enum umal_fc fc;
+ int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg;
+
+ link_chg = (sc->umal_link != phy_dev->link);
+ speed_chg = (sc->umal_speed != phy_dev->speed);
+ duplex_chg = (sc->umal_duplex != phy_dev->duplex);
+ pause_chg = (sc->umal_pause != phy_dev->pause);
+
+ if (!link_chg && !speed_chg && !duplex_chg && !pause_chg)
+ return; /* Hmmm... */
+
+ if (!phy_dev->link) {
+ if (link_chg) {
+ sc->umal_link = phy_dev->link;
+ sc->umal_speed = umal_speed_none;
+ sc->umal_duplex = umal_duplex_none;
+ sc->umal_fc = umal_fc_disabled;
+ sc->umal_pause = -1;
+ pr_info("%s: link unavailable\n", dev->name);
+ }
+ return;
+ }
+
+ if (phy_dev->duplex == DUPLEX_FULL) {
+ if (phy_dev->pause)
+ fc = umal_fc_frame;
+ else
+ fc = umal_fc_disabled;
+ } else
+ fc = umal_fc_collision;
+ fc_chg = (sc->umal_fc != fc);
+
+ pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed,
+ phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H');
+
+ spin_lock_irqsave(&sc->umal_lock, flags);
+
+ sc->umal_speed = phy_dev->speed;
+ sc->umal_duplex = phy_dev->duplex;
+ sc->umal_fc = fc;
+ sc->umal_pause = phy_dev->pause;
+ sc->umal_link = phy_dev->link;
+
+ if ((speed_chg || duplex_chg || fc_chg) &&
+ sc->umal_state != umal_state_off) {
+ /*
+ * something changed, restart the channel
+ */
+ umal_channel_stop(sc);
+ umal_channel_start(sc);
+ }
+
+ spin_unlock_irqrestore(&sc->umal_lock, flags);
+}
+
+static int umal_probe(struct platform_device *pldev)
+{
+ struct net_device *dev;
+ struct umal_softc *sc;
+ struct resource *res;
+ int err;
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ BUG_ON(!res);
+
+ /*
+ * Okay, cool. Initialize this MAC.
+ */
+ dev = alloc_etherdev(sizeof(struct umal_softc));
+ if (!dev) {
+ printk(KERN_ERR "%s: unable to allocate etherdev\n",
+ dev_name(&pldev->dev));
+ err = -ENOMEM;
+ goto out_out;
+ }
+
+ dev_set_drvdata(&pldev->dev, dev);
+ SET_NETDEV_DEV(dev, &pldev->dev);
+
+ sc = netdev_priv(dev);
+
+ err = umal_init(pldev, res->start);
+ if (err)
+ goto out_kfree;
+
+ return 0;
+
+out_kfree:
+ free_netdev(dev);
+
+out_out:
+ return err;
+}
+
+static int __exit umal_remove(struct platform_device *pldev)
+{
+ struct net_device *dev = dev_get_drvdata(&pldev->dev);
+ struct umal_softc *sc = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ umal_uninitctx(sc);
+ mdiobus_unregister(sc->mii_bus);
+ free_netdev(dev);
+
+ return 0;
+}
+
+#if CONFIG_PM
+static void umal_reset(struct net_device *ndev)
+{
+ UMAL_CFG1 = UMAL_CFG1_RESET; /* reset MAC */
+ UMAL_CFG1 = 0; /* clear the reset bit of MAC */
+ UMAL_IFCTRL = UMAL_IFCTRL_RESET; /* reset the MAC Interface */
+ UMAL_DMAIntrMask = 1;
+
+ UMAL_FIFOCFG0 = 0x000000ff; /* reset FIFO */
+ UMAL_FIFOCFG1 = 0x0fff0fff; /* request enable modules in fifo */
+ UMAL_FIFOCFG2 = 0x0aaa0555; /* request enable modules in fifo */
+ UMAL_FIFOCFG3 = 0x02800fff; /* set water mark register */
+ UMAL_FIFOCFG4 = 0x00000070;
+ UMAL_FIFOCFG5 = 0x0007ff8f;
+ UMAL_FIFOCFG0 = 0x0000ff00; /* request enable modules in fifo */
+
+ UMAL_CFG2 = 0x7016;
+}
+
+static void umal_shutdown(struct net_device *ndev)
+{
+ /* not implemented*/
+ return;
+}
+
+static int umal_suspend(struct platform_device *pldev, pm_message_t state)
+{
+ struct net_device *ndev = platform_get_drvdata(pldev);
+
+ if (netif_running(ndev)) {
+ netif_device_detach(ndev);
+ umal_shutdown(ndev);
+ }
+ return 0;
+}
+
+static int umal_resume(struct platform_device *pldev)
+{
+ struct net_device *dev = platform_get_drvdata(pldev);
+
+ if (netif_running(dev)) {
+ umal_reset(dev);
+ netif_device_attach(dev);
+ }
+ return 0;
+}
+#else
+static int umal_suspend(struct platform_device *pldev, pm_message_t state) { }
+static int umal_resume(struct platform_device *pldev) { }
+#endif
+static struct platform_driver umal_driver = {
+ .probe = umal_probe,
+ .remove = __exit_p(umal_remove),
+ .driver = {
+ .name = umal_string,
+ .owner = THIS_MODULE,
+ },
+ .suspend = umal_suspend,
+ .resume = umal_resume,
+};
+
+static int __init umal_init_module(void)
+{
+ return platform_driver_register(&umal_driver);
+}
+
+static void __exit umal_cleanup_module(void)
+{
+ platform_driver_unregister(&umal_driver);
+}
+
+module_init(umal_init_module);
+module_exit(umal_cleanup_module);
^ permalink raw reply related
* Re: [PATCH] xen: netfront: Drop GSO SKBs which do not have csum_blank.
From: Ian Campbell @ 2011-01-22 9:43 UTC (permalink / raw)
To: Jeremy Fitzhardinge; +Cc: netdev@vger.kernel.org, xen-devel@lists.xensource.com
In-Reply-To: <4D3A2BD2.5030802@goop.org>
On Sat, 2011-01-22 at 00:58 +0000, Jeremy Fitzhardinge wrote:
> On 01/05/2011 05:23 AM, Ian Campbell wrote:
> > The Linux network stack expects all GSO SKBs to have ip_summed ==
> > CHECKSUM_PARTIAL (which implies that the frame contains a partial
> > checksum) and the Xen network ring protocol similarly expects an SKB
> > which has GSO set to also have NETRX_csum_blank (which also implies a
> > partial checksum). Therefore drop such frames on receive otherwise
> > they will trigger the warning in skb_gso_segment.
> >
> > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> > Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> > Cc: xen-devel@lists.xensource.com
> > Cc: netdev@vger.kernel.org
> > ---
> > drivers/net/xen-netfront.c | 5 +++++
> > 1 files changed, 5 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
> > index cdbeec9..8b8c480 100644
> > --- a/drivers/net/xen-netfront.c
> > +++ b/drivers/net/xen-netfront.c
> > @@ -836,6 +836,11 @@ static int handle_incoming_queue(struct net_device *dev,
> > dev->stats.rx_errors++;
> > continue;
> > }
> > + } else if (skb_is_gso(skb)) {
> > + kfree_skb(skb);
> > + packets_dropped++;
> > + dev->stats.rx_errors++;
> > + continue;
>
> This looks redundant; why not something like:
>
> diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
> index 47e6a71..c1b8f64 100644
> --- a/drivers/net/xen-netfront.c
> +++ b/drivers/net/xen-netfront.c
> @@ -852,13 +852,12 @@ static int handle_incoming_queue(struct net_device *dev,
> /* Ethernet work: Delayed to here as it peeks the header. */
> skb->protocol = eth_type_trans(skb, dev);
>
> - if (skb->ip_summed == CHECKSUM_PARTIAL) {
> - if (skb_checksum_setup(skb)) {
> - kfree_skb(skb);
> - packets_dropped++;
> - dev->stats.rx_errors++;
> - continue;
> - }
> + if (skb->ip_summed != CHECKSUM_PARTIAL ||
> + skb_checksum_setup(skb)) {
That drops non-partial skbs. However they are fine unless they also
claim to be gso.
Perhaps you meant "skb->ip_summed == CHECKSUM_PARTIAL && !
skb_checksum_setup(skb)" which I think works but doesn't allow us to
correctly chain the gso check onto the else.
Ian.
> + kfree_skb(skb);
> + packets_dropped++;
> + dev->stats.rx_errors++;
> + continue;
> }
>
> dev->stats.rx_packets++;
>
> Thanks,
> J
>
>
^ permalink raw reply
* Re: Problems with /proc/net/tcp6 - possible bug - ipv6
From: Eric Dumazet @ 2011-01-22 8:59 UTC (permalink / raw)
To: PK; +Cc: linux-kernel, netdev
In-Reply-To: <702550.61465.qm@web63902.mail.re1.yahoo.com>
Le vendredi 21 janvier 2011 à 22:30 -0800, PK a écrit :
> Creating many ipv6 connections hits a ceiling on connections/fds ; okay, fine.
>
> But in my case I'm seeing millions of entries spring up within a few seconds and
> then vanish within a few minutes, in /proc/net/tcp6 (vanish due to garbage
> collection?)
>
> Furthermore I can trigger this easily on vanilla kernels from 2.6.36 to
> 2.6.38-rc1-next-20110121 inside a ubuntu 10.10 amd64 vm, causing the kernel to
> spew warnings. There is also some corruption in the logs (see kernel-sample.log
> line 296), but that may be unrelated.
>
> More explanation, kernel config of the primary machine I saw this on, sample
> ruby script to reproduce (inside the ubuntu VMs I apt-get and use ruby-1.9.1),
> are located at
> https://github.com/runningdogx/net6-bug
>
> Seems to only affect 64-bit. So far I have not been able to reproduce on 32-bit
> ubuntu VMs of any kernel version.
> Seems to only affect IPv6. So far I have not been able to reproduce using IPv4
> connections (and watching /proc/net/tcp of course).
> Does not trigger the bug if the connections are made to ::1. Only externally
> routable local and global IPv6 addresses seem to cause problems.
> Seems to have been introduced between 2.6.35 and 2.6.36 (see README on github
> for more kernels I've tried)
>
> All the tested Ubuntu VMs are stock 10.10 userland, with vanilla kernels (the
> latest ubuntu kernel is 2.6.35-something, and my initial test didn't show it
> suffering from this problem)
>
> Originally noticed on separate Gentoo 64-bit non-vm system when doing web
> benchmarking.
>
> not subscribed, so please keep me in cc although I'll try to follow the thread
>
>
Hi PK (Sorry, your real name is hidden)
I could not reproduce this on current linux-2.6 kernel.
How many vcpus running in your VM, and memory ?
Note : a recent commit did fix /proc/net/tcp[6] behavior
commit 1bde5ac49398a064c753bb490535cfad89e99a5f
Author: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu Dec 23 09:32:46 2010 -0800
tcp: fix listening_get_next()
Alexey Vlasov found /proc/net/tcp could sometime loop and display
millions of sockets in LISTEN state.
In 2.6.29, when we converted TCP hash tables to RCU, we left two
sk_next() calls in listening_get_next().
We must instead use sk_nulls_next() to properly detect an end of chain.
Reported-by: Alexey Vlasov <renton@renton.name>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* Re: [PATCH] neigh: __rcu annotations
From: Paul E. McKenney @ 2011-01-22 1:36 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1295510567.2653.487.camel@edumazet-laptop>
On Thu, Jan 20, 2011 at 09:02:47AM +0100, Eric Dumazet wrote:
> fix some minor issues and sparse (__rcu) warnings
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> net/core/neighbour.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/net/core/neighbour.c b/net/core/neighbour.c
> index 60a9029..799f06e 100644
> --- a/net/core/neighbour.c
> +++ b/net/core/neighbour.c
> @@ -316,7 +316,7 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int entries)
> {
> size_t size = entries * sizeof(struct neighbour *);
> struct neigh_hash_table *ret;
> - struct neighbour **buckets;
> + struct neighbour __rcu **buckets;
>
> ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
> if (!ret)
> @@ -324,14 +324,14 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int entries)
> if (size <= PAGE_SIZE)
> buckets = kzalloc(size, GFP_ATOMIC);
> else
> - buckets = (struct neighbour **)
> + buckets = (struct neighbour __rcu **)
> __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
> get_order(size));
> if (!buckets) {
> kfree(ret);
> return NULL;
> }
> - rcu_assign_pointer(ret->hash_buckets, buckets);
> + ret->hash_buckets = buckets;
> ret->hash_mask = entries - 1;
> get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
> return ret;
> @@ -343,7 +343,7 @@ static void neigh_hash_free_rcu(struct rcu_head *head)
> struct neigh_hash_table,
> rcu);
> size_t size = (nht->hash_mask + 1) * sizeof(struct neighbour *);
> - struct neighbour **buckets = nht->hash_buckets;
> + struct neighbour __rcu **buckets = nht->hash_buckets;
>
> if (size <= PAGE_SIZE)
> kfree(buckets);
> @@ -1540,7 +1540,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
> panic("cannot create neighbour proc dir entry");
> #endif
>
> - tbl->nht = neigh_hash_alloc(8);
> + RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(8));
>
> phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
> tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
> @@ -1602,7 +1602,8 @@ int neigh_table_clear(struct neigh_table *tbl)
> }
> write_unlock(&neigh_tbl_lock);
>
> - call_rcu(&tbl->nht->rcu, neigh_hash_free_rcu);
> + call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
> + neigh_hash_free_rcu);
Hello, Eric,
Any chance of a comment? Perhaps something like:
/*
* Because this has been removed from the list, no other updater
* can access this element.
*/
Thanx, Paul
> tbl->nht = NULL;
>
> kfree(tbl->phash_buckets);
>
>
> --
> 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
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