9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-23 14:00 jmk
  0 siblings, 0 replies; 24+ messages in thread
From: jmk @ 2001-10-23 14:00 UTC (permalink / raw)
  To: 9fans

Kenji (okamoto@granite.cias.osakafu-u.ac.jp) actually tried my clock fix on the
distributed code and found at least two problems:

1) you must also add portclock.$O to the 'PORT=' section in alphapc/mkfile;
2) the declaration of the Mach structure 'inclockintr' element is missing
   in alphapc/dat.h - see pc/dat.h for where it goes.

There may be more. Sorry about that and thanks Kenji.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-11-05 10:21       ` Jonadab the Unsightly One
@ 2001-11-05 11:42         ` Boyd Roberts
  0 siblings, 0 replies; 24+ messages in thread
From: Boyd Roberts @ 2001-11-05 11:42 UTC (permalink / raw)
  To: 9fans

> 248622 is a ...

It was my Digital badge #.  The thread was about research in Digital IIRC.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-25  6:06     ` andrey mirtchovski
@ 2001-11-05 10:21       ` Jonadab the Unsightly One
  2001-11-05 11:42         ` Boyd Roberts
  0 siblings, 1 reply; 24+ messages in thread
From: Jonadab the Unsightly One @ 2001-11-05 10:21 UTC (permalink / raw)
  To: 9fans

aam396@mail.usask.ca (andrey mirtchovski) writes:

> incidentally #248622 is exactly the size of my xmahjong executable on this
> machine... weird (or maybe that's what you had in mind?)
>
> 42 seems like a much more meaningful number to me :)

248622 is a higher resonance of 42.  First off, 24 is 42 backwards,
then you have 86, and the arithmetic mean of 8 and 6 is 4.  Then you
have 2 2s.  See?  248622 is 42 all over, from beginning to end.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-11-05  5:32 okamoto
  0 siblings, 0 replies; 24+ messages in thread
From: okamoto @ 2001-11-05  5:32 UTC (permalink / raw)
  To: 9fans

Oops!  I've forgotten to report this.

>I have a DEC PC with PentiumII 266MHz, from which I'm now typing.
>This PC (PC 5510) has 21143 chip on the motherboard.   I failed to make
>it work for Plan 9, and am using another ether card...

This was solved by Jim, and now it's working very fine for me.
Thank you very much Jim.

Kenji



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-25  4:36   ` Boyd Roberts
@ 2001-10-25  6:06     ` andrey mirtchovski
  2001-11-05 10:21       ` Jonadab the Unsightly One
  0 siblings, 1 reply; 24+ messages in thread
From: andrey mirtchovski @ 2001-10-25  6:06 UTC (permalink / raw)
  To: 9fans

On Thu, 25 Oct 2001, Boyd Roberts wrote:

> There is some truth in that -- #248622
> 

incidentally #248622 is exactly the size of my xmahjong executable on this
machine... weird (or maybe that's what you had in mind?)

42 seems like a much more meaningful number to me :)



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 14:35 ` Ronald G Minnich
  2001-10-23 20:32   ` Matthew Hannigan
@ 2001-10-25  4:36   ` Boyd Roberts
  2001-10-25  6:06     ` andrey mirtchovski
  1 sibling, 1 reply; 24+ messages in thread
From: Boyd Roberts @ 2001-10-25  4:36 UTC (permalink / raw)
  To: 9fans

From: "Ronald G Minnich" <rminnich@lanl.gov>
> Ah yes, the infamous "All the good people left DEC so we can't design
> ethernet cards anymore" problem with Alphas.

There is some truth in that -- #248622




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-25  1:13 okamoto
  0 siblings, 0 replies; 24+ messages in thread
From: okamoto @ 2001-10-25  1:13 UTC (permalink / raw)
  To: 9fans

>I wouldn't call this an Alpha problem, I would call it a DEC ethernet
>card problem--I see the same behavior when I put it in a PC.

I have a DEC PC with PentiumII 266MHz, from which I'm now typing.
This PC (PC 5510) has 21143 chip on the motherboard.   I failed to make
it work for Plan 9, and am using another ether card...
Error was like:
  TX timeout.

Kenji



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 20:32   ` Matthew Hannigan
@ 2001-10-23 22:26     ` Dan Cross
  0 siblings, 0 replies; 24+ messages in thread
From: Dan Cross @ 2001-10-23 22:26 UTC (permalink / raw)
  To: 9fans

In article <3BD5D3D7.D119D57A@zip.com.au> you write:
>It's not just DEC.  And its pervasive enough that I think
>it must be a difficult problem.  We have HP-UX and Sun
>machines ranging in both age (software and hardware) from
>3 to 0 years and NONE of them do proper auto-negotiation
>with our Cisco switches.  NONE.  And Cisco and Sun must be
>one of the most common combinations out there.  Trouble is
>they sorta work. I shudder to think how much wasted bandwidth
>there is.

The duplexing has got to throw it off; it was my understanding from a
long time ago that FD 100 Mbps negotiation had never been standardized.
I don't know if that's really true or not, but if so, it could explain
some of the bizarreness of these results.

I don't know how common Cisco+Sun *really* is; I'm not sure that Sun
is all that common anymore.

	- Dan C.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-23 20:41 rob pike
  0 siblings, 0 replies; 24+ messages in thread
From: rob pike @ 2001-10-23 20:41 UTC (permalink / raw)
  To: 9fans

> this really smart fellow from the Frozen North 

Nanook of the BIOS?

-rob



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 20:17     ` Scott Schwartz
  2001-10-23 20:26       ` andrey
@ 2001-10-23 20:36       ` Ronald G Minnich
  1 sibling, 0 replies; 24+ messages in thread
From: Ronald G Minnich @ 2001-10-23 20:36 UTC (permalink / raw)
  To: 9fans

On Tue, 23 Oct 2001, Scott Schwartz wrote:

> So are you going to replace your linux-bios with plan9-bios now? :-)

actually the only thing standing between us and having 9load in flash is
my amount of spare time. I just don't have it. That's why we are counting
on this really smart fellow from the Frozen North when he comes here in
January. :-)

ron



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 14:35 ` Ronald G Minnich
@ 2001-10-23 20:32   ` Matthew Hannigan
  2001-10-23 22:26     ` Dan Cross
  2001-10-25  4:36   ` Boyd Roberts
  1 sibling, 1 reply; 24+ messages in thread
From: Matthew Hannigan @ 2001-10-23 20:32 UTC (permalink / raw)
  To: 9fans


It's not just DEC.  And its pervasive enough that I think
it must be a difficult problem.  We have HP-UX and Sun
machines ranging in both age (software and hardware) from
3 to 0 years and NONE of them do proper auto-negotiation
with our Cisco switches.  NONE.  And Cisco and Sun must be
one of the most common combinations out there.  Trouble is
they sorta work. I shudder to think how much wasted bandwidth
there is.

-Matt


Ronald G Minnich wrote:
> [ .. ] The usual way we fix it is to tell the switch to skip
> autonegotiation and wire the port to 100 Full. I mean, really, it's 2001,
> so 10 mbit half is unlikely anyway. [ .. ]


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 20:17     ` Scott Schwartz
@ 2001-10-23 20:26       ` andrey
  2001-10-23 20:36       ` Ronald G Minnich
  1 sibling, 0 replies; 24+ messages in thread
From: andrey @ 2001-10-23 20:26 UTC (permalink / raw)
  To: 9fans

yes, if i can help it :)

Scott Schwartz wrote:

> Ronald writes:
> | Not a problem as we toasted the SRM and run our own stuff from flash
> | instead. Boy did that feel good!
>
> So are you going to replace your linux-bios with plan9-bios now? :-)



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 19:23   ` Ronald G Minnich
@ 2001-10-23 20:17     ` Scott Schwartz
  2001-10-23 20:26       ` andrey
  2001-10-23 20:36       ` Ronald G Minnich
  0 siblings, 2 replies; 24+ messages in thread
From: Scott Schwartz @ 2001-10-23 20:17 UTC (permalink / raw)
  To: 9fans

Ronald writes:
| Not a problem as we toasted the SRM and run our own stuff from flash
| instead. Boy did that feel good!

So are you going to replace your linux-bios with plan9-bios now? :-)



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 18:55 ` Mike Haertel
@ 2001-10-23 19:23   ` Ronald G Minnich
  2001-10-23 20:17     ` Scott Schwartz
  0 siblings, 1 reply; 24+ messages in thread
From: Ronald G Minnich @ 2001-10-23 19:23 UTC (permalink / raw)
  To: 9fans

On Tue, 23 Oct 2001, Mike Haertel wrote:

> I wouldn't call this an Alpha problem, I would call it a DEC ethernet
> card problem--I see the same behavior when I put it in a PC.

you're right, it only gets to be an alpha problem when it is welded on the
motherboard and the SRM misconfigures it :-)

Not a problem as we toasted the SRM and run our own stuff from flash
instead. Boy did that feel good!

ron



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 14:17 jmk
  2001-10-23 14:35 ` Ronald G Minnich
  2001-10-23 14:56 ` Sam Ducksworth
@ 2001-10-23 18:55 ` Mike Haertel
  2001-10-23 19:23   ` Ronald G Minnich
  2 siblings, 1 reply; 24+ messages in thread
From: Mike Haertel @ 2001-10-23 18:55 UTC (permalink / raw)
  To: 9fans

>I spent a frustrating couple of days
>trying to get it to work which involved a lot of power-cycling of the
>Alpha due to the nature of the problem and eventually the Alpha just
>said enough and refused to work at all.

Did you check to see if the power supply gave out?  If it's a PC164
board, it's a standard ATX power supply, except you just have to wire
the power-on line to a mechanical switch.  Failed power supplies are
the bane of PC's and PC-like hardware.

I've also had a frustrating time with DEC ethernet cards.  The 21143-based
DE-500 that I have does not do autonegotiation correctly.  I finally got a
cheapo 100mbps fixed speed hub to wire it to and gave up on full duplex.
I wouldn't call this an Alpha problem, I would call it a DEC ethernet
card problem--I see the same behavior when I put it in a PC.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 14:56 ` Sam Ducksworth
@ 2001-10-23 17:25   ` Ronald G Minnich
  0 siblings, 0 replies; 24+ messages in thread
From: Ronald G Minnich @ 2001-10-23 17:25 UTC (permalink / raw)
  To: 9fans

On Tue, 23 Oct 2001, Sam Ducksworth wrote:
> i have seen things like this happen before and it is usually a problem with
> autonegotiation of the port speed. did you try to turn off the autoneg and
> force the port in question to the speed desired speed?

that may work, although with recent alpha hardware it did not do the job
unless you jammed the port to half duplex, which sucks. You really need to
bang the driver.

ron



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-23 14:58 jmk
  0 siblings, 0 replies; 24+ messages in thread
From: jmk @ 2001-10-23 14:58 UTC (permalink / raw)
  To: 9fans

On Tue Oct 23 10:36:25 EDT 2001, rminnich@lanl.gov wrote:
> ...
> Ah yes, the infamous "All the good people left DEC so we can't design
> ethernet cards anymore" problem with Alphas. We have a few hundred of
> these machines here. DEC never seems to have gotten auto-negotiation right
> in the last few years, and once you figure it out and fix it, it doesn't
> work anyway on the next little rev of the hardware. The problem always
> seems to boil down to very small timing problems such that the card comes
> up half and the switch full, or the switch half and card full, or both
> full, but the PHY is messed up so they can't talk anyway (the last time we
> fixed this). The usual way we fix it is to tell the switch to skip
> autonegotiation and wire the port to 100 Full. I mean, really, it's 2001,
> so 10 mbit half is unlikely anyway. Hardwiring switch ports works until it
> doesn't, and then you tweak the driver. Which will work until the next
> broken Alpha hardware comes in -- which won't be happening for long, so
> this will be less of a problem in future.
> ...

Yes, that's it. I had it working fine in my office on a Netgear switch (which
has no management, all the ports always autonegotiate) by telling the Alpha
firmware to bring it up at 10Mb; we could then load Plan 9 over the wire and
Plan 9 managed to negotiate to 100Mb OK. I obviously tried all this trickery
on the Procurve and I wrote the Plan 9 autonegotiate code while the DE-500 was
hooked up to a Procurve.

The galling thing was the attitude of the switch maintainers who "didn't change
a thing", clearly the card was at fault and could never have worked. When it
was pointed out that 2 systems which used to work before they "didn't do anything"
are no longer happy they just went off in the huff, leaving someone else to
tidy up their handywork. But we've all been there. Spleen vented.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 14:17 jmk
  2001-10-23 14:35 ` Ronald G Minnich
@ 2001-10-23 14:56 ` Sam Ducksworth
  2001-10-23 17:25   ` Ronald G Minnich
  2001-10-23 18:55 ` Mike Haertel
  2 siblings, 1 reply; 24+ messages in thread
From: Sam Ducksworth @ 2001-10-23 14:56 UTC (permalink / raw)
  To: 9fans

i have seen things like this happen before and it is usually a problem with
autonegotiation of the port speed. did you try to turn off the autoneg and
force the port in question to the speed desired speed?

> had been done without taking the systems down so fortunately the
> fileserver was still working (no idea how, but miracles sometimes happen).
> I had to replace the ether card in the fileserver as, sure enough, after
> a reboot it too couldn't talk to the Procurve.
>

--sam




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23 14:17 jmk
@ 2001-10-23 14:35 ` Ronald G Minnich
  2001-10-23 20:32   ` Matthew Hannigan
  2001-10-25  4:36   ` Boyd Roberts
  2001-10-23 14:56 ` Sam Ducksworth
  2001-10-23 18:55 ` Mike Haertel
  2 siblings, 2 replies; 24+ messages in thread
From: Ronald G Minnich @ 2001-10-23 14:35 UTC (permalink / raw)
  To: 9fans

On Tue, 23 Oct 2001 jmk@plan9.bell-labs.com wrote:

> So, I asked if anything had changed with the Procurve switch and the
> answer was no, well, actually we upgraded the firmware in all of them by
> rotating them out with a spare. I tried the other DE-500 based system
> and found it wouldn't talk to the Procurve either. Somehow the upgrade
> had been done without taking the systems down so fortunately the
> fileserver was still working (no idea how, but miracles sometimes happen).
> I had to replace the ether card in the fileserver as, sure enough, after
> a reboot it too couldn't talk to the Procurve.


Ah yes, the infamous "All the good people left DEC so we can't design
ethernet cards anymore" problem with Alphas. We have a few hundred of
these machines here. DEC never seems to have gotten auto-negotiation right
in the last few years, and once you figure it out and fix it, it doesn't
work anyway on the next little rev of the hardware. The problem always
seems to boil down to very small timing problems such that the card comes
up half and the switch full, or the switch half and card full, or both
full, but the PHY is messed up so they can't talk anyway (the last time we
fixed this). The usual way we fix it is to tell the switch to skip
autonegotiation and wire the port to 100 Full. I mean, really, it's 2001,
so 10 mbit half is unlikely anyway. Hardwiring switch ports works until it
doesn't, and then you tweak the driver. Which will work until the next
broken Alpha hardware comes in -- which won't be happening for long, so
this will be less of a problem in future.

I've never been able to figure out how these guys did so well with their
ethernet chips years ago and then did nothing but screw up the last five
years. I'm convinced all the good guys quit and went to other companies --
that would explain a lot.

ron



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-23 14:17 jmk
  2001-10-23 14:35 ` Ronald G Minnich
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: jmk @ 2001-10-23 14:17 UTC (permalink / raw)
  To: 9fans

On Tue Oct 23 00:54:32 EDT 2001, mike@ducky.net wrote:
> >Sorry we couldn't help with the problem, but we have no working alpha
> 
> Wow!  What happened to your Alpha?
> 
> So, is anyone else out there running Plan 9 on the Alpha?

During the summer I moved the Alpha out of my office and into the
machine room and found that it wouldn't talk to the HP Procurve switch.
This was confusing as there were 2 other Plan 9 machines on that switch
using the same generation DE-500 (21140 based) ethernet cards - one of
them was our main fileserver. I spent a frustrating couple of days
trying to get it to work which involved a lot of power-cycling of the
Alpha due to the nature of the problem and eventually the Alpha just
said enough and refused to work at all.

So, I asked if anything had changed with the Procurve switch and the 
answer was no, well, actually we upgraded the firmware in all of them by
rotating them out with a spare. I tried the other DE-500 based system
and found it wouldn't talk to the Procurve either. Somehow the upgrade
had been done without taking the systems down so fortunately the
fileserver was still working (no idea how, but miracles sometimes happen).
I had to replace the ether card in the fileserver as, sure enough, after
a reboot it too couldn't talk to the Procurve.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-23  4:53 ` Mike Haertel
@ 2001-10-23  5:54   ` George Bronnikov
  0 siblings, 0 replies; 24+ messages in thread
From: George Bronnikov @ 2001-10-23  5:54 UTC (permalink / raw)
  To: 9fans

On Mon, 22 Oct 2001, Mike Haertel wrote:

> >Sorry we couldn't help with the problem, but we have no working alpha
>
> Wow!  What happened to your Alpha?
>
> So, is anyone else out there running Plan 9 on the Alpha?

I did try to port it to my AS200 a year ago. There was a lot to do in the
arch-....c file.

I made it boot, setup memory, probe devices, see the SCSI controller, try
to start the first user process -- and then it hung up.  Thus I didn't
set up memory properly after all.

And then the IDE where I held the sources broke (physically).  Yes, I
know, I should have backuped often.

I think it would take me about a week to reproduce the state I was in --
but I don't have a spare week now.

	Goga




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
  2001-10-22 14:11 jmk
@ 2001-10-23  4:53 ` Mike Haertel
  2001-10-23  5:54   ` George Bronnikov
  0 siblings, 1 reply; 24+ messages in thread
From: Mike Haertel @ 2001-10-23  4:53 UTC (permalink / raw)
  To: 9fans

>Sorry we couldn't help with the problem, but we have no working alpha

Wow!  What happened to your Alpha?

So, is anyone else out there running Plan 9 on the Alpha?


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-22 14:11 jmk
  2001-10-23  4:53 ` Mike Haertel
  0 siblings, 1 reply; 24+ messages in thread
From: jmk @ 2001-10-22 14:11 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 529 bytes --]

Sorry we couldn't help with the problem, but we have no working alpha
and the one we did have had a DE-500 with a 21140 on it so that wouldn't
have helped anyway.

I've attached the current ether2114x.c with your additions, the other changes
you'll find there are to accomodate cards with larger EEPROMs.

I've also attached the alpha clock.c we have, it uses port/portclock.c which
handles the lock problem you found already.

Yes, we should make more of an effort to share drivers.

Thanks for the fixes.

--jim

[-- Attachment #2: clock.c --]
[-- Type: text/plain, Size: 1385 bytes --]

#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"axp.h"
#include	"ureg.h"

void
clockinit(void)
{
}

uvlong
cycletimer(void)
{
	ulong pcc;
	vlong delta;

	pcc = rpcc(nil) & 0xFFFFFFFF;
	if(m->cpuhz == 0){
		/*
		 * pcclast is needed to detect wraparound of
		 * the cycle timer which is only 32-bits.
		 * m->cpuhz is set from the info passed from
		 * the firmware.
		 * This could be in clockinit if can
		 * guarantee no wraparound between then and now.
		 *
		 * All the clock stuff needs work.
		 */
		m->cpuhz = hwrpb->cfreq;
		m->pcclast = pcc;
	}
	delta = pcc - m->pcclast;
	if(delta < 0)
		delta += 0x100000000LL;
	m->pcclast = pcc;
	m->fastclock += delta;

	return MACHP(0)->fastclock;
}

vlong
fastticks(uvlong* hz)
{
	uvlong ticks;
	int x;

	x = splhi();
	ticks = cycletimer();
	splx(x);

	if(hz)
		*hz = m->cpuhz;

	return (vlong)ticks;
}

void
microdelay(int us)
{
	uvlong eot;

	eot = fastticks(nil) + (m->cpuhz/1000000)*us;
	while(fastticks(nil) < eot)
		;
}

void
delay(int millisecs)
{
	microdelay(millisecs*1000);
}

void
clock(Ureg *ureg)
{
	static int count;

	cycletimer();

	/* HZ == 100, timer == 1024Hz.  error < 1ms */
	count += 100;
	if (count < 1024)
		return;
	count -= 1024;

	portclock(ureg);
}

[-- Attachment #3: ether2114x.c --]
[-- Type: text/plain, Size: 37502 bytes --]

/*
 * Digital Semiconductor DECchip 2114x PCI Fast Ethernet LAN Controller.
 * To do:
 *	thresholds;
 *	ring sizing;
 *	handle more error conditions;
 *	tidy setup packet mess;
 *	push initialisation back to attach;
 *	full SROM decoding.
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"

#define DEBUG		(0)
#define debug		if(DEBUG)print

enum {
	Nrde		= 64,
	Ntde		= 64,
};

#define Rbsz		ROUNDUP(sizeof(Etherpkt)+4, 4)

enum {					/* CRS0 - Bus Mode */
	Swr		= 0x00000001,	/* Software Reset */
	Bar		= 0x00000002,	/* Bus Arbitration */
	Dsl		= 0x0000007C,	/* Descriptor Skip Length (field) */
	Ble		= 0x00000080,	/* Big/Little Endian */
	Pbl		= 0x00003F00,	/* Programmable Burst Length (field) */
	Cal		= 0x0000C000,	/* Cache Alignment (field) */
	Cal8		= 0x00004000,	/* 8 longword boundary alignment */
	Cal16		= 0x00008000,	/* 16 longword boundary alignment */
	Cal32		= 0x0000C000,	/* 32 longword boundary alignment */
	Tap		= 0x000E0000,	/* Transmit Automatic Polling (field) */
	Dbo		= 0x00100000,	/* Descriptor Byte Ordering Mode */
	Rml		= 0x00200000,	/* Read Multiple */
}; 

enum {					/* CSR[57] - Status and Interrupt Enable */
	Ti		= 0x00000001,	/* Transmit Interrupt */
	Tps		= 0x00000002,	/* Transmit Process Stopped */
	Tu		= 0x00000004,	/* Transmit buffer Unavailable */
	Tjt		= 0x00000008,	/* Transmit Jabber Timeout */
	Unf		= 0x00000020,	/* transmit UNderFlow */
	Ri		= 0x00000040,	/* Receive Interrupt */
	Ru		= 0x00000080,	/* Receive buffer Unavailable */
	Rps		= 0x00000100,	/* Receive Process Stopped */
	Rwt		= 0x00000200,	/* Receive Watchdog Timeout */
	Eti		= 0x00000400,	/* Early Transmit Interrupt */
	Gte		= 0x00000800,	/* General purpose Timer Expired */
	Fbe		= 0x00002000,	/* Fatal Bit Error */
	Ais		= 0x00008000,	/* Abnormal Interrupt Summary */
	Nis		= 0x00010000,	/* Normal Interrupt Summary */
	Rs		= 0x000E0000,	/* Receive process State (field) */
	Ts		= 0x00700000,	/* Transmit process State (field) */
	Eb		= 0x03800000,	/* Error bits */
};

enum {					/* CSR6 - Operating Mode */
	Hp		= 0x00000001,	/* Hash/Perfect receive filtering mode */
	Sr		= 0x00000002,	/* Start/stop Receive */
	Ho		= 0x00000004,	/* Hash-Only filtering mode */
	Pb		= 0x00000008,	/* Pass Bad frames */
	If		= 0x00000010,	/* Inverse Filtering */
	Sb		= 0x00000020,	/* Start/stop Backoff counter */
	Pr		= 0x00000040,	/* Promiscuous Mode */
	Pm		= 0x00000080,	/* Pass all Multicast */
	Fd		= 0x00000200,	/* Full Duplex mode */
	Om		= 0x00000C00,	/* Operating Mode (field) */
	Fc		= 0x00001000,	/* Force Collision */
	St		= 0x00002000,	/* Start/stop Transmission Command */
	Tr		= 0x0000C000,	/* ThReshold control bits (field) */
	Tr128		= 0x00000000,
	Tr256		= 0x00004000,
	Tr512		= 0x00008000,
	Tr1024		= 0x0000C000,
	Ca		= 0x00020000,	/* CApture effect enable */
	Ps		= 0x00040000,	/* Port Select */
	Hbd		= 0x00080000,	/* HeartBeat Disable */
	Imm		= 0x00100000,	/* IMMediate mode */
	Sf		= 0x00200000,	/* Store and Forward */
	Ttm		= 0x00400000,	/* Transmit Threshold Mode */
	Pcs		= 0x00800000,	/* PCS function */
	Scr		= 0x01000000,	/* SCRambler mode */
	Mbo		= 0x02000000,	/* Must Be One */
	Ra		= 0x40000000,	/* Receive All */
	Sc		= 0x80000000,	/* Special Capture effect enable */

	TrMODE		= Tr512,	/* default transmission threshold */
};

enum {					/* CSR9 - ROM and MII Management */
	Scs		= 0x00000001,	/* serial ROM chip select */
	Sclk		= 0x00000002,	/* serial ROM clock */
	Sdi		= 0x00000004,	/* serial ROM data in */
	Sdo		= 0x00000008,	/* serial ROM data out */
	Ss		= 0x00000800,	/* serial ROM select */
	Wr		= 0x00002000,	/* write */
	Rd		= 0x00004000,	/* read */

	Mdc		= 0x00010000,	/* MII management clock */
	Mdo		= 0x00020000,	/* MII management write data */
	Mii		= 0x00040000,	/* MII management operation mode (W) */
	Mdi		= 0x00080000,	/* MII management data in */
};

enum {					/* CSR12 - General-Purpose Port */
	Gpc		= 0x00000100,	/* General Purpose Control */
};

typedef struct Des {
	int	status;
	int	control;
	ulong	addr;
	Block*	bp;
} Des;

enum {					/* status */
	Of		= 0x00000001,	/* Rx: OverFlow */
	Ce		= 0x00000002,	/* Rx: CRC Error */
	Db		= 0x00000004,	/* Rx: Dribbling Bit */
	Re		= 0x00000008,	/* Rx: Report on MII Error */
	Rw		= 0x00000010,	/* Rx: Receive Watchdog */
	Ft		= 0x00000020,	/* Rx: Frame Type */
	Cs		= 0x00000040,	/* Rx: Collision Seen */
	Tl		= 0x00000080,	/* Rx: Frame too Long */
	Ls		= 0x00000100,	/* Rx: Last deScriptor */
	Fs		= 0x00000200,	/* Rx: First deScriptor */
	Mf		= 0x00000400,	/* Rx: Multicast Frame */
	Rf		= 0x00000800,	/* Rx: Runt Frame */
	Dt		= 0x00003000,	/* Rx: Data Type (field) */
	De		= 0x00004000,	/* Rx: Descriptor Error */
	Fl		= 0x3FFF0000,	/* Rx: Frame Length (field) */
	Ff		= 0x40000000,	/* Rx: Filtering Fail */

	Def		= 0x00000001,	/* Tx: DEFerred */
	Uf		= 0x00000002,	/* Tx: UnderFlow error */
	Lf		= 0x00000004,	/* Tx: Link Fail report */
	Cc		= 0x00000078,	/* Tx: Collision Count (field) */
	Hf		= 0x00000080,	/* Tx: Heartbeat Fail */
	Ec		= 0x00000100,	/* Tx: Excessive Collisions */
	Lc		= 0x00000200,	/* Tx: Late Collision */
	Nc		= 0x00000400,	/* Tx: No Carrier */
	Lo		= 0x00000800,	/* Tx: LOss of carrier */
	To		= 0x00004000,	/* Tx: Transmission jabber timeOut */

	Es		= 0x00008000,	/* [RT]x: Error Summary */
	Own		= 0x80000000,	/* [RT]x: OWN bit */
};

enum {					/* control */
	Bs1		= 0x000007FF,	/* [RT]x: Buffer 1 Size */
	Bs2		= 0x003FF800,	/* [RT]x: Buffer 2 Size */

	Ch		= 0x01000000,	/* [RT]x: second address CHained */
	Er		= 0x02000000,	/* [RT]x: End of Ring */

	Ft0		= 0x00400000,	/* Tx: Filtering Type 0 */
	Dpd		= 0x00800000,	/* Tx: Disabled PaDding */
	Ac		= 0x04000000,	/* Tx: Add CRC disable */
	Set		= 0x08000000,	/* Tx: SETup packet */
	Ft1		= 0x10000000,	/* Tx: Filtering Type 1 */
	Fseg		= 0x20000000,	/* Tx: First SEGment */
	Lseg		= 0x40000000,	/* Tx: Last SEGment */
	Ic		= 0x80000000,	/* Tx: Interrupt on Completion */
};

enum {					/* PHY registers */
	Bmcr		= 0,		/* Basic Mode Control */
	Bmsr		= 1,		/* Basic Mode Status */
	Phyidr1		= 2,		/* PHY Identifier #1 */
	Phyidr2		= 3,		/* PHY Identifier #2 */
	Anar		= 4,		/* Auto-Negotiation Advertisment */
	Anlpar		= 5,		/* Auto-Negotiation Link Partner Ability */
	Aner		= 6,		/* Auto-Negotiation Expansion */
};

enum {					/* Variants */
	Tulip0		= (0x0009<<16)|0x1011,
	Tulip3		= (0x0019<<16)|0x1011,
	Pnic		= (0x0002<<16)|0x11AD,
	Pnic2		= (0xC115<<16)|0x11AD,
};

typedef struct Ctlr Ctlr;
typedef struct Ctlr {
	int	port;
	Pcidev*	pcidev;
	Ctlr*	next;
	int	active;
	int	id;			/* (pcidev->did<<16)|pcidev->vid */

	uchar*	srom;
	int	sromsz;			/* address size in bits */
	uchar*	sromea;			/* MAC address */
	uchar*	leaf;
	int	sct;			/* selected connection type */
	int	k;			/* info block count */
	uchar*	infoblock[16];
	int	sctk;			/* sct block index */
	int	curk;			/* current block index */
	uchar*	type5block;

	int	phy[32];		/* logical to physical map */
	int	phyreset;		/* reset bitmap */
	int	curphyad;
	int	fdx;
	int	ttm;

	uchar	fd;			/* option */
	int	medium;			/* option */

	int	csr6;			/* CSR6 - operating mode */
	int	mask;			/* CSR[57] - interrupt mask */
	int	mbps;

	Lock	lock;

	Des*	rdr;			/* receive descriptor ring */
	int	nrdr;			/* size of rdr */
	int	rdrx;			/* index into rdr */

	Lock	tlock;
	Des*	tdr;			/* transmit descriptor ring */
	int	ntdr;			/* size of tdr */
	int	tdrh;			/* host index into tdr */
	int	tdri;			/* interface index into tdr */
	int	ntq;			/* descriptors active */
	int	ntqmax;
	Block*	setupbp;

	ulong	of;			/* receive statistics */
	ulong	ce;
	ulong	cs;
	ulong	tl;
	ulong	rf;
	ulong	de;

	ulong	ru;
	ulong	rps;
	ulong	rwt;

	ulong	uf;			/* transmit statistics */
	ulong	ec;
	ulong	lc;
	ulong	nc;
	ulong	lo;
	ulong	to;

	ulong	tps;
	ulong	tu;
	ulong	tjt;
	ulong	unf;
} Ctlr;

static Ctlr* ctlrhead;
static Ctlr* ctlrtail;

#define csr32r(c, r)	(inl((c)->port+((r)*8)))
#define csr32w(c, r, l)	(outl((c)->port+((r)*8), (ulong)(l)))

static void
promiscuous(void* arg, int on)
{
	Ctlr *ctlr;

	ctlr = ((Ether*)arg)->ctlr;
	ilock(&ctlr->lock);
	if(on)
		ctlr->csr6 |= Pr;
	else
		ctlr->csr6 &= ~Pr;
	csr32w(ctlr, 6, ctlr->csr6);
	iunlock(&ctlr->lock);
}

static void
attach(Ether* ether)
{
	Ctlr *ctlr;

	ctlr = ether->ctlr;
	ilock(&ctlr->lock);
	if(!(ctlr->csr6 & Sr)){
		ctlr->csr6 |= Sr;
		csr32w(ctlr, 6, ctlr->csr6);
	}
	iunlock(&ctlr->lock);
}

static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
	Ctlr *ctlr;
	char *buf, *p;
	int i, l, len;

	ctlr = ether->ctlr;

	ether->crcs = ctlr->ce;
	ether->frames = ctlr->rf+ctlr->cs;
	ether->buffs = ctlr->de+ctlr->tl;
	ether->overflows = ctlr->of;

	if(n == 0)
		return 0;

	p = malloc(READSTR);
	l = snprint(p, READSTR, "Overflow: %lud\n", ctlr->of);
	l += snprint(p+l, READSTR-l, "Ru: %lud\n", ctlr->ru);
	l += snprint(p+l, READSTR-l, "Rps: %lud\n", ctlr->rps);
	l += snprint(p+l, READSTR-l, "Rwt: %lud\n", ctlr->rwt);
	l += snprint(p+l, READSTR-l, "Tps: %lud\n", ctlr->tps);
	l += snprint(p+l, READSTR-l, "Tu: %lud\n", ctlr->tu);
	l += snprint(p+l, READSTR-l, "Tjt: %lud\n", ctlr->tjt);
	l += snprint(p+l, READSTR-l, "Unf: %lud\n", ctlr->unf);
	l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->ce);
	l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->cs);
	l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->tl);
	l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->rf);
	l += snprint(p+l, READSTR-l, "Descriptor Error: %lud\n", ctlr->de);
	l += snprint(p+l, READSTR-l, "Underflow Error: %lud\n", ctlr->uf);
	l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec);
	l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->lc);
	l += snprint(p+l, READSTR-l, "No Carrier: %lud\n", ctlr->nc);
	l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->lo);
	l += snprint(p+l, READSTR-l, "Transmit Jabber Timeout: %lud\n",
		ctlr->to);
	l += snprint(p+l, READSTR-l, "csr6: %luX %uX\n", csr32r(ctlr, 6),
		ctlr->csr6);
	snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax);
	ctlr->ntqmax = 0;
	buf = a;
	len = readstr(offset, buf, n, p);
	if(offset > l)
		offset -= l;
	else
		offset = 0;
	buf += len;
	n -= len;

	l = snprint(p, READSTR, "srom:");
	for(i = 0; i < (1<<ctlr->sromsz); i++){
		if(i && ((i & 0x0F) == 0))
			l += snprint(p+l, READSTR-l, "\n     ");
		l += snprint(p+l, READSTR-l, " %2.2uX", ctlr->srom[i]);
	}

	snprint(p+l, READSTR-l, "\n");
	len += readstr(offset, buf, n, p);
	free(p);

	return len;
}

static void
txstart(Ether* ether)
{
	Ctlr *ctlr;
	Block *bp;
	Des *des;
	int control;

	ctlr = ether->ctlr;
	while(ctlr->ntq < (ctlr->ntdr-1)){
		if(ctlr->setupbp){
			bp = ctlr->setupbp;
			ctlr->setupbp = 0;
			control = Ic|Set|BLEN(bp);
		}
		else{
			bp = qget(ether->oq);
			if(bp == nil)
				break;
			control = Ic|Lseg|Fseg|BLEN(bp);
		}

		ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic;
		des = &ctlr->tdr[ctlr->tdrh];
		des->bp = bp;
		des->addr = PCIWADDR(bp->rp);
		des->control |= control;
		ctlr->ntq++;
		coherence();
		des->status = Own;
		csr32w(ctlr, 1, 0);
		ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr);
	}

	if(ctlr->ntq > ctlr->ntqmax)
		ctlr->ntqmax = ctlr->ntq;
}

static void
transmit(Ether* ether)
{
	Ctlr *ctlr;

	ctlr = ether->ctlr;
	ilock(&ctlr->tlock);
	txstart(ether);
	iunlock(&ctlr->tlock);
}

static void
interrupt(Ureg*, void* arg)
{
	Ctlr *ctlr;
	Ether *ether;
	int len, status;
	Des *des;
	Block *bp;

	ether = arg;
	ctlr = ether->ctlr;

	while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
		/*
		 * Acknowledge the interrupts and mask-out
		 * the ones that are implicitly handled.
		 */
		csr32w(ctlr, 5, status);
		status &= (ctlr->mask & ~(Nis|Ti));

		if(status & Ais){
			if(status & Tps)
				ctlr->tps++;
			if(status & Tu)
				ctlr->tu++;
			if(status & Tjt)
				ctlr->tjt++;
			if(status & Ru)
				ctlr->ru++;
			if(status & Rps)
				ctlr->rps++;
			if(status & Rwt)
				ctlr->rwt++;
			status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps);
		}

		/*
		 * Received packets.
		 */
		if(status & Ri){
			des = &ctlr->rdr[ctlr->rdrx];
			while(!(des->status & Own)){
				if(des->status & Es){
					if(des->status & Of)
						ctlr->of++;
					if(des->status & Ce)
						ctlr->ce++;
					if(des->status & Cs)
						ctlr->cs++;
					if(des->status & Tl)
						ctlr->tl++;
					if(des->status & Rf)
						ctlr->rf++;
					if(des->status & De)
						ctlr->de++;
				}
				else if(bp = iallocb(Rbsz)){
					len = ((des->status & Fl)>>16)-4;
					des->bp->wp = des->bp->rp+len;
					etheriq(ether, des->bp, 1);
					des->bp = bp;
					des->addr = PCIWADDR(bp->rp);
				}

				des->control &= Er;
				des->control |= Rbsz;
				coherence();
				des->status = Own;

				ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
				des = &ctlr->rdr[ctlr->rdrx];
			}
			status &= ~Ri;
		}

		/*
		 * Check the transmit side:
		 *	check for Transmit Underflow and Adjust
		 *	the threshold upwards;
		 *	free any transmitted buffers and try to
		 *	top-up the ring.
		 */
		if(status & Unf){
			ctlr->unf++;
			ilock(&ctlr->lock);
			csr32w(ctlr, 6, ctlr->csr6 & ~St);
			switch(ctlr->csr6 & Tr){
			case Tr128:
				len = Tr256;
				break;
			case Tr256:
				len = Tr512;
				break;
			case Tr512:
				len = Tr1024;
				break;
			default:
			case Tr1024:
				len = Sf;
				break;
			}
			ctlr->csr6 = (ctlr->csr6 & ~Tr)|len;
			csr32w(ctlr, 6, ctlr->csr6);
			iunlock(&ctlr->lock);
			csr32w(ctlr, 5, Tps);
			status &= ~(Unf|Tps);
		}

		ilock(&ctlr->tlock);
		while(ctlr->ntq){
			des = &ctlr->tdr[ctlr->tdri];
			if(des->status & Own)
				break;

			if(des->status & Es){
				if(des->status & Uf)
					ctlr->uf++;
				if(des->status & Ec)
					ctlr->ec++;
				if(des->status & Lc)
					ctlr->lc++;
				if(des->status & Nc)
					ctlr->nc++;
				if(des->status & Lo)
					ctlr->lo++;
				if(des->status & To)
					ctlr->to++;
				ether->oerrs++;
			}

			freeb(des->bp);
			des->control &= Er;

			ctlr->ntq--;
			ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr);
		}
		txstart(ether);
		iunlock(&ctlr->tlock);

		/*
		 * Anything left not catered for?
		 */
		if(status)
			panic("#l%d: status %8.8uX\n", ether->ctlrno, status);
	}
}

static void
ctlrinit(Ether* ether)
{
	Ctlr *ctlr;
	Des *des;
	Block *bp;
	int i;
	uchar bi[Eaddrlen*2];

	ctlr = ether->ctlr;

	/*
	 * Allocate and initialise the receive ring;
	 * allocate and initialise the transmit ring;
	 * unmask interrupts and start the transmit side;
	 * create and post a setup packet to initialise
	 * the physical ethernet address.
	 */
	ctlr->rdr = xspanalloc(ctlr->nrdr*sizeof(Des), 8*sizeof(ulong), 0);
	for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
		des->bp = iallocb(Rbsz);
		if(des->bp == nil)
			panic("can't allocate ethernet receive ring\n");
		des->status = Own;
		des->control = Rbsz;
		des->addr = PCIWADDR(des->bp->rp);
	}
	ctlr->rdr[ctlr->nrdr-1].control |= Er;
	ctlr->rdrx = 0;
	csr32w(ctlr, 3, PCIWADDR(ctlr->rdr));

	ctlr->tdr = xspanalloc(ctlr->ntdr*sizeof(Des), 8*sizeof(ulong), 0);
	ctlr->tdr[ctlr->ntdr-1].control |= Er;
	ctlr->tdrh = 0;
	ctlr->tdri = 0;
	csr32w(ctlr, 4, PCIWADDR(ctlr->tdr));

	/*
	 * Clear any bits in the Status Register (CSR5) as
	 * the PNIC has a different reset value from a true 2114x.
	 */
	ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti;
	csr32w(ctlr, 5, ctlr->mask);
	csr32w(ctlr, 7, ctlr->mask);
	ctlr->csr6 |= St;
	csr32w(ctlr, 6, ctlr->csr6);

	for(i = 0; i < Eaddrlen/2; i++){
		bi[i*4] = ether->ea[i*2];
		bi[i*4+1] = ether->ea[i*2+1];
		bi[i*4+2] = ether->ea[i*2+1];
		bi[i*4+3] = ether->ea[i*2];
	}
	bp = iallocb(Eaddrlen*2*16);
	if(bp == nil)
		panic("can't allocate ethernet setup buffer\n");
	memset(bp->rp, 0xFF, sizeof(bi));
	for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi))
		memmove(bp->rp+i, bi, sizeof(bi));
	bp->wp += sizeof(bi)*16;

	ctlr->setupbp = bp;
	ether->oq = qopen(256*1024, 1, 0, 0);
	transmit(ether);
}

static void
csr9w(Ctlr* ctlr, int data)
{
	csr32w(ctlr, 9, data);
	microdelay(1);
}

static int
miimdi(Ctlr* ctlr, int n)
{
	int data, i;

	/*
	 * Read n bits from the MII Management Register.
	 */
	data = 0;
	for(i = n-1; i >= 0; i--){
		if(csr32r(ctlr, 9) & Mdi)
			data |= (1<<i);
		csr9w(ctlr, Mii|Mdc);
		csr9w(ctlr, Mii);
	}
	csr9w(ctlr, 0);

	return data;
}

static void
miimdo(Ctlr* ctlr, int bits, int n)
{
	int i, mdo;

	/*
	 * Write n bits to the MII Management Register.
	 */
	for(i = n-1; i >= 0; i--){
		if(bits & (1<<i))
			mdo = Mdo;
		else
			mdo = 0;
		csr9w(ctlr, mdo);
		csr9w(ctlr, mdo|Mdc);
		csr9w(ctlr, mdo);
	}
}

static int
miir(Ctlr* ctlr, int phyad, int regad)
{
	int data, i;

	if(ctlr->id == Pnic){
		i = 1000;
		csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18));
		do{
			microdelay(1);
			data = csr32r(ctlr, 20);
		}while((data & 0x80000000) && --i);

		if(i == 0)
			return -1;
		return data & 0xFFFF;
	}

	/*
	 * Preamble;
	 * ST+OP+PHYAD+REGAD;
	 * TA + 16 data bits.
	 */
	miimdo(ctlr, 0xFFFFFFFF, 32);
	miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14);
	data = miimdi(ctlr, 18);

	if(data & 0x10000)
		return -1;

	return data & 0xFFFF;
}

static void
miiw(Ctlr* ctlr, int phyad, int regad, int data)
{
	/*
	 * Preamble;
	 * ST+OP+PHYAD+REGAD+TA + 16 data bits;
	 * Z.
	 */
	miimdo(ctlr, 0xFFFFFFFF, 32);
	data &= 0xFFFF;
	data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16);
	miimdo(ctlr, data, 32);
	csr9w(ctlr, Mdc);
	csr9w(ctlr, 0);
}

static int
sromr(Ctlr* ctlr, int r)
{
	int i, op, data, size;

	if(ctlr->id == Pnic){
		i = 1000;
		csr32w(ctlr, 19, 0x600|r);
		do{
			microdelay(1);
			data = csr32r(ctlr, 19);
		}while((data & 0x80000000) && --i);

		if(ctlr->sromsz == 0)
			ctlr->sromsz = 6;

		return csr32r(ctlr, 9) & 0xFFFF;
	}

	/*
	 * This sequence for reading a 16-bit register 'r'
	 * in the EEPROM is taken straight from Section
	 * 7.4 of the 21140 Hardware Reference Manual.
	 */
reread:
	csr9w(ctlr, Rd|Ss);
	csr9w(ctlr, Rd|Ss|Scs);
	csr9w(ctlr, Rd|Ss|Sclk|Scs);
	csr9w(ctlr, Rd|Ss);

	op = 0x06;
	for(i = 3-1; i >= 0; i--){
		data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs;
		csr9w(ctlr, data);
		csr9w(ctlr, data|Sclk);
		csr9w(ctlr, data);
	}

	/*
	 * First time through must work out the EEPROM size.
	 */
	if((size = ctlr->sromsz) == 0)
		size = 8;

	for(size = size-1; size >= 0; size--){
		data = Rd|Ss|(((r>>size) & 0x01)<<2)|Scs;
		csr9w(ctlr, data);
		csr9w(ctlr, data|Sclk);
		csr9w(ctlr, data);
		microdelay(1);
		if(!(csr32r(ctlr, 9) & Sdo))
			break;
	}

	data = 0;
	for(i = 16-1; i >= 0; i--){
		csr9w(ctlr, Rd|Ss|Sclk|Scs);
		if(csr32r(ctlr, 9) & Sdo)
			data |= (1<<i);
		csr9w(ctlr, Rd|Ss|Scs);
	}

	csr9w(ctlr, 0);

	if(ctlr->sromsz == 0){
		ctlr->sromsz = 8-size;
		goto reread;
	}

	return data & 0xFFFF;
}

static void
softreset(Ctlr* ctlr)
{
	/*
	 * Soft-reset the controller and initialise bus mode.
	 * Delay should be >= 50 PCI cycles (2×S @ 25MHz).
	 */
	csr32w(ctlr, 0, Swr);
	microdelay(10);
	csr32w(ctlr, 0, Rml|Cal16);
	delay(1);
}

static int
type5block(Ctlr* ctlr, uchar* block)
{
	int csr15, i, len;

	/*
	 * Reset or GPR sequence. Reset should be once only,
	 * before the GPR sequence.
	 * Note 'block' is not a pointer to the block head but
	 * a pointer to the data in the block starting at the
	 * reset length value so type5block can be used for the
	 * sequences contained in type 1 and type 3 blocks.
	 * The SROM docs state the 21140 type 5 block is the
	 * same as that for the 21143, but the two controllers
	 * use different registers and sequence-element lengths
	 * so the 21140 code here is a guess for a real type 5
	 * sequence.
	 */
	len = *block++;
	if(ctlr->id != Tulip3){
		for(i = 0; i < len; i++){
			csr32w(ctlr, 12, *block);
			block++;
		}
		return len;
	}

	for(i = 0; i < len; i++){
		csr15 = *block++<<16;
		csr15 |= *block++<<24;
		csr32w(ctlr, 15, csr15);
		debug("%8.8uX ", csr15);
	}
	return 2*len;
}

static int
typephylink(Ctlr* ctlr, uchar*)
{
	int an, bmcr, bmsr, csr6, x;

	/*
	 * Fail if
	 *	auto-negotiataion enabled but not complete;
	 *	no valid link established.
	 */
	bmcr = miir(ctlr, ctlr->curphyad, Bmcr);
	miir(ctlr, ctlr->curphyad, Bmsr);
	bmsr = miir(ctlr, ctlr->curphyad, Bmsr);
	debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr);
	if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004))
		return 0;

	if(bmcr & 0x1000){
		an = miir(ctlr, ctlr->curphyad, Anar);
		an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0;
		debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n",
	    		miir(ctlr, ctlr->curphyad, Anar),
			miir(ctlr, ctlr->curphyad, Anlpar),
			an);
	
		if(an & 0x0100)
			x = 0x4000;
		else if(an & 0x0080)
			x = 0x2000;
		else if(an & 0x0040)
			x = 0x1000;
		else if(an & 0x0020)
			x = 0x0800;
		else
			x = 0;
	}
	else if((bmcr & 0x2100) == 0x2100)
		x = 0x4000;
	else if(bmcr & 0x2000){
		/*
		 * If FD capable, force it if necessary.
		 */
		if((bmsr & 0x4000) && ctlr->fd){
			miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100);
			x = 0x4000;
		}
		else
			x = 0x2000;
	}
	else if(bmcr & 0x0100)
		x = 0x1000;
	else
		x = 0x0800;

	csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
	if(ctlr->fdx & x)
		csr6 |= Fd;
	if(ctlr->ttm & x)
		csr6 |= Ttm;
	debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n",
		csr6, ctlr->csr6, csr32r(ctlr, 6));
	if(csr6 != ctlr->csr6){
		ctlr->csr6 = csr6;
		csr32w(ctlr, 6, csr6);
	}

	return 1;
}

static int
typephymode(Ctlr* ctlr, uchar* block, int wait)
{
	uchar *p;
	int len, mc, nway, phyx, timeo;

	if(DEBUG){
		int i;

		len = (block[0] & ~0x80)+1;
		for(i = 0; i < len; i++)
			debug("%2.2uX ", block[i]);
		debug("\n");
	}

	if(block[1] == 1)
		len = 1;
	else if(block[1] == 3)
		len = 2;
	else
		return -1;

	/*
	 * Snarf the media capabilities, nway advertisment,
	 * FDX and TTM bitmaps.
	 */
	p = &block[5+len*block[3]+len*block[4+len*block[3]]];
	mc = *p++;
	mc |= *p++<<8;
	nway = *p++;
	nway |= *p++<<8;
	ctlr->fdx = *p++;
	ctlr->fdx |= *p++<<8;
	ctlr->ttm = *p++;
	ctlr->ttm |= *p<<8;
	debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n",
		mc, nway, ctlr->fdx, ctlr->ttm);
	USED(mc);

	phyx = block[2];
	ctlr->curphyad = ctlr->phy[phyx];

	ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
	//csr32w(ctlr, 6, ctlr->csr6);
	if(typephylink(ctlr, block))
		return 0;

	if(!(ctlr->phyreset & (1<<phyx))){
		debug("reset seq: len %d: ", block[3]);
		if(ctlr->type5block)
			type5block(ctlr, &ctlr->type5block[2]);
		else
			type5block(ctlr, &block[4+len*block[3]]);
		debug("\n");
		ctlr->phyreset |= (1<<phyx);
	}

	/*
	 * GPR sequence.
	 */
	debug("gpr seq: len %d: ", block[3]);
	type5block(ctlr, &block[3]);
	debug("\n");

	ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
	//csr32w(ctlr, 6, ctlr->csr6);
	if(typephylink(ctlr, block))
		return 0;

	/*
	 * Turn off auto-negotiation, set the auto-negotiation
	 * advertisment register then start the auto-negotiation
	 * process again.
	 */
	miiw(ctlr, ctlr->curphyad, Bmcr, 0);
	miiw(ctlr, ctlr->curphyad, Anar, nway|1);
	miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000);

	if(!wait)
		return 0;

	for(timeo = 0; timeo < 30; timeo++){
		if(typephylink(ctlr, block))
			return 0;
		delay(100);
	}

	return -1;
}

static int
typesymmode(Ctlr *ctlr, uchar *block, int wait)
{
	uint gpmode, gpdata, command;

	USED(wait);
	gpmode = block[3] | ((uint) block[4] << 8);
	gpdata = block[5] | ((uint) block[6] << 8);
	command = (block[7] | ((uint) block[8] << 8)) & 0x71;
	if (command & 0x8000) {
		print("ether2114x.c: FIXME: handle type 4 mode blocks where cmd.active_invalid != 0\n");
		return -1;
	}
	csr32w(ctlr, 15, gpmode);
	csr32w(ctlr, 15, gpdata);
	ctlr->csr6 = (command & 0x71) << 18;
	csr32w(ctlr, 6, ctlr->csr6);
	return 0;
}

static int
type0link(Ctlr* ctlr, uchar* block)
{
	int m, polarity, sense;

	m = (block[3]<<8)|block[2];
	sense = 1<<((m & 0x000E)>>1);
	if(m & 0x0080)
		polarity = sense;
	else
		polarity = 0;

	return (csr32r(ctlr, 12) & sense)^polarity;
}

static int
type0mode(Ctlr* ctlr, uchar* block, int wait)
{
	int csr6, m, timeo;

	csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE;
debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
    ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]); 
	switch(block[0]){
	default:
		break;

	case 0x04:			/* 10BASE-TFD */
	case 0x05:			/* 100BASE-TXFD */
	case 0x08:			/* 100BASE-FXFD */
		/*
		 * Don't attempt full-duplex
		 * unless explicitly requested.
		 */
		if(!ctlr->fd)
			return -1;
		csr6 |= Fd;
		break;
	}

	m = (block[3]<<8)|block[2];
	if(m & 0x0001)
		csr6 |= Ps;
	if(m & 0x0010)
		csr6 |= Ttm;
	if(m & 0x0020)
		csr6 |= Pcs;
	if(m & 0x0040)
		csr6 |= Scr;

	csr32w(ctlr, 12, block[1]);
	microdelay(10);
	csr32w(ctlr, 6, csr6);
	ctlr->csr6 = csr6;

	if(!wait)
		return 0;

	for(timeo = 0; timeo < 30; timeo++){
		if(type0link(ctlr, block))
			return 0;
		delay(100);
	}

	return -1;
}

static int
mediaxx(Ether* ether, int wait)
{
	Ctlr* ctlr;
	uchar *block;

	ctlr = ether->ctlr;
	block = ctlr->infoblock[ctlr->curk];
	if(block[0] & 0x80){
		switch(block[1]){
		default:
			return -1;
		case 0:
			if(ctlr->medium >= 0 && block[2] != ctlr->medium)
				return 0;
/* need this test? */	if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2])
				return 0;
			if(type0mode(ctlr, block+2, wait))
				return 0;
			break;
		case 1:
			if(typephymode(ctlr, block, wait))
				return 0;
			break;
		case 3:
			if(typephymode(ctlr, block, wait))
				return 0;
			break;
		case 4:
			if(typesymmode(ctlr, block, wait))
				return 0;
			break;
		}
	}
	else{
		if(ctlr->medium >= 0 && block[0] != ctlr->medium)
			return 0;
/* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0])
			return 0;
		if(type0mode(ctlr, block, wait))
			return 0;
	}

	if(ctlr->csr6){
		if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm))
			return 10;
		return 100;
	}

	return 0;
}

static int
media(Ether* ether, int wait)
{
	Ctlr* ctlr;
	int k, mbps;

	ctlr = ether->ctlr;
	for(k = 0; k < ctlr->k; k++){
		mbps = mediaxx(ether, wait);
		if(mbps > 0)
			return mbps;
		if(ctlr->curk == 0)
			ctlr->curk = ctlr->k-1;
		else
			ctlr->curk--;
	}

	return 0;
}

static char* mediatable[9] = {
	"10BASE-T",				/* TP */
	"10BASE-2",				/* BNC */
	"10BASE-5",				/* AUI */
	"100BASE-TX",
	"10BASE-TFD",
	"100BASE-TXFD",
	"100BASE-T4",
	"100BASE-FX",
	"100BASE-FXFD",
};

static uchar en1207[] = {		/* Accton EN1207-COMBO */
	0x00, 0x00, 0xE8,		/* [0]  vendor ethernet code */
	0x00,				/* [3]  spare */

	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
	0x1F,				/* [6]  general purpose control */
	2,				/* [7]  block count */

	0x00,				/* [8]  media code (10BASE-TX) */
	0x0B,				/* [9]  general purpose port data */
	0x9E, 0x00,			/* [10] command (LSB+MSB = 0x009E) */

	0x03,				/* [8]  media code (100BASE-TX) */
	0x1B,				/* [9]  general purpose port data */
	0x6D, 0x00,			/* [10] command (LSB+MSB = 0x006D) */

					/* There is 10BASE-2 as well, but... */
};

static uchar ana6910fx[] = {		/* Adaptec (Cogent) ANA-6910FX */
	0x00, 0x00, 0x92,		/* [0]  vendor ethernet code */
	0x00,				/* [3]  spare */

	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
	0x3F,				/* [6]  general purpose control */
	1,				/* [7]  block count */

	0x07,				/* [8]  media code (100BASE-FX) */
	0x03,				/* [9]  general purpose port data */
	0x2D, 0x00			/* [10] command (LSB+MSB = 0x000D) */
};

static uchar smc9332[] = {		/* SMC 9332 */
	0x00, 0x00, 0xC0,		/* [0]  vendor ethernet code */
	0x00,				/* [3]  spare */

	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
	0x1F,				/* [6]  general purpose control */
	2,				/* [7]  block count */

	0x00,				/* [8]  media code (10BASE-TX) */
	0x00,				/* [9]  general purpose port data */
	0x9E, 0x00,			/* [10] command (LSB+MSB = 0x009E) */

	0x03,				/* [8]  media code (100BASE-TX) */
	0x09,				/* [9]  general purpose port data */
	0x6D, 0x00,			/* [10] command (LSB+MSB = 0x006D) */
};

static uchar* leaf21140[] = {
	en1207,				/* Accton EN1207-COMBO */
	ana6910fx,			/* Adaptec (Cogent) ANA-6910FX */
	smc9332,			/* SMC 9332 */
	nil,
};

/*
 * Copied to ctlr->srom at offset 20.
 */
static uchar leafpnic[] = {
	0x00, 0x00, 0x00, 0x00,		/* MAC address */
	0x00, 0x00,
	0x00,				/* controller 0 device number */
	0x1E, 0x00,			/* controller 0 info leaf offset */
	0x00,				/* reserved */
	0x00, 0x08,			/* selected connection type */
	0x00,				/* general purpose control */
	0x01,				/* block count */

	0x8C,				/* format indicator and count */
	0x01,				/* block type */
	0x00,				/* PHY number */
	0x00,				/* GPR sequence length */
	0x00,				/* reset sequence length */
	0x00, 0x78,			/* media capabilities */
	0xE0, 0x01,			/* Nway advertisment */
	0x00, 0x50,			/* FDX bitmap */
	0x00, 0x18,			/* TTM bitmap */
};

static int
srom(Ctlr* ctlr)
{
	int i, k, oui, phy, x;
	uchar *p;

	/*
	 * This is a partial decoding of the SROM format described in
	 * 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05,
	 * 2-Mar-98'. Only the 2114[03] are handled, support for other
	 * controllers can be added as needed.
	 * Do a dummy read first to get the size and allocate ctlr->srom.
	 */
	sromr(ctlr, 0);
	if(ctlr->srom == nil)
		ctlr->srom = malloc((1<<ctlr->sromsz)*sizeof(ushort));
	for(i = 0; i < (1<<ctlr->sromsz); i++){
		x = sromr(ctlr, i);
		ctlr->srom[2*i] = x;
		ctlr->srom[2*i+1] = x>>8;
	}

	/*
	 * There are 2 SROM layouts:
	 *	e.g. Digital EtherWORKS	station address at offset 20;
	 *				this complies with the 21140A SROM
	 *				application note from Digital;
	 * 	e.g. SMC9332		station address at offset 0 followed by
	 *				2 additional bytes, repeated at offset
	 *				6; the 8 bytes are also repeated in
	 *				reverse order at offset 8.
	 * To check which it is, read the SROM and check for the repeating
	 * patterns of the non-compliant cards; if that fails use the one at
	 * offset 20.
	 */
	ctlr->sromea = ctlr->srom;
	for(i = 0; i < 8; i++){
		x = ctlr->srom[i];
		if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){
			ctlr->sromea = &ctlr->srom[20];
			break;
		}
	}

	/*
	 * Fake up the SROM for the PNIC.
	 * It looks like a 21140 with a PHY.
	 * The MAC address is byte-swapped in the orginal SROM data.
	 */
	if(ctlr->id == Pnic){
		memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
		for(i = 0; i < Eaddrlen; i += 2){
			ctlr->srom[20+i] = ctlr->srom[i+1];
			ctlr->srom[20+i+1] = ctlr->srom[i];
		}
	}

	/*
	 * Next, try to find the info leaf in the SROM for media detection.
	 * If it's a non-conforming card try to match the vendor ethernet code
	 * and point p at a fake info leaf with compact 21140 entries.
	 */
	if(ctlr->sromea == ctlr->srom){
		p = nil;
		for(i = 0; leaf21140[i] != nil; i++){
			if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){
				p = &leaf21140[i][4];
				break;
			}
		}
		if(p == nil)
			return -1;
	}
	else
		p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]];

	/*
	 * Set up the info needed for later media detection.
	 * For the 21140, set the general-purpose mask in CSR12.
	 * The info block entries are stored in order of increasing
	 * precedence, so detection will work backwards through the
	 * stored indexes into ctlr->srom.
	 * If an entry is found which matches the selected connection
	 * type, save the index. Otherwise, start at the last entry.
	 * If any MII entries are found (type 1 and 3 blocks), scan
	 * for PHYs.
	 */
	ctlr->leaf = p;
	ctlr->sct = *p++;
	ctlr->sct |= *p++<<8;
	if(ctlr->id != Tulip3){
		csr32w(ctlr, 12, Gpc|*p++);
		delay(200);
	}
	ctlr->k = *p++;
	if(ctlr->k >= nelem(ctlr->infoblock))
		ctlr->k = nelem(ctlr->infoblock)-1;
	ctlr->sctk = ctlr->k-1;
	phy = 0;
	for(k = 0; k < ctlr->k; k++){
		ctlr->infoblock[k] = p;
		/*
		 * The RAMIX PMC665 has a badly-coded SROM,
		 * hence the test for 21143 and type 3.
		 */
		if((*p & 0x80) || (ctlr->id == Tulip3 && *(p+1) == 3)){
			*p |= 0x80;
			if(*(p+1) == 1 || *(p+1) == 3)
				phy = 1;
			if(*(p+1) == 5)
				ctlr->type5block = p;
			p += (*p & ~0x80)+1;
		}
		else{
			debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
				p[0], p[1], p[2], p[3]); 
			if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
				ctlr->sctk = k;
			p += 4;
		}
	}
	ctlr->curk = ctlr->sctk;
	debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n",
		ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy);

	if(phy){
		x = 0;
		for(k = 0; k < nelem(ctlr->phy); k++){
			if((oui = miir(ctlr, k, 2)) == -1 || oui == 0)
				continue;
			if(DEBUG){
				oui = (oui & 0x3FF)<<6;
				oui |= miir(ctlr, k, 3)>>10;
				miir(ctlr, k, 1);
				debug("phy%d: index %d oui %uX reg1 %uX\n",
					x, k, oui, miir(ctlr, k, 1));
				USED(oui);
			}
			ctlr->phy[x] = k;
		}
	}

	ctlr->fd = 0;
	ctlr->medium = -1;

	return 0;
}

static void
dec2114xpci(void)
{
	Ctlr *ctlr;
	Pcidev *p;
	int x;

	p = nil;
	while(p = pcimatch(p, 0, 0)){
		if(p->ccrb != 0x02 || p->ccru != 0)
			continue;
		switch((p->did<<16)|p->vid){
		default:
			continue;

		case Tulip3:			/* 21143 */
			/*
			 * Exit sleep mode.
			 */
			x = pcicfgr32(p, 0x40);
			x &= ~0xc0000000;
			pcicfgw32(p, 0x40, x);
			/*FALLTHROUGH*/

		case Pnic:			/* PNIC */
		case Pnic2:			/* PNIC-II */
		case Tulip0:			/* 21140 */
			break;
		}

		/*
		 * bar[0] is the I/O port register address and
		 * bar[1] is the memory-mapped register address.
		 */
		ctlr = malloc(sizeof(Ctlr));
		ctlr->port = p->mem[0].bar & ~0x01;
		ctlr->pcidev = p;
		ctlr->id = (p->did<<16)|p->vid;

		if(ioalloc(ctlr->port, p->mem[0].size, 0, "dec2114x") < 0){
			print("dec2114x: port 0x%uX in use\n", ctlr->port);
			free(ctlr);
			continue;
		}

		/*
		 * Some cards (e.g. ANA-6910FX) seem to need the Ps bit
		 * set or they don't always work right after a hardware
		 * reset.
		 */
		csr32w(ctlr, 6, Mbo|Ps);
		softreset(ctlr);

		if(srom(ctlr)){
			iofree(ctlr->port);
			free(ctlr);
			continue;
		}

		switch(ctlr->id){
		default:
			break;

		case Pnic:			/* PNIC */
			/*
			 * Turn off the jabber timer.
			 */
			csr32w(ctlr, 15, 0x00000001);
			break;
		}

		if(ctlrhead != nil)
			ctlrtail->next = ctlr;
		else
			ctlrhead = ctlr;
		ctlrtail = ctlr;
	}
}

static int
reset(Ether* ether)
{
	Ctlr *ctlr;
	int i, x;
	uchar ea[Eaddrlen];
	static int scandone;

	if(scandone == 0){
		dec2114xpci();
		scandone = 1;
	}

	/*
	 * Any adapter matches if no ether->port is supplied,
	 * otherwise the ports must match.
	 */
	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
		if(ctlr->active)
			continue;
		if(ether->port == 0 || ether->port == ctlr->port){
			ctlr->active = 1;
			break;
		}
	}
	if(ctlr == nil)
		return -1;

	ether->ctlr = ctlr;
	ether->port = ctlr->port;
	ether->irq = ctlr->pcidev->intl;
	ether->tbdf = ctlr->pcidev->tbdf;

	/*
	 * Check if the adapter's station address is to be overridden.
	 * If not, read it from the EEPROM and set in ether->ea prior to
	 * loading the station address in the hardware.
	 */
	memset(ea, 0, Eaddrlen);
	if(memcmp(ea, ether->ea, Eaddrlen) == 0)
		memmove(ether->ea, ctlr->sromea, Eaddrlen);

	/*
	 * Look for a medium override in case there's no autonegotiation
	 * (no MII) or the autonegotiation fails.
	 */
	for(i = 0; i < ether->nopt; i++){
		if(cistrcmp(ether->opt[i], "FD") == 0){
			ctlr->fd = 1;
			continue;
		}
		for(x = 0; x < nelem(mediatable); x++){
			debug("compare <%s> <%s>\n", mediatable[x],
				ether->opt[i]);
			if(cistrcmp(mediatable[x], ether->opt[i]))
				continue;
			ctlr->medium = x;
	
			switch(ctlr->medium){
			default:
				ctlr->fd = 0;
				break;
	
			case 0x04:		/* 10BASE-TFD */
			case 0x05:		/* 100BASE-TXFD */
			case 0x08:		/* 100BASE-FXFD */
				ctlr->fd = 1;
				break;
			}
			break;
		}
	}

	ether->mbps = media(ether, 1);

	/*
	 * Initialise descriptor rings, ethernet address.
	 */
	ctlr->nrdr = Nrde;
	ctlr->ntdr = Ntde;
	pcisetbme(ctlr->pcidev);
	ctlrinit(ether);

	/*
	 * Linkage to the generic ethernet driver.
	 */
	ether->attach = attach;
	ether->transmit = transmit;
	ether->interrupt = interrupt;
	ether->ifstat = ifstat;

	ether->arg = ether;
	ether->promiscuous = promiscuous;

	return 0;
}

void
ether2114xlink(void)
{
	addethercard("21140",  reset);
	addethercard("2114x",  reset);
}

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update)
@ 2001-10-22  7:54 Mike Haertel
  0 siblings, 0 replies; 24+ messages in thread
From: Mike Haertel @ 2001-10-22  7:54 UTC (permalink / raw)
  To: 9fans

Ok, nobody replied to my previous query, so I was on my own.
In order to get my Alpha working, I fixed two things.

1.  Fixed a bug in the clock interrupt handler.

term% diff 9/alphapc/clock.c 9.new/alphapc/clock.c
137,140c137,141
< 		lock(&clock0lock);
< 		for(lp = clock0link; lp; lp = lp->link)
< 			lp->clock();
< 		unlock(&clock0lock);
---
> 		if (canlock(&clock0lock)) {
> 			for(lp = clock0link; lp; lp = lp->link)
> 				lp->clock();
> 			unlock(&clock0lock);
> 		}

2.  Added (very minimal) support for the DEC DE-500 (and perhaps
other 21143-based cards that use SYM media controllers) to ether2114x.c.
I based my work on the more up-to-date driver in the PC platform port
of Plan 9.  Therefore, to apply this patch, do two steps:
	a) copy /sys/src/9/pc/ether2114x.c to /sys/src/9/alphapc
	2) apply the following diffs
Note that the portion of the diffs from line 978 onwards can
also be applied to /sys/src/9/pc/ether2114x.c to add support for
21143 cards with SYM media controllers on PC platforms.

By the way, I think it would be a big win to share PCI drivers
between platforms.  The only difference between the Alpha and PCI
versions of ether2114x.c were use of PCIWADDR instead of PADDR,
and one use of xspanalloc instead of malloc.  With just a little
work I'm sure many drivers could be platform-independent.

term% diff 9/pc/ether2114x.c 9.new/alphapc/ether21114x.c
388c388
< 		des->addr = PADDR(bp->rp);
---
> 		des->addr = PCIWADDR(bp->rp);
473c473
< 					des->addr = PADDR(bp->rp);
---
> 					des->addr = PCIWADDR(bp->rp);
577c577
< 	ctlr->rdr = malloc(ctlr->nrdr*sizeof(Des));
---
> 	ctlr->rdr = xspanalloc(ctlr->nrdr*sizeof(Des), 8*sizeof(ulong), 0);
582c582
< 		des->addr = PADDR(des->bp->rp);
---
> 		des->addr = PCIWADDR(des->bp->rp);
586c586
< 	csr32w(ctlr, 3, PADDR(ctlr->rdr));
---
> 	csr32w(ctlr, 3, PCIWADDR(ctlr->rdr));
592c592
< 	csr32w(ctlr, 4, PADDR(ctlr->tdr));
---
> 	csr32w(ctlr, 4, PCIWADDR(ctlr->tdr));
978a979,998
> typesymmode(Ctlr *ctlr, uchar *block, int wait)
> {
> 	uint gpmode, gpdata, command;
> 
> 	USED(wait);
> 	gpmode = block[3] | ((uint) block[4] << 8);
> 	gpdata = block[5] | ((uint) block[6] << 8);
> 	command = (block[7] | ((uint) block[8] << 8)) & 0x71;
> 	if (command & 0x8000) {
> 		print("ether2114x.c: FIXME: handle type 4 mode blocks where cmd.active_invalid != 0\n");
> 		return -1;
> 	}
> 	csr32w(ctlr, 15, gpmode);
> 	csr32w(ctlr, 15, gpdata);
> 	ctlr->csr6 = (command & 0x71) << 18;
> 	csr32w(ctlr, 6, ctlr->csr6);
> 	return 0;
> }
> 
> static int
1070a1091,1094
> 				return 0;
> 			break;
> 		case 4:
> 			if(typesymmode(ctlr, block, wait))


^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2001-11-05 11:42 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-10-23 14:00 [9fans] Alpha success (w/ clock.c bugfix and ether2114x.c update) jmk
  -- strict thread matches above, loose matches on Subject: below --
2001-11-05  5:32 okamoto
2001-10-25  1:13 okamoto
2001-10-23 20:41 rob pike
2001-10-23 14:58 jmk
2001-10-23 14:17 jmk
2001-10-23 14:35 ` Ronald G Minnich
2001-10-23 20:32   ` Matthew Hannigan
2001-10-23 22:26     ` Dan Cross
2001-10-25  4:36   ` Boyd Roberts
2001-10-25  6:06     ` andrey mirtchovski
2001-11-05 10:21       ` Jonadab the Unsightly One
2001-11-05 11:42         ` Boyd Roberts
2001-10-23 14:56 ` Sam Ducksworth
2001-10-23 17:25   ` Ronald G Minnich
2001-10-23 18:55 ` Mike Haertel
2001-10-23 19:23   ` Ronald G Minnich
2001-10-23 20:17     ` Scott Schwartz
2001-10-23 20:26       ` andrey
2001-10-23 20:36       ` Ronald G Minnich
2001-10-22 14:11 jmk
2001-10-23  4:53 ` Mike Haertel
2001-10-23  5:54   ` George Bronnikov
2001-10-22  7:54 Mike Haertel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).