| This file documents the driver changes needed to support use as part |
| of a PXE stack. |
| |
| PROPER WAY |
| ========== |
| |
| 1. The probe() routine. |
| |
| There are three additional fields that need to be filled in the nic |
| structure: ioaddr, irqno and irq. |
| |
| ioaddr is the base I/O address and seems to be for information only; |
| no use will be made of this value other than displaying it on the |
| screen. |
| |
| irqno must be the IRQ number for the NIC. For PCI NICs this can |
| simply be copied from pci->irq. |
| |
| irq is a function pointer, like poll and transmit. It must point to |
| the driver's irq() function. |
| |
| 2. The poll() routine. |
| |
| This must take an additional parameter: "int retrieve". Calling |
| poll() with retrieve!=0 should function exactly as before. Calling |
| poll() with retrieve==0 indicates that poll() should check for the |
| presence of a packet to read, but must *not* read the packet. The |
| packet will be read by a subsequent call to poll() with retrieve!=0. |
| |
| The easiest way to implement this is to insert the line |
| if ( ! retrieve ) return 1; |
| between the "is there a packet ready" and the "fetch packet" parts of |
| the existing poll() routine. |
| |
| Care must be taken that a call to poll() with retrieve==0 does not |
| clear the NIC's "packet ready" status indicator, otherwise the |
| subsequent call to poll() with retrieve!=0 will fail because it will |
| think that there is no packet to read. |
| |
| poll() should also acknowledge and clear the NIC's "packet received" |
| interrupt. It does not need to worry about enabling/disabling |
| interrupts; this is taken care of by calls to the driver's irq() |
| routine. |
| |
| Etherboot will forcibly regenerate an interrupt if a packet remains |
| pending after all interrupts have been acknowledged. You can |
| therefore get away with having poll() just acknolwedge and clear all |
| NIC interrupts, without particularly worrying about exactly when this |
| should be done. |
| |
| 3. The irq() routine. |
| |
| This is a new routine, with prototype |
| void DRIVER_irq ( struct nic *nic, irq_action_t action ); |
| "action" takes one of three possible values: ENABLE, DISABLE or FORCE. |
| ENABLE and DISABLE mean to enable/disable the NIC's "packet received" |
| interrupt. FORCE means that the NIC should be forced to generate a |
| fake "packet received" interrupt. |
| |
| If you are unable to implement FORCE, your NIC will not work when |
| being driven via the UNDI interface under heavy network traffic |
| conditions. Since Etherboot's UNDI driver (make bin/undi.zpxe) is the |
| only program known to use this interface, it probably doesn't really |
| matter. |
| |
| |
| QUICK AND DIRTY WAY |
| =================== |
| |
| It is possible to use the system timer interrupt (IRQ 0) rather than a |
| genuine NIC interrupt. Since there is a constant stream of timer |
| interrupts, the net upshot is a whole load of spurious "NIC" |
| interrupts that have no effect other than to cause unnecessary PXE API |
| calls. It's inefficient but it works. |
| |
| To achieve this, simply set nic->irqno=0 in probe() and point nic->irq |
| to a dummy routine that does nothing. Add the line |
| if ( ! retrieve ) return 1; |
| at the beginning of poll(), to prevent the packet being read (and |
| discarded) when poll() is called with retrieve==0; |
| |
| |
| UNCONVERTED DRIVERS |
| =================== |
| |
| Drivers that have not yet been converted should continue to function |
| when not used as part of a PXE stack, although there will be a |
| harmless compile-time warning about assignment from an incompatible |
| pointer type in the probe() function, since the prototype for the |
| poll() function is missing the "int retrieve" parameter. |