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 
20 FILE_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 */
48 struct 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 
87 static 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  */
95 static union u_PXENV_ANY __bss16 ( undinet_params );
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  */
104 SEGOFF16_t __bss16 ( undinet_entry_point );
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 */
115 static struct profiler undinet_irq_profiler __profiler =
116  { .name = "undinet.irq" };
117 
118 /** Receive profiler */
119 static 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() */
125  struct profiler total;
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 */
135 static 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  */
148 static 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  */
160 static 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 */
168 static 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  */
188 static inline __attribute__ (( always_inline )) const char *
189 undinet_function_name ( unsigned int function ) {
190  switch ( function ) {
191  case PXENV_START_UNDI:
192  return "PXENV_START_UNDI";
193  case PXENV_STOP_UNDI:
194  return "PXENV_STOP_UNDI";
195  case PXENV_UNDI_STARTUP:
196  return "PXENV_UNDI_STARTUP";
197  case PXENV_UNDI_CLEANUP:
198  return "PXENV_UNDI_CLEANUP";
200  return "PXENV_UNDI_INITIALIZE";
202  return "PXENV_UNDI_RESET_ADAPTER";
203  case PXENV_UNDI_SHUTDOWN:
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";
209  case PXENV_UNDI_TRANSMIT:
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  */
254 static struct undinet_profiler * undinet_profiler ( unsigned int function ) {
255 
256  /* Determine applicable profiler */
257  switch ( function ) {
258  case PXENV_UNDI_TRANSMIT:
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  */
278 static int undinet_call ( struct undi_nic *undinic, unsigned int function,
279  void *params, size_t params_len ) {
280  struct undinet_profiler *profiler = undinet_profiler ( function );
281  PXENV_EXIT_t exit;
284  uint32_t stopped;
285  uint32_t after;
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 );
317  profile_start_at ( &profiler->p2r, before );
318  profile_stop_at ( &profiler->p2r, started );
319  profile_start_at ( &profiler->ext, started );
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,
340  undinet_function_name ( function ), strerror ( rc ) );
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  */
370 extern 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 */
393 volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
394 #define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
395 
396 /** Last observed trigger count */
397 static unsigned int last_trigger_count = 0;
398 
399 /**
400  * Hook UNDI interrupt service routine
401  *
402  * @v irq IRQ number
403  */
404 static 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  */
422 static void undinet_unhook_isr ( unsigned int irq ) {
423 
424  assert ( irq <= IRQ_MAX );
425 
426  unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( intptr_t ) undiisr ),
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  */
436 static 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 */
460 static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
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  */
474 static 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 ) :
517  protocol = 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  */
588 static 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 ) {
642  netdev_rx_err ( netdev, NULL, rc );
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  */
728 static 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 ) );
757  undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
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:
766  undinet_close ( netdev );
767  return rc;
768 }
769 
770 /**
771  * Close NIC
772  *
773  * @v netdev Net device
774  */
775 static 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  */
818 static 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  */
874 static int undinet_irq_is_broken ( struct net_device *netdev ) {
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  */
931 int 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 ) );
954  undinet_entry_point = undi->entry;
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 */
1054  netdev_link_up ( netdev );
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:
1078  netdev_nullify ( netdev );
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  */
1089 void 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 ) );
1106  undinet_call ( undinic, PXENV_UNDI_SHUTDOWN,
1107  &undi_shutdown, sizeof ( undi_shutdown ) );
1108  memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
1109  undinet_call ( undinic, PXENV_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 */
1121  memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
1122 
1123  /* Free network device */
1124  netdev_nullify ( netdev );
1125  netdev_put ( netdev );
1126 
1127  DBGC ( undinic, "UNDINIC %p removed\n", undinic );
1128 }
#define UNDI_HACK_EB54
Work around Etherboot 5.4 bugs.
Definition: undinet.c:71
#define undiisr_rearm
Definition: undinet.c:386
#define __attribute__(x)
Definition: compiler.h:10
#define PXENV_UNDI_SHUTDOWN
PXE API function code for pxenv_undi_shutdown()
Definition: pxe_api.h:922
#define EINVAL
Invalid argument.
Definition: errno.h:428
Parameter block for pxenv_undi_isr()
Definition: pxe_api.h:1479
#define PXENV_UNDI_FORCE_INTERRUPT
PXE API function code for pxenv_undi_force_interrupt()
Definition: pxe_api.h:1259
iPXE I/O API
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition: netdevice.h:766
#define iob_put(iobuf, len)
Definition: iobuf.h:124
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition: netdevice.c:586
A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD.
Definition: pxe_api.h:1025
FILE_LICENCE(GPL2_OR_LATER)
#define SUPPORTED_IRQ
Interrupt Request supported.
Definition: pxe_api.h:1378
#define P_IP
IP protocol.
Definition: pxe_api.h:1012
#define PXENV_UNDI_CLEANUP
PXE API function code for pxenv_undi_cleanup()
Definition: pxe_api.h:841
#define IMR_BIT(x)
Definition: pic8259.h:49
UINT16_t IntNumber
IRQ number.
Definition: pxe_api.h:1169
#define PXENV_UNDI_SET_STATION_ADDRESS
PXE API function code for pxenv_undi_set_station_address()
Definition: pxe_api.h:1105
An UNDI NIC.
Definition: undinet.c:48
int(* open)(struct net_device *netdev)
Open network device.
Definition: netdevice.h:222
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition: pciextra.c:38
#define PXENV_START_UNDI
PXE API function code for pxenv_start_undi()
Definition: pxe_api.h:435
#define PXENV_UNDI_CLEAR_STATISTICS
PXE API function code for pxenv_undi_clear_statistics()
Definition: pxe_api.h:1221
#define undiisr_trigger_count
Definition: undinet.c:394
#define PXENV_STOP_UNDI
PXE API function code for pxenv_stop_undi()
Definition: pxe_api.h:505
#define iob_push(iobuf, len)
Definition: iobuf.h:88
I/O buffers.
#define PXENV_UNDI_GET_MCAST_ADDRESS
PXE API function code for pxenv_undi_get_mcast_address()
Definition: pxe_api.h:1278
#define FLTR_PRMSCS
Accept all packets; listen in promiscuous mode.
Definition: pxe_api.h:953
#define ETH_P_IP
Definition: if_ether.h:18
int undinet_probe(struct undi_device *undi, struct device *dev)
Probe UNDI device.
Definition: undinet.c:931
#define DBGC(...)
Definition: compiler.h:505
Parameter block for pxenv_undi_initialize()
Definition: pxe_api.h:863
#define PXENV_UNDI_GET_IFACE_INFO
PXE API function code for pxenv_undi_get_iface_info()
Definition: pxe_api.h:1359
#define EPXECALL(status)
Definition: undinet.c:63
static void undinet_poll(struct net_device *netdev)
Poll for received packets.
Definition: undinet.c:588
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
Definition: undinet.c:842
Parameter block for pxenv_undi_transmit()
Definition: pxe_api.h:1049
int32_t before
Initial microcode version.
Definition: ucode.h:16
#define PXENV_UNDI_SET_MCAST_ADDRESS
PXE API function code for pxenv_undi_set_mcast_address()
Definition: pxe_api.h:1084
#define UNDI_FL_INITIALIZED
UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called.
Definition: undi.h:99
void send_eoi(unsigned int irq)
Send End-Of-Interrupt to the PIC.
Definition: pic8259.c:65
static int undinet_irq_is_broken(struct net_device *netdev)
Check for devices with broken support for generating interrupts.
Definition: undinet.c:874
UINT16_t flags
Flags.
Definition: undi.h:54
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.
Definition: undi.h:80
static unsigned long profile_started(struct profiler *profiler)
Get start time.
Definition: profile.h:79
UNDI network device driver.
UNDI driver.
UINT32_t ServiceFlags
Service flags.
Definition: pxe_api.h:1401
A data structure for storing profiling information.
Definition: profile.h:26
#define rm_ds
Definition: libkir.h:39
#define XMT_BROADCAST
Broadcast packet.
Definition: pxe_api.h:1018
unsigned long intptr_t
Definition: stdint.h:21
UINT16_t PktFilter
Receive packet filter.
Definition: pxe_api.h:973
#define PXENV_UNDI_GET_NIC_TYPE
PXE API function code for pxenv_undi_get_nic_type()
Definition: pxe_api.h:1299
static void profile_stop(struct profiler *profiler)
Stop profiling.
Definition: profile.h:173
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition: string.c:186
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:130
UINT16_t FuncFlag
Function flag.
Definition: pxe_api.h:1489
#define undiisr_imr
Definition: undinet.c:378
UINT32_t LinkSpeed
Link speed, in bits per second.
Definition: pxe_api.h:1394
static void undinet_close(struct net_device *netdev)
Close NIC.
Definition: undinet.c:775
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
Definition: pci.h:78
struct device dev
Generic device.
Definition: pci.h:212
#define PXENV_UNKNOWN
PXE API invalid function code.
Definition: pxe.h:13
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:101
A hardware device description.
Definition: device.h:19
void undinet_remove(struct undi_device *undi)
Remove UNDI device.
Definition: undinet.c:1089
#define PXENV_UNDI_ISR_OUT_RECEIVE
A packet has been received.
Definition: pxe_api.h:1467
SEGSEL_t ES
es register as passed to the Option ROM initialisation routine.
Definition: pxe_api.h:490
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
Definition: biosint.c:25
Parameter block for pxenv_undi_close()
Definition: pxe_api.h:993
UINT16_t isapnp_csn
ISAPnP card select number, or UNDI_NO_ISAPNP_CSN.
Definition: undi.h:36
static struct profiler undinet_irq_profiler __profiler
IRQ profiler.
Definition: undinet.c:115
static void profile_stop_at(struct profiler *profiler, unsigned long stopped)
Stop profiling.
Definition: profile.h:145
static int undinet_isr_triggered(void)
Test to see if UNDI ISR has been triggered.
Definition: undinet.c:436
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition: netdevice.h:518
OFF16_t DI
di register as passed to the Option ROM initialisation routine.
Definition: pxe_api.h:476
struct ena_llq_option desc
Descriptor counts.
Definition: ena.h:20
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
Definition: biosint.c:70
#define PXENV_UNDI_ISR_IN_PROCESS
Start processing interrupt.
Definition: pxe_api.h:1455
#define ENOMEM
Not enough space.
Definition: errno.h:534
A hardware device.
Definition: device.h:76
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition: iobuf.h:216
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int started
"startup() has been called" flag
Definition: init.c:37
UINT16_t PXENV_EXIT_t
A PXE exit code.
Definition: pxe_types.h:44
const char * name
Name.
Definition: profile.h:28
uint16_t pci_vendor
PCI vendor ID.
Definition: undinet.c:838
static unsigned int last_trigger_count
Last observed trigger count.
Definition: undinet.c:397
UINT16_t FrameLength
Total frame length.
Definition: pxe_api.h:1491
MAC_ADDR_t PermNodeAddress
Permanent (EEPROM) MAC address.
Definition: pxe_api.h:1180
#define BUS_TYPE_PCI
PCI bus type.
Definition: device.h:43
static struct undinet_profiler * undinet_profiler(unsigned int function)
Determine applicable profiler pair (for debugging)
Definition: undinet.c:254
static int undinet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
Definition: undinet.c:474
#define PXENV_UNDI_CLOSE
PXE API function code for pxenv_undi_close()
Definition: pxe_api.h:990
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition: netdevice.h:575
Ethernet protocol.
UINT8_t Protocol
Protocol.
Definition: pxe_api.h:1057
void * priv
Driver private data.
Definition: netdevice.h:431
SEGOFF16_t DestAddr
Destination MAC address.
Definition: pxe_api.h:1063
#define DBGC_HDA(...)
Definition: compiler.h:506
UINT8_t XmitFlag
Unicast/broadcast flag.
Definition: pxe_api.h:1062
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition: netdevice.h:788
#define FLTR_BRDCST
Accept broadcast packets.
Definition: pxe_api.h:951
ring len
Length.
Definition: dwmac.h:231
Parameter block for pxenv_undi_set_station_address()
Definition: pxe_api.h:1108
#define UNDI_FL_KEEP_ALL
UNDI flag: keep stack resident.
Definition: undi.h:102
static struct net_device * netdev
Definition: gdbudp.c:52
static void undinet_hook_isr(unsigned int irq)
Hook UNDI interrupt service routine.
Definition: undinet.c:404
SEGOFF16_t Frame
Data buffer address.
Definition: pxe_api.h:1493
#define UNDI_RX_ALIGN
Alignment of received frame payload.
Definition: undinet.c:85
Parameter block for pxenv_undi_shutdown()
Definition: pxe_api.h:925
unsigned int irq
Assigned IRQ number.
Definition: undinet.c:52
static void profile_start(struct profiler *profiler)
Start profiling.
Definition: profile.h:160
UINT16_t BX
bx register as passed to the Option ROM initialisation routine.
Definition: pxe_api.h:453
Profiling.
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition: netdevice.c:941
#define PXENV_UNDI_ISR_OUT_TRANSMIT
A packet transmission has completed.
Definition: pxe_api.h:1465
Parameter block for pxenv_undi_startup()
Definition: pxe_api.h:825
#define PXENV_UNDI_TRANSMIT
PXE API function code for pxenv_undi_transmit()
Definition: pxe_api.h:1009
SEGOFF16_t entry
Entry point.
Definition: undi.h:28
uint8_t flags
Flags.
Definition: ena.h:18
#define basemem_packet
static uint8_t __data16_array(undinet_destaddr, [ETH_ALEN])
UNDI transmit destination address.
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
int hacks
Bug workarounds.
Definition: undinet.c:56
PCI bus.
A PCI device.
Definition: pci.h:210
int register_netdev(struct net_device *netdev)
Register network device.
Definition: netdevice.c:759
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:159
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:175
static const char * undinet_function_name(unsigned int function)
Name PXE API call.
Definition: undinet.c:189
static union u_PXENV_ANY __bss16(undinet_params)
UNDI parameter block.
#define IRQ_INT(irq)
Definition: pic8259.h:57
A network device.
Definition: netdevice.h:352
#define undiisr_irq
Definition: undinet.c:374
__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.
Definition: undi.h:38
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
Definition: iobuf.h:179
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition: netdevice.h:531
Parameter block for pxenv_undi_get_information()
Definition: pxe_api.h:1166
unsigned char uint8_t
Definition: stdint.h:10
#define PXENV_UNDI_GET_STATISTICS
PXE API function code for pxenv_undi_get_statistics()
Definition: pxe_api.h:1198
#define PXENV_UNDI_SET_PACKET_FILTER
PXE API function code for pxenv_undi_set_packet_filter()
Definition: pxe_api.h:1125
#define PXENV_UNDI_INITIATE_DIAGS
PXE API function code for pxenv_undi_initiate_diags()
Definition: pxe_api.h:1240
#define PXENV_UNDI_OPEN
PXE API function code for pxenv_undi_open()
Definition: pxe_api.h:941
static void undinet_irq(struct net_device *netdev, int enable)
Enable/disable interrupts.
Definition: undinet.c:818
#define XMT_DESTADDR
Unicast packet.
Definition: pxe_api.h:1017
void * discard_D
Definition: bigint.h:31
MAC_ADDR_t StationAddress
Station MAC address.
Definition: pxe_api.h:1110
#define ETH_ALEN
Definition: if_ether.h:8
struct profiler r2p
Time spent transitioning back to protected mode.
Definition: undinet.c:131
#define undiisr_bit
Definition: undinet.c:382
#define undinet_params
Definition: undinet.c:96
unsigned int uint32_t
Definition: stdint.h:12
An UNDI device.
Definition: undi.h:22
#define PXENV_UNDI_ISR_IN_GET_NEXT
Continue processing interrupt.
Definition: pxe_api.h:1457
struct profiler ext
Time spent in external code.
Definition: undinet.c:129
PnP BIOS.
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
#define undinet_destaddr
Definition: undinet.c:465
#define PCI_CAP_ID_EXP
PCI Express.
Definition: pci.h:97
Network device operations.
Definition: netdevice.h:213
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition: netdevice.c:548
struct device * dev
Underlying hardware device.
Definition: netdevice.h:364
#define LL_BROADCAST
Packet is a broadcast packet.
Definition: netdevice.h:108
UINT16_t pci_busdevfn
PCI bus:dev.fn, or UNDI_NO_PCI_BUSDEVFN.
Definition: undi.h:34
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
Network device management.
Parameter block for pxenv_undi_cleanup()
Definition: pxe_api.h:844
#define copy_from_real
Definition: libkir.h:79
#define RDTSC_IF_PROFILING
Definition: undinet.c:109
static const struct undinet_irq_broken undinet_irq_broken_list[]
List of devices with broken support for generating interrupts.
Definition: undinet.c:858
MAC_ADDR_t CurrentNodeAddress
Current MAC address.
Definition: pxe_api.h:1179
#define UNDI_INITIALIZE_RETRY_MAX
Maximum number of times to retry PXENV_UNDI_INITIALIZE.
Definition: undinet.c:76
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
#define undinet_tbd
Definition: undinet.c:461
#define iob_reserve(iobuf, len)
Definition: iobuf.h:71
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
Definition: profile.h:131
__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.
Definition: undinet.c:840
#define FLTR_DIRECTED
Accept "directed" packets.
Definition: pxe_api.h:949
static unsigned long profile_stopped(struct profiler *profiler)
Get stop time.
Definition: profile.h:96
#define PXENV_UNDI_RESET_ADAPTER
PXE API function code for pxenv_undi_reset_adapter()
Definition: pxe_api.h:888
#define __from_data16(pointer)
Definition: libkir.h:22
static void undinet_unhook_isr(unsigned int irq)
Unhook UNDI interrupt service routine.
Definition: undinet.c:422
struct profiler total
Total time spent performing REAL_CALL()
Definition: undinet.c:125
SEGOFF16_t TBD
Address of the Transmit Buffer Descriptor.
Definition: pxe_api.h:1068
int32_t after
Final microcode version.
Definition: ucode.h:18
void * data
Start of data.
Definition: iobuf.h:52
#define PXENV_UNDI_ISR
PXE API function code for pxenv_undi_isr()
Definition: pxe_api.h:1450
int find_pnp_bios(void)
Locate Plug-and-Play BIOS.
Definition: pnpbios.c:101
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition: ethernet.c:264
Parameter block for pxenv_undi_get_iface_info()
Definition: pxe_api.h:1381
#define undinet_entry_point
Definition: undinet.c:105
struct device_description desc
Device description.
Definition: device.h:82
#define P_RARP
RARP protocol.
Definition: pxe_api.h:1014
#define IMR_REG(x)
Definition: pic8259.h:48
uint8_t __data16(undiisr_irq)
IRQ number.
#define PXENV_GET_CACHED_INFO
PXE API function code for pxenv_get_cached_info()
Definition: pxe_api.h:270
int isr_processing
Currently processing ISR.
Definition: undinet.c:54
#define PXENV_UNDI_ISR_OUT_DONE
Finished processing interrupt.
Definition: pxe_api.h:1463
#define undiisr_next_handler
Definition: undinet.c:390
uint16_t protocol
Protocol ID.
Definition: stp.h:18
#define PCI_SUBSYSTEM_VENDOR_ID
PCI subsystem vendor ID.
Definition: pci.h:75
#define ETH_P_ARP
Definition: if_ether.h:19
static void undi_set_drvdata(struct undi_device *undi, void *priv)
Set UNDI driver-private data.
Definition: undi.h:70
void undiisr(void)
UNDI interrupt service routine.
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:387
UINT8_t IfaceType[16]
Interface type.
Definition: pxe_api.h:1393
#define ETH_P_RARP
Definition: if_ether.h:20
#define P_ARP
ARP protocol.
Definition: pxe_api.h:1013
#define PXENV_UNDI_GET_INFORMATION
PXE API function code for pxenv_undi_get_information()
Definition: pxe_api.h:1155
Parameter block for pxenv_start_undi()
Definition: pxe_api.h:438
#define P_UNKNOWN
Media header already filled in.
Definition: pxe_api.h:1011
static void pci_init(struct pci_device *pci, unsigned int busdevfn)
Initialise PCI device.
Definition: pci.h:340
#define PXENV_UNDI_STARTUP
PXE API function code for pxenv_undi_startup()
Definition: pxe_api.h:815
#define UNDI_RX_QUOTA
Maximum number of received packets per poll.
Definition: undinet.c:82
UINT16_t AX
ax register as passed to the Option ROM initialisation routine.
Definition: pxe_api.h:446
#define PXENV_UNDI_INITIALIZE
PXE API function code for pxenv_undi_initialize()
Definition: pxe_api.h:860
uint16_t pci_subsys
PCI subsystem ID.
Definition: undinet.c:844
UINT16_t FrameHeaderLength
Frame header length.
Definition: pxe_api.h:1492
#define BIOS_SEG
Definition: pnpbios.h:13
static struct net_device_operations undinet_operations
UNDI network device operations.
Definition: undinet.c:827
An Ethernet link-layer header.
Definition: if_ether.h:31
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
Definition: netdevice.h:381
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
#define IRQ_MAX
Definition: pic8259.h:60
#define UNDI_INITIALIZE_RETRY_DELAY_MS
Delay between retries of PXENV_UNDI_INITIALIZE.
Definition: undinet.c:79
UINT16_t DX
dx register as passed to the Option ROM initialisation routine.
Definition: pxe_api.h:462
UINT16_t BufferLength
Data buffer length.
Definition: pxe_api.h:1490
#define UNDI_FL_STARTED
UNDI flag: START_UNDI has been called.
Definition: undi.h:96
#define htons(value)
Definition: byteswap.h:135
Parameter block for pxenv_stop_undi()
Definition: pxe_api.h:508
struct bofm_section_header done
Definition: bofm_test.c:46
Parameter block for pxenv_undi_open()
Definition: pxe_api.h:958
static int undinet_open(struct net_device *netdev)
Open NIC.
Definition: undinet.c:728
#define PCI_ANY_ID
Match-anything ID.
Definition: pci.h:186
A device with broken support for generating interrupts.
Definition: undinet.c:836
int irq_supported
Device supports IRQs.
Definition: undinet.c:50
A PXE API call breakdown profiler.
Definition: undinet.c:123
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:37
struct profiler p2r
Time spent transitioning to real mode.
Definition: undinet.c:127