60#define EINFO_EPXECALL \
61 __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
62 "External PXE API error" )
63#define EPXECALL( status ) EPLATFORM ( EINFO_EPXECALL, status )
71#define UNDI_HACK_EB54 0x0001
76#define UNDI_INITIALIZE_RETRY_MAX 10
79#define UNDI_INITIALIZE_RETRY_DELAY_MS 200
82#define UNDI_RX_QUOTA 4
85#define UNDI_RX_ALIGN 16
96#define undinet_params __use_data16 ( undinet_params )
105#define undinet_entry_point __use_data16 ( undinet_entry_point )
109#define RDTSC_IF_PROFILING "rdtsc\n\t"
111#define RDTSC_IF_PROFILING ""
116 { .name =
"undinet.irq" };
120 { .name =
"undinet.rx" };
136 { .name =
"undinet.tx" },
137 { .name =
"undinet.tx_p2r" },
138 { .name =
"undinet.tx_ext" },
139 { .name =
"undinet.tx_r2p" },
149 { .name =
"undinet.isr" },
150 { .name =
"undinet.isr_p2r" },
151 { .name =
"undinet.isr_ext" },
152 { .name =
"undinet.isr_r2p" },
161 { .name =
"undinet.unknown" },
162 { .name =
"undinet.unknown_p2r" },
163 { .name =
"undinet.unknown_ext" },
164 { .name =
"undinet.unknown_r2p" },
169 { .name =
"undinet.misc" },
170 { .name =
"undinet.misc_p2r" },
171 { .name =
"undinet.misc_ext" },
172 { .name =
"undinet.misc_r2p" },
192 return "PXENV_START_UNDI";
194 return "PXENV_STOP_UNDI";
196 return "PXENV_UNDI_STARTUP";
198 return "PXENV_UNDI_CLEANUP";
200 return "PXENV_UNDI_INITIALIZE";
202 return "PXENV_UNDI_RESET_ADAPTER";
204 return "PXENV_UNDI_SHUTDOWN";
206 return "PXENV_UNDI_OPEN";
208 return "PXENV_UNDI_CLOSE";
210 return "PXENV_UNDI_TRANSMIT";
212 return "PXENV_UNDI_SET_MCAST_ADDRESS";
214 return "PXENV_UNDI_SET_STATION_ADDRESS";
216 return "PXENV_UNDI_SET_PACKET_FILTER";
218 return "PXENV_UNDI_GET_INFORMATION";
220 return "PXENV_UNDI_GET_STATISTICS";
222 return "PXENV_UNDI_CLEAR_STATISTICS";
224 return "PXENV_UNDI_INITIATE_DIAGS";
226 return "PXENV_UNDI_FORCE_INTERRUPT";
228 return "PXENV_UNDI_GET_MCAST_ADDRESS";
230 return "PXENV_UNDI_GET_NIC_TYPE";
232 return "PXENV_UNDI_GET_IFACE_INFO";
240 return "PXENV_UNDI_ISR";
242 return "PXENV_GET_CACHED_INFO";
244 return "UNKNOWN API CALL";
259 return &undinet_tx_profiler;
261 return &undinet_isr_profiler;
263 return &undinet_unknown_profiler;
265 return &undinet_misc_profiler;
279 void *params,
size_t params_len ) {
303 "lcall *undinet_entry_point\n\t"
304 "movw %%ax, %%bx\n\t"
309 :
"=a" ( stopped ),
"=d" (
started ),
334 SEGOFF16_t rm_params = {
339 DBGC ( undinic,
"UNDINIC %p %s failed: %s\n", undinic,
341 DBGC ( undinic,
"UNDINIC %p parameters at %04x:%04x length "
342 "%#02zx, entry point at %04x:%04x\n", undinic,
343 rm_params.segment, rm_params.offset, params_len,
346 DBGC ( undinic,
"UNDINIC %p parameters provided:\n", undinic );
347 DBGC_HDA ( undinic, rm_params, params, params_len );
348 DBGC ( undinic,
"UNDINIC %p parameters returned:\n", undinic );
374#define undiisr_irq __use_data16 ( undiisr_irq )
378#define undiisr_imr __use_data16 ( undiisr_imr )
382#define undiisr_bit __use_data16 ( undiisr_bit )
386#define undiisr_rearm __use_data16 ( undiisr_rearm )
390#define undiisr_next_handler __use_data16 ( undiisr_next_handler )
394#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
437 unsigned int this_trigger_count;
461#define undinet_tbd __use_data16 ( undinet_tbd )
465#define undinet_destaddr __use_data16 ( undinet_destaddr )
479 const void *ll_source;
503 &net_proto, &
flags ) ) != 0 ) {
504 DBGC ( undinic,
"UNDINIC %p could not strip Ethernet header: "
509 switch ( net_proto ) {
533 memset ( &undi_transmit, 0,
sizeof ( undi_transmit ) );
549 sizeof ( undi_transmit ) ) ) != 0 )
611 enable_irq ( undinic->
irq );
641 sizeof ( undi_isr ) ) ) != 0 ) {
656 if ( (
len == 0 ) || (
len < frag_len ) ) {
658 DBGC ( undinic,
"UNDINIC %p reported insane "
659 "fragment (%zd of %zd bytes)\n",
660 undinic, frag_len,
len );
667 DBGC ( undinic,
"UNDINIC %p could not "
668 "allocate %zd bytes for RX "
669 "buffer\n", undinic,
len );
677 if ( frag_len > max_frag_len ) {
678 DBGC ( undinic,
"UNDINIC %p fragment too big "
679 "(%zd+%zd does not fit into %zd)\n",
680 undinic,
iob_len ( iobuf ), frag_len,
681 (
iob_len ( iobuf ) + max_frag_len ) );
682 frag_len = max_frag_len;
685 undi_isr.
Frame.segment,
686 undi_isr.
Frame.offset, frag_len );
705 DBGC ( undinic,
"UNDINIC %p ISR returned invalid "
706 "FuncFlag %04x\n", undinic, undi_isr.
FuncFlag );
715 DBGC ( undinic,
"UNDINIC %p returned incomplete packet "
716 "(%zd of %zd)\n", undinic,
iob_len ( iobuf ),
735 if ( undinic->
irq ) {
737 enable_irq ( undinic->
irq );
749 &undi_set_address,
sizeof ( undi_set_address ) );
756 memset ( &undi_open, 0,
sizeof ( undi_open ) );
759 sizeof ( undi_open ) ) ) != 0 )
762 DBGC ( undinic,
"UNDINIC %p opened\n", undinic );
785 sizeof ( undi_isr ) ) ) != 0 )
801 sizeof ( undi_close ) );
804 if ( undinic->
irq ) {
805 disable_irq ( undinic->
irq );
809 DBGC ( undinic,
"UNDINIC %p closed\n", undinic );
822 DBGC ( undinic,
"UNDINIC %p cannot %s interrupts\n",
823 undinic, ( enable ?
"enable" :
"disable" ) );
902 DBGC ( undinic,
"UNDINIC %p %04x:%04x subsys "
903 "%04x:%04x has broken interrupts\n",
904 undinic,
desc->vendor,
desc->device,
905 subsys_vendor, subsys );
916 DBGC ( undinic,
"UNDINIC %p is PCI Express: assuming "
917 "interrupts are unreliable\n", undinic );
953 memset ( undinic, 0,
sizeof ( *undinic ) );
955 DBGC ( undinic,
"UNDINIC %p using UNDI %p\n", undinic, undi );
959 memset ( &start_undi, 0,
sizeof ( start_undi ) );
967 sizeof ( start_undi ) ) ) != 0 )
974 memset ( &undi_startup, 0,
sizeof ( undi_startup ) );
977 sizeof ( undi_startup ) ) ) != 0 )
978 goto err_undi_startup;
985 for ( retry = 0 ; ; ) {
986 memset ( &undi_init, 0,
sizeof ( undi_init ) );
990 sizeof ( undi_init ) ) ) ==0)
993 goto err_undi_initialize;
994 DBGC ( undinic,
"UNDINIC %p retrying "
995 "PXENV_UNDI_INITIALIZE (retry %d)\n",
1004 memset ( &undi_info, 0,
sizeof ( undi_info ) );
1006 &undi_info,
sizeof ( undi_info ) ) ) != 0 )
1007 goto err_undi_get_information;
1012 DBGC ( undinic,
"UNDINIC %p ignoring invalid IRQ %d\n",
1013 undinic, undinic->
irq );
1016 DBGC ( undinic,
"UNDINIC %p has MAC address %s and IRQ %d\n",
1018 if ( undinic->
irq ) {
1020 assert ( ! irq_enabled ( undinic->
irq ) );
1024 memset ( &undi_iface, 0,
sizeof ( undi_iface ) );
1026 &undi_iface,
sizeof ( undi_iface ) ) ) != 0 )
1027 goto err_undi_get_iface_info;
1028 DBGC ( undinic,
"UNDINIC %p has type %s, speed %d, flags %08x\n",
1032 ( undinic->
irq != 0 ) ) {
1035 DBGC ( undinic,
"UNDINIC %p using %s mode\n", undinic,
1038 sizeof ( undi_iface.
IfaceType ) ) == 0 ) {
1039 DBGC ( undinic,
"UNDINIC %p Etherboot 5.4 workaround enabled\n",
1044 DBGC ( undinic,
"UNDINIC %p forcing polling mode due to "
1045 "broken interrupts\n", undinic );
1056 DBGC ( undinic,
"UNDINIC %p added\n", undinic );
1060 err_undi_get_iface_info:
1061 err_undi_get_information:
1062 err_undi_initialize:
1064 memset ( &undi_shutdown, 0,
sizeof ( undi_shutdown ) );
1066 sizeof ( undi_shutdown ) );
1067 memset ( &undi_cleanup, 0,
sizeof ( undi_cleanup ) );
1069 sizeof ( undi_cleanup ) );
1073 memset ( &stop_undi, 0,
sizeof ( stop_undi ) );
1075 sizeof ( stop_undi ) );
1105 memset ( &undi_shutdown, 0,
sizeof ( undi_shutdown ) );
1107 &undi_shutdown,
sizeof ( undi_shutdown ) );
1108 memset ( &undi_cleanup, 0,
sizeof ( undi_cleanup ) );
1110 &undi_cleanup,
sizeof ( undi_cleanup ) );
1114 memset ( &stop_undi, 0,
sizeof ( stop_undi ) );
1116 sizeof ( stop_undi ) );
1127 DBGC ( undinic,
"UNDINIC %p removed\n", undinic );
#define NULL
NULL pointer (VOID *)
struct arbelprm_rc_send_wqe rc
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
#define assert(condition)
Assert a condition at run-time.
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
struct bofm_section_header done
#define BUS_TYPE_PCI
PCI bus type.
uint8_t function
Function.
struct ena_llq_option desc
Descriptor counts.
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
int eth_pull(struct net_device *netdev __unused, struct io_buffer *iobuf, const void **ll_dest, const void **ll_source, uint16_t *net_proto, unsigned int *flags)
Remove Ethernet link-layer header.
static struct net_device * netdev
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
#define EINVAL
Invalid argument.
#define ENOMEM
Not enough space.
#define PXENV_EXIT_SUCCESS
No error occurred.
UINT16_t PXENV_EXIT_t
A PXE exit code.
#define PXENV_GET_CACHED_INFO
PXE API function code for pxenv_get_cached_info()
#define PXENV_START_UNDI
PXE API function code for pxenv_start_undi()
#define PXENV_STOP_UNDI
PXE API function code for pxenv_stop_undi()
#define PXENV_UNDI_CLEANUP
PXE API function code for pxenv_undi_cleanup()
#define PXENV_UNDI_CLEAR_STATISTICS
PXE API function code for pxenv_undi_clear_statistics()
#define PXENV_UNDI_CLOSE
PXE API function code for pxenv_undi_close()
#define PXENV_UNDI_FORCE_INTERRUPT
PXE API function code for pxenv_undi_force_interrupt()
#define PXENV_UNDI_GET_IFACE_INFO
PXE API function code for pxenv_undi_get_iface_info()
#define SUPPORTED_IRQ
Interrupt Request supported.
#define PXENV_UNDI_GET_MCAST_ADDRESS
PXE API function code for pxenv_undi_get_mcast_address()
#define PXENV_UNDI_GET_NIC_TYPE
PXE API function code for pxenv_undi_get_nic_type()
#define PXENV_UNDI_GET_STATISTICS
PXE API function code for pxenv_undi_get_statistics()
#define PXENV_UNDI_INITIALIZE
PXE API function code for pxenv_undi_initialize()
#define PXENV_UNDI_INITIATE_DIAGS
PXE API function code for pxenv_undi_initiate_diags()
#define PXENV_UNDI_ISR_OUT_DONE
Finished processing interrupt.
#define PXENV_UNDI_ISR_IN_GET_NEXT
Continue processing interrupt.
#define PXENV_UNDI_ISR_OUT_RECEIVE
A packet has been received.
#define PXENV_UNDI_ISR
PXE API function code for pxenv_undi_isr()
#define PXENV_UNDI_ISR_OUT_TRANSMIT
A packet transmission has completed.
#define PXENV_UNDI_ISR_IN_PROCESS
Start processing interrupt.
#define FLTR_PRMSCS
Accept all packets; listen in promiscuous mode.
#define FLTR_BRDCST
Accept broadcast packets.
#define FLTR_DIRECTED
Accept "directed" packets.
#define PXENV_UNDI_OPEN
PXE API function code for pxenv_undi_open()
#define PXENV_UNDI_RESET_ADAPTER
PXE API function code for pxenv_undi_reset_adapter()
#define PXENV_UNDI_SET_MCAST_ADDRESS
PXE API function code for pxenv_undi_set_mcast_address()
#define PXENV_UNDI_SET_PACKET_FILTER
PXE API function code for pxenv_undi_set_packet_filter()
#define PXENV_UNDI_SET_STATION_ADDRESS
PXE API function code for pxenv_undi_set_station_address()
#define PXENV_UNDI_SHUTDOWN
PXE API function code for pxenv_undi_shutdown()
#define PXENV_UNDI_STARTUP
PXE API function code for pxenv_undi_startup()
#define P_RARP
RARP protocol.
#define PXENV_UNDI_TRANSMIT
PXE API function code for pxenv_undi_transmit()
#define XMT_DESTADDR
Unicast packet.
#define P_UNKNOWN
Media header already filled in.
#define XMT_BROADCAST
Broadcast packet.
#define P_ARP
ARP protocol.
#define UNDI_HACK_EB54
Work around Etherboot 5.4 bugs.
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
#define __profiler
Declare a profiler.
static void profile_stop_at(struct profiler *profiler, unsigned long stopped)
Stop profiling.
static void profile_stop(struct profiler *profiler)
Stop profiling.
static unsigned long profile_started(struct profiler *profiler)
Get start time.
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
static void profile_start(struct profiler *profiler)
Start profiling.
static unsigned long profile_stopped(struct profiler *profiler)
Get stop time.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
static int started
"startup() has been called" flag
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
#define iob_push(iobuf, len)
#define iob_put(iobuf, len)
#define iob_disown(iobuf)
Disown an I/O buffer.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
#define iob_reserve(iobuf, len)
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
#define __data16(variable)
#define REAL_CODE(asm_code_str)
#define __bss16(variable)
#define __data16_array(variable, array)
#define __from_data16(pointer)
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
void unregister_netdev(struct net_device *netdev)
Unregister network device.
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
int register_netdev(struct net_device *netdev)
Register network device.
Network device management.
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
#define LL_BROADCAST
Packet is a broadcast packet.
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
#define PCI_ANY_ID
Match-anything ID.
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
static void pci_init(struct pci_device *pci, unsigned int busdevfn)
Initialise PCI device.
#define PCI_CAP_ID_EXP
PCI Express.
#define PCI_SUBSYSTEM_VENDOR_ID
PCI subsystem vendor ID.
void send_eoi(unsigned int irq)
Send End-Of-Interrupt to the PIC.
int find_pnp_bios(void)
Locate Plug-and-Play BIOS.
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
#define PXENV_UNKNOWN
PXE API invalid function code.
uint16_t protocol
Protocol ID.
char * strerror(int errno)
Retrieve string representation of error number.
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
A hardware device description.
An Ethernet link-layer header.
void * data
Start of data.
Network device operations.
struct device dev
Generic device.
A data structure for storing profiling information.
Parameter block for pxenv_start_undi()
SEGSEL_t ES
es register as passed to the Option ROM initialisation routine.
UINT16_t DX
dx register as passed to the Option ROM initialisation routine.
OFF16_t DI
di register as passed to the Option ROM initialisation routine.
UINT16_t BX
bx register as passed to the Option ROM initialisation routine.
UINT16_t AX
ax register as passed to the Option ROM initialisation routine.
Parameter block for pxenv_stop_undi()
Parameter block for pxenv_undi_cleanup()
Parameter block for pxenv_undi_close()
Parameter block for pxenv_undi_get_iface_info()
UINT32_t LinkSpeed
Link speed, in bits per second.
UINT32_t ServiceFlags
Service flags.
UINT8_t IfaceType[16]
Interface type.
Parameter block for pxenv_undi_initialize()
Parameter block for pxenv_undi_isr()
UINT16_t FrameHeaderLength
Frame header length.
UINT16_t FrameLength
Total frame length.
UINT16_t BufferLength
Data buffer length.
UINT16_t FuncFlag
Function flag.
SEGOFF16_t Frame
Data buffer address.
Parameter block for pxenv_undi_open()
UINT16_t PktFilter
Receive packet filter.
Parameter block for pxenv_undi_set_station_address()
MAC_ADDR_t StationAddress
Station MAC address.
Parameter block for pxenv_undi_shutdown()
Parameter block for pxenv_undi_startup()
A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD.
Parameter block for pxenv_undi_transmit()
UINT8_t Protocol
Protocol.
SEGOFF16_t TBD
Address of the Transmit Buffer Descriptor.
UINT8_t XmitFlag
Unicast/broadcast flag.
SEGOFF16_t DestAddr
Destination MAC address.
UINT16_t pci_busdevfn
PCI bus:dev.fn, or UNDI_NO_PCI_BUSDEVFN.
UINT16_t isapnp_csn
ISAPnP card select number, or UNDI_NO_ISAPNP_CSN.
UINT16_t isapnp_read_port
ISAPnP read port, or UNDI_NO_ISAPNP_READ_PORT.
SEGOFF16_t entry
Entry point.
int hacks
Bug workarounds.
int isr_processing
Currently processing ISR.
unsigned int irq
Assigned IRQ number.
int irq_supported
Device supports IRQs.
A device with broken support for generating interrupts.
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
uint16_t pci_subsys
PCI subsystem ID.
uint16_t pci_device
PCI device ID.
uint16_t pci_vendor
PCI vendor ID.
A PXE API call breakdown profiler.
struct profiler p2r
Time spent transitioning to real mode.
struct profiler r2p
Time spent transitioning back to protected mode.
struct profiler ext
Time spent in external code.
struct profiler total
Total time spent performing REAL_CALL()
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
int32_t after
Final microcode version.
int32_t before
Initial microcode version.
#define UNDI_FL_KEEP_ALL
UNDI flag: keep stack resident.
static void undi_set_drvdata(struct undi_device *undi, void *priv)
Set UNDI driver-private data.
#define UNDI_FL_INITIALIZED
UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called.
static void * undi_get_drvdata(struct undi_device *undi)
Get UNDI driver-private data.
#define UNDI_FL_STARTED
UNDI flag: START_UNDI has been called.
static int undinet_call(struct undi_nic *undinic, unsigned int function, void *params, size_t params_len)
Issue UNDI API call.
static void undinet_hook_isr(unsigned int irq)
Hook UNDI interrupt service routine.
#define UNDI_RX_QUOTA
Maximum number of received packets per poll.
static struct net_device_operations undinet_operations
UNDI network device operations.
#define UNDI_INITIALIZE_RETRY_DELAY_MS
Delay between retries of PXENV_UNDI_INITIALIZE.
static void undinet_close(struct net_device *netdev)
Close NIC.
static const struct undinet_irq_broken undinet_irq_broken_list[]
List of devices with broken support for generating interrupts.
static void undinet_unhook_isr(unsigned int irq)
Unhook UNDI interrupt service routine.
static int undinet_isr_triggered(void)
Test to see if UNDI ISR has been triggered.
static int undinet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
static void undinet_poll(struct net_device *netdev)
Poll for received packets.
#define undiisr_trigger_count
#define UNDI_RX_ALIGN
Alignment of received frame payload.
#define UNDI_INITIALIZE_RETRY_MAX
Maximum number of times to retry PXENV_UNDI_INITIALIZE.
static struct undinet_profiler * undinet_profiler(unsigned int function)
Determine applicable profiler pair (for debugging)
int undinet_probe(struct undi_device *undi, struct device *dev)
Probe UNDI device.
static int undinet_open(struct net_device *netdev)
Open NIC.
#define undiisr_next_handler
static unsigned int last_trigger_count
Last observed trigger count.
#define RDTSC_IF_PROFILING
void undiisr(void)
UNDI interrupt service routine.
void undinet_remove(struct undi_device *undi)
Remove UNDI device.
#define undinet_entry_point
static void undinet_irq(struct net_device *netdev, int enable)
Enable/disable interrupts.
static int undinet_irq_is_broken(struct net_device *netdev)
Check for devices with broken support for generating interrupts.
static const char * undinet_function_name(unsigned int function)
Name PXE API call.
UNDI network device driver.