SMSC LAN9118 Ethernet Driver

Name

CYGPKG_DEVS_ETH_SMSC_LAN9118 -- eCos Support for SMSC LAN9118 Ethernet Devices

Description

The SMSC LAN9118 chip is a high performance single chip ethernet controller which can be interfaced to a variety of embedded processors. This package provides an eCos driver for that device. The driver supports both polled mode for use by RedBoot and interrupt-driven mode for use by a full TCP/IP stack.

The exact interface between the LAN9118 chip and the main processor is determined by the platform HAL. On some platforms there may even be multiple LAN9118 chips. This package only provides the platform-independent code. It is up to the platform HAL to instantiate one or more device instances and to provide information such as the base address and interrupt vector. There is also no explicit support for features like auto-negotiation or advanced flow control. These are left to the platform HAL or to the application, although usually the default settings will be acceptable for most applications.

Configuration Options

This package should be loaded automatically when selecting a target equipped with a LAN9118 ethernet chip. and it should never be necessary to load it explicitly. If the application does not actually require ethernet functionality then the package is inactive and the final executable will not suffer any overheads from unused functionality. This is determined by the presence of the generic ethernet I/O package CYGPKG_IO_ETH_DRIVERS. Typically the choice of eCos template causes the right thing to happen. For example the default template does not include any TCP/IP stack so CYGPKG_IO_ETH_DRIVERS is not included, but both the net and redboot templates do include a TCP/IP stack so will specify that package and hence enable the ethernet driver.

Optionally the ethernet driver can maintain statistics about the number of incoming and transmitted ethernet frames, receive overruns, collisions, and other conditions. Maintaining and providing these statistics involves some overhead, and is controlled by the configuration option CYGFUN_DEVS_ETH_SMSC_LAN9118_STATISTICS. Typically these statistics are only accessed through SNMP, so by default statistics gathering is enabled if the configuration includes CYGPKG_SNMPAGENT and disabled otherwise.

Porting the Driver to New Hardware

It is the responsibility of the platform HAL to instantiate one or more devices, depending on the number of LAN9118 chips present. Typically this involves a separate file in the platform HAL sources:

#include <cyg/io/lan9118.h>

LAN9118_INSTANCE(alaia, 0, "eth0", alaia_eth_init);

static bool
alaia_eth_init(struct cyg_netdevtab_entry* tab)
{
    …

    return cyg_lan9118_eth_init(tab);
}
    

The first two arguments to the LAN9118_INSTANCE macro identify the platform and the device instance, and are used to construct unique variable names. The third argument gives the device name, and the final argument is a platform-specific initialization function. The platform HAL should also contain suitable CDL to build this file:


    cdl_component CYGHWR_HAL_ALAIA_ETH {
	display		"External ethernet support"
	parent		CYGPKG_IO_ETH_DRIVERS
	flavor		none
	active_if	CYGPKG_IO_ETH_DRIVERS
	implements 	CYGNUM_DEVS_ETH_SMSC_LAN9118_COUNT
	compile		-library=libextras.a alaia_eth.c
	description "
            The Alaia board comes with a single LAN9118 ethernet device."

        cdl_option CYGNUM_HAL_ALAIA_ETH_ISR_PRIORITY {
            …
        }
        …
    }
    

If the configuration does not include the generic ethernet support then this component will be inactive. Otherwise the file alaia_eth.c will get built into libextras.a, ensuring the device instance does not get eliminated by linker garbage collection. The interface CYGNUM_DEVS_ETH_SMSC_LAN9118_COUNT should be implemented once per LAN9118 chip. If additional configuration options are needed, for example to control the MAC address or the interrupt priority, then these can go inside the component.

The driver needs to know where to access the device. If there is a single LAN9118 chip then the required information can be supplied via #define's in the plf_io.h header:

#define HAL_LAN9118_BASE            0xBA000000
#define HAL_LAN9118_ISRVEC          CYGNUM_HAL_ISR_LAN9118
#define HAL_LAN9118_ISRPRI          CYGNUM_HAL_ALAIA_ETH_ISR_PRIORITY
    

Otherwise the platform-specific initialization function should put this information in fields in the LAN9118 instance structure:

static bool
alaia_eth_init(struct cyg_netdevtab_entry* tab)
{
    LAN9118_INSTANCE_NAME(alaia, 0).lan9118_base   = 0xBA000000;
    LAN9118_INSTANCE_NAME(alaia, 0).lan9118_isrvec = CYGNUM_HAL_ISR_PIO4;
    LAN9118_INSTANCE_NAME(alaia, 0).lan9118_isrpri = 1;
    LAN9118_INSTANCE_NAME(alaia, 1).lan9118_base   = 0xBB000000;
    LAN9118_INSTANCE_NAME(alaia, 1).lan9118_isrvec = CYGNUM_HAL_ISR_PIO5;
    LAN9118_INSTANCE_NAME(alaia, 1).lan9118_isrpri = 1;
    …
    return cyg_lan9118_eth_init(tab);
}
    

The initialization function should ensure that the processor's bus interface is set up correctly for talking to the ethernet chip, and that the interrupt vector has been configured correctly for level vs. edge interrupts. This must happen before calling the driver init function. Also the lan9118_hw_flags should be set correctly as per the flags in lan9118.h, for example:

static bool
alaia_eth_init(struct cyg_netdevtab_entry* tab)
{
    …
    LAN9118_INSTANCE_NAME(alaia, 0).lan9118_hw_flags  =
        (LAN9118_HW_FLAGS_IRQ_POL_ACTIVE_HIGH    |
         LAN9118_HW_FLAGS_IRQ_PUSH_PULL          |
         LAN9118_HW_FLAGS_HAS_LED1               |
         LAN9118_HW_FLAGS_HAS_LED2);
    …
    return cyg_lan9118_eth_init(tab);
}
    

The LAN9118 can be accessed via either a 16-bit or 32-bit bus, and from big-endian or little-endian processors. This gives a number of combinations. The chip is inherently little-endian, so on a little-endian processor there should be no problems. On a big-endian processor there are two possibilities. If the LAN9118 is interfaced in the obvious way then it will be necessary to swap the data of all incoming and outgoing packets, which imposes a significant performance penalty. On a 16-bit bus the LAN9118_HW_FLAGS_16BIT_BE flag should be set. Alternatively the bytes on the bus can be swapped, either by the hardware or by programming the processor's bus interface. This means no swapping is needed for data, but all accesses to the LAN9118's command and status registers need swapping instead. However most of that swapping can be done at compile-time so has no overhead. Defining HAL_LAN9118_SWAP_COMMANDS in plf_io.h sets up this mode. If there are multiple ethernet chips then the driver assumes they are all wired the same way. For further details consult the driver's source code.

All ethernet devices require a unique MAC address. Ideally this will be provided by a serial EEPROM or similar, and if such a device is present and attached to the LAN9118 then it will be used automatically by the ethernet chip to set the MAC address. If the platform does not have a suitable EEPROM then the MAC address must come from elsewhere, for example a RedBoot fconfig option, and the platform-specific initialization function should fill in the instance's lan9118_mac field.

2017-02-09
Documentation license for this page: eCosPro License