This is very nice. You might be interested in comparing notes with
Axel Bernal ([EMAIL PROTECTED])
How hard would it be to make this driver work with the new POSIXIO
interface we added?
On Tue, Sep 07, 1999 at 08:26:21PM -0700, Michael M. Morrison wrote:
> This is a quick overview of the interface that we used to communicate with
> ethernet devices from our realtime task. It is important to note that this
> gives us an interface to RAW ethernet frames, not the IP/UDP/TCP networking
> layers. This is not that much of an issue considering that remote Linux
> machines can open sockets of type SOCK_PACKET which will receive raw frames
> (actually ALL frames). In addition this means that all error-checking
> (except for the hardware CRC) has to be done by the application. Our
> application communicates with a remote device at 800hz over a dedicated
> ethernet using this method. We are using kernel 2.2.10, the beta11 release
> of RTL, and the tulip driver as our baseline.
>
> Ethernet Drivers
> -----------------------
> The communication from the kernel to an ethernet driver is through function
> pointers in a 'device' structure, so that there can be multiple devices
> loaded at once. As devices are modprob'd in, a new 'device' structure is
> built, and registered via the core networking code in linux/net/core/dev.c.
> An 'skb' is a 'struct sk_buff *' which is the encapsulation that the network
> drivers use send/receive frames.
>
> The functions of interest are:
> dev->open( dev ): open the device, prepare for use
> dev->stop( dev ): stop the device, shut it down
> dev->hard_start_xmit( skb, dev ): transmit the frame in the skb
> dev->do_ioctl( dev, struct ifreq *, ioctl number): described later
>
> The variables of interest are:
> dev->tbusy: the device busy status flag
> dev->flags: some drivers check dev->flags to make sure IF_IFUP is set in
> their dev->open routine. The tulip driver does not do this. Thanks to
> D.Becker for pointing this out.
> dev->dev_addr[6]: the hardware address of the card.
>
> Ethernet devices communicate to the kernel via the following functions:
> netif_rx( skb ): informs the core networking code that a frame has been
> received
> mark_bh( NET_BH ): informs the kernel that the "bottom half" of the driver
> routine for the ethernet subsystem should be run at it's earliest convience.
>
> There are several additional functions that are required from the core
> networking code:
> dev_get( "ethN" ): get the device structure for the ethernet device numbered
> 'N'.
> dev_alloc_skb( length ): allocate an skb of the given size
> dev_kfree_skb( skb ): free the skb
> skb_put( skb, length ): reserve 'length' bytes at the end of the packet, and
> return a pointer to it.
> skb_push( skb, length ): reserve 'length' bytes at the start of the packet,
> and return a pointer to it.
>
> Device driver modifications
> --------------------------------------
> Given the above information, there are two places in the ethernet driver
> that need to be modified: the calls to netif_rx and mark_bh. These routines
> need to be hooked such that they call our code, as opposed to the kernel/net
> code.
>
> We chose to modify the 'private' data structure that the driver attaches to
> dev->priv (when dev->open() is called), and add a function pointer to be
> called whenever netif_rx or mark_bh was to be used. In addition we modified
> the do_ioctl of the driver and added a new SIOCDEVPRIVATE to set the
> function pointer. In this way it was supposed that the driver could be used
> by either the RT side, or the Linux side by checking the function pointer to
> see if it was NULL at the appropriate times. Our implementation uses one
> function call that passes an skb if netif_rx was to be called, and NULL if
> mark_bh was to be called. Not all drivers have the do_ioctl compiled in.
> In our case, we modified the 'tulip' driver, which did not compile it in by
> default.
>
> It should go without saying that the device MUST be ifconfig'd down (or
> never ifconfig'd at all) to use the above method. RT and non-RT would not
> play well together.
>
> We modified the dev->stop() routine to set the dev->priv->functionPointer to
> NULL before the rest of the shutdown of the device occurs. When this was
> not done, we experienced spurious crashes on the shutdown of the device in
> the tulip driver.
>
> Device Init
> ---------------
> To initialize the device and prepare it for use:
>
> dev = dev_get( "eth1" );
> dev->open( dev );
> ifr.data = rxPacket; // our receive routine
> dev->do_ioctl( dev, &ifr, SIOCDEVPRIVATE+3 ); // our special ioctl
> memcpy( localHWAddress, dev->dev_addr, 6 );
>
> Transmit
> ------------
> To transmit a frame:
>
> if( dev->tbusy == 0 ) {
> skb = dev_alloc_skb( length );
> ptr = skb_put( skb, length );
> memcpy( &ptr[0], localHWAddress, 6 );
> memcpy( &ptr[6], remoteHWAddress, 6 );
> ptr[6+6] = ETH_TYPE_HI;
> ptr[6+6+1] = ETH_TYPE_LO;
> memcpy( &ptr[6+6+1+1], outData, length );
> dev->hard_start_xmit( skb, dev );
> }
>
> Notes:
> 1) The proper header for an 'ethernet' (as opposed to 802.3) encoded packet
> is:
> [ 6 bytes of source hardware address ][ 6 bytes of dest hardware
> ddress ][ 2 bytes of 'type' ][...data...]
> 2) There is a minimum length of 48 bytes in the data portion of an ethernet
> encoded packet.
> 3) The maximum length of the data portion is 1500 - (6+6+2)
> 4) Use care when selecting a 'type'. We use 0x0900, which is the code from
> an old ethernet debugging device, I believe. It also needs to be in
> 'network' byte order, which is big endian. 802.3 uses this portion as the
> 'length' field.
> 5) The device itself free's the skb when it is done with it.
>
> Receive
> ------------
> When the driver receives a frame (or wants the "bottom-half" run), it will
> call our rxPacket routine via the function pointer registered earler. In
> our case, if the argument was NULL, then rxPacket was being called in place
> of the mark_bh routine. We do nothing in this case (in fact, it is rarely
> if ever called in the tulip driver). In the event the argument was
> non-NULL, then rxPacket was being called in place of the netif_rx with an
> skb of data:
>
> skb_push( skb, 6+6+2 ); // optional
> memcpy( inData, skb->data, skb->len );
> dev_kfree_skb( skb );
> packetAvailable = 1;
>
> Notes:
> 1) The driver attempts to align the skb->data portion on a 4 byte boundary
> (I believe), and therefore removes the 14 byte header from the skb->data
> area. The skb_push() will move the data pointer back by 14 bytes to
> recapture the header. This may not be required in all circumstances, and
> there may be another way to get the header - I have not looked into it.
> 2) The data does not have to be copied out of the skb immediately, but
> eventually the skb needs to be free'd by your code.
>
> Shutdown
> --------------
> To shutdown the driver call dev->close( dev ).
>
>
>
> We created a separate kernel-loadable module which encapsulates the above
> method that we load as part of our startup sequence. A fair amount of this
> was typed from memory, so there may be a typo or two. It is not clear to us
> how much time may be taken up in the dev_alloc_skb call (which eventually
> calls a kernel routine for skb_alloc which, in turn, calls kmalloc(). We
> have not tested this code on an SMP configuration, since 2.2.10+beta11 would
> crash when compiled with SMP on.
>
> We welcome comments on the use of the above method, and would be happy to
> share the module and modified tulip driver as reference implementations.
>
> ---
> Michael M. Morrison
> VP, Chief Technical Officer
> Hyperion Technologies, Inc.
> (970) 493-1900
>
> --- [rtl] ---
> To unsubscribe:
> echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
> echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
> ----
> For more information on Real-Time Linux see:
> http://www.rtlinux.org/~rtlinux/
--- [rtl] ---
To unsubscribe:
echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
----
For more information on Real-Time Linux see:
http://www.rtlinux.org/~rtlinux/