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/

Reply via email to