* [PATCH 18/18] iseries_veth: Be consistent about driver name, increment version
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
In-Reply-To: <1125538127.859382.875909607846.qpush@concordia>
The iseries_veth driver tells sysfs that it's called 'iseries_veth', but if
you ask it via ethtool it thinks it's called 'veth'. I think this comes from
2.4 when the driver was called 'veth', but it's definitely called
'iseries_veth' now, so fix it.
To make sure we don't do it again define DRV_NAME and use it everywhere.
While we're at it, change the version number to 2.0, to reflect the changes
made in this patch series.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 16 ++++++++++------
1 files changed, 10 insertions(+), 6 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -125,6 +125,9 @@ struct veth_lpevent {
};
+#define DRV_NAME "iseries_veth"
+#define DRV_VERSION "2.0"
+
#define VETH_NUMBUFFERS (120)
#define VETH_ACKTIMEOUT (1000000) /* microseconds */
#define VETH_MAX_MCAST (12)
@@ -227,14 +230,14 @@ static void veth_timed_reset(unsigned lo
*/
#define veth_info(fmt, args...) \
- printk(KERN_INFO "iseries_veth: " fmt, ## args)
+ printk(KERN_INFO DRV_NAME ": " fmt, ## args)
#define veth_error(fmt, args...) \
- printk(KERN_ERR "iseries_veth: Error: " fmt, ## args)
+ printk(KERN_ERR DRV_NAME ": Error: " fmt, ## args)
#ifdef DEBUG
#define veth_debug(fmt, args...) \
- printk(KERN_DEBUG "iseries_veth: " fmt, ## args)
+ printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
#else
#define veth_debug(fmt, args...) do {} while (0)
#endif
@@ -997,9 +1000,10 @@ static void veth_set_multicast_list(stru
static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strncpy(info->driver, "veth", sizeof(info->driver) - 1);
+ strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
info->driver[sizeof(info->driver) - 1] = '\0';
- strncpy(info->version, "1.0", sizeof(info->version) - 1);
+ strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+ info->version[sizeof(info->version) - 1] = '\0';
}
static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -1642,7 +1646,7 @@ static struct vio_device_id veth_device_
MODULE_DEVICE_TABLE(vio, veth_device_table);
static struct vio_driver veth_driver = {
- .name = "iseries_veth",
+ .name = DRV_NAME,
.id_table = veth_device_table,
.probe = veth_probe,
.remove = veth_remove
^ permalink raw reply
* Re: [PATCH] hostap: Fix null pointer dereference in prism2_pccard_card_present()
From: Jouni Malinen @ 2005-09-01 2:10 UTC (permalink / raw)
To: Kalle Valo; +Cc: hostap, netdev, Jeff Garzik
In-Reply-To: <87slwq0xwa.fsf@litku.valo.iki.fi>
On Wed, Aug 31, 2005 at 09:22:29PM +0300, Kalle Valo wrote:
> Jouni Malinen <jkmaline@cc.hut.fi> writes:
> > local->hw_priv was initialized only after the interrupt handler was
> > registered. This could trigger a NULL pointer dereference in
> > prism2_pccard_card_present() that assumed that local->hw_priv is always
> > set (and it should have been). Fix this by setting local->hw_priv before
> > registering the interrupt handler.
>
> I was trying to test Jouni's patch but now I can't reproduce the oops
> with latest ieee80211-wifi branch and my NULL pointer check removed.
> Earlier I could reproduce it every time. Strange.
Triggering this race conditions requires that you are sharing the same
interrupt line with another device which is generating interrupts at the
same time as Host AP driver is initializing the card. I don't know
whether interrupt assignment could have changed in the latest version,
but I would guess more like cause would be a difference in, e.g., how
other devices are being used at the time Host AP driver was being
initialized.
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply
* Re: [PATCH 0/18] Updates & bug fixes for iseries_veth network driver
From: Jeff Garzik @ 2005-09-01 2:43 UTC (permalink / raw)
To: Michael Ellerman; +Cc: netdev, linux-kernel, linuxppc64-dev
In-Reply-To: <1125538127.859382.875909607846.qpush@concordia>
applied patches 1-18
^ permalink raw reply
* Linux multicast support
From: amine @ 2005-09-01 15:05 UTC (permalink / raw)
To: netdev
Hi,
I have a question about Multicast in Linux IP stack. I need to know why are
loking the " dev->xmit_lock" when mading change in device multicast list?
Is it required to suppress parallel execution of that handler and
set_multicast_list?
Thank in advance
--
EL HEDADI Amine
R&D
phone :
Email : amine@anevia.com
^ permalink raw reply
* Re: Very strange Marvell/Yukon Gigabit NIC networking problems
From: Stephen Hemminger @ 2005-09-01 17:59 UTC (permalink / raw)
To: Steve Kieu
Cc: Jesse Brandeburg, Daniel Drake, Steve Kieu, linux-kernel, netdev
In-Reply-To: <20050831000948.40799.qmail@web53607.mail.yahoo.com>
On Wed, 31 Aug 2005 10:09:48 +1000 (EST)
Steve Kieu <haiquy@yahoo.com> wrote:
>
> --- Stephen Hemminger <shemminger@osdl.org> wrote:
>
> > On Wed, 31 Aug 2005 07:49:37 +1000 (EST)
>
> > >
> > > install-8_23.tar.bz2
> >
> > Just look for references to CHIP_REV_YU_LITE_A3 in
> > the driver
> > sk98lin/skgeinit.c and sk98lin/skxmac2.c
> > The comparison should always be:
>
> Have a look but no clue to patch it, there are one
> instance of comparing
I don't fix the out of tree vendor driver. sorry.
^ permalink raw reply
* Re: Very strange Marvell/Yukon Gigabit NIC networking problems
From: Stephen Hemminger @ 2005-09-01 18:09 UTC (permalink / raw)
To: Daniel Drake; +Cc: Steve Kieu, linux-kernel, Netdev List
In-Reply-To: <431448F7.2020506@gentoo.org>
On Tue, 30 Aug 2005 12:54:31 +0100
Daniel Drake <dsd@gentoo.org> wrote:
> Hi Stephen,
>
> This looks like an issue I reported previously. After you use a recent skge,
> you can't use any older drivers or the windows driver, but skge still works
> fine every time.
>
> http://marc.theaimsgroup.com/?l=linux-netdev&m=112268414417743&w=2
>
> The Gentoo bug report is here:
>
> http://bugs.gentoo.org/show_bug.cgi?id=100258
>
> I closed the Gentoo bug as I hoped this patch would solve it:
>
> http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff_plain;h=0eedf4ac5b536c7922263adf1b1d991d2e2397b9;hp=acdd80d514a08800380c9f92b1bf4d4c9e818125
>
> But according to Steve Kieu, the problem is still there in 2.6.13. It's
> slightly odd as Steve was previously a sk98lin user and initially reported
> this problem for sk98lin in 2.6.13 whereas it did not happen with sk98lin in
> 2.6.12.
>
> Any ideas?
>
> Thanks.
>
> Steve Kieu wrote:
> > Tested , not broken, working now but the same problem,
> > that is if I reboot to winXP or 2.6.12, 2.6.11, the
> > NIC is unusaeble. In XP it always says link is down,
> > or media disconnected (from ipconfig command output in
> > XP)
> > is it because the firmware of NIC has changed or any
> > reason?
> >
> >
> > I noticed warning messages only with 2.6.13
> >
> > PCI: Failed to allocate mem resource #10:2000000@0 for
> > 0000:02:01.0
> >
> > and modem device in 2.6.13 IRQ is disabled.
This is a different problem related to ACPI and other bus
changes in 2.6.13.
> > ACPI: PCI Interrupt Link [LKMO] enabled at IRQ 20
> > ACPI: PCI Interrupt 0000:00:06.1[B] -> Link [LKMO] ->
> > GSI 20 (level, low) -> IRQ
> > 17
> > ACPI: PCI interrupt for device 0000:00:06.1 disabled
> >
> > not sure if it gives more information.
> >
> > skge addr 0xfeaf8000 irq 19 chip Yukon-Lite rev 9
> > skge eth0: addr 00:11:d8:f2:1f:18
> > ACPI: PCI Interrupt 0000:02:01.0[A] -> Link [LNKB] ->
> > GSI 18 (level, low) -> IRQ
> > 16
> > Yenta: CardBus bridge found at 0000:02:01.0
> > [1043:1987]
> > skge eth0: enabling interface
> >
> > skge eth0: Link is up at 10 Mbps, half duplex, flow
> > control none
> >
> > Not sure how can I restore this thing back to normal
> > (sigh)
Is this the correct summary of the problem scenarios.
Assume each one starts from cold boot (power off).
* 2.6.13(skge) boot => Good
* 2.6.13(sk98lin) boot => Good
* 2.6.13 + SK version of sk98lin => Good
* XP boot => Good
Okay, now the cases where one OS is run first and
a reboot is done to a second, or in the case of
just Linux, this should be the same as rmmoding on
driver and modprobing
Second
First | skge | sk98lin | XP
skge | OK | BAD | BAD
sk98lin | ok | OK | ok
XP | ok | ok | OK
^ permalink raw reply
* Netdevice reference leak in af_ax25.c ??
From: Ben Greear @ 2005-09-01 18:41 UTC (permalink / raw)
To: linux-hams, ralf; +Cc: netdev
I believe the SO_BINDTODEVICE case in net/ax25/af_x25.c (line 613 or so)
leaks a reference to a net device. It does a dev_get_by_name,
which holds a reference, but since it never assigns the pointer
anywhere, I do not see how it can ever free it later.
Please clue me in as to where it's released if it actually is.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: Netdevice reference leak in af_ax25.c ??
From: Patrick McHardy @ 2005-09-01 18:56 UTC (permalink / raw)
To: Ben Greear; +Cc: linux-hams, ralf, netdev
In-Reply-To: <43174B67.9030109@candelatech.com>
Ben Greear wrote:
>
> I believe the SO_BINDTODEVICE case in net/ax25/af_x25.c (line 613 or so)
> leaks a reference to a net device. It does a dev_get_by_name,
> which holds a reference, but since it never assigns the pointer
> anywhere, I do not see how it can ever free it later.
>
> Please clue me in as to where it's released if it actually is.
I can't find the code you're talking about, there's no dev_get* in my
version of af_x25.c. Please paste the code you're talking about in
your bugreports, thanks.
^ permalink raw reply
* Re: Netdevice reference leak in af_ax25.c ??
From: Ben Greear @ 2005-09-01 19:02 UTC (permalink / raw)
To: Patrick McHardy; +Cc: linux-hams, ralf, netdev
In-Reply-To: <43174ED3.6040106@trash.net>
Patrick McHardy wrote:
> Ben Greear wrote:
>
>>I believe the SO_BINDTODEVICE case in net/ax25/af_x25.c (line 613 or so)
>>leaks a reference to a net device. It does a dev_get_by_name,
>>which holds a reference, but since it never assigns the pointer
>>anywhere, I do not see how it can ever free it later.
>>
>>Please clue me in as to where it's released if it actually is.
>
>
> I can't find the code you're talking about, there's no dev_get* in my
> version of af_x25.c. Please paste the code you're talking about in
> your bugreports, thanks.
Please ignore the NRDK thing..I am adding reference counting debugging
to the netdevice code. This is from the 2.6.13 kernel:
In this method:
/*
* Handling for system calls applied via the various interfaces to an
* AX25 socket object
*/
static int ax25_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, int optlen)
{
.....
case SO_BINDTODEVICE:
if (optlen > IFNAMSIZ)
optlen=IFNAMSIZ;
if (copy_from_user(devname, optval, optlen)) {
res = -EFAULT;
break;
}
dev = dev_get_by_name(devname, NDRK_GENERIC);
if (dev == NULL) {
res = -ENODEV;
break;
}
if (sk->sk_type == SOCK_SEQPACKET &&
(sock->state != SS_UNCONNECTED ||
sk->sk_state == TCP_LISTEN)) {
res = -EADDRNOTAVAIL;
dev_put(dev, NDRK_GENERIC);
break;
}
ax25->ax25_dev = ax25_dev_ax25dev(dev);
ax25_fillin_cb(ax25, ax25->ax25_dev);
dev_put(dev, NDRK_GENERIC); /* TODO: Verify we should put it here. */
break;
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: Netdevice reference leak in af_ax25.c ??
From: Ralf Baechle @ 2005-09-01 19:30 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Ben Greear, linux-hams, netdev
In-Reply-To: <43174ED3.6040106@trash.net>
On Thu, Sep 01, 2005 at 08:56:19PM +0200, Patrick McHardy wrote:
> > I believe the SO_BINDTODEVICE case in net/ax25/af_x25.c (line 613 or so)
> > leaks a reference to a net device. It does a dev_get_by_name,
> > which holds a reference, but since it never assigns the pointer
> > anywhere, I do not see how it can ever free it later.
> >
> > Please clue me in as to where it's released if it actually is.
>
> I can't find the code you're talking about, there's no dev_get* in my
> version of af_x25.c. Please paste the code you're talking about in
> your bugreports, thanks.
Ben meant net/ax25/af_ax25. The dev value is stored in the ax25_cb
indirectly after converting it to an ax25dev pointer and will be freed
what that ax25_cb (which really is the protocol-specific part of the
socket) is going to be closed.
You poked my nose at a bug though - it is possible to leak references by
performing multiple SO_BINDTODEVICE operations; we should either only
permit the first one to succeed or to drop the reference of the old
device in case of a repeated SO_BINDTODEVICE. After the weekend ...
Ralf
^ permalink raw reply
* Re: Netdevice reference leak in af_ax25.c ??
From: Ben Greear @ 2005-09-01 19:42 UTC (permalink / raw)
To: Ralf Baechle; +Cc: Patrick McHardy, linux-hams, netdev
In-Reply-To: <20050901193008.GA13363@linux-mips.org>
Ralf Baechle wrote:
> On Thu, Sep 01, 2005 at 08:56:19PM +0200, Patrick McHardy wrote:
>
>
>>>I believe the SO_BINDTODEVICE case in net/ax25/af_x25.c (line 613 or so)
>>>leaks a reference to a net device. It does a dev_get_by_name,
>>>which holds a reference, but since it never assigns the pointer
>>>anywhere, I do not see how it can ever free it later.
>>>
>>>Please clue me in as to where it's released if it actually is.
>>
>>I can't find the code you're talking about, there's no dev_get* in my
>>version of af_x25.c. Please paste the code you're talking about in
>>your bugreports, thanks.
>
>
> Ben meant net/ax25/af_ax25. The dev value is stored in the ax25_cb
> indirectly after converting it to an ax25dev pointer and will be freed
> what that ax25_cb (which really is the protocol-specific part of the
> socket) is going to be closed.
Ok, I'm getting hopelessly lost in the ax25 code trying to follow
references, so I'm just going to use the generic ref counting debugging.
That will still point to the right module, but not the line of code,
should a leak occur (and should the patch be accepted) :)
> You poked my nose at a bug though - it is possible to leak references by
> performing multiple SO_BINDTODEVICE operations; we should either only
> permit the first one to succeed or to drop the reference of the old
> device in case of a repeated SO_BINDTODEVICE. After the weekend ...
Thanks for taking a look.
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH] 8139cp: Catch all interrupts
From: Pierre Ossman @ 2005-09-01 20:16 UTC (permalink / raw)
To: Jeff Garzik, LKML, netdev, Felipe Damasio
[-- Attachment #1: Type: text/plain, Size: 604 bytes --]
Register interrupt handler when net device is registered. Avoids missing
interrupts if the interrupt mask gets out of sync.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
---
The reason this patch is needed for me is that the resume function is
broken. It enables interrupts unconditionally, but the interrupt handler
is only registered when the device is up.
I don't have enough knowledge about the driver to fix the resume
function so this patch will instead make sure that the interrupt handler
is registered at all times (which can be a nice safeguard even when the
resume function gets fixed).
[-- Attachment #2: 8139cp-catch-irq.patch --]
[-- Type: text/x-patch, Size: 1327 bytes --]
Index: linux-wbsd/drivers/net/8139cp.c
===================================================================
--- linux-wbsd/drivers/net/8139cp.c (revision 165)
+++ linux-wbsd/drivers/net/8139cp.c (working copy)
@@ -1204,20 +1204,11 @@
cp_init_hw(cp);
- rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
- if (rc)
- goto err_out_hw;
-
netif_carrier_off(dev);
mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
netif_start_queue(dev);
return 0;
-
-err_out_hw:
- cp_stop_hw(cp);
- cp_free_rings(cp);
- return rc;
}
static int cp_close (struct net_device *dev)
@@ -1238,7 +1229,6 @@
spin_unlock_irqrestore(&cp->lock, flags);
synchronize_irq(dev->irq);
- free_irq(dev->irq, dev);
cp_free_rings(cp);
return 0;
@@ -1813,6 +1803,10 @@
if (rc)
goto err_out_iomap;
+ rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
+ if (rc)
+ goto err_out_unreg;
+
printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
"%02x:%02x:%02x:%02x:%02x:%02x, "
"IRQ %d\n",
@@ -1832,6 +1826,8 @@
return 0;
+err_out_unreg:
+ unregister_netdev(dev);
err_out_iomap:
iounmap(regs);
err_out_res:
@@ -1852,6 +1848,7 @@
if (!dev)
BUG();
+ free_irq(dev->irq, dev);
unregister_netdev(dev);
iounmap(cp->regs);
if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
^ permalink raw reply
* Re: [2.6 patch] include/net/ip_vs.h: "extern inline" -> "static inline"
From: David S. Miller @ 2005-09-01 22:09 UTC (permalink / raw)
To: bunk; +Cc: wensong, ja, netdev, linux-kernel
In-Reply-To: <20050824155806.GF4851@stusta.de>
From: Adrian Bunk <bunk@stusta.de>
Date: Wed, 24 Aug 2005 17:58:06 +0200
> "extern inline" doesn't make much sense.
>
> Signed-off-by: Adrian Bunk <bunk@stusta.de>
Applied, thanks Adrian.
^ permalink raw reply
* Re: Possible BUG in IPv4 TCP window handling, all recent 2.4.x/2.6.x kernels
From: Ion Badulescu @ 2005-09-01 22:53 UTC (permalink / raw)
To: David S. Miller; +Cc: linux-kernel, linux-net, netdev
In-Reply-To: <20050901.154300.118239765.davem@davemloft.net>
Hi David,
On Thu, 1 Sep 2005, David S. Miller wrote:
> Thanks for the empty posting. Please provide the content you
> intended to post, and furthermore please post it to the network
> developer mailing list, netdev@vger.kernel.org
First of all, thanks for the reply (even to an empty posting :).
The posting wasn't actually empty, it was probably too long (94K according
to my sent-mail folder) and majordomo truncated it to zero. It has some
tcpdump snippets, that's what made it so long... unfortunately, they're
all necessary to understand the nature of the bug. I wasn't sure about
netdev, that's why I posted it only to linux-kernel and linux-net.
I can provide the full tcpdump out-of-band to interested people, since I
don't think I can get it past majordomo.
Here is the text of the message without the tcpdump inserts:
---------------------------------------------------------------------------
Hello,
I've been tracking down this bug for some time, and I'm fairly convinced
at this point that it's a kernel bug.
Under certain conditions, the TCP stack starts shrinking the TCP window
down to some ridiculously low values (hundreds of bytes, as low as 181)
and never recovers. The certain conditions I mentioned are not well
understood at this point, but they include a long-lived connection with a
very one-sided, fluctuating traffic flowing through it.
So far I've been able to reproduce it on plain-vanilla 2.4.9, 2.4.11.9,
and 2.4.12.2, as well as on the RHEL3 kernels 2.4.21-20 and 2.4.21-31. The
hardware is dual Opteron 250, running both 32- and 64-bit SMP kernels
(seems to make no difference). I've also seen the bug occur on a single
Athlon XP running 2.6.11.9 UP.
The bug occurs with all sysctl settings at their default values. I've
tried enabling and disabling pretty much all the tcp-related sysctl's in
/proc/sys/net/ipv4, to no visible improvement.
Here are a few tcpdump snippets of a TCP connection exhibiting the bug
(the complete tcpdump is available upon request, but it's very large).
10.2.20.246 is the data receiver and is the box exhibiting the bug (I'm
not sure what 10.2.224.182 is running, I don't have access to it). The
data being sent through is real-time financial data; the session begins by
catching up (at line speed) to present time, then continues to receive
real-time data as it is being generated. For what it's worth, we've never
been seen the bug occur while the session is still catching up (and
receiving a few large packets at a time); it always seems to happen while
receiving real-time data (many small packets, variably interspaced).
[I apologize for the amount of tcpdump data, but it's the only way to show
the bug in action.]
[tcpdump output removed]
The connection is established and the receiver's TCP window quickly ramps
up to 8192.
[tcpdump output removed]
Shortly thereafter the TCP window increases further to 16534. It remains
around 16534 for the next 5 minutes or so.
[tcpdump output removed]
A few minutes later it has finally caught up to present time and it starts
receiving smaller packets containing real-time data. The TCP window is
still 16534 at this point.
[tcpdump output removed]
This is where things start going bad. The window starts shrinking from
15340 all the way down to 2355 over the course of 0.3 seconds. Notice the
many duplicate acks that serve no purpose (there are no lost packets and
the tcpdump is taken on the receiver so there is no packets/acks crossed
in flight).
[tcpdump output removed]
Five minutes later the TCP window is still at 2355, having never
recovered. The window is so small that the available bandwidth for this
connection is too small to keep up with the real-time data so it is
falling behind, hence large packets are again being used. The application
processing the data (Java-based) is mostly idle at this point, and netstat
shows its recv queue to be empty. There is no apparent reason why the
kernel shouldn't enlarge the window.
In fact, if I let it continue, it eventually shrinks the window even
further (by 18:19:29, the time I'm writing this email, it's gone all the
way down to 1373). As I mentioned earlier, I've seen it go as low as 181.
We are kind of stumped at this point, and it's proving to be a
show-stopping bug for our purposes, especially over WAN links that have
higher latency (for obvious reasons). Any kind of assistance would be
greatly appreciated.
Thanks,
-Ion
^ permalink raw reply
* Re: Possible BUG in IPv4 TCP window handling, all recent 2.4.x/2.6.x kernels
From: Jesper Juhl @ 2005-09-01 23:37 UTC (permalink / raw)
To: Ion Badulescu; +Cc: David S. Miller, linux-kernel, linux-net, netdev
In-Reply-To: <Pine.LNX.4.61.0509011845040.6083@guppy.limebrokerage.com>
On 9/2/05, Ion Badulescu <lists@limebrokerage.com> wrote:
> Hi David,
>
> On Thu, 1 Sep 2005, David S. Miller wrote:
>
> > Thanks for the empty posting. Please provide the content you
> > intended to post, and furthermore please post it to the network
> > developer mailing list, netdev@vger.kernel.org
>
> First of all, thanks for the reply (even to an empty posting :).
>
> The posting wasn't actually empty, it was probably too long (94K according
Two solutions commonly applied to that problem :
- put the big file(s) online somewhere and include an URL in the email
- compress the file(s) and attach the compressed files to the email
--
Jesper Juhl <jesper.juhl@gmail.com>
Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html
Plain text mails only, please http://www.expita.com/nomime.html
^ permalink raw reply
* [PATCH 0/8] orinoco: Bringing in-sync with CVS
From: Pavel Roskin @ 2005-09-02 0:00 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Hello!
Following 8 patches bring orinoco drivers in the kernel fully in-sync
with the CVS repository at http://savannah.nongnu.org/projects/orinoco/
("for_linus" branch).
The patches include 2 new front-end drivers: orinoco_nortel and
spectrum_cs. They also remove EXPERIMENTAL designation of the PCI
front-ends (PCI, PLX and TMD). The rest is pretty minor.
I'm placing the patches to http://red-bean.com/proski/orinoco/
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 1/8] orinoco: Stop using "ieee802_11.h".
From: Pavel Roskin @ 2005-09-02 0:01 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA, Orinoco Development List
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree 56bfcdb38b3d04c1f8c1fd705e411f4be53b663c (from dee4f325520d4ea29397dd67ca657b7235bb1790)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 18:15:07 2005 -0400
Stop using "ieee802_11.h".
Use equivalent constants from <net/ieee80211.h>
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -99,11 +99,10 @@
#include <asm/system.h>
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
-#include "ieee802_11.h"
/********************************************************************/
/* Module information */
/********************************************************************/
@@ -148,11 +147,11 @@ MODULE_PARM_DESC(force_monitor, "Allow m
/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
#define ORINOCO_MIN_MTU 256
-#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
#define SYMBOL_MAX_VER_LEN (14)
#define USER_BAP 0
#define IRQ_BAP 1
#define MAX_IRQLOOPS_PER_IRQ 10
@@ -440,11 +439,11 @@ static int orinoco_change_mtu(struct net
struct orinoco_private *priv = netdev_priv(dev);
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
return -EINVAL;
- if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) >
+ if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
(priv->nicbuf_size - ETH_HLEN) )
return -EINVAL;
dev->mtu = new_mtu;
@@ -916,11 +915,11 @@ static void __orinoco_ev_rx(struct net_d
/* At least on Symbol firmware with PCF we get quite a
lot of these legitimately - Poll frames with no
data. */
return;
}
- if (length > IEEE802_11_DATA_LEN) {
+ if (length > IEEE80211_DATA_LEN) {
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
dev->name, length);
stats->rx_length_errors++;
goto update_stats;
}
@@ -2270,11 +2269,11 @@ static int orinoco_init(struct net_devic
TRACE_ENTER(dev->name);
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
- priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
+ priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
/* Initialize the firmware */
err = orinoco_reinit_firmware(dev);
if (err != 0) {
printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 2/8] orinoco: Change orinoco_translate_scan() to return error code on error.
From: Pavel Roskin @ 2005-09-02 0:02 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree 8fc038ec51acf5f777fade80c5e38112b766aeee (from ca955293cdfd3139e150d3b4fed3922a7eb651fb)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 19:10:12 2005 -0400
Change orinoco_translate_scan() to return error code on error.
Adjust the caller to check for errors and clean up if needed.
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -4023,11 +4023,12 @@ static int orinoco_ioctl_setscan(struct
orinoco_unlock(priv, &flags);
return err;
}
/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
+ * format that the Wireless Tools will understand - Jean II
+ * Return message length or -errno for fatal errors */
static inline int orinoco_translate_scan(struct net_device *dev,
char *buffer,
char *scan,
int scan_len)
{
@@ -4063,25 +4064,31 @@ static inline int orinoco_translate_scan
atom_len = 68;
offset = 0;
break;
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
- if (priv->has_hostscan)
- atom_len = scan[0] + (scan[1] << 8);
- else
+ if (priv->has_hostscan) {
+ atom_len = le16_to_cpup((u16 *)scan);
+ /* Sanity check for atom_len */
+ if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+ printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
+ dev->name, atom_len);
+ return -EIO;
+ }
+ } else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
default:
- return 0;
+ return -EOPNOTSUPP;
}
/* Check that we got an whole number of atoms */
if ((scan_len - offset) % atom_len) {
printk(KERN_ERR "%s: Unexpected scan data length %d, "
"atom_len %d, offset %d\n", dev->name, scan_len,
atom_len, offset);
- return 0;
+ return -EIO;
}
/* Read the entries one by one */
for (; offset + atom_len <= scan_len; offset += atom_len) {
/* Get next atom */
@@ -4212,37 +4219,45 @@ static int orinoco_ioctl_getscan(struct
err = -ENODATA;
} else {
/* We have some results to push back to user space */
/* Translate to WE format */
- srq->length = orinoco_translate_scan(dev, extra,
- priv->scan_result,
- priv->scan_len);
-
- /* Return flags */
- srq->flags = (__u16) priv->scan_mode;
-
- /* Results are here, so scan no longer in progress */
- priv->scan_inprogress = 0;
-
- /* In any case, Scan results will be cleaned up in the
- * reset function and when exiting the driver.
- * The person triggering the scanning may never come to
- * pick the results, so we need to do it in those places.
- * Jean II */
+ int ret = orinoco_translate_scan(dev, extra,
+ priv->scan_result,
+ priv->scan_len);
+
+ if (ret < 0) {
+ err = ret;
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+ } else {
+ srq->length = ret;
+
+ /* Return flags */
+ srq->flags = (__u16) priv->scan_mode;
+
+ /* In any case, Scan results will be cleaned up in the
+ * reset function and when exiting the driver.
+ * The person triggering the scanning may never come to
+ * pick the results, so we need to do it in those places.
+ * Jean II */
#ifdef SCAN_SINGLE_READ
- /* If you enable this option, only one client (the first
- * one) will be able to read the result (and only one
- * time). If there is multiple concurent clients that
- * want to read scan results, this behavior is not
- * advisable - Jean II */
- kfree(priv->scan_result);
- priv->scan_result = NULL;
+ /* If you enable this option, only one client (the first
+ * one) will be able to read the result (and only one
+ * time). If there is multiple concurent clients that
+ * want to read scan results, this behavior is not
+ * advisable - Jean II */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
#endif /* SCAN_SINGLE_READ */
- /* Here, if too much time has elapsed since last scan,
- * we may want to clean up scan results... - Jean II */
+ /* Here, if too much time has elapsed since last scan,
+ * we may want to clean up scan results... - Jean II */
+ }
+
+ /* Scan is no longer in progress */
+ priv->scan_inprogress = 0;
}
orinoco_unlock(priv, &flags);
return err;
}
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 3/8] orinoco: Remove entry for Intel PRO/Wireless 2011B.
From: Pavel Roskin @ 2005-09-02 0:04 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree c88faac230cc9775445e5c644991c352e35c72a1 (from dce61aef99ceb57370b70222dc34d788666c0ac3)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 17:09:45 2005 -0400
Remove entry for Intel PRO/Wireless 2011B.
It is not supported by this driver because it has no firmware in
flash. spectrum_cs is needed for this device.
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -602,11 +602,10 @@ static char version[] __initdata = DRIVE
" (David Gibson <hermes-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>, "
"Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>, et al)";
static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001),
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 4/8] orinoco: Fix memory leak on error in processing hostscan frames.
From: Pavel Roskin @ 2005-09-02 0:05 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree ca955293cdfd3139e150d3b4fed3922a7eb651fb (from cb289b9f9b2a0f3ae7070a008f22e383b37526ee)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 19:08:00 2005 -0400
Fix memory leak on error in processing hostscan frames.
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -1284,12 +1284,14 @@ static void __orinoco_ev_info(struct net
break;
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
- if (err)
+ if (err) {
+ kfree(buf);
break;
+ }
#ifdef ORINOCO_DEBUG
{
int i;
printk(KERN_DEBUG "Scan result [%02X", buf[0]);
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 5/8] orinoco: Optimize orinoco_join_ap()
From: Pavel Roskin @ 2005-09-02 0:06 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree cb289b9f9b2a0f3ae7070a008f22e383b37526ee (from 56bfcdb38b3d04c1f8c1fd705e411f4be53b663c)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 19:05:16 2005 -0400
Optimize orinoco_join_ap() - break from loop once the requested
BSSID
is found.
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -1049,12 +1049,13 @@ static void orinoco_join_ap(struct net_d
struct join_req {
u8 bssid[ETH_ALEN];
u16 channel;
} __attribute__ ((packed)) req;
const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
- struct prism2_scan_apinfo *atom;
+ struct prism2_scan_apinfo *atom = NULL;
int offset = 4;
+ int found = 0;
u8 *buf;
u16 len;
/* Allocate buffer for scan results */
buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
@@ -1085,19 +1086,22 @@ static void orinoco_join_ap(struct net_d
/* Go through the scan results looking for the channel of the AP
* we were requested to join */
for (; offset + atom_len <= len; offset += atom_len) {
atom = (struct prism2_scan_apinfo *) (buf + offset);
- if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
- goto found;
+ if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+ found = 1;
+ break;
+ }
}
- DEBUG(1, "%s: Requested AP not found in scan results\n",
- dev->name);
- goto out;
+ if (! found) {
+ DEBUG(1, "%s: Requested AP not found in scan results\n",
+ dev->name);
+ goto out;
+ }
- found:
memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
req.channel = atom->channel; /* both are little-endian */
err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
&req);
if (err)
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 6/8] orinoco: Remove EXPERIMENTAL mark from PLX_HERMES, TMD_HERMES and PCI_HERMES.
From: Pavel Roskin @ 2005-09-02 0:07 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree ceb6695092be8dcdfe2dec6ee5097d613011489d (from 6b39374a27eb4be7e9d82145ae270ba02ea90dc8)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 14:50:10 2005 -0400
Remove EXPERIMENTAL mark from PLX_HERMES, TMD_HERMES and PCI_HERMES.
Those drivers have been used for a long time, and there have been very
few problem reports.
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -183,39 +183,33 @@ config APPLE_AIRPORT
built into the Macintosh iBook and other recent PowerPC-based
Macintosh machines. This is essentially a Lucent Orinoco card with
a non-standard interface
config PLX_HERMES
- tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)"
- depends on PCI && HERMES && EXPERIMENTAL
+ tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
+ depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in PLX9052 based PCI adaptors. These
adaptors are not a full PCMCIA controller but act as a more limited
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines. The Netgear
MA301 is such an adaptor.
- Support for these adaptors is so far still incomplete and buggy.
- You have been warned.
-
config TMD_HERMES
- tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)"
- depends on PCI && HERMES && EXPERIMENTAL
+ tristate "Hermes in TMD7160 based PCI adaptor support"
+ depends on PCI && HERMES
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in TMD7160 based PCI adaptors. These
adaptors are not a full PCMCIA controller but act as a more limited
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines.
- Support for these adaptors is so far still incomplete and buggy.
- You have been warned.
-
config PCI_HERMES
- tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)"
- depends on PCI && HERMES && EXPERIMENTAL
+ tristate "Prism 2.5 PCI 802.11b adaptor support"
+ depends on PCI && HERMES
help
Enable support for PCI and mini-PCI 802.11b wireless NICs based on
the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also
common. Some of the built-in wireless adaptors in laptops are of
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 7/8] orinoco: New driver - orinoco_nortel.
From: Pavel Roskin @ 2005-09-02 0:08 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree dce61aef99ceb57370b70222dc34d788666c0ac3 (from ceb6695092be8dcdfe2dec6ee5097d613011489d)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 15:50:55 2005 -0400
New driver - orinoco_nortel.
This is a driver for Nortel emobility PCI adaptors, which consist of an
Orinoco compatible PCMCIA card and a simple PCI-to-PCMCIA bridge. The
driver initializes the device and uses Orinoco core driver for actual
wireless networking.
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -203,10 +203,19 @@ config TMD_HERMES
orinoco) driver when used in TMD7160 based PCI adaptors. These
adaptors are not a full PCMCIA controller but act as a more limited
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines.
+config NORTEL_HERMES
+ tristate "Nortel emobility PCI adaptor support"
+ depends on PCI && HERMES
+ help
+ Enable support for PCMCIA cards supported by the "Hermes" (aka
+ orinoco) driver when used in Nortel emobility PCI adaptors. These
+ adaptors are not full PCMCIA controllers, but act as a more limited
+ PCI <-> PCMCIA bridge.
+
config PCI_HERMES
tristate "Prism 2.5 PCI 802.11b adaptor support"
depends on PCI && HERMES
help
Enable support for PCI and mini-PCI 802.11b wireless NICs based on
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -16,10 +16,11 @@ obj-$(CONFIG_HERMES) += orinoco.o herme
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
obj-$(CONFIG_APPLE_AIRPORT) += airport.o
obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
obj-$(CONFIG_ATMEL) += atmel.o
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
new file mode 100644
--- /dev/null
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -0,0 +1,324 @@
+/* orinoco_nortel.c
+ *
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter.
+ *
+ * Copyright (C) 2002 Tobias Hoffmann
+ * (C) 2003 Christoph Jungegger <disdos-Bv35esvkf38b1SvskN2V4Q@public.gmane.org>
+ *
+ * Some of this code is borrowed from orinoco_plx.c
+ * Copyright (C) 2001 Daniel Barlow
+ * Some of this code is borrowed from orinoco_pci.c
+ * Copyright (C) 2001 Jean Tourrilhes
+ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
+ * has been copied from it. linux-wlan-ng-0.1.10 is originally :
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#define DRIVER_NAME "orinoco_nortel"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/fcntl.h>
+
+#include <pcmcia/cisreg.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
+#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+
+
+/* Nortel specific data */
+struct nortel_pci_card {
+ unsigned long iobase1;
+ unsigned long iobase2;
+};
+
+/*
+ * Do a soft reset of the PCI card using the Configuration Option Register
+ * We need this to get going...
+ * This is the part of the code that is strongly inspired from wlan-ng
+ *
+ * Note bis : Don't try to access HERMES_CMD during the reset phase.
+ * It just won't work !
+ */
+static int nortel_pci_cor_reset(struct orinoco_private *priv)
+{
+ struct nortel_pci_card *card = priv->card;
+
+ /* Assert the reset until the card notice */
+ outw_p(8, card->iobase1 + 2);
+ inw(card->iobase2 + COR_OFFSET);
+ outw_p(0x80, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+
+ /* Give time for the card to recover from this hard effort */
+ outw_p(0, card->iobase2 + COR_OFFSET);
+ outw_p(0, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+
+ /* set COR as usual */
+ outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+
+ outw_p(0x228, card->iobase1 + 2);
+
+ return 0;
+}
+
+int nortel_pci_hw_init(struct nortel_pci_card *card)
+{
+ int i;
+ u32 reg;
+
+ /* setup bridge */
+ if (inw(card->iobase1) & 1) {
+ printk(KERN_ERR PFX "brg1 answer1 wrong\n");
+ return -EBUSY;
+ }
+ outw_p(0x118, card->iobase1 + 2);
+ outw_p(0x108, card->iobase1 + 2);
+ mdelay(30);
+ outw_p(0x8, card->iobase1 + 2);
+ for (i = 0; i < 30; i++) {
+ mdelay(30);
+ if (inw(card->iobase1) & 0x10) {
+ break;
+ }
+ }
+ if (i == 30) {
+ printk(KERN_ERR PFX "brg1 timed out\n");
+ return -EBUSY;
+ }
+ if (inw(card->iobase2 + 0xe0) & 1) {
+ printk(KERN_ERR PFX "brg2 answer1 wrong\n");
+ return -EBUSY;
+ }
+ if (inw(card->iobase2 + 0xe2) & 1) {
+ printk(KERN_ERR PFX "brg2 answer2 wrong\n");
+ return -EBUSY;
+ }
+ if (inw(card->iobase2 + 0xe4) & 1) {
+ printk(KERN_ERR PFX "brg2 answer3 wrong\n");
+ return -EBUSY;
+ }
+
+ /* set the PCMCIA COR-Register */
+ outw_p(COR_VALUE, card->iobase2 + COR_OFFSET);
+ mdelay(1);
+ reg = inw(card->iobase2 + COR_OFFSET);
+ if (reg != COR_VALUE) {
+ printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
+ reg);
+ return -EBUSY;
+ }
+
+ /* set leds */
+ outw_p(1, card->iobase1 + 10);
+ return 0;
+}
+
+static int nortel_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int err;
+ struct orinoco_private *priv;
+ struct nortel_pci_card *card;
+ struct net_device *dev;
+ void __iomem *iomem;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRIVER_NAME);
+ if (err != 0) {
+ printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+ goto fail_resources;
+ }
+
+ iomem = pci_iomap(pdev, 3, 0);
+ if (!iomem) {
+ err = -ENOMEM;
+ goto fail_map_io;
+ }
+
+ /* Allocate network device */
+ dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset);
+ if (!dev) {
+ printk(KERN_ERR PFX "Cannot allocate network device\n");
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ priv = netdev_priv(dev);
+ card = priv->card;
+ card->iobase1 = pci_resource_start(pdev, 0);
+ card->iobase2 = pci_resource_start(pdev, 1);
+ dev->base_addr = pci_resource_start(pdev, 2);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING);
+
+ printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, "
+ "io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr);
+
+ err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ dev->name, dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+ err = -EBUSY;
+ goto fail_irq;
+ }
+ dev->irq = pdev->irq;
+
+ err = nortel_pci_hw_init(card);
+ if (err) {
+ printk(KERN_ERR PFX "Hardware initialization failed\n");
+ goto fail;
+ }
+
+ err = nortel_pci_cor_reset(priv);
+ if (err) {
+ printk(KERN_ERR PFX "Initial reset failed\n");
+ goto fail;
+ }
+
+
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register network device\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ return 0;
+
+ fail:
+ free_irq(pdev->irq, dev);
+
+ fail_irq:
+ pci_set_drvdata(pdev, NULL);
+ free_orinocodev(dev);
+
+ fail_alloc:
+ pci_iounmap(pdev, iomem);
+
+ fail_map_io:
+ pci_release_regions(pdev);
+
+ fail_resources:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void __devexit nortel_pci_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct nortel_pci_card *card = priv->card;
+
+ /* clear leds */
+ outw_p(0, card->iobase1 + 10);
+
+ unregister_netdev(dev);
+ free_irq(dev->irq, dev);
+ pci_set_drvdata(pdev, NULL);
+ free_orinocodev(dev);
+ pci_iounmap(pdev, priv->hw.iobase);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+
+static struct pci_device_id nortel_pci_id_table[] = {
+ /* Nortel emobility PCI */
+ {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
+ {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, nortel_pci_id_table);
+
+static struct pci_driver nortel_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = nortel_pci_id_table,
+ .probe = nortel_pci_init_one,
+ .remove = __devexit_p(nortel_pci_remove_one),
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+ " (Tobias Hoffmann & Christoph Jungegger <disdos-Bv35esvkf38b1SvskN2V4Q@public.gmane.org>)";
+MODULE_AUTHOR("Christoph Jungegger <disdos-Bv35esvkf38b1SvskN2V4Q@public.gmane.org>");
+MODULE_DESCRIPTION
+ ("Driver for wireless LAN cards using the Nortel PCI bridge");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init nortel_pci_init(void)
+{
+ printk(KERN_DEBUG "%s\n", version);
+ return pci_module_init(&nortel_pci_driver);
+}
+
+static void __exit nortel_pci_exit(void)
+{
+ pci_unregister_driver(&nortel_pci_driver);
+ ssleep(1);
+}
+
+module_init(nortel_pci_init);
+module_exit(nortel_pci_exit);
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* [PATCH 8/8] orinoco: New driver - spectrum_cs.
From: Pavel Roskin @ 2005-09-02 0:10 UTC (permalink / raw)
To: Orinoco Development List, netdev-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
diff-tree dee4f325520d4ea29397dd67ca657b7235bb1790 (from c88faac230cc9775445e5c644991c352e35c72a1)
Author: Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
Date: Thu Sep 1 17:46:39 2005 -0400
New driver - spectrum_cs.
Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
Symbol Wireless Networker LA4100, CompactFlash cards by Socket
Communications and Intel PRO/Wireless 2011B.
The driver implements Symbol firmware download. The rest is handled
in hermes.c and orinoco.c.
Utilities for downloading the Symbol firmware are available at
http://sourceforge.net/projects/orinoco/
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -269,10 +269,23 @@ config PCMCIA_HERMES
You will also very likely also need the Wireless Tools in order to
configure your card and that /etc/pcmcia/wireless.opts works:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+config PCMCIA_SPECTRUM
+ tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
+ depends on NET_RADIO && PCMCIA && HERMES
+ ---help---
+
+ This is a driver for 802.11b cards using RAM-loadable Symbol
+ firmware, such as Symbol Wireless Networker LA4100, CompactFlash
+ cards by Socket Communications and Intel PRO/Wireless 2011B.
+
+ This driver requires firmware download on startup. Utilities
+ for downloading Symbol firmware are available at
+ <http://sourceforge.net/projects/orinoco/>
+
config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
---help---
This is the standard Linux driver to support Cisco/Aironet PCMCIA
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -17,10 +17,11 @@ obj-$(CONFIG_PCMCIA_HERMES) += orinoco_c
obj-$(CONFIG_APPLE_AIRPORT) += airport.o
obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
obj-$(CONFIG_ATMEL) += atmel.o
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
new file mode 100644
--- /dev/null
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -0,0 +1,1120 @@
+/*
+ * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
+ * Symbol Wireless Networker LA4100, CompactFlash cards by Socket
+ * Communications and Intel PRO/Wireless 2011B.
+ *
+ * The driver implements Symbol firmware download. The rest is handled
+ * in hermes.c and orinoco.c.
+ *
+ * Utilities for downloading the Symbol firmware are available at
+ * http://sourceforge.net/projects/orinoco/
+ *
+ * Copyright (C) 2002-2005 Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>
+ * Portions based on orinoco_cs.c:
+ * Copyright (C) David Gibson, Linuxcare Australia
+ * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
+ * Copyright (C) Symbol Technologies.
+ *
+ * See copyright notice in file orinoco.c.
+ */
+
+#define DRIVER_NAME "spectrum_cs"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/config.h>
+#ifdef __IN_PCMCIA_PACKAGE__
+#include <pcmcia/k_compat.h>
+#endif /* __IN_PCMCIA_PACKAGE__ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "orinoco.h"
+
+/*
+ * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into
+ * the driver. Use get_symbol_fw script to generate spectrum_fw.h and
+ * copy it to the same directory as spectrum_cs.c.
+ *
+ * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the
+ * runtime using hotplug. Use the same get_symbol_fw script to generate
+ * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the
+ * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and
+ * make sure that you have hotplug installed and enabled in the kernel.
+ */
+/* #define SPECTRUM_FW_INCLUDED 1 */
+
+#ifdef SPECTRUM_FW_INCLUDED
+/* Header with the firmware */
+#include "spectrum_fw.h"
+#else /* !SPECTRUM_FW_INCLUDED */
+#include <linux/firmware.h>
+static unsigned char *primsym;
+static unsigned char *secsym;
+static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
+static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
+#endif /* !SPECTRUM_FW_INCLUDED */
+
+/********************************************************************/
+/* Module stuff */
+/********************************************************************/
+
+MODULE_AUTHOR("Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>");
+MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Module parameters */
+
+/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+static int ignore_cis_vcc; /* = 0 */
+module_param(ignore_cis_vcc, int, 0);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
+
+/********************************************************************/
+/* Magic constants */
+/********************************************************************/
+
+/*
+ * The dev_info variable is the "key" that is used to match up this
+ * device driver with appropriate cards, through the card
+ * configuration database.
+ */
+static dev_info_t dev_info = DRIVER_NAME;
+
+/********************************************************************/
+/* Data structures */
+/********************************************************************/
+
+/* PCMCIA specific device information (goes in the card field of
+ * struct orinoco_private */
+struct orinoco_pccard {
+ dev_link_t link;
+ dev_node_t node;
+};
+
+/*
+ * A linked list of "instances" of the device. Each actual PCMCIA
+ * card corresponds to one device instance, and is described by one
+ * dev_link_t structure (defined in ds.h).
+ */
+static dev_link_t *dev_list; /* = NULL */
+
+/********************************************************************/
+/* Function prototypes */
+/********************************************************************/
+
+/* device methods */
+static int spectrum_cs_hard_reset(struct orinoco_private *priv);
+
+/* PCMCIA gumpf */
+static void spectrum_cs_config(dev_link_t * link);
+static void spectrum_cs_release(dev_link_t * link);
+static int spectrum_cs_event(event_t event, int priority,
+ event_callback_args_t * args);
+
+static dev_link_t *spectrum_cs_attach(void);
+static void spectrum_cs_detach(dev_link_t *);
+
+/********************************************************************/
+/* Firmware downloader */
+/********************************************************************/
+
+/* Position of PDA in the adapter memory */
+#define EEPROM_ADDR 0x3000
+#define EEPROM_LEN 0x200
+#define PDA_OFFSET 0x100
+
+#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET)
+#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2)
+
+/* Constants for the CISREG_CCSR register */
+#define HCR_RUN 0x07 /* run firmware after reset */
+#define HCR_IDLE 0x0E /* don't run firmware after reset */
+#define HCR_MEM16 0x10 /* memory width bit, should be preserved */
+
+/*
+ * AUX port access. To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register. Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* End markers */
+#define PDI_END 0x00000000 /* End of PDA */
+#define BLOCK_END 0xFFFFFFFF /* Last image block */
+#define TEXT_END 0x1A /* End of text header */
+
+/*
+ * The following structures have little-endian fields denoted by
+ * the leading underscore. Don't access them directly - use inline
+ * functions defined below.
+ */
+
+/*
+ * The binary image to be downloaded consists of series of data blocks.
+ * Each block has the following structure.
+ */
+struct dblock {
+ u32 _addr; /* adapter address where to write the block */
+ u16 _len; /* length of the data only, in bytes */
+ char data[0]; /* data to be written */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data References are located in in the image after the last data
+ * block. They refer to areas in the adapter memory where the plug data
+ * items with matching ID should be written.
+ */
+struct pdr {
+ u32 _id; /* record ID */
+ u32 _addr; /* adapter address where to write the data */
+ u32 _len; /* expected length of the data, in bytes */
+ char next[0]; /* next PDR starts here */
+} __attribute__ ((packed));
+
+
+/*
+ * Plug Data Items are located in the EEPROM read from the adapter by
+ * primary firmware. They refer to the device-specific data that should
+ * be plugged into the secondary firmware.
+ */
+struct pdi {
+ u16 _len; /* length of ID and data, in words */
+ u16 _id; /* record ID */
+ char data[0]; /* plug data */
+} __attribute__ ((packed));;
+
+
+/* Functions for access to little-endian data */
+static inline u32
+dblock_addr(const struct dblock *blk)
+{
+ return le32_to_cpu(blk->_addr);
+}
+
+static inline u32
+dblock_len(const struct dblock *blk)
+{
+ return le16_to_cpu(blk->_len);
+}
+
+static inline u32
+pdr_id(const struct pdr *pdr)
+{
+ return le32_to_cpu(pdr->_id);
+}
+
+static inline u32
+pdr_addr(const struct pdr *pdr)
+{
+ return le32_to_cpu(pdr->_addr);
+}
+
+static inline u32
+pdr_len(const struct pdr *pdr)
+{
+ return le32_to_cpu(pdr->_len);
+}
+
+static inline u32
+pdi_id(const struct pdi *pdi)
+{
+ return le16_to_cpu(pdi->_id);
+}
+
+/* Return length of the data only, in bytes */
+static inline u32
+pdi_len(const struct pdi *pdi)
+{
+ return 2 * (le16_to_cpu(pdi->_len) - 1);
+}
+
+
+/* Set address of the auxiliary port */
+static inline void
+spectrum_aux_setaddr(hermes_t *hw, u32 addr)
+{
+ hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+ hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+
+/* Open access to the auxiliary port */
+static int
+spectrum_aux_open(hermes_t *hw)
+{
+ int i;
+
+ /* Already open? */
+ if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
+ return 0;
+
+ hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+ hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+ hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+ hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
+
+ for (i = 0; i < 20; i++) {
+ udelay(10);
+ if (hermes_read_reg(hw, HERMES_CONTROL) ==
+ HERMES_AUX_ENABLED)
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+
+#define CS_CHECK(fn, ret) \
+ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+/*
+ * Reset the card using configuration registers COR and CCSR.
+ * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
+ */
+static int
+spectrum_reset(dev_link_t *link, int idle)
+{
+ int last_ret, last_fn;
+ conf_reg_t reg;
+ u_int save_cor;
+
+ /* Doing it if hardware is gone is guaranteed crash */
+ if (!(link->state & DEV_CONFIG))
+ return -ENODEV;
+
+ /* Save original COR value */
+ reg.Function = 0;
+ reg.Action = CS_READ;
+ reg.Offset = CISREG_COR;
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ save_cor = reg.Value;
+
+ /* Soft-Reset card */
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ reg.Value = (save_cor | COR_SOFT_RESET);
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ udelay(1000);
+
+ /* Read CCSR */
+ reg.Action = CS_READ;
+ reg.Offset = CISREG_CCSR;
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+
+ /*
+ * Start or stop the firmware. Memory width bit should be
+ * preserved from the value we've just read.
+ */
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_CCSR;
+ reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ udelay(1000);
+
+ /* Restore original COR configuration index */
+ reg.Action = CS_WRITE;
+ reg.Offset = CISREG_COR;
+ reg.Value = (save_cor & ~COR_SOFT_RESET);
+ CS_CHECK(AccessConfigurationRegister,
+ pcmcia_access_configuration_register(link->handle, ®));
+ udelay(1000);
+ return 0;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ return -ENODEV;
+}
+
+
+/*
+ * Scan PDR for the record with the specified RECORD_ID.
+ * If it's not found, return NULL.
+ */
+static struct pdr *
+spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
+{
+ struct pdr *pdr = first_pdr;
+
+ while (pdr_id(pdr) != PDI_END) {
+ /*
+ * PDR area is currently not terminated by PDI_END.
+ * It's followed by CRC records, which have the type
+ * field where PDR has length. The type can be 0 or 1.
+ */
+ if (pdr_len(pdr) < 2)
+ return NULL;
+
+ /* If the record ID matches, we are done */
+ if (pdr_id(pdr) == record_id)
+ return pdr;
+
+ pdr = (struct pdr *) pdr->next;
+ }
+ return NULL;
+}
+
+
+/* Process one Plug Data Item - find corresponding PDR and plug it */
+static int
+spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
+{
+ struct pdr *pdr;
+
+ /* Find the PDI corresponding to this PDR */
+ pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
+
+ /* No match is found, safe to ignore */
+ if (!pdr)
+ return 0;
+
+ /* Lengths of the data in PDI and PDR must match */
+ if (pdi_len(pdi) != pdr_len(pdr))
+ return -EINVAL;
+
+ /* do the actual plugging */
+ spectrum_aux_setaddr(hw, pdr_addr(pdr));
+ hermes_write_words(hw, HERMES_AUXDATA, pdi->data,
+ pdi_len(pdi) / 2);
+
+ return 0;
+}
+
+
+/* Read PDA from the adapter */
+static int
+spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len)
+{
+ int ret;
+ int pda_size;
+
+ /* Issue command to read EEPROM */
+ ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+ if (ret)
+ return ret;
+
+ /* Open auxiliary port */
+ ret = spectrum_aux_open(hw);
+ if (ret)
+ return ret;
+
+ /* read PDA from EEPROM */
+ spectrum_aux_setaddr(hw, PDA_ADDR);
+ hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
+
+ /* Check PDA length */
+ pda_size = le16_to_cpu(pda[0]);
+ if (pda_size > pda_len)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+/* Parse PDA and write the records into the adapter */
+static int
+spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
+ u16 *pda)
+{
+ int ret;
+ struct pdi *pdi;
+ struct pdr *first_pdr;
+ const struct dblock *blk = first_block;
+
+ /* Skip all blocks to locate Plug Data References */
+ while (dblock_addr(blk) != BLOCK_END)
+ blk = (struct dblock *) &blk->data[dblock_len(blk)];
+
+ first_pdr = (struct pdr *) blk;
+
+ /* Go through every PDI and plug them into the adapter */
+ pdi = (struct pdi *) (pda + 2);
+ while (pdi_id(pdi) != PDI_END) {
+ ret = spectrum_plug_pdi(hw, first_pdr, pdi);
+ if (ret)
+ return ret;
+
+ /* Increment to the next PDI */
+ pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
+ }
+ return 0;
+}
+
+
+/* Load firmware blocks into the adapter */
+static int
+spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
+{
+ const struct dblock *blk;
+ u32 blkaddr;
+ u32 blklen;
+
+ blk = first_block;
+ blkaddr = dblock_addr(blk);
+ blklen = dblock_len(blk);
+
+ while (dblock_addr(blk) != BLOCK_END) {
+ spectrum_aux_setaddr(hw, blkaddr);
+ hermes_write_words(hw, HERMES_AUXDATA, blk->data,
+ blklen / 2);
+
+ blk = (struct dblock *) &blk->data[blklen];
+ blkaddr = dblock_addr(blk);
+ blklen = dblock_len(blk);
+ }
+ return 0;
+}
+
+
+/*
+ * Process a firmware image - stop the card, load the firmware, reset
+ * the card and make sure it responds. For the secondary firmware take
+ * care of the PDA - read it and then write it on top of the firmware.
+ */
+static int
+spectrum_dl_image(hermes_t *hw, dev_link_t *link,
+ const unsigned char *image)
+{
+ int ret;
+ const unsigned char *ptr;
+ const struct dblock *first_block;
+
+ /* Plug Data Area (PDA) */
+ u16 pda[PDA_WORDS];
+
+ /* Binary block begins after the 0x1A marker */
+ ptr = image;
+ while (*ptr++ != TEXT_END);
+ first_block = (const struct dblock *) ptr;
+
+ /* Read the PDA */
+ if (image != primsym) {
+ ret = spectrum_read_pda(hw, pda, sizeof(pda));
+ if (ret)
+ return ret;
+ }
+
+ /* Stop the firmware, so that it can be safely rewritten */
+ ret = spectrum_reset(link, 1);
+ if (ret)
+ return ret;
+
+ /* Program the adapter with new firmware */
+ ret = spectrum_load_blocks(hw, first_block);
+ if (ret)
+ return ret;
+
+ /* Write the PDA to the adapter */
+ if (image != primsym) {
+ ret = spectrum_apply_pda(hw, first_block, pda);
+ if (ret)
+ return ret;
+ }
+
+ /* Run the firmware */
+ ret = spectrum_reset(link, 0);
+ if (ret)
+ return ret;
+
+ /* Reset hermes chip and make sure it responds */
+ ret = hermes_init(hw);
+
+ /* hermes_reset() should return 0 with the secondary firmware */
+ if (image != primsym && ret != 0)
+ return -ENODEV;
+
+ /* And this should work with any firmware */
+ if (!hermes_present(hw))
+ return -ENODEV;
+
+ return 0;
+}
+
+
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+spectrum_dl_firmware(hermes_t *hw, dev_link_t *link)
+{
+ int ret;
+ client_handle_t handle = link->handle;
+
+#ifndef SPECTRUM_FW_INCLUDED
+ const struct firmware *fw_entry;
+
+ if (request_firmware(&fw_entry, primary_fw_name,
+ &handle_to_dev(handle)) == 0) {
+ primsym = fw_entry->data;
+ } else {
+ printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+ primary_fw_name);
+ return -ENOENT;
+ }
+
+ if (request_firmware(&fw_entry, secondary_fw_name,
+ &handle_to_dev(handle)) == 0) {
+ secsym = fw_entry->data;
+ } else {
+ printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+ secondary_fw_name);
+ return -ENOENT;
+ }
+#endif
+
+ /* Load primary firmware */
+ ret = spectrum_dl_image(hw, link, primsym);
+ if (ret) {
+ printk(KERN_ERR PFX "Primary firmware download failed\n");
+ return ret;
+ }
+
+ /* Load secondary firmware */
+ ret = spectrum_dl_image(hw, link, secsym);
+
+ if (ret) {
+ printk(KERN_ERR PFX "Secondary firmware download failed\n");
+ }
+
+ return ret;
+}
+
+/********************************************************************/
+/* Device methods */
+/********************************************************************/
+
+static int
+spectrum_cs_hard_reset(struct orinoco_private *priv)
+{
+ struct orinoco_pccard *card = priv->card;
+ dev_link_t *link = &card->link;
+ int err;
+
+ if (!hermes_present(&priv->hw)) {
+ /* The firmware needs to be reloaded */
+ if (spectrum_dl_firmware(&priv->hw, &card->link) != 0) {
+ printk(KERN_ERR PFX "Firmware download failed\n");
+ err = -ENODEV;
+ }
+ } else {
+ /* Soft reset using COR and HCR */
+ spectrum_reset(link, 0);
+ }
+
+ return 0;
+}
+
+/********************************************************************/
+/* PCMCIA stuff */
+/********************************************************************/
+
+/*
+ * This creates an "instance" of the driver, allocating local data
+ * structures for one device. The device is registered with Card
+ * Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a card
+ * insertion event. */
+static dev_link_t *
+spectrum_cs_attach(void)
+{
+ struct net_device *dev;
+ struct orinoco_private *priv;
+ struct orinoco_pccard *card;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret;
+
+ dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
+ if (! dev)
+ return NULL;
+ priv = netdev_priv(dev);
+ card = priv->card;
+
+ /* Link both structures together */
+ link = &card->link;
+ link->priv = dev;
+
+ /* Interrupt setup */
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Handler = orinoco_interrupt;
+ link->irq.Instance = dev;
+
+ /* General socket configuration defaults can go here. In this
+ * client, we assume very little, and rely on the CIS for
+ * almost everything. In most clients, many details (i.e.,
+ * number, sizes, and attributes of IO windows) are fixed by
+ * the nature of the device, and can be hard-wired here. */
+ link->conf.Attributes = 0;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Register with Card Services */
+ /* FIXME: need a lock? */
+ link->next = dev_list;
+ dev_list = link;
+
+ client_reg.dev_info = &dev_info;
+ client_reg.Version = 0x0210; /* FIXME: what does this mean? */
+ client_reg.event_callback_args.client_data = link;
+
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ spectrum_cs_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* spectrum_cs_attach */
+
+/*
+ * This deletes a driver "instance". The device is de-registered with
+ * Card Services. If it has been released, all local data structures
+ * are freed. Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void spectrum_cs_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+ struct net_device *dev = link->priv;
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link)
+ break;
+
+ BUG_ON(*linkp == NULL);
+
+ if (link->state & DEV_CONFIG)
+ spectrum_cs_release(link);
+
+ /* Break the link with Card Services */
+ if (link->handle)
+ pcmcia_deregister_client(link->handle);
+
+ /* Unlink device structure, and free it */
+ *linkp = link->next;
+ DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev);
+ if (link->dev) {
+ DEBUG(0, PFX "About to unregister net device %p\n",
+ dev);
+ unregister_netdev(dev);
+ }
+ free_orinocodev(dev);
+} /* spectrum_cs_detach */
+
+/*
+ * spectrum_cs_config() is scheduled to run after a CARD_INSERTION
+ * event is received, to configure the PCMCIA socket, and to make the
+ * device available to the system.
+ */
+
+static void
+spectrum_cs_config(dev_link_t *link)
+{
+ struct net_device *dev = link->priv;
+ client_handle_t handle = link->handle;
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_pccard *card = priv->card;
+ hermes_t *hw = &priv->hw;
+ int last_fn, last_ret;
+ u_char buf[64];
+ config_info_t conf;
+ cisinfo_t info;
+ tuple_t tuple;
+ cisparse_t parse;
+ void __iomem *mem;
+
+ CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info));
+
+ /*
+ * This reads the card's CONFIG tuple to find its
+ * configuration registers.
+ */
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ /* Look up the current Vcc */
+ CS_CHECK(GetConfigurationInfo,
+ pcmcia_get_configuration_info(handle, &conf));
+ link->conf.Vcc = conf.Vcc;
+
+ /*
+ * In this loop, we scan the CIS for configuration table
+ * entries, each of which describes a valid card
+ * configuration, including voltage, IO window, memory window,
+ * and interrupt settings.
+ *
+ * We make no assumptions about the card to be configured: we
+ * use just the information available in the CIS. In an ideal
+ * world, this would work for any PCMCIA card, but it requires
+ * a complete and accurate CIS. In practice, a driver usually
+ * "knows" most of these things without consulting the CIS,
+ * and most client drivers will only use the CIS to fill in
+ * implementation-defined details.
+ */
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ while (1) {
+ cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+ cistpl_cftable_entry_t dflt = { .index = 0 };
+
+ if ( (pcmcia_get_tuple_data(handle, &tuple) != 0)
+ || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0))
+ goto next_entry;
+
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ dflt = *cfg;
+ if (cfg->index == 0)
+ goto next_entry;
+ link->conf.ConfigIndex = cfg->index;
+
+ /* Does this card need audio output? */
+ if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+ link->conf.Attributes |= CONF_ENABLE_SPKR;
+ link->conf.Status = CCSR_AUDIO_ENA;
+ }
+
+ /* Use power settings for Vcc and Vpp if present */
+ /* Note that the CIS values need to be rescaled */
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+ DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+ if (!ignore_cis_vcc)
+ goto next_entry;
+ }
+ } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
+ DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+ if(!ignore_cis_vcc)
+ goto next_entry;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ /* Do we need to allocate an interrupt? */
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+ /* IO window settings */
+ link->io.NumPorts1 = link->io.NumPorts2 = 0;
+ if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+ cistpl_io_t *io =
+ (cfg->io.nwin) ? &cfg->io : &dflt.io;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(io->flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 =
+ IO_DATA_PATH_WIDTH_16;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 =
+ IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines =
+ io->flags & CISTPL_IO_LINES_MASK;
+ link->io.BasePort1 = io->win[0].base;
+ link->io.NumPorts1 = io->win[0].len;
+ if (io->nwin > 1) {
+ link->io.Attributes2 =
+ link->io.Attributes1;
+ link->io.BasePort2 = io->win[1].base;
+ link->io.NumPorts2 = io->win[1].len;
+ }
+
+ /* This reserves IO space but doesn't actually enable it */
+ if (pcmcia_request_io(link->handle, &link->io) != 0)
+ goto next_entry;
+ }
+
+
+ /* If we got this far, we're cool! */
+
+ break;
+
+ next_entry:
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ last_ret = pcmcia_get_next_tuple(handle, &tuple);
+ if (last_ret == CS_NO_MORE_ITEMS) {
+ printk(KERN_ERR PFX "GetNextTuple(): No matching "
+ "CIS configuration. Maybe you need the "
+ "ignore_cis_vcc=1 parameter.\n");
+ goto cs_failed;
+ }
+ }
+
+ /*
+ * Allocate an interrupt line. Note that this does not assign
+ * a handler to the interrupt, unless the 'Handler' member of
+ * the irq structure is initialized.
+ */
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+
+ /* We initialize the hermes structure before completing PCMCIA
+ * configuration just in case the interrupt handler gets
+ * called. */
+ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+ if (!mem)
+ goto cs_failed;
+
+ hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+
+ /*
+ * This actually configures the PCMCIA socket -- setting up
+ * the I/O windows and the interrupt mapping, and putting the
+ * card and host interface into "Memory and IO" mode.
+ */
+ CS_CHECK(RequestConfiguration,
+ pcmcia_request_configuration(link->handle, &link->conf));
+
+ /* Ok, we have the configuration, prepare to register the netdev */
+ dev->base_addr = link->io.BasePort1;
+ dev->irq = link->irq.AssignedIRQ;
+ SET_MODULE_OWNER(dev);
+ card->node.major = card->node.minor = 0;
+
+ /* Reset card and download firmware */
+ if (spectrum_cs_hard_reset(priv) != 0) {
+ goto failed;
+ }
+
+ SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+ /* Tell the stack we exist */
+ if (register_netdev(dev) != 0) {
+ printk(KERN_ERR PFX "register_netdev() failed\n");
+ goto failed;
+ }
+
+ /* At this point, the dev_node_t structure(s) needs to be
+ * initialized and arranged in a linked list at link->dev. */
+ strcpy(card->node.dev_name, dev->name);
+ link->dev = &card->node; /* link->dev being non-NULL is also
+ used to indicate that the
+ net_device has been registered */
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ /* Finally, report what we've done */
+ printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
+ dev->name, link->conf.ConfigIndex,
+ link->conf.Vcc / 10, link->conf.Vcc % 10);
+ if (link->conf.Vpp1)
+ printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+ link->conf.Vpp1 % 10);
+ printk(", irq %d", link->irq.AssignedIRQ);
+ if (link->io.NumPorts1)
+ printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ link->io.BasePort1 + link->io.NumPorts1 - 1);
+ if (link->io.NumPorts2)
+ printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ link->io.BasePort2 + link->io.NumPorts2 - 1);
+ printk("\n");
+
+ return;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+
+ failed:
+ spectrum_cs_release(link);
+} /* spectrum_cs_config */
+
+/*
+ * After a card is removed, spectrum_cs_release() will unregister the
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+spectrum_cs_release(dev_link_t *link)
+{
+ struct net_device *dev = link->priv;
+ struct orinoco_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ /* We're committed to taking the device away now, so mark the
+ * hardware as unavailable */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Don't bother checking to see if these succeed or not */
+ pcmcia_release_configuration(link->handle);
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ if (link->irq.AssignedIRQ)
+ pcmcia_release_irq(link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+ if (priv->hw.iobase)
+ ioport_unmap(priv->hw.iobase);
+} /* spectrum_cs_release */
+
+/*
+ * The card status event handler. Mostly, this schedules other stuff
+ * to run after an event is received.
+ */
+static int
+spectrum_cs_event(event_t event, int priority,
+ event_callback_args_t * args)
+{
+ dev_link_t *link = args->client_data;
+ struct net_device *dev = link->priv;
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = 0;
+ unsigned long flags;
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ break;
+
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ spectrum_cs_config(link);
+ break;
+
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ /* Mark the device as stopped, to block IO until later */
+ if (link->state & DEV_CONFIG) {
+ /* This is probably racy, but I can't think of
+ a better way, short of rewriting the PCMCIA
+ layer to not suck :-( */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ err = __orinoco_down(dev);
+ if (err)
+ printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
+ dev->name,
+ event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
+ err);
+
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ pcmcia_release_configuration(link->handle);
+ }
+ break;
+
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ /* FIXME: should we double check that this is
+ * the same card as we had before */
+ pcmcia_request_configuration(link->handle, &link->conf);
+ netif_device_attach(dev);
+ priv->hw_unavailable--;
+ schedule_work(&priv->reset_work);
+ }
+ break;
+ }
+
+ return err;
+} /* spectrum_cs_event */
+
+/********************************************************************/
+/* Module initialization */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+ " (Pavel Roskin <proski-mXXj517/zsQ@public.gmane.org>,"
+ " David Gibson <hermes-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>, et al)";
+
+static struct pcmcia_device_id spectrum_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */
+ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
+ PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
+
+static struct pcmcia_driver orinoco_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRIVER_NAME,
+ },
+ .attach = spectrum_cs_attach,
+ .event = spectrum_cs_event,
+ .detach = spectrum_cs_detach,
+ .id_table = spectrum_cs_ids,
+};
+
+static int __init
+init_spectrum_cs(void)
+{
+ printk(KERN_DEBUG "%s\n", version);
+
+ return pcmcia_register_driver(&orinoco_driver);
+}
+
+static void __exit
+exit_spectrum_cs(void)
+{
+ pcmcia_unregister_driver(&orinoco_driver);
+ BUG_ON(dev_list != NULL);
+}
+
+module_init(init_spectrum_cs);
+module_exit(exit_spectrum_cs);
--
Regards,
Pavel Roskin
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
^ permalink raw reply
* Re: Possible BUG in IPv4 TCP window handling, all recent 2.4.x/2.6.x kernels
From: John Heffner @ 2005-09-02 2:51 UTC (permalink / raw)
To: Ion Badulescu; +Cc: David S. Miller, linux-net, linux-kernel, netdev
In-Reply-To: <Pine.LNX.4.61.0509011845040.6083@guppy.limebrokerage.com>
On Sep 1, 2005, at 6:53 PM, Ion Badulescu wrote:
>
> A few minutes later it has finally caught up to present time and it
> starts receiving smaller packets containing real-time data. The TCP
> window is still 16534 at this point.
>
> [tcpdump output removed]
>
> This is where things start going bad. The window starts shrinking from
> 15340 all the way down to 2355 over the course of 0.3 seconds. Notice
> the many duplicate acks that serve no purpose (there are no lost
> packets and the tcpdump is taken on the receiver so there is no
> packets/acks crossed in flight).
I have an idea why this is going on. Packets are pre-allocated by the
driver to be a max packet size, so when you send small packets, it
wastes a lot of memory. Currently Linux uses the packets at the
beginning of a connection to make a guess at how best to advertise its
window so as not to overflow the socket's memory bounds. Since you
start out with big segments then go to small ones, this is defeating
that mechanism. It's actually documented in the comments in
tcp_input.c. :)
* The scheme does not work when sender sends good segments opening
* window and then starts to feed us spagetti. But it should work
* in common situations. Otherwise, we have to rely on queue collapsing.
If you overflow the socket's memory bound, it ends up calling
tcp_clamp_window(). (I'm not sure this is really the right thing to do
here before trying to collapse the queue.) If the receiving
application doesn't fall too far behind, it might help you to set a
much larger receiver buffer.
-John
^ 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