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 /** IRQ profiler */
108 static struct profiler undinet_irq_profiler __profiler =
109  { .name = "undinet.irq" };
110 
111 /** Receive profiler */
112 static struct profiler undinet_rx_profiler __profiler =
113  { .name = "undinet.rx" };
114 
115 /** A PXE API call breakdown profiler */
117  /** Total time spent performing REAL_CALL() */
118  struct profiler total;
119  /** Time spent transitioning to real mode */
120  struct profiler p2r;
121  /** Time spent in external code */
122  struct profiler ext;
123  /** Time spent transitioning back to protected mode */
124  struct profiler r2p;
125 };
126 
127 /** PXENV_UNDI_TRANSMIT profiler */
128 static struct undinet_profiler undinet_tx_profiler __profiler = {
129  { .name = "undinet.tx" },
130  { .name = "undinet.tx_p2r" },
131  { .name = "undinet.tx_ext" },
132  { .name = "undinet.tx_r2p" },
133 };
134 
135 /** PXENV_UNDI_ISR profiler
136  *
137  * Note that this profiler will not see calls to
138  * PXENV_UNDI_ISR_IN_START, which are handled by the UNDI ISR and do
139  * not go via undinet_call().
140  */
141 static struct undinet_profiler undinet_isr_profiler __profiler = {
142  { .name = "undinet.isr" },
143  { .name = "undinet.isr_p2r" },
144  { .name = "undinet.isr_ext" },
145  { .name = "undinet.isr_r2p" },
146 };
147 
148 /** PXE unknown API call profiler
149  *
150  * This profiler can be used to measure the overhead of a dummy PXE
151  * API call.
152  */
153 static struct undinet_profiler undinet_unknown_profiler __profiler = {
154  { .name = "undinet.unknown" },
155  { .name = "undinet.unknown_p2r" },
156  { .name = "undinet.unknown_ext" },
157  { .name = "undinet.unknown_r2p" },
158 };
159 
160 /** Miscellaneous PXE API call profiler */
161 static struct undinet_profiler undinet_misc_profiler __profiler = {
162  { .name = "undinet.misc" },
163  { .name = "undinet.misc_p2r" },
164  { .name = "undinet.misc_ext" },
165  { .name = "undinet.misc_r2p" },
166 };
167 
168 /*****************************************************************************
169  *
170  * UNDI API call
171  *
172  *****************************************************************************
173  */
174 
175 /**
176  * Name PXE API call
177  *
178  * @v function API call number
179  * @ret name API call name
180  */
181 static inline __attribute__ (( always_inline )) const char *
182 undinet_function_name ( unsigned int function ) {
183  switch ( function ) {
184  case PXENV_START_UNDI:
185  return "PXENV_START_UNDI";
186  case PXENV_STOP_UNDI:
187  return "PXENV_STOP_UNDI";
188  case PXENV_UNDI_STARTUP:
189  return "PXENV_UNDI_STARTUP";
190  case PXENV_UNDI_CLEANUP:
191  return "PXENV_UNDI_CLEANUP";
193  return "PXENV_UNDI_INITIALIZE";
195  return "PXENV_UNDI_RESET_ADAPTER";
196  case PXENV_UNDI_SHUTDOWN:
197  return "PXENV_UNDI_SHUTDOWN";
198  case PXENV_UNDI_OPEN:
199  return "PXENV_UNDI_OPEN";
200  case PXENV_UNDI_CLOSE:
201  return "PXENV_UNDI_CLOSE";
202  case PXENV_UNDI_TRANSMIT:
203  return "PXENV_UNDI_TRANSMIT";
205  return "PXENV_UNDI_SET_MCAST_ADDRESS";
207  return "PXENV_UNDI_SET_STATION_ADDRESS";
209  return "PXENV_UNDI_SET_PACKET_FILTER";
211  return "PXENV_UNDI_GET_INFORMATION";
213  return "PXENV_UNDI_GET_STATISTICS";
215  return "PXENV_UNDI_CLEAR_STATISTICS";
217  return "PXENV_UNDI_INITIATE_DIAGS";
219  return "PXENV_UNDI_FORCE_INTERRUPT";
221  return "PXENV_UNDI_GET_MCAST_ADDRESS";
223  return "PXENV_UNDI_GET_NIC_TYPE";
225  return "PXENV_UNDI_GET_IFACE_INFO";
226  /*
227  * Duplicate case value; this is a bug in the PXE specification.
228  *
229  * case PXENV_UNDI_GET_STATE:
230  * return "PXENV_UNDI_GET_STATE";
231  */
232  case PXENV_UNDI_ISR:
233  return "PXENV_UNDI_ISR";
235  return "PXENV_GET_CACHED_INFO";
236  default:
237  return "UNKNOWN API CALL";
238  }
239 }
240 
241 /**
242  * Determine applicable profiler pair (for debugging)
243  *
244  * @v function API call number
245  * @ret profiler Profiler
246  */
247 static struct undinet_profiler * undinet_profiler ( unsigned int function ) {
248 
249  /* Determine applicable profiler */
250  switch ( function ) {
251  case PXENV_UNDI_TRANSMIT:
252  return &undinet_tx_profiler;
253  case PXENV_UNDI_ISR:
254  return &undinet_isr_profiler;
255  case PXENV_UNKNOWN:
256  return &undinet_unknown_profiler;
257  default:
258  return &undinet_misc_profiler;
259  }
260 }
261 
262 /**
263  * Issue UNDI API call
264  *
265  * @v undinic UNDI NIC
266  * @v function API call number
267  * @v params PXE parameter block
268  * @v params_len Length of PXE parameter block
269  * @ret rc Return status code
270  */
271 static int undinet_call ( struct undi_nic *undinic, unsigned int function,
272  void *params, size_t params_len ) {
273  struct undinet_profiler *profiler = undinet_profiler ( function );
274  PXENV_EXIT_t exit;
275  uint32_t before;
277  uint32_t stopped;
278  uint32_t after;
279  int discard_D;
280  int rc;
281 
282  /* Copy parameter block and entry point */
283  assert ( params_len <= sizeof ( undinet_params ) );
284  memcpy ( &undinet_params, params, params_len );
285 
286  /* Call real-mode entry point. This calling convention will
287  * work with both the !PXE and the PXENV+ entry points.
288  */
289  profile_start ( &profiler->total );
290  __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
291  "rdtsc\n\t"
292  "pushl %%eax\n\t"
293  "pushw %%es\n\t"
294  "pushw %%di\n\t"
295  "pushw %%bx\n\t"
296  "lcall *undinet_entry_point\n\t"
297  "movw %%ax, %%bx\n\t"
298  "rdtsc\n\t"
299  "addw $6, %%sp\n\t"
300  "popl %%edx\n\t"
301  "popl %%ebp\n\t" /* gcc bug */ )
302  : "=a" ( stopped ), "=d" ( started ),
303  "=b" ( exit ), "=D" ( discard_D )
304  : "b" ( function ),
305  "D" ( __from_data16 ( &undinet_params ) )
306  : "ecx", "esi" );
307  profile_stop ( &profiler->total );
308  before = profile_started ( &profiler->total );
309  after = profile_stopped ( &profiler->total );
310  profile_start_at ( &profiler->p2r, before );
311  profile_stop_at ( &profiler->p2r, started );
312  profile_start_at ( &profiler->ext, started );
313  profile_stop_at ( &profiler->ext, stopped );
314  profile_start_at ( &profiler->r2p, stopped );
315  profile_stop_at ( &profiler->r2p, after );
316 
317  /* Determine return status code based on PXENV_EXIT and
318  * PXENV_STATUS
319  */
320  rc = ( ( exit == PXENV_EXIT_SUCCESS ) ?
321  0 : -EPXECALL ( undinet_params.Status ) );
322 
323  /* If anything goes wrong, print as much debug information as
324  * it's possible to give.
325  */
326  if ( rc != 0 ) {
327  SEGOFF16_t rm_params = {
328  .segment = rm_ds,
329  .offset = __from_data16 ( &undinet_params ),
330  };
331 
332  DBGC ( undinic, "UNDINIC %p %s failed: %s\n", undinic,
333  undinet_function_name ( function ), strerror ( rc ) );
334  DBGC ( undinic, "UNDINIC %p parameters at %04x:%04x length "
335  "%#02zx, entry point at %04x:%04x\n", undinic,
336  rm_params.segment, rm_params.offset, params_len,
337  undinet_entry_point.segment,
338  undinet_entry_point.offset );
339  DBGC ( undinic, "UNDINIC %p parameters provided:\n", undinic );
340  DBGC_HDA ( undinic, rm_params, params, params_len );
341  DBGC ( undinic, "UNDINIC %p parameters returned:\n", undinic );
342  DBGC_HDA ( undinic, rm_params, &undinet_params, params_len );
343  }
344 
345  /* Copy parameter block back */
346  memcpy ( params, &undinet_params, params_len );
347 
348  return rc;
349 }
350 
351 /*****************************************************************************
352  *
353  * UNDI interrupt service routine
354  *
355  *****************************************************************************
356  */
357 
358 /**
359  * UNDI interrupt service routine
360  *
361  * The UNDI ISR increments a counter (@c trigger_count) and exits.
362  */
363 extern void undiisr ( void );
364 
365 /** IRQ number */
367 #define undiisr_irq __use_data16 ( undiisr_irq )
368 
369 /** IRQ chain vector */
371 #define undiisr_next_handler __use_data16 ( undiisr_next_handler )
372 
373 /** IRQ trigger count */
374 volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
375 #define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
376 
377 /** Last observed trigger count */
378 static unsigned int last_trigger_count = 0;
379 
380 /**
381  * Hook UNDI interrupt service routine
382  *
383  * @v irq IRQ number
384  */
385 static void undinet_hook_isr ( unsigned int irq ) {
386 
387  assert ( irq <= IRQ_MAX );
388  assert ( undiisr_irq == 0 );
389 
390  undiisr_irq = irq;
391  hook_bios_interrupt ( IRQ_INT ( irq ), ( ( intptr_t ) undiisr ),
393 }
394 
395 /**
396  * Unhook UNDI interrupt service routine
397  *
398  * @v irq IRQ number
399  */
400 static void undinet_unhook_isr ( unsigned int irq ) {
401 
402  assert ( irq <= IRQ_MAX );
403 
404  unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( intptr_t ) undiisr ),
406  undiisr_irq = 0;
407 }
408 
409 /**
410  * Test to see if UNDI ISR has been triggered
411  *
412  * @ret triggered ISR has been triggered since last check
413  */
414 static int undinet_isr_triggered ( void ) {
415  unsigned int this_trigger_count;
416 
417  /* Read trigger_count. Do this only once; it is volatile */
418  this_trigger_count = undiisr_trigger_count;
419 
420  if ( this_trigger_count == last_trigger_count ) {
421  /* Not triggered */
422  return 0;
423  } else {
424  /* Triggered */
425  last_trigger_count = this_trigger_count;
426  return 1;
427  }
428 }
429 
430 /*****************************************************************************
431  *
432  * UNDI network device interface
433  *
434  *****************************************************************************
435  */
436 
437 /** UNDI transmit buffer descriptor */
438 static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
439 #define undinet_tbd __use_data16 ( undinet_tbd )
440 
441 /** UNDI transmit destination address */
443 #define undinet_destaddr __use_data16 ( undinet_destaddr )
444 
445 /**
446  * Transmit packet
447  *
448  * @v netdev Network device
449  * @v iobuf I/O buffer
450  * @ret rc Return status code
451  */
452 static int undinet_transmit ( struct net_device *netdev,
453  struct io_buffer *iobuf ) {
454  struct undi_nic *undinic = netdev->priv;
455  struct s_PXENV_UNDI_TRANSMIT undi_transmit;
456  const void *ll_dest;
457  const void *ll_source;
458  uint16_t net_proto;
459  unsigned int flags;
461  size_t len;
462  int rc;
463 
464  /* Technically, we ought to make sure that the previous
465  * transmission has completed before we re-use the buffer.
466  * However, many PXE stacks (including at least some Intel PXE
467  * stacks and Etherboot 5.4) fail to generate TX completions.
468  * In practice this won't be a problem, since our TX datapath
469  * has a very low packet volume and we can get away with
470  * assuming that a TX will be complete by the time we want to
471  * transmit the next packet.
472  */
473 
474  /* Some PXE stacks are unable to cope with P_UNKNOWN, and will
475  * always try to prepend a link-layer header. Work around
476  * these stacks by stripping the existing link-layer header
477  * and allowing the PXE stack to (re)construct the link-layer
478  * header itself.
479  */
480  if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
481  &net_proto, &flags ) ) != 0 ) {
482  DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
483  "%s\n", undinic, strerror ( rc ) );
484  return rc;
485  }
486  memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
487  switch ( net_proto ) {
488  case htons ( ETH_P_IP ) :
489  protocol = P_IP;
490  break;
491  case htons ( ETH_P_ARP ) :
492  protocol = P_ARP;
493  break;
494  case htons ( ETH_P_RARP ) :
495  protocol = P_RARP;
496  break;
497  default:
498  /* Unknown protocol; restore the original link-layer header */
499  iob_push ( iobuf, sizeof ( struct ethhdr ) );
501  break;
502  }
503 
504  /* Copy packet to UNDI I/O buffer */
505  len = iob_len ( iobuf );
506  if ( len > sizeof ( basemem_packet ) )
507  len = sizeof ( basemem_packet );
508  memcpy ( &basemem_packet, iobuf->data, len );
509 
510  /* Create PXENV_UNDI_TRANSMIT data structure */
511  memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
512  undi_transmit.Protocol = protocol;
513  undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
515  undi_transmit.DestAddr.segment = rm_ds;
516  undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
517  undi_transmit.TBD.segment = rm_ds;
518  undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
519 
520  /* Create PXENV_UNDI_TBD data structure */
521  undinet_tbd.ImmedLength = len;
522  undinet_tbd.Xmit.segment = rm_ds;
523  undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
524 
525  /* Issue PXE API call */
526  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_TRANSMIT, &undi_transmit,
527  sizeof ( undi_transmit ) ) ) != 0 )
528  goto done;
529 
530  /* Free I/O buffer */
531  netdev_tx_complete ( netdev, iobuf );
532  done:
533  return rc;
534 }
535 
536 /**
537  * Poll for received packets
538  *
539  * @v netdev Network device
540  *
541  * Fun, fun, fun. UNDI drivers don't use polling; they use
542  * interrupts. We therefore cheat and pretend that an interrupt has
543  * occurred every time undinet_poll() is called. This isn't too much
544  * of a hack; PCI devices share IRQs and so the first thing that a
545  * proper ISR should do is call PXENV_UNDI_ISR to determine whether or
546  * not the UNDI NIC generated the interrupt; there is no harm done by
547  * spurious calls to PXENV_UNDI_ISR. Similarly, we wouldn't be
548  * handling them any more rapidly than the usual rate of
549  * undinet_poll() being called even if we did implement a full ISR.
550  * So it should work. Ha!
551  *
552  * Addendum (21/10/03). Some cards don't play nicely with this trick,
553  * so instead of doing it the easy way we have to go to all the hassle
554  * of installing a genuine interrupt service routine and dealing with
555  * the wonderful 8259 Programmable Interrupt Controller. Joy.
556  *
557  * Addendum (10/07/07). When doing things such as iSCSI boot, in
558  * which we have to co-operate with a running OS, we can't get away
559  * with the "ISR-just-increments-a-counter-and-returns" trick at all,
560  * because it involves tying up the PIC for far too long, and other
561  * interrupt-dependent components (e.g. local disks) start breaking.
562  * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
563  * from within interrupt context in order to deassert the device
564  * interrupt, and sends EOI if applicable.
565  */
566 static void undinet_poll ( struct net_device *netdev ) {
567  struct undi_nic *undinic = netdev->priv;
568  struct s_PXENV_UNDI_ISR undi_isr;
569  struct io_buffer *iobuf = NULL;
570  unsigned int quota = UNDI_RX_QUOTA;
571  size_t len;
572  size_t reserve_len;
573  size_t frag_len;
574  size_t max_frag_len;
575  int rc;
576 
577  if ( ! undinic->isr_processing ) {
578  /* Allow interrupt to occur. Do this even if
579  * interrupts are not known to be supported, since
580  * some cards erroneously report that they do not
581  * support interrupts.
582  */
583  if ( ! undinet_isr_triggered() ) {
584  /* Allow interrupt to occur */
585  profile_start ( &undinet_irq_profiler );
586  __asm__ __volatile__ ( "sti\n\t"
587  "nop\n\t"
588  "nop\n\t"
589  "cli\n\t" );
590  profile_stop ( &undinet_irq_profiler );
591 
592  /* If interrupts are known to be supported,
593  * then do nothing on this poll; wait for the
594  * interrupt to be triggered.
595  */
596  if ( undinic->irq_supported )
597  return;
598  }
599 
600  /* Start ISR processing */
601  undinic->isr_processing = 1;
603  } else {
604  /* Continue ISR processing */
606  }
607 
608  /* Run through the ISR loop */
609  while ( quota ) {
610  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
611  sizeof ( undi_isr ) ) ) != 0 ) {
612  netdev_rx_err ( netdev, NULL, rc );
613  break;
614  }
615  switch ( undi_isr.FuncFlag ) {
617  /* We don't care about transmit completions */
618  break;
620  /* Packet fragment received */
621  profile_start ( &undinet_rx_profiler );
622  len = undi_isr.FrameLength;
623  frag_len = undi_isr.BufferLength;
624  reserve_len = ( -undi_isr.FrameHeaderLength &
625  ( UNDI_RX_ALIGN - 1 ) );
626  if ( ( len == 0 ) || ( len < frag_len ) ) {
627  /* Don't laugh. VMWare does it. */
628  DBGC ( undinic, "UNDINIC %p reported insane "
629  "fragment (%zd of %zd bytes)\n",
630  undinic, frag_len, len );
632  break;
633  }
634  if ( ! iobuf ) {
635  iobuf = alloc_iob ( reserve_len + len );
636  if ( ! iobuf ) {
637  DBGC ( undinic, "UNDINIC %p could not "
638  "allocate %zd bytes for RX "
639  "buffer\n", undinic, len );
640  /* Fragment will be dropped */
642  goto done;
643  }
644  iob_reserve ( iobuf, reserve_len );
645  }
646  max_frag_len = iob_tailroom ( iobuf );
647  if ( frag_len > max_frag_len ) {
648  DBGC ( undinic, "UNDINIC %p fragment too big "
649  "(%zd+%zd does not fit into %zd)\n",
650  undinic, iob_len ( iobuf ), frag_len,
651  ( iob_len ( iobuf ) + max_frag_len ) );
652  frag_len = max_frag_len;
653  }
654  copy_from_real ( iob_put ( iobuf, frag_len ),
655  undi_isr.Frame.segment,
656  undi_isr.Frame.offset, frag_len );
657  if ( iob_len ( iobuf ) == len ) {
658  /* Whole packet received; deliver it */
659  netdev_rx ( netdev, iob_disown ( iobuf ) );
660  quota--;
661  /* Etherboot 5.4 fails to return all packets
662  * under mild load; pretend it retriggered.
663  */
664  if ( undinic->hacks & UNDI_HACK_EB54 )
666  }
667  profile_stop ( &undinet_rx_profiler );
668  break;
670  /* Processing complete */
671  undinic->isr_processing = 0;
672  goto done;
673  default:
674  /* Should never happen. VMWare does it routinely. */
675  DBGC ( undinic, "UNDINIC %p ISR returned invalid "
676  "FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
677  undinic->isr_processing = 0;
678  goto done;
679  }
681  }
682 
683  done:
684  if ( iobuf ) {
685  DBGC ( undinic, "UNDINIC %p returned incomplete packet "
686  "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
687  ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
688  netdev_rx_err ( netdev, iobuf, -EINVAL );
689  }
690 }
691 
692 /**
693  * Open NIC
694  *
695  * @v netdev Net device
696  * @ret rc Return status code
697  */
698 static int undinet_open ( struct net_device *netdev ) {
699  struct undi_nic *undinic = netdev->priv;
700  struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
701  struct s_PXENV_UNDI_OPEN undi_open;
702  int rc;
703 
704  /* Hook interrupt service routine and enable interrupt if applicable */
705  if ( undinic->irq ) {
706  undinet_hook_isr ( undinic->irq );
707  enable_irq ( undinic->irq );
708  send_eoi ( undinic->irq );
709  }
710 
711  /* Set station address. Required for some PXE stacks; will
712  * spuriously fail on others. Ignore failures. We only ever
713  * use it to set the MAC address to the card's permanent value
714  * anyway.
715  */
716  memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
717  sizeof ( undi_set_address.StationAddress ) );
719  &undi_set_address, sizeof ( undi_set_address ) );
720 
721  /* Open NIC. We ask for promiscuous operation, since it's the
722  * only way to ask for all multicast addresses. On any
723  * switched network, it shouldn't really make a difference to
724  * performance.
725  */
726  memset ( &undi_open, 0, sizeof ( undi_open ) );
727  undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
728  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open,
729  sizeof ( undi_open ) ) ) != 0 )
730  goto err;
731 
732  DBGC ( undinic, "UNDINIC %p opened\n", undinic );
733  return 0;
734 
735  err:
736  undinet_close ( netdev );
737  return rc;
738 }
739 
740 /**
741  * Close NIC
742  *
743  * @v netdev Net device
744  */
745 static void undinet_close ( struct net_device *netdev ) {
746  struct undi_nic *undinic = netdev->priv;
747  struct s_PXENV_UNDI_ISR undi_isr;
748  struct s_PXENV_UNDI_CLOSE undi_close;
749  int rc;
750 
751  /* Ensure ISR has exited cleanly */
752  while ( undinic->isr_processing ) {
754  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
755  sizeof ( undi_isr ) ) ) != 0 )
756  break;
757  switch ( undi_isr.FuncFlag ) {
760  /* Continue draining */
761  break;
762  default:
763  /* Stop processing */
764  undinic->isr_processing = 0;
765  break;
766  }
767  }
768 
769  /* Close NIC */
770  undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close,
771  sizeof ( undi_close ) );
772 
773  /* Disable interrupt and unhook ISR if applicable */
774  if ( undinic->irq ) {
775  disable_irq ( undinic->irq );
776  undinet_unhook_isr ( undinic->irq );
777  }
778 
779  DBGC ( undinic, "UNDINIC %p closed\n", undinic );
780 }
781 
782 /**
783  * Enable/disable interrupts
784  *
785  * @v netdev Net device
786  * @v enable Interrupts should be enabled
787  */
788 static void undinet_irq ( struct net_device *netdev, int enable ) {
789  struct undi_nic *undinic = netdev->priv;
790 
791  /* Cannot support interrupts yet */
792  DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n",
793  undinic, ( enable ? "enable" : "disable" ) );
794 }
795 
796 /** UNDI network device operations */
798  .open = undinet_open,
799  .close = undinet_close,
800  .transmit = undinet_transmit,
801  .poll = undinet_poll,
802  .irq = undinet_irq,
803 };
804 
805 /** A device with broken support for generating interrupts */
807  /** PCI vendor ID */
809  /** PCI device ID */
811  /** PCI subsystem vendor ID */
813  /** PCI subsystem ID */
815 };
816 
817 /**
818  * List of devices with broken support for generating interrupts
819  *
820  * Some PXE stacks are known to claim that IRQs are supported, but
821  * then never generate interrupts. No satisfactory solution has been
822  * found to this problem; the workaround is to add the PCI vendor and
823  * device IDs to this list. This is something of a hack, since it
824  * will generate false positives for identical devices with a working
825  * PXE stack (e.g. those that have been reflashed with iPXE), but it's
826  * an improvement on the current situation.
827  */
829  /* HP XX70x laptops */
830  { 0x8086, 0x1502, PCI_ANY_ID, PCI_ANY_ID },
831  { 0x8086, 0x1503, PCI_ANY_ID, PCI_ANY_ID },
832  /* HP 745 G3 laptop */
833  { 0x14e4, 0x1687, PCI_ANY_ID, PCI_ANY_ID },
834 };
835 
836 /**
837  * Check for devices with broken support for generating interrupts
838  *
839  * @v desc Device description
840  * @ret irq_is_broken Interrupt support is broken; no interrupts are generated
841  */
842 static int undinet_irq_is_broken ( struct device_description *desc ) {
843  const struct undinet_irq_broken *broken;
844  struct pci_device pci;
845  uint16_t subsys_vendor;
846  uint16_t subsys;
847  unsigned int i;
848 
849  /* Ignore non-PCI devices */
850  if ( desc->bus_type != BUS_TYPE_PCI )
851  return 0;
852 
853  /* Read subsystem IDs */
854  pci_init ( &pci, desc->location );
855  pci_read_config_word ( &pci, PCI_SUBSYSTEM_VENDOR_ID, &subsys_vendor );
856  pci_read_config_word ( &pci, PCI_SUBSYSTEM_ID, &subsys );
857 
858  /* Check for a match against the broken device list */
859  for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
860  sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
861  broken = &undinet_irq_broken_list[i];
862  if ( ( broken->pci_vendor == desc->vendor ) &&
863  ( broken->pci_device == desc->device ) &&
864  ( ( broken->pci_subsys_vendor == subsys_vendor ) ||
865  ( broken->pci_subsys_vendor == PCI_ANY_ID ) ) &&
866  ( ( broken->pci_subsys == subsys ) ||
867  ( broken->pci_subsys == PCI_ANY_ID ) ) ) {
868  return 1;
869  }
870  }
871  return 0;
872 }
873 
874 /**
875  * Probe UNDI device
876  *
877  * @v undi UNDI device
878  * @v dev Underlying generic device
879  * @ret rc Return status code
880  */
881 int undinet_probe ( struct undi_device *undi, struct device *dev ) {
882  struct net_device *netdev;
883  struct undi_nic *undinic;
884  struct s_PXENV_START_UNDI start_undi;
885  struct s_PXENV_UNDI_STARTUP undi_startup;
886  struct s_PXENV_UNDI_INITIALIZE undi_init;
887  struct s_PXENV_UNDI_GET_INFORMATION undi_info;
888  struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
889  struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
890  struct s_PXENV_UNDI_CLEANUP undi_cleanup;
891  struct s_PXENV_STOP_UNDI stop_undi;
892  unsigned int retry;
893  int rc;
894 
895  /* Allocate net device */
896  netdev = alloc_etherdev ( sizeof ( *undinic ) );
897  if ( ! netdev )
898  return -ENOMEM;
900  undinic = netdev->priv;
901  undi_set_drvdata ( undi, netdev );
902  netdev->dev = dev;
903  memset ( undinic, 0, sizeof ( *undinic ) );
904  undinet_entry_point = undi->entry;
905  DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
906 
907  /* Hook in UNDI stack */
908  if ( ! ( undi->flags & UNDI_FL_STARTED ) ) {
909  memset ( &start_undi, 0, sizeof ( start_undi ) );
910  start_undi.AX = undi->pci_busdevfn;
911  start_undi.BX = undi->isapnp_csn;
912  start_undi.DX = undi->isapnp_read_port;
913  start_undi.ES = BIOS_SEG;
914  start_undi.DI = find_pnp_bios();
915  if ( ( rc = undinet_call ( undinic, PXENV_START_UNDI,
916  &start_undi,
917  sizeof ( start_undi ) ) ) != 0 )
918  goto err_start_undi;
919  }
920  undi->flags |= UNDI_FL_STARTED;
921 
922  /* Bring up UNDI stack */
923  if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
924  memset ( &undi_startup, 0, sizeof ( undi_startup ) );
925  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
926  &undi_startup,
927  sizeof ( undi_startup ) ) ) != 0 )
928  goto err_undi_startup;
929  /* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
930  * due to a transient condition (e.g. media test
931  * failing because the link has only just come out of
932  * reset). We may therefore need to retry this call
933  * several times.
934  */
935  for ( retry = 0 ; ; ) {
936  memset ( &undi_init, 0, sizeof ( undi_init ) );
937  if ( ( rc = undinet_call ( undinic,
939  &undi_init,
940  sizeof ( undi_init ) ) ) ==0)
941  break;
942  if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
943  goto err_undi_initialize;
944  DBGC ( undinic, "UNDINIC %p retrying "
945  "PXENV_UNDI_INITIALIZE (retry %d)\n",
946  undinic, retry );
947  /* Delay to allow link to settle if necessary */
949  }
950  }
951  undi->flags |= UNDI_FL_INITIALIZED;
952 
953  /* Get device information */
954  memset ( &undi_info, 0, sizeof ( undi_info ) );
955  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_INFORMATION,
956  &undi_info, sizeof ( undi_info ) ) ) != 0 )
957  goto err_undi_get_information;
958  memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
960  undinic->irq = undi_info.IntNumber;
961  if ( undinic->irq > IRQ_MAX ) {
962  DBGC ( undinic, "UNDINIC %p ignoring invalid IRQ %d\n",
963  undinic, undinic->irq );
964  undinic->irq = 0;
965  }
966  DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
967  undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
968 
969  /* Get interface information */
970  memset ( &undi_iface, 0, sizeof ( undi_iface ) );
971  if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
972  &undi_iface, sizeof ( undi_iface ) ) ) != 0 )
973  goto err_undi_get_iface_info;
974  DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
975  undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
976  undi_iface.ServiceFlags );
977  if ( ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) &&
978  ( undinic->irq != 0 ) ) {
979  undinic->irq_supported = 1;
980  }
981  DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
982  ( undinic->irq_supported ? "interrupt" : "polling" ) );
983  if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
984  sizeof ( undi_iface.IfaceType ) ) == 0 ) {
985  DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
986  undinic );
987  undinic->hacks |= UNDI_HACK_EB54;
988  }
989  if ( undinet_irq_is_broken ( &dev->desc ) ) {
990  DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
991  "broken interrupts\n", undinic );
992  undinic->irq_supported = 0;
993  }
994 
995  /* Register network device */
996  if ( ( rc = register_netdev ( netdev ) ) != 0 )
997  goto err_register;
998 
999  /* Mark as link up; we don't handle link state */
1000  netdev_link_up ( netdev );
1001 
1002  DBGC ( undinic, "UNDINIC %p added\n", undinic );
1003  return 0;
1004 
1005  err_register:
1006  err_undi_get_iface_info:
1007  err_undi_get_information:
1008  err_undi_initialize:
1009  /* Shut down UNDI stack */
1010  memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
1011  undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
1012  sizeof ( undi_shutdown ) );
1013  memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
1014  undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
1015  sizeof ( undi_cleanup ) );
1016  undi->flags &= ~UNDI_FL_INITIALIZED;
1017  err_undi_startup:
1018  /* Unhook UNDI stack */
1019  memset ( &stop_undi, 0, sizeof ( stop_undi ) );
1020  undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
1021  sizeof ( stop_undi ) );
1022  undi->flags &= ~UNDI_FL_STARTED;
1023  err_start_undi:
1024  netdev_nullify ( netdev );
1025  netdev_put ( netdev );
1026  undi_set_drvdata ( undi, NULL );
1027  return rc;
1028 }
1029 
1030 /**
1031  * Remove UNDI device
1032  *
1033  * @v undi UNDI device
1034  */
1035 void undinet_remove ( struct undi_device *undi ) {
1036  struct net_device *netdev = undi_get_drvdata ( undi );
1037  struct undi_nic *undinic = netdev->priv;
1038  struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
1039  struct s_PXENV_UNDI_CLEANUP undi_cleanup;
1040  struct s_PXENV_STOP_UNDI stop_undi;
1041 
1042  /* Unregister net device */
1044 
1045  /* If we are preparing for an OS boot, or if we cannot exit
1046  * via the PXE stack, then shut down the PXE stack.
1047  */
1048  if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
1049 
1050  /* Shut down UNDI stack */
1051  memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
1052  undinet_call ( undinic, PXENV_UNDI_SHUTDOWN,
1053  &undi_shutdown, sizeof ( undi_shutdown ) );
1054  memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
1055  undinet_call ( undinic, PXENV_UNDI_CLEANUP,
1056  &undi_cleanup, sizeof ( undi_cleanup ) );
1057  undi->flags &= ~UNDI_FL_INITIALIZED;
1058 
1059  /* Unhook UNDI stack */
1060  memset ( &stop_undi, 0, sizeof ( stop_undi ) );
1061  undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
1062  sizeof ( stop_undi ) );
1063  undi->flags &= ~UNDI_FL_STARTED;
1064  }
1065 
1066  /* Clear entry point */
1067  memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
1068 
1069  /* Free network device */
1070  netdev_nullify ( netdev );
1071  netdev_put ( netdev );
1072 
1073  DBGC ( undinic, "UNDINIC %p removed\n", undinic );
1074 }
#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:746
#define iob_put(iobuf, len)
Definition: iobuf.h:116
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition: netdevice.c:501
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:375
#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:80
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:881
#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:566
uint16_t pci_subsys_vendor
PCI subsystem vendor ID.
Definition: undinet.c:812
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:170
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:128
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:745
#define PCI_SUBSYSTEM_ID
PCI subsystem ID.
Definition: pci.h:77
struct device dev
Generic device.
Definition: pci.h:189
#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:1035
#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:108
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:414
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition: netdevice.h:498
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:208
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:808
static unsigned int last_trigger_count
Last observed trigger count.
Definition: undinet.c:378
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:247
static int undinet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
Definition: undinet.c:452
#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:555
Ethernet protocol.
UINT8_t Protocol
Protocol.
Definition: pxe_api.h:1057
void * priv
Driver private data.
Definition: netdevice.h:425
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:768
#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:842
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:385
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:844
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:187
int register_netdev(struct net_device *netdev)
Register network device.
Definition: netdevice.c:667
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:151
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:182
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:348
#define undiisr_irq
Definition: undinet.c:367
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:171
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition: netdevice.h:511
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:788
#define XMT_DESTADDR
Unicast packet.
Definition: pxe_api.h:1017
void * discard_D
Definition: bigint.h:29
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:124
#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:122
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:271
#define undinet_destaddr
Definition: undinet.c:443
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:470
struct device * dev
Underlying hardware device.
Definition: netdevice.h:360
__asm__ __volatile__("\n1:\n\t" "movb -1(%2,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "xorl %%eax, %%eax\n\t" "mov %3, %1\n\t" "rep stosb\n\t" :"=&D"(discard_D), "=&c"(discard_c) :"r"(data), "g"(pad_len), "0"(value0), "1"(len) :"eax")
#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
static const struct undinet_irq_broken undinet_irq_broken_list[]
List of devices with broken support for generating interrupts.
Definition: undinet.c:828
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:439
#define iob_reserve(iobuf, len)
Definition: iobuf.h:63
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:810
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:400
struct profiler total
Total time spent performing REAL_CALL()
Definition: undinet.c:118
SEGOFF16_t TBD
Address of the Transmit Buffer Descriptor.
Definition: pxe_api.h:1068
void * data
Start of data.
Definition: iobuf.h:44
#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:371
uint16_t protocol
Protocol ID.
Definition: stp.h:18
#define PCI_SUBSYSTEM_VENDOR_ID
PCI subsystem vendor ID.
Definition: pci.h:74
#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:381
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:313
#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:814
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:797
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:375
#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:698
#define PCI_ANY_ID
Match-anything ID.
Definition: pci.h:163
A device with broken support for generating interrupts.
Definition: undinet.c:806
int irq_supported
Device supports IRQs.
Definition: undinet.c:50
A PXE API call breakdown profiler.
Definition: undinet.c:116
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:32
struct profiler p2r
Time spent transitioning to real mode.
Definition: undinet.c:120
uint8_t flags
Flags.
Definition: ena.h:18