January 12, 2026

Kyu - network - structure of the H5 emac driver

It might seem premature to talk about the H5 driver, since it doesn't quite exist yet. What I actually will talk about is the structure of the H3 driver, which I plan to get into shape to be shared by both the H3 and H5 chip.

External interfaces

There aren't many. We initialize the driver, and from that point on interrupts and "send" requests are the only things that cause driver code to run.

emac_init () - This does the bulk of hardware initialization, but does not yet make the interface active.

emac_activate () - This enables interrupts and calls the "start" routine for both Rx and Tx

emac_show () - This is called by the Kyu "n 1" command to show a brief summary of statistics. It shows the interrupt count and the number of Tx and Rx packets.

emac_debug () - This is run by a different Kyu "n" command and give a lot more that "n 1". It shows the Rx and Tx rings.

get_emac_addr () - This provides the MAC address for the network stack.

emac_send () - This gives the driver a packet to be added to the Tx ring and ultimately to be transmitted.

When a packet has been received, the driver calls net_rcv(). This call is made at interrupt level, so the network code does the least possible amount of work, adding the packet to a queue.

Internal interfaces

emac_handler() - This chips assigns just one interrupt to the network interface. This handler reads a device register to discover the cause of the interrupt, and calls rx_handler() or tx_handler() accordingly.

The most important internal datastructures are the Rx and Tx buffer rings (rx_list and tx_list).

PHY (mdio) interface

At this time I am being extremely lazy and doing more or less nothing here. We just inherit the PHY setup from U-Boot, and that seems to work fine. Someday writing my own code for this (and the necessary PHY drivers) will make a good project.

Initialization

Calls are made from h5/board.c.

The routine board_net_init() calls emac_init().
The routine board_net_activate() calls emac_activate().

Both of these calls are made from net_hw_init() in net/net_main.c and the activate call immediately follows the init call. (So there is really no need for them to be separated).


Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org