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