* Re: [1/4] kevent: core files.
From: Evgeniy Polyakov @ 2006-06-23 20:17 UTC (permalink / raw)
To: Benjamin LaHaise; +Cc: David Miller, netdev
In-Reply-To: <20060623195513.GC14126@kvack.org>
On Fri, Jun 23, 2006 at 03:55:13PM -0400, Benjamin LaHaise (bcrl@kvack.org) wrote:
> On Fri, Jun 23, 2006 at 11:24:29PM +0400, Evgeniy Polyakov wrote:
> > What API are you talking about?
> > There is only epoll(), which is 40% slower than kevent, and AIO, which
> > works not as state machine, but as repeated call for the same work.
> > There is also inotify, which allocates new message each time event
> > occurs, which is not a good solution for every situation.
>
> AIO can be implemented as a state machine. Nothing in the API stops
> you from doing that, and in fact there was code which was implemented as
> a state machine used on 2.4 kernels.
But now it is implemented as repeated call for the same work, which does
not look like it can be used for any other types of work.
And repeated work introduce latencies.
As far as I recall, it is you who wanted to remove thread based approach
from AIO subsystem.
> > Linux just does not have unified event processing mechanism, which was
> > pointed to many times in AIO mail list and when epoll() was only
> > introduced. I would even say, that Linux does not have such mechanism at
> > all, since every potential user implements it's own, which can not be
> > used with others.
>
> The epoll event API doesn't have space in the event fields for result codes
> as needed for AIO. The AIO API does -- how is it lacking in this regard?
AIO completion approach was designed to be used with process context VFS
update. read/write approach can not cover other types of notifications,
like inode updates or timers.
> > Kevent fixes that. Although implementation itself can be suboptimal for
> > some cases or even unacceptible at all, but it is really needed
> > functionality.
>
> At the expense of adding another API? How is this a good thing? Why
> not spit out events in the existing format?
Format of the structure transferred between the objects does not matter
at all. We can create a wrapper on kevent structures or kevent can
transform data from AIO objects.
The main design goal of kevent is to provide easy connected hooks into
any state machine, which might be used by kernelspace to notify about
any kind of events without any knowledge of it's background nature.
Kevent can be used for example as notification blocks for address
changes or it can replace netlink completely (it can even emulate
event multicasting).
Kevent is queue of events, which can be transferred from any object to
any destination.
> > Every existing notification can be built on top of kevent. One can find
> > how easy it was to implement generic poll/select notifications (what
> > epoll() does) or socket notifications (which are similar to epoll(), but
> > are called from inside socket state machine, thus improving processing
> > performance).
>
> So far your code is adding a lot without unifying anything.
Not at all!
Kevent is a mechanism, which allows to impleement AIO, network AIO, poll
and select, timer control, adaptive readhead (as example of AIO VFS
update). All the code I present shows how to use kevent, it is not part
of the kevent. One can find Makefile in kevent dir to check what is the
core of the subsystem, which allows to be used as a transport for
events.
AIO, NAIO, poll/select, socket and timer notifications are just users.
One can add it's own usage as easy as to call kevent_storage
initialization function and event generation function. All other pieces
are hidded in the implementation.
> -ben
> --
> "Time is of no importance, Mr. President, only life is important."
> Don't Email: <dont@kvack.org>.
--
Evgeniy Polyakov
^ permalink raw reply
* [PATCH REPOST 0/2][RFC] Network Event Notifier Mechanism
From: Steve Wise @ 2006-06-23 20:19 UTC (permalink / raw)
To: davem; +Cc: netdev
This patch implements a mechanism that allows interested clients to
register for notification of certain network events. The intended use
is to allow RDMA devices (linux/drivers/infiniband) to be notified of
neighbour updates, ICMP redirects, path MTU changes, and route changes.
The reason these devices need update events is because they typically
cache this information in hardware and need to be notified when this
information has been updated.
The key events of interest are:
- neighbour mac address change
- routing redirect (the next hop neighbour changes for a dst_entry)
- path mtu change (the patch mtu for a dst_entry changes).
- route add/deletes
This approach is one of many possibilities and may be preferred because it
uses an existing notification mechanism that has precedent in the stack.
An alternative would be to add a netdev method to notify affect devices
of these events.
This code does not yet implement path MTU change because the number of
places in which this value is updated is large and if this mechanism
seems reasonable, it would be probably be best to funnel these updates
through a single function.
We would like to get this or similar functionality included in 2.6.19
and request comments.
This patchset consists of 2 patches:
1) New files implementing the Network Event Notifier
2) Core network changes to generate network event notifications
Signed-off-by: Tom Tucker <tom@opengridcomputing.com>
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
^ permalink raw reply
* [PATCH REPOST 1/2] Network Event Notifier Mechanism.
From: Steve Wise @ 2006-06-23 20:19 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <20060623201918.32482.89765.stgit@stevo-desktop>
This patch uses notifier blocks to implement a network event
notifier mechanism.
Clients register their callback function by calling
register_netevent_notifier() like this:
static struct notifier_block nb = {
.notifier_call = my_callback_func
};
...
register_netevent_notifier(&nb);
---
include/net/netevent.h | 41 +++++++++++++++++++++++++++++
net/core/netevent.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+), 0 deletions(-)
diff --git a/include/net/netevent.h b/include/net/netevent.h
new file mode 100644
index 0000000..9ceab27
--- /dev/null
+++ b/include/net/netevent.h
@@ -0,0 +1,41 @@
+#ifndef _NET_EVENT_H
+#define _NET_EVENT_H
+
+/*
+ * Generic netevent notifiers
+ *
+ * Authors:
+ * Tom Tucker <tom@opengridcomputing.com>
+ *
+ * Changes:
+ */
+
+#ifdef __KERNEL__
+
+#include <net/dst.h>
+
+struct netevent_redirect {
+ struct dst_entry *old;
+ struct dst_entry *new;
+};
+
+struct netevent_route_change {
+ int event;
+ struct fib_info *fib_info;
+};
+
+enum netevent_notif_type {
+ NETEVENT_NEIGH_UPDATE = 1, /* arg is * struct neighbour */
+ NETEVENT_ROUTE_UPDATE, /* arg is * netevent_route_change */
+ NETEVENT_PMTU_UPDATE,
+ NETEVENT_REDIRECT, /* arg is * struct netevent_redirect */
+};
+
+extern int register_netevent_notifier(struct notifier_block *nb);
+extern int unregister_netevent_notifier(struct notifier_block *nb);
+extern int call_netevent_notifiers(unsigned long val, void *v);
+
+#endif
+#endif
+
+
diff --git a/net/core/netevent.c b/net/core/netevent.c
new file mode 100644
index 0000000..8f3e0a6
--- /dev/null
+++ b/net/core/netevent.c
@@ -0,0 +1,67 @@
+/*
+ * Network event notifiers
+ *
+ * Authors:
+ * Tom Tucker <tom@opengridcomputing.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ */
+
+#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
+
+static ATOMIC_NOTIFIER_HEAD(netevent_notif_chain);
+
+/**
+ * register_netevent_notifier - register a netevent notifier block
+ * @nb: notifier
+ *
+ * Register a notifier to be called when a netevent occurs.
+ * The notifier passed is linked into the kernel structures and must
+ * not be reused until it has been unregistered. A negative errno code
+ * is returned on a failure.
+ */
+int register_netevent_notifier(struct notifier_block *nb)
+{
+ int err;
+
+ err = atomic_notifier_chain_register(&netevent_notif_chain, nb);
+ return err;
+}
+
+/**
+ * netevent_unregister_notifier - unregister a netevent notifier block
+ * @nb: notifier
+ *
+ * Unregister a notifier previously registered by
+ * register_neigh_notifier(). The notifier is unlinked into the
+ * kernel structures and may then be reused. A negative errno code
+ * is returned on a failure.
+ */
+
+int unregister_netevent_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&netevent_notif_chain, nb);
+}
+
+/**
+ * call_netevent_notifiers - call all netevent notifier blocks
+ * @val: value passed unmodified to notifier function
+ * @v: pointer passed unmodified to notifier function
+ *
+ * Call all neighbour notifier blocks. Parameters and return value
+ * are as for notifier_call_chain().
+ */
+
+int call_netevent_notifiers(unsigned long val, void *v)
+{
+ return atomic_notifier_call_chain(&netevent_notif_chain, val, v);
+}
+
+EXPORT_SYMBOL_GPL(register_netevent_notifier);
+EXPORT_SYMBOL_GPL(unregister_netevent_notifier);
^ permalink raw reply related
* [PATCH REPOST 2/2] Core network changes to support network event notification.
From: Steve Wise @ 2006-06-23 20:19 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <20060623201918.32482.89765.stgit@stevo-desktop>
This patch adds event calls for neighbour change, route update, and
routing redirect events.
TODO: PMTU change events.
---
net/core/Makefile | 2 +-
net/core/neighbour.c | 8 ++++++++
net/ipv4/fib_semantics.c | 7 +++++++
net/ipv4/route.c | 6 ++++++
4 files changed, 22 insertions(+), 1 deletions(-)
diff --git a/net/core/Makefile b/net/core/Makefile
index e9bd246..2645ba4 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -7,7 +7,7 @@ obj-y := sock.o request_sock.o skbuff.o
obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
-obj-y += dev.o ethtool.o dev_mcast.o dst.o \
+obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o
obj-$(CONFIG_XFRM) += flow.o
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 50a8c73..c637897 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -30,9 +30,11 @@ #include <linux/times.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/sock.h>
+#include <net/netevent.h>
#include <linux/rtnetlink.h>
#include <linux/random.h>
#include <linux/string.h>
+#include <linux/notifier.h>
#define NEIGH_DEBUG 1
@@ -755,6 +757,7 @@ #endif
neigh->nud_state = NUD_STALE;
neigh->updated = jiffies;
neigh_suspect(neigh);
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
}
} else if (state & NUD_DELAY) {
if (time_before_eq(now,
@@ -763,6 +766,7 @@ #endif
neigh->nud_state = NUD_REACHABLE;
neigh->updated = jiffies;
neigh_connect(neigh);
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
next = neigh->confirmed + neigh->parms->reachable_time;
} else {
NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
@@ -783,6 +787,7 @@ #endif
neigh->nud_state = NUD_FAILED;
neigh->updated = jiffies;
notify = 1;
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
@@ -1056,6 +1061,9 @@ out:
(neigh->flags | NTF_ROUTER) :
(neigh->flags & ~NTF_ROUTER);
}
+
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
+
write_unlock_bh(&neigh->lock);
#ifdef CONFIG_ARPD
if (notify && neigh->parms->app_probes)
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 0f4145b..67a30af 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -45,6 +45,7 @@ #include <net/tcp.h>
#include <net/sock.h>
#include <net/ip_fib.h>
#include <net/ip_mp_alg.h>
+#include <net/netevent.h>
#include "fib_lookup.h"
@@ -278,9 +279,15 @@ void rtmsg_fib(int event, u32 key, struc
struct nlmsghdr *n, struct netlink_skb_parms *req)
{
struct sk_buff *skb;
+ struct netevent_route_change rev;
+
u32 pid = req ? req->pid : n->nlmsg_pid;
int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+ rev.event = event;
+ rev.fib_info = fa->fa_info;
+ call_netevent_notifiers(NETEVENT_ROUTE_UPDATE, &rev);
+
skb = alloc_skb(size, GFP_KERNEL);
if (!skb)
return;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index cc9423d..e9ba831 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -105,6 +105,7 @@ #include <net/tcp.h>
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/ip_mp_alg.h>
+#include <net/netevent.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
@@ -1120,6 +1121,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
struct rtable *rth, **rthp;
u32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
+ struct netevent_redirect netevent;
if (!in_dev)
return;
@@ -1211,6 +1213,10 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
rt_drop(rt);
goto do_next;
}
+
+ netevent.old = &rth->u.dst;
+ netevent.new = &rt->u.dst;
+ call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
rt_del(hash, rth);
if (!rt_intern_hash(hash, rt, &rt))
^ permalink raw reply related
* Re: [1/4] kevent: core files.
From: David Miller @ 2006-06-23 20:19 UTC (permalink / raw)
To: johnpol; +Cc: bcrl, netdev
In-Reply-To: <20060623192422.GA11508@2ka.mipt.ru>
From: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Date: Fri, 23 Jun 2006 23:24:29 +0400
> Linux just does not have unified event processing mechanism, which was
> pointed to many times in AIO mail list and when epoll() was only
> introduced. I would even say, that Linux does not have such mechanism at
> all, since every potential user implements it's own, which can not be
> used with others.
>
> Kevent fixes that. Although implementation itself can be suboptimal for
> some cases or even unacceptible at all, but it is really needed
> functionality.
I completely agree with Evgeniy here.
There is nothing in the kernel today that provides integrated event
handling. Nothing. So when someone says to use the "existing" stuff,
they need to have their head examined.
The existing AIO stuff stinks as a set of interfaces. It was designed
by a standards committee, not by people truly interested in a good
performing event processing design. It is especially poorly suited
for networking, and any networking developer understands this.
It is pretty much a foregone conclusion that we will need new
APIs to get good networking performance. Every existing interface
has one limitation or another.
So we should be happy people like Evgeniy try to work on this stuff,
instead of discouraging them.
^ permalink raw reply
* Re: [PATCH REPOST 1/2] Network Event Notifier Mechanism.
From: David Miller @ 2006-06-23 20:26 UTC (permalink / raw)
To: swise; +Cc: netdev
In-Reply-To: <20060623201928.32482.69191.stgit@stevo-desktop>
From: Steve Wise <swise@opengridcomputing.com>
Date: Fri, 23 Jun 2006 15:19:28 -0500
> +struct netevent_route_change {
> + int event;
> + struct fib_info *fib_info;
> +};
It's not generic if you're putting ipv4 FIB route objects
in the datastructure.
This is so much unnecessary syntactic sugar for what you're
trying to accomplish.
Just pass a "void *", and have the type of the object defined by which
notifier it is. This is exactly how all notifiers work today.
Then you don't need any new infrastructure at all. The existing
notifier bits handle this kind of scheme already, no need to
invent new stuff.
^ permalink raw reply
* Re: [1/4] kevent: core files.
From: Benjamin LaHaise @ 2006-06-23 20:31 UTC (permalink / raw)
To: David Miller; +Cc: johnpol, netdev
In-Reply-To: <20060623.131940.48806210.davem@davemloft.net>
On Fri, Jun 23, 2006 at 01:19:40PM -0700, David Miller wrote:
> I completely agree with Evgeniy here.
>
> There is nothing in the kernel today that provides integrated event
> handling. Nothing. So when someone says to use the "existing" stuff,
> they need to have their head examined.
The existing AIO events are *events*, with the syscalls providing the
reading of events.
> The existing AIO stuff stinks as a set of interfaces. It was designed
> by a standards committee, not by people truly interested in a good
> performing event processing design. It is especially poorly suited
> for networking, and any networking developer understands this.
I disagree. Stuffing an event that a read or write is complete/ready is a
good way of handling things, even more so with hardware that will perform
the memory copies to/from user buffers.
> It is pretty much a foregone conclusion that we will need new
> APIs to get good networking performance. Every existing interface
> has one limitation or another.
Eh? Nobody has posted any numbers comparing the approaches yet, so this
is pure handwaving, unless you have real concrete results?
> So we should be happy people like Evgeniy try to work on this stuff,
> instead of discouraging them.
I would like to encourage him, but at the same time I don't want to see
creating APIs that essentially duplicate existing work and needlessly
break compatibility. I completely agree that the in-kernel APIs are not
as encompassing as they should be, and within the kernel Evgeniy's work
may well be the way to go. What I do not agree is that we need new
syscalls at this point. I'm perfectly willing to accept proof that change
is needed if we do a proper comparision between any new syscall API and the
use of the existing syscall API, but the pain of introducing a new API is
sufficiently large that I think it is worth looking at the numbers.
-ben
--
"Time is of no importance, Mr. President, only life is important."
Don't Email: <dont@kvack.org>.
^ permalink raw reply
* Streamline testing of 802.11 drivers
From: Luis R. Rodriguez @ 2006-06-23 20:33 UTC (permalink / raw)
To: netdev, zd1211-devs; +Cc: Kishore Ramachandran, Ivan Seskar
I've mentioned this to a few but here it is out to everyone. So as you
know we have a lot of work ahead of us for linux wireless development.
To help speed this up, we at Winlab, would like to start hosting a
testbed for linux wireless development, open to the public. Short term
goals would be to start off a couple of nodes for each driver
currently under development like bcm43xx, zd1211, rt2x00, ipw3945,
ipw2200 and the like, and a provide a set streamlined tests we can use
to really put to test the drivers and stacks.
This wouldn't be easy if we didn't have infrastructure but we already
do. Our grid consists of 400 nodes with 2 wireless cards each and 3
ethernet ports (one for control) --
http://orbit-lab.org/wiki/Tutorial/Testbed. 90% of our nodes use the
atheros 5213 chipset and the rest ipw2200s. We'd like to expand this
with the more wireless cards currently being worked on for linux.
Right now we have zome zd1211s so we'll start with that (I'll start
working on a port to d80211) but will try to accomodate other nodes as
we get more wireless cards. We will need some help too though, to
streamline the testing. If you have ideas or would like to contribute
please let me know. We can purchase wireless cards but if you already
have reliable confirmed wireless cards which can be used for putting
into the testbed let me know.
Luis
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
^ permalink raw reply
* Re: [RFC 3/7] NetLabel: CIPSOv4 engine
From: Ted @ 2006-06-23 20:34 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060623.131512.21593290.davem@davemloft.net>
On Fri, 2006-06-23 at 13:15 -0700, David Miller wrote:
> From: Ted <txtoth@gmail.com>
> Date: Fri, 23 Jun 2006 13:48:01 -0500
>
> > Realistically customers most likely to adopt use of SELinux are
> > going to be ones that currently use other trusted OSs such as TSOL
> > and HP-UX CMW.
>
> Every single user who installs a modern distribution these days likely
> gets SELINUX enabled by default, and are therefore adopters of
> SELINUX. That's a lot of people.
>
> The number of people with existing CIPSO infrastructure are miniscule
> in comparison.
>
I think that except those who currently use and understand trusted OSs
users will change SELinux to permissive mode because they won't have the
expertise to deal with policy issues.
> Please do not even imply that CIPSO use is anything but fringe in the
> grand scheme of things. It most certainly is. And it will be
> replaced by IPSEC based labelling, that is a fact. If people cannot
> move over to IPSEC labelling simply because their HPUX/TSOL doesn't
> support it, I'm perfectly happy for those users to stick with HPUX and
> TSOL. A lot of people think Linux should try to be everything for
> everybody, I'm not one of those people :-)
>
I can guarantee that initially SELinux adoption will be by those running
trusted OSs and they will want their systems to be able to interoperate
at level. The idea that IPSEC will fill this need in the near term is
just not realistic.
> For CIPSO we eat a non-trivial maintainence and bloat cost in order to
> support legacy stuff for this relatively tiny group of potential
> users.
>
> I'd rather pay the bloat and development costs on something forward
> thinking like IPSEC labelling. Something people will actually be
> using years from now, rather than a dying technology that few people
> (relatively speaking) use as it is.
>
> Finally, even if CIPSO is something we want to put in, don't worry
> about it as there's still time to discuss things. A couple days
> before the merge window of 2.6.18 development closes is not the time
> to be submitting half-finished work and expecting it to be integrated.
> If 2.6.18 integration is what the submitter desires, they should have
> finished their work and started this review process weeks if not
> months ago.
^ permalink raw reply
* Re: [PATCH REPOST 1/2] Network Event Notifier Mechanism.
From: Steve Wise @ 2006-06-23 20:34 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20060623.132647.39159829.davem@davemloft.net>
On Fri, 2006-06-23 at 13:26 -0700, David Miller wrote:
> From: Steve Wise <swise@opengridcomputing.com>
> Date: Fri, 23 Jun 2006 15:19:28 -0500
>
> > +struct netevent_route_change {
> > + int event;
> > + struct fib_info *fib_info;
> > +};
>
> It's not generic if you're putting ipv4 FIB route objects
> in the datastructure.
>
> This is so much unnecessary syntactic sugar for what you're
> trying to accomplish.
>
> Just pass a "void *", and have the type of the object defined by which
> notifier it is. This is exactly how all notifiers work today.
>
> Then you don't need any new infrastructure at all. The existing
> notifier bits handle this kind of scheme already, no need to
> invent new stuff.
Ok.
But what about the redirect event? It really needs to pass two bits of
info: The old dst_entry ptr and the new dst_entry ptr. This is needed
so the rdma driver can figure out which connections now need to use the
new dst_entry...
^ permalink raw reply
* Re: [1/4] kevent: core files.
From: Benjamin LaHaise @ 2006-06-23 20:44 UTC (permalink / raw)
To: Evgeniy Polyakov; +Cc: David Miller, netdev
In-Reply-To: <20060623201716.GA26168@2ka.mipt.ru>
On Sat, Jun 24, 2006 at 12:17:17AM +0400, Evgeniy Polyakov wrote:
> But now it is implemented as repeated call for the same work, which does
> not look like it can be used for any other types of work.
Given an iocb, you do not have to return -EIOCBRETRY, instead return
-EIOCBQUEUED and then from whatever context do an aio_complete() with the
result for that iocb.
> And repeated work introduce latencies.
> As far as I recall, it is you who wanted to remove thread based approach
> from AIO subsystem.
I have essentially given up on trying to get the filesystem AIO patches
in given that the concerns against them are "woe complexity" with no real
recourse for inclusion being open. If David is open to changes in the
networking area, I'd love to see it built on top of your code.
> AIO completion approach was designed to be used with process context VFS
> update. read/write approach can not cover other types of notifications,
> like inode updates or timers.
The completion event is 100% generic and does not need to come from process
context. Calling aio_complete() from irq context is entirely valid.
> Format of the structure transferred between the objects does not matter
> at all. We can create a wrapper on kevent structures or kevent can
> transform data from AIO objects.
> The main design goal of kevent is to provide easy connected hooks into
> any state machine, which might be used by kernelspace to notify about
> any kind of events without any knowledge of it's background nature.
> Kevent can be used for example as notification blocks for address
> changes or it can replace netlink completely (it can even emulate
> event multicasting).
>
> Kevent is queue of events, which can be transferred from any object to
> any destination.
And io_getevents() reads a queue of events, so I'm not sure why you need
a new syscall.
> Not at all!
> Kevent is a mechanism, which allows to impleement AIO, network AIO, poll
> and select, timer control, adaptive readhead (as example of AIO VFS
> update). All the code I present shows how to use kevent, it is not part
> of the kevent. One can find Makefile in kevent dir to check what is the
> core of the subsystem, which allows to be used as a transport for
> events.
>
> AIO, NAIO, poll/select, socket and timer notifications are just users.
> One can add it's own usage as easy as to call kevent_storage
> initialization function and event generation function. All other pieces
> are hidded in the implementation.
I'll look at adapting your code to use the existing syscalls. Maybe code
will be better at expressing my concerns.
-ben
--
"Time is of no importance, Mr. President, only life is important."
Don't Email: <dont@kvack.org>.
^ permalink raw reply
* Re: [1/4] kevent: core files.
From: Evgeniy Polyakov @ 2006-06-23 20:54 UTC (permalink / raw)
To: Benjamin LaHaise; +Cc: David Miller, netdev
In-Reply-To: <20060623203114.GD14126@kvack.org>
On Fri, Jun 23, 2006 at 04:31:14PM -0400, Benjamin LaHaise (bcrl@kvack.org) wrote:
> may well be the way to go. What I do not agree is that we need new
> syscalls at this point. I'm perfectly willing to accept proof that change
> is needed if we do a proper comparision between any new syscall API and the
> use of the existing syscall API, but the pain of introducing a new API is
> sufficiently large that I think it is worth looking at the numbers.
New syscall is just an interface. Originally kevent (and it still can)
use char device and it's ioctl method.
It is perfectly possible to create wrappers for posix aio_* calls,
although I do not see why it is needed.
No need to concentrate on end-users interface at this point - it can be
changed at any time since design allows it, we should think about
overall design and if it is ok, move forward in implementation.
Btw, new API adds only one syscall for userspace kevent processing (and
three for send/recv/sendfile for network AIO).
According to numbers: kevent compared to epoll resulted in the
folllowing numbers:
kevent: more than 2600 requests per second (trivial web server)
epoll: about 1600-1800 requests.
Number of errors for 3k bursts of connections with 30K connections total
in 10seconds:
kevent: about 2k errors.
epoll: upto 15k errors.
More detailed results can be found on project's homepage at:
tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
> -ben
--
Evgeniy Polyakov
^ permalink raw reply
* Re: [1/4] kevent: core files.
From: David Miller @ 2006-06-23 20:54 UTC (permalink / raw)
To: bcrl; +Cc: johnpol, netdev
In-Reply-To: <20060623203114.GD14126@kvack.org>
From: Benjamin LaHaise <bcrl@kvack.org>
Date: Fri, 23 Jun 2006 16:31:14 -0400
> Eh? Nobody has posted any numbers comparing the approaches yet, so this
> is pure handwaving, unless you have real concrete results?
Evgeniy posts numbers and performance graphs on his kevent work all
the time.
Van Jacobson did in his LCA2006 net channel slides too, perhaps you
missed that.
^ permalink raw reply
* Re: Streamline testing of 802.11 drivers
From: Luis R. Rodriguez @ 2006-06-23 20:56 UTC (permalink / raw)
To: netdev, zd1211-devs; +Cc: Ivan Seskar, Kishore Ramachandran
In-Reply-To: <43e72e890606231333kd0fc534x5d08dad955d13bf5@mail.gmail.com>
Oh and mini-PCI please :)
On 6/23/06, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
> I've mentioned this to a few but here it is out to everyone. So as you
> know we have a lot of work ahead of us for linux wireless development.
> To help speed this up, we at Winlab, would like to start hosting a
> testbed for linux wireless development, open to the public. Short term
> goals would be to start off a couple of nodes for each driver
> currently under development like bcm43xx, zd1211, rt2x00, ipw3945,
> ipw2200 and the like, and a provide a set streamlined tests we can use
> to really put to test the drivers and stacks.
>
> This wouldn't be easy if we didn't have infrastructure but we already
> do. Our grid consists of 400 nodes with 2 wireless cards each and 3
> ethernet ports (one for control) --
> http://orbit-lab.org/wiki/Tutorial/Testbed. 90% of our nodes use the
> atheros 5213 chipset and the rest ipw2200s. We'd like to expand this
> with the more wireless cards currently being worked on for linux.
>
> Right now we have zome zd1211s so we'll start with that (I'll start
> working on a port to d80211) but will try to accomodate other nodes as
> we get more wireless cards. We will need some help too though, to
> streamline the testing. If you have ideas or would like to contribute
> please let me know. We can purchase wireless cards but if you already
> have reliable confirmed wireless cards which can be used for putting
> into the testbed let me know.
>
> Luis
>
^ permalink raw reply
* Re: [PATCH REPOST 1/2] Network Event Notifier Mechanism.
From: David Miller @ 2006-06-23 20:56 UTC (permalink / raw)
To: swise; +Cc: netdev
In-Reply-To: <1151094895.7808.87.camel@stevo-desktop>
From: Steve Wise <swise@opengridcomputing.com>
Date: Fri, 23 Jun 2006 15:34:55 -0500
> But what about the redirect event? It really needs to pass two bits of
> info: The old dst_entry ptr and the new dst_entry ptr. This is needed
> so the rdma driver can figure out which connections now need to use the
> new dst_entry...
struct foo_event_data {
struct whatever a;
struct thistoo b;
};
struct foo_event_data x;
x->a = xxx;
x->b = yyy;
event->data = (void *) &x;
send_event(&event);
Why do you need typed data to do this?
^ permalink raw reply
* Re: [1/4] kevent: core files.
From: Evgeniy Polyakov @ 2006-06-23 21:08 UTC (permalink / raw)
To: Benjamin LaHaise; +Cc: David Miller, netdev
In-Reply-To: <20060623204442.GE14126@kvack.org>
On Fri, Jun 23, 2006 at 04:44:42PM -0400, Benjamin LaHaise (bcrl@kvack.org) wrote:
> > AIO completion approach was designed to be used with process context VFS
> > update. read/write approach can not cover other types of notifications,
> > like inode updates or timers.
>
> The completion event is 100% generic and does not need to come from process
> context. Calling aio_complete() from irq context is entirely valid.
put_ioctx() can sleep.
And the whole approach is different: AIO just wakes up requesting
thread, so user must provide a lot to be able to work with AIO.
It perfectly fits VFS design, but it is not acceptible for generic event
notifications.
> > Format of the structure transferred between the objects does not matter
> > at all. We can create a wrapper on kevent structures or kevent can
> > transform data from AIO objects.
>
> > The main design goal of kevent is to provide easy connected hooks into
> > any state machine, which might be used by kernelspace to notify about
> > any kind of events without any knowledge of it's background nature.
> > Kevent can be used for example as notification blocks for address
> > changes or it can replace netlink completely (it can even emulate
> > event multicasting).
> >
> > Kevent is queue of events, which can be transferred from any object to
> > any destination.
>
> And io_getevents() reads a queue of events, so I'm not sure why you need
> a new syscall.
It is not syscall, but overall design should be analyzed.
It is possible to use existing ssycalls, kevent design does not care
about how it's data structures are delivered to the internal
"processor".
> > Not at all!
> > Kevent is a mechanism, which allows to impleement AIO, network AIO, poll
> > and select, timer control, adaptive readhead (as example of AIO VFS
> > update). All the code I present shows how to use kevent, it is not part
> > of the kevent. One can find Makefile in kevent dir to check what is the
> > core of the subsystem, which allows to be used as a transport for
> > events.
> >
> > AIO, NAIO, poll/select, socket and timer notifications are just users.
> > One can add it's own usage as easy as to call kevent_storage
> > initialization function and event generation function. All other pieces
> > are hidded in the implementation.
>
> I'll look at adapting your code to use the existing syscalls. Maybe code
> will be better at expressing my concerns.
That would be great.
> -ben
--
Evgeniy Polyakov
^ permalink raw reply
* Re: [PATCH]: e1000: Janitor: Use #defined values for literals
From: Linas Vepstas @ 2006-06-23 21:12 UTC (permalink / raw)
To: Auke Kok
Cc: netdev, john.ronciak, jesse.brandeburg, jeffrey.t.kirsher,
Zhang, Yanmin, Jeff Garzik, linux-kernel
In-Reply-To: <449C49F9.6090005@intel.com>
On Fri, Jun 23, 2006 at 01:07:21PM -0700, Auke Kok wrote:
> Linas Vepstas wrote:
> >Minor janitorial patch: use #defines for literal values.
> >
> >- pci_enable_wake(pdev, 3, 0);
> >- pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
> >+ pci_enable_wake(pdev, PCI_D3hot, 0);
> >+ pci_enable_wake(pdev, PCI_D3cold, 0);
> >
> I Acked this but that's silly - the patches sent yesterday already change
> the code above and this patch is no longer needed (thanks Jesse for
> spotting this).
>
> This patch would conflict with them so please don't apply.
Oh, OK, I didn't see the patches sent yesterday, I tripped over this
on an unrelated code walk.
--linas
^ permalink raw reply
* Re: [PATCH 3/3] bcm43xx-d80211: use host_gen_beacon_template
From: Michael Buesch @ 2006-06-23 21:12 UTC (permalink / raw)
To: Jiri Benc, John W. Linville; +Cc: netdev, Alexander Tsvyashchenko
In-Reply-To: <20060623181636.6DC1C483AD@silver.suse.cz>
On Friday 23 June 2006 20:16, Jiri Benc wrote:
> Use new host_gen_beacon_template flag. This also means workaround with
> "iwconfig essid" after hostapd is run is not necessary anymore.
>
> Signed-off-by: Jiri Benc <jbenc@suse.cz>
Signed-off-by: Michael Buesch <mb@bu3sch.de>
John, please apply.
> ---
>
> drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c | 36 ++++++---------------
> 1 files changed, 11 insertions(+), 25 deletions(-)
>
> --- dscape.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
> +++ dscape/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
> @@ -1710,17 +1710,12 @@ static void bcm43xx_write_probe_resp_tem
> kfree(probe_resp_data);
> }
>
> -static int bcm43xx_refresh_cached_beacon(struct bcm43xx_private *bcm)
> +static int bcm43xx_refresh_cached_beacon(struct bcm43xx_private *bcm,
> + struct sk_buff *beacon)
> {
> - struct ieee80211_tx_control control;
> -
> if (bcm->cached_beacon)
> kfree_skb(bcm->cached_beacon);
> - bcm->cached_beacon = ieee80211_beacon_get(bcm->net_dev,
> - bcm->interface.if_id,
> - &control);
> - if (unlikely(!bcm->cached_beacon))
> - return -ENOMEM;
> + bcm->cached_beacon = beacon;
>
> return 0;
> }
> @@ -1743,16 +1738,15 @@ static void bcm43xx_update_templates(str
> bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
> }
>
> -static void bcm43xx_refresh_templates(struct bcm43xx_private *bcm)
> +static void bcm43xx_refresh_templates(struct bcm43xx_private *bcm,
> + struct sk_buff *beacon)
> {
> int err;
>
> - err = bcm43xx_refresh_cached_beacon(bcm);
> + err = bcm43xx_refresh_cached_beacon(bcm, beacon);
> if (unlikely(err))
> return;
> bcm43xx_update_templates(bcm);
> - kfree_skb(bcm->cached_beacon);
> - bcm->cached_beacon = NULL;
> }
>
> static void bcm43xx_set_ssid(struct bcm43xx_private *bcm,
> @@ -1792,19 +1786,11 @@ static void bcm43xx_set_beacon_int(struc
> static void handle_irq_beacon(struct bcm43xx_private *bcm)
> {
> u32 status;
> - int err;
>
> bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
> status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
>
> - if (!bcm->cached_beacon) {
> - err = bcm43xx_refresh_cached_beacon(bcm);
> - if (unlikely(err))
> - goto ack;
> - }
> -
> - if ((status & 0x1) && (status & 0x2)) {
> -ack:
> + if (!bcm->cached_beacon || ((status & 0x1) && (status & 0x2))) {
> /* ACK beacon IRQ. */
> bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
> BCM43xx_IRQ_BEACON);
> @@ -4382,7 +4368,6 @@ static int bcm43xx_net_config(struct net
>
> if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) {
> bcm43xx_set_beacon_int(bcm, conf->beacon_int);
> - bcm43xx_refresh_templates(bcm);
> }
>
> bcm43xx_unlock_irqonly(bcm, flags);
> @@ -4553,7 +4538,7 @@ static int bcm43xx_add_interface(struct
> if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
> bcm43xx_select_opmode(bcm);
> if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP))
> - bcm43xx_refresh_templates(bcm);
> + bcm43xx_refresh_templates(bcm, NULL);
> }
> err = 0;
>
> @@ -4606,7 +4591,8 @@ static int bcm43xx_config_interface(stru
> if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) {
> assert(conf->type == IEEE80211_IF_TYPE_AP);
> bcm43xx_set_ssid(bcm, conf->ssid, conf->ssid_len);
> - bcm43xx_refresh_templates(bcm);
> + if (conf->beacon)
> + bcm43xx_refresh_templates(bcm, conf->beacon);
> }
> }
> bcm43xx_unlock_irqsafe(bcm, flags);
> @@ -4701,7 +4687,7 @@ static int __devinit bcm43xx_init_one(st
> goto out;
> ieee->version = IEEE80211_VERSION;
> ieee->name = KBUILD_MODNAME;
> - ieee->host_gen_beacon = 1;
> + ieee->host_gen_beacon_template = 1;
> ieee->rx_includes_fcs = 1;
> ieee->monitor_during_oper = 1;
> ieee->tx = bcm43xx_net_hard_start_xmit;
>
--
Greetings Michael.
^ permalink raw reply
* Re: hostapd patch for d80211
From: Michael Buesch @ 2006-06-23 21:13 UTC (permalink / raw)
To: Jiri Benc
Cc: bcm43xx-dev, netdev, Alexander Tsvyashchenko, Francois Barre,
Jouni Malinen
In-Reply-To: <20060623201933.59578ecc@griffin.suse.cz>
On Friday 23 June 2006 20:19, Jiri Benc wrote:
> On Mon, 19 Jun 2006 11:07:34 +0200, Michael Buesch wrote:
> > Important notes from Alexander Tsvyashchenko's initial mail follow:
> > [...]
> > Although my previous patch to hostapd to make it interoperable with
> > bcm43xx & dscape has been merged already in their CVS version, due to
> > the subsequent changes in dscape stack current hostapd is again
> > incompartible :-(
>
> This patch allows devicescape driver in hostapd to work with recent d80211.
> No manipulation with network interfaces is needed anymore - hostapd even
> switches the interface to AP mode automatically now. Just modprobe
> bcm43xx-d80211, run hostapd and enjoy :-)
>
> Signed-off-by: Jiri Benc <jbenc@suse.cz>
Well, if it works.... Jouni, please apply.
I did not test it. But I trust Jiri. If he says it works, then
it does work :)
> ---
>
> driver_devicescape.c | 77 ++++++++++++++++++++++++++++++++++++++++++---------
> 1 files changed, 64 insertions(+), 13 deletions(-)
>
> --- hostapd-0.5-2006-06-19.orig/driver_devicescape.c
> +++ hostapd-0.5-2006-06-19/driver_devicescape.c
> @@ -73,6 +73,7 @@ struct i802_driver_data {
>
> char iface[IFNAMSIZ + 1];
> char mgmt_iface[IFNAMSIZ + 1];
> + int mgmt_ifindex;
> int sock; /* raw packet socket for driver access */
> int ioctl_sock; /* socket for ioctl() use */
> int wext_sock; /* socket for wireless events */
> @@ -88,6 +89,21 @@ static const struct driver_ops devicesca
> static int i802_sta_set_flags(void *priv, const u8 *addr,
> int flags_or, int flags_and);
>
> +static int i802_set_ap_mode(struct i802_driver_data *drv)
> +{
> + struct iwreq iwr;
> +
> + memset(&iwr, 0, sizeof(iwr));
> + strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
> + iwr.u.mode = IW_MODE_MASTER;
> +
> + if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
> + perror("ioctl[SIOCSIWMODE]");
> + return -1;
> + }
> +
> + return 0;
> +}
>
> static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up)
> {
> @@ -96,13 +112,16 @@ static int hostapd_set_iface_flags(struc
> if (drv->ioctl_sock < 0)
> return -1;
>
> + if (dev_up)
> + i802_set_ap_mode(drv);
> +
> memset(&ifr, 0, sizeof(ifr));
> - snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->mgmt_iface);
> + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->iface);
>
> if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
> perror("ioctl[SIOCGIFFLAGS]");
> wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)",
> - drv->mgmt_iface);
> + drv->iface);
> return -1;
> }
>
> @@ -303,7 +322,35 @@ static int hostap_ioctl_prism2param(stru
> return hostap_ioctl_prism2param_iface(drv->iface, drv, param, value);
> }
>
> -
> +static int hostap_ioctl_get_prism2param_iface(const char *iface,
> + struct i802_driver_data *drv,
> + int param)
> +{
> + struct iwreq iwr;
> + int *i;
> +
> + memset(&iwr, 0, sizeof(iwr));
> + strncpy(iwr.ifr_name, iface, IFNAMSIZ);
> + i = (int *) iwr.u.name;
> + *i = param;
> +
> + if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_GET_PRISM2_PARAM, &iwr) < 0) {
> + char buf[128];
> + snprintf(buf, sizeof(buf),
> + "%s: ioctl[PRISM2_IOCTL_GET_PRISM2_PARAM]", iface);
> + perror(buf);
> + return -1;
> + }
> +
> + return *i;
> +}
> +
> +static int hostap_ioctl_get_prism2param(struct i802_driver_data *drv,
> + int param)
> +{
> + return hostap_ioctl_get_prism2param_iface(drv->iface, drv, param);
> +}
> +
> static int i802_set_ssid(void *priv, const u8 *buf, int len)
> {
> struct i802_driver_data *drv = priv;
> @@ -1338,12 +1385,20 @@ static int i802_init_sockets(struct i802
> return -1;
> }
>
> + /* Enable management interface */
> + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 1) < 0)
> + return -1;
> + drv->mgmt_ifindex =
> + hostap_ioctl_get_prism2param(drv, PRISM2_PARAM_MGMT_IF);
> + if (drv->mgmt_ifindex < 0)
> + return -1;
> memset(&ifr, 0, sizeof(ifr));
> - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", drv->mgmt_iface);
> - if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
> - perror("ioctl(SIOCGIFINDEX)");
> + ifr.ifr_ifindex = drv->mgmt_ifindex;
> + if (ioctl(drv->ioctl_sock, SIOCGIFNAME, &ifr) != 0) {
> + perror("ioctl(SIOCGIFNAME)");
> return -1;
> }
> + snprintf(drv->mgmt_iface, sizeof(drv->mgmt_iface), "%s", ifr.ifr_name);
>
> if (hostapd_set_iface_flags(drv, 1))
> return -1;
> @@ -1716,13 +1771,6 @@ static int i802_init(struct hostapd_data
> drv->ops = devicescape_driver_ops;
> drv->hapd = hapd;
> memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
> - if (strncmp(hapd->conf->iface, "wlan", 4) == 0) {
> - snprintf(drv->mgmt_iface, sizeof(drv->mgmt_iface),
> - "wmaster%sap", hapd->conf->iface + 4);
> - } else {
> - snprintf(drv->mgmt_iface, sizeof(drv->mgmt_iface),
> - "%sap", hapd->conf->iface);
> - }
>
> if (i802_init_sockets(drv))
> goto failed;
> @@ -1751,6 +1799,9 @@ static void i802_deinit(void *priv)
>
> (void) hostapd_set_iface_flags(drv, 0);
>
> + /* Disable management interface */
> + hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 0);
> +
> if (drv->sock >= 0)
> close(drv->sock);
> if (drv->ioctl_sock >= 0)
>
>
--
Greetings Michael.
^ permalink raw reply
* RE: New Qlogic qla3xxx NIC Driver v2.02.00k34 for upstream inclusion
From: Ron Mercer @ 2006-06-23 21:23 UTC (permalink / raw)
To: netdev; +Cc: linux-driver
> 9) [minor] "N/A" appears to be an inaccurate value for fw_version in
> ql_get_drvinfo()
Does anyone know what would be appropriate for this ethtool command? My
device does not use firmware. I took the "N/A" idea from e1000 and
skge.
^ permalink raw reply
* [PATCH] smc91x: disable DMA mode on the logicpd pxa270
From: Lennert Buytenhek @ 2006-06-23 21:24 UTC (permalink / raw)
To: jgarzik, netdev; +Cc: nico, mikee, peterb
Enabling PXA DMA for the smc91x on the logicpd pxa270 produces
unacceptable interference with the TFT panel, so disable it. Also
delete the lpd270 versions of the SMC_{in,out}[bl]() macros, as they
aren't used, since the board only supports 16bit accesses.
Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Index: linux-2.6.17-git5/drivers/net/smc91x.h
===================================================================
--- linux-2.6.17-git5.orig/drivers/net/smc91x.h
+++ linux-2.6.17-git5/drivers/net/smc91x.h
@@ -136,14 +136,9 @@
#define SMC_CAN_USE_32BIT 0
#define SMC_IO_SHIFT 0
#define SMC_NOWAIT 1
-#define SMC_USE_PXA_DMA 1
-#define SMC_inb(a, r) readb((a) + (r))
#define SMC_inw(a, r) readw((a) + (r))
-#define SMC_inl(a, r) readl((a) + (r))
-#define SMC_outb(v, a, r) writeb(v, (a) + (r))
#define SMC_outw(v, a, r) writew(v, (a) + (r))
-#define SMC_outl(v, a, r) writel(v, (a) + (r))
#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
^ permalink raw reply
* Re: [3/5] [NET]: Add software TSOv4
From: Michael Chan @ 2006-06-23 21:26 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, netdev
In-Reply-To: <1151091230.6498.4.camel@rh4>
On Fri, 2006-06-23 at 12:33 -0700, Michael Chan wrote:
> On Thu, 2006-06-22 at 18:14 +1000, Herbert Xu wrote:
> > [NET]: Add software TSOv4
> >
> > This patch adds the GSO implementation for IPv4 TCP.
>
> Herbert, Looks like there were some problems in the CHECKSUM_HW case.
> This patch should fix it. Please double-check my checksum math.
This patch is more correct. Please ignore the previous one.
[NET]: Fix CHECKSUM_HW GSO problems.
Fix checksum problems in the GSO code path for CHECKSUM_HW packets.
The ipv4 TCP pseudo header checksum has to be adjusted for GSO
segmented packets.
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0e029c4..b9c37f1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2186,7 +2186,8 @@ struct sk_buff *tcp_tso_segment(struct s
if (skb->ip_summed == CHECKSUM_NONE) {
th->check = csum_fold(csum_partial(
skb->h.raw, thlen, csum_add(skb->csum, delta)));
- }
+ } else if (skb->ip_summed == CHECKSUM_HW)
+ th->check = ~csum_fold(csum_add(th->check, delta));
seq += len;
skb = skb->next;
@@ -2200,6 +2201,10 @@ struct sk_buff *tcp_tso_segment(struct s
delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw));
th->check = csum_fold(csum_partial(
skb->h.raw, thlen, csum_add(skb->csum, delta)));
+ } else if (skb->ip_summed == CHECKSUM_HW) {
+ delta = csum_add(oldlen, htonl(skb->len -
+ (skb->h.raw - skb->data)));
+ th->check = ~csum_fold(csum_add(th->check, delta));
}
out:
^ permalink raw reply related
* Re: [RFC PATCH 1/2] Hardware button support for Wireless cards: radiobtn
From: Ivo van Doorn @ 2006-06-23 21:35 UTC (permalink / raw)
To: Vojtech Pavlik; +Cc: Jiri Benc, Stefan Rompf, Francois Romieu, netdev
In-Reply-To: <20060623193246.GC6270@suse.cz>
[-- Attachment #1: Type: text/plain, Size: 4276 bytes --]
> > So basicly 1 input device for every single wireless driver that implements
> > the RF-Kill button?
>
> Yes.
>
> > Is there any particular reason for not using 1 input device shared by all?
>
> Yes.
>
> In the unlikely case where there are two devices which implement a
> rfkill button in the system, the input core doesn't have a way how to
> express the state of these two different buttons with the same meaning
> (and hence the same code - KEY_RFKILL) in a single input device.
>
> You'd have to assign a range of codes to the shared device, which goes
> agains the design of the Linux inpu layer.
>
> Anyway, for the most common case, where you have a single RF-Kill key in
> the whole system, there will not be any difference to using the shared
> device.
>
> What do you consider the benefits of using a shared input device?
Well it is a matter of preference, especially on how this rfkill.ko would
be implemented. When the user has 2 buttons, should all radios
(wifi, bluetooth etc) be switched off by pressing each individual key
or just 1 key to switch off everything.
But now that I am further thinking about this, (and looking on how
my laptop currently works with 1 wifi button and 1 bluetooth button)
perhaps multiple input devices would indeed be best.
userspace can decide if more interfaces should be attached to the button
or not. And this would be the preferred situation.
> > Userspace could switch off the radio by using the txpower ioctl of
> > ifdown/ifup. Or should an approach call be implemented?
>
> I'm an input guy, the details of how to disable the radio I'll leave up
> to you - the WiFi folks on netdev.
:)
> You may want to consider that the radio chip usually synthesizes a
> frequency that it mixes with the incoming signal to frequency-shift it
> to a low frequency which then can be demodulated. Because of that, even
> the receiver, when working, can affect devices nearby. This is why FM
> radio receivers are not allowed on airplanes.
>
> Hardware RF-Kill disables both RX and TX, by stopping the radio chip.
> Setting TX power to an extremely low value might not be the same.
>
> On the other hand, you may define in the API that setting TX power to
> zero also disables the receiver.
ok, no need for new ioctl calls in that case I believe.
Using the txpower the radio can be switched on and off, without giving a low or 0 as value.
But the decision to use ifup and ifdown or iwconfig txpower on/off could be done later,
since it can handled in user space.
> > > 3) ACPI buttons drivers, and keyboard drivers will generate KEY_RFKILL
> > > on machines where RF-Kill keys are reported using ACPI events or
> > > keyboard scancodes.
> >
> > Why both an input and ACPI event?
> > With ACPI restricted to x86 only, wouldn't a more generic approach be desired?
>
> I was talking about the ACPI EC sending us an event. This is how are
> ACPI buttons implemented in certain notebooks. I definitely don't want
> to use the acpi events as received by acpid now as the interface. Sorry
> for the confusion.
ah ok. :)
> > > 3) A rfkill.ko input handler module will be implemented, that listens to
> > > the SW_RFKILL and KEY_RFKILL events from all devices in the system, and
> > > will enable/disable radios on all 802.11 devices in the system.
> > >
> > > The above will make the RF-Kill button work under all real scenarios as
> > > user expects - it will enable/disable the radio. In the case where a
> > > user has an additional PCMCIA card, both the radios will be disabled by
> > > presing the RF-Kill button, which is arguably what the user expects.
> > > Even BlueTooth or other RF technologies (CDMA, EDGE) can hook into this
> > > mechanism.
> > >
> > > 4) When userspace wants to take over the control over RF-Kill, and start
> > > additional services based on that, it can open the input devices to get
> > > the state of the buttons/switches, AND it can issue the EVIOCGRAB
> > > ioctl() to prevent the rfkill.ko and any other handlers from getting the
> > > events.
> > >
> > > This allows simple implementation of dbus notifications and
> > > NetworkManager-style configuration of network interfaces.
>
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [RFT PATCH] pcnet32: NAPI support
From: Don Fry @ 2006-06-23 21:32 UTC (permalink / raw)
To: lsorense, netdev
This set of changes combines the work done by Len Sorensen and myself to
add compile time support for NAPI for the pcnet32 driver. I have tested
it on ia32 and ppc64 hardware with various versions of the pcnet32
adapter. I have also made a few changes requested by Jon Mason, but the
substitution of the many magic numbers in the driver is not yet done.
If no-one encounters any problems when testing this, I will break up the
several changes, into proper patches and submit them next week.
Signed-off-by: Don Fry <brazilnut@us.ibm.com>
--- linux-2.6.17/drivers/net/orig.Kconfig 2006-06-15 11:49:39.000000000 -0700
+++ linux-2.6.17/drivers/net/Kconfig 2006-06-22 15:44:52.000000000 -0700
@@ -1272,6 +1272,23 @@ config PCNET32
<file:Documentation/networking/net-modules.txt>. The module
will be called pcnet32.
+config PCNET32_NAPI
+ bool "Use RX polling (NAPI) (EXPERIMENTAL)"
+ depends on PCNET32 && EXPERIMENTAL
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
+
config AMD8111_ETH
tristate "AMD 8111 (new PCI lance) support"
depends on NET_PCI && PCI
--- linux-2.6.17/drivers/net/orig.pcnet32.c Sat Jun 17 18:49:35 2006
+++ linux-2.6.17/drivers/net/pcnet32.c Fri Jun 23 13:13:02 2006
@@ -21,9 +21,15 @@
*
*************************************************************************/
+#include <linux/config.h>
+
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.32"
-#define DRV_RELDATE "18.Mar.2006"
+#ifdef CONFIG_PCNET32_NAPI
+#define DRV_VERSION "1.33-NAPI"
+#else
+#define DRV_VERSION "1.33"
+#endif
+#define DRV_RELDATE "23.Jun.2006"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -58,18 +64,15 @@ static const char *const version =
* PCI device identifiers for "new style" Linux PCI Device Drivers
*/
static struct pci_device_id pcnet32_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
/*
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
* the incorrect vendor id.
*/
- { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
{ } /* terminate list */
};
@@ -277,13 +280,14 @@ struct pcnet32_private {
u32 phymask;
};
-static void pcnet32_probe_vlbus(void);
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
-static int pcnet32_rx(struct net_device *);
+#ifdef CONFIG_PCNET32_NAPI
+static int pcnet32_poll(struct net_device *dev, int *budget);
+#endif
static void pcnet32_tx_timeout(struct net_device *dev);
static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
static int pcnet32_close(struct net_device *);
@@ -425,6 +429,235 @@ static struct pcnet32_access pcnet32_dwi
.reset = pcnet32_dwio_reset
};
+static void pcnet32_netif_stop(struct net_device *dev)
+{
+ dev->trans_start = jiffies;
+ netif_poll_disable(dev);
+ netif_tx_disable(dev);
+}
+
+static void pcnet32_netif_start(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ netif_poll_enable(dev);
+}
+
+/*
+ * Allocate space for the new sized tx ring.
+ * Free old resources
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_tx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_tx_head *new_tx_ring;
+ struct sk_buff **new_skb_list;
+
+ pcnet32_purge_tx_ring(dev);
+
+ new_tx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_tx_ring == NULL) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk("\n" KERN_ERR PFX
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc(sizeof(dma_addr_t), (1 << size), GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk("\n" KERN_ERR PFX
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_tx_ring;
+ }
+
+ new_skb_list = kcalloc(sizeof(struct sk_buff *), (1 << size), GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk("\n" KERN_ERR PFX
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ kfree(lp->tx_skbuff);
+ kfree(lp->tx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ lp->tx_ring_size, lp->tx_ring,
+ lp->tx_ring_dma_addr);
+
+ lp->tx_ring_size = (1 << size);
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->tx_len_bits = (size << 12);
+ lp->tx_ring = new_tx_ring;
+ lp->tx_ring_dma_addr = new_ring_dma_addr;
+ lp->tx_dma_addr = new_dma_addr_list;
+ lp->tx_skbuff = new_skb_list;
+ return;
+
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_tx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ new_tx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+/*
+ * Allocate space for the new sized rx ring.
+ * Re-use old receive buffers.
+ * alloc extra buffers
+ * free unneeded buffers
+ * free unneeded buffers
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_rx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_rx_head *new_rx_ring;
+ struct sk_buff **new_skb_list;
+ int new, overlap;
+
+ new_rx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_rx_ring == NULL) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk("\n" KERN_ERR PFX
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc(sizeof(dma_addr_t), (1 << size), GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk("\n" KERN_ERR PFX
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_rx_ring;
+ }
+
+ new_skb_list = kcalloc(sizeof(struct sk_buff *), (1 << size), GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk("\n" KERN_ERR PFX
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ /* first copy the current receive buffers */
+ overlap = min(size, lp->rx_ring_size);
+ for (new = 0; new < overlap; new++) {
+ new_rx_ring[new] = lp->rx_ring[new];
+ new_dma_addr_list[new] = lp->rx_dma_addr[new];
+ new_skb_list[new] = lp->rx_skbuff[new];
+ }
+ /* now allocate any new buffers needed */
+ for (; new < size; new++ ) {
+ struct sk_buff *rx_skbuff;
+ new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
+ if (!(rx_skbuff = new_skb_list[new])) {
+ /* keep the original lists and buffers */
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
+ dev->name);
+ goto free_all_new;
+ }
+ skb_reserve(rx_skbuff, 2);
+
+ new_dma_addr_list[new] =
+ pci_map_single(lp->pci_dev, rx_skbuff->data,
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = le16_to_cpu(0x8000);
+ }
+ /* and free any unneeded buffers */
+ for (; new < lp->rx_ring_size; new++) {
+ if (lp->rx_skbuff[new]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_skbuff[new]);
+ }
+ }
+
+ kfree(lp->rx_skbuff);
+ kfree(lp->rx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ lp->rx_ring_size, lp->rx_ring,
+ lp->rx_ring_dma_addr);
+
+ lp->rx_ring_size = (1 << size);
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->rx_len_bits = (size << 4);
+ lp->rx_ring = new_rx_ring;
+ lp->rx_ring_dma_addr = new_ring_dma_addr;
+ lp->rx_dma_addr = new_dma_addr_list;
+ lp->rx_skbuff = new_skb_list;
+ return;
+
+ free_all_new:
+ for (; --new >= lp->rx_ring_size; ) {
+ if (new_skb_list[new]) {
+ pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(new_skb_list[new]);
+ }
+ }
+ kfree(new_skb_list);
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_rx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ new_rx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int i;
+
+ /* free all allocated skbuffs */
+ for (i = 0; i < lp->rx_ring_size; i++) {
+ lp->rx_ring[i].status = 0; /* CPU owns buffer */
+ wmb(); /* Make sure adapter sees owner change */
+ if (lp->rx_skbuff[i]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(lp->rx_skbuff[i]);
+ }
+ lp->rx_skbuff[i] = NULL;
+ lp->rx_dma_addr[i] = 0;
+ }
+}
+
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@@ -525,10 +758,10 @@ static void pcnet32_get_ringparam(struct
{
struct pcnet32_private *lp = dev->priv;
- ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
- ering->tx_pending = lp->tx_ring_size - 1;
- ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
- ering->rx_pending = lp->rx_ring_size - 1;
+ ering->tx_max_pending = TX_MAX_RING_SIZE;
+ ering->tx_pending = lp->tx_ring_size;
+ ering->rx_max_pending = RX_MAX_RING_SIZE;
+ ering->rx_pending = lp->rx_ring_size;
}
static int pcnet32_set_ringparam(struct net_device *dev,
@@ -536,44 +769,44 @@ static int pcnet32_set_ringparam(struct
{
struct pcnet32_private *lp = dev->priv;
unsigned long flags;
+ unsigned int size;
+ ulong ioaddr = dev->base_addr;
int i;
if (ering->rx_mini_pending || ering->rx_jumbo_pending)
return -EINVAL;
if (netif_running(dev))
- pcnet32_close(dev);
+ pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- pcnet32_free_ring(dev);
- lp->tx_ring_size =
- min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
- lp->rx_ring_size =
- min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+ lp->a.write_csr(ioaddr, 0, 0x0004); /* stop the chip */
+
+ size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
/* set the minimum ring size to 4, to allow the loopback test to work
* unchanged.
*/
for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
- if (lp->tx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->tx_ring_size = (1 << i);
- lp->tx_mod_mask = lp->tx_ring_size - 1;
- lp->tx_len_bits = (i << 12);
-
+ if ((1 << i) != lp->tx_ring_size)
+ pcnet32_realloc_tx_ring(dev, lp, i);
+
+ size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
- if (lp->rx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->rx_ring_size = (1 << i);
- lp->rx_mod_mask = lp->rx_ring_size - 1;
- lp->rx_len_bits = (i << 4);
+ if ((1 << i) != lp->rx_ring_size)
+ pcnet32_realloc_rx_ring(dev, lp, i);
+
+ dev->weight = lp->rx_ring_size / 2;
- if (pcnet32_alloc_ring(dev, dev->name)) {
- pcnet32_free_ring(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- return -ENOMEM;
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, 0x0042);
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -583,9 +816,6 @@ static int pcnet32_set_ringparam(struct
"%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
lp->rx_ring_size, lp->tx_ring_size);
- if (netif_running(dev))
- pcnet32_open(dev);
-
return 0;
}
@@ -639,25 +869,27 @@ static int pcnet32_loopback_test(struct
unsigned long flags;
unsigned long ticks;
- *data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
if (netif_running(dev))
+#ifdef CONFIG_PCNET32_NAPI
+ pcnet32_netif_stop(dev);
+#else
pcnet32_close(dev);
+#endif
spin_lock_irqsave(&lp->lock, flags);
+ lp->a.write_csr(ioaddr, 0, 0x0004); /* stop the chip */
+
+ numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, 4, 0x0915);
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
- lp->init_block.mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->init_block.filter[0] = 0;
- lp->init_block.filter[1] = 0;
-
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
@@ -704,10 +936,10 @@ static int pcnet32_loopback_test(struct
}
x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
- x = x | 0x0002;
- a->write_bcr(ioaddr, 32, x);
+ a->write_bcr(ioaddr, 32, x | 0x0002);
- lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
+ x = a->read_csr(ioaddr, 15); /* set int loopback in CSR15 */
+ lp->a.write_csr(ioaddr, 15, x | 0x0044);
teststatus = le16_to_cpu(0x8000);
lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
@@ -764,25 +996,30 @@ static int pcnet32_loopback_test(struct
}
x++;
}
- if (!rc) {
- *data1 = 0;
- }
clean_up:
+ *data1 = rc;
pcnet32_purge_tx_ring(dev);
+
x = a->read_csr(ioaddr, 15) & 0xFFFF;
a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
- x = x & ~0x0002;
- a->write_bcr(ioaddr, 32, x);
-
- spin_unlock_irqrestore(&lp->lock, flags);
+ a->write_bcr(ioaddr, 32, (x & ~0x0002));
if (netif_running(dev)) {
+#ifdef CONFIG_PCNET32_NAPI
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, 0x0042);
+ spin_unlock_irqrestore(&lp->lock, flags);
+#else
+ spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
+#endif
} else {
+ pcnet32_purge_rx_ring(dev);
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ spin_unlock_irqrestore(&lp->lock, flags);
}
return (rc);
@@ -845,6 +1082,39 @@ static int pcnet32_phys_id(struct net_de
return 0;
}
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags)
+{
+ int csr5;
+ struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_access *a = &lp->a;
+ ulong ioaddr = dev->base_addr;
+ int ticks;
+
+ /* set SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = a->read_csr(ioaddr, 5);
+ a->write_csr(ioaddr, 5, csr5 | 0x0001);
+
+ /* poll waiting for bit to be set */
+ ticks = 0;
+ while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
+ spin_unlock_irqrestore(&lp->lock, *flags);
+ mdelay(1);
+ spin_lock_irqsave(&lp->lock, *flags);
+ ticks++;
+ if (ticks > 200) {
+ if (netif_msg_hw(lp))
+ printk(KERN_DEBUG
+ "%s: Error getting into suspend!\n",
+ dev->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
@@ -863,31 +1133,17 @@ static void pcnet32_get_regs(struct net_
struct pcnet32_private *lp = dev->priv;
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
- int ticks;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
csr0 = a->read_csr(ioaddr, 0);
if (!(csr0 & 0x0004)) { /* If not stopped */
- /* set SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0001);
-
- /* poll waiting for bit to be set */
- ticks = 0;
- while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
- spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
- spin_lock_irqsave(&lp->lock, flags);
- ticks++;
- if (ticks > 200) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error getting into suspend!\n",
- dev->name);
- break;
- }
- }
+ if (!pcnet32_suspend(dev, &flags))
+ if (netif_msg_hw(lp))
+ printk(KERN_DEBUG
+ "%s: Error getting into suspend!\n",
+ dev->name);
}
/* read address PROM */
@@ -926,8 +1182,11 @@ static void pcnet32_get_regs(struct net_
}
if (!(csr0 & 0x0004)) { /* If not stopped */
+ int csr5;
+
/* clear SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0000);
+ csr5 = a->read_csr(ioaddr, 5);
+ a->write_csr(ioaddr, 5, csr5 & (~0x0001));
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -958,7 +1217,7 @@ static struct ethtool_ops pcnet32_ethtoo
/* only probes for non-PCI devices, the rest are handled by
* pci_register_driver via pcnet32_probe_pci */
-static void __devinit pcnet32_probe_vlbus(void)
+static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
{
unsigned int *port, ioaddr;
@@ -1396,6 +1655,10 @@ pcnet32_probe1(unsigned long ioaddr, int
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
+ dev->weight = lp->rx_ring_size / 2;
+#ifdef CONFIG_PCNET32_NAPI
+ dev->poll = pcnet32_poll;
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -1763,16 +2026,7 @@ static int pcnet32_open(struct net_devic
err_free_ring:
/* free any allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -2004,6 +2258,286 @@ static int pcnet32_start_xmit(struct sk_
return 0;
}
+static int pcnet32_rx_entry(struct net_device *dev,
+ struct pcnet32_private *lp,
+ struct pcnet32_rx_head *rxp,
+ int entry)
+{
+ int status = (short)le16_to_cpu(rxp->status) >> 8;
+ int rx_in_place = 0;
+ struct sk_buff *skb;
+ short pkt_len;
+
+ if (status != 0x03) { /* There was an error. */
+ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf@perftech.com> to Russ Nelson: Even with full-sized
+ * buffers it's possible for a jabber packet to use two
+ * buffers, with only the last correctly noting the error.
+ */
+ if (status & 0x01) /* Only count a general error at the */
+ lp->stats.rx_errors++; /* end of a packet. */
+ if (status & 0x20)
+ lp->stats.rx_frame_errors++;
+ if (status & 0x10)
+ lp->stats.rx_over_errors++;
+ if (status & 0x08)
+ lp->stats.rx_crc_errors++;
+ if (status & 0x04)
+ lp->stats.rx_fifo_errors++;
+ return 1;
+ }
+
+ pkt_len = (le32_to_cpu(rxp->msg_length) & 0xfff) - 4;
+
+ /* Discard oversize frames. */
+ if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR "%s: Impossible packet size %d!\n",
+ dev->name, pkt_len);
+ lp->stats.rx_errors++;
+ return 1;
+ }
+ if (pkt_len < 60) {
+ if (netif_msg_rx_err(lp))
+ printk(KERN_ERR "%s: Runt packet!\n", dev->name);
+ lp->stats.rx_errors++;
+ return 1;
+ }
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+
+ if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {
+ skb_reserve(newskb, 2);
+ skb = lp->rx_skbuff[entry];
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ skb_put(skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ lp->rx_dma_addr[entry] =
+ pci_map_single(lp->pci_dev,
+ newskb->data,
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
+ rx_in_place = 1;
+ } else
+ skb = NULL;
+ } else {
+ skb = dev_alloc_skb(pkt_len + 2);
+ }
+
+ if (skb == NULL) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ return 1;
+ }
+ skb->dev = dev;
+ if (!rx_in_place) {
+ skb_reserve(skb, 2); /* 16 byte align */
+ skb_put(skb, pkt_len); /* Make room */
+ pci_dma_sync_single_for_cpu(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ eth_copy_and_sum(skb,
+ (unsigned char *)(lp->rx_skbuff[entry]->data),
+ pkt_len, 0);
+ pci_dma_sync_single_for_device(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ }
+ lp->stats.rx_bytes += skb->len;
+ lp->stats.rx_packets++;
+ skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_PCNET32_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
+ return 1;
+}
+
+static int pcnet32_rx(struct net_device *dev, int quota)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int entry = lp->cur_rx & lp->rx_mod_mask;
+ struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
+ int npackets = 0;
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
+ npackets += pcnet32_rx_entry(dev, lp, rxp, entry);
+//printk("DONF: %s npackets=%d\n", dev->name, npackets);
+ /*
+ * The docs say that the buffer length isn't touched, but Andrew
+ * Boyd of QNX reports that some revs of the 79C965 clear it.
+ */
+ rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ wmb(); /* Make sure owner changes after others are visible */
+ rxp->status = le16_to_cpu(0x8000);
+ entry = (++lp->cur_rx) & lp->rx_mod_mask;
+ rxp = &lp->rx_ring[entry];
+ }
+
+ return npackets;
+}
+
+static int pcnet32_tx(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ unsigned int dirty_tx = lp->dirty_tx;
+ int delta;
+ int must_restart = 0;
+
+ while (dirty_tx != lp->cur_tx) {
+ int entry = dirty_tx & lp->tx_mod_mask;
+ int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+
+ if (status < 0)
+ break; /* It still hasn't been Txed */
+
+ lp->tx_ring[entry].base = 0;
+
+ if (status & 0x4000) {
+ /* There was an major error, log it. */
+ int err_status =
+ le32_to_cpu(lp->tx_ring[entry].
+ misc);
+ lp->stats.tx_errors++;
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx error status=%04x err_status=%08x\n",
+ dev->name, status,
+ err_status);
+ if (err_status & 0x04000000)
+ lp->stats.tx_aborted_errors++;
+ if (err_status & 0x08000000)
+ lp->stats.tx_carrier_errors++;
+ if (err_status & 0x10000000)
+ lp->stats.tx_window_errors++;
+#ifndef DO_DXSUFLO
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx FIFO error!\n",
+ dev->name);
+ must_restart = 1;
+ }
+#else
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
+ if (!lp->dxsuflo) { /* If controller doesn't recover ... */
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx FIFO error!\n",
+ dev->name);
+ must_restart = 1;
+ }
+ }
+#endif
+ } else {
+ if (status & 0x1800)
+ lp->stats.collisions++;
+ lp->stats.tx_packets++;
+ }
+
+ /* We must free the original skb */
+ if (lp->tx_skbuff[entry]) {
+ pci_unmap_single(lp->pci_dev,
+ lp->tx_dma_addr[entry],
+ lp->tx_skbuff[entry]->
+ len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(lp->tx_skbuff[entry]);
+ lp->tx_skbuff[entry] = NULL;
+ lp->tx_dma_addr[entry] = 0;
+ }
+ dirty_tx++;
+ }
+
+ delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);
+ if (delta > lp->tx_ring_size) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, lp->cur_tx,
+ lp->tx_full);
+ dirty_tx += lp->tx_ring_size;
+ delta -= lp->tx_ring_size;
+ }
+
+ if (lp->tx_full &&
+ netif_queue_stopped(dev) &&
+ delta < lp->tx_ring_size - 2) {
+ /* The ring is no longer full, clear tbusy. */
+ lp->tx_full = 0;
+ netif_wake_queue(dev);
+ }
+ lp->dirty_tx = dirty_tx;
+
+ return must_restart;
+}
+
+#ifdef CONFIG_PCNET32_NAPI
+static int pcnet32_poll(struct net_device *dev, int *budget)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int quota = min(dev->quota, *budget);
+ unsigned long ioaddr = dev->base_addr;
+ u16 val;
+ unsigned long flags;
+
+ quota = pcnet32_rx(dev, quota);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ if (pcnet32_tx(dev)) {
+ /* reset the chip to clear the error condition, then restart */
+ lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, 4, 0x0915);
+ pcnet32_restart(dev, 0x0002);
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ *budget -= quota;
+ dev->quota -= quota;
+
+ if (dev->quota == 0) {
+ return 1;
+ }
+
+ netif_rx_complete(dev);
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /* clear interrupt masks */
+ val = lp->a.read_csr(ioaddr, 3);
+ val &= 0x00ff;
+ lp->a.write_csr(ioaddr, 3, val);
+
+ /* Set interrupt enable. */
+ lp->a.write_csr(ioaddr, 0, 0x0040);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+}
+#endif
+
/* The PCNET32 interrupt handler. */
static irqreturn_t
pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2011,9 +2545,9 @@ pcnet32_interrupt(int irq, void *dev_id,
struct net_device *dev = dev_id;
struct pcnet32_private *lp;
unsigned long ioaddr;
- u16 csr0, rap;
int boguscnt = max_interrupt_work;
- int must_restart;
+ u16 csr0;
+ irqreturn_t rc = IRQ_HANDLED;
if (!dev) {
if (pcnet32_debug & NETIF_MSG_INTR)
@@ -2027,141 +2561,33 @@ pcnet32_interrupt(int irq, void *dev_id,
spin_lock(&lp->lock);
- rap = lp->a.read_rap(ioaddr);
- while ((csr0 = lp->a.read_csr(ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) {
- if (csr0 == 0xffff) {
- break; /* PCMCIA remove happened */
- }
+ csr0 = lp->a.read_csr(ioaddr, 0);
+ if (csr0 == 0xffff) {
+ rc = IRQ_NONE;
+ } else while (csr0 & 0x8f00 && --boguscnt >= 0) {
/* Acknowledge all of the current interrupt sources ASAP. */
lp->a.write_csr(ioaddr, 0, csr0 & ~0x004f);
- must_restart = 0;
-
if (netif_msg_intr(lp))
printk(KERN_DEBUG
"%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
dev->name, csr0, lp->a.read_csr(ioaddr, 0));
- if (csr0 & 0x0400) /* Rx interrupt */
- pcnet32_rx(dev);
-
- if (csr0 & 0x0200) { /* Tx-done interrupt */
- unsigned int dirty_tx = lp->dirty_tx;
- int delta;
-
- while (dirty_tx != lp->cur_tx) {
- int entry = dirty_tx & lp->tx_mod_mask;
- int status =
- (short)le16_to_cpu(lp->tx_ring[entry].
- status);
-
- if (status < 0)
- break; /* It still hasn't been Txed */
-
- lp->tx_ring[entry].base = 0;
-
- if (status & 0x4000) {
- /* There was an major error, log it. */
- int err_status =
- le32_to_cpu(lp->tx_ring[entry].
- misc);
- lp->stats.tx_errors++;
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx error status=%04x err_status=%08x\n",
- dev->name, status,
- err_status);
- if (err_status & 0x04000000)
- lp->stats.tx_aborted_errors++;
- if (err_status & 0x08000000)
- lp->stats.tx_carrier_errors++;
- if (err_status & 0x10000000)
- lp->stats.tx_window_errors++;
-#ifndef DO_DXSUFLO
- if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
- /* Ackk! On FIFO errors the Tx unit is turned off! */
- /* Remove this verbosity later! */
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx FIFO error! CSR0=%4.4x\n",
- dev->name, csr0);
- must_restart = 1;
- }
-#else
- if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
- if (!lp->dxsuflo) { /* If controller doesn't recover ... */
- /* Ackk! On FIFO errors the Tx unit is turned off! */
- /* Remove this verbosity later! */
- if (netif_msg_tx_err
- (lp))
- printk(KERN_ERR
- "%s: Tx FIFO error! CSR0=%4.4x\n",
- dev->
- name,
- csr0);
- must_restart = 1;
- }
- }
-#endif
- } else {
- if (status & 0x1800)
- lp->stats.collisions++;
- lp->stats.tx_packets++;
- }
-
- /* We must free the original skb */
- if (lp->tx_skbuff[entry]) {
- pci_unmap_single(lp->pci_dev,
- lp->tx_dma_addr[entry],
- lp->tx_skbuff[entry]->
- len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(lp->tx_skbuff[entry]);
- lp->tx_skbuff[entry] = NULL;
- lp->tx_dma_addr[entry] = 0;
- }
- dirty_tx++;
- }
-
- delta =
- (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask +
- lp->tx_ring_size);
- if (delta > lp->tx_ring_size) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, lp->cur_tx,
- lp->tx_full);
- dirty_tx += lp->tx_ring_size;
- delta -= lp->tx_ring_size;
- }
-
- if (lp->tx_full &&
- netif_queue_stopped(dev) &&
- delta < lp->tx_ring_size - 2) {
- /* The ring is no longer full, clear tbusy. */
- lp->tx_full = 0;
- netif_wake_queue(dev);
- }
- lp->dirty_tx = dirty_tx;
- }
-
/* Log misc errors. */
if (csr0 & 0x4000)
lp->stats.tx_errors++; /* Tx babble. */
if (csr0 & 0x1000) {
/*
- * this happens when our receive ring is full. This shouldn't
- * be a problem as we will see normal rx interrupts for the frames
- * in the receive ring. But there are some PCI chipsets (I can
- * reproduce this on SP3G with Intel saturn chipset) which have
- * sometimes problems and will fill up the receive ring with
- * error descriptors. In this situation we don't get a rx
- * interrupt, but a missed frame interrupt sooner or later.
- * So we try to clean up our receive ring here.
+ * This happens when our receive ring is full. This
+ * shouldn't be a problem as we will see normal rx
+ * interrupts for the frames in the receive ring. But
+ * there are some PCI chipsets (I can reproduce this
+ * on SP3G with Intel saturn chipset) which have
+ * sometimes problems and will fill up the receive
+ * ring with error descriptors. In this situation we
+ * don't get a rx interrupt, but a missed frame
+ * interrupt sooner or later.
*/
- pcnet32_rx(dev);
lp->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
@@ -2171,19 +2597,34 @@ pcnet32_interrupt(int irq, void *dev_id,
dev->name, csr0);
/* unlike for the lance, there is no restart needed */
}
-
- if (must_restart) {
+#ifdef CONFIG_PCNET32_NAPI
+ if (netif_rx_schedule_prep(dev)) {
+ u16 val;
+ /* set interrupt masks */
+ val = lp->a.read_csr(ioaddr, 3);
+ val |= 0x5f00;
+ lp->a.write_csr(ioaddr, 3, val);
+ __netif_rx_schedule(dev);
+ break;
+ }
+#else
+//printk("DONF: %s: weight is %d\n", dev->name, dev->weight);
+ pcnet32_rx(dev, dev->weight);
+ if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
lp->a.write_csr(ioaddr, 4, 0x0915);
pcnet32_restart(dev, 0x0002);
netif_wake_queue(dev);
}
+#endif
+ csr0 = lp->a.read_csr(ioaddr, 0);
}
- /* Set interrupt enable. */
+#ifndef CONFIG_PCNET32_NAPI
+ /*Set interrupt enable. */
lp->a.write_csr(ioaddr, 0, 0x0040);
- lp->a.write_rap(ioaddr, rap);
+#endif
if (netif_msg_intr(lp))
printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
@@ -2191,170 +2632,13 @@ pcnet32_interrupt(int irq, void *dev_id,
spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-static int pcnet32_rx(struct net_device *dev)
-{
- struct pcnet32_private *lp = dev->priv;
- int entry = lp->cur_rx & lp->rx_mod_mask;
- int boguscnt = lp->rx_ring_size / 2;
-
- /* If we own the next entry, it's a new packet. Send it up. */
- while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
- int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
-
- if (status != 0x03) { /* There was an error. */
- /*
- * There is a tricky error noted by John Murphy,
- * <murf@perftech.com> to Russ Nelson: Even with full-sized
- * buffers it's possible for a jabber packet to use two
- * buffers, with only the last correctly noting the error.
- */
- if (status & 0x01) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet. */
- if (status & 0x20)
- lp->stats.rx_frame_errors++;
- if (status & 0x10)
- lp->stats.rx_over_errors++;
- if (status & 0x08)
- lp->stats.rx_crc_errors++;
- if (status & 0x04)
- lp->stats.rx_fifo_errors++;
- lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
- } else {
- /* Malloc up new buffer, compatible with net-2e. */
- short pkt_len =
- (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)
- - 4;
- struct sk_buff *skb;
-
- /* Discard oversize frames. */
- if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Impossible packet size %d!\n",
- dev->name, pkt_len);
- lp->stats.rx_errors++;
- } else if (pkt_len < 60) {
- if (netif_msg_rx_err(lp))
- printk(KERN_ERR "%s: Runt packet!\n",
- dev->name);
- lp->stats.rx_errors++;
- } else {
- int rx_in_place = 0;
-
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
-
- if ((newskb =
- dev_alloc_skb(PKT_BUF_SZ))) {
- skb_reserve(newskb, 2);
- skb = lp->rx_skbuff[entry];
- pci_unmap_single(lp->pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ - 2,
- PCI_DMA_FROMDEVICE);
- skb_put(skb, pkt_len);
- lp->rx_skbuff[entry] = newskb;
- newskb->dev = dev;
- lp->rx_dma_addr[entry] =
- pci_map_single(lp->pci_dev,
- newskb->data,
- PKT_BUF_SZ -
- 2,
- PCI_DMA_FROMDEVICE);
- lp->rx_ring[entry].base =
- le32_to_cpu(lp->
- rx_dma_addr
- [entry]);
- rx_in_place = 1;
- } else
- skb = NULL;
- } else {
- skb = dev_alloc_skb(pkt_len + 2);
- }
-
- if (skb == NULL) {
- int i;
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory squeeze, deferring packet.\n",
- dev->name);
- for (i = 0; i < lp->rx_ring_size; i++)
- if ((short)
- le16_to_cpu(lp->
- rx_ring[(entry +
- i)
- & lp->
- rx_mod_mask].
- status) < 0)
- break;
-
- if (i > lp->rx_ring_size - 2) {
- lp->stats.rx_dropped++;
- lp->rx_ring[entry].status |=
- le16_to_cpu(0x8000);
- wmb(); /* Make sure adapter sees owner change */
- lp->cur_rx++;
- }
- break;
- }
- skb->dev = dev;
- if (!rx_in_place) {
- skb_reserve(skb, 2); /* 16 byte align */
- skb_put(skb, pkt_len); /* Make room */
- pci_dma_sync_single_for_cpu(lp->pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ -
- 2,
- PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb,
- (unsigned char *)(lp->
- rx_skbuff
- [entry]->
- data),
- pkt_len, 0);
- pci_dma_sync_single_for_device(lp->
- pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ
- - 2,
- PCI_DMA_FROMDEVICE);
- }
- lp->stats.rx_bytes += skb->len;
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- }
- }
- /*
- * The docs say that the buffer length isn't touched, but Andrew Boyd
- * of QNX reports that some revs of the 79C965 clear it.
- */
- lp->rx_ring[entry].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
- wmb(); /* Make sure owner changes after all others are visible */
- lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
- entry = (++lp->cur_rx) & lp->rx_mod_mask;
- if (--boguscnt <= 0)
- break; /* don't stay in loop forever */
- }
-
- return 0;
+ return rc;
}
static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
- int i;
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2385,31 +2669,8 @@ static int pcnet32_close(struct net_devi
spin_lock_irqsave(&lp->lock, flags);
- /* free all allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- wmb(); /* Make sure adapter sees owner change */
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
-
- for (i = 0; i < lp->tx_ring_size; i++) {
- lp->tx_ring[i].status = 0; /* CPU owns buffer */
- wmb(); /* Make sure adapter sees owner change */
- if (lp->tx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
- lp->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(lp->tx_skbuff[i]);
- }
- lp->tx_skbuff[i] = NULL;
- lp->tx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
+ pcnet32_purge_tx_ring(dev);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2420,13 +2681,10 @@ static struct net_device_stats *pcnet32_
{
struct pcnet32_private *lp = dev->priv;
unsigned long ioaddr = dev->base_addr;
- u16 saved_addr;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- saved_addr = lp->a.read_rap(ioaddr);
lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
- lp->a.write_rap(ioaddr, saved_addr);
spin_unlock_irqrestore(&lp->lock, flags);
return &lp->stats;
@@ -2439,6 +2697,7 @@ static void pcnet32_load_multicast(struc
volatile struct pcnet32_init_block *ib = &lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
+ unsigned long ioaddr = dev->base_addr;
char *addrs;
int i;
u32 crc;
@@ -2447,6 +2706,10 @@ static void pcnet32_load_multicast(struc
if (dev->flags & IFF_ALLMULTI) {
ib->filter[0] = 0xffffffff;
ib->filter[1] = 0xffffffff;
+ lp->a.write_csr(ioaddr, 8, 0xffff);
+ lp->a.write_csr(ioaddr, 9, 0xffff);
+ lp->a.write_csr(ioaddr, 10, 0xffff);
+ lp->a.write_csr(ioaddr, 11, 0xffff);
return;
}
/* clear the multicast filter */
@@ -2468,6 +2731,8 @@ static void pcnet32_load_multicast(struc
le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
(1 << (crc & 0xf)));
}
+ for (i = 0; i < 4; i++)
+ lp->a.write_csr(ioaddr, 8+i, le16_to_cpu(mcast_table[i]));
return;
}
@@ -2478,8 +2743,11 @@ static void pcnet32_set_multicast_list(s
{
unsigned long ioaddr = dev->base_addr, flags;
struct pcnet32_private *lp = dev->priv;
+ int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
+ suspended = pcnet32_suspend(dev, &flags);
+ csr15 = lp->a.read_csr(ioaddr, 15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
if (netif_msg_hw(lp))
@@ -2488,15 +2756,24 @@ static void pcnet32_set_multicast_list(s
lp->init_block.mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
+ lp->a.write_csr(ioaddr, 15, csr15 | 0x8000);
} else {
lp->init_block.mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ lp->a.write_csr(ioaddr, 15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
- pcnet32_restart(dev, 0x0042); /* Resume normal operation */
- netif_wake_queue(dev);
+ if (suspended) {
+ int csr5;
+ /* clear SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = lp->a.read_csr(ioaddr, 5);
+ lp->a.write_csr(ioaddr, 5, csr5 & (~0x0001));
+ } else {
+ lp->a.write_csr(ioaddr, 0, 0x0004); /* stop the lance. */
+ pcnet32_restart(dev, 0x0042); /* Resume normal operation */
+ netif_wake_queue(dev);
+ }
spin_unlock_irqrestore(&lp->lock, flags);
}
@@ -2736,7 +3013,7 @@ static int __init pcnet32_init_module(vo
/* should we find any remaining VLbus devices ? */
if (pcnet32vlb)
- pcnet32_probe_vlbus();
+ pcnet32_probe_vlbus(pcnet32_portlist);
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply
* Re: [1/4] kevent: core files.
From: Benjamin LaHaise @ 2006-06-23 21:31 UTC (permalink / raw)
To: Evgeniy Polyakov; +Cc: David Miller, netdev
In-Reply-To: <20060623210826.GC26168@2ka.mipt.ru>
On Sat, Jun 24, 2006 at 01:08:27AM +0400, Evgeniy Polyakov wrote:
> On Fri, Jun 23, 2006 at 04:44:42PM -0400, Benjamin LaHaise (bcrl@kvack.org) wrote:
> > > AIO completion approach was designed to be used with process context VFS
> > > update. read/write approach can not cover other types of notifications,
> > > like inode updates or timers.
> >
> > The completion event is 100% generic and does not need to come from process
> > context. Calling aio_complete() from irq context is entirely valid.
>
> put_ioctx() can sleep.
Err, no, that should definately not be the case. If it can, someone has
completely broken aio.
> It is not syscall, but overall design should be analyzed.
> It is possible to use existing ssycalls, kevent design does not care
> about how it's data structures are delivered to the internal
> "processor".
Okay, that's good to hear. =-)
-ben
--
"Time is of no importance, Mr. President, only life is important."
Don't Email: <dont@kvack.org>.
^ 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