* new driver for IBM ethernet chip
From: Christoph Raisch @ 2006-06-02 11:02 UTC (permalink / raw)
To: netdev; +Cc: Marcus Eder, Jan-Bernd Themann
We're currently developing a new Ethernet device driver for a 10G IBM chip
for System p. (ppc64)
A later version of the driver should end up in mainline kernel.
How should we proceed to get first comments by the community?
Either post this code as a patch to netdev or
put a full tarball on for example sourceforge?
Gruss / Regards . . . Christoph Raisch
christoph raisch, HCAD teamlead, IODF2 (d/3627), ibm boeblingen lab,
phone: (+49/0)7031-16 4584, fax: -16 2042, loc: 71032-05-003, internet:
raisch@de.ibm.com
^ permalink raw reply
* Re: [PATCH] softmac: Fix handling of authentication failure
From: John W. Linville @ 2006-06-02 12:04 UTC (permalink / raw)
To: Daniel Drake; +Cc: Larry Finger, netdev, johannes
In-Reply-To: <44800E74.9070605@gentoo.org>
On Fri, Jun 02, 2006 at 11:09:56AM +0100, Daniel Drake wrote:
> Larry Finger wrote:
> >This statement fails to compile on my system using Linus' tree, because
> >ieee80211softmac_disassoc needs a second argument - the reason. It seems
> >as if WLAN_REASON_PREV_AUTH_NOT_VALID would be appropriate.
>
> Thanks for pointing that out. This patch depends on a patch titled
> "softmac: deauthentication implies deassociation" which is apparently
> not present in Linus' tree.
That patch is in the upstream branch (also available in the master
branch) of wireless-2.6, which is probably what anyone doing wireless
patches should(*) be using.
The approved release process only allows for non-bugfix patches
in the first two weeks after a Linus blesses a new kernel release.
After that only bugfixes are allowed, with non-bugfix patches getting
queued for the next merge window. The upstream branch represents
that queue of patches.
Hth!
John
(*) The exception being those workign on Devicescape-related patches,
who should be working off the master branch of wireless-dev.
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply
* Re: 2.6.17-rc4: netfilter LOG messages truncated via NETCONSOLE
From: Frank van Maarseveen @ 2006-06-02 12:35 UTC (permalink / raw)
To: Patrick McHardy; +Cc: linux-kernel, Kernel Netdev Mailing List
In-Reply-To: <447F2537.1080807@trash.net>
On Thu, Jun 01, 2006 at 07:34:47PM +0200, Patrick McHardy wrote:
> Frank van Maarseveen wrote:
> > ok, now "tc -s -d qdisc show" says (after noticing missing netconsole
> > packets):
> >
> > qdisc pfifo_fast 0: dev eth0 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
> > Sent 155031 bytes 2067 pkt (dropped 0, overlimits 0 requeues 0)
> > backlog 0b 0p requeues 0
>
>
> Mhh no dropped packets. I tried to reproduce the problem by changing
> netconsole to always use the dev_queue_xmit path, but works flawlessly
> for me. Please try to find out if the packets are lost before or after
> the qdisc by looking at the packet counter.
qdisc pfifo_fast 0: dev eth0 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 155031 bytes 2067 pkt (dropped 0, overlimits 0 requeues 0)
^^^^
This packet counter increases by 17: the TCP RST plus 16 netconsole
packets which are received. But it should have been 27 (TCP RST plus 26):
10 are missing (I thought 9 but it's 10).
>
> BTW: You still haven't sent me the packet dump (from the originating
> machine).
tcpdump:
10:50:22.811044 00:12:3f:85:17:52 > 00:08:c7:69:29:ae, ethertype IPv4 (0x0800), length 74: IP espoo.38629 > posio.21212: S 2489079094:2489079094(0) win 5840 <mss 1460,sackOK,timestamp 1359482768 0,nop,wscale 7>
10:50:22.811679 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 54: IP posio.21212 > espoo.38629: R 0:0(0) ack 2489079095 win 0
10:50:22.811731 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 55: IP posio.6665 > espoo.syslog: UDP, length: 13
10:50:22.811738 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 46: IP posio.6665 > espoo.syslog: UDP, length: 4
10:50:22.811745 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811752 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811760 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811766 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811773 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811780 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811787 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811795 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811801 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811809 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811816 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811823 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811830 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
10:50:22.811839 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
On "espoo" I do a "netcat posio 21212" to trigger the netfilter rule on
posio (there's only 1 rule):
Chain INPUT (policy ACCEPT 2876 packets, 743K bytes)
pkts bytes target prot opt in out source destination
1 60 LOG tcp -- * * 172.17.1.64 0.0.0.0/0 tcp dpt:21212 LOG flags 0 level 4
The netfilter message is sent back via netconsole from "posio" to "espoo"
except for 10 packets. This is a tcpdump done after rebooting "posio"
to 2.6.13.2 showing how it should have looked:
12:28:29.900384 00:12:3f:85:17:52 > 00:08:c7:69:29:ae, ethertype IPv4 (0x0800), length 74: IP espoo.45517 > posio.21212: S 122190451:122190451(0) win 5840 <mss 1460,sackOK,timestamp 1365370072 0,nop,wscale 7>
12:28:29.900939 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 54: IP posio.21212 > espoo.45517: R 0:0(0) ack 122190452 win 0
12:28:29.900995 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 55: IP posio.6665 > espoo.syslog: UDP, length: 13
12:28:29.901026 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 46: IP posio.6665 > espoo.syslog: UDP, length: 4
12:28:29.901055 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901082 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901112 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901158 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901185 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901212 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901238 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901275 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901301 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901308 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901314 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901319 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901326 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901332 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 45: IP posio.6665 > espoo.syslog: UDP, length: 3
12:28:29.901342 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901348 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901354 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901360 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901366 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901372 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901405 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901411 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901418 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
12:28:29.901423 00:08:c7:69:29:ae > 00:12:3f:85:17:52, ethertype IPv4 (0x0800), length 75: IP posio.6665 > espoo.syslog: UDP, length: 33
I'm unable to get the exact text due to varying packet loss at some
other place right now (verified by running tcpdump at both ends) but
it should be something like this (different machine, different case but
just to give an impression about the formatting):
May 31 10:39:02 sirkka IN=eth0 OUT=
May 31 10:39:02 sirkka MAC=
May 31 10:39:02 sirkka 00:
May 31 10:39:02 sirkka 60:
May 31 10:39:02 sirkka 97:
May 31 10:39:02 sirkka bc:
May 31 10:39:02 sirkka 4b:
May 31 10:39:02 sirkka a3:
May 31 10:39:02 sirkka 00:
May 31 10:39:02 sirkka 04:
May 31 10:39:02 sirkka 9a:
May 31 10:39:02 sirkka a0:
May 31 10:39:02 sirkka 1d:
May 31 10:39:02 sirkka d1:
May 31 10:39:02 sirkka 08:
May 31 10:39:02 sirkka 00
May 31 10:39:02 sirkka SRC=172.19.1.4 DST=172.17.1.110
May 31 10:39:02 sirkka LEN=48 TOS=0x00 PREC=0x00 TTL=126 ID=10359
May 31 10:39:02 sirkka DF
May 31 10:39:02 sirkka PROTO=TCP
May 31 10:39:02 sirkka SPT=1681 DPT=445
May 31 10:39:02 sirkka WINDOW=64512
May 31 10:39:02 sirkka RES=0x00
May 31 10:39:02 sirkka SYN
May 31 10:39:02 sirkka URGP=0
May 31 10:39:02 sirkka
--
Frank
^ permalink raw reply
* Re: [Bugme-new] [Bug 6613] New: iptables broken on 32-bit PReP (ARCH=ppc)
From: Patrick McHardy @ 2006-06-02 13:08 UTC (permalink / raw)
To: Meelis Roos; +Cc: Andrew Morton, bugme-daemon, netdev
In-Reply-To: <Pine.SOC.4.61.0606012346350.28838@math.ut.ee>
Meelis Roos wrote:
>> Then lets try something different. Please enable the
>> DEBUG_IP_FIREWALL_USER define in net/ipv4/netfilter/ip_tables.c and
>> post the results, if any.
>
>
> On bootup I get this in dmesg (one Bad offset has been added):
>
> ip_tables: (C) 2000-2006 Netfilter Core Team
> Netfilter messages via NETLINK v0.30.
> ip_conntrack version 2.4 (1536 buckets, 12288 max) - 224 bytes per
> conntrack
> translate_table: size 632
> Bad offset cb437924
> ip_nat_init: can't setup rules.
>
> And on iptables -t nat -L
>
> translate_table: size 632
> Bad offset cb4368f4
> ip_nat_init: can't setup rules.
> translate_table: size 632
> Bad offset cb4368f4
> ip_nat_init: can't setup rules.
>
> Seems iptable_nat does not load at all this time.
>
> Modprobe iptable_filter still fails, dmesg contains
> translate_table: size 632
> Finished chain 1
> Finished chain 2
> Finished chain 3
>
> Next modprobe iptable_nat gives
>
> translate_table: size 632
> Bad offset c8e01944
> ip_nat_init: can't setup rules.
Very strange, this means that the initial table data must somehow
be wrong, but for some reason it still seems to get past the
size and offset checks for the filter table. I can't see how
loading the filter table could fail after the "Finished chain .."
messages without another message. Which kernel version did you
perform these test on?
^ permalink raw reply
* Re: [Bugme-new] [Bug 6613] New: iptables broken on 32-bit PReP (ARCH=ppc)
From: Meelis Roos @ 2006-06-02 13:18 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Andrew Morton, bugme-daemon, netdev
In-Reply-To: <4480385C.7080405@trash.net>
> Very strange, this means that the initial table data must somehow
> be wrong, but for some reason it still seems to get past the
> size and offset checks for the filter table. I can't see how
> loading the filter table could fail after the "Finished chain .."
> messages without another message. Which kernel version did you
> perform these test on?
Yesterdays 2.6.17-rc5+git.
--
Meelis Roos (mroos@linux.ee)
^ permalink raw reply
* Greeting!
From: Bibian M. @ 2006-06-02 13:43 UTC (permalink / raw)
To: Steffen
Hi my Dear Stranger!
I want to start my first letter from a question: "Is it possible to be happy without LOVE?"
I think that you will agree with me if the answer will be "NO WAY". Love is the most beautiful and exciting thing
that may happen between man and woman! It inspires us only for doing positive things towards each other.
One very famous writer said: "The beauty will rescue the world" i agree with his words but still i would add :
" LOVE and Beauty will rescure the world".
I hope you agree with me that Love is a big notion.
There's love to God, to Mother, to a child to the country where you were born, and there's love that joins a man
and woman for all their life. That is the LOVE i'm looking for! And i'm seeking for the man who is also eager to have
this life long adventure full of surprises and new experience we can share together! Will you join me for this trip?
I do realise that it should be very difficult to say "Yes" from the first letter having no idea about me.
That's why i just offer to get to know each other better though correspondence that will help us to reveal many things
about each other whether we mach perfectly or not. In addition you can look at my pictures and read some info about me here
http://ojbf5HinfFcJyKG9bDUk.i-am-waiting4love.net/
I hope you'll like what you see and read there.
Well closing my first letter to you i just want to thank you for reading it and i really hope that you'll share
my point of view on what i said above. I do really hope that you'll answer me soon.
so long...
Bi M.
^ permalink raw reply
* Re: [Bugme-new] [Bug 6613] New: iptables broken on 32-bit PReP (ARCH=ppc)
From: Patrick McHardy @ 2006-06-02 13:56 UTC (permalink / raw)
To: Meelis Roos; +Cc: Andrew Morton, bugme-daemon, netdev
In-Reply-To: <Pine.SOC.4.61.0606021617480.1298@math.ut.ee>
Meelis Roos wrote:
>> Very strange, this means that the initial table data must somehow
>> be wrong, but for some reason it still seems to get past the
>> size and offset checks for the filter table. I can't see how
>> loading the filter table could fail after the "Finished chain .."
>> messages without another message. Which kernel version did you
>> perform these test on?
>
>
> Yesterdays 2.6.17-rc5+git.
Please enable DEBUG_IP_FIREWALL_USER in net/netfilter/x_tables.c as well
and retry. Results of the raw or mangle table would also be interesting
because they contain a different number of built-in chains.
^ permalink raw reply
* RE: [openib-general] Re: [PATCH 1/2] iWARP Connection Manager.
From: Steve Wise @ 2006-06-02 13:57 UTC (permalink / raw)
To: Caitlin Bestler
Cc: Tom Tucker, Sean Hefty, netdev, rdreier, linux-kernel,
openib-general
In-Reply-To: <54AD0F12E08D1541B826BE97C98F99F150D3E6@NT-SJCA-0751.brcm.ad.broadcom.com>
> >
> > The problem is that we can't synchronously cancel an
> > outstanding connect request. Once we've asked the adapter to
> > connect, we can't tell him to stop, we have to wait for it to
> > fail. During the time period between when we ask to connect
> > and the adapter says yeah-or-nay, the user hits ctrl-C. This
> > is the case where disconnect and/or destroy gets called and
> > we have to block it waiting for the outstanding connect
> > request to complete.
> >
> > One alternative to this approach is to do the kfree of the
> > cm_id in the deref logic. This was the original design and
> > leaves the object around to handle the completion of the
> > connect and still allows the app to clean up and go away
> > without all this waitin' around. When the adapter finally
> > finishes and releases it's reference, the object is kfree'd.
> >
> > Hope this helps.
> >
> Why couldn't you synchronously put the cm_id in a state of
> "pending delete" and do the actual delete when the RNIC
> provides a response to the request?
This is Tom's "alternative" mentioned above. The provider already keeps
an explicit reference on the cm_id while it might possibly deliver an
event on that cm_id. So if you change deref to kfree the cm_id on its
last deref (when the refcnt reaches 0), then you can avoid blocking
during destroy...
> There could even be
> an optional method to see if the device is capable of
> cancelling the request. I know it can't yank a SYN back
> from the wire, but it could refrain from retransmitting.
I would suggest we don't add this optional method until we see an RNIC
that supports canceling a connect request or accept synchronously...
Steve.
^ permalink raw reply
* Re: 2.6.17-rc4: netfilter LOG messages truncated via NETCONSOLE (2)
From: Frank van Maarseveen @ 2006-06-02 14:02 UTC (permalink / raw)
To: Patrick McHardy; +Cc: linux-kernel, Kernel Netdev Mailing List
In-Reply-To: <20060602123559.GA7505@janus>
On Fri, Jun 02, 2006 at 02:35:59PM +0200, me wrote:
[...]
> This is a tcpdump done after rebooting "posio"
> to 2.6.13.2 showing how it should have looked:
[snip]
The 2.6.13.2 data is inconsistent. The bug appears to be present there at
well after closer examination. So there must be another factor involved
because I have at least one case logged where 2.6.13.2 did work (the
"sirkka" log in my previous mail). Applying your patch on 2.6.13.2
again removes the protocol is buggy messages (when doing a tcpdump)
but the problem of the 10 missing packets persists.
--
Frank
^ permalink raw reply
* Re: 2.6.17-rc4: netfilter LOG messages truncated via NETCONSOLE (2)
From: Patrick McHardy @ 2006-06-02 14:16 UTC (permalink / raw)
To: Frank van Maarseveen; +Cc: linux-kernel, Kernel Netdev Mailing List
In-Reply-To: <20060602140212.GA7881@janus>
[-- Attachment #1: Type: text/plain, Size: 529 bytes --]
Frank van Maarseveen wrote:
> The 2.6.13.2 data is inconsistent. The bug appears to be present there at
> well after closer examination. So there must be another factor involved
> because I have at least one case logged where 2.6.13.2 did work (the
> "sirkka" log in my previous mail). Applying your patch on 2.6.13.2
> again removes the protocol is buggy messages (when doing a tcpdump)
> but the problem of the 10 missing packets persists.
Which network driver are you using? Does this patch show anything in
the ringbuffer?
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 389 bytes --]
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index e8e05ce..2b12280 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -302,6 +302,9 @@ static void netpoll_send_skb(struct netp
netpoll_poll(np);
udelay(50);
} while (npinfo->tries > 0);
+
+ printk("failed to transmit\n");
+ kfree_skb(skb);
}
void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
^ permalink raw reply related
* Re: [RFC PATCH 1/2] Hardware button support for Wireless cards: radiobtn
From: Ivo van Doorn @ 2006-06-02 14:30 UTC (permalink / raw)
To: Francois Romieu; +Cc: netdev
In-Reply-To: <200605312005.31067.IvDoorn@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 9871 bytes --]
> > > The first parameter of strcat() must be big enough to contain the whole
> > > string.
> >
> > Will replace it with
> > sprintf(wrqu->name, "radiobtn/", radiobtn->dev_name);
>
> Or actually, I don't think the radiobtn/ won't be actually needed as prefix.
> The name passed to the radiobtn driver by the driver should be sufficient.
Updated version,
Signed-off-by Ivo van Doorn <IvDoorn@gmail.com>
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 4bad588..212caad 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -79,4 +79,14 @@ config HP_SDC_RTC
Say Y here if you want to support the built-in real time clock
of the HP SDC controller.
+config RADIOBTN
+ tristate "Hardware radio button support"
+ help
+ Say Y here if you have an integrated WiFi or Bluetooth device
+ which contains an hardware button for enabling or disabling the radio.
+ When this driver is used, this driver will make sure the radio will
+ be correctly enabled and disabled when needed. It will then also
+ use the created input device to signal user space of this event
+ which allows userspace to take additional actions.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415c491..9af3d98 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+obj-$(CONFIG_RADIOBTN) += radiobtn.o
\ No newline at end of file
diff --git a/drivers/input/misc/radiobtn.c b/drivers/input/misc/radiobtn.c
new file mode 100644
index 0000000..4379abe
--- /dev/null
+++ b/drivers/input/misc/radiobtn.c
@@ -0,0 +1,163 @@
+/*
+ Copyright (C) 2006 Ivo van Doorn
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Radio hardware button support
+ Poll frequently all registered hardware for hardware button status,
+ if changed enabled or disable the radio of that hardware device.
+ Send signal to input device to inform userspace about the new status.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/radiobtn.h>
+
+MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Radio hardware button support");
+MODULE_LICENSE("GPL");
+
+static void radiobtn_poll(unsigned long data)
+{
+ struct radio_button *radiobtn = (struct radio_button*)data;
+ int state;
+
+ /*
+ * Poll for the new state.
+ * Check if the state has changed.
+ */
+ state = !!radiobtn->button_poll(radiobtn->data);
+ if (state != radiobtn->current_state) {
+ radiobtn->current_state = state;
+
+ /*
+ * Enable or disable the radio when this
+ * should be done in software.
+ */
+ if (state && radiobtn->enable_radio)
+ radiobtn->enable_radio(radiobtn->data);
+ else if (!state && radiobtn->disable_radio)
+ radiobtn->disable_radio(radiobtn->data);
+
+ /*
+ * Report key event.
+ */
+ input_report_key(radiobtn->input_dev, KEY_RADIO, 1);
+ input_sync(radiobtn->input_dev);
+ input_report_key(radiobtn->input_dev, KEY_RADIO, 0);
+ input_sync(radiobtn->input_dev);
+ }
+
+ /*
+ * Check if polling has been disabled.
+ */
+ if (radiobtn->poll_delay != 0) {
+ radiobtn->poll_timer.expires =
+ jiffies + msecs_to_jiffies(radiobtn->poll_delay);
+ add_timer(&radiobtn->poll_timer);
+ }
+}
+
+int radiobtn_register_device(struct radio_button *radiobtn)
+{
+ int status;
+
+ /*
+ * Check if all mandatory fields have been set.
+ */
+ if (radiobtn->poll_delay == 0 || radiobtn->button_poll == NULL)
+ return -EINVAL;
+
+ /*
+ * Allocate, initialize and register input device.
+ */
+ radiobtn->input_dev = input_allocate_device();
+ if (!radiobtn->input_dev) {
+ printk(KERN_ERR "Failed to allocate input device %s.\n",
+ radiobtn->dev_name);
+ return -ENOMEM;
+ }
+
+ radiobtn->input_dev->name = "Radio button";
+ radiobtn->input_dev->phys = radiobtn->dev_name;
+ radiobtn->input_dev->id.bustype = BUS_HOST;
+ set_bit(KEY_RADIO, radiobtn->input_dev->keybit);
+
+ status = input_register_device(radiobtn->input_dev);
+ if (status) {
+ printk(KERN_ERR "Failed to register input device %s.\n",
+ radiobtn->dev_name);
+ input_free_device(radiobtn->input_dev);
+ return status;
+ }
+
+ /*
+ * Set the initial state of the button.
+ */
+ radiobtn->current_state = radiobtn->button_poll(radiobtn->data);
+
+ /*
+ * Initialize timer.
+ */
+ init_timer(&radiobtn->poll_timer);
+ radiobtn->poll_timer.function = radiobtn_poll;
+ radiobtn->poll_timer.data = (unsigned long)radiobtn;
+ radiobtn->poll_timer.expires =
+ jiffies + msecs_to_jiffies(radiobtn->poll_delay);
+ add_timer(&radiobtn->poll_timer);
+
+ printk(KERN_INFO "Created new %s: %s.\n",
+ radiobtn->input_dev->name, radiobtn->input_dev->phys);
+
+ return 0;
+}
+
+void radiobtn_unregister_device(struct radio_button *radiobtn)
+{
+ /*
+ * Stop timer.
+ */
+ radiobtn->poll_delay = 0;
+ del_timer_sync(&radiobtn->poll_timer);
+
+ /*
+ * Remove input device.
+ */
+ input_unregister_device(radiobtn->input_dev);
+ input_free_device(radiobtn->input_dev);
+}
+
+static int __init radiobtn_init(void)
+{
+ printk(KERN_INFO "Loading radio button driver.\n");
+ return 0;
+}
+
+static void __exit radiobtn_exit(void)
+{
+ printk(KERN_INFO "Unloading radio button driver.\n");
+}
+
+EXPORT_SYMBOL(radiobtn_register_device);
+EXPORT_SYMBOL(radiobtn_unregister_device);
+
+module_init(radiobtn_init);
+module_exit(radiobtn_exit);
diff --git a/include/linux/radiobtn.h b/include/linux/radiobtn.h
new file mode 100644
index 0000000..3467606
--- /dev/null
+++ b/include/linux/radiobtn.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2006 Ivo van Doorn
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Radio hardware button support
+ Laptops are quite often equiped with support with a hardware button
+ to enabled and disable the radio of the integrated wireless network
+ or bluetooth interface.
+ Altough some devices will make sure that when pressed the radio
+ is disabled in hardware, other device depend on the software
+ to enabled or disable the radio accordingly.
+ This driver will create an input device and will poll registered
+ hardware frequently to listen if the button has been pressed.
+ When the device requires the software to disable or enable
+ the radio it will do so correctly, but it will also in all cases
+ send a signal to the input device to inform any listening daemon
+ the state has changed and will allow userspace to handle certain
+ tasks as well if required.
+ */
+
+#ifndef RADIOBTN_H
+#define RADIOBTN_H
+
+#include <linux/input.h>
+
+/**
+ * struct radio_button - radio hardware structure.
+ * @dev_name: Name of the interface. This will become the name
+ * of the input device created in /dev/radio/.
+ * @data: Private data which will be passed along with the radio handlers.
+ * @button_poll(unsigned long data): Handler which will be called
+ * with the poll_delay interval.
+ * @enable_radio(unsigned long data): Optional handler to enable the radio
+ * once the button has been pressed when the hardware does not do this
+ * automaticly.
+ * @disable_radio(unsigned long data): Optional handler to disable the radio
+ * once the button has been pressed when the hardware does not do this
+ * automaticly.
+ * @poll_delay: Delay in msecs between each poll.
+ * @current_state: Current state of the button.
+ * (Should not be touched by driver)
+ * @input_dev: Pointer to input device for this radio button.
+ * (Should not be touched by driver)
+ * @poll_timer: Timer used to poll for the button status.
+ * (Should not be touched by driver)
+ */
+struct radio_button {
+ const char *dev_name;
+
+ unsigned long data;
+
+ int (*button_poll)(unsigned long data);
+ void (*enable_radio)(unsigned long data);
+ void (*disable_radio)(unsigned long data);
+
+ unsigned int poll_delay;
+
+ unsigned int current_state;
+
+ struct input_dev *input_dev;
+
+ struct timer_list poll_timer;
+};
+
+int radiobtn_register_device(struct radio_button *);
+void radiobtn_unregister_device(struct radio_button *);
+
+#endif /* RADIOBTN_H */
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply related
* Re: 2.6.17-rc4: netfilter LOG messages truncated via NETCONSOLE (2)
From: Frank van Maarseveen @ 2006-06-02 14:39 UTC (permalink / raw)
To: Patrick McHardy; +Cc: linux-kernel, Kernel Netdev Mailing List
In-Reply-To: <44804828.2050909@trash.net>
On Fri, Jun 02, 2006 at 04:16:08PM +0200, Patrick McHardy wrote:
> Which network driver are you using?
I've seen it with two completely different NICs at the sender side:
0000:02:08.0 Ethernet controller: Intel Corporation 82557/8/9 [Ethernet Pro 100] (rev 05)
0000:02:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM5751 Gigabit Ethernet PCI Express (rev 01)
Snippet from bootlog:
Jun 2 16:24:05 posio kernel: e100: Intel(R) PRO/100 Network Driver, 3.5.10-k2-NAPI
Jun 2 16:24:05 posio kernel: e100: Copyright(c) 1999-2005 Intel Corporation
Jun 2 16:24:05 posio kernel: ACPI: PCI Interrupt 0000:02:08.0[A] -> GSI 16 (level, low) -> IRQ 16
Jun 2 16:24:05 posio kernel: e100: eth0: e100_probe: addr 0x40400000, irq 16, MAC addr 00:08:C7:69:29:AE
Jun 2 16:24:05 posio kernel: netconsole: device eth0 not up yet, forcing it
Jun 2 16:24:05 posio kernel: e100: eth0: e100_watchdog: link up, 100Mbps, full-duplex
Jun 2 16:24:05 posio kernel: netconsole: carrier detect appears untrustworthy, waiting 4 seconds
Jun 2 16:24:05 posio kernel: netconsole: network logging started
> Does this patch show anything in
> the ringbuffer?
no.
> --- a/net/core/netpoll.c
> +++ b/net/core/netpoll.c
> @@ -302,6 +302,9 @@ static void netpoll_send_skb(struct netp
> netpoll_poll(np);
> udelay(50);
> } while (npinfo->tries > 0);
> +
> + printk("failed to transmit\n");
> + kfree_skb(skb);
> }
>
> void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
--
Frank
^ permalink raw reply
* Re: [PATCH] softmac: Fix handling of authentication failure
From: Larry Finger @ 2006-06-02 14:55 UTC (permalink / raw)
To: Daniel Drake, Larry Finger, netdev, johannes
In-Reply-To: <20060602120439.GA14289@tuxdriver.com>
John W. Linville wrote:
> On Fri, Jun 02, 2006 at 11:09:56AM +0100, Daniel Drake wrote:
>
>> Larry Finger wrote:
>>
>>> This statement fails to compile on my system using Linus' tree, because
>>> ieee80211softmac_disassoc needs a second argument - the reason. It seems
>>> as if WLAN_REASON_PREV_AUTH_NOT_VALID would be appropriate.
>>>
>> Thanks for pointing that out. This patch depends on a patch titled
>> "softmac: deauthentication implies deassociation" which is apparently
>> not present in Linus' tree.
>>
>
> That patch is in the upstream branch (also available in the master
> branch) of wireless-2.6, which is probably what anyone doing wireless
> patches should(*) be using.
>
> The approved release process only allows for non-bugfix patches
> in the first two weeks after a Linus blesses a new kernel release.
> After that only bugfixes are allowed, with non-bugfix patches getting
> queued for the next merge window. The upstream branch represents
> that queue of patches.
>
> Hth!
>
> John
>
> (*) The exception being those workign on Devicescape-related patches,
> who should be working off the master branch of wireless-dev.
>
Normally I use the master branch of wireless-2.6; however that code has
something in it that kills interrupts from my bcm4306 card, but I
haven't had time to chase down that problem. A second difficulty is that
my Linksys WRT54G V1 died and the only replacement I could find on short
notice was a V5 model, which is truly an abomination using VXWorks, not
Linux. When the AP changed, my working system of bcm43xx-softmac with
WPA authentication now refuses to authenticate, and I have to use a
wired connection. Accordingly, I try every softmac patch that might
solve my problem - thus I applied Daniels's patch to Linus's tree.
Larry
^ permalink raw reply
* Re: Question about tcp hash function tcp_hashfn()
From: Brian F. G. Bidulock @ 2006-06-02 15:10 UTC (permalink / raw)
To: Evgeniy Polyakov
Cc: Florian Weimer, David Miller, draghuram, linux-kernel, netdev
In-Reply-To: <20060602074845.GA17798@2ka.mipt.ru>
Evgeniy,
I agree, even with constant source IP, the hash still should have
performed better (but didn't). Constant source IP and varying
port is a realistic data set for a port proxy.
^ permalink raw reply
* Re: new driver for IBM ethernet chip
From: Randy.Dunlap @ 2006-06-02 16:00 UTC (permalink / raw)
To: Christoph Raisch; +Cc: netdev, MEDER, THEMANN
In-Reply-To: <OFA75C1070.77D8B8F0-ONC125717F.003D730C-C1257181.003C592B@de.ibm.com>
On Fri, 2 Jun 2006 13:02:37 +0200 Christoph Raisch wrote:
> We're currently developing a new Ethernet device driver for a 10G IBM chip
> for System p. (ppc64)
>
> A later version of the driver should end up in mainline kernel.
> How should we proceed to get first comments by the community?
> Either post this code as a patch to netdev or
yes
> put a full tarball on for example sourceforge?
nope.
Please read and observe: Documentation/SubmittingPatches
and Section 3 of it, References, for other sources of
expectations/requirements.
The -mm tree also contains Documentation/SubmitChecklist
that you may find useful.
---
~Randy
^ permalink raw reply
* Re: RFC3927 ARP patch status?
From: David Daney @ 2006-06-02 16:36 UTC (permalink / raw)
To: Anand Kumria; +Cc: netdev
In-Reply-To: <20060602143837.GF549@progsoc.uts.edu.au>
Anand Kumria wrote:
> Hi David,
>
> Do you know the status of your RFC3927 ARP patch? Is it likely to make
> it into a mainline kernel?
>
That would be up to the kernel network maintainers.
There were some discussions about whether it made sense for the kernel
to support the behavior required by the RFC. Other comments debated the
wisdom of using a tightly targeted patch specific to the RFC, or whether
a more general but intrusive solution would be better.
The patch is there. I signed-off-by on it.
If you need RFC3927 compliance, you are free to apply the patch. If the
network maintainers are so inclined, they can do the necessary things
to get it into the mainline.
David Daney
^ permalink raw reply
* Re: Question about tcp hash function tcp_hashfn()
From: Florian Weimer @ 2006-06-02 17:26 UTC (permalink / raw)
To: Evgeniy Polyakov
Cc: David Miller, draghuram, linux-kernel, netdev,
Brian F. G. Bidulock
In-Reply-To: <20060602074845.GA17798@2ka.mipt.ru>
* Evgeniy Polyakov:
> :) thats true, but to be 100% honest I used different code to test for
> hash artifacts...
Ah, okay.
> But it still does not fix artifacts with for example const IP and random
> ports or const IP and linear port selection.
I see them now. Hmm. Is there a theoretical explanation for them?
^ permalink raw reply
* Re: RFC3927 ARP patch status?
From: Anand Kumria @ 2006-06-02 17:31 UTC (permalink / raw)
To: David Daney; +Cc: netdev
In-Reply-To: <44806926.1050509@avtrex.com>
On Fri, Jun 02, 2006 at 09:36:54AM -0700, David Daney wrote:
> Anand Kumria wrote:
> >Hi David,
> >
> >Do you know the status of your RFC3927 ARP patch? Is it likely to make
> >it into a mainline kernel?
> >
>
> That would be up to the kernel network maintainers.
>
> There were some discussions about whether it made sense for the kernel
> to support the behavior required by the RFC. Other comments debated the
Hmm, well the behaviour at the moment is certainly suboptimal. Any
compliant RFC3927 implementation has to generate an additional broadcast
ARP -- the kernel will send a directed response, which isn't enough.
> The patch is there. I signed-off-by on it.
>
> If you need RFC3927 compliance, you are free to apply the patch. If the
> network maintainers are so inclined, they can do the necessary things
> to get it into the mainline.
Okay, thanks.
Anand
--
`When any government, or any church for that matter, undertakes to say to
its subjects, "This you may not read, this you must not see, this you are
forbidden to know," the end result is tyranny and oppression no matter how
holy the motives' -- Robert A Heinlein, "If this goes on --"
^ permalink raw reply
* Re: Question about tcp hash function tcp_hashfn()
From: Brian F. G. Bidulock @ 2006-06-02 17:37 UTC (permalink / raw)
To: Florian Weimer
Cc: Evgeniy Polyakov, David Miller, draghuram, linux-kernel, netdev
In-Reply-To: <87ac8v8o4i.fsf@mid.deneb.enyo.de>
Florian,
On Fri, 02 Jun 2006, Florian Weimer wrote:
>
> I see them now. Hmm. Is there a theoretical explanation for them?
Jenkins is an ad hoc function that is far from ideal. As you know,
the ideal hash changes 1/2 the bits in the output value for each one
bit change in the input value(s). Jenkins changes a few as 1/3 and
performs less than ideal over even a small smaple of the input data
set (Jenkins said he checked several billion of the trilions of
changes).
It should not be suprising that a general purpose ad hoc function
(Jenkins) performs poorer than a specific purpose ad hoc function
(XOR), for the very specific input data sets that the later was chosen
to cover.
Theoretically, XOR can be improved upon, but Jenkins doesn't do it.
^ permalink raw reply
* Re: [Bugme-new] [Bug 6638] New: tg3 output freezes on compaq nc6000
From: Andrew Morton @ 2006-06-02 18:22 UTC (permalink / raw)
To: bugme-daemon@kernel-bugs.osdl.org; +Cc: netdev, Klaus.Reichl
In-Reply-To: <200606021240.k52CepX2017904@fire-2.osdl.org>
On Fri, 2 Jun 2006 05:40:51 -0700
bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=6638
>
> Summary: tg3 output freezes on compaq nc6000
> Kernel Version: 2.6.16.19
> Status: NEW
> Severity: normal
> Owner: jgarzik@pobox.com
> Submitter: Klaus.Reichl@alcatel.at
>
>
> Most recent kernel where this bug did not occur: none
> Distribution: Debian Sarge with latest kernel
> Hardware Environment: compaq nc6000
> Software Environment:
> Problem Description:
> The output engine of the tg3 driver freezes when generating high load.
>
> `ifconfig' shows incomming packets, however, outgoing counter is not incremented
> any more.
>
> Resetting the device (ifdown eth0, ifup eth0) heals the problem.
>
> Steps to reproduce:
> Heavily copy files to NFS disk.
>
> ------- You are receiving this mail because: -------
> You are on the CC list for the bug, or are watching someone who is.
^ permalink raw reply
* Re: The AI parameter of tcp_highspeed.c (in 2.6.18)
From: Stephen Hemminger @ 2006-06-02 19:05 UTC (permalink / raw)
To: Xiaoliang (David) Wei, John Heffner; +Cc: netdev
In-Reply-To: <7335583a0605292112l1f5a6ec3x4b1c1e4ae45688f5@mail.gmail.com>
Went backed and looked at the RFC. The problem was just a simple
translation of table to C array (0 based). Added this to the TCP testing repository.
Subject: [PATCH] Problem observed by Xiaoliang (David) Wei:
When snd_cwnd is smaller than 38 and the connection is in
congestion avoidance phase (snd_cwnd > snd_ssthresh), the snd_cwnd
seems to stop growing.
The additive increase was confused because C array's are 0 based.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
---
net/ipv4/tcp_highspeed.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
121685b7b61c8faeb87e6c6f0c346b0fe1c46fd2
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index b72fa55..ba7c63c 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -135,7 +135,8 @@ static void hstcp_cong_avoid(struct sock
/* Do additive increase */
if (tp->snd_cwnd < tp->snd_cwnd_clamp) {
- tp->snd_cwnd_cnt += ca->ai;
+ /* cwnd = cwnd + a(w) / cwnd */
+ tp->snd_cwnd_cnt += ca->ai + 1;
if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
tp->snd_cwnd_cnt -= tp->snd_cwnd;
tp->snd_cwnd++;
--
1.3.3
^ permalink raw reply related
* [PATCH 2.6.16.18] MSI: Proposed fix for MSI/MSI-X load failure
From: Ravinandan Arakali @ 2006-06-02 19:21 UTC (permalink / raw)
To: linux-kernel
Cc: netdev, leonid.grossman, ananda.raju, rapuru.sriram,
ravinandan.arakali
Hi,
This patch suggests a fix for the MSI/MSI-X load failure.
Please review the patch.
Symptoms:
When a driver is loaded with MSI followed by MSI-X, the load fails indicating
that the MSI vector is still active. And vice versa.
Suspected rootcause:
This happens inspite of driver calling free_irq() followed by
pci_disable_msi/pci_disable_msix. This appears to be a kernel bug
wherein the pci_disable_msi and pci_disable_msix calls do not
clear/unpopulate the msi_desc data structure that was populated
by pci_enable_msi/pci_enable_msix.
Proposed fix:
Free the MSI vector in pci_disable_msi and all allocated MSI-X vectors
in pci_disable_msix.
Testing:
The fix has been tested on IA64 platforms with Neterion's Xframe driver.
Signed-off-by: Ravinandan Arakali <ravinandan.arakali@neterion.com>
---
diff -urpN old/drivers/pci/msi.c new/drivers/pci/msi.c
--- old/drivers/pci/msi.c 2006-05-31 19:02:19.000000000 -0700
+++ new/drivers/pci/msi.c 2006-05-31 19:02:39.000000000 -0700
@@ -779,6 +779,7 @@ void pci_disable_msi(struct pci_dev* dev
nr_released_vectors++;
default_vector = entry->msi_attrib.default_vector;
spin_unlock_irqrestore(&msi_lock, flags);
+ msi_free_vector(dev, dev->irq, 1);
/* Restore dev->irq to its default pin-assertion vector */
dev->irq = default_vector;
disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
@@ -1046,6 +1047,7 @@ void pci_disable_msix(struct pci_dev* de
}
}
+ msi_remove_pci_irq_vectors(dev);
}
/**
^ permalink raw reply
* Driver for Rsltek 8139D / Silan SC92031
From: Daniel Drake @ 2006-06-02 20:16 UTC (permalink / raw)
To: netdev; +Cc: cantao
[-- Attachment #1: Type: text/plain, Size: 477 bytes --]
Here's a strange one. Cantao (on CC) bought what he thought was a cheap
realtek PCI NIC, it actually turns out it is a Rsltek (yes, Rsltek)
8139D card.
It includes an old (2.4/2.5) driver which claims to be for Silan SC92031
(attached).
The driver has some very obvious similarities with 8139too, however the
register layout and usage is quite different.
Has anyone got any idea whats going on here? It seems like something
based on a realtek chip, but not...
Daniel
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sc92031.c --]
[-- Type: text/x-csrc; name="sc92031.c", Size: 60418 bytes --]
/***************************************************************************
sl.c - 8139D Fast Ethernet driver
-------------------
begin : Ò» 8ÔÂ 6 15:05:44 CST 2002
copyright : (C) 2002 by gaoyonghong
email : gyh1@localhost.localdomain
***************************************************************************/
#define DRV_NAME "Rsltek 8139"
#define DRV_VERSION "1.0.0"
#define SILAN_DRIVER_NAME DRV_NAME"Rsltek 8139D PCI Fast Ethernet driver v"DRV_VERSION
#ifndef __KERNEL__
#define __KERNEL__
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/errno.h>
#include <asm/uaccess.h>
#define USE_IO_OPS
#ifdef SILAN_DEBUG
// note: prints function name for you
#define PDEBUG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define PDEBUG(fmt, args...)
#endif
#ifdef SILAN_NDEBUG
#define assert(expr) do { } while (0)
#else
#define assert(expr) \
if(!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
#endif
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).*/
static int multicast_filter_limit = 64;
/* Size of the in-memory receive ring. */
#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
/* Number of Tx descriptor registers. */
#define NUM_TX_DESC 4
/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
#define MAX_ETH_FRAME_SIZE 1536
/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*HZ)
#define SILAN_STATE_NUM 2 /* number of ETHTOOL_GSTATS */
enum work_mode {
Autoselect = 0x00,
M10_Half = 0x01,
M10_Full = 0x02,
M100_Half = 0x04,
M100_Full = 0x08,
} work_mode;
struct tx_info {
struct sk_buff *skb;
dma_addr_t mapping;
};
struct Mii_ioctl_data {
u32 phy_id;
u32 reg_num;
u32 val_in;
u32 val_out;
};
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,18)
static struct{
const char string[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
{"tx_timeout"},
{"rx_loss"},
};
#endif
struct pci_device_id silan_pci_tbl[ ] __devinitdata = {
{ 0x1904, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0 ,0 , 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, silan_pci_tbl);
/* Symbolic offsets to registers. */
enum SILAN_registers {
Config0 = 0x00, // Config0
Config1 = 0x04, // Config1
RxBufWPtr = 0x08, // Rx buffer writer poiter
IntrStatus = 0x0C, // Interrupt status
IntrMask = 0x10, // Interrupt mask
RxbufAddr = 0x14, // Rx buffer start address
RxBufRPtr = 0x18, // Rx buffer read pointer
Txstatusall = 0x1C, // Transmit status of all descriptors
TxStatus0 = 0x20, // Transmit status (Four 32bit registers).
TxAddr0 = 0x30, // Tx descriptors (also four 32bit).
RxConfig = 0x40, // Rx configuration
MAC0 = 0x44, // Ethernet hardware address.
MAR0 = 0x4C, // Multicast filter.
RxStatus0 = 0x54, // Rx status
TxConfig = 0x5C, // Tx configuration
PhyCtrl = 0x60, // physical control
FlowCtrlConfig = 0x64, // flow control
Miicmd0 = 0x68, // Mii command0 register
Miicmd1 = 0x6C, // Mii command1 register
Miistatus = 0x70, // Mii status register
Timercnt = 0x74, // Timer counter register
TimerIntr = 0x78, // Timer interrupt register
PMConfig = 0x7C, // Power Manager configuration
CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers)
Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser)
LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser)
TestD0 = 0xD0,
TestD4 = 0xD4,
TestD8 = 0xD8,
};
#define MII_BMCR 0 // Basic mode control register
#define MII_BMSR 1 // Basic mode status register
#define Mii_JAB 16
#define Mii_OutputStatus 24
#define BMCR_FULLDPLX 0x0100 // Full duplex
#define BMCR_ANRESTART 0x0200 // Auto negotiation restart
#define BMCR_ANENABLE 0x1000 // Enable auto negotiation
#define BMCR_SPEED100 0x2000 // Select 100Mbps
#define BMSR_LSTATUS 0x0004 // Link status
#define PHY_16_JAB_ENB 0x1000
#define PHY_16_PORT_ENB 0x1
enum IntrStatusBits {
LinkFail = 0x80000000,
LinkOK = 0x40000000,
TimeOut = 0x20000000,
RxOverflow = 0x0040,
RxOK = 0x0020,
TxOK = 0x0001,
IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
};
enum TxStatusBits {
TxCarrierLost = 0x20000000,
TxAborted = 0x10000000,
TxOutOfWindow = 0x08000000,
TxNccShift = 22,
EarlyTxThresShift = 16,
TxStatOK = 0x8000,
TxUnderrun = 0x4000,
TxOwn = 0x2000,
};
enum RxStatusBits {
RxStatesOK = 0x80000,
RxBadAlign = 0x40000,
RxHugeFrame = 0x20000,
RxSmallFrame = 0x10000,
RxCRCOK = 0x8000,
RxCrlFrame = 0x4000,
Rx_Broadcast = 0x2000,
Rx_Multicast = 0x1000,
RxAddrMatch = 0x0800,
MiiErr = 0x0400,
};
enum RxConfigBits {
RxFullDx = 0x80000000,
RxEnb = 0x40000000,
RxSmall = 0x20000000,
RxHuge = 0x10000000,
RxErr = 0x08000000,
RxAllphys = 0x04000000,
RxMulticast = 0x02000000,
RxBroadcast = 0x01000000,
RxLoopBack = (1 << 23) | (1 << 22),
LowThresholdShift = 12,
HighThresholdShift = 2,
};
enum TxConfigBits {
TxFullDx = 0x80000000,
TxEnb = 0x40000000,
TxEnbPad = 0x20000000,
TxEnbHuge = 0x10000000,
TxEnbFCS = 0x08000000,
TxNoBackOff = 0x04000000,
TxEnbPrem = 0x02000000,
TxCareLostCrs = 0x1000000,
TxExdCollNum = 0xf00000,
TxDataRate = 0x80000,
};
enum PhyCtrlconfigbits {
PhyCtrlAne = 0x80000000,
PhyCtrlSpd100 = 0x40000000,
PhyCtrlSpd10 = 0x20000000,
PhyCtrlPhyBaseAddr = 0x1f000000,
PhyCtrlDux = 0x800000,
PhyCtrlReset = 0x400000,
};
enum FlowCtrlConfigBits {
FlowCtrlFullDX = 0x80000000,
FlowCtrlEnb = 0x40000000,
};
enum Config0Bits {
Cfg0_Reset = 0x80000000,
Cfg0_Anaoff = 0x40000000,
Cfg0_LDPS = 0x20000000,
};
enum Config1Bits {
Cfg1_EarlyRx = 1 << 31,
Cfg1_EarlyTx = 1 << 30,
//rx buffer size
Cfg1_Rcv8K = 0x0,
Cfg1_Rcv16K = 0x1,
Cfg1_Rcv32K = 0x3,
Cfg1_Rcv64K = 0x7,
Cfg1_Rcv128K = 0xf,
};
enum MiiCmd0Bits {
Mii_Divider = 0x20000000,
Mii_WRITE = 0x400000,
Mii_READ = 0x200000,
Mii_SCAN = 0x100000,
Mii_Tamod = 0x80000,
Mii_Drvmod = 0x40000,
Mii_mdc = 0x20000,
Mii_mdoen = 0x10000,
Mii_mdo = 0x8000,
Mii_mdi = 0x4000,
};
enum MiiStatusBits {
Mii_StatusBusy = 0x80000000,
};
enum PMConfigBits {
PM_Enable = 1 << 31,
PM_LongWF = 1 << 30,
PM_Magic = 1 << 29,
PM_LANWake = 1 << 28,
PM_LWPTN = (1 << 27 | 1<< 26),
PM_LinkUp = 1 << 25,
PM_WakeUp = 1 << 24,
};
struct silan_private {
void *mmio_addr;
struct pci_dev *pdev;
struct net_device_stats net_stats;
unsigned char *rx_ring;
unsigned long dirty_rx; // Index into the Rx buffer of next Rx pkt
unsigned long cur_tx;
unsigned long dirty_tx;
struct tx_info tx_info[NUM_TX_DESC];
unsigned char *tx_buf[NUM_TX_DESC]; // Tx bounce buffers
unsigned char *tx_bufs; // Tx bounce buffer region.
dma_addr_t rx_ring_dma;
dma_addr_t tx_bufs_dma;
enum work_mode mediaopt;
unsigned int intr_status;
unsigned int media_link_speed;
unsigned int media_duplex;
unsigned int tx_early_ctrl;
unsigned int rx_early_ctrl;
spinlock_t lock;
uint32_t rx_config;
uint32_t tx_config;
unsigned long tx_timeouts;
unsigned long rx_loss;
long rx_value;
int packet_filter;
uint32_t txenablepad;
};
#ifdef USE_IO_OPS
#define SILAN_R8(reg) inb(((unsigned long)ioaddr) + (reg))
#define SILAN_R16(reg) inw(((unsigned long)ioaddr) + (reg))
#define SILAN_R32(reg) ((unsigned long)inl(((unsigned long)ioaddr) + (reg)))
#define SILAN_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg))
#define SILAN_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg))
#define SILAN_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg))
#undef readb
#undef readw
#undef readl
#undef writeb
#undef writew
#undef writel
#define readb(addr) inb((unsigned long)(addr))
#define readw(addr) inw((unsigned long)(addr))
#define readl(addr) inl((unsigned long)(addr))
#define writeb(val,addr) outb((val),(unsigned long)(addr))
#define writew(val,addr) outw((val),(unsigned long)(addr))
#define writel(val,addr) outl((val),(unsigned long)(addr))
#else
// read/write MMIO register
#define SILAN_R8(reg) readb (ioaddr + (reg))
#define SILAN_R16(reg) readw (ioaddr + (reg))
#define SILAN_R32(reg) (unsigned long)readl (ioaddr + (reg))
#define SILAN_W8(reg, val8) writeb ((val8), ioaddr + (reg))
#define SILAN_W16(reg, val16) writew ((val16), ioaddr + (reg))
#define SILAN_W32(reg, val32) writel ((val32), ioaddr + (reg))
#endif /* USE_IO_OPS */
MODULE_AUTHOR ("gaoyonghong");
MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
MODULE_LICENSE("GPL");
MODULE_PARM (multicast_filter_limit, "i");
MODULE_PARM (work_mode, "i");
MODULE_PARM_DESC (multicast_filter_limit, "Rsltek 8139D maximum number of filtered multicast addresses");
MODULE_PARM_DESC (work_mode,"Rsltek 8139D netcard media method");
/* Index to Function */
static int silan_probe(struct pci_dev *pdev,const struct pci_device_id *id);
static void silan_hw_init(struct net_device *dev);
static int silan_open(struct net_device *dev);
static int silan_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void silan_rx(struct net_device *dev);
static int silan_close(struct net_device *dev);
static void silan_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void silan_config_media(struct net_device *dev);
static void mii_cmd_select(void *ioaddr, unsigned long cmd, unsigned long *phys);
static void silan_init_ring(struct net_device *dev);
static void silan_tx_clear(struct silan_private *adapter);
static void silan_tx_timeout(struct net_device *device);
static void silan_tx_interrupt(struct net_device *dev);
static void silan_rx_err(uint32_t rx_status, struct net_device *dev,
struct silan_private *adapter, uint32_t rx_size);
static void silan_mlink_intr(struct net_device *dev);
static void silan_remove(struct pci_dev *pdev);
static void Mii_ethtool_gset(void *ioaddr, struct ethtool_cmd *ecmd);
static int Mii_ethtool_sset(void *ioaddr, struct ethtool_cmd *ecmd);
static int Mii_link_ok(struct net_device *dev, void *ioaddr);
static int Mii_restart(void *ioaddr);
static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);
static struct net_device_stats *silan_get_stats(struct net_device *dev);
static uint32_t silan_ether_crc32(unsigned long length, unsigned char *data);
static void silan_set_multi_list(struct net_device *dev);
static void silan_rx_mode(struct net_device *dev);
#ifdef CONFIG_PM
static int silan_suspend(struct pci_dev *pdev, uint32_t state);
static int silan_resume(struct pci_dev *pdev);
#endif
static int __devinit silan_probe(struct pci_dev *pdev,const struct pci_device_id *id)
{
struct net_device *dev = NULL;
struct silan_private *adapter;
uint32_t pio_start, pio_end, pio_flags, pio_len;
unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
void *ioaddr;
int rc;
int i;
uint8_t pci_rev;
uint16_t pci_command;
assert (pdev != NULL);
assert (id != NULL);
pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
if ((pdev->vendor == 0x1904) && (pdev->device == 0x8139)) {
printk(KERN_INFO "pci dev %s (id %04x:%04x rev %02x) \n",
pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
} else {
printk( KERN_INFO " unkown chip \n");
return -ENODEV;
}
// configure pci command
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
if ((pci_command & (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |PCI_COMMAND_IO)) != 0x7) {
pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |PCI_COMMAND_IO;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
}
dev = alloc_etherdev(sizeof(*adapter));
if (dev == NULL) {
printk (KERN_ERR "%s: Unable to alloc new net device\n", pdev->slot_name);
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
adapter = dev->priv;
memset(adapter,0 ,sizeof(*adapter));
adapter->pdev = pdev;
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pci_enable_device(pdev);
if (rc){
goto err_out;
}
pio_start = pci_resource_start(pdev, 1);
pio_end = pci_resource_end(pdev, 1);
pio_flags = pci_resource_flags(pdev, 1);
pio_len = pci_resource_len(pdev, 1);
mmio_start = pci_resource_start(pdev, 0);
mmio_end = pci_resource_end(pdev, 0);
mmio_flags = pci_resource_flags(pdev, 0);
mmio_len = pci_resource_len(pdev, 0);
PDEBUG("PIO region size == 0x%02x\n", pio_len);
PDEBUG("MMIO region size == 0x%02lx\n", mmio_len);
#ifdef USE_IO_OPS
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
printk(KERN_ERR "%s: region #0 not a PIO resource, aborting\n",
pdev->slot_name);
rc = -ENODEV;
goto err_out;
}
/* check for PCI region reporting */
if (pio_len < 0x80) {
printk(KERN_ERR "%s: Invalid PCI I/O region size(s), aborting\n",
pdev->slot_name);
rc = -ENODEV;
goto err_out;
}
#else
// make sure PCI base addr 1 is MMIO
if (!(mmio_flags & IORESOURCE_MEM)) {
printk(KERN_ERR "%s: region #1 not an MMIO resource, aborting\n",
pdev->slot_name);
rc = -ENODEV;
goto err_out;
}
if (mmio_len < 0x80) {
printk(KERN_ERR "%s: Invalid PCI mem region size(s), aborting\n",
pdev->slot_name);
rc = -ENODEV;
goto err_out;
}
#endif
rc = pci_request_regions(pdev, (char *)DRV_NAME);
if (rc)
goto err_out;
/* enable PCI bus-mastering */
pci_set_master (pdev);
#ifdef USE_IO_OPS
ioaddr = (void *)pio_start;
dev->base_addr = pio_start;
adapter->mmio_addr = ioaddr;
#else
// ioremap MMIO region
ioaddr = ioremap(mmio_start, mmio_len);
if (ioaddr == NULL) {
printk (KERN_ERR "%s: cannot remap MMIO, aborting\n", pdev->slot_name);
rc = -EIO;
goto err_out;
}
dev->base_addr = (unsigned long)ioaddr;
adapter->mmio_addr = ioaddr;
#endif /* USE_IO_OPS */
printk(KERN_INFO "PCI PM Wakeup\n");
SILAN_W32(PMConfig, ((~PM_LongWF & ~PM_LWPTN ) | PM_Enable));
assert (ioaddr != NULL);
assert (dev != NULL);
assert (adapter != NULL);
((uint32_t *)(dev->dev_addr))[0] = be32_to_cpu(SILAN_R32(MAC0));
((uint16_t *)(dev->dev_addr))[2] = be16_to_cpu(SILAN_R32(MAC0+4));
/* The SILAN-specific entries in the device structure. */
dev->open = silan_open;
dev->hard_start_xmit = silan_start_xmit;
dev->stop = silan_close;
dev->get_stats = silan_get_stats;
dev->set_multicast_list = silan_set_multi_list;
dev->do_ioctl = netdev_ioctl;
dev->tx_timeout = silan_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->irq = pdev->irq;
/* dev is fully set up and ready to use now */
PDEBUG("register device named %s (%p)\n", dev->name, dev);
i = register_netdev(dev);
if (i)
goto err_out;
pci_set_drvdata(pdev, dev);
spin_lock_init(&adapter->lock);
adapter->packet_filter = dev->flags & (IFF_PROMISC|IFF_ALLMULTI|IFF_MULTICAST|IFF_BROADCAST);
printk(KERN_INFO "%s: at 0x%lx, %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,IRQ %d\n",
dev->name, dev->base_addr,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5],
dev->irq);
return 0;
err_out:
#ifndef USE_IO_OPS
if (adapter->mmio_addr)
iounmap(adapter->mmio_addr);
#endif /* !USE_IO_OPS */
pci_release_regions(pdev);
#ifndef SILAN_NDEBUG
memset(dev, 0, sizeof(struct net_device) + sizeof(struct silan_private));
#endif
kfree(dev);
dev = NULL;
pci_set_drvdata(pdev, NULL);
return rc;
}
static void mii_cmd_select(void *ioaddr, unsigned long cmd, unsigned long *phys)
{
unsigned long mii_status;
assert (ioaddr != NULL);
SILAN_W32(Miicmd0, Mii_Divider);
do {
mii_status = 0;
udelay(10);
mii_status = SILAN_R32(Miistatus);
} while (mii_status & Mii_StatusBusy);
switch (cmd){
case Mii_SCAN:
SILAN_W32(Miicmd1, 0x1 << 6);
SILAN_W32(Miicmd0, Mii_Divider | Mii_SCAN);
break;
case Mii_READ:
SILAN_W32(Miicmd1, phys[0] << 6);
SILAN_W32(Miicmd0, Mii_Divider | Mii_READ);
break;
default: /* WRITE*/
SILAN_W32(Miicmd1, phys[0] << 6 | phys[1] << 11);
SILAN_W32(Miicmd0, Mii_Divider | Mii_WRITE);
break ;
}
do {
udelay(10);
mii_status = SILAN_R32(Miistatus);
} while (mii_status & Mii_StatusBusy);
if (Mii_READ == cmd) {
phys[1] = (mii_status >> 13) & 0xffff;
}
}
static void silan_config_media(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
unsigned long phys[2];
unsigned long temp;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
adapter->mediaopt = work_mode;
temp = SILAN_R32(PhyCtrl);
temp &=~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
temp |= (PhyCtrlAne | PhyCtrlReset);
switch (adapter->mediaopt) {
case Autoselect:
printk(KERN_INFO "autoselect supported\n");
temp |= (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
break;
case M10_Half:
printk(KERN_INFO "10M half_duplex supported\n");
temp |= PhyCtrlSpd10;
break;
case M10_Full:
printk(KERN_INFO "10M Full_duplex supported\n");
temp |= (PhyCtrlDux |PhyCtrlSpd10);
break;
case M100_Half:
printk(KERN_INFO "100M half_duplex supported\n");
temp |= PhyCtrlSpd100;
break;
case M100_Full:
printk(KERN_INFO "100M full_duplex supported\n");
temp |= (PhyCtrlDux |PhyCtrlSpd100);
break;
default:
break;
}
SILAN_W32(PhyCtrl,temp);
mdelay(10);
temp &=~PhyCtrlReset;
SILAN_W32(PhyCtrl,temp);
mdelay(1);
phys[0] = Mii_JAB;
phys[1] = PHY_16_JAB_ENB |PHY_16_PORT_ENB;
mii_cmd_select(ioaddr, Mii_WRITE, phys);
netif_carrier_off(dev);
netif_stop_queue(dev);
mii_cmd_select(ioaddr, Mii_SCAN, phys);
return;
}
static unsigned char shade_map[ ] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
static uint32_t silan_ether_crc32(unsigned long length, unsigned char *data)
{
uint32_t crc = 0xffffffff;
uint32_t crcr = 0;
int current_octet = 0;
int bit = 0;
for (; length>0; length--) {
current_octet = *data++;
for (bit = 0; bit < 8; bit++){
if (((current_octet& 0x1)^(crc & 0x1)) != 0) {
crc >>= 1;
crc ^= 0xEDB88320;
} else {
crc >>= 1;
}
current_octet >>= 1;
}
}
crcr = shade_map[crc >> 28];
crcr |= (shade_map[(crc >> 24) & 0xf] << 4);
crcr |= (shade_map[(crc >> 20) & 0xf] << 8);
crcr |= (shade_map[(crc >> 16) & 0xf] << 12);
crcr |= (shade_map[(crc >> 12) & 0xf] << 16);
crcr |= (shade_map[(crc >> 8) & 0xf] << 20);
crcr |= (shade_map[(crc >> 4) & 0xf] << 24);
crcr |= (shade_map[crc & 0xf] << 28);
return crcr;
}
static void silan_set_multi_list(struct net_device *dev)
{
struct silan_private * adapter = dev->priv;
void * ioaddr = adapter->mmio_addr;
uint32_t mc_filter[2]={0,0};
int i, j, mc_max;
uint32_t crc;
struct dev_mc_list *mclist;
if(dev->flags & IFF_PROMISC) {
printk(" %s: promisc mode is enable.\n",dev->name);
mc_filter[0] = mc_filter[1] = 0xffffffff;
} else if (dev->flags & IFF_ALLMULTI) {
printk("%s: allmulti mode is enable.\n",dev->name);
mc_filter[0] = mc_filter[1] = 0xffffffff;
} else if ((dev->flags & IFF_MULTICAST) && (dev->mc_count > 0)) {
assert(NULL != dev->mc_list);
PDEBUG("multicast mode is enabled.\n");
mc_filter[0] = mc_filter[1] = 0;
mc_max = dev->mc_count > multicast_filter_limit ? multicast_filter_limit : dev->mc_count;
mclist = dev->mc_list;
for (i=0; (NULL!= mclist) && (i < mc_max); i++, mclist=mclist->next) {
j=0;
crc = ~silan_ether_crc32(ETH_ALEN, mclist->dmi_addr);
crc >>= 24;
if (crc & 0x1) j |= 0x2;
if (crc & 0x2) j |= 0x1;
if (crc & 0x10) j |= 0x20;
if (crc & 0x20) j |= 0x10;
if (crc & 0x40) j |= 0x8;
if (crc & 0x80) j |= 0x4;
if (j > 31) {
mc_filter[0] |= (0x1 << (j - 32));
} else {
mc_filter[1] |= (0x1 << j);
}
}
}
SILAN_W32 ((MAR0 + 0), mc_filter[0]);
SILAN_W32 ((MAR0 + 4), mc_filter[1]);
if ((netif_carrier_ok(dev))
&& (adapter->packet_filter != (dev->flags & (IFF_PROMISC|IFF_ALLMULTI|IFF_MULTICAST|IFF_BROADCAST)))) {
silan_rx_mode(dev);
adapter->packet_filter = dev->flags & (IFF_PROMISC|IFF_ALLMULTI|IFF_MULTICAST|IFF_BROADCAST);
}
}
static void silan_rx_mode(struct net_device *dev)
{
struct silan_private * adapter = dev->priv;
void * ioaddr = adapter->mmio_addr;
uint32_t rx_mode = 0;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
PDEBUG("adapter->rx_config = 0x%x dev->flags = 0x%x\n", adapter->rx_config, dev->flags);
if (adapter->packet_filter & IFF_PROMISC)
rx_mode = RxEnb|RxSmall|RxHuge|RxErr|RxBroadcast|RxMulticast|RxAllphys;
if (adapter->packet_filter & (IFF_ALLMULTI | IFF_MULTICAST))
rx_mode = RxEnb|RxMulticast;
if (adapter->packet_filter & IFF_BROADCAST)
rx_mode = RxEnb|RxBroadcast;
if ((adapter->rx_config | rx_mode) != adapter->rx_config) {
adapter->rx_config |= rx_mode;
SILAN_W32(RxConfig, adapter->rx_config);
}
PDEBUG("ADAPTER->RX_CONFIG = 0x%x\n", adapter->rx_config);
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void silan_init_ring(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
int i;
assert (dev != NULL);
adapter->cur_tx = 0;
adapter->dirty_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
adapter->tx_buf[i] = &adapter->tx_bufs[i * TX_BUF_SIZE];
adapter->tx_info[i].skb = NULL;
adapter->tx_info[i].mapping = 0;
}
adapter->dirty_rx = adapter->rx_ring_dma;
adapter->media_duplex = 0;
adapter->media_link_speed = 0;
}
static void silan_tx_clear(struct silan_private *adapter)
{
int i;
adapter->cur_tx = 0;
adapter->dirty_tx = 0;
/* dump the unsent Tx packets */
for (i = 0; i < NUM_TX_DESC; i++) {
if (adapter->tx_info[i].mapping != 0) {
pci_unmap_single(adapter->pdev, adapter->tx_info[i].mapping,
adapter->tx_info[i].skb->len, PCI_DMA_TODEVICE);
adapter->tx_info[i].mapping = 0;
}
if (adapter->tx_info[i].skb ) {
dev_kfree_skb(adapter->tx_info[i].skb);
adapter->tx_info[i].skb = NULL;
adapter->net_stats.tx_dropped++;
}
}
}
/* Start the hardware at open or resume.*/
static void silan_hw_init(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
int i;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
//disable PM
SILAN_W32(PMConfig,0);
// soft reset the chip
SILAN_W32(Config0, Cfg0_Reset);
mdelay(200);
SILAN_W32(Config0, 0);
mdelay(10);
//disable interrupt
SILAN_W32(IntrMask, 0);
// clear multicast address
SILAN_W32(MAR0 + 0, 0);
SILAN_W32(MAR0 + 4, 0);
// init Rx ring buffer DMA address
SILAN_W32(RxbufAddr, adapter->rx_ring_dma);
// init Tx buffer DMA addresses
for (i = 0; i < NUM_TX_DESC; i++)
SILAN_W32(TxAddr0 + (i * 4),
adapter->tx_bufs_dma + (adapter->tx_buf[i] - adapter->tx_bufs));
// configure rx buffer size
if (adapter->tx_early_ctrl && adapter->rx_early_ctrl)
SILAN_W32(Config1, Cfg1_EarlyRx | Cfg1_EarlyTx | Cfg1_Rcv64K | RX_FIFO_THRESH << 21);
else if (adapter->tx_early_ctrl)
SILAN_W32( Config1, Cfg1_EarlyTx | Cfg1_Rcv64K);
else if (adapter->rx_early_ctrl)
SILAN_W32(Config1, Cfg1_EarlyRx | Cfg1_Rcv64K | RX_FIFO_THRESH << 21);
else
SILAN_W32(Config1, Cfg1_Rcv64K);
// configure media mode
silan_config_media(dev);
//enable rx and tx
if (netif_carrier_ok(dev)) {
adapter->rx_config |= RxEnb;
adapter->tx_config |= TxEnb;
} else {
adapter->rx_config &= ~RxEnb;
adapter->tx_config &= ~TxEnb;
}
SILAN_W32(RxConfig, adapter->rx_config);
SILAN_W32(TxConfig, adapter->tx_config);
/* calculate rx fifo overflow */
adapter->rx_value = 0;
//clear INT register
adapter->intr_status = SILAN_R32(IntrStatus);
// Enable all known interrupts by setting the interrupt mask.
SILAN_W32(IntrMask, IntrBits);
}
static int silan_open(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
int retval;
unsigned long flags;
assert (dev != NULL);
assert (adapter != NULL);
retval = request_irq(dev->irq, silan_interrupt, SA_SHIRQ, dev->name, dev);
if (retval) {
return retval;
}
adapter->tx_bufs = pci_alloc_consistent(adapter->pdev, TX_BUF_TOT_LEN,
&adapter->tx_bufs_dma);
adapter->rx_ring = pci_alloc_consistent(adapter->pdev, RX_BUF_LEN,
&adapter->rx_ring_dma);
if (adapter->tx_bufs == NULL || adapter->rx_ring == NULL) {
free_irq(dev->irq, dev);
if (adapter->tx_bufs)
pci_free_consistent(adapter->pdev, TX_BUF_TOT_LEN,
adapter->tx_bufs, adapter->tx_bufs_dma);
if (adapter->rx_ring)
pci_free_consistent(adapter->pdev, RX_BUF_LEN ,
adapter->rx_ring, adapter->rx_ring_dma);
return -ENOMEM;
}
spin_lock_irqsave(&adapter->lock, flags);
silan_init_ring(dev); // initial tx/rx variable
silan_hw_init(dev); // hardware initialize
spin_unlock_irqrestore(&adapter->lock, flags);
PDEBUG("%s: silan_open() ioaddr 0x%lx IRQ %d \n",
dev->name, pci_resource_start (adapter->pdev, 1), dev->irq);
return 0;
}
static void silan_tx_timeout(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
int i;
unsigned long flags;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
adapter->tx_timeouts++;
printk("Tx is time out count:%ld\n", adapter->tx_timeouts);
/* Disable interrupts by clearing the interrupt mask.*/
SILAN_W32(IntrMask, 0);
PDEBUG("%s: Tx queue cur entry %ld dirty entry %ld timeout counts %ld\n",
dev->name, adapter->cur_tx, adapter->dirty_tx, adapter->tx_timeouts);
for (i = 0; i < NUM_TX_DESC; i++) {
PDEBUG("%s: Tx descriptor %d is 0x%8.8lx.%s\n",
dev->name, i, SILAN_R32(TxStatus0 +(i * 4)),
i == (int)(adapter->dirty_tx % NUM_TX_DESC) ? " (queue head)" : "");
}
/* Stop a shared interrupt */
spin_lock_irqsave(&adapter->lock, flags);
silan_tx_clear(adapter);
spin_unlock_irqrestore(&adapter->lock, flags);
/* reset everything */
silan_hw_init(dev);
silan_set_multi_list(dev);
netif_wake_queue(dev);
}
static int silan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
int entry;
int len = skb->len;
if(skb == NULL || len <= 0) {
printk(KERN_WARNING "%s: driver layer request mode: skbuff==NULL\n", dev->name);
return 0;
}
// Calculate the next Tx descriptor entry.
entry = adapter->cur_tx % NUM_TX_DESC;
assert(adapter->tx_info[entry].skb == NULL);
assert(adapter->tx_info[entry].mapping == 0);
adapter->tx_info[entry].skb = skb;
/* for skb->len < 60, padding payload with 0x20. */
if ((len < ETH_ZLEN) && (!adapter->txenablepad)) {
//adapter->tx_info[entry].mapping = 0;
memcpy(adapter->tx_buf[entry], skb->data, len);
memset(adapter->tx_buf[entry] + len, 0x20, (ETH_ZLEN - len) );
SILAN_W32(TxAddr0 + entry*4, adapter->tx_bufs_dma + (adapter->tx_buf[entry] - adapter->tx_bufs));
len = ETH_ZLEN;
}
else if ((long)skb->data & 3) {
//adapter->tx_info[entry].mapping = 0;
memcpy(adapter->tx_buf[entry], skb->data, len);
SILAN_W32(TxAddr0 + entry*4, adapter->tx_bufs_dma + (adapter->tx_buf[entry] - adapter->tx_bufs));
}
else {
adapter->tx_info[entry].mapping =
pci_map_single(adapter->pdev, skb->data, len, PCI_DMA_TODEVICE);
SILAN_W32(TxAddr0 + entry*4, adapter->tx_info[entry].mapping);
}
if (len < 100)
SILAN_W32(TxStatus0 + entry*4, len);
else if (len <300)
SILAN_W32(TxStatus0 + entry*4, 0x30000 | len);
else
SILAN_W32(TxStatus0 + entry*4, 0x50000 | len);
dev->trans_start = jiffies;
spin_lock_irq(&adapter->lock);
adapter->cur_tx++;
if ((adapter->cur_tx - adapter->dirty_tx) == NUM_TX_DESC)
netif_stop_queue(dev);
spin_unlock_irq(&adapter->lock);
PDEBUG("%s: Queued Tx packet size %d to tx-buffer %d.\n",
dev->name, len, entry);
return 0;
}
static void silan_tx_interrupt(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
int entry;
unsigned long dirty_tx;
unsigned long tx_status;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
dirty_tx = adapter->dirty_tx;
while (adapter->cur_tx - dirty_tx > 0) {
entry = dirty_tx % NUM_TX_DESC;
tx_status = SILAN_R32(TxStatus0 + (entry * 4));
PDEBUG("entry = 0x%x, tx_status = 0x%8.8lx \n", entry, tx_status);
if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted))) {
//printk("no tx packet will be transmitted .\n" );
break;
}
if (tx_status & TxStatOK) {
adapter->net_stats.tx_bytes += tx_status & 0x1fff;
adapter->net_stats.tx_packets++;
/* Note: TxCarrierLost is always asserted at 100mbps. */
adapter->net_stats.collisions += (tx_status >> 22) & 0xf;
}
if (tx_status & (TxOutOfWindow | TxAborted)) {
printk (KERN_NOTICE "%s: Transmit error.\n",dev->name);
adapter->net_stats.tx_errors++;
if (tx_status & TxAborted)
adapter->net_stats.tx_aborted_errors++;
if (tx_status & TxCarrierLost) {
adapter->net_stats.tx_carrier_errors++;
}
if (tx_status & TxOutOfWindow)
adapter->net_stats.tx_window_errors++;
}
if (tx_status & TxUnderrun)
adapter->net_stats.tx_fifo_errors++;
// free the TX packets
if (adapter->tx_info[entry].mapping != 0) {
pci_unmap_single(adapter->pdev, adapter->tx_info[entry].mapping,
adapter->tx_info[entry].skb->len, PCI_DMA_TODEVICE);
adapter->tx_info[entry].mapping = 0;
}
dev_kfree_skb_irq(adapter->tx_info[entry].skb);
adapter->tx_info[entry].skb = NULL;
PDEBUG("%s: tx done, slot %ld.\n", dev->name, dirty_tx);
dirty_tx++;
}
#ifndef SILAN_NDEBUG
if (adapter->cur_tx - dirty_tx > NUM_TX_DESC) {
printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs %ld.\n",
dev->name, dirty_tx, adapter->cur_tx);
dirty_tx += NUM_TX_DESC;
}
#endif
if (adapter->dirty_tx != dirty_tx) {
adapter->dirty_tx = dirty_tx;
if (netif_queue_stopped (dev))
netif_wake_queue (dev);
}
}
static void silan_rx_err(uint32_t rx_status, struct net_device *dev,
struct silan_private *adapter, uint32_t rx_size)
{
PDEBUG("%s: Ethernet frame had rx error, status %8.8x.\n",
dev->name, rx_status);
if((rx_size > (MAX_ETH_FRAME_SIZE + 4)) || (rx_size < 16)) {
PDEBUG(KERN_NOTICE "%s: Ethernet frame lengh too long or short!\n", dev->name);
adapter->net_stats.rx_errors++;
adapter->net_stats.rx_length_errors++;
}
if (!(rx_status & RxStatesOK)) {
adapter->net_stats.rx_errors++;
if (rx_status & (RxHugeFrame | RxSmallFrame )){
PDEBUG(KERN_NOTICE "%s: Ethernet frame lengh errors!\n", dev->name);
adapter->net_stats.rx_length_errors++;
}
if (rx_status & RxBadAlign) {
adapter->net_stats.rx_frame_errors++;
PDEBUG("rx_frame_error\n");
}
if (!(rx_status & RxCRCOK))
adapter->net_stats.rx_crc_errors++;
} else {
adapter->rx_loss++;
}
}
static void silan_rx(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
unsigned char *rx_ring;
unsigned long cur_rx;
unsigned long ring_offset;
uint32_t rx_status;
unsigned long rx_size;
unsigned long pkt_size;
unsigned long semi_len;
struct sk_buff *skb;
long rx_len;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr!= NULL);
cur_rx = SILAN_R32(RxBufWPtr);
/* cur_rx is only 17 bits in the RxBufWPtr register. if cur_rx can be used in physical space,
* we need to change it to 32 bits physical address
*/
cur_rx |= adapter->rx_ring_dma & (~(unsigned long)(RX_BUF_LEN - 1));
if(cur_rx < adapter->rx_ring_dma)
cur_rx = cur_rx + RX_BUF_LEN;
if(cur_rx >= adapter->dirty_rx)
rx_len = (long)(cur_rx - adapter->dirty_rx);
else
rx_len = (long)(RX_BUF_LEN - (adapter->dirty_rx - cur_rx));
rx_ring = adapter->rx_ring;
ring_offset = (adapter->dirty_rx - adapter->rx_ring_dma) & (unsigned long)(RX_BUF_LEN - 1);
PDEBUG("in rx cur_rx %8.8lx ring_dma %8.8x rx_len %ld ring_offset %8.8lx\n",
cur_rx, adapter->rx_ring_dma, rx_len, ring_offset);
if (rx_len > RX_BUF_LEN) {
PDEBUG("rx packets length > rx buffer\n");
return;
}
if (rx_len == 0)
return;
spin_lock(&adapter->lock);
while (rx_len > 0 ) {
rx_status = *(uint32_t *)(rx_ring + ring_offset);
rx_size = rx_status >> 20 ;
rx_size = (rx_size + 3) & ~3; //for 4 bytes aligned
pkt_size = rx_size - 4; // Omit the four octet CRC from the length.
PDEBUG("%s:rx_status %8.8x, rx_size %ld.\n", dev->name, rx_status, rx_size);
#if (SILAN_DEBUG > 1)
{
PDEBUG ("%s: Frame contents\n ", dev->name);
int i;
for (i = 0; i < 30; i++){
if (i % 10 == 0) printk ("\n");
printk (" %2.2x", rx_ring[ring_offset + i]);
}
printk("\n");
}
#endif
if ((rx_status == 0) || (rx_size > (MAX_ETH_FRAME_SIZE + 4)) || (rx_size < 16) || !(rx_status & RxStatesOK)) {
silan_rx_err (rx_status, dev, adapter,rx_size);
break;
}
rx_len -= (long)(rx_size + 4);
if (rx_len > RX_BUF_LEN) {
printk(KERN_ERR "rx_len is too huge, rx_len = %ld\n", rx_len);
break;
}
if (rx_len < 0) {
printk(KERN_ERR "rx_len is too small\n");
break;
}
// Malloc up new buffer
skb = dev_alloc_skb(pkt_size + 2);
if (skb == NULL) {
printk (KERN_WARNING "%s: Couldn't allocate a skb_buff of size %ld. \n",
dev->name, pkt_size);
adapter->net_stats.rx_dropped++;
}
else {
skb->dev = dev;
skb_reserve(skb, 2); // 16 byte align the IP fields.
if ((ring_offset + rx_size) > RX_BUF_LEN) {
semi_len = (unsigned long)RX_BUF_LEN -(4 + ring_offset);// 4 bytes for receive frame header
memcpy(skb_put(skb, semi_len), &rx_ring[ring_offset + 4], semi_len);
memcpy(skb_put(skb, pkt_size - semi_len), rx_ring, pkt_size -semi_len);
}
else {
#if HAS_IP_COPYSUM
eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
skb_put (skb, pkt_size);
#else
memcpy(skb_put(skb,pkt_size),&rx_ring[ring_offset+4], pkt_size);
#endif
}
skb->protocol = eth_type_trans(skb, dev);
dev->last_rx = jiffies;
netif_rx(skb);
adapter->net_stats.rx_bytes += pkt_size;
adapter->net_stats.rx_packets++;
if (rx_status & Rx_Multicast)
adapter->net_stats.multicast++;
PDEBUG("rx_bytes = %ld,rx_packets = %ld,multicast = %ld.\n",
adapter->net_stats.rx_bytes,
adapter->net_stats.rx_packets, adapter->net_stats.multicast);
}
ring_offset = (ring_offset + rx_size + 4)&(unsigned long)(RX_BUF_LEN - 1); // 4 bytes for receive frame head
}
spin_unlock(&adapter->lock);
adapter->dirty_rx = cur_rx;
SILAN_W32(RxBufRPtr, adapter->dirty_rx);
PDEBUG("%s: Done siln8139d_rx(), current dirty_rx = %8.8lx \n",
dev->name, adapter->dirty_rx);
}
/* media link interrupt */
static void silan_mlink_intr(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
unsigned long phys[2];
uint32_t flow_cfg = 0;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
phys[0] = MII_BMSR;
mii_cmd_select(ioaddr, Mii_READ, phys);
PDEBUG("mii_status = %4.4lx\n", phys[1]);
if ((phys[1] & BMSR_LSTATUS) == 0) {
printk(KERN_INFO "%s: media is unconnected, link down, or incompatible connection\n",
dev->name);
netif_carrier_off(dev);
netif_stop_queue(dev);
adapter->net_stats.tx_carrier_errors++;
mii_cmd_select(ioaddr, Mii_SCAN, phys);
//disable rx/tx
adapter->rx_config &= ~RxEnb;
adapter->tx_config &= ~TxEnb;
SILAN_W32(RxConfig, adapter->rx_config);
SILAN_W32(TxConfig, adapter->tx_config);
return;
}
printk(KERN_INFO "%s: media is connected--->", dev->name);
netif_carrier_on(dev);
phys[0] = Mii_OutputStatus;
mii_cmd_select(ioaddr, Mii_READ, phys);
adapter->media_duplex = (phys[1] & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
adapter->media_link_speed = (phys[1] & 0x2) ? SPEED_100 :SPEED_10;
printk(KERN_INFO "speed:%dM, duplex:%s.\n",
adapter->media_link_speed,
(adapter->media_duplex == 0x0001)? "full":"half");
mii_cmd_select(ioaddr, Mii_SCAN, phys);
// Initial Tx/Rx configuration
adapter->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
adapter->tx_config = 0x48800000 ;
if (adapter->txenablepad)
adapter->tx_config |= 0x20000000;
if (adapter->media_link_speed == SPEED_10)
adapter->tx_config |= 0x80000;
// configure rx mode
silan_rx_mode(dev);
/* configure Rx register */
silan_set_multi_list(dev);
if (adapter->media_duplex == DUPLEX_FULL) {
adapter->rx_config |= RxFullDx;
adapter->tx_config |= TxFullDx;
flow_cfg = FlowCtrlFullDX | FlowCtrlEnb;
} else {
adapter->rx_config &= ~RxFullDx;
adapter->tx_config &= ~TxFullDx;
}
//enable rx and tx
adapter->rx_config |= RxEnb;
adapter->tx_config |= TxEnb;
SILAN_W32(RxConfig, adapter->rx_config);
SILAN_W32(TxConfig, adapter->tx_config);
SILAN_W32(FlowCtrlConfig, flow_cfg);
netif_start_queue(dev);
}
static void silan_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
SILAN_W32(IntrMask, 0);
adapter->intr_status = SILAN_R32(IntrStatus) & IntrBits;
if ((adapter->intr_status == 0xffffffff) || (adapter->intr_status == 0))
return;
while (0 != adapter->intr_status) {
PDEBUG("%s: interrupt status = %#8.8x\n",dev->name, adapter->intr_status);
/* interrupt after transfering data */
if (netif_running(dev) && (adapter->intr_status & TxOK )) {
spin_lock(&adapter->lock);
silan_tx_interrupt (dev);
spin_unlock(&adapter->lock);
}
/* receive interrupt */
if (netif_running(dev) && (adapter->intr_status & RxOK)) {
silan_rx(dev);
}
/* media link interrupt.*/
if (adapter->intr_status & (LinkFail | LinkOK)) {
silan_mlink_intr(dev);
}
if (netif_running(dev) && adapter->intr_status & RxOverflow) {
printk(KERN_WARNING "rx buffer is full!\n");
adapter->net_stats.rx_errors++;
}
if (adapter->intr_status & TimeOut) {
printk(KERN_WARNING "time is too long \n");
adapter->net_stats.rx_errors++;
adapter->net_stats.rx_length_errors++;
}
adapter->intr_status = SILAN_R32(IntrStatus) & IntrBits;
}
// Enable all known interrupts by setting the interrupt mask.
SILAN_W32(IntrMask, IntrBits);
return;
}
static int silan_close(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
unsigned long flags;
assert (dev != NULL);
assert (adapter != NULL);
assert (ioaddr != NULL);
netif_stop_queue(dev);
spin_lock_irqsave(&adapter->lock, flags);
/* Stop the chip's Tx and Rx DMA processes. */
adapter->rx_config &= ~RxEnb;
adapter->tx_config &= ~TxEnb;
SILAN_W32(RxConfig, adapter->rx_config);
SILAN_W32(RxConfig, adapter->tx_config);
/* Disable interrupts by clearing the interrupt mask. */
SILAN_W32(IntrMask, 0);
spin_unlock_irqrestore(&adapter->lock, flags);
synchronize_irq( );
free_irq(dev->irq, dev);
silan_tx_clear(adapter);
adapter->dirty_rx = adapter->rx_ring_dma;
pci_free_consistent(adapter->pdev, RX_BUF_LEN,
adapter->rx_ring, adapter->rx_ring_dma);
pci_free_consistent(adapter->pdev, TX_BUF_TOT_LEN,
adapter->tx_bufs, adapter->tx_bufs_dma);
adapter->rx_ring = NULL;
adapter->tx_bufs = NULL;
return 0;
}
#ifdef CONFIG_PM
static int silan_suspend(struct pci_dev *pdev, u32 state)
{
struct net_device *dev = pci_get_drvdata (pdev);
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
unsigned long flags;
if (!netif_running(dev))
return 0;
netif_device_detach(dev);
spin_lock_irqsave(&adapter->lock, flags);
/* Disable interrupts, stop Tx and Rx. */
SILAN_W32(IntrMask, 0);
adapter->rx_config &= ~RxEnb;
adapter->tx_config &= ~TxEnb;
SILAN_W32(RxConfig, adapter->rx_config);
SILAN_W32(RxConfig, adapter->tx_config);
spin_unlock_irqrestore(&adapter->lock, flags);
return 0;
}
static int silan_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (!netif_running (dev))
return 0;
netif_device_attach (dev);
silan_hw_init(dev);
return 0;
}
#endif
static void __devexit silan_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct silan_private *adapter;
assert (dev != NULL);
adapter = dev->priv;
assert (adapter != NULL);
unregister_netdev (dev);
#ifndef USE_IO_OPS
if (adapter->mmio_addr)
iounmap(adapter->mmio_addr);
#endif
pci_release_regions(pdev);
#ifndef SILAN8139D_NDEBUG
memset(dev, 0, sizeof(struct net_device) + sizeof(struct silan_private));
#endif
kfree(dev);
pci_set_drvdata(pdev,NULL);
return;
}
static struct net_device_stats *silan_get_stats(struct net_device *dev)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
unsigned long flags;
int temp = 0;
if (netif_running(dev)) {
spin_lock_irqsave(&adapter->lock, flags);
/* Update the error count. */
temp = (SILAN_R32(RxStatus0) >> 16) & 0xffff;
if( temp == 0xffff) {
adapter->rx_value += temp;
adapter->net_stats.rx_fifo_errors = adapter->rx_value;
} else {
adapter->net_stats.rx_fifo_errors = temp + adapter->rx_value;
}
spin_unlock_irqrestore(&adapter->lock, flags);
}
return &adapter->net_stats;
}
static void Mii_ethtool_gset(void * ioaddr, struct ethtool_cmd *ecmd)
{
unsigned long temp, phys[2];
ecmd->supported =
(M10_Half | M10_Full | M100_Half | M100_Full | Autoselect);
ecmd->phy_address = SILAN_R32(Miicmd1) >> 27;
temp = SILAN_R32(PhyCtrl);
if ((temp & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))== 0x60800000)
ecmd->advertising = Autoselect;
if ((temp & PhyCtrlSpd10)== 0x20000000)
ecmd->advertising = M10_Half;
if ((temp & (PhyCtrlSpd10 |PhyCtrlDux)) == 0x20800000)
ecmd->advertising = M10_Full;
if ((temp & PhyCtrlSpd100) == 0x40000000)
ecmd->advertising = M100_Half;
if ((temp & (PhyCtrlSpd100 |PhyCtrlDux)) == 0x40800000)
ecmd->advertising = M100_Full;
if (temp & PhyCtrlAne) {
ecmd->advertising = Autoselect;
ecmd->autoneg = AUTONEG_ENABLE;
} else {
ecmd->autoneg = AUTONEG_DISABLE;
}
phys[0] = Mii_OutputStatus;
mii_cmd_select(ioaddr, Mii_READ, phys);
ecmd->speed = phys[1] & 0x2 ? SPEED_100 :SPEED_10;
ecmd->duplex = phys[1] & 0x4 ? DUPLEX_FULL : DUPLEX_HALF;
mii_cmd_select (ioaddr, Mii_SCAN, phys);
return ;
}
static int Mii_ethtool_sset(void *ioaddr, struct ethtool_cmd *ecmd)
{
uint32_t temp, temp1;
if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
return -EINVAL;
if(ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
if (ecmd->phy_address != 0x1f)
return -EINVAL;
if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
return -EINVAL;
if (ecmd->autoneg == AUTONEG_ENABLE) {
if ((ecmd->advertising & (Autoselect|M10_Half |M10_Full |M100_Half |M100_Full)) == 0)
return -EINVAL;
temp = SILAN_R32(PhyCtrl);
temp1 = temp;
temp &=~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
temp |= PhyCtrlAne ;
switch (ecmd->advertising) {
case Autoselect:
printk(KERN_INFO "autoselect supported\n");
temp |= (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
break;
case M10_Half:
printk(KERN_INFO "10M half_duplex supported\n");
temp |= PhyCtrlSpd10;
break;
case M10_Full:
printk(KERN_INFO "10M Full_duplex supported\n");
temp |= (PhyCtrlDux |PhyCtrlSpd10);
break;
case M100_Half:
printk(KERN_INFO "100M half_duplex supported\n");
temp |= PhyCtrlSpd100;
break;
case M100_Full:
printk(KERN_INFO "100M full_duplex supported\n");
temp |= (PhyCtrlDux |PhyCtrlSpd100);
break;
default:
break;
}
if (temp1 != temp) {
SILAN_W32(PhyCtrl, temp);
}
}
return 0;
}
static int Mii_link_ok (struct net_device *dev, void *ioaddr)
{
unsigned long phys[2];
printk(" mii_link_ok called .\n");
phys[0] = MII_BMSR;
mii_cmd_select(ioaddr, Mii_READ, phys);
if (!(phys[1] & BMSR_LSTATUS)) {
netif_carrier_off(dev);
mii_cmd_select(ioaddr, Mii_SCAN, phys);
return(netif_carrier_ok(dev));
}
netif_carrier_on(dev);
mii_cmd_select(ioaddr, Mii_SCAN, phys);
return(netif_carrier_ok(dev));
}
static int Mii_restart(void *ioaddr)
{
unsigned long phys[2];
int err = -EINVAL;
/* if autoneg is off, it's an error */
phys[0] = MII_BMCR;
mii_cmd_select(ioaddr, Mii_READ, phys);
if (phys[1] & BMCR_ANENABLE) {
phys[1] |= BMCR_ANRESTART;
mii_cmd_select(ioaddr, Mii_WRITE, phys);
err = 0;
}
mii_cmd_select(ioaddr, Mii_SCAN, phys);
return err;
}
/* W ake-On-Lan options. */
#define SL_WAKE_PHY (1 << 0)
#define SL_WAKE_MAGIC (1 << 1)
#define SL_WAKE_MATCH (1 << 2)
/*Get the ethtool Wake-on-LAN settings. Assumes that wol points to
kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
other interrupts aren't messing with the 8139d. */
extern int netdev_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
u32 pmconfig = 0;
wol->supported = SL_WAKE_PHY | SL_WAKE_MAGIC | SL_WAKE_MATCH;
wol->wolopts = 0;
if (pmconfig & PM_LinkUp)
wol->wolopts |= SL_WAKE_PHY;
if (pmconfig & PM_Magic)
wol->wolopts |= SL_WAKE_MAGIC;
if (pmconfig & PM_WakeUp)
wol->wolopts |= SL_WAKE_MATCH;
return 0;
}
/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes
that wol points to kernel memory and other interrupts
aren't messing with the 8139d. */
extern int netdev_set_wol(struct net_device *dev, const struct ethtool_wolinfo *wol)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
u32 pmconfig = 0;
pmconfig = SILAN_R32(PMConfig) & (~(PM_LinkUp | PM_Magic | PM_WakeUp));
if (wol->wolopts & SL_WAKE_PHY)
pmconfig |= PM_LinkUp;
if (wol->wolopts & SL_WAKE_MAGIC)
pmconfig |= PM_Magic;
if (wol->wolopts & SL_WAKE_MATCH)
pmconfig |= PM_WakeUp;
SILAN_W32(PMConfig, pmconfig);
return 0;
}
static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
{
struct silan_private *adapter = dev->priv;
void *ioaddr = adapter->mmio_addr;
uint32_t ethcmd;
int r;
if (get_user(ethcmd, (u32 *)useraddr))
return -EFAULT; /* Bad address */
switch (ethcmd) {
/* Get driver info */
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strcpy(info.driver, DRV_NAME);
strcpy(info.version, DRV_VERSION);
strcpy(info.bus_info, adapter->pdev->slot_name);
if (copy_to_user (useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
}
/* get settings */
case ETHTOOL_GSET: {
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
spin_lock_irq(&adapter->lock);
Mii_ethtool_gset(ioaddr, &ecmd);
spin_unlock_irq(&np->lock);
if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
/*set settings */
case ETHTOOL_SSET: {
struct ethtool_cmd ecmd = { ETHTOOL_GSET};
if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
return -EFAULT;
spin_lock_irq(&adapter->lock);
r = Mii_ethtool_sset(ioaddr, &ecmd);
spin_unlock_irq(&adapter->lock);
return r;
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
edata.data = Mii_link_ok(dev, ioaddr);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
/* restart autonegotiation */
case ETHTOOL_NWAY_RST: {
r = Mii_restart(ioaddr);
return r;
}
/*Get wake-on-lan options*/
case ETHTOOL_GWOL:{
struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
spin_lock_irq (&adapter->lock);
netdev_get_wol(dev , &wol);
spin_unlock_irq (&adapter->lock);
if (copy_to_user (useraddr, &wol, sizeof (wol)))
return -EFAULT;
return 0;
}
/*Set wake-on-lan options */
case ETHTOOL_SWOL:{
struct ethtool_wolinfo wol ={ETHTOOL_SWOL};
int rc;
if(copy_from_user (&wol, useraddr, sizeof (wol)))
return -EFAULT;
spin_lock_irq (&adapter->lock);
rc = netdev_set_wol(dev, &wol);
spin_unlock_irq (&adapter->lock);
return rc;
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,18)
/* get string list(s) */
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
if (copy_from_user(&estr, useraddr, sizeof(estr)))
return -EFAULT;
if (estr.string_set != ETH_SS_STATS)
return -EINVAL;
estr.len = SILAN_STATE_NUM;
if (copy_to_user(useraddr, &estr, sizeof(estr)))
return -EFAULT;
if (copy_to_user(useraddr + sizeof(estr), ðtool_stats_keys, sizeof(ethtool_stats_keys)))
return -EFAULT;
return 0;
}
/* get NIC-specific statistics */
case ETHTOOL_GSTATS: {
struct ethtool_stats estats = { ETHTOOL_GSTATS };
u64 *tmp_state;
const unsigned int sz = sizeof(u64) * SILAN_STATE_NUM;
int i;
estats.n_stats = SILAN_STATE_NUM;
if (copy_to_user(useraddr, &estats, sizeof(estats)))
return -EFAULT;
tmp_state = kmalloc(sz, GFP_KERNEL);
if (!tmp_state)
return -ENOMEM;
memset(tmp_state, 0, sz);
i = 0;
tmp_state[i++] = adapter->tx_timeouts;
tmp_state[i++] = adapter->rx_loss;
if (i != SILAN_STATE_NUM)
BUG();
if(copy_to_user(useraddr + sizeof(estats), tmp_state, sz));
return -EFAULT;
kfree(tmp_state);
return 0;
}
#endif
default:
break;
}
/* Operation not supported on transport endpoint */
return -EOPNOTSUPP;
}
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
struct silan_private *adapter = dev->priv;
struct Mii_ioctl_data *data = (struct Mii_ioctl_data *)&rq->ifr_data;
void *ioaddr = adapter->mmio_addr;
unsigned long phys[2], flags;
int rc = 0;
spin_lock_irqsave (&adapter->lock, flags);
if (!netif_running(dev))
return -EINVAL; // Invalid argument
if (cmd == SIOCETHTOOL) {
return (netdev_ethtool_ioctl(dev, (void *) rq->ifr_data));
data->reg_num = (SILAN_R32(Miicmd1) >> 6) & 0x001f;
phys[0] = data->reg_num;
PDEBUG("reg_num-phys[0] = 0x%lx\n", phys[0]);
switch (cmd) {
case SIOCDEVPRIVATE:
data->phy_id = (SILAN_R32(Miicmd1) >> 27) & 0x001f;
break;
case SIOCDEVPRIVATE+1:
mii_cmd_select(ioaddr, Mii_READ, phys);
data->val_out = phys[1];
mii_cmd_select(ioaddr, Mii_SCAN, phys);
break;
default:
rc = -EOPNOTSUPP;
break;
}
}
spin_unlock_irqrestore(&adapter->lock, flags);
return rc;
}
static struct pci_driver silan_pci_driver = {
name: (char*) DRV_NAME,
id_table: silan_pci_tbl,
probe: silan_probe,
remove: __devexit_p(silan_remove),
#ifdef CONFIG_PM
suspend: silan_suspend,
resume: silan_resume,
#endif
};
static int __init silan_init_module(void)
{
unsigned char *work_mode1 = NULL;
#ifdef MODULE
printk (KERN_INFO SILAN_DRIVER_NAME "\n");
#endif
switch(work_mode){
case 0x00:
work_mode1 = "Autoselect";
break;
case 0x01:
work_mode1 = "10M Half_duplex";
break;
case 0x02:
work_mode1 = "10M Full_duplex";
break;
case 0x04:
work_mode1 = "100M Half_duplex";
break;
case 0x08:
work_mode1 = "100M Full_duplex";
break;
default:
break;
}
printk(KERN_INFO "work_mode -> %s\n ", work_mode1);
return pci_module_init(&silan_pci_driver);
}
static void __exit silan_cleanup_module(void)
{
pci_unregister_driver(&silan_pci_driver);
}
module_init(silan_init_module);
module_exit(silan_cleanup_module);
^ permalink raw reply
* Re: Driver for Rsltek 8139D / Silan SC92031
From: Stephen Hemminger @ 2006-06-02 20:28 UTC (permalink / raw)
To: Daniel Drake; +Cc: netdev, cantao
In-Reply-To: <44809CB5.50501@gentoo.org>
On Fri, 02 Jun 2006 21:16:53 +0100
Daniel Drake <dsd@gentoo.org> wrote:
> Here's a strange one. Cantao (on CC) bought what he thought was a cheap
> realtek PCI NIC, it actually turns out it is a Rsltek (yes, Rsltek)
> 8139D card.
>
> It includes an old (2.4/2.5) driver which claims to be for Silan SC92031
> (attached).
>
> The driver has some very obvious similarities with 8139too, however the
> register layout and usage is quite different.
>
> Has anyone got any idea whats going on here? It seems like something
> based on a realtek chip, but not...
>
> Daniel
>
It certainly is a good driver as is...
^ permalink raw reply
* Re: Driver for Rsltek 8139D / Silan SC92031
From: Stephen Hemminger @ 2006-06-02 20:57 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Daniel Drake, netdev, cantao
In-Reply-To: <20060602132846.2ee6c71a@localhost.localdomain>
On Fri, 2 Jun 2006 13:28:46 -0700
Stephen Hemminger <shemminger@osdl.org> wrote:
> On Fri, 02 Jun 2006 21:16:53 +0100
> Daniel Drake <dsd@gentoo.org> wrote:
>
> > Here's a strange one. Cantao (on CC) bought what he thought was a cheap
> > realtek PCI NIC, it actually turns out it is a Rsltek (yes, Rsltek)
> > 8139D card.
> >
> > It includes an old (2.4/2.5) driver which claims to be for Silan SC92031
> > (attached).
> >
> > The driver has some very obvious similarities with 8139too, however the
> > register layout and usage is quite different.
> >
> > Has anyone got any idea whats going on here? It seems like something
> > based on a realtek chip, but not...
> >
> > Daniel
> >
>
> It certainly is a good driver as is...
NOT
^ 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