====== Differences ====== This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
soc:2008:mdeck:notes:gpxe_driver_api [2008/05/23 06:59]
mdc created
soc:2008:mdeck:notes:gpxe_driver_api [2009/11/03 08:58] (current)
meteger
Line 1: Line 1:
 ====== gPXE Driver API Documentation ====== ====== gPXE Driver API Documentation ======
 +A gPXE network driver may incorporate elements of the following:
 +  * [[#​gpxe_pci_device_driver_api|gPXE PCI Device Driver API]]
 +  * [[#​gpxe_network_driver_api|gPXE Network Driver API]]
 +  * [[#​non-volatile_storage_api|Non-Volatile Storage API]]
  
 +Note the [[:​dev:​netdriverapi|previous driver model]] of Etherboot is deprecated.
 +Existing Etherboot PCI drivers are temporarily supported via the compatibility layer in src/​drivers/​net/​legacy.c
 +Drivers currently conforming to the gPXE Network Driver API are:
 +  * 3c90x
 +  * ath5k
 +  * atl1e
 +  * b44
 +  * e1000
 +  * etherfabric
 +  * mtnic
 +  * natsemi
 +  * phantom
 +  * pnic
 +  * r8169
 +  * rtl8139
 +  * rtl818x
 +  * sis190
 +  * sky2
  
  
 +===== gPXE PCI Device Driver API =====
 +A PCI driver provides its API routines to gPXE via a ''​struct pci_driver''​. ​ For example, in natsemi.c:
 +<code c>
 +struct pci_driver natsemi_driver __pci_driver = {
 + .ids = natsemi_nics,​
 + .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),​
 + .probe = natsemi_probe,​
 + .remove = natsemi_remove,​
 +};
 +</​code>​
 +The ''​.ids''​ and ''​.id_count''​ members list the vendor & device IDs of supported devices. ​
 +The functions natsemi_probe & natsemi_remove are driver implementations of the required PCI device driver API functions: ​
 +  * ''​[[#​probe|static int probe ( struct pci_device* , const struct pci_device_id* )]]''​
 +  * ''​[[#​remove|static void remove ( struct pci_device* )]]''​
 +
 +==== probe ====
 +''​static int probe ( struct pci_device* , const struct pci_device_id* )''​\\
 +This function is called [[:​soc:​2008:​mdeck:​notes:​initialization|first]] to initialize the card.  Here a typical network driver will:
 +  - Allocate a ''​struct net_device''​ with associated private data using ''​alloc_etherdev()''​.
 +  - Associate the driver functions with the ''​net_device''​ via ''​netdev_init()''​.
 +  - Associate the ''​net_device''​ with the ''​pci_device''​ via ''​pci_set_drvdata()''​.
 +  - Initialize private data.
 +  - Ensure busmastering is enabled and check pci latency with ''​adjust_pci_device()''​.
 +  - Reset the device.
 +  - Initialize [[#​EEPROM|EEPROM]].
 +  - Read the MAC address from EEPROM.
 +  - Check the link state and report ''​netdev_link_up()''​ if connected. ​ Many drivers don't yet handle the link state and simply assume the link is up.
 +  - Name the device and add it to the list of network devices via ''​register_netdev()''​.
 +  - Possibly setup a non-volatile stored options block with ''​nvo_init()''​ & ''​register_nvo()''​.
 +
 +==== remove ====
 +''​static void remove ( struct pci_device* )''​\\
 +This function is called last to remove the device. ​ A typical driver will:
 +  - Call ''​unregister_nvo()''​ for any registered non-volatile stored options.
 +  - Call ''​iounmap()''​ for any addresses previously mapped with ''​ioremap()''​.
 +  - Call ''​unregister_netdev()''​ for the device previously registered with ''​register_netdev()''​
 +  - Reset the device.
 +  - Dissociate driver functions from ''​net_device''​ via ''​netdev_nullify()''​.
 +  - Decrement reference count of ''​net_device''​ with ''​netdev_put()''​.
 +
 +
 +
 +===== gPXE Network Driver API =====
 +A network driver in gPXE provides its API routines to the system via a ''​struct net_device_operations''​ during the initial ''​probe()''​ call
 +(see [[:​soc:​2008:​mdeck:​notes:​initialization|initialization of a network driver]]). ​ For example, in natsemi.c:
 +<code c>
 +static struct net_device_operations natsemi_operations = {
 +        .open           = natsemi_open,​
 +        .close ​         = natsemi_close,​
 +        .transmit ​      = natsemi_transmit,​
 +        .poll           = natsemi_poll,​
 + .irq = natsemi_irq,​
 +};
 +</​code>​
 +Here, natsemi_open/​close/​etc are driver implementations of the required network driver API functions: ​
 +  * ''​[[#​close|static void close ( struct net_device* )]]''​
 +  * ''​[[#​open|static int open ( struct net_device* )]]''​
 +  * ''​[[#​transmit|static int transmit ( struct net_device*,​ struct io_buffer* )]]''​
 +  * ''​[[#​poll|static void poll ( struct net_device* )]]''​
 +  * ''​[[#​irq|static void irq ( struct net_device*,​ int enable )]]''​
 +
 +==== close ====
 +''​static void close ( struct net_device* )''​\\
 +This function is called if the device is open in ''​autoboot()''​ during [[:​soc:​2008:​mdeck:​notes:​initialization|initialization]],​ after a failed or successful attempt to boot the network device. ​ In this routine, a typical driver might:
 +  - Acknowledge interrupts.
 +  - Disable irq, receives.
 +  - Reset the device.
 +  - Free any used resources (e.g. rx/tx rings, dma buffers, etc).
 +
 +==== open ====
 +''​static int open ( struct net_device* )''​\\
 +This function is first called in ''​netboot()''​ when attempting a device boot during [[:​soc:​2008:​mdeck:​notes:​initialization|initialization]],​ after ''​close()''​ of any previous device attempt is called. ​ A driver would:
 +  - Program MAC address to device.
 +  - Setup TX & RX rings.
 +  - Perform other configuration (e.g. filters, bursts, interrupts).
 +  - Enable RX and TX.
 +
 +==== transmit ====
 +''​static int transmit ( struct net_device*,​ struct io_buffer* )''​\\
 +A data transmission is actuated with this routine. ​ A typical driver might:
 +  - Check for tx overflow.
 +  - Save buffer pointer for later tx completion reference.
 +  - Pad & align packet if necessary.
 +  - Add packet to transmit ring.
 +  - Possibly ensure transmit is on.
 +
 +==== poll ====
 +''​static void poll ( struct net_device* )''​\\
 +This function is called periodically by the network stack to process tx completions and rx packets. ​ A typical driver would:
 +  - Acknowledge interrupts.
 +  - Check hardware and feed tx completions to ''​netdev_tx_complete()''​ or ''​netdev_tx_complete_err()''​.
 +  - Add good received packets to receive queue with ''​netdev_rx()'',​ or report corrupted packets to ''​netdev_rx_err()''​
 +  - Check link state occasionally,​ and report changes with ''​netdev_link_up()''​ or ''​netdev_link_down()''​
 +
 +==== irq ====
 +''​static void irq ( struct net_device*,​ int enable )''​\\
 +In this function, a typical driver will:
 +  - Enable interrupts if the int parameter is non-zero
 +Note the //force interrupt// behavior from Etherboot is deprecated.
 +
 +
 +
 +===== Non-Volatile Storage API =====
 +The nvs API may be used to access non-volatile storage that conforms to a number of supported SPI variants.
 +  * To initialize nvs support:
 +    - The read_bit() and write_bit() function pointers are stored in a ''​struct spi_bit_basher''​.
 +    - The mode & endianness are also initialized.
 +    - ''​init_spi_bit_basher()''​ is called.
 +    - A ''​struct spi_device''​ is initialized (EEPROM-model dependent).
 +    - Bus is copied: ''​spidev.bus = &​spibb.bus''​
 +    - If non-volatile options will be utilized:
 +      - Call ''​nvo_init(&​nvob,​ &​spidev.nvs,​ nvof, ..)''​ where ''​nvof''​ is an array of ''​struct nvo_fragment''​s that specify the usable regions. ​ This will also initialize a settings block. ​
 +    - Else, if non-volatile options will //not// be used:
 +      - Initialize a ''​struct nvo_block''​ with ''​nvob.nvs = &​spidev.nvs''​
 +      - Assign usable regions via ''​nvob.fragments = nvof''​ where ''​nvof''​ is an array of ''​struct nvo_fragment''​s that specify the usable regions.
 +  * Use ''​nvs_read()''​ to perform a serial read @ a specific address.
 +  * Use ''​nvs_write()''​ to perform a serial write @ a specific address.

QR Code
QR Code soc:2008:mdeck:notes:gpxe_driver_api (generated for current page)