Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Dec 1999 13:44:47 -0800 (PST)
From:      Julian Elischer <julian@whistle.com>
To:        Bill Paul <wpaul@skynet.ctr.columbia.edu>
Cc:        hackers@FreeBSD.ORG
Subject:   Re: USB ethernet hacking
Message-ID:  <Pine.BSF.4.10.9912191335460.41729-100000@current1.whistle.com>
In-Reply-To: <199912192103.QAA03584@skynet.ctr.columbia.edu>

next in thread | previous in thread | raw e-mail | index | archive | help


On Sun, 19 Dec 1999, Bill Paul wrote:

> For those of you who don't know, I've been working on a driver for the
> ADMtek USB Ethernet chip (AN986 Pegasus). It kinda sorta works:
> 
> aue0: ADMtek Inc. ADMtek 10/100 USB MAC, rev 1.10/1.01, addr 2
> aue0: Ethernet address: 00:00:e8:00:00:a2
> miibus0: <MII bus> on aue0
> ukphy0: <Generic IEEE 802.3u media interface> on miibus0
> ukphy0:  10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
> 
> The particular adapter I have is a combo device which supports both
> 10/100 ethernet and 1Mbps HomePNA (ethernet over home telephone cabling).
> I only have the ethernet PHY enabled for the moment since I don't
> have any way to test the HomePNA part, and I need to write a separate
> HomePNA PHY driver so that the media type is recognized correctly.
> (Right now, the ukphy driver thinks it's just another 10Mbps PHY,
> which causes the miibus layer to think the interface has two 10baseT/UTP
> media selections, which doesn't work.)
> 
> I've gotten the thing working well enough with FreeBSD-current that I
> can telnet over it and type this message. However, there are some problems
> that I've run into which I don't know how to solve due to my inexperience
> with USB.
> 
> First of all, there's one major problem with the USB code as it's currently
> implemented with regard to "synchronous" transfers. There are two basic ways
> to transfer data to/from a USB device: an asynchronous method, and a
> synchronous one. The asynchronous one works like this:
> 
> 	- allocate a USB transfer handle
> 	- set it up with the correct parameters, including a pointer
> 	  to a callback routine
> 	- call usbd_transfer() to initiate it
> 	- go off and to other stuff for a while
> 	- when the transfer is done, the USB controller's interrupt
> 	  handler will call the callback routine with the transfer
> 	  results.
> 
> The synchronous method works like this:
> 
> 	- allocate a USB transfer handle
> 	- set it up with the correct parameters
> 	- call usbd_sync_transfer() to initiate it
> 	- usbd_sync_transfer() blocks until the transfer is complete,
> 	  and which point you can call usbd_get_xfer_status() to
> 	  find the results
> 
> The problem is that the synchronous method is not really synchronous:
> in usbdi.c:usbd_transfer(), if we are performing a sync transfer and
> the transfer doesn't complete right away, the code calls tsleep() in
> the hope that it can pause the process that initiated the transfer and
> wake it up later. Unfortunately, you can't call tsleep() from interrupt
> context, and I need to be able to do that. Why? Because reading and
> writing the registers on the ethernet MAC in the ADMtek device is done
> by performing transfers using USB endpoint 0 (the control endpoint).
> The miibus code needs to be able to read the PHY status once in a while,
> and this is done by setting up a timeout() that fires once a second to
> tall the aue_tick() routine, which in turn calls mii_tick() to drive
> the miibus code. But aue_tick() is called at interrupt context, and
> the kernel panicks whenever it hits that tsleep() in usbd_transfer().


Doug Ambrisko and I wrote a netgraph based USB-to-USB networking device
node. We used the async method and it works fine. We just added 
a queue and called an interrupt level 'start routine' much like any other
driver.  It works like a charm. I don't see why it wouldn't work for an 
ethenet style device.. We had to add splimp() protection in some places
because splusb() is actually splbio() but it seems to work as expected.





> 
> I have worked around this for now by hacking usbdi.c so that it polls
> the controller interrupt/status register instead of tsleep()ing. I'm not
> sure this is the best solution, but it's the only one that seems to work.

why not use the async method?
 
> 
> However that's not my biggest problem. My biggest problem is getting
> transfers over 1100 bytes or so to work reliably. My initial scheme
> for transmitting and receiving packets was to set up asynchronous
> transfers with callbacks.

That's what we did and we can send 1500 byte packets with no problems.


> Packets are sent over bulk transfer endpoints
> (one for RX, one for TX). For TX, I would set up a transfer and initiate
> it, then wait until the callback is called to free the mbuf containing
> the packet data.

 We just copied the data from the mbuf into a dedicated
buffer and freed the mbuff immediatly.

> This seemed to work, but only for transfers around
> 1000 to 1100 bytes or so. Trying to transfer packets of 1200 bytes or
> more always seemed to yield an "IOERROR" error. I switched the packet
> transmission code to use synchronous transfers (i.e. waiting for the
> transfer to complete before moving on) and this seemed to help: I could
> now get transmissions up to 1500 bytes to work without errors.

Once again, we used a dedicated buffer which we copied from.


> 
> However, I have the same problem now with received packets: trying to
> receive a frame larger than 1100 bytes also causes an IOERROR, however
> I can't use a synchronous transfer here since that would cause the kernel
> to freeze in its tracks waiting for a packet.
> 
> Tracing down the error shows that the uhci driver is getting an error
> status of 0x500000, which is apparently the logical OR of two error bits:
> "babble" and "stall." I have the Intel UHCI spec document and it mentions
> these errors, however it doesn't seem to say what causes them, how to
> clear them or, more importantly, how to avoid them. If I could just
> figure out how to get this thing to handle these "large" transfers, I
> would be a happy camper.
> 
> I put a copy of my current code at:
> 
> http://www.freebsd.org/~wpaul/ADMtek/USB/4.0
> 
> This directory contains the source for the if_aue driver, plus a patch
> for usbdi.c with the changes I made to get sync transfers to work properly
> in interrupt context. The code is still very grotty. The datasheet for
> the ADMtek Pegasus chip is at http://www.admtek.com.tw.
> 
> -Bill
> 
> P.S.: Please don't write me asking for help getting your USB ethernet
>       adapter work with FreeBSD. Don't ask me when/if the driver will
>       be done. Don't ask me if your favorite adapter will be supported.
>       Don't ask me how to make the code work with FreeBSD 3.x.
> 
> 
Julian




To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.10.9912191335460.41729-100000>