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;
282  uint32_t before;
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 chain vector */
378 #define undiisr_next_handler __use_data16 ( undiisr_next_handler )
379 
380 /** IRQ trigger count */
381 volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
382 #define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
383 
384 /** Last observed trigger count */
385 static unsigned int last_trigger_count = 0;
386 
387 /**
388  * Hook UNDI interrupt service routine
389  *
390  * @v irq IRQ number
391  */
392 static void undinet_hook_isr ( unsigned int irq ) {
393 
394  assert ( irq <= IRQ_MAX );
395  assert ( undiisr_irq == 0 );
396 
397  undiisr_irq = irq;
398  hook_bios_interrupt ( IRQ_INT ( irq ), ( ( intptr_t ) undiisr ),
400 }
401 
402 /**
403  * Unhook UNDI interrupt service routine
404  *
405  * @v irq IRQ number
406  */
407 static void undinet_unhook_isr ( unsigned int irq ) {
408 
409  assert ( irq <= IRQ_MAX );
410 
411  unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( intptr_t ) undiisr ),
413  undiisr_irq = 0;
414 }
415 
416 /**
417  * Test to see if UNDI ISR has been triggered
418  *
419  * @ret triggered ISR has been triggered since last check
420  */
421 static int undinet_isr_triggered ( void ) {
422  unsigned int this_trigger_count;
423 
424  /* Read trigger_count. Do this only once; it is volatile */
425  this_trigger_count = undiisr_trigger_count;
426 
427  if ( this_trigger_count == last_trigger_count ) {
428  /* Not triggered */
429  return 0;
430  } else {
431  /* Triggered */
432  last_trigger_count = this_trigger_count;
433  return 1;
434  }
435 }
436 
437 /*****************************************************************************
438  *
439  * UNDI network device interface
440  *
441  *****************************************************************************
442  */
443 
444 /** UNDI transmit buffer descriptor */
445 static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
446 #define undinet_tbd __use_data16 ( undinet_tbd )
447 
448 /** UNDI transmit destination address */
450 #define undinet_destaddr __use_data16 ( undinet_destaddr )
451 
452 /**
453  * Transmit packet
454  *
455  * @v netdev Network device
456  * @v iobuf I/O buffer
457  * @ret rc Return status code
458  */
459 static int undinet_transmit ( struct net_device *netdev,
460  struct io_buffer *iobuf ) {
461  struct undi_nic *undinic = netdev->priv;
462  struct s_PXENV_UNDI_TRANSMIT undi_transmit;
463  const void *ll_dest;
464  const void *ll_source;
465  uint16_t net_proto;
466  unsigned int flags;
468  size_t len;
469  int rc;
470 
471  /* Technically, we ought to make sure that the previous
472  * transmission has completed before we re-use the buffer.
473  * However, many PXE stacks (including at least some Intel PXE
474  * stacks and Etherboot 5.4) fail to generate TX completions.
475  * In practice this won't be a problem, since our TX datapath
476  * has a very low packet volume and we can get away with
477  * assuming that a TX will be complete by the time we want to
478  * transmit the next packet.
479  */
480 
481  /* Some PXE stacks are unable to cope with P_UNKNOWN, and will
482  * always try to prepend a link-layer header. Work around
483  * these stacks by stripping the existing link-layer header
484  * and allowing the PXE stack to (re)construct the link-layer
485  * header itself.
486  */
487  if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
488  &net_proto, &flags ) ) != 0 ) {
489  DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
490  "%s\n", undinic, strerror ( rc ) );
491  return rc;
492  }
493  memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
494  switch ( net_proto ) {
495  case htons ( ETH_P_IP ) :
496  protocol = P_IP;
497  break;
498  case htons ( ETH_P_ARP ) :
499  protocol = P_ARP;
500  break;
501  case htons ( ETH_P_RARP ) :
502  protocol = P_RARP;
503  break;
504  default:
505  /* Unknown protocol; restore the original link-layer header */
506  iob_push ( iobuf, sizeof ( struct ethhdr ) );
508  break;
509  }
510 
511  /* Copy packet to UNDI I/O buffer */
512  len = iob_len ( iobuf );
513  if ( len > sizeof ( basemem_packet ) )
514  len = sizeof ( basemem_packet );
515  memcpy ( &basemem_packet, iobuf->data, len );
516 
517  /* Create PXENV_UNDI_TRANSMIT data structure */
518  memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
519  undi_transmit.Protocol = protocol;
520  undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
522  undi_transmit.DestAddr.segment = rm_ds;
523  undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
524  undi_transmit.TBD.segment = rm_ds;
525  undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
526 
527  /* Create PXENV_UNDI_TBD data structure */
528  undinet_tbd.ImmedLength = len;
529  undinet_tbd.Xmit.segment = rm_ds;
530  undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
531 
532  /* Issue PXE API call */
533  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_TRANSMIT, &undi_transmit,
534  sizeof ( undi_transmit ) ) ) != 0 )
535  goto done;
536 
537  /* Free I/O buffer */
538  netdev_tx_complete ( netdev, iobuf );
539  done:
540  return rc;
541 }
542 
543 /**
544  * Poll for received packets
545  *
546  * @v netdev Network device
547  *
548  * Fun, fun, fun. UNDI drivers don't use polling; they use
549  * interrupts. We therefore cheat and pretend that an interrupt has
550  * occurred every time undinet_poll() is called. This isn't too much
551  * of a hack; PCI devices share IRQs and so the first thing that a
552  * proper ISR should do is call PXENV_UNDI_ISR to determine whether or
553  * not the UNDI NIC generated the interrupt; there is no harm done by
554  * spurious calls to PXENV_UNDI_ISR. Similarly, we wouldn't be
555  * handling them any more rapidly than the usual rate of
556  * undinet_poll() being called even if we did implement a full ISR.
557  * So it should work. Ha!
558  *
559  * Addendum (21/10/03). Some cards don't play nicely with this trick,
560  * so instead of doing it the easy way we have to go to all the hassle
561  * of installing a genuine interrupt service routine and dealing with
562  * the wonderful 8259 Programmable Interrupt Controller. Joy.
563  *
564  * Addendum (10/07/07). When doing things such as iSCSI boot, in
565  * which we have to co-operate with a running OS, we can't get away
566  * with the "ISR-just-increments-a-counter-and-returns" trick at all,
567  * because it involves tying up the PIC for far too long, and other
568  * interrupt-dependent components (e.g. local disks) start breaking.
569  * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
570  * from within interrupt context in order to deassert the device
571  * interrupt, and sends EOI if applicable.
572  */
573 static void undinet_poll ( struct net_device *netdev ) {
574  struct undi_nic *undinic = netdev->priv;
575  struct s_PXENV_UNDI_ISR undi_isr;
576  struct io_buffer *iobuf = NULL;
577  unsigned int quota = UNDI_RX_QUOTA;
578  size_t len;
579  size_t reserve_len;
580  size_t frag_len;
581  size_t max_frag_len;
582  int rc;
583 
584  if ( ! undinic->isr_processing ) {
585  /* Allow interrupt to occur. Do this even if
586  * interrupts are not known to be supported, since
587  * some cards erroneously report that they do not
588  * support interrupts.
589  */
590  if ( ! undinet_isr_triggered() ) {
591  /* Allow interrupt to occur */
592  profile_start ( &undinet_irq_profiler );
593  __asm__ __volatile__ ( "sti\n\t"
594  "nop\n\t"
595  "nop\n\t"
596  "cli\n\t" );
597  profile_stop ( &undinet_irq_profiler );
598 
599  /* If interrupts are known to be supported,
600  * then do nothing on this poll; wait for the
601  * interrupt to be triggered.
602  */
603  if ( undinic->irq_supported )
604  return;
605  }
606 
607  /* Start ISR processing */
608  undinic->isr_processing = 1;
610  } else {
611  /* Continue ISR processing */
613  }
614 
615  /* Run through the ISR loop */
616  while ( quota ) {
617  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
618  sizeof ( undi_isr ) ) ) != 0 ) {
619  netdev_rx_err ( netdev, NULL, rc );
620  break;
621  }
622  switch ( undi_isr.FuncFlag ) {
624  /* We don't care about transmit completions */
625  break;
627  /* Packet fragment received */
628  profile_start ( &undinet_rx_profiler );
629  len = undi_isr.FrameLength;
630  frag_len = undi_isr.BufferLength;
631  reserve_len = ( -undi_isr.FrameHeaderLength &
632  ( UNDI_RX_ALIGN - 1 ) );
633  if ( ( len == 0 ) || ( len < frag_len ) ) {
634  /* Don't laugh. VMWare does it. */
635  DBGC ( undinic, "UNDINIC %p reported insane "
636  "fragment (%zd of %zd bytes)\n",
637  undinic, frag_len, len );
639  break;
640  }
641  if ( ! iobuf ) {
642  iobuf = alloc_iob ( reserve_len + len );
643  if ( ! iobuf ) {
644  DBGC ( undinic, "UNDINIC %p could not "
645  "allocate %zd bytes for RX "
646  "buffer\n", undinic, len );
647  /* Fragment will be dropped */
649  goto done;
650  }
651  iob_reserve ( iobuf, reserve_len );
652  }
653  max_frag_len = iob_tailroom ( iobuf );
654  if ( frag_len > max_frag_len ) {
655  DBGC ( undinic, "UNDINIC %p fragment too big "
656  "(%zd+%zd does not fit into %zd)\n",
657  undinic, iob_len ( iobuf ), frag_len,
658  ( iob_len ( iobuf ) + max_frag_len ) );
659  frag_len = max_frag_len;
660  }
661  copy_from_real ( iob_put ( iobuf, frag_len ),
662  undi_isr.Frame.segment,
663  undi_isr.Frame.offset, frag_len );
664  if ( iob_len ( iobuf ) == len ) {
665  /* Whole packet received; deliver it */
666  netdev_rx ( netdev, iob_disown ( iobuf ) );
667  quota--;
668  /* Etherboot 5.4 fails to return all packets
669  * under mild load; pretend it retriggered.
670  */
671  if ( undinic->hacks & UNDI_HACK_EB54 )
673  }
674  profile_stop ( &undinet_rx_profiler );
675  break;
677  /* Processing complete */
678  undinic->isr_processing = 0;
679  goto done;
680  default:
681  /* Should never happen. VMWare does it routinely. */
682  DBGC ( undinic, "UNDINIC %p ISR returned invalid "
683  "FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
684  undinic->isr_processing = 0;
685  goto done;
686  }
688  }
689 
690  done:
691  if ( iobuf ) {
692  DBGC ( undinic, "UNDINIC %p returned incomplete packet "
693  "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
694  ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
695  netdev_rx_err ( netdev, iobuf, -EINVAL );
696  }
697 }
698 
699 /**
700  * Open NIC
701  *
702  * @v netdev Net device
703  * @ret rc Return status code
704  */
705 static int undinet_open ( struct net_device *netdev ) {
706  struct undi_nic *undinic = netdev->priv;
707  struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
708  struct s_PXENV_UNDI_OPEN undi_open;
709  int rc;
710 
711  /* Hook interrupt service routine and enable interrupt if applicable */
712  if ( undinic->irq ) {
713  undinet_hook_isr ( undinic->irq );
714  enable_irq ( undinic->irq );
715  send_eoi ( undinic->irq );
716  }
717 
718  /* Set station address. Required for some PXE stacks; will
719  * spuriously fail on others. Ignore failures. We only ever
720  * use it to set the MAC address to the card's permanent value
721  * anyway.
722  */
723  memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
724  sizeof ( undi_set_address.StationAddress ) );
726  &undi_set_address, sizeof ( undi_set_address ) );
727 
728  /* Open NIC. We ask for promiscuous operation, since it's the
729  * only way to ask for all multicast addresses. On any
730  * switched network, it shouldn't really make a difference to
731  * performance.
732  */
733  memset ( &undi_open, 0, sizeof ( undi_open ) );
734  undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
735  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open,
736  sizeof ( undi_open ) ) ) != 0 )
737  goto err;
738 
739  DBGC ( undinic, "UNDINIC %p opened\n", undinic );
740  return 0;
741 
742  err:
743  undinet_close ( netdev );
744  return rc;
745 }
746 
747 /**
748  * Close NIC
749  *
750  * @v netdev Net device
751  */
752 static void undinet_close ( struct net_device *netdev ) {
753  struct undi_nic *undinic = netdev->priv;
754  struct s_PXENV_UNDI_ISR undi_isr;
755  struct s_PXENV_UNDI_CLOSE undi_close;
756  int rc;
757 
758  /* Ensure ISR has exited cleanly */
759  while ( undinic->isr_processing ) {
761  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
762  sizeof ( undi_isr ) ) ) != 0 )
763  break;
764  switch ( undi_isr.FuncFlag ) {
767  /* Continue draining */
768  break;
769  default:
770  /* Stop processing */
771  undinic->isr_processing = 0;
772  break;
773  }
774  }
775 
776  /* Close NIC */
777  undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close,
778  sizeof ( undi_close ) );
779 
780  /* Disable interrupt and unhook ISR if applicable */
781  if ( undinic->irq ) {
782  disable_irq ( undinic->irq );
783  undinet_unhook_isr ( undinic->irq );
784  }
785 
786  DBGC ( undinic, "UNDINIC %p closed\n", undinic );
787 }
788 
789 /**
790  * Enable/disable interrupts
791  *
792  * @v netdev Net device
793  * @v enable Interrupts should be enabled
794  */
795 static void undinet_irq ( struct net_device *netdev, int enable ) {
796  struct undi_nic *undinic = netdev->priv;
797 
798  /* Cannot support interrupts yet */
799  DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n",
800  undinic, ( enable ? "enable" : "disable" ) );
801 }
802 
803 /** UNDI network device operations */
805  .open = undinet_open,
806  .close = undinet_close,
807  .transmit = undinet_transmit,
808  .poll = undinet_poll,
809  .irq = undinet_irq,
810 };
811 
812 /** A device with broken support for generating interrupts */
814  /** PCI vendor ID */
816  /** PCI device ID */
818  /** PCI subsystem vendor ID */
820  /** PCI subsystem ID */
822 };
823 
824 /**
825  * List of devices with broken support for generating interrupts
826  *
827  * Some PXE stacks are known to claim that IRQs are supported, but
828  * then never generate interrupts. No satisfactory solution has been
829  * found to this problem; the workaround is to add the PCI vendor and
830  * device IDs to this list. This is something of a hack, since it
831  * will generate false positives for identical devices with a working
832  * PXE stack (e.g. those that have been reflashed with iPXE), but it's
833  * an improvement on the current situation.
834  */
836  /* HP XX70x laptops */
837  { 0x8086, 0x1502, PCI_ANY_ID, PCI_ANY_ID },
838  { 0x8086, 0x1503, PCI_ANY_ID, PCI_ANY_ID },
839  /* HP 745 G3 laptop */
840  { 0x14e4, 0x1687, PCI_ANY_ID, PCI_ANY_ID },
841 };
842 
843 /**
844  * Check for devices with broken support for generating interrupts
845  *
846  * @v desc Device description
847  * @ret irq_is_broken Interrupt support is broken; no interrupts are generated
848  */
849 static int undinet_irq_is_broken ( struct device_description *desc ) {
850  const struct undinet_irq_broken *broken;
851  struct pci_device pci;
852  uint16_t subsys_vendor;
853  uint16_t subsys;
854  unsigned int i;
855 
856  /* Ignore non-PCI devices */
857  if ( desc->bus_type != BUS_TYPE_PCI )
858  return 0;
859 
860  /* Read subsystem IDs */
861  pci_init ( &pci, desc->location );
862  pci_read_config_word ( &pci, PCI_SUBSYSTEM_VENDOR_ID, &subsys_vendor );
863  pci_read_config_word ( &pci, PCI_SUBSYSTEM_ID, &subsys );
864 
865  /* Check for a match against the broken device list */
866  for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
867  sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
868  broken = &undinet_irq_broken_list[i];
869  if ( ( broken->pci_vendor == desc->vendor ) &&
870  ( broken->pci_device == desc->device ) &&
871  ( ( broken->pci_subsys_vendor == subsys_vendor ) ||
872  ( broken->pci_subsys_vendor == PCI_ANY_ID ) ) &&
873  ( ( broken->pci_subsys == subsys ) ||
874  ( broken->pci_subsys == PCI_ANY_ID ) ) ) {
875  return 1;
876  }
877  }
878  return 0;
879 }
880 
881 /**
882  * Probe UNDI device
883  *
884  * @v undi UNDI device
885  * @v dev Underlying generic device
886  * @ret rc Return status code
887  */
888 int undinet_probe ( struct undi_device *undi, struct device *dev ) {
889  struct net_device *netdev;
890  struct undi_nic *undinic;
891  struct s_PXENV_START_UNDI start_undi;
892  struct s_PXENV_UNDI_STARTUP undi_startup;
893  struct s_PXENV_UNDI_INITIALIZE undi_init;
894  struct s_PXENV_UNDI_GET_INFORMATION undi_info;
895  struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
896  struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
897  struct s_PXENV_UNDI_CLEANUP undi_cleanup;
898  struct s_PXENV_STOP_UNDI stop_undi;
899  unsigned int retry;
900  int rc;
901 
902  /* Allocate net device */
903  netdev = alloc_etherdev ( sizeof ( *undinic ) );
904  if ( ! netdev )
905  return -ENOMEM;
907  undinic = netdev->priv;
908  undi_set_drvdata ( undi, netdev );
909  netdev->dev = dev;
910  memset ( undinic, 0, sizeof ( *undinic ) );
911  undinet_entry_point = undi->entry;
912  DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
913 
914  /* Hook in UNDI stack */
915  if ( ! ( undi->flags & UNDI_FL_STARTED ) ) {
916  memset ( &start_undi, 0, sizeof ( start_undi ) );
917  start_undi.AX = undi->pci_busdevfn;
918  start_undi.BX = undi->isapnp_csn;
919  start_undi.DX = undi->isapnp_read_port;
920  start_undi.ES = BIOS_SEG;
921  start_undi.DI = find_pnp_bios();
922  if ( ( rc = undinet_call ( undinic, PXENV_START_UNDI,
923  &start_undi,
924  sizeof ( start_undi ) ) ) != 0 )
925  goto err_start_undi;
926  }
927  undi->flags |= UNDI_FL_STARTED;
928 
929  /* Bring up UNDI stack */
930  if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
931  memset ( &undi_startup, 0, sizeof ( undi_startup ) );
932  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
933  &undi_startup,
934  sizeof ( undi_startup ) ) ) != 0 )
935  goto err_undi_startup;
936  /* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
937  * due to a transient condition (e.g. media test
938  * failing because the link has only just come out of
939  * reset). We may therefore need to retry this call
940  * several times.
941  */
942  for ( retry = 0 ; ; ) {
943  memset ( &undi_init, 0, sizeof ( undi_init ) );
944  if ( ( rc = undinet_call ( undinic,
946  &undi_init,
947  sizeof ( undi_init ) ) ) ==0)
948  break;
949  if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
950  goto err_undi_initialize;
951  DBGC ( undinic, "UNDINIC %p retrying "
952  "PXENV_UNDI_INITIALIZE (retry %d)\n",
953  undinic, retry );
954  /* Delay to allow link to settle if necessary */
956  }
957  }
958  undi->flags |= UNDI_FL_INITIALIZED;
959 
960  /* Get device information */
961  memset ( &undi_info, 0, sizeof ( undi_info ) );
962  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_INFORMATION,
963  &undi_info, sizeof ( undi_info ) ) ) != 0 )
964  goto err_undi_get_information;
965  memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
967  undinic->irq = undi_info.IntNumber;
968  if ( undinic->irq > IRQ_MAX ) {
969  DBGC ( undinic, "UNDINIC %p ignoring invalid IRQ %d\n",
970  undinic, undinic->irq );
971  undinic->irq = 0;
972  }
973  DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
974  undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
975 
976  /* Get interface information */
977  memset ( &undi_iface, 0, sizeof ( undi_iface ) );
978  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
979  &undi_iface, sizeof ( undi_iface ) ) ) != 0 )
980  goto err_undi_get_iface_info;
981  DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
982  undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
983  undi_iface.ServiceFlags );
984  if ( ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) &&
985  ( undinic->irq != 0 ) ) {
986  undinic->irq_supported = 1;
987  }
988  DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
989  ( undinic->irq_supported ? "interrupt" : "polling" ) );
990  if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
991  sizeof ( undi_iface.IfaceType ) ) == 0 ) {
992  DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
993  undinic );
994  undinic->hacks |= UNDI_HACK_EB54;
995  }
996  if ( undinet_irq_is_broken ( &dev->desc ) ) {
997  DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
998  "broken interrupts\n", undinic );
999  undinic->irq_supported = 0;
1000  }
1001 
1002  /* Register network device */
1003  if ( ( rc = register_netdev ( netdev ) ) != 0 )
1004  goto err_register;
1005 
1006  /* Mark as link up; we don't handle link state */
1007  netdev_link_up ( netdev );
1008 
1009  DBGC ( undinic, "UNDINIC %p added\n", undinic );
1010  return 0;
1011 
1012  err_register:
1013  err_undi_get_iface_info:
1014  err_undi_get_information:
1015  err_undi_initialize:
1016  /* Shut down UNDI stack */
1017  memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
1018  undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
1019  sizeof ( undi_shutdown ) );
1020  memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
1021  undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
1022  sizeof ( undi_cleanup ) );
1023  undi->flags &= ~UNDI_FL_INITIALIZED;
1024  err_undi_startup:
1025  /* Unhook UNDI stack */
1026  memset ( &stop_undi, 0, sizeof ( stop_undi ) );
1027  undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
1028  sizeof ( stop_undi ) );
1029  undi->flags &= ~UNDI_FL_STARTED;
1030  err_start_undi:
1031  netdev_nullify ( netdev );
1032  netdev_put ( netdev );
1033  undi_set_drvdata ( undi, NULL );
1034  return rc;
1035 }
1036 
1037 /**
1038  * Remove UNDI device
1039  *
1040  * @v undi UNDI device
1041  */
1042 void undinet_remove ( struct undi_device *undi ) {
1043  struct net_device *netdev = undi_get_drvdata ( undi );
1044  struct undi_nic *undinic = netdev->priv;
1045  struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
1046  struct s_PXENV_UNDI_CLEANUP undi_cleanup;
1047  struct s_PXENV_STOP_UNDI stop_undi;
1048 
1049  /* Unregister net device */
1051 
1052  /* If we are preparing for an OS boot, or if we cannot exit
1053  * via the PXE stack, then shut down the PXE stack.
1054  */
1055  if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
1056 
1057  /* Shut down UNDI stack */
1058  memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
1059  undinet_call ( undinic, PXENV_UNDI_SHUTDOWN,
1060  &undi_shutdown, sizeof ( undi_shutdown ) );
1061  memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
1062  undinet_call ( undinic, PXENV_UNDI_CLEANUP,
1063  &undi_cleanup, sizeof ( undi_cleanup ) );
1064  undi->flags &= ~UNDI_FL_INITIALIZED;
1065 
1066  /* Unhook UNDI stack */
1067  memset ( &stop_undi, 0, sizeof ( stop_undi ) );
1068  undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
1069  sizeof ( stop_undi ) );
1070  undi->flags &= ~UNDI_FL_STARTED;
1071  }
1072 
1073  /* Clear entry point */
1074  memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
1075 
1076  /* Free network device */
1077  netdev_nullify ( netdev );
1078  netdev_put ( netdev );
1079 
1080  DBGC ( undinic, "UNDINIC %p removed\n", undinic );
1081 }
#define UNDI_HACK_EB54
Work around Etherboot 5.4 bugs.
Definition: undinet.c:71
#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:758
#define iob_put(iobuf, len)
Definition: iobuf.h:120
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition: netdevice.c:542
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
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
#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:382
#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:84
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:888
#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:573
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
Definition: undinet.c:819
Parameter block for pxenv_undi_transmit()
Definition: pxe_api.h:1049
#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
UINT16_t flags
Flags.
Definition: undi.h:54
#define disable_irq(x)
Definition: pic8259.h:52
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:77
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:171
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:129
UINT16_t FuncFlag
Function flag.
Definition: pxe_api.h:1489
unsigned int vendor
Vendor ID.
Definition: device.h:31
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:752
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
Definition: pci.h:78
struct device dev
Generic device.
Definition: pci.h:208
#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:1042
#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:24
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:143
static int undinet_isr_triggered(void)
Test to see if UNDI ISR has been triggered.
Definition: undinet.c:421
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition: netdevice.h:510
OFF16_t DI
di register as passed to the Option ROM initialisation routine.
Definition: pxe_api.h:476
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
Definition: biosint.c:69
#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:73
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition: iobuf.h:212
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:815
static unsigned int last_trigger_count
Last observed trigger count.
Definition: undinet.c:385
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:459
#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:567
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:780
#define FLTR_BRDCST
Accept broadcast packets.
Definition: pxe_api.h:951
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 int undinet_irq_is_broken(struct device_description *desc)
Check for devices with broken support for generating interrupts.
Definition: undinet.c:849
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:392
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:158
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:899
unsigned int location
Location.
Definition: device.h:29
#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
#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:206
int register_netdev(struct net_device *netdev)
Register network device.
Definition: netdevice.c:722
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:155
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:60
A network device.
Definition: netdevice.h:352
#define undiisr_irq
Definition: undinet.c:374
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:175
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition: netdevice.h:523
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:795
#define XMT_DESTADDR
Unicast packet.
Definition: pxe_api.h:1017
__asm__ __volatile__("\n1:\n\t" "movb -1(%3,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "xorl %%eax, %%eax\n\t" "mov %4, %1\n\t" "rep stosb\n\t" :"=&D"(discard_D), "=&c"(discard_c), "+m"(*value) :"r"(data), "g"(pad_len), "0"(value0), "1"(len) :"eax")
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 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:450
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:504
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:835
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
#define enable_irq(x)
Definition: pic8259.h:51
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
#define undinet_tbd
Definition: undinet.c:446
#define iob_reserve(iobuf, len)
Definition: iobuf.h:67
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
Definition: profile.h:129
__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:817
unsigned int bus_type
Bus type.
Definition: device.h:24
#define FLTR_DIRECTED
Accept "directed" packets.
Definition: pxe_api.h:949
uint32_t len
Length.
Definition: ena.h:14
static unsigned long profile_stopped(struct profiler *profiler)
Get stop time.
Definition: profile.h:94
#define PXENV_UNDI_RESET_ADAPTER
PXE API function code for pxenv_undi_reset_adapter()
Definition: pxe_api.h:888
unsigned int device
Device ID.
Definition: device.h:33
#define __from_data16(pointer)
Definition: libkir.h:22
static void undinet_unhook_isr(unsigned int irq)
Unhook UNDI interrupt service routine.
Definition: undinet.c:407
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
void * data
Start of data.
Definition: iobuf.h:48
#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:79
#define P_RARP
RARP protocol.
Definition: pxe_api.h:1014
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:378
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:332
#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:821
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:804
An Ethernet link-layer header.
Definition: if_ether.h:30
#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:362
String functions.
#define IRQ_MAX
Definition: pic8259.h:63
#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:705
#define PCI_ANY_ID
Match-anything ID.
Definition: pci.h:182
A device with broken support for generating interrupts.
Definition: undinet.c:813
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:33
struct profiler p2r
Time spent transitioning to real mode.
Definition: undinet.c:127
uint8_t flags
Flags.
Definition: ena.h:18