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 */
50 int irq_supported;
51 /** Assigned IRQ number */
52 unsigned int irq;
53 /** Currently processing ISR */
54 int isr_processing;
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 */
123 struct undinet_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 *
undinet_function_name(unsigned int function)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";
199 case PXENV_UNDI_INITIALIZE:
200 return "PXENV_UNDI_INITIALIZE";
201 case PXENV_UNDI_RESET_ADAPTER:
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";
211 case PXENV_UNDI_SET_MCAST_ADDRESS:
212 return "PXENV_UNDI_SET_MCAST_ADDRESS";
213 case PXENV_UNDI_SET_STATION_ADDRESS:
214 return "PXENV_UNDI_SET_STATION_ADDRESS";
215 case PXENV_UNDI_SET_PACKET_FILTER:
216 return "PXENV_UNDI_SET_PACKET_FILTER";
217 case PXENV_UNDI_GET_INFORMATION:
218 return "PXENV_UNDI_GET_INFORMATION";
219 case PXENV_UNDI_GET_STATISTICS:
220 return "PXENV_UNDI_GET_STATISTICS";
221 case PXENV_UNDI_CLEAR_STATISTICS:
222 return "PXENV_UNDI_CLEAR_STATISTICS";
223 case PXENV_UNDI_INITIATE_DIAGS:
224 return "PXENV_UNDI_INITIATE_DIAGS";
225 case PXENV_UNDI_FORCE_INTERRUPT:
226 return "PXENV_UNDI_FORCE_INTERRUPT";
227 case PXENV_UNDI_GET_MCAST_ADDRESS:
228 return "PXENV_UNDI_GET_MCAST_ADDRESS";
229 case PXENV_UNDI_GET_NIC_TYPE:
230 return "PXENV_UNDI_GET_NIC_TYPE";
231 case PXENV_UNDI_GET_IFACE_INFO:
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";
241 case PXENV_GET_CACHED_INFO:
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 */
undinet_profiler(unsigned int function)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 */
undinet_call(struct undi_nic * undinic,unsigned int function,void * params,size_t params_len)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;
283 uint32_t started;
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 */
298 RDTSC_IF_PROFILING
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"
305 RDTSC_IF_PROFILING
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 */
373 uint8_t __data16 ( undiisr_irq );
374 #define undiisr_irq __use_data16 ( undiisr_irq )
375
376 /** IRQ chain vector */
377 struct segoff __data16 ( undiisr_next_handler );
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 */
undinet_hook_isr(unsigned int irq)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 ),
399 &undiisr_next_handler );
400 }
401
402 /**
403 * Unhook UNDI interrupt service routine
404 *
405 * @v irq IRQ number
406 */
undinet_unhook_isr(unsigned int irq)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 ),
412 &undiisr_next_handler );
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 */
undinet_isr_triggered(void)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 */
449 static uint8_t __data16_array ( undinet_destaddr, [ETH_ALEN] );
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 */
undinet_transmit(struct net_device * netdev,struct io_buffer * iobuf)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;
467 uint8_t protocol;
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 ) );
507 protocol = P_UNKNOWN;
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 ) ?
521 XMT_BROADCAST : XMT_DESTADDR );
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 */
undinet_poll(struct net_device * netdev)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;
609 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
610 } else {
611 /* Continue ISR processing */
612 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
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 ) {
623 case PXENV_UNDI_ISR_OUT_TRANSMIT:
624 /* We don't care about transmit completions */
625 break;
626 case PXENV_UNDI_ISR_OUT_RECEIVE:
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 );
638 netdev_rx_err ( netdev, NULL, -EINVAL );
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 */
648 netdev_rx_err ( netdev, NULL, -ENOMEM );
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 )
672 --last_trigger_count;
673 }
674 profile_stop ( &undinet_rx_profiler );
675 break;
676 case PXENV_UNDI_ISR_OUT_DONE:
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 }
687 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
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 */
undinet_open(struct net_device * netdev)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 ) );
725 undinet_call ( undinic, PXENV_UNDI_SET_STATION_ADDRESS,
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 */
undinet_close(struct net_device * netdev)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 ) {
760 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
761 if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
762 sizeof ( undi_isr ) ) ) != 0 )
763 break;
764 switch ( undi_isr.FuncFlag ) {
765 case PXENV_UNDI_ISR_OUT_TRANSMIT:
766 case PXENV_UNDI_ISR_OUT_RECEIVE:
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 */
undinet_irq(struct net_device * netdev,int enable)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 */
804 static struct net_device_operations undinet_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 */
813 struct undinet_irq_broken {
814 /** PCI vendor ID */
815 uint16_t pci_vendor;
816 /** PCI device ID */
817 uint16_t pci_device;
818 /** PCI subsystem vendor ID */
819 uint16_t pci_subsys_vendor;
820 /** PCI subsystem ID */
821 uint16_t pci_subsys;
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 */
835 static const struct undinet_irq_broken undinet_irq_broken_list[] = {
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 */
undinet_irq_is_broken(struct device_description * desc)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 */
undinet_probe(struct undi_device * undi,struct device * dev)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;
906 netdev_init ( netdev, &undinet_operations );
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,
945 PXENV_UNDI_INITIALIZE,
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 */
955 mdelay ( UNDI_INITIALIZE_RETRY_DELAY_MS );
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 );
966 memcpy ( netdev->ll_addr, undi_info.CurrentNodeAddress, 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 */
undinet_remove(struct undi_device * undi)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 */
1050 unregister_netdev ( netdev );
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 }
1082