Subject: Re: help with tulip port from netbsd to darwin
To: chuck remes <cremes@mac.com>
From: Sean Davis <dive@endersgame.net>
List: tech-net
Date: 04/16/2002 20:33:51
I have one of those cards:
tlp0 at pci0 dev 9 function 0: ADMtek AN985 Ethernet, pass 1.1
tlp0: interrupting at irq 12
tlp0: Ethernet address 00:04:5a:67:5e:a7
acphy0 at tlp0 phy 1: ACXXX 10/100 media interface, rev. 0
acphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
When it first came into my posession, it didn't work in the netbsd-1-5
branch, and the handling for it in -current went in only a few days before I
tried current to see if I could get it to work. I've used other tulip cards
in FreeBSD and NetBSD before, with no problems, I think that the ADMtek
cards are slightly different than the standard everyday tulip. I don't know
the hardware details very well, but from brief reading through
sys/dev/pci/if_tlp_pci.c revision 1.64, the biggest oddity I see is:
* The ADMtek AN985 can be configured in Single-Chip
* mode or MAC-only mode. Single-Chip uses the built-in
* PHY, MAC-only has an external PHY (usually HomePNA).
* The selection is based on an EEPROM setting, and both
* PHYs are accessed via MII attached to SIO.
*
* The AN985 "ghosts" the internal PHY onto all
* MII addresses, so we have to use a media init
* routine that limits the search.
* XXX How does this work with MAC-only mode?
(As far as I can tell, the reason it didn't work in netbsd-1-5 was because
acphy wasn't in the branch yet. But don't take my word for it :)
Disregard this of course if you have already taken that into consideration,
I just thought it might be worth noting, as it seems to be behavior unique
to the AN985 cards.
-Sean
On Tue, Apr 16, 2002 at 06:44:04PM -0500, chuck remes wrote:
> If this is an inappropriate question for the list, my apologies!
>
> I've undertaken the task of porting the tulip driver from freebsd/netbsd
> to darwin. I don't know if you are in the business of helping people port
> this driver to other OSes, but I'm hoping for some help with a few
> questions. I searched all the archives of tech-net, but virtually none of
> the discussion covers coding of the driver. As an aside, I don't know if
> any of you are familiar with darwin or not, but its driver model is based
> on IOKit which is substantially different from any other bsd unix. On the
> off chance you'll answer, I'll include as much info as I can. :-)
>
> Anyway, I'm almost done. I have receiving working, but transmitting won't
> work no matter what incantations I attempt. My target chipset is the
> ADMtek 985 (out of a Linksys EtherFast release 5.1, a 21143 clone). My
> descriptors (chained) are aligned along a quadword boundary (3 lowest bits
> are 0) and I coalesce my outgoing mbuf into a single physical segment.
> Also, to verify bus timing issues aren't throwing me off I have set the
> transmitter for store-and-forward mode.
>
> After tx'ing the first packet, my registers look like:
> control = 0xfef98082 tx_demand = 0xffffffff
> rx_demand = 0xffffffff rx_desc = 0x0ce54808
> tx_desc = 0x0ce54888 status = 0xfc67c814
> netconfig = 0xffb72153 intrrupts = 0xfffe5410
> lpc = 0xfffe0000 MIIeeprom = 0xfff0b7f8
> rom = 0x00000000 timer = 0xfffe0000
> 10btstat = 0x00000000 siareset = 0x00000200
>
> Here's my empty tx descriptor chain (8 desc).
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce54898
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce548a8
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce548b8
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce548c8
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce548d8
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce548e8
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce548f8
> s = 0x00000000 c = 0x00000000 b1 = 0x00000000 b2 = 0x0ce54888 <- points
> back to first
>
> Here are the values in my descriptor before kicking the transmitter (csr1)
> outputPacket, output pkt length = 42
> outputPacket, tx mbuf 0x02d5e8d6 in desc 0
> outputPacket, B4 s = 0x80000000 c = 0xe100002a b1 = 0x02d5e8d6 b2 =
> 0x0ce54898
> outputPacket, kick tx-er
> outputPacket, AF s = 0x1a078c80 c = 0xe100002a b1 = 0x02d5e8d6 b2 =
> 0x0ce54898
>
> The status word gets set to a very bizarre value. Most of those bits aren'
> t even defined (in either the 21143 datasheet or the ADMtek datasheet).
> Those that are say (bit 7) hearbeat failure, (bit 10) no carrier, and (bit
> 11) loss of carrier.
>
> After sending a second packet, the status register is 0xfc67c815. The
> lowest bit got set after the second packet!
>
> This is telling me that (bit 2) tx buf unavailable and (bits 22,21) tx
> suspended due to underflow or unavail descriptor. Strangely, bit 0 is set
> which tells me the tx finished, so at least I know it is reading the
> tx_interrupt bit out of the control word (bit 0 does not set if I don't
> set that bit in the control word of the descriptor).
>
> Darwin runs on PPC, so there are endian differences. I take care of all
> that by reordering the bytes in the tulip descriptor structure and writing
> the addresses in little-endian to the card (in a method _descOrder()) much
> like the netbsd driver uses the DESC_BO macro.
>
> Here is a segment of code that shows my output packet routine.
>
> UInt32 com_chuck_iokit_tulip::outputPacket(struct mbuf * m, void * param)
> {
> if ( !enabledNetif)
> {
> IOLog("%s, interface not enabled\n", __FUNCTION__);
> // drop the packet
> freePacket( m);
> return kIOReturnOutputDropped;
> }
>
> if ( txActiveCount >= TULIP_TX_RING_LENGTH) {
> IOLog("%s, kIOReturnOutputStall", __FUNCTION__);
> return kIOReturnOutputStall;
> }
>
> struct IOPhysicalSegment vector;
> int segments;
>
> // coalesce to one mbuf segment
> segments = txMbufCursor->getPhysicalSegmentsWithCoalesce( m, &vector);
>
> if ( ! segments)
> {
> // record error stats
> IOLog("%s, getPhysicalSegmentswithCoalesce returned zero\n",
> __FUNCTION__);
> freePacket( m);
> return kIOReturnOutputDropped;
> }
>
> txActiveCount++; // update counter
>
> int i = txHead;
> tulip_descriptor_t * d = &tx_desc_ring[ txHead];
>
> IOLog("%s, output pkt length = %d\n", __FUNCTION__, m->m_len);
> // tells chip to use chain-mode, plus length of mbuf seg
> d->control = _descOrder( ADMTEK_TX_CTL_TLINK | m->m_len);
> d->status = 0;
> // assign physical address to buffer1
> d->buffer1 = _descOrder( vector.location);
> // save the virtual address so we can safely call freePacket()
> tx_mbuf_ring[ i] = m;
> IOLog("%s, tx mbuf 0x%08x in desc %d\n", __FUNCTION__, (UInt32) vector.
> location, i);
>
> d->control |= _descOrder( ADMTEK_TX_CTL_FIRSTFRAG);
> d->control |= _descOrder( ADMTEK_TX_CTL_LASTFRAG);
> // force interrupt every 4 packets to allow for housekeeping tasks
> d->control |= _descOrder( ADMTEK_TX_CTL_FINT);
> // set OWN bit so chip knows it can take control of descriptor
> d->status = _descOrder( ADMTEK_TX_STAT_OWN);
>
> RING_INCREMENT( txHead, TULIP_TX_RING_LENGTH);
> IOLog("%s, B4 s = 0x%08x c = 0x%08x b1 = 0x%08x b2 = 0x%08x\n",
> __FUNCTION__,
> _descOrder(tx_desc_ring[i].status),
> _descOrder(tx_desc_ring[i].control),
> _descOrder(tx_desc_ring[i].buffer1),
> _descOrder(tx_desc_ring[i].buffer2));
>
> // kick transmitter
> _writeRegister( ADMTEK_TXSTART, 0xbaadf00d);
>
> IOLog("%s, kick tx-er\n", __FUNCTION__);IOSleep(20);
> IOLog("%s, AF s = 0x%08x c = 0x%08x b1 = 0x%08x b2 = 0x%08x\n",
> __FUNCTION__,
> _descOrder(tx_desc_ring[i].status),
> _descOrder(tx_desc_ring[i].control),
> _descOrder(tx_desc_ring[i].buffer1),
> _descOrder(tx_desc_ring[i].buffer2));
>
> return kIOReturnOutputSuccess;
> }
>
> Any ideas?
>
> cr
>
--
/~\ The ASCII Sean Davis
\ / Ribbon Campaign aka dive
X Against HTML
/ \ Email! http://eros.endersgame.net:8000/~dive