none none none

REDD: RTLinux Ethernet Device Drivers

Project Description

Supported Drivers

The API: Special Features




Testing REDD

The REDD Logo


Development Page
The development page at: Logo
Project Description

REDD is an Open Source project consisting on a set of Ethernet card drivers for RTLinux-GPL. This drivers provide the standard POSIX API (open, close, read, write and ioctl calls) and can be accessed by RT-tasks to send and receive messages through an Ethernet network.

Two kind of drivers are distinguised:

Native drivers are interrupt-driven drivers that use the Linux PCI subsystem to access the PCI bus. This drivers were included in the RTL-lwIP distribution until version 0.5.

Etherboot drivers are the porting of the Etherboot project's Ethernet drivers to RTLinux-GPL. This drivers are accessed by means of polling and they've been modified to provide the POSIX API and to make abstract the polling access to the final user (normally an RT-task). This porting is handled in another web page by now: RTL-EtherbootD project . The RTL-EtherbootD web page will be merged into this one in short.

NOTE: the drivers only provide access to the network, they don't implement no protocol (such as ARP or RARP) and also they don't add Ethernet headers to your data (Etherboot drivers can do it, that's called the raw API). Your application must add the proper headers. Take this into account.

NOTE FOR DRIVER DEVELOPERS: The RTLinux code needed to develop a new REDD driver is gathered together in the file src/include/drivers/rtl_posix_if.h. This simplifies a lot the work of developing a new driver. The rest of work deals with modifying the Linux driver sources to make them not to call some Linux kernel calls and substitute them for the proper calls. The file rtl_posix_if.h not only gathers together the RTLinux code but specifies which functions have to be provided by any driver and standarizes the structure of a REDD driver.
If you're interested in developing a new driver contact me at (serpeal_AT_upvnet_DOT_upv_DOT_es).

NOTE FOR PROTOCOL DEVELOPERS: REDD provides a mechanism that allows developers to substitute the open, read, write, close and ioctl (hereafter the POSIX calls) with your own calls without modifying the driver's code. This mechanism is provided in the file src/include/posix_fake/rtl_posixio_fake.h. That file allows your code to get a pointer to each of the POSIX calls functions declared in the driver and use them (if you want) inside your calls (that will substitute the driver's ones). This allows you to add code before and after the POSIX calls transparently (the final user will call read, write, etc.. in the same way, but your code will be executed instead of the driver's code), being a powerful mechanism to develop protocols that use the network (in fact we're developing a real-time protocol over Ethernet using that structure :)

Supported Drivers [top]

Native drivers - two drivers ported by now:

  • 3c59x driver: ported to RTLinux by Sergio Pérez (serpeal_at_upvnet_dot_upv_dot_es).

  • 8139too driver: ported to RTLinux by ByungGi Baek (gi_at_realtimewave_dot_com).

  • e100 driver: ported to RTLinux by De Yu Liu (bullleo2003_at_yahoo_dot_com).

Since the RTLinux native drivers are ported from the Linux drivers, each driver should support the same adaptors than the Linux driver. This lines are from the original drivers:

  • 3c59x: this driver is for the 3Com "Vortex" and "Boomerang" series ethercards. Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597 and the EtherLink XL 3c900 and 3c905 cards.

  • 8139too: this driver is for boards based on the RTL8129 and RTL8139 PCI ethernet chips. It also supports RTL8139C+ PCI ethernet chips.

  • e100: the following Intel network adapters are compatible with the drivers in this release.

    Controller Adapter Name Board IDs
    82558 PRO/100+ PCI Adapter 668081-xxx, 689661-xxx
    82558 PRO/100+ Management Adapter 691334-xxx, 701738-xxx, 721383-xxx
    82558 PRO/100+ Dual Port Server Adapter 714303-xxx, 711269-xxx, A28276-xxx
    82558 PRO/100+ PCI Server Adapter 710550-xxx
    PRO/100 S Server Adapter 752438-xxx (82550)
    A56831-xxx, A10563-xxx, A12171-xxx, A12321-xxx, A12320-xxx, A12170-xxx
    748568-xxx (82559)
    748565-xxx (82559)
    PRO/100 S Desktop Adapter 751767-xxx (82550)
    748592-xxx, A12167-xxx, A12318-xxx, A12317-xxx, A12165-xxx
    748569-xxx (82559)
    82559 PRO/100+ Server Adapter 729757-xxx
    82559 PRO/100 S Management Adapter 748566-xxx, 748564-xxx
    82550 PRO/100 S Dual Port Server Adapter A56831-xxx
    82551 PRO/100 M Desktop Adapter
    PRO/100 S Advanced Management Adapter
    747842-xxx, 745171-xxx
    CNR PRO/100 VE Desktop Adapter
    PRO/100 VM Desktop Adapter
    A10386-xxx, A10725-xxx, A23801-xxx, A19716-xxx
    A14323-xxx, A19725-xxx, A23801-xxx, A22220-xxx, A23796-xxx

Etherboot drivers - this porting is handled in another web page by now. The detailed list of supported drivers is listed here. Please visit the RTL-EtherbootD project web site for more information.

The API: Special Features [top]

This drivers, despite the usual API, provide the standard POSIX API, i.e., the standard open(), close(), read(), write() and ioctl() calls. Except for the read() call, the other calls are used as usual.

The read() call has been implemented to provide the standard interface, although the way of using that interface by default is not the usual (the drivers can provide the usual way of interfacing them by modifying a macro... go on reading :): it implements the ZERO COPY technique. A normal read() call would need the user to pass a pointer to a previously reserved memory area and the driver would fill that area with data (this way of interfacing the read can be achieved by uncommenting the macro _NO_ZERO_COPY_API_ in the reddopts.h file) call. That means that the driver would have to perform a copy for each packet. In the implementation we provide, the driver saves the expense of that copy just by returning a pointer to the packet being hold in the internal buffers of the driver; this technique is usually named zero copy.

Now a description of the API of each call and an example using it will be shown. The examples are taken from the test program provided with REDD, which is a ping server. You can see the whole code here. Pay special attention to the read() call.

SYNOPSIS: int open(const char *pathname, int flags);

Next, an example of how to use the open() call with RTLinux drivers. In RTLinux, the open call MUST be called inside the init_module() function. Each driver will be located in a virtual location, such as /dev/, and will have a name, such as eth0, or rtl0 or whatever name. In the next example we'll open /dev/eth0 in blocking mode (0 does not mean blocking mode, blocking mode is set by default). The returned value, fd, is used to identify the device. A reference to fd will be used in the next examples.

      if((fd=open("/dev/eth0",0)) == -1){
        rtl_printf("ERROR OPENING /dev/eth0 in blocking mode\n");
        return -1;

The driver can be opened in non-blocking mode by using the flag O_NONBLOCK as follows:

      if((fd=open("/dev/eth0",O_NONBLOCK)) == -1){
        rtl_printf("ERROR OPENING /dev/eth0 in non-blocking mode\n");
        return -1;

SYNOPSIS: int close(int fd);

Next, an example of how to use the close() call with RTLinux drivers. If fd is the device we want to close, then this code closes the device referenced by fd.


SYNOPSIS: int ioctl(int d, int request, ...);

The ioctl() call is used to set or to get parameters of the device. In the next example we'll show how to get the Ethernet card's MAC address by means of ioctl().

   unsigned char MAC[6];
   //Obtain the network interface's MAC address. 
   ioctl(fd, 2, (unsigned long) MAC);

SYNOPSIS: ssize_t read(int fd, void *buf, size_t count);

As said before, by default the read() call uses the ZERO COPY technique. Although the read()'s interface is standard, the way of using that interface has to be modified to implement the zero copy technique. Using the zero copy technique, in order to get a pointer to the driver's internal buffer, an indirection level is needed. To achieve this, a structure encapsulating a memory pointer is needed. The next structure is the one used in REDD:

   struct memory{
      void *mem;

The next code shows how to interface the read call using the previous structure:

   struct memory receive_buffer;
   unsigned char *in_buf;
   int len;
   // Obtain the size of the packet and put it into the "len" variable
   len = read(fd,(void *) &receive_buffer,1536);

   //This implements the ZERO COPY technique. In one hand, instead of copying 
   //the buffer into the one passed by us the driver give us a pointer to the 
   //internal buffer, thus saving the expense of a copy. On the other hand, 
   //we should NOT modify that buffer.
   in_buf = (char *) receive_buffer.mem;

Programming this way the driver's interface, after performing the read() call, receive_buffer.mem will contain a pointer to the driver's internal buffer.

If you want to interface read() as usual and not to use the ZERO COPY API uncomment the define _NO_ZERO_COPY_API_ in the reddopts.h file. That will allow you to use the read() call as usual. Nex a code showing how to use the read() call in this mode (it is supposed that the driver has been opened in blocking mode):

   unsigned char in_buf[1536];
   int len;
   // Obtain the size of the packet and put it into the "len" variable
   len = read(fd,(void *) &in_buf,1536);

If the driver is opened in non-blocking mode (using the O_NONBLOCK flag), then the application must poll the driver to see if a packet has arrived. The next code shows how to use the read() call if the driver is opened in non-blocking mode:

   unsigned char in_buf[1536];
   int len;

       // Obtain the size of the packet and put it into the "len" variable
       len = read(fd,(void *) &in_buf,1536);

The usleep() call is necessary (although the time to sleep can vary). If not called, your machine will be blocked in the do-while loop until a packet arrives, and that can hang your machine.

For more information about the implementation of the drivers, please read the paper "Building Ethernet Drivers on RTLinux-GPL", downloadable in the download section.

Requirements [top]

In order to correctly compile and run REDD you need:

  • TLSF - Real-Time Dynamic Memory Allocator: this is the first real-time dynamic memory allocator in the world. It has it's own web page, however the latest version is not prepared to run in RTLinux, so we've prepared our own tarball where we've modified TLSF to run in RTLinux and to use the memory provided by bigphysarea. It is used to handle the drivers' buffers. TLSF-1.3.1 is included in the REDD-0.3 tarball, however we've prepared a separate tarball for those that are interested in using it in RTLinux. Go to the download section.
  • Bigphysarea: this is a driver which allocates a big piece of memory during boottime and returns the entire piece or parts of it to a requesting driver (download it here).
Download Section [top]

Here you can download the native drivers and a tool for both native and Etherboot drivers. If you want to download the Etherboot drivers, please visit the RTL-EtherbootD web page.


RTLinux Ethernet Device Drivers version 0.4 (Native drivers). View the changelog.
400 kb
RTLinux Ethernet Device Drivers version 0.3 (Native drivers). View the changelog.
404 kb
RTLinux Ethernet Device Drivers version 0.2 (Native drivers). View the changelog.
404 kb
RTLinux Ethernet Device Drivers version 0.1.1 (Native drivers). View the changelog.
360 kb
RTLinux Ethernet Device Drivers version 0.1 (Native drivers)
368 kb
Real-Time Dynamic Memory Allocator for RTLinux (included in REDD-0.3)
308 kb
Building Ethernet Drivers on RTLinux-GPL
Paper describing the main features of this drivers and how to build new drivers.
360 kb
Testing REDD [top]

You can test any REDD driver by inserting the ping server examples provided in src/test. If you've uncommented the _NO_ZERO_COPY_API_ defined in src/reddopts.h then you can use the ping_posix.o module to test the drivers (ping_posix.o uses the read() call as the standard defines). If you haven't uncommented that option then you can test the drivers by means of the ping_zc.o module, which is a ping server that uses the read() function applying the ZERO COPY technique.

In both cases you may want to modify the sources (in src/test) to open the devices in nonblocking mode (by modifying the line: open(DEVICE_NAME,0) with open(DEVICE_NAME,O_NONBLOCK)).

Depending on the driver that you want to test you must configure the source files in order to test the driver you need. For example: by default, ping_zc.c opens "/dev/eth0", which is assigned to the 3c59x driver. If you want to test the realtek driver you must change "/dev/eth0" by "/dev/rtl0" or the e100 driver by using "/dev/rtle0".

Both ping_zc.o and ping_posix.o modules have parameters. You must give the IP address of your machine to the ping server in order to serve echo replies. Usage (it is the same for both):

This module requires parameters.
         insmod ping_{zc,posix}.o IP=ip_address;
         insmod ping_{zc,posix}.o IP="";
     For more information type as root:
         modinfo ping_{zc,posix}.o;

Here you can visit the ping_zc.c code.

The REDD logo [top]

The logo is a mixture between a drawing of the first Ethernet system by Bob Metcalfe (taken from here) and the RT-Tux of the Real Time Linux Foundation.

none none


This mixture represents the essence of the REDD project, doesn't it?
Frequently Asked Questions [top]

Can I have two drivers for the same card, the Linux one and the RTLinux one?

You can, but they can't work at the same time. The RTLinux driver must control the card, so the Linux driver must not interfere. In fact, before inserting the RTLinux driver you must turn down the Linux one (lets call it eth0) by means of the command:
$ifconfig eth0 down
If you don't do this you may hang your machine.
After removing the RTLinux driver you can turn up your linux driver by typing:
$ifconfig eth0 up
Your Linux driver will start working as it always did.

Can Linux access the RTLinux driver?

Not yet. I'm working in a layer that will allow Linux to share any RTLinux driver in a prioritised way. As soon as I finish this layer I will release a new REDD version.

Does the RTLinux driver handle more than one Ethernet card at the same time?

No, an RTLinux driver handles only one Ethernet card, the one located nearer in the PCI bus.

I have two Ethernet cards of the same model: eth0 and eth1. Can I use the Linux driver for eth0 and the RTLinux one for eth1 or viceversa?

You cannot assign eth0 to Linux and eth1 to RTLinux, becase the RTLinux driver will try to manage the eth0 Ethernet card and your machine will be hanged. Assigning eth0 to RTLinux and eth1 to Linux may work, but I've never tested it. Let me know if it works.

When inserting the RTLinux driver the kernel shouts "Unresolved symbols" and something about "rtl_malloc" or whatever. What's happening?

The REDD project depends on a real-time dynamic memory allocator called TLSF to manage the drivers' buffers. Go to the requirements section to know more about it.

How do I install TLSF in RTLinux?

The TLSF tarball provided in the download section is the latest version of TLSF ready to run in RTLinux. Compile the sources and a module called "rtl_malloc.o" will be generated. This module is ready to be inserted in the kernel by means of insmod. Nothing else has to be done.

About bigphysarea... I have to apply two patches to the Linux kernel: the bigphysarea patch and the RTLinux one. Which one do I apply first?

Apply the bigphysarea patch and then the RTLinux one. Remember to check the "Support for big physical area reservation" option in the "Processor type and features" menu when compiling the Linux kernel.

After patching the kernel and compiling, users must add a line in the lilo.conf file like the next:


How do I know if bigphysarea is installed properly?


After adding this line and rebooting, to see if bigphysarea is properly installed run:

$cat /proc/bigphysarea

You should see something like this:

Big physical area, size 16384 kB
free list: used list:
number of blocks: 1 0
size of largest block: 16384 kB 0 kB
total: 16384 kB 0 kB

Or executing:

$cat /proc/ksysms | grep bigphys

You'll see something like:

c012e8c8 bigphysarea_alloc
c012e8e8 bigphysarea_free
c012e698 bigphysarea_alloc_pages
c012e814 bigphysarea_free_pages

How do I access the driver? I mean, what's the interface it provides?

The API provided by the drivers is described in the section called The API: Special Features.

Last updated: 2004/12/03 11:20 $ (GMT+1)


[03/12/04] REDD-0.4 released!!
Lots of changes!!!.
Read the changelog.
Download it here.

Archived news.

RTL-lwIP project
RTL-EtherbootD project
Etherboot project
RT-Portal UPV

Interoperable Web Page

Valid HTML 4.01!

Valid CSS!

The development of this web page and the work it contains has been supported under the Spanish grant TIC2002-04123-C03-03: Reliable Distributed Embedded Real-Time Systems based on Components (TRECOM).
Webmaster and project maintainer: Sergio Pérez Alcañiz (serpeal_AT_upvnet_DOT_upv_DOT_es)