iPXE
snpnet.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 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
20FILE_LICENCE ( GPL2_OR_LATER );
21FILE_SECBOOT ( PERMITTED );
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <errno.h>
27#include <ipxe/iobuf.h>
28#include <ipxe/netdevice.h>
29#include <ipxe/ethernet.h>
30#include <ipxe/if_ether.h>
31#include <ipxe/vsprintf.h>
32#include <ipxe/timer.h>
33#include <ipxe/efi/efi.h>
35#include <ipxe/efi/efi_driver.h>
36#include <ipxe/efi/efi_utils.h>
37#include <ipxe/efi/efi_snp.h>
38#include "snpnet.h"
39
40/** @file
41 *
42 * SNP NIC driver
43 *
44 */
45
46/** An SNP NIC */
47struct snp_nic {
48 /** EFI device */
50 /** Simple network protocol */
52 /** Generic device */
53 struct device dev;
54
55 /** Maximum packet size
56 *
57 * This is calculated as the sum of MediaHeaderSize and
58 * MaxPacketSize, and may therefore be an overestimate.
59 */
60 size_t mtu;
61
62 /** Current transmit buffer */
64 /** Current receive buffer */
66};
67
68/** Maximum number of received packets per poll */
69#define SNP_RX_QUOTA 4
70
71/** Maximum initialisation retry count */
72#define SNP_INITIALIZE_RETRY_MAX 10
73
74/** Delay between each initialisation retry */
75#define SNP_INITIALIZE_RETRY_DELAY_MS 10
76
77/** Additional padding for receive buffers
78 *
79 * Some SNP implementations seem to require additional space in the
80 * allocated receive buffers, otherwise full-length packets will be
81 * silently dropped.
82 *
83 * The EDK2 MnpDxe driver happens to allocate an additional 8 bytes of
84 * padding (4 for a VLAN tag, 4 for the Ethernet frame checksum).
85 * Match this behaviour since drivers are very likely to have been
86 * tested against MnpDxe.
87 */
88#define SNP_RX_PAD 8
89
90/** An SNP interface patch to inhibit shutdown for insomniac devices */
92 /** Original Shutdown() method */
94 /** Original Stop() method */
96};
97
98/**
99 * Format SNP MAC address (for debugging)
100 *
101 * @v mac MAC address
102 * @v len Length of MAC address
103 * @ret text MAC address as text
104 */
105static const char * snpnet_mac_text ( EFI_MAC_ADDRESS *mac, size_t len ) {
106 static char buf[ sizeof ( *mac ) * 3 /* "xx:" or "xx\0" */ ];
107 size_t used = 0;
108 unsigned int i;
109
110 for ( i = 0 ; i < len ; i++ ) {
111 used += ssnprintf ( &buf[used], ( sizeof ( buf ) - used ),
112 "%s%02x", ( used ? ":" : "" ),
113 mac->Addr[i] );
114 }
115 return buf;
116}
117
118/**
119 * Dump SNP mode information (for debugging)
120 *
121 * @v netdev Network device
122 */
123static void snpnet_dump_mode ( struct net_device *netdev ) {
124 struct snp_nic *snp = netdev->priv;
126 size_t mac_len = mode->HwAddressSize;
127 unsigned int i;
128
129 /* Do nothing unless debugging is enabled */
130 if ( ! DBG_EXTRA )
131 return;
132
133 DBGC2 ( snp, "SNP %s st %d type %d hdr %d pkt %d rxflt %#x/%#x%s "
134 "nvram %d acc %d mcast %d/%d\n", netdev->name, mode->State,
135 mode->IfType, mode->MediaHeaderSize, mode->MaxPacketSize,
136 mode->ReceiveFilterSetting, mode->ReceiveFilterMask,
137 ( mode->MultipleTxSupported ? " multitx" : "" ),
138 mode->NvRamSize, mode->NvRamAccessSize,
139 mode->MCastFilterCount, mode->MaxMCastFilterCount );
140 DBGC2 ( snp, "SNP %s hw %s", netdev->name,
141 snpnet_mac_text ( &mode->PermanentAddress, mac_len ) );
142 DBGC2 ( snp, " addr %s%s",
143 snpnet_mac_text ( &mode->CurrentAddress, mac_len ),
144 ( mode->MacAddressChangeable ? "" : "(f)" ) );
145 DBGC2 ( snp, " bcast %s\n",
146 snpnet_mac_text ( &mode->BroadcastAddress, mac_len ) );
147 for ( i = 0 ; i < mode->MCastFilterCount ; i++ ) {
148 DBGC2 ( snp, "SNP %s mcast %s\n", netdev->name,
149 snpnet_mac_text ( &mode->MCastFilter[i], mac_len ) );
150 }
151 DBGC2 ( snp, "SNP %s media %s\n", netdev->name,
152 ( mode->MediaPresentSupported ?
153 ( mode->MediaPresent ? "present" : "not present" ) :
154 "presence not supported" ) );
155}
156
157/**
158 * Check link state
159 *
160 * @v netdev Network device
161 */
162static void snpnet_check_link ( struct net_device *netdev ) {
163 struct snp_nic *snp = netdev->priv;
165
166 /* Do nothing unless media presence detection is supported */
167 if ( ! mode->MediaPresentSupported )
168 return;
169
170 /* Report any link status change */
171 if ( mode->MediaPresent && ( ! netdev_link_ok ( netdev ) ) ) {
173 } else if ( ( ! mode->MediaPresent ) && netdev_link_ok ( netdev ) ) {
175 }
176}
177
178/**
179 * Transmit packet
180 *
181 * @v netdev Network device
182 * @v iobuf I/O buffer
183 * @ret rc Return status code
184 */
185static int snpnet_transmit ( struct net_device *netdev,
186 struct io_buffer *iobuf ) {
187 struct snp_nic *snp = netdev->priv;
188 EFI_STATUS efirc;
189 int rc;
190
191 /* Do nothing if shutdown is in progress */
193 return -ECANCELED;
194
195 /* Defer the packet if there is already a transmission in progress */
196 if ( snp->txbuf ) {
197 netdev_tx_defer ( netdev, iobuf );
198 return 0;
199 }
200
201 /* Pad to minimum Ethernet length, to work around underlying
202 * drivers that do not correctly handle frame padding
203 * themselves.
204 */
205 iob_pad ( iobuf, ETH_ZLEN );
206
207 /* Transmit packet */
208 if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ),
209 iobuf->data, NULL, NULL,
210 NULL ) ) != 0 ) {
211 rc = -EEFI ( efirc );
212 DBGC ( snp, "SNP %s could not transmit: %s\n",
213 netdev->name, strerror ( rc ) );
214 return rc;
215 }
216 snp->txbuf = iobuf;
217
218 return 0;
219}
220
221/**
222 * Poll for completed packets
223 *
224 * @v netdev Network device
225 */
226static void snpnet_poll_tx ( struct net_device *netdev ) {
227 struct snp_nic *snp = netdev->priv;
228 struct io_buffer *iobuf;
229 UINT32 irq;
230 VOID *txbuf;
231 EFI_STATUS efirc;
232 int rc;
233
234 /* Get status */
235 txbuf = NULL;
236 if ( ( efirc = snp->snp->GetStatus ( snp->snp, &irq, &txbuf ) ) != 0 ) {
237 rc = -EEFI ( efirc );
238 DBGC ( snp, "SNP %s could not get status: %s\n",
239 netdev->name, strerror ( rc ) );
241 return;
242 }
243
244 /* Do nothing unless we have a completion */
245 if ( ! txbuf )
246 return;
247
248 /* Sanity check */
249 if ( ! snp->txbuf ) {
250 DBGC ( snp, "SNP %s reported spurious TX completion\n",
251 netdev->name );
253 return;
254 }
255
256 /* Complete transmission */
257 iobuf = snp->txbuf;
258 snp->txbuf = NULL;
259 netdev_tx_complete ( netdev, iobuf );
260}
261
262/**
263 * Poll for received packets
264 *
265 * @v netdev Network device
266 */
267static void snpnet_poll_rx ( struct net_device *netdev ) {
268 struct snp_nic *snp = netdev->priv;
269 UINTN len;
270 unsigned int quota;
271 EFI_STATUS efirc;
272 int rc;
273
274 /* Retrieve up to SNP_RX_QUOTA packets */
275 for ( quota = SNP_RX_QUOTA ; quota ; quota-- ) {
276
277 /* Allocate buffer, if required */
278 if ( ! snp->rxbuf ) {
279 snp->rxbuf = alloc_iob ( snp->mtu + SNP_RX_PAD );
280 if ( ! snp->rxbuf ) {
281 /* Leave for next poll */
282 break;
283 }
284 }
285
286 /* Receive packet */
287 len = iob_tailroom ( snp->rxbuf );
288 if ( ( efirc = snp->snp->Receive ( snp->snp, NULL, &len,
289 snp->rxbuf->data, NULL,
290 NULL, NULL ) ) != 0 ) {
291
292 /* EFI_NOT_READY is just the usual "no packet"
293 * status indication; ignore it.
294 */
295 if ( efirc == EFI_NOT_READY )
296 break;
297
298 /* Anything else is an error */
299 rc = -EEFI ( efirc );
300 DBGC ( snp, "SNP %s could not receive: %s\n",
301 netdev->name, strerror ( rc ) );
303 break;
304 }
305
306 /* Hand off to network stack */
307 iob_put ( snp->rxbuf, len );
308 netdev_rx ( netdev, snp->rxbuf );
309 snp->rxbuf = NULL;
310 }
311}
312
313/**
314 * Poll for completed packets
315 *
316 * @v netdev Network device
317 */
318static void snpnet_poll ( struct net_device *netdev ) {
319
320 /* Do nothing if shutdown is in progress */
322 return;
323
324 /* Process any TX completions */
326
327 /* Process any RX completions */
329
330 /* Check for link state changes */
332}
333
334/**
335 * Set receive filters
336 *
337 * @v netdev Network device
338 * @ret rc Return status code
339 */
340static int snpnet_rx_filters ( struct net_device *netdev ) {
341 struct snp_nic *snp = netdev->priv;
342 UINT32 filters[] = {
353 };
354 unsigned int i;
355 EFI_STATUS efirc;
356 int rc;
357
358 /* Try possible receive filters in turn */
359 for ( i = 0; i < ( sizeof ( filters ) / sizeof ( filters[0] ) ); i++ ) {
360 efirc = snp->snp->ReceiveFilters ( snp->snp, filters[i],
362 0, NULL );
363 if ( efirc == 0 )
364 return 0;
365 rc = -EEFI ( efirc );
366 DBGC ( snp, "SNP %s could not set receive filters %#02x (have "
367 "%#02x): %s\n", netdev->name, filters[i],
369 }
370
371 return rc;
372}
373
374/**
375 * Open network device
376 *
377 * @v netdev Network device
378 * @ret rc Return status code
379 */
380static int snpnet_open ( struct net_device *netdev ) {
381 struct snp_nic *snp = netdev->priv;
382 EFI_MAC_ADDRESS *mac = ( ( void * ) netdev->ll_addr );
384 EFI_STATUS efirc;
385 unsigned int retry;
386 int rc;
387
388 /* Try setting MAC address (before initialising) */
389 if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){
390 rc = -EEFI ( efirc );
391 DBGC ( snp, "SNP %s could not set station address before "
392 "initialising: %s\n", netdev->name, strerror ( rc ) );
393 /* Ignore error */
394 }
395
396 /* Initialise NIC, retrying multiple times if link stays down */
397 for ( retry = 0 ; ; ) {
398
399 /* Initialise NIC, if not already initialised */
400 if ( ( mode->State != EfiSimpleNetworkInitialized ) &&
401 ( ( efirc = snp->snp->Initialize ( snp->snp,
402 0, 0 ) ) != 0 ) ) {
403 rc = -EEFI ( efirc );
405 DBGC ( snp, "SNP %s could not initialise: %s\n",
406 netdev->name, strerror ( rc ) );
407 return rc;
408 }
409
410 /* Stop if we have link up (or no link detection capability) */
411 if ( ( ! mode->MediaPresentSupported ) || mode->MediaPresent )
412 break;
413
414 /* Stop if we have exceeded our retry count. This is
415 * not a failure; it is plausible that we genuinely do
416 * not have link up.
417 */
418 if ( ++retry >= SNP_INITIALIZE_RETRY_MAX )
419 break;
420 DBGC ( snp, "SNP %s retrying initialisation (retry %d)\n",
421 netdev->name, retry );
422
423 /* Delay to allow time for link to establish */
425
426 /* Shut down and retry (unless device is insomniac);
427 * this is sometimes necessary in order to persuade
428 * the underlying SNP driver to actually update the
429 * link state.
430 */
431 if ( ( ! netdev_insomniac ( netdev ) ) &&
432 ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
433 rc = -EEFI ( efirc );
435 DBGC ( snp, "SNP %s could not shut down: %s\n",
436 netdev->name, strerror ( rc ) );
437 return rc;
438 }
439 }
440
441 /* Try setting MAC address (after initialising) */
442 if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){
443 rc = -EEFI ( efirc );
444 DBGC ( snp, "SNP %s could not set station address after "
445 "initialising: %s\n", netdev->name, strerror ( rc ) );
446 /* Ignore error */
447 }
448
449 /* Set receive filters */
450 if ( ( rc = snpnet_rx_filters ( netdev ) ) != 0 ) {
451 /* Ignore error */
452 }
453
454 /* Dump mode information (for debugging) */
456
457 return 0;
458}
459
460/**
461 * Close network device
462 *
463 * @v netdev Network device
464 */
465static void snpnet_close ( struct net_device *netdev ) {
466 struct snp_nic *snp = netdev->priv;
467 EFI_STATUS efirc;
468 int rc;
469
470 /* Shut down NIC (unless whole system shutdown is in progress,
471 * or device is insomniac).
472 */
473 if ( ( ! efi_shutdown_in_progress ) &&
474 ( ! netdev_insomniac ( netdev ) ) &&
475 ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
476 rc = -EEFI ( efirc );
477 DBGC ( snp, "SNP %s could not shut down: %s\n",
478 netdev->name, strerror ( rc ) );
479 /* Nothing we can do about this */
480 }
481
482 /* Discard transmit buffer, if applicable */
483 if ( snp->txbuf ) {
485 snp->txbuf = NULL;
486 }
487
488 /* Discard receive buffer, if applicable */
489 if ( snp->rxbuf ) {
490 free_iob ( snp->rxbuf );
491 snp->rxbuf = NULL;
492 }
493}
494
495/** SNP network device operations */
497 .open = snpnet_open,
498 .close = snpnet_close,
499 .transmit = snpnet_transmit,
500 .poll = snpnet_poll,
501};
502
503/**
504 * Check to see if driver supports a device
505 *
506 * @v device EFI device handle
507 * @v protocol Protocol GUID
508 * @v inhibit_wifi Inhibit wireless devices
509 * @ret rc Return status code
510 */
512 int inhibit_wifi ) {
513 EFI_HANDLE parent;
514 int rc;
515
516 /* Check that this is not a device we are providing ourselves */
517 if ( find_snpdev ( device ) != NULL ) {
518 DBGCP ( device, "HANDLE %s is provided by this binary\n",
520 return -ENOTTY;
521 }
522
523 /* Test for presence of protocol */
524 if ( ( rc = efi_test ( device, protocol ) ) != 0 ) {
525 DBGCP ( device, "HANDLE %s is not a %s device\n",
528 return rc;
529 }
530
531 /* Check that there are no instances of this protocol further
532 * up this device path.
533 */
535 &parent, 1 ) ) == 0 ) {
536 DBGC2 ( device, "HANDLE %s has %s-supporting parent ",
539 DBGC2 ( device, "%s\n", efi_handle_name ( parent ) );
540 return -ENOTTY;
541 }
542 DBGC ( device, "HANDLE %s is a %s device\n",
544
545 /* Check for wireless devices, if applicable */
546 if ( inhibit_wifi &&
547 ( ( efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) ) {
548 DBGC ( device, "HANDLE %s is wireless: assuming vendor %s "
549 "driver is too unreliable to use\n",
552 return -ENOTTY;
553 }
554
555 return 0;
556}
557
558/**
559 * Check if device must be insomniac
560 *
561 * @v device EFI device handle
562 * @v is_insomniac Device must be insomniac
563 */
565 int rc;
566
567 /* Check for wireless devices
568 *
569 * The UEFI model for wireless network configuration is
570 * somewhat underdefined. At the time of writing, the EDK2
571 * "UEFI WiFi Connection Manager" driver provides only one way
572 * to configure wireless network credentials, which is to
573 * enter them interactively via an HII form. Credentials are
574 * not stored (or exposed via any protocol interface), and so
575 * any temporary disconnection from the wireless network will
576 * inevitably leave the interface in an unusable state that
577 * cannot be recovered without user intervention.
578 *
579 * Experimentation shows that at least some wireless network
580 * drivers will disconnect from the wireless network when the
581 * SNP Shutdown() method is called, or if the device is not
582 * polled sufficiently frequently to maintain its association
583 * to the network. We therefore inhibit calls to Shutdown()
584 * and Stop() for any such SNP protocol interfaces, and mark
585 * our network device as insomniac so that it will be polled
586 * even when closed.
587 */
588 if ( ( rc = efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) {
589 DBGC ( device, "SNP %s is wireless: assuming insomniac\n",
591 return 1;
592 }
593
594 return 0;
595}
596
597/**
598 * Ignore shutdown attempt
599 *
600 * @v snp SNP interface
601 * @ret efirc EFI status code
602 */
603static EFI_STATUS EFIAPI
608
609/**
610 * Patch SNP protocol interface to prevent shutdown
611 *
612 * @v device EFI device handle
613 * @v patch Interface patch
614 * @ret rc Return status code
615 */
617 struct snp_insomniac_patch *patch ) {
619 int rc;
620
621 /* Open interface for ephemeral use */
623 &interface ) ) != 0 ) {
624 DBGC ( device, "SNP %s cannot open SNP protocol for patching: "
625 "%s\n", efi_handle_name ( device ), strerror ( rc ) );
626 return rc;
627 }
628
629 /* Record original Shutdown() and Stop() methods */
630 patch->shutdown = interface->Shutdown;
631 patch->stop = interface->Stop;
632
633 /* Inhibit other UEFI drivers' calls to Shutdown() and Stop()
634 *
635 * This is necessary since disconnecting the MnpDxe driver
636 * will attempt to shut down the SNP device, which would leave
637 * us with an unusable device.
638 */
639 interface->Shutdown = snpnet_do_nothing;
641 DBGC ( device, "SNP %s patched to inhibit shutdown\n",
643
644 return 0;
645}
646
647/**
648 * Restore patched SNP protocol interface
649 *
650 * @v device EFI device handle
651 * @v patch Interface patch to fill in
652 * @ret rc Return status code
653 */
655 struct snp_insomniac_patch *patch ) {
657 int rc;
658
659 /* Avoid returning uninitialised data on error */
660 memset ( patch, 0, sizeof ( *patch ) );
661
662 /* Open interface for ephemeral use */
664 &interface ) ) != 0 ) {
665 DBGC ( device, "SNP %s cannot open patched SNP protocol: %s\n",
667 return rc;
668 }
669
670 /* Restore original Shutdown() and Stop() methods, if possible */
671 if ( interface->Shutdown == snpnet_do_nothing )
672 interface->Shutdown = patch->shutdown;
673 if ( interface->Stop == snpnet_do_nothing )
674 interface->Stop = patch->stop;
675
676 /* Check that original methods were restored (by us or others) */
677 if ( ( interface->Shutdown != patch->shutdown ) ||
678 ( interface->Stop != patch->stop ) ) {
679 DBGC ( device, "SNP %s could not restore patched SNP "
680 "protocol\n", efi_handle_name ( device ) );
681 return -EBUSY;
682 }
683
684 return 0;
685}
686
687/**
688 * Exclude existing drivers
689 *
690 * @v device EFI device handle
691 * @ret rc Return status code
692 */
695 struct snp_insomniac_patch patch;
696 int insomniac;
697 int rc;
698
699 /* Check if this is a device that must not ever be shut down */
700 insomniac = snpnet_is_insomniac ( device );
701
702 /* Inhibit calls to Shutdown() and Stop(), if applicable */
703 if ( insomniac &&
704 ( ( rc = snpnet_insomniac_patch ( device, &patch ) ) != 0 ) ) {
705 goto err_patch;
706 }
707
708 /* Exclude existing SNP drivers */
709 if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) {
710 DBGC ( device, "SNP %s could not exclude drivers: %s\n",
712 goto err_exclude;
713 }
714
715 err_exclude:
716 if ( insomniac )
718 err_patch:
719 return rc;
720}
721
722/**
723 * Attach driver to device
724 *
725 * @v efidev EFI device
726 * @ret rc Return status code
727 */
728int snpnet_start ( struct efi_device *efidev ) {
729 EFI_HANDLE device = efidev->device;
732 struct net_device *netdev;
733 struct snp_nic *snp;
734 EFI_STATUS efirc;
735 int rc;
736
737 /* Open SNP protocol */
738 if ( ( rc = efi_open_by_driver ( device,
740 &interface ) ) != 0 ) {
741 DBGC ( device, "SNP %s cannot open SNP protocol: %s\n",
745 goto err_open_protocol;
746 }
747
748 /* Allocate and initialise structure */
749 netdev = alloc_etherdev ( sizeof ( *snp ) );
750 if ( ! netdev ) {
751 rc = -ENOMEM;
752 goto err_alloc;
753 }
755 snp = netdev->priv;
756 snp->efidev = efidev;
757 snp->snp = interface;
758 mode = snp->snp->Mode;
760
761 /* Populate underlying device information */
762 efi_device_info ( device, "SNP", &snp->dev );
763 snp->dev.driver_name = "SNP";
764 snp->dev.parent = &efidev->dev;
765 list_add ( &snp->dev.siblings, &efidev->dev.children );
766 INIT_LIST_HEAD ( &snp->dev.children );
767 netdev->dev = &snp->dev;
768
769 /* Check if device is insomniac */
770 if ( snpnet_is_insomniac ( device ) )
771 netdev->state |= NETDEV_INSOMNIAC;
772
773 /* Bring to the correct state for a closed interface */
774 if ( ( mode->State == EfiSimpleNetworkStopped ) &&
775 ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) {
776 rc = -EEFI ( efirc );
777 DBGC ( device, "SNP %s could not start: %s\n",
779 goto err_start;
780 }
781 if ( ( mode->State == EfiSimpleNetworkInitialized ) &&
782 ( ! netdev_insomniac ( netdev ) ) &&
783 ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
784 rc = -EEFI ( efirc );
785 DBGC ( device, "SNP %s could not shut down: %s\n",
787 goto err_shutdown;
788 }
789
790 /* Populate network device parameters */
791 if ( mode->HwAddressSize != netdev->ll_protocol->hw_addr_len ) {
792 DBGC ( device, "SNP %s has invalid hardware address length "
793 "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
794 rc = -ENOTSUP;
795 goto err_hw_addr_len;
796 }
797 memcpy ( netdev->hw_addr, &mode->PermanentAddress,
798 netdev->ll_protocol->hw_addr_len );
799 if ( mode->HwAddressSize != netdev->ll_protocol->ll_addr_len ) {
800 DBGC ( device, "SNP %s has invalid link-layer address length "
801 "%d\n", efi_handle_name ( device ), mode->HwAddressSize);
802 rc = -ENOTSUP;
803 goto err_ll_addr_len;
804 }
805 memcpy ( netdev->ll_addr, &mode->CurrentAddress,
806 netdev->ll_protocol->ll_addr_len );
807 snp->mtu = ( snp->snp->Mode->MaxPacketSize +
808 snp->snp->Mode->MediaHeaderSize );
809
810 /* Register network device */
811 if ( ( rc = register_netdev ( netdev ) ) != 0 )
812 goto err_register_netdev;
813 DBGC ( device, "SNP %s registered as %s\n",
814 efi_handle_name ( device ), netdev->name );
815
816 /* Set initial link state */
817 if ( snp->snp->Mode->MediaPresentSupported ) {
819 } else {
821 }
822
823 return 0;
824
826 err_register_netdev:
827 err_ll_addr_len:
828 err_hw_addr_len:
829 err_shutdown:
830 err_start:
831 list_del ( &snp->dev.siblings );
833 netdev_put ( netdev );
834 err_alloc:
836 err_open_protocol:
837 return rc;
838}
839
840/**
841 * Detach driver from device
842 *
843 * @v efidev EFI device
844 */
845void snpnet_stop ( struct efi_device *efidev ) {
846 struct net_device *netdev = efidev_get_drvdata ( efidev );
847 struct snp_nic *snp = netdev->priv;
849 EFI_STATUS efirc;
850 int rc;
851
852 /* Unregister network device */
854
855 /* Stop SNP protocol (unless whole system shutdown is in progress) */
856 if ( ( ! efi_shutdown_in_progress ) &&
857 ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
858 rc = -EEFI ( efirc );
859 DBGC ( device, "SNP %s could not stop: %s\n",
861 /* Nothing we can do about this */
862 }
863
864 /* Free network device */
865 list_del ( &snp->dev.siblings );
867 netdev_put ( netdev );
868
869 /* Close SNP protocol */
871}
UINT64 UINTN
Unsigned value of native width.
#define EFIAPI
unsigned int UINT32
4-byte unsigned value.
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
#define VOID
Undeclared type.
Definition Base.h:272
The EFI_SIMPLE_NETWORK_PROTOCOL provides services to initialize a network interface,...
#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
EFI_STATUS(EFIAPI * EFI_SIMPLE_NETWORK_SHUTDOWN)(IN EFI_SIMPLE_NETWORK_PROTOCOL *This)
Resets a network adapter and leaves it in a state that is safe for another driver to initialize.
@ EfiSimpleNetworkInitialized
@ EfiSimpleNetworkStopped
struct _EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK_PROTOCOL
#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST
#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
EFI_STATUS(EFIAPI * EFI_SIMPLE_NETWORK_STOP)(IN EFI_SIMPLE_NETWORK_PROTOCOL *This)
Changes the state of a network interface from "started" to "stopped".
#define EFI_NOT_READY
Enumeration of EFI_STATUS.
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
GUID EFI_GUID
128-bit buffer containing a unique identifier value.
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
ring len
Length.
Definition dwmac.h:226
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
Definition efi_debug.c:652
int efi_driver_exclude(EFI_HANDLE device, EFI_GUID *protocol)
Try to disconnect an existing EFI driver.
Definition efi_driver.c:438
EFI driver interface.
static void * efidev_get_drvdata(struct efi_device *efidev)
Get EFI driver-private data.
Definition efi_driver.h:98
static void efidev_set_drvdata(struct efi_device *efidev, void *priv)
Set EFI driver-private data.
Definition efi_driver.h:87
EFI_GUID efi_simple_network_protocol_guid
Simple network protocol GUID.
Definition efi_guid.c:341
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition efi_guid.c:726
EFI_GUID efi_wifi2_protocol_guid
WiFi 2 protocol GUID.
Definition efi_guid.c:437
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition efi_init.c:60
void efi_close_by_driver(EFI_HANDLE handle, EFI_GUID *protocol)
Close protocol opened for persistent use by a driver.
Definition efi_open.c:279
struct efi_snp_device * find_snpdev(EFI_HANDLE handle)
Find SNP device by EFI device handle.
Definition efi_snp.c:2104
iPXE EFI SNP interface
void efi_device_info(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying device information.
Definition efi_utils.c:189
int efi_locate_device(EFI_HANDLE device, EFI_GUID *protocol, EFI_HANDLE *parent, unsigned int skip)
Locate parent device supporting a given protocol.
Definition efi_utils.c:46
EFI utilities.
uint8_t mac[ETH_ALEN]
MAC address.
Definition ena.h:13
uint16_t mode
Acceleration mode.
Definition ena.h:15
Error codes.
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition ethernet.c:265
Ethernet protocol.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC2(...)
Definition compiler.h:522
#define DBG_EXTRA
Definition compiler.h:319
#define DBGCP(...)
Definition compiler.h:539
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EPIPE
Broken pipe.
Definition errno.h:620
#define ENOMEM
Not enough space.
Definition errno.h:535
#define EBUSY
Device or resource busy.
Definition errno.h:339
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ECANCELED
Operation canceled.
Definition errno.h:344
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define ETH_ZLEN
Definition if_ether.h:11
EFI API.
#define efi_open_by_driver(handle, protocol, interface)
Open protocol for persistent use by a driver.
Definition efi.h:474
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition efi.h:444
#define EFI_HANDLE
Definition efi.h:53
#define efi_test(handle, protocol)
Test protocol existence.
Definition efi.h:433
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition efi.h:175
#define DBGC_EFI_OPENERS(...)
Definition efi.h:345
iPXE timers
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void iob_pad(struct io_buffer *iobuf, size_t min_len)
Pad I/O buffer.
Definition iobpad.c:50
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
Definition iobuf.h:180
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition list.h:46
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void netdev_link_down(struct net_device *netdev)
Mark network device as having link down.
Definition netdevice.c:231
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition netdevice.c:549
void netdev_tx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard transmitted packet.
Definition netdevice.c:441
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition netdevice.c:942
void netdev_tx_defer(struct net_device *netdev, struct io_buffer *iobuf)
Defer transmitted packet.
Definition netdevice.c:413
void netdev_tx_complete_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Complete network transmission.
Definition netdevice.c:471
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition netdevice.c:587
int register_netdev(struct net_device *netdev)
Register network device.
Definition netdevice.c:760
Network device management.
static int netdev_link_ok(struct net_device *netdev)
Check link state of network device.
Definition netdevice.h:640
#define NETDEV_INSOMNIAC
Network device must be polled even when closed.
Definition netdevice.h:462
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition netdevice.h:789
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition netdevice.h:519
static int netdev_insomniac(struct net_device *netdev)
Check whether or not network device must be polled even while closed.
Definition netdevice.h:707
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition netdevice.h:532
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition netdevice.h:767
static int snpnet_open(struct net_device *netdev)
Open network device.
Definition snpnet.c:380
int snpnet_supported(EFI_HANDLE device, EFI_GUID *protocol, int inhibit_wifi)
Check to see if driver supports a device.
Definition snpnet.c:511
int snpnet_start(struct efi_device *efidev)
Attach driver to device.
Definition snpnet.c:728
static void snpnet_check_link(struct net_device *netdev)
Check link state.
Definition snpnet.c:162
static int snpnet_insomniac_restore(EFI_HANDLE device, struct snp_insomniac_patch *patch)
Restore patched SNP protocol interface.
Definition snpnet.c:654
static EFI_STATUS EFIAPI snpnet_do_nothing(EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused)
Ignore shutdown attempt.
Definition snpnet.c:604
#define SNP_RX_QUOTA
Maximum number of received packets per poll.
Definition snpnet.c:69
static int snpnet_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit packet.
Definition snpnet.c:185
static void snpnet_poll(struct net_device *netdev)
Poll for completed packets.
Definition snpnet.c:318
#define SNP_INITIALIZE_RETRY_DELAY_MS
Delay between each initialisation retry.
Definition snpnet.c:75
static struct net_device_operations snpnet_operations
SNP network device operations.
Definition snpnet.c:496
static void snpnet_dump_mode(struct net_device *netdev)
Dump SNP mode information (for debugging)
Definition snpnet.c:123
static void snpnet_close(struct net_device *netdev)
Close network device.
Definition snpnet.c:465
static int snpnet_is_insomniac(EFI_HANDLE device)
Check if device must be insomniac.
Definition snpnet.c:564
#define SNP_INITIALIZE_RETRY_MAX
Maximum initialisation retry count.
Definition snpnet.c:72
static void snpnet_poll_tx(struct net_device *netdev)
Poll for completed packets.
Definition snpnet.c:226
static const char * snpnet_mac_text(EFI_MAC_ADDRESS *mac, size_t len)
Format SNP MAC address (for debugging)
Definition snpnet.c:105
int snpnet_exclude(EFI_HANDLE device)
Exclude existing drivers.
Definition snpnet.c:693
#define SNP_RX_PAD
Additional padding for receive buffers.
Definition snpnet.c:88
static int snpnet_insomniac_patch(EFI_HANDLE device, struct snp_insomniac_patch *patch)
Patch SNP protocol interface to prevent shutdown.
Definition snpnet.c:616
static int snpnet_rx_filters(struct net_device *netdev)
Set receive filters.
Definition snpnet.c:340
static void snpnet_poll_rx(struct net_device *netdev)
Poll for received packets.
Definition snpnet.c:267
void snpnet_stop(struct efi_device *efidev)
Detach driver from device.
Definition snpnet.c:845
SNP NIC driver.
uint16_t protocol
Protocol ID.
Definition stp.h:7
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
32-byte buffer containing a network Media Access Control address.
UINT32 ReceiveFilterMask
The multicast receive filter settings supported by the network interface.
UINT32 MediaHeaderSize
The size, in bytes, of the network interface's media header.
BOOLEAN MediaPresentSupported
TRUE if the presence of media can be determined; otherwise FALSE.
UINT32 MaxPacketSize
The maximum size, in bytes, of the packets supported by the network interface.
UINT32 ReceiveFilterSetting
The current multicast receive filter settings.
EFI_SIMPLE_NETWORK_INITIALIZE Initialize
EFI_SIMPLE_NETWORK_RECEIVE Receive
EFI_SIMPLE_NETWORK_START Start
EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters
EFI_SIMPLE_NETWORK_MODE * Mode
Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device.
EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown
EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress
EFI_SIMPLE_NETWORK_TRANSMIT Transmit
EFI_SIMPLE_NETWORK_STOP Stop
EFI_SIMPLE_NETWORK_GET_STATUS GetStatus
A hardware device.
Definition device.h:77
struct list_head children
Devices attached to this device.
Definition device.h:87
An EFI device.
Definition efi_driver.h:18
EFI_HANDLE device
EFI device handle.
Definition efi_driver.h:22
struct device dev
Generic device.
Definition efi_driver.h:20
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
Network device operations.
Definition netdevice.h:214
A network device.
Definition netdevice.h:353
An SNP interface patch to inhibit shutdown for insomniac devices.
Definition snpnet.c:91
EFI_SIMPLE_NETWORK_SHUTDOWN shutdown
Original Shutdown() method.
Definition snpnet.c:93
EFI_SIMPLE_NETWORK_STOP stop
Original Stop() method.
Definition snpnet.c:95
An SNP NIC.
Definition snpnet.c:47
size_t mtu
Maximum packet size.
Definition snpnet.c:60
struct io_buffer * txbuf
Current transmit buffer.
Definition snpnet.c:63
struct io_buffer * rxbuf
Current receive buffer.
Definition snpnet.c:65
EFI_SIMPLE_NETWORK_PROTOCOL * snp
Simple network protocol.
Definition snpnet.c:51
struct device dev
Generic device.
Definition snpnet.c:53
struct efi_device * efidev
EFI device.
Definition snpnet.c:49
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
#define TRUE
Definition tlan.h:46
#define FALSE
Definition tlan.h:45
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition vsprintf.c:421
printf() and friends