Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
soc:2008:mdeck:notes:gpxe_driver_api [2008/05/28 16:54]
mdeck
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 ======
-The current ​gPXE driver ​model differs from the previous Etherboot ​API.+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]]
  
-Drivers currently conforming to gPXE are:+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   * e1000
 +  * etherfabric
 +  * mtnic
   * natsemi   * natsemi
 +  * phantom
 +  * pnic
 +  * r8169
   * rtl8139   * rtl8139
 +  * rtl818x
 +  * sis190
 +  * sky2
  
-The gPXE driver API is detailed in this document. ​ Study of the [[:​soc:​2008:​mdeck:​notes:​initialization|initialization of a network driver]] may also prove fruitful. + 
-===== Driver ​Exported Functions ​===== +===== gPXE PCI Device ​Driver ​API ===== 
-The following ​functions are defined in a gPXE network ​driver:+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* )]]''​   * ''​[[#​probe|static int probe ( struct pci_device* , const struct pci_device_id* )]]''​
   * ''​[[#​remove|static void remove ( struct pci_device* )]]''​   * ''​[[#​remove|static void remove ( struct pci_device* )]]''​
-  * ''​[[#​reset|static void reset ( struct net_device* )]]''​ 
-  * ''​[[#​open|static int open ( struct net_device* )]]''​ 
-  * ''​[[#​close|static void close ( 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 )]]''​ 
  
-In addition, a PCI network driver defines a ''​struct pci_driver'':​ 
-  * ''​.ids = ''​ an array of ''​struct pci_device_id''​s 
-  * ''​.id_count = ''​ array count 
-  * ''​.probe = ''​ the driver ''​probe''​ function 
-  * ''​.remove = ''​ the driver ''​remove''​ function 
 ==== probe ==== ==== probe ====
 ''​static int probe ( struct pci_device* , const struct pci_device_id* )''​\\ ''​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 driver will:+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()''​.   - 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 driver functions with the ''​net_device''​ via ''​netdev_init()''​.
Line 35: Line 51:
   - Initialize [[#​EEPROM|EEPROM]].   - Initialize [[#​EEPROM|EEPROM]].
   - Read the MAC address from EEPROM.   - Read the MAC address from EEPROM.
-  - Mark the ''​net_device''​ as having a link up with ''​netdev_link_up()''​, as we don't yet handle the link state.+  - 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()''​.   - 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()''​.   - Possibly setup a non-volatile stored options block with ''​nvo_init()''​ & ''​register_nvo()''​.
Line 49: Line 65:
   - Decrement reference count of ''​net_device''​ with ''​netdev_put()''​.   - Decrement reference count of ''​net_device''​ with ''​netdev_put()''​.
  
-==== reset ==== 
-''​static void reset ( struct net_device* )''​\\ 
-This function issues a hardware reset and waits for completion. ​ A typical driver might: 
-  - Mask off interrupts. 
-  - Clear pending transmits. 
-  - Trigger hardware reset. 
-  - Wait for completion. 
  
-==== open ==== + 
-''​static int open ( struct ​net_device* )''​\\ +===== gPXE Network Driver API ===== 
-This function is called after ''​probe()'' ​during ​[[:​soc:​2008:​mdeck:​notes:​initialization|initialization]].  ​A driver would+A network driver in gPXE provides its API routines to the system via a ''​struct ​net_device_operations'' ​during the initial ​''​probe()'' ​call 
-  - Program MAC address to device+(see [[:​soc:​2008:​mdeck:​notes:​initialization|initialization ​of a network driver]]).  ​For example, in natsemi.c
-  - Setup TX & RX rings+<code c> 
-  - Perform other configuration (e.gfiltersburstsinterrupts). +static struct net_device_operations natsemi_operations = { 
-  ​- Enable RX and TX.+        ​.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 ==== ==== close ====
 ''​static void close ( struct net_device* )''​\\ ''​static void close ( struct net_device* )''​\\
-In this function, a typical driver might:+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.   - Acknowledge interrupts.
   - Disable irq, receives.   - Disable irq, receives.
   - Reset the device.   - Reset the device.
   - Free any used resources (e.g. rx/tx rings, dma buffers, etc).   - 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 ==== ==== transmit ====
Line 84: Line 113:
 ==== poll ==== ==== poll ====
 ''​static void poll ( struct net_device* )''​\\ ''​static void poll ( struct net_device* )''​\\
-This function is called periodically to process tx completions and rx packets. ​ A typical driver would:+This function is called periodically ​by the network stack to process tx completions and rx packets. ​ A typical driver would:
   - Acknowledge interrupts.   - Acknowledge interrupts.
-  - Feed tx completions to ''​netdev_tx_complete()''​ or ''​netdev_tx_complete_err()''​. +  - 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 feed corrupted packets to ''​netdev_rx_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 ==== ==== irq ====
Line 93: Line 123:
 In this function, a typical driver will: In this function, a typical driver will:
   - Enable interrupts if the int parameter is non-zero   - Enable interrupts if the int parameter is non-zero
 +Note the //force interrupt// behavior from Etherboot is deprecated.
 +
 +
  
-===== EEPROM ===== +===== Non-Volatile Storage API ===== 
-The EEPROM can be accessed via direct port access or using nvs functions. +The nvs API may be used to access non-volatile storage that conforms to a number of supported SPI variants.
-==== Non-volatile storage (nvs) ==== +
-The nvs functions ​may be used to access non-volatile storage that conforms to a number of supported SPI protocols.+
   * To initialize nvs support:   * To initialize nvs support:
     - The read_bit() and write_bit() function pointers are stored in a ''​struct spi_bit_basher''​.     - The read_bit() and write_bit() function pointers are stored in a ''​struct spi_bit_basher''​.
Line 104: Line 135:
     - A ''​struct spi_device''​ is initialized (EEPROM-model dependent).     - A ''​struct spi_device''​ is initialized (EEPROM-model dependent).
     - Bus is copied: ''​spidev.bus = &​spibb.bus''​     - Bus is copied: ''​spidev.bus = &​spibb.bus''​
-    - EITHER+    - 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''​       - 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.       - Assign usable regions via ''​nvob.fragments = nvof''​ where ''​nvof''​ is an array of ''​struct nvo_fragment''​s that specify the usable regions.
-    - OR 
-      - Call ''​nvo_init(&​nvob,​ &​spidev.nvs,​ 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_read()''​ to perform a serial read @ a specific address.
   * Use ''​nvs_write()''​ to perform a serial write @ 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)