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" },
190 switch (
function ) {
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";
257 switch (
function ) {
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_next_handler __use_data16 ( undiisr_next_handler ) 382 #define undiisr_trigger_count __use_data16 ( undiisr_trigger_count ) 422 unsigned int this_trigger_count;
446 #define undinet_tbd __use_data16 ( undinet_tbd ) 450 #define undinet_destaddr __use_data16 ( undinet_destaddr ) 464 const void *ll_source;
488 &net_proto, &
flags ) ) != 0 ) {
489 DBGC ( undinic,
"UNDINIC %p could not strip Ethernet header: " 494 switch ( net_proto ) {
518 memset ( &undi_transmit, 0,
sizeof ( undi_transmit ) );
534 sizeof ( undi_transmit ) ) ) != 0 )
618 sizeof ( undi_isr ) ) ) != 0 ) {
633 if ( (
len == 0 ) || (
len < frag_len ) ) {
635 DBGC ( undinic,
"UNDINIC %p reported insane " 636 "fragment (%zd of %zd bytes)\n",
637 undinic, frag_len,
len );
644 DBGC ( undinic,
"UNDINIC %p could not " 645 "allocate %zd bytes for RX " 646 "buffer\n", undinic,
len );
654 if ( frag_len > max_frag_len ) {
655 DBGC ( undinic,
"UNDINIC %p fragment too big " 656 "(%zd+%zd does not fit into %zd)\n",
657 undinic,
iob_len ( iobuf ), frag_len,
658 (
iob_len ( iobuf ) + max_frag_len ) );
659 frag_len = max_frag_len;
662 undi_isr.
Frame.segment,
663 undi_isr.
Frame.offset, frag_len );
682 DBGC ( undinic,
"UNDINIC %p ISR returned invalid " 683 "FuncFlag %04x\n", undinic, undi_isr.
FuncFlag );
692 DBGC ( undinic,
"UNDINIC %p returned incomplete packet " 693 "(%zd of %zd)\n", undinic,
iob_len ( iobuf ),
712 if ( undinic->
irq ) {
726 &undi_set_address,
sizeof ( undi_set_address ) );
733 memset ( &undi_open, 0,
sizeof ( undi_open ) );
736 sizeof ( undi_open ) ) ) != 0 )
739 DBGC ( undinic,
"UNDINIC %p opened\n", undinic );
762 sizeof ( undi_isr ) ) ) != 0 )
778 sizeof ( undi_close ) );
781 if ( undinic->
irq ) {
786 DBGC ( undinic,
"UNDINIC %p closed\n", undinic );
799 DBGC ( undinic,
"UNDINIC %p cannot %s interrupts\n",
800 undinic, ( enable ?
"enable" :
"disable" ) );
910 memset ( undinic, 0,
sizeof ( *undinic ) );
912 DBGC ( undinic,
"UNDINIC %p using UNDI %p\n", undinic, undi );
916 memset ( &start_undi, 0,
sizeof ( start_undi ) );
924 sizeof ( start_undi ) ) ) != 0 )
931 memset ( &undi_startup, 0,
sizeof ( undi_startup ) );
934 sizeof ( undi_startup ) ) ) != 0 )
935 goto err_undi_startup;
942 for ( retry = 0 ; ; ) {
943 memset ( &undi_init, 0,
sizeof ( undi_init ) );
947 sizeof ( undi_init ) ) ) ==0)
950 goto err_undi_initialize;
951 DBGC ( undinic,
"UNDINIC %p retrying " 952 "PXENV_UNDI_INITIALIZE (retry %d)\n",
961 memset ( &undi_info, 0,
sizeof ( undi_info ) );
963 &undi_info,
sizeof ( undi_info ) ) ) != 0 )
964 goto err_undi_get_information;
969 DBGC ( undinic,
"UNDINIC %p ignoring invalid IRQ %d\n",
970 undinic, undinic->
irq );
973 DBGC ( undinic,
"UNDINIC %p has MAC address %s and IRQ %d\n",
977 memset ( &undi_iface, 0,
sizeof ( undi_iface ) );
979 &undi_iface,
sizeof ( undi_iface ) ) ) != 0 )
980 goto err_undi_get_iface_info;
981 DBGC ( undinic,
"UNDINIC %p has type %s, speed %d, flags %08x\n",
985 ( undinic->
irq != 0 ) ) {
988 DBGC ( undinic,
"UNDINIC %p using %s mode\n", undinic,
991 sizeof ( undi_iface.
IfaceType ) ) == 0 ) {
992 DBGC ( undinic,
"UNDINIC %p Etherboot 5.4 workaround enabled\n",
997 DBGC ( undinic,
"UNDINIC %p forcing polling mode due to " 998 "broken interrupts\n", undinic );
1009 DBGC ( undinic,
"UNDINIC %p added\n", undinic );
1013 err_undi_get_iface_info:
1014 err_undi_get_information:
1015 err_undi_initialize:
1017 memset ( &undi_shutdown, 0,
sizeof ( undi_shutdown ) );
1019 sizeof ( undi_shutdown ) );
1020 memset ( &undi_cleanup, 0,
sizeof ( undi_cleanup ) );
1022 sizeof ( undi_cleanup ) );
1026 memset ( &stop_undi, 0,
sizeof ( stop_undi ) );
1028 sizeof ( stop_undi ) );
1058 memset ( &undi_shutdown, 0,
sizeof ( undi_shutdown ) );
1060 &undi_shutdown,
sizeof ( undi_shutdown ) );
1061 memset ( &undi_cleanup, 0,
sizeof ( undi_cleanup ) );
1063 &undi_cleanup,
sizeof ( undi_cleanup ) );
1067 memset ( &stop_undi, 0,
sizeof ( stop_undi ) );
1069 sizeof ( stop_undi ) );
1080 DBGC ( undinic,
"UNDINIC %p removed\n", undinic );
#define UNDI_HACK_EB54
Work around Etherboot 5.4 bugs.
#define PXENV_UNDI_SHUTDOWN
PXE API function code for pxenv_undi_shutdown()
#define EINVAL
Invalid argument.
Parameter block for pxenv_undi_isr()
#define PXENV_UNDI_FORCE_INTERRUPT
PXE API function code for pxenv_undi_force_interrupt()
struct arbelprm_rc_send_wqe rc
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
#define iob_put(iobuf, len)
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD.
FILE_LICENCE(GPL2_OR_LATER)
#define SUPPORTED_IRQ
Interrupt Request supported.
#define PXENV_UNDI_CLEANUP
PXE API function code for pxenv_undi_cleanup()
#define PXENV_UNDI_SET_STATION_ADDRESS
PXE API function code for pxenv_undi_set_station_address()
int(* open)(struct net_device *netdev)
Open network device.
#define PXENV_START_UNDI
PXE API function code for pxenv_start_undi()
#define PXENV_UNDI_CLEAR_STATISTICS
PXE API function code for pxenv_undi_clear_statistics()
#define undiisr_trigger_count
#define PXENV_STOP_UNDI
PXE API function code for pxenv_stop_undi()
#define iob_push(iobuf, len)
#define PXENV_UNDI_GET_MCAST_ADDRESS
PXE API function code for pxenv_undi_get_mcast_address()
#define FLTR_PRMSCS
Accept all packets; listen in promiscuous mode.
uint64_t desc
Microcode descriptor list physical address.
int undinet_probe(struct undi_device *undi, struct device *dev)
Probe UNDI device.
Parameter block for pxenv_undi_initialize()
#define PXENV_UNDI_GET_IFACE_INFO
PXE API function code for pxenv_undi_get_iface_info()
static void undinet_poll(struct net_device *netdev)
Poll for received packets.
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
Parameter block for pxenv_undi_transmit()
int32_t before
Initial microcode version.
#define PXENV_UNDI_SET_MCAST_ADDRESS
PXE API function code for pxenv_undi_set_mcast_address()
#define UNDI_FL_INITIALIZED
UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called.
void send_eoi(unsigned int irq)
Send End-Of-Interrupt to the PIC.
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
static void * undi_get_drvdata(struct undi_device *undi)
Get UNDI driver-private data.
static unsigned long profile_started(struct profiler *profiler)
Get start time.
UNDI network device driver.
UINT32_t ServiceFlags
Service flags.
A data structure for storing profiling information.
#define XMT_BROADCAST
Broadcast packet.
UINT16_t PktFilter
Receive packet filter.
#define PXENV_UNDI_GET_NIC_TYPE
PXE API function code for pxenv_undi_get_nic_type()
static void profile_stop(struct profiler *profiler)
Stop profiling.
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
UINT16_t FuncFlag
Function flag.
UINT32_t LinkSpeed
Link speed, in bits per second.
static void undinet_close(struct net_device *netdev)
Close NIC.
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
struct device dev
Generic device.
#define PXENV_UNKNOWN
PXE API invalid function code.
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.
A hardware device description.
void undinet_remove(struct undi_device *undi)
Remove UNDI device.
#define PXENV_UNDI_ISR_OUT_RECEIVE
A packet has been received.
SEGSEL_t ES
es register as passed to the Option ROM initialisation routine.
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
Parameter block for pxenv_undi_close()
UINT16_t isapnp_csn
ISAPnP card select number, or UNDI_NO_ISAPNP_CSN.
static struct profiler undinet_irq_profiler __profiler
IRQ profiler.
static void profile_stop_at(struct profiler *profiler, unsigned long stopped)
Stop profiling.
static int undinet_isr_triggered(void)
Test to see if UNDI ISR has been triggered.
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
OFF16_t DI
di register as passed to the Option ROM initialisation routine.
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
#define PXENV_UNDI_ISR_IN_PROCESS
Start processing interrupt.
#define ENOMEM
Not enough space.
#define iob_disown(iobuf)
Disown an I/O buffer.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int started
"startup() has been called" flag
UINT16_t PXENV_EXIT_t
A PXE exit code.
uint16_t pci_vendor
PCI vendor ID.
static unsigned int last_trigger_count
Last observed trigger count.
UINT16_t FrameLength
Total frame length.
#define BUS_TYPE_PCI
PCI bus type.
static struct undinet_profiler * undinet_profiler(unsigned int function)
Determine applicable profiler pair (for debugging)
static int undinet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
#define PXENV_UNDI_CLOSE
PXE API function code for pxenv_undi_close()
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
UINT8_t Protocol
Protocol.
void * priv
Driver private data.
SEGOFF16_t DestAddr
Destination MAC address.
UINT8_t XmitFlag
Unicast/broadcast flag.
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
#define FLTR_BRDCST
Accept broadcast packets.
Parameter block for pxenv_undi_set_station_address()
#define UNDI_FL_KEEP_ALL
UNDI flag: keep stack resident.
static int undinet_irq_is_broken(struct device_description *desc)
Check for devices with broken support for generating interrupts.
static struct net_device * netdev
static void undinet_hook_isr(unsigned int irq)
Hook UNDI interrupt service routine.
SEGOFF16_t Frame
Data buffer address.
#define UNDI_RX_ALIGN
Alignment of received frame payload.
Parameter block for pxenv_undi_shutdown()
unsigned int irq
Assigned IRQ number.
static void profile_start(struct profiler *profiler)
Start profiling.
UINT16_t BX
bx register as passed to the Option ROM initialisation routine.
void unregister_netdev(struct net_device *netdev)
Unregister network device.
#define PXENV_UNDI_ISR_OUT_TRANSMIT
A packet transmission has completed.
Parameter block for pxenv_undi_startup()
#define PXENV_UNDI_TRANSMIT
PXE API function code for pxenv_undi_transmit()
SEGOFF16_t entry
Entry point.
static uint8_t __data16_array(undinet_destaddr, [ETH_ALEN])
UNDI transmit destination address.
char * strerror(int errno)
Retrieve string representation of error number.
int hacks
Bug workarounds.
int register_netdev(struct net_device *netdev)
Register network device.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
static const char * undinet_function_name(unsigned int function)
Name PXE API call.
static union u_PXENV_ANY __bss16(undinet_params)
UNDI parameter block.
__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))
UINT16_t isapnp_read_port
ISAPnP read port, or UNDI_NO_ISAPNP_READ_PORT.
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
#define PXENV_UNDI_GET_STATISTICS
PXE API function code for pxenv_undi_get_statistics()
#define PXENV_UNDI_SET_PACKET_FILTER
PXE API function code for pxenv_undi_set_packet_filter()
#define PXENV_UNDI_INITIATE_DIAGS
PXE API function code for pxenv_undi_initiate_diags()
#define PXENV_UNDI_OPEN
PXE API function code for pxenv_undi_open()
static void undinet_irq(struct net_device *netdev, int enable)
Enable/disable interrupts.
#define XMT_DESTADDR
Unicast packet.
MAC_ADDR_t StationAddress
Station MAC address.
struct profiler r2p
Time spent transitioning back to protected mode.
#define PXENV_UNDI_ISR_IN_GET_NEXT
Continue processing interrupt.
struct profiler ext
Time spent in external code.
static int undinet_call(struct undi_nic *undinic, unsigned int function, void *params, size_t params_len)
Issue UNDI API call.
Network device operations.
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
struct device * dev
Underlying hardware device.
#define LL_BROADCAST
Packet is a broadcast packet.
UINT16_t pci_busdevfn
PCI bus:dev.fn, or UNDI_NO_PCI_BUSDEVFN.
#define PXENV_EXIT_SUCCESS
No error occurred.
Network device management.
Parameter block for pxenv_undi_cleanup()
#define RDTSC_IF_PROFILING
static const struct undinet_irq_broken undinet_irq_broken_list[]
List of devices with broken support for generating interrupts.
#define UNDI_INITIALIZE_RETRY_MAX
Maximum number of times to retry PXENV_UNDI_INITIALIZE.
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
#define iob_reserve(iobuf, len)
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
__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")
uint16_t pci_device
PCI device ID.
#define FLTR_DIRECTED
Accept "directed" packets.
static unsigned long profile_stopped(struct profiler *profiler)
Get stop time.
#define PXENV_UNDI_RESET_ADAPTER
PXE API function code for pxenv_undi_reset_adapter()
#define __from_data16(pointer)
static void undinet_unhook_isr(unsigned int irq)
Unhook UNDI interrupt service routine.
struct profiler total
Total time spent performing REAL_CALL()
SEGOFF16_t TBD
Address of the Transmit Buffer Descriptor.
int32_t after
Final microcode version.
void * data
Start of data.
#define PXENV_UNDI_ISR
PXE API function code for pxenv_undi_isr()
int find_pnp_bios(void)
Locate Plug-and-Play BIOS.
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Parameter block for pxenv_undi_get_iface_info()
#define undinet_entry_point
struct device_description desc
Device description.
#define P_RARP
RARP protocol.
uint8_t __data16(undiisr_irq)
IRQ number.
#define PXENV_GET_CACHED_INFO
PXE API function code for pxenv_get_cached_info()
int isr_processing
Currently processing ISR.
#define PXENV_UNDI_ISR_OUT_DONE
Finished processing interrupt.
#define undiisr_next_handler
uint16_t protocol
Protocol ID.
#define PCI_SUBSYSTEM_VENDOR_ID
PCI subsystem vendor ID.
static void undi_set_drvdata(struct undi_device *undi, void *priv)
Set UNDI driver-private data.
void undiisr(void)
UNDI interrupt service routine.
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
UINT8_t IfaceType[16]
Interface type.
#define P_ARP
ARP protocol.
Parameter block for pxenv_start_undi()
#define P_UNKNOWN
Media header already filled in.
static void pci_init(struct pci_device *pci, unsigned int busdevfn)
Initialise PCI device.
#define PXENV_UNDI_STARTUP
PXE API function code for pxenv_undi_startup()
#define UNDI_RX_QUOTA
Maximum number of received packets per poll.
UINT16_t AX
ax register as passed to the Option ROM initialisation routine.
#define PXENV_UNDI_INITIALIZE
PXE API function code for pxenv_undi_initialize()
uint16_t pci_subsys
PCI subsystem ID.
UINT16_t FrameHeaderLength
Frame header length.
static struct net_device_operations undinet_operations
UNDI network device operations.
An Ethernet link-layer header.
#define REAL_CODE(asm_code_str)
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
#define NULL
NULL pointer (VOID *)
#define UNDI_INITIALIZE_RETRY_DELAY_MS
Delay between retries of PXENV_UNDI_INITIALIZE.
UINT16_t DX
dx register as passed to the Option ROM initialisation routine.
UINT16_t BufferLength
Data buffer length.
#define UNDI_FL_STARTED
UNDI flag: START_UNDI has been called.
Parameter block for pxenv_stop_undi()
struct bofm_section_header done
Parameter block for pxenv_undi_open()
static int undinet_open(struct net_device *netdev)
Open NIC.
#define PCI_ANY_ID
Match-anything ID.
A device with broken support for generating interrupts.
int irq_supported
Device supports IRQs.
A PXE API call breakdown profiler.
void * memset(void *dest, int character, size_t len) __nonnull
struct profiler p2r
Time spent transitioning to real mode.