Chapter 162. lwIP Direct Ethernet Device Driver

162.1. Introduction

This chapter provides a simple description of the basic requirements for a low-level, hardware specific, lwIP-direct ethernet driver.

Using a lwIP-direct driver provides benefits in performance and smaller code- and memory-footprints. It also allows for the potential for zero-copy UDP support and reduced (single) copy TCP support depending on the hardware available. The main disadvantage over the standard ethernet driver world is the lack of RedBoot network debugging support.

The high-level driver implemented by this package (which is only code, without state of its own) is used to provide a common interface for lwIP to either a lwIP-specific direct driver (as described in this chapter), or via a wrapper interface to a standard generic ethernet driver (covered by Section 161.1, “Generic Ethernet API”).

Unlike the generic ethernet (standard) device driver support the lwIP device driver interface uses a fixed namespace between the lwIP and driver layers. Normally only a single driver instance exists for a lwIP configured world, so the use of a fixed namespace is, in reality, not an issue since lwIP is designed for lightweight, low resource, deeply-embedded systems. If a target platform really does provide more than one distinct ethernet hardware implementation, requiring completely different hardware drivers, then a wrapper layer conforming to the “direct” driver interface is provided when the option CYGFUN_IO_ETH_DRIVERS_LWIP_DRIVER_DIRECT_MULTI is configured. This implements a per-driver descriptor interface between the individual low-level hardware interfaces for the platform and this common Ethernet I/O package.

Normally a direct driver implementation will also provide a driver specific header file which is referenced from the lwIP CDL option CYGBLD_LWIP_HW_DRIVER_OVERRIDE_HEADER. The CDL covering the direct driver package should explicitly set the value to the required header file name. Similarly when support is configured for multiple direct drivers, the CDL option CYGBLD_LWIP_VARIANT_OVERRIDE_HEADER can be used to reference a header providing any needed platform/variant/driver specific features.

These header files can be used to provide access to prototypes and manifests needed to support specific lwIP features as required. For example, if the hardware driver uses DMA, and requires timely support for re-using PBUFs once lwIP has finished processing them, then the ECOS_LWIP_PBUF_POOL_FREE_HOOK manifest can be defined to reference a callback function (See DRV_HDWR_pbuf_pool_free_hook()).

The following sections give an overview of the small set of functions that the driver needs to provide to be usable by this package. When the multiple direct driver support is being used then these named functions are provided by this common CYGPKG_IO_ETH_DRIVERS I/O Ethernet package, with a per-driver descriptor structure used to reference the specific driver implementations (See Section 162.3, “Multiple direct drivers”).

162.2. API reference

The following function definitions document the namespace used by the eCos lwIP TCP/IP stack to interact with hardware drivers.

162.3. Multiple direct drivers

When support for multiple direct drivers is configured then a driver instance is contained within a cyg_lwip_eth_t structure:

typedef struct cyg_lwip_eth {
  const char *name; // NUL terminated ASCII human-readable name
  void (*init)(struct cyg_lwip_eth *drvdesc);
  void (*run_deliveries)(void *instance);
  err_t (*ll_output)(struct netif *netif,struct pbuf *p);
  int (*pbuf_free_hook)(void *instance,struct pbuf *p);
  void (*phy_event)(struct netif *netif);
  int (*ioctl)(struct netif *netif,unsigned long key,void *data,int data_length);
  void *instance;
  cyg_uint32 flags;
} CYG_HAL_TABLE_TYPE cyg_lwip_eth_t;

This CYGPKG_IO_ETH_DRIVERS package will implement the wrapper namespace to support lwIP, calling the relevant individual device driver registered functions as required.

You create an instance of cyg_lwip_eth_t using the CYG_LWIP_DRIVER macro, which sets up the structure. Using this macro ensures that if the internal design changes then existing source will fail to compile until updated to reflect the changed functionality. This is better than having definitions within the low-level drivers themselves, with the possibility of them building successfully but then failing at run-time.

The individual hardware drivers are initialised automatically via the wrapper provided cyg_lwip_eth_ecos_init() function, which iterates over the __LWIPDEVTAB__ vector containing the driver instance descriptors as required.


When lwIP direct drivers are written to support CYGFUN_IO_ETH_DRIVERS_LWIP_DRIVER_DIRECT_MULTI configurations they MUST reference their cyg_lwip_eth_t descriptor via the state field of the struct netif describing the lwIP network interface. The instance field of the cyg_lwip_eth_t can be used to hold driver specific instance data.

The function pointers referenced from the cyg_lwip_eth_t descriptor closely match the raw namespace, with the exception that initialisation is passed the cyg_lwip_eth_t driver descriptor pointer, and the run_deliveries and pbuf_free_hook implementations are passed the private instance pointer. This ensures that the individual driver implementation can access the necessary state as would be the case for a single driver configuration.


For the pbuf_free_hook support we should ideally pass the pbuf back to the original driver instance that allocated that specific pbuf. However, for the moment, the code just offers the pbuf to each configured driver in turn (the alternative would introduce complexity into the driver model for minimal gains).

This “do you want this pbuf” approach does not affect the behaviour, only the performance, of the driver when used in a multi-driver configuration. If the developer needs to ensure that a particular driver instance is “higher priority” than other lwIP Ethernet drivers for pbuf re-use then they should enforce a mechanism for ensuring the ordering of the __LWIPDEVTAB__device table.