iPXE
undinet.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20FILE_LICENCE ( GPL2_OR_LATER );
21
22#include <string.h>
23#include <unistd.h>
24#include <byteswap.h>
25#include <pxe.h>
26#include <realmode.h>
27#include <pic8259.h>
28#include <biosint.h>
29#include <pnpbios.h>
30#include <basemem_packet.h>
31#include <ipxe/io.h>
32#include <ipxe/iobuf.h>
33#include <ipxe/netdevice.h>
34#include <ipxe/if_ether.h>
35#include <ipxe/ethernet.h>
36#include <ipxe/pci.h>
37#include <ipxe/profile.h>
38#include <undi.h>
39#include <undinet.h>
40
41/** @file
42 *
43 * UNDI network device driver
44 *
45 */
46
47/** An UNDI NIC */
48struct undi_nic {
49 /** Device supports IRQs */
51 /** Assigned IRQ number */
52 unsigned int irq;
53 /** Currently processing ISR */
55 /** Bug workarounds */
56 int hacks;
57};
58
59/* Disambiguate the various error causes */
60#define EINFO_EPXECALL \
61 __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
62 "External PXE API error" )
63#define EPXECALL( status ) EPLATFORM ( EINFO_EPXECALL, status )
64
65/**
66 * @defgroup undi_hacks UNDI workarounds
67 * @{
68 */
69
70/** Work around Etherboot 5.4 bugs */
71#define UNDI_HACK_EB54 0x0001
72
73/** @} */
74
75/** Maximum number of times to retry PXENV_UNDI_INITIALIZE */
76#define UNDI_INITIALIZE_RETRY_MAX 10
77
78/** Delay between retries of PXENV_UNDI_INITIALIZE */
79#define UNDI_INITIALIZE_RETRY_DELAY_MS 200
80
81/** Maximum number of received packets per poll */
82#define UNDI_RX_QUOTA 4
83
84/** Alignment of received frame payload */
85#define UNDI_RX_ALIGN 16
86
87static void undinet_close ( struct net_device *netdev );
88
89/**
90 * UNDI parameter block
91 *
92 * Used as the parameter block for all UNDI API calls. Resides in
93 * base memory.
94 */
96#define undinet_params __use_data16 ( undinet_params )
97
98/**
99 * UNDI entry point
100 *
101 * Used as the indirection vector for all UNDI API calls. Resides in
102 * base memory.
103 */
105#define undinet_entry_point __use_data16 ( undinet_entry_point )
106
107/* Read TSC in real mode only when profiling */
108#if PROFILING
109#define RDTSC_IF_PROFILING "rdtsc\n\t"
110#else
111#define RDTSC_IF_PROFILING ""
112#endif
113
114/** IRQ profiler */
115static struct profiler undinet_irq_profiler __profiler =
116 { .name = "undinet.irq" };
117
118/** Receive profiler */
119static struct profiler undinet_rx_profiler __profiler =
120 { .name = "undinet.rx" };
121
122/** A PXE API call breakdown profiler */
124 /** Total time spent performing REAL_CALL() */
126 /** Time spent transitioning to real mode */
127 struct profiler p2r;
128 /** Time spent in external code */
129 struct profiler ext;
130 /** Time spent transitioning back to protected mode */
131 struct profiler r2p;
132};
133
134/** PXENV_UNDI_TRANSMIT profiler */
135static struct undinet_profiler undinet_tx_profiler __profiler = {
136 { .name = "undinet.tx" },
137 { .name = "undinet.tx_p2r" },
138 { .name = "undinet.tx_ext" },
139 { .name = "undinet.tx_r2p" },
140};
141
142/** PXENV_UNDI_ISR profiler
143 *
144 * Note that this profiler will not see calls to
145 * PXENV_UNDI_ISR_IN_START, which are handled by the UNDI ISR and do
146 * not go via undinet_call().
147 */
148static struct undinet_profiler undinet_isr_profiler __profiler = {
149 { .name = "undinet.isr" },
150 { .name = "undinet.isr_p2r" },
151 { .name = "undinet.isr_ext" },
152 { .name = "undinet.isr_r2p" },
153};
154
155/** PXE unknown API call profiler
156 *
157 * This profiler can be used to measure the overhead of a dummy PXE
158 * API call.
159 */
160static struct undinet_profiler undinet_unknown_profiler __profiler = {
161 { .name = "undinet.unknown" },
162 { .name = "undinet.unknown_p2r" },
163 { .name = "undinet.unknown_ext" },
164 { .name = "undinet.unknown_r2p" },
165};
166
167/** Miscellaneous PXE API call profiler */
168static struct undinet_profiler undinet_misc_profiler __profiler = {
169 { .name = "undinet.misc" },
170 { .name = "undinet.misc_p2r" },
171 { .name = "undinet.misc_ext" },
172 { .name = "undinet.misc_r2p" },
173};
174
175/*****************************************************************************
176 *
177 * UNDI API call
178 *
179 *****************************************************************************
180 */
181
182/**
183 * Name PXE API call
184 *
185 * @v function API call number
186 * @ret name API call name
187 */
188static inline __attribute__ (( always_inline )) const char *
190 switch ( function ) {
191 case PXENV_START_UNDI:
192 return "PXENV_START_UNDI";
193 case PXENV_STOP_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";
205 case PXENV_UNDI_OPEN:
206 return "PXENV_UNDI_OPEN";
207 case PXENV_UNDI_CLOSE:
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";
233 /*
234 * Duplicate case value; this is a bug in the PXE specification.
235 *
236 * case PXENV_UNDI_GET_STATE:
237 * return "PXENV_UNDI_GET_STATE";
238 */
239 case PXENV_UNDI_ISR:
240 return "PXENV_UNDI_ISR";
242 return "PXENV_GET_CACHED_INFO";
243 default:
244 return "UNKNOWN API CALL";
245 }
246}
247
248/**
249 * Determine applicable profiler pair (for debugging)
250 *
251 * @v function API call number
252 * @ret profiler Profiler
253 */
254static struct undinet_profiler * undinet_profiler ( unsigned int function ) {
255
256 /* Determine applicable profiler */
257 switch ( function ) {
259 return &undinet_tx_profiler;
260 case PXENV_UNDI_ISR:
261 return &undinet_isr_profiler;
262 case PXENV_UNKNOWN:
263 return &undinet_unknown_profiler;
264 default:
265 return &undinet_misc_profiler;
266 }
267}
268
269/**
270 * Issue UNDI API call
271 *
272 * @v undinic UNDI NIC
273 * @v function API call number
274 * @v params PXE parameter block
275 * @v params_len Length of PXE parameter block
276 * @ret rc Return status code
277 */
278static int undinet_call ( struct undi_nic *undinic, unsigned int function,
279 void *params, size_t params_len ) {
281 PXENV_EXIT_t exit;
284 uint32_t stopped;
286 int discard_D;
287 int rc;
288
289 /* Copy parameter block and entry point */
290 assert ( params_len <= sizeof ( undinet_params ) );
291 memcpy ( &undinet_params, params, params_len );
292
293 /* Call real-mode entry point. This calling convention will
294 * work with both the !PXE and the PXENV+ entry points.
295 */
296 profile_start ( &profiler->total );
297 __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
299 "pushl %%eax\n\t"
300 "pushw %%es\n\t"
301 "pushw %%di\n\t"
302 "pushw %%bx\n\t"
303 "lcall *undinet_entry_point\n\t"
304 "movw %%ax, %%bx\n\t"
306 "addw $6, %%sp\n\t"
307 "popl %%edx\n\t"
308 "popl %%ebp\n\t" /* gcc bug */ )
309 : "=a" ( stopped ), "=d" ( started ),
310 "=b" ( exit ), "=D" ( discard_D )
311 : "b" ( function ),
312 "D" ( __from_data16 ( &undinet_params ) )
313 : "ecx", "esi" );
314 profile_stop ( &profiler->total );
315 before = profile_started ( &profiler->total );
316 after = profile_stopped ( &profiler->total );
320 profile_stop_at ( &profiler->ext, stopped );
321 profile_start_at ( &profiler->r2p, stopped );
322 profile_stop_at ( &profiler->r2p, after );
323
324 /* Determine return status code based on PXENV_EXIT and
325 * PXENV_STATUS
326 */
327 rc = ( ( exit == PXENV_EXIT_SUCCESS ) ?
328 0 : -EPXECALL ( undinet_params.Status ) );
329
330 /* If anything goes wrong, print as much debug information as
331 * it's possible to give.
332 */
333 if ( rc != 0 ) {
334 SEGOFF16_t rm_params = {
335 .segment = rm_ds,
336 .offset = __from_data16 ( &undinet_params ),
337 };
338
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,
344 undinet_entry_point.segment,
345 undinet_entry_point.offset );
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 );
349 DBGC_HDA ( undinic, rm_params, &undinet_params, params_len );
350 }
351
352 /* Copy parameter block back */
353 memcpy ( params, &undinet_params, params_len );
354
355 return rc;
356}
357
358/*****************************************************************************
359 *
360 * UNDI interrupt service routine
361 *
362 *****************************************************************************
363 */
364
365/**
366 * UNDI interrupt service routine
367 *
368 * The UNDI ISR increments a counter (@c trigger_count) and exits.
369 */
370extern void undiisr ( void );
371
372/** IRQ number */
374#define undiisr_irq __use_data16 ( undiisr_irq )
375
376/** IRQ mask register */
378#define undiisr_imr __use_data16 ( undiisr_imr )
379
380/** IRQ mask bit */
382#define undiisr_bit __use_data16 ( undiisr_bit )
383
384/** IRQ rearm flag */
386#define undiisr_rearm __use_data16 ( undiisr_rearm )
387
388/** IRQ chain vector */
390#define undiisr_next_handler __use_data16 ( undiisr_next_handler )
391
392/** IRQ trigger count */
394#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
395
396/** Last observed trigger count */
397static unsigned int last_trigger_count = 0;
398
399/**
400 * Hook UNDI interrupt service routine
401 *
402 * @v irq IRQ number
403 */
404static void undinet_hook_isr ( unsigned int irq ) {
405
406 assert ( irq <= IRQ_MAX );
407 assert ( undiisr_irq == 0 );
408
409 undiisr_irq = irq;
410 undiisr_imr = IMR_REG ( irq );
411 undiisr_bit = IMR_BIT ( irq );
412 undiisr_rearm = 0;
413 hook_bios_interrupt ( IRQ_INT ( irq ), ( ( intptr_t ) undiisr ),
415}
416
417/**
418 * Unhook UNDI interrupt service routine
419 *
420 * @v irq IRQ number
421 */
422static void undinet_unhook_isr ( unsigned int irq ) {
423
424 assert ( irq <= IRQ_MAX );
425
428 undiisr_irq = 0;
429}
430
431/**
432 * Test to see if UNDI ISR has been triggered
433 *
434 * @ret triggered ISR has been triggered since last check
435 */
436static int undinet_isr_triggered ( void ) {
437 unsigned int this_trigger_count;
438
439 /* Read trigger_count. Do this only once; it is volatile */
440 this_trigger_count = undiisr_trigger_count;
441
442 if ( this_trigger_count == last_trigger_count ) {
443 /* Not triggered */
444 return 0;
445 } else {
446 /* Triggered */
447 last_trigger_count = this_trigger_count;
448 return 1;
449 }
450}
451
452/*****************************************************************************
453 *
454 * UNDI network device interface
455 *
456 *****************************************************************************
457 */
458
459/** UNDI transmit buffer descriptor */
461#define undinet_tbd __use_data16 ( undinet_tbd )
462
463/** UNDI transmit destination address */
465#define undinet_destaddr __use_data16 ( undinet_destaddr )
466
467/**
468 * Transmit packet
469 *
470 * @v netdev Network device
471 * @v iobuf I/O buffer
472 * @ret rc Return status code
473 */
474static int undinet_transmit ( struct net_device *netdev,
475 struct io_buffer *iobuf ) {
476 struct undi_nic *undinic = netdev->priv;
477 struct s_PXENV_UNDI_TRANSMIT undi_transmit;
478 const void *ll_dest;
479 const void *ll_source;
480 uint16_t net_proto;
481 unsigned int flags;
483 size_t len;
484 int rc;
485
486 /* Technically, we ought to make sure that the previous
487 * transmission has completed before we re-use the buffer.
488 * However, many PXE stacks (including at least some Intel PXE
489 * stacks and Etherboot 5.4) fail to generate TX completions.
490 * In practice this won't be a problem, since our TX datapath
491 * has a very low packet volume and we can get away with
492 * assuming that a TX will be complete by the time we want to
493 * transmit the next packet.
494 */
495
496 /* Some PXE stacks are unable to cope with P_UNKNOWN, and will
497 * always try to prepend a link-layer header. Work around
498 * these stacks by stripping the existing link-layer header
499 * and allowing the PXE stack to (re)construct the link-layer
500 * header itself.
501 */
502 if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
503 &net_proto, &flags ) ) != 0 ) {
504 DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
505 "%s\n", undinic, strerror ( rc ) );
506 return rc;
507 }
508 memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
509 switch ( net_proto ) {
510 case htons ( ETH_P_IP ) :
511 protocol = P_IP;
512 break;
513 case htons ( ETH_P_ARP ) :
514 protocol = P_ARP;
515 break;
516 case htons ( ETH_P_RARP ) :
518 break;
519 default:
520 /* Unknown protocol; restore the original link-layer header */
521 iob_push ( iobuf, sizeof ( struct ethhdr ) );
523 break;
524 }
525
526 /* Copy packet to UNDI I/O buffer */
527 len = iob_len ( iobuf );
528 if ( len > sizeof ( basemem_packet ) )
529 len = sizeof ( basemem_packet );
530 memcpy ( &basemem_packet, iobuf->data, len );
531
532 /* Create PXENV_UNDI_TRANSMIT data structure */
533 memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
534 undi_transmit.Protocol = protocol;
535 undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
537 undi_transmit.DestAddr.segment = rm_ds;
538 undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
539 undi_transmit.TBD.segment = rm_ds;
540 undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
541
542 /* Create PXENV_UNDI_TBD data structure */
543 undinet_tbd.ImmedLength = len;
544 undinet_tbd.Xmit.segment = rm_ds;
545 undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
546
547 /* Issue PXE API call */
548 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_TRANSMIT, &undi_transmit,
549 sizeof ( undi_transmit ) ) ) != 0 )
550 goto done;
551
552 /* Free I/O buffer */
553 netdev_tx_complete ( netdev, iobuf );
554 done:
555 return rc;
556}
557
558/**
559 * Poll for received packets
560 *
561 * @v netdev Network device
562 *
563 * Fun, fun, fun. UNDI drivers don't use polling; they use
564 * interrupts. We therefore cheat and pretend that an interrupt has
565 * occurred every time undinet_poll() is called. This isn't too much
566 * of a hack; PCI devices share IRQs and so the first thing that a
567 * proper ISR should do is call PXENV_UNDI_ISR to determine whether or
568 * not the UNDI NIC generated the interrupt; there is no harm done by
569 * spurious calls to PXENV_UNDI_ISR. Similarly, we wouldn't be
570 * handling them any more rapidly than the usual rate of
571 * undinet_poll() being called even if we did implement a full ISR.
572 * So it should work. Ha!
573 *
574 * Addendum (21/10/03). Some cards don't play nicely with this trick,
575 * so instead of doing it the easy way we have to go to all the hassle
576 * of installing a genuine interrupt service routine and dealing with
577 * the wonderful 8259 Programmable Interrupt Controller. Joy.
578 *
579 * Addendum (10/07/07). When doing things such as iSCSI boot, in
580 * which we have to co-operate with a running OS, we can't get away
581 * with the "ISR-just-increments-a-counter-and-returns" trick at all,
582 * because it involves tying up the PIC for far too long, and other
583 * interrupt-dependent components (e.g. local disks) start breaking.
584 * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
585 * from within interrupt context in order to deassert the device
586 * interrupt, and sends EOI if applicable.
587 */
588static void undinet_poll ( struct net_device *netdev ) {
589 struct undi_nic *undinic = netdev->priv;
590 struct s_PXENV_UNDI_ISR undi_isr;
591 struct io_buffer *iobuf = NULL;
592 unsigned int quota = UNDI_RX_QUOTA;
593 size_t len;
594 size_t reserve_len;
595 size_t frag_len;
596 size_t max_frag_len;
597 int rc;
598
599 if ( ! undinic->isr_processing ) {
600 /* Allow interrupt to occur. Do this even if
601 * interrupts are not known to be supported, since
602 * some cards erroneously report that they do not
603 * support interrupts.
604 */
605 if ( ! undinet_isr_triggered() ) {
606
607 /* Rearm interrupt if needed */
608 if ( undiisr_rearm ) {
609 undiisr_rearm = 0;
610 assert ( undinic->irq != 0 );
611 enable_irq ( undinic->irq );
612 }
613
614 /* Allow interrupt to occur */
615 profile_start ( &undinet_irq_profiler );
616 __asm__ __volatile__ ( "sti\n\t"
617 "nop\n\t"
618 "nop\n\t"
619 "cli\n\t" );
620 profile_stop ( &undinet_irq_profiler );
621
622 /* If interrupts are known to be supported,
623 * then do nothing on this poll; wait for the
624 * interrupt to be triggered.
625 */
626 if ( undinic->irq_supported )
627 return;
628 }
629
630 /* Start ISR processing */
631 undinic->isr_processing = 1;
633 } else {
634 /* Continue ISR processing */
636 }
637
638 /* Run through the ISR loop */
639 while ( quota ) {
640 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
641 sizeof ( undi_isr ) ) ) != 0 ) {
643 break;
644 }
645 switch ( undi_isr.FuncFlag ) {
647 /* We don't care about transmit completions */
648 break;
650 /* Packet fragment received */
651 profile_start ( &undinet_rx_profiler );
652 len = undi_isr.FrameLength;
653 frag_len = undi_isr.BufferLength;
654 reserve_len = ( -undi_isr.FrameHeaderLength &
655 ( UNDI_RX_ALIGN - 1 ) );
656 if ( ( len == 0 ) || ( len < frag_len ) ) {
657 /* Don't laugh. VMWare does it. */
658 DBGC ( undinic, "UNDINIC %p reported insane "
659 "fragment (%zd of %zd bytes)\n",
660 undinic, frag_len, len );
662 break;
663 }
664 if ( ! iobuf ) {
665 iobuf = alloc_iob ( reserve_len + len );
666 if ( ! iobuf ) {
667 DBGC ( undinic, "UNDINIC %p could not "
668 "allocate %zd bytes for RX "
669 "buffer\n", undinic, len );
670 /* Fragment will be dropped */
672 goto done;
673 }
674 iob_reserve ( iobuf, reserve_len );
675 }
676 max_frag_len = iob_tailroom ( iobuf );
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;
683 }
684 copy_from_real ( iob_put ( iobuf, frag_len ),
685 undi_isr.Frame.segment,
686 undi_isr.Frame.offset, frag_len );
687 if ( iob_len ( iobuf ) == len ) {
688 /* Whole packet received; deliver it */
689 netdev_rx ( netdev, iob_disown ( iobuf ) );
690 quota--;
691 /* Etherboot 5.4 fails to return all packets
692 * under mild load; pretend it retriggered.
693 */
694 if ( undinic->hacks & UNDI_HACK_EB54 )
696 }
697 profile_stop ( &undinet_rx_profiler );
698 break;
700 /* Processing complete */
701 undinic->isr_processing = 0;
702 goto done;
703 default:
704 /* Should never happen. VMWare does it routinely. */
705 DBGC ( undinic, "UNDINIC %p ISR returned invalid "
706 "FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
707 undinic->isr_processing = 0;
708 goto done;
709 }
711 }
712
713 done:
714 if ( iobuf ) {
715 DBGC ( undinic, "UNDINIC %p returned incomplete packet "
716 "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
717 ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
718 netdev_rx_err ( netdev, iobuf, -EINVAL );
719 }
720}
721
722/**
723 * Open NIC
724 *
725 * @v netdev Net device
726 * @ret rc Return status code
727 */
728static int undinet_open ( struct net_device *netdev ) {
729 struct undi_nic *undinic = netdev->priv;
730 struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
731 struct s_PXENV_UNDI_OPEN undi_open;
732 int rc;
733
734 /* Hook interrupt service routine and enable interrupt if applicable */
735 if ( undinic->irq ) {
736 undinet_hook_isr ( undinic->irq );
737 enable_irq ( undinic->irq );
738 send_eoi ( undinic->irq );
739 }
740
741 /* Set station address. Required for some PXE stacks; will
742 * spuriously fail on others. Ignore failures. We only ever
743 * use it to set the MAC address to the card's permanent value
744 * anyway.
745 */
746 memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
747 sizeof ( undi_set_address.StationAddress ) );
749 &undi_set_address, sizeof ( undi_set_address ) );
750
751 /* Open NIC. We ask for promiscuous operation, since it's the
752 * only way to ask for all multicast addresses. On any
753 * switched network, it shouldn't really make a difference to
754 * performance.
755 */
756 memset ( &undi_open, 0, sizeof ( undi_open ) );
758 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open,
759 sizeof ( undi_open ) ) ) != 0 )
760 goto err;
761
762 DBGC ( undinic, "UNDINIC %p opened\n", undinic );
763 return 0;
764
765 err:
767 return rc;
768}
769
770/**
771 * Close NIC
772 *
773 * @v netdev Net device
774 */
775static void undinet_close ( struct net_device *netdev ) {
776 struct undi_nic *undinic = netdev->priv;
777 struct s_PXENV_UNDI_ISR undi_isr;
778 struct s_PXENV_UNDI_CLOSE undi_close;
779 int rc;
780
781 /* Ensure ISR has exited cleanly */
782 while ( undinic->isr_processing ) {
784 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
785 sizeof ( undi_isr ) ) ) != 0 )
786 break;
787 switch ( undi_isr.FuncFlag ) {
790 /* Continue draining */
791 break;
792 default:
793 /* Stop processing */
794 undinic->isr_processing = 0;
795 break;
796 }
797 }
798
799 /* Close NIC */
800 undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close,
801 sizeof ( undi_close ) );
802
803 /* Disable interrupt and unhook ISR if applicable */
804 if ( undinic->irq ) {
805 disable_irq ( undinic->irq );
806 undinet_unhook_isr ( undinic->irq );
807 }
808
809 DBGC ( undinic, "UNDINIC %p closed\n", undinic );
810}
811
812/**
813 * Enable/disable interrupts
814 *
815 * @v netdev Net device
816 * @v enable Interrupts should be enabled
817 */
818static void undinet_irq ( struct net_device *netdev, int enable ) {
819 struct undi_nic *undinic = netdev->priv;
820
821 /* Cannot support interrupts yet */
822 DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n",
823 undinic, ( enable ? "enable" : "disable" ) );
824}
825
826/** UNDI network device operations */
828 .open = undinet_open,
829 .close = undinet_close,
830 .transmit = undinet_transmit,
831 .poll = undinet_poll,
832 .irq = undinet_irq,
833};
834
835/** A device with broken support for generating interrupts */
837 /** PCI vendor ID */
839 /** PCI device ID */
841 /** PCI subsystem vendor ID */
843 /** PCI subsystem ID */
845};
846
847/**
848 * List of devices with broken support for generating interrupts
849 *
850 * Some PXE stacks are known to claim that IRQs are supported, but
851 * then never generate interrupts. No satisfactory solution has been
852 * found to this problem; the workaround is to add the PCI vendor and
853 * device IDs to this list. This is something of a hack, since it
854 * will generate false positives for identical devices with a working
855 * PXE stack (e.g. those that have been reflashed with iPXE), but it's
856 * an improvement on the current situation.
857 */
859 /* HP XX70x laptops */
860 { 0x8086, 0x1502, PCI_ANY_ID, PCI_ANY_ID },
861 { 0x8086, 0x1503, PCI_ANY_ID, PCI_ANY_ID },
862 /* HP 745 G3 laptop */
863 { 0x14e4, 0x1687, PCI_ANY_ID, PCI_ANY_ID },
864 /* ASUSTeK KNPA-U16 server */
865 { 0x8086, 0x1521, 0x1043, PCI_ANY_ID },
866};
867
868/**
869 * Check for devices with broken support for generating interrupts
870 *
871 * @v netdev Net device
872 * @ret irq_is_broken Interrupt support is broken; no interrupts are generated
873 */
875 struct undi_nic *undinic = netdev->priv;
876 struct device_description *desc = &netdev->dev->desc;
877 const struct undinet_irq_broken *broken;
878 struct pci_device pci;
879 uint16_t subsys_vendor;
880 uint16_t subsys;
881 unsigned int i;
882
883 /* Ignore non-PCI devices */
884 if ( desc->bus_type != BUS_TYPE_PCI )
885 return 0;
886
887 /* Read subsystem IDs */
888 pci_init ( &pci, desc->location );
889 pci_read_config_word ( &pci, PCI_SUBSYSTEM_VENDOR_ID, &subsys_vendor );
890 pci_read_config_word ( &pci, PCI_SUBSYSTEM_ID, &subsys );
891
892 /* Check for a match against the broken device list */
893 for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
894 sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
895 broken = &undinet_irq_broken_list[i];
896 if ( ( broken->pci_vendor == desc->vendor ) &&
897 ( broken->pci_device == desc->device ) &&
898 ( ( broken->pci_subsys_vendor == subsys_vendor ) ||
899 ( broken->pci_subsys_vendor == PCI_ANY_ID ) ) &&
900 ( ( broken->pci_subsys == subsys ) ||
901 ( broken->pci_subsys == PCI_ANY_ID ) ) ) {
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 );
906 return 1;
907 }
908 }
909
910 /* Check for a PCI Express capability. Given the number of
911 * issues found with legacy INTx emulation on PCIe systems, we
912 * assume that there is a high chance of interrupts not
913 * working on any PCIe device.
914 */
915 if ( pci_find_capability ( &pci, PCI_CAP_ID_EXP ) ) {
916 DBGC ( undinic, "UNDINIC %p is PCI Express: assuming "
917 "interrupts are unreliable\n", undinic );
918 return 1;
919 }
920
921 return 0;
922}
923
924/**
925 * Probe UNDI device
926 *
927 * @v undi UNDI device
928 * @v dev Underlying generic device
929 * @ret rc Return status code
930 */
931int undinet_probe ( struct undi_device *undi, struct device *dev ) {
932 struct net_device *netdev;
933 struct undi_nic *undinic;
934 struct s_PXENV_START_UNDI start_undi;
935 struct s_PXENV_UNDI_STARTUP undi_startup;
936 struct s_PXENV_UNDI_INITIALIZE undi_init;
937 struct s_PXENV_UNDI_GET_INFORMATION undi_info;
938 struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
939 struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
940 struct s_PXENV_UNDI_CLEANUP undi_cleanup;
941 struct s_PXENV_STOP_UNDI stop_undi;
942 unsigned int retry;
943 int rc;
944
945 /* Allocate net device */
946 netdev = alloc_etherdev ( sizeof ( *undinic ) );
947 if ( ! netdev )
948 return -ENOMEM;
950 undinic = netdev->priv;
951 undi_set_drvdata ( undi, netdev );
952 netdev->dev = dev;
953 memset ( undinic, 0, sizeof ( *undinic ) );
955 DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
956
957 /* Hook in UNDI stack */
958 if ( ! ( undi->flags & UNDI_FL_STARTED ) ) {
959 memset ( &start_undi, 0, sizeof ( start_undi ) );
960 start_undi.AX = undi->pci_busdevfn;
961 start_undi.BX = undi->isapnp_csn;
962 start_undi.DX = undi->isapnp_read_port;
963 start_undi.ES = BIOS_SEG;
964 start_undi.DI = find_pnp_bios();
965 if ( ( rc = undinet_call ( undinic, PXENV_START_UNDI,
966 &start_undi,
967 sizeof ( start_undi ) ) ) != 0 )
968 goto err_start_undi;
969 }
970 undi->flags |= UNDI_FL_STARTED;
971
972 /* Bring up UNDI stack */
973 if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
974 memset ( &undi_startup, 0, sizeof ( undi_startup ) );
975 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
976 &undi_startup,
977 sizeof ( undi_startup ) ) ) != 0 )
978 goto err_undi_startup;
979 /* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
980 * due to a transient condition (e.g. media test
981 * failing because the link has only just come out of
982 * reset). We may therefore need to retry this call
983 * several times.
984 */
985 for ( retry = 0 ; ; ) {
986 memset ( &undi_init, 0, sizeof ( undi_init ) );
987 if ( ( rc = undinet_call ( undinic,
989 &undi_init,
990 sizeof ( undi_init ) ) ) ==0)
991 break;
992 if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
993 goto err_undi_initialize;
994 DBGC ( undinic, "UNDINIC %p retrying "
995 "PXENV_UNDI_INITIALIZE (retry %d)\n",
996 undinic, retry );
997 /* Delay to allow link to settle if necessary */
999 }
1000 }
1001 undi->flags |= UNDI_FL_INITIALIZED;
1002
1003 /* Get device information */
1004 memset ( &undi_info, 0, sizeof ( undi_info ) );
1005 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_INFORMATION,
1006 &undi_info, sizeof ( undi_info ) ) ) != 0 )
1007 goto err_undi_get_information;
1008 memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
1009 memcpy ( netdev->ll_addr, undi_info.CurrentNodeAddress, ETH_ALEN );
1010 undinic->irq = undi_info.IntNumber;
1011 if ( undinic->irq > IRQ_MAX ) {
1012 DBGC ( undinic, "UNDINIC %p ignoring invalid IRQ %d\n",
1013 undinic, undinic->irq );
1014 undinic->irq = 0;
1015 }
1016 DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
1017 undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
1018 if ( undinic->irq ) {
1019 /* Sanity check - prefix should have disabled the IRQ */
1020 assert ( ! irq_enabled ( undinic->irq ) );
1021 }
1022
1023 /* Get interface information */
1024 memset ( &undi_iface, 0, sizeof ( undi_iface ) );
1025 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
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",
1029 undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
1030 undi_iface.ServiceFlags );
1031 if ( ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) &&
1032 ( undinic->irq != 0 ) ) {
1033 undinic->irq_supported = 1;
1034 }
1035 DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
1036 ( undinic->irq_supported ? "interrupt" : "polling" ) );
1037 if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
1038 sizeof ( undi_iface.IfaceType ) ) == 0 ) {
1039 DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
1040 undinic );
1041 undinic->hacks |= UNDI_HACK_EB54;
1042 }
1043 if ( undinet_irq_is_broken ( netdev ) ) {
1044 DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
1045 "broken interrupts\n", undinic );
1046 undinic->irq_supported = 0;
1047 }
1048
1049 /* Register network device */
1050 if ( ( rc = register_netdev ( netdev ) ) != 0 )
1051 goto err_register;
1052
1053 /* Mark as link up; we don't handle link state */
1055
1056 DBGC ( undinic, "UNDINIC %p added\n", undinic );
1057 return 0;
1058
1059 err_register:
1060 err_undi_get_iface_info:
1061 err_undi_get_information:
1062 err_undi_initialize:
1063 /* Shut down UNDI stack */
1064 memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
1065 undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
1066 sizeof ( undi_shutdown ) );
1067 memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
1068 undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
1069 sizeof ( undi_cleanup ) );
1070 undi->flags &= ~UNDI_FL_INITIALIZED;
1071 err_undi_startup:
1072 /* Unhook UNDI stack */
1073 memset ( &stop_undi, 0, sizeof ( stop_undi ) );
1074 undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
1075 sizeof ( stop_undi ) );
1076 undi->flags &= ~UNDI_FL_STARTED;
1077 err_start_undi:
1079 netdev_put ( netdev );
1080 undi_set_drvdata ( undi, NULL );
1081 return rc;
1082}
1083
1084/**
1085 * Remove UNDI device
1086 *
1087 * @v undi UNDI device
1088 */
1089void undinet_remove ( struct undi_device *undi ) {
1090 struct net_device *netdev = undi_get_drvdata ( undi );
1091 struct undi_nic *undinic = netdev->priv;
1092 struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
1093 struct s_PXENV_UNDI_CLEANUP undi_cleanup;
1094 struct s_PXENV_STOP_UNDI stop_undi;
1095
1096 /* Unregister net device */
1098
1099 /* If we are preparing for an OS boot, or if we cannot exit
1100 * via the PXE stack, then shut down the PXE stack.
1101 */
1102 if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
1103
1104 /* Shut down UNDI stack */
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 ) );
1111 undi->flags &= ~UNDI_FL_INITIALIZED;
1112
1113 /* Unhook UNDI stack */
1114 memset ( &stop_undi, 0, sizeof ( stop_undi ) );
1115 undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
1116 sizeof ( stop_undi ) );
1117 undi->flags &= ~UNDI_FL_STARTED;
1118 }
1119
1120 /* Clear entry point */
1122
1123 /* Free network device */
1125 netdev_put ( netdev );
1126
1127 DBGC ( undinic, "UNDINIC %p removed\n", undinic );
1128}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
__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))
unsigned short uint16_t
Definition stdint.h:11
unsigned long intptr_t
Definition stdint.h:21
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
void * discard_D
Definition bigint.h:32
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define basemem_packet
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
Definition biosint.c:25
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
Definition biosint.c:70
struct bofm_section_header done
Definition bofm_test.c:46
#define BUS_TYPE_PCI
PCI bus type.
Definition device.h:44
ring len
Length.
Definition dwmac.h:226
uint8_t function
Function.
Definition edd.h:5
uint8_t flags
Flags.
Definition ena.h:7
struct ena_llq_option desc
Descriptor counts.
Definition ena.h:9
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition ethernet.c:265
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition ethernet.c:176
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.
Definition ethernet.c:102
Ethernet protocol.
static struct net_device * netdev
Definition gdbudp.c:53
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition pxe_types.h:45
UINT16_t PXENV_EXIT_t
A PXE exit code.
Definition pxe_types.h:44
#define PXENV_GET_CACHED_INFO
PXE API function code for pxenv_get_cached_info()
Definition pxe_api.h:270
#define PXENV_START_UNDI
PXE API function code for pxenv_start_undi()
Definition pxe_api.h:435
#define PXENV_STOP_UNDI
PXE API function code for pxenv_stop_undi()
Definition pxe_api.h:505
#define PXENV_UNDI_CLEANUP
PXE API function code for pxenv_undi_cleanup()
Definition pxe_api.h:841
#define PXENV_UNDI_CLEAR_STATISTICS
PXE API function code for pxenv_undi_clear_statistics()
Definition pxe_api.h:1221
#define PXENV_UNDI_CLOSE
PXE API function code for pxenv_undi_close()
Definition pxe_api.h:990
#define PXENV_UNDI_FORCE_INTERRUPT
PXE API function code for pxenv_undi_force_interrupt()
Definition pxe_api.h:1259
#define PXENV_UNDI_GET_IFACE_INFO
PXE API function code for pxenv_undi_get_iface_info()
Definition pxe_api.h:1359
#define SUPPORTED_IRQ
Interrupt Request supported.
Definition pxe_api.h:1378
#define PXENV_UNDI_GET_INFORMATION
PXE API function code for pxenv_undi_get_information()
Definition pxe_api.h:1155
#define PXENV_UNDI_GET_MCAST_ADDRESS
PXE API function code for pxenv_undi_get_mcast_address()
Definition pxe_api.h:1278
#define PXENV_UNDI_GET_NIC_TYPE
PXE API function code for pxenv_undi_get_nic_type()
Definition pxe_api.h:1299
#define PXENV_UNDI_GET_STATISTICS
PXE API function code for pxenv_undi_get_statistics()
Definition pxe_api.h:1198
#define PXENV_UNDI_INITIALIZE
PXE API function code for pxenv_undi_initialize()
Definition pxe_api.h:860
#define PXENV_UNDI_INITIATE_DIAGS
PXE API function code for pxenv_undi_initiate_diags()
Definition pxe_api.h:1240
#define PXENV_UNDI_ISR_OUT_DONE
Finished processing interrupt.
Definition pxe_api.h:1463
#define PXENV_UNDI_ISR_IN_GET_NEXT
Continue processing interrupt.
Definition pxe_api.h:1457
#define PXENV_UNDI_ISR_OUT_RECEIVE
A packet has been received.
Definition pxe_api.h:1467
#define PXENV_UNDI_ISR
PXE API function code for pxenv_undi_isr()
Definition pxe_api.h:1450
#define PXENV_UNDI_ISR_OUT_TRANSMIT
A packet transmission has completed.
Definition pxe_api.h:1465
#define PXENV_UNDI_ISR_IN_PROCESS
Start processing interrupt.
Definition pxe_api.h:1455
#define FLTR_PRMSCS
Accept all packets; listen in promiscuous mode.
Definition pxe_api.h:953
#define FLTR_BRDCST
Accept broadcast packets.
Definition pxe_api.h:951
#define FLTR_DIRECTED
Accept "directed" packets.
Definition pxe_api.h:949
#define PXENV_UNDI_OPEN
PXE API function code for pxenv_undi_open()
Definition pxe_api.h:941
#define PXENV_UNDI_RESET_ADAPTER
PXE API function code for pxenv_undi_reset_adapter()
Definition pxe_api.h:888
#define PXENV_UNDI_SET_MCAST_ADDRESS
PXE API function code for pxenv_undi_set_mcast_address()
Definition pxe_api.h:1084
#define PXENV_UNDI_SET_PACKET_FILTER
PXE API function code for pxenv_undi_set_packet_filter()
Definition pxe_api.h:1125
#define PXENV_UNDI_SET_STATION_ADDRESS
PXE API function code for pxenv_undi_set_station_address()
Definition pxe_api.h:1105
#define PXENV_UNDI_SHUTDOWN
PXE API function code for pxenv_undi_shutdown()
Definition pxe_api.h:922
#define PXENV_UNDI_STARTUP
PXE API function code for pxenv_undi_startup()
Definition pxe_api.h:815
#define P_RARP
RARP protocol.
Definition pxe_api.h:1014
#define PXENV_UNDI_TRANSMIT
PXE API function code for pxenv_undi_transmit()
Definition pxe_api.h:1009
#define P_IP
IP protocol.
Definition pxe_api.h:1012
#define XMT_DESTADDR
Unicast packet.
Definition pxe_api.h:1017
#define P_UNKNOWN
Media header already filled in.
Definition pxe_api.h:1011
#define XMT_BROADCAST
Broadcast packet.
Definition pxe_api.h:1018
#define P_ARP
ARP protocol.
Definition pxe_api.h:1013
#define UNDI_HACK_EB54
Work around Etherboot 5.4 bugs.
Definition undinet.c:71
#define ETH_ALEN
Definition if_ether.h:9
#define ETH_P_RARP
Definition if_ether.h:21
#define ETH_P_IP
Definition if_ether.h:19
#define ETH_P_ARP
Definition if_ether.h:20
#define htons(value)
Definition byteswap.h:136
#define __attribute__(x)
Definition compiler.h:10
iPXE I/O API
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
Profiling.
#define __profiler
Declare a profiler.
Definition profile.h:61
static void profile_stop_at(struct profiler *profiler, unsigned long stopped)
Stop profiling.
Definition profile.h:146
static void profile_stop(struct profiler *profiler)
Stop profiling.
Definition profile.h:174
static unsigned long profile_started(struct profiler *profiler)
Get start time.
Definition profile.h:80
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
Definition profile.h:132
static void profile_start(struct profiler *profiler)
Start profiling.
Definition profile.h:161
static unsigned long profile_stopped(struct profiler *profiler)
Get stop time.
Definition profile.h:97
String functions.
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
Definition init.c:38
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_push(iobuf, len)
Definition iobuf.h:89
#define iob_put(iobuf, len)
Definition iobuf.h:125
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_reserve(iobuf, len)
Definition iobuf.h:72
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
Definition iobuf.h:180
#define rm_ds
Definition libkir.h:39
#define __data16(variable)
Definition libkir.h:14
#define REAL_CODE(asm_code_str)
Definition libkir.h:226
#define __bss16(variable)
Definition libkir.h:16
#define __data16_array(variable, array)
Definition libkir.h:15
#define __from_data16(pointer)
Definition libkir.h:22
#define copy_from_real
Definition libkir.h:79
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition netdevice.c:549
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition netdevice.c:942
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition netdevice.c:587
int register_netdev(struct net_device *netdev)
Register network device.
Definition netdevice.c:760
Network device management.
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition netdevice.h:789
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition netdevice.h:519
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition netdevice.h:532
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
#define LL_BROADCAST
Packet is a broadcast packet.
Definition netdevice.h:109
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition netdevice.h:767
PCI bus.
#define PCI_ANY_ID
Match-anything ID.
Definition pci.h:187
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
Definition pci.h:79
static void pci_init(struct pci_device *pci, unsigned int busdevfn)
Initialise PCI device.
Definition pci.h:341
#define PCI_CAP_ID_EXP
PCI Express.
Definition pci.h:98
#define PCI_SUBSYSTEM_VENDOR_ID
PCI subsystem vendor ID.
Definition pci.h:76
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition pciextra.c:39
void send_eoi(unsigned int irq)
Send End-Of-Interrupt to the PIC.
Definition pic8259.c:65
#define IMR_REG(x)
Definition pic8259.h:48
#define IRQ_INT(irq)
Definition pic8259.h:57
#define IRQ_MAX
Definition pic8259.h:60
#define IMR_BIT(x)
Definition pic8259.h:49
int find_pnp_bios(void)
Locate Plug-and-Play BIOS.
Definition pnpbios.c:101
PnP BIOS.
#define BIOS_SEG
Definition pnpbios.h:13
__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.
Definition pxe.h:13
uint16_t protocol
Protocol ID.
Definition stp.h:7
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition string.c:187
A hardware device description.
Definition device.h:20
A hardware device.
Definition device.h:77
An Ethernet link-layer header.
Definition if_ether.h:32
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
Network device operations.
Definition netdevice.h:214
A network device.
Definition netdevice.h:353
A PCI device.
Definition pci.h:211
struct device dev
Generic device.
Definition pci.h:213
A data structure for storing profiling information.
Definition profile.h:27
Parameter block for pxenv_start_undi()
Definition pxe_api.h:438
SEGSEL_t ES
es register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:490
UINT16_t DX
dx register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:462
OFF16_t DI
di register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:476
UINT16_t BX
bx register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:453
UINT16_t AX
ax register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:446
Parameter block for pxenv_stop_undi()
Definition pxe_api.h:508
Parameter block for pxenv_undi_cleanup()
Definition pxe_api.h:844
Parameter block for pxenv_undi_close()
Definition pxe_api.h:993
Parameter block for pxenv_undi_get_iface_info()
Definition pxe_api.h:1381
UINT32_t LinkSpeed
Link speed, in bits per second.
Definition pxe_api.h:1394
UINT32_t ServiceFlags
Service flags.
Definition pxe_api.h:1401
UINT8_t IfaceType[16]
Interface type.
Definition pxe_api.h:1393
Parameter block for pxenv_undi_get_information()
Definition pxe_api.h:1166
MAC_ADDR_t CurrentNodeAddress
Current MAC address.
Definition pxe_api.h:1179
MAC_ADDR_t PermNodeAddress
Permanent (EEPROM) MAC address.
Definition pxe_api.h:1180
UINT16_t IntNumber
IRQ number.
Definition pxe_api.h:1169
Parameter block for pxenv_undi_initialize()
Definition pxe_api.h:863
Parameter block for pxenv_undi_isr()
Definition pxe_api.h:1479
UINT16_t FrameHeaderLength
Frame header length.
Definition pxe_api.h:1492
UINT16_t FrameLength
Total frame length.
Definition pxe_api.h:1491
UINT16_t BufferLength
Data buffer length.
Definition pxe_api.h:1490
UINT16_t FuncFlag
Function flag.
Definition pxe_api.h:1489
SEGOFF16_t Frame
Data buffer address.
Definition pxe_api.h:1493
Parameter block for pxenv_undi_open()
Definition pxe_api.h:958
UINT16_t PktFilter
Receive packet filter.
Definition pxe_api.h:973
Parameter block for pxenv_undi_set_station_address()
Definition pxe_api.h:1108
MAC_ADDR_t StationAddress
Station MAC address.
Definition pxe_api.h:1110
Parameter block for pxenv_undi_shutdown()
Definition pxe_api.h:925
Parameter block for pxenv_undi_startup()
Definition pxe_api.h:825
A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD.
Definition pxe_api.h:1025
Parameter block for pxenv_undi_transmit()
Definition pxe_api.h:1049
UINT8_t Protocol
Protocol.
Definition pxe_api.h:1057
SEGOFF16_t TBD
Address of the Transmit Buffer Descriptor.
Definition pxe_api.h:1068
UINT8_t XmitFlag
Unicast/broadcast flag.
Definition pxe_api.h:1062
SEGOFF16_t DestAddr
Destination MAC address.
Definition pxe_api.h:1063
An UNDI device.
Definition undi.h:22
UINT16_t pci_busdevfn
PCI bus:dev.fn, or UNDI_NO_PCI_BUSDEVFN.
Definition undi.h:34
UINT16_t isapnp_csn
ISAPnP card select number, or UNDI_NO_ISAPNP_CSN.
Definition undi.h:36
UINT16_t isapnp_read_port
ISAPnP read port, or UNDI_NO_ISAPNP_READ_PORT.
Definition undi.h:38
UINT16_t flags
Flags.
Definition undi.h:54
SEGOFF16_t entry
Entry point.
Definition undi.h:28
An UNDI NIC.
Definition undinet.c:48
int hacks
Bug workarounds.
Definition undinet.c:56
int isr_processing
Currently processing ISR.
Definition undinet.c:54
unsigned int irq
Assigned IRQ number.
Definition undinet.c:52
int irq_supported
Device supports IRQs.
Definition undinet.c:50
A device with broken support for generating interrupts.
Definition undinet.c:836
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
Definition undinet.c:842
uint16_t pci_subsys
PCI subsystem ID.
Definition undinet.c:844
uint16_t pci_device
PCI device ID.
Definition undinet.c:840
uint16_t pci_vendor
PCI vendor ID.
Definition undinet.c:838
A PXE API call breakdown profiler.
Definition undinet.c:123
struct profiler p2r
Time spent transitioning to real mode.
Definition undinet.c:127
struct profiler r2p
Time spent transitioning back to protected mode.
Definition undinet.c:131
struct profiler ext
Time spent in external code.
Definition undinet.c:129
struct profiler total
Total time spent performing REAL_CALL()
Definition undinet.c:125
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
int32_t after
Final microcode version.
Definition ucode.h:7
int32_t before
Initial microcode version.
Definition ucode.h:5
UNDI driver.
#define UNDI_FL_KEEP_ALL
UNDI flag: keep stack resident.
Definition undi.h:102
static void undi_set_drvdata(struct undi_device *undi, void *priv)
Set UNDI driver-private data.
Definition undi.h:70
#define UNDI_FL_INITIALIZED
UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called.
Definition undi.h:99
static void * undi_get_drvdata(struct undi_device *undi)
Get UNDI driver-private data.
Definition undi.h:80
#define UNDI_FL_STARTED
UNDI flag: START_UNDI has been called.
Definition undi.h:96
static int undinet_call(struct undi_nic *undinic, unsigned int function, void *params, size_t params_len)
Issue UNDI API call.
Definition undinet.c:278
static void undinet_hook_isr(unsigned int irq)
Hook UNDI interrupt service routine.
Definition undinet.c:404
#define undiisr_bit
Definition undinet.c:382
#define UNDI_RX_QUOTA
Maximum number of received packets per poll.
Definition undinet.c:82
static struct net_device_operations undinet_operations
UNDI network device operations.
Definition undinet.c:827
#define UNDI_INITIALIZE_RETRY_DELAY_MS
Delay between retries of PXENV_UNDI_INITIALIZE.
Definition undinet.c:79
static void undinet_close(struct net_device *netdev)
Close NIC.
Definition undinet.c:775
static const struct undinet_irq_broken undinet_irq_broken_list[]
List of devices with broken support for generating interrupts.
Definition undinet.c:858
static void undinet_unhook_isr(unsigned int irq)
Unhook UNDI interrupt service routine.
Definition undinet.c:422
static int undinet_isr_triggered(void)
Test to see if UNDI ISR has been triggered.
Definition undinet.c:436
#define undiisr_rearm
Definition undinet.c:386
static int undinet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
Definition undinet.c:474
static void undinet_poll(struct net_device *netdev)
Poll for received packets.
Definition undinet.c:588
#define undiisr_trigger_count
Definition undinet.c:394
#define UNDI_RX_ALIGN
Alignment of received frame payload.
Definition undinet.c:85
#define undinet_tbd
Definition undinet.c:461
#define undinet_destaddr
Definition undinet.c:465
#define undiisr_imr
Definition undinet.c:378
#define UNDI_INITIALIZE_RETRY_MAX
Maximum number of times to retry PXENV_UNDI_INITIALIZE.
Definition undinet.c:76
static struct undinet_profiler * undinet_profiler(unsigned int function)
Determine applicable profiler pair (for debugging)
Definition undinet.c:254
int undinet_probe(struct undi_device *undi, struct device *dev)
Probe UNDI device.
Definition undinet.c:931
static int undinet_open(struct net_device *netdev)
Open NIC.
Definition undinet.c:728
#define undiisr_next_handler
Definition undinet.c:390
static unsigned int last_trigger_count
Last observed trigger count.
Definition undinet.c:397
#define RDTSC_IF_PROFILING
Definition undinet.c:111
#define undinet_params
Definition undinet.c:96
void undiisr(void)
UNDI interrupt service routine.
#define EPXECALL(status)
Definition undinet.c:63
#define undiisr_irq
Definition undinet.c:374
void undinet_remove(struct undi_device *undi)
Remove UNDI device.
Definition undinet.c:1089
#define undinet_entry_point
Definition undinet.c:105
static void undinet_irq(struct net_device *netdev, int enable)
Enable/disable interrupts.
Definition undinet.c:818
static int undinet_irq_is_broken(struct net_device *netdev)
Check for devices with broken support for generating interrupts.
Definition undinet.c:874
static const char * undinet_function_name(unsigned int function)
Name PXE API call.
Definition undinet.c:189
UNDI network device driver.