2 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <gpxe/netdevice.h>
25 #include <gpxe/iobuf.h>
28 #include <gpxe/efi/efi.h>
29 #include <gpxe/efi/Protocol/DriverBinding.h>
30 #include <gpxe/efi/Protocol/PciIo.h>
31 #include <gpxe/efi/Protocol/SimpleNetwork.h>
32 #include <gpxe/efi/Protocol/ComponentName2.h>
33 #include <gpxe/efi/Protocol/NetworkInterfaceIdentifier.h>
34 #include <config/general.h>
38 * gPXE EFI SNP interface
43 struct efi_snp_device {
44 /** The underlying gPXE network device */
45 struct net_device *netdev;
46 /** EFI device handle */
48 /** The SNP structure itself */
49 EFI_SIMPLE_NETWORK_PROTOCOL snp;
50 /** The SNP "mode" (parameters) */
51 EFI_SIMPLE_NETWORK_MODE mode;
52 /** Outstanding TX packet count (via "interrupt status")
54 * Used in order to generate TX completions.
56 unsigned int tx_count_interrupts;
57 /** Outstanding TX packet count (via "recycled tx buffers")
59 * Used in order to generate TX completions.
61 unsigned int tx_count_txbufs;
62 /** Outstanding RX packet count (via "interrupt status") */
63 unsigned int rx_count_interrupts;
64 /** Outstanding RX packet count (via WaitForPacket event) */
65 unsigned int rx_count_events;
66 /** The network interface identifier */
67 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
69 wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
72 * This field is variable in size and must appear at the end
75 EFI_DEVICE_PATH_PROTOCOL path;
78 /** EFI simple network protocol GUID */
79 static EFI_GUID efi_simple_network_protocol_guid
80 = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
82 /** EFI driver binding protocol GUID */
83 static EFI_GUID efi_driver_binding_protocol_guid
84 = EFI_DRIVER_BINDING_PROTOCOL_GUID;
86 /** EFI component name protocol GUID */
87 static EFI_GUID efi_component_name2_protocol_guid
88 = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
90 /** EFI device path protocol GUID */
91 static EFI_GUID efi_device_path_protocol_guid
92 = EFI_DEVICE_PATH_PROTOCOL_GUID;
94 /** Efi network interface identifier GUID */
95 static EFI_GUID efi_nii_protocol_guid = {
96 /* No, this isn't the GUID defined as
97 * EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID in
98 * Protocol/NetworkInterfaceIdentifier.h. That GUID gets
99 * ignored by the EFI network stack. You have to use this one
102 0x1ACED566, 0x76ED, 0x4218,
103 { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
106 /** EFI PCI I/O protocol GUID */
107 static EFI_GUID efi_pci_io_protocol_guid
108 = EFI_PCI_IO_PROTOCOL_GUID;
111 * Set EFI SNP mode based on gPXE net device parameters
113 * @v snp SNP interface
115 static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
116 struct net_device *netdev = snpdev->netdev;
117 EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
118 unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len;
120 mode->HwAddressSize = ll_addr_len;
121 mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len;
122 mode->MaxPacketSize = netdev->max_pkt_len;
123 mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
124 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
125 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
126 assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
127 memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
128 memcpy ( &mode->BroadcastAddress, netdev->ll_protocol->ll_broadcast,
130 memcpy ( &mode->PermanentAddress, netdev->ll_addr, ll_addr_len );
131 mode->IfType = ntohs ( netdev->ll_protocol->ll_proto );
132 mode->MacAddressChangeable = TRUE;
133 mode->MediaPresentSupported = TRUE;
134 mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
138 * Poll net device and count received packets
140 * @v snpdev SNP device
142 static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
143 struct io_buffer *iobuf;
144 unsigned int before = 0;
145 unsigned int after = 0;
146 unsigned int arrived;
148 /* We have to report packet arrivals, and this is the easiest
151 list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
153 netdev_poll ( snpdev->netdev );
154 list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
156 arrived = ( after - before );
158 snpdev->rx_count_interrupts += arrived;
159 snpdev->rx_count_events += arrived;
163 * Change SNP state from "stopped" to "started"
165 * @v snp SNP interface
166 * @ret efirc EFI status code
168 static EFI_STATUS EFIAPI
169 efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
170 struct efi_snp_device *snpdev =
171 container_of ( snp, struct efi_snp_device, snp );
173 DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
175 snpdev->mode.State = EfiSimpleNetworkStarted;
180 * Change SNP state from "started" to "stopped"
182 * @v snp SNP interface
183 * @ret efirc EFI status code
185 static EFI_STATUS EFIAPI
186 efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
187 struct efi_snp_device *snpdev =
188 container_of ( snp, struct efi_snp_device, snp );
190 DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
192 snpdev->mode.State = EfiSimpleNetworkStopped;
197 * Open the network device
199 * @v snp SNP interface
200 * @v extra_rx_bufsize Extra RX buffer size, in bytes
201 * @v extra_tx_bufsize Extra TX buffer size, in bytes
202 * @ret efirc EFI status code
204 static EFI_STATUS EFIAPI
205 efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
206 UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
207 struct efi_snp_device *snpdev =
208 container_of ( snp, struct efi_snp_device, snp );
211 DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
212 snpdev, ( ( unsigned long ) extra_rx_bufsize ),
213 ( ( unsigned long ) extra_tx_bufsize ) );
215 if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
216 DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
217 snpdev, snpdev->netdev->name, strerror ( rc ) );
218 return RC_TO_EFIRC ( rc );
221 snpdev->mode.State = EfiSimpleNetworkInitialized;
226 * Reset the network device
228 * @v snp SNP interface
229 * @v ext_verify Extended verification required
230 * @ret efirc EFI status code
232 static EFI_STATUS EFIAPI
233 efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
234 struct efi_snp_device *snpdev =
235 container_of ( snp, struct efi_snp_device, snp );
238 DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
239 snpdev, ( ext_verify ? "with" : "without" ) );
241 netdev_close ( snpdev->netdev );
242 snpdev->mode.State = EfiSimpleNetworkStarted;
244 if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
245 DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
246 snpdev, snpdev->netdev->name, strerror ( rc ) );
247 return RC_TO_EFIRC ( rc );
250 snpdev->mode.State = EfiSimpleNetworkInitialized;
255 * Shut down the network device
257 * @v snp SNP interface
258 * @ret efirc EFI status code
260 static EFI_STATUS EFIAPI
261 efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
262 struct efi_snp_device *snpdev =
263 container_of ( snp, struct efi_snp_device, snp );
265 DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
267 netdev_close ( snpdev->netdev );
268 snpdev->mode.State = EfiSimpleNetworkStarted;
273 * Manage receive filters
275 * @v snp SNP interface
276 * @v enable Receive filters to enable
277 * @v disable Receive filters to disable
278 * @v mcast_reset Reset multicast filters
279 * @v mcast_count Number of multicast filters
280 * @v mcast Multicast filters
281 * @ret efirc EFI status code
283 static EFI_STATUS EFIAPI
284 efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
285 UINT32 disable, BOOLEAN mcast_reset,
286 UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
287 struct efi_snp_device *snpdev =
288 container_of ( snp, struct efi_snp_device, snp );
291 DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
292 snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
293 ( ( unsigned long ) mcast_count ) );
294 for ( i = 0 ; i < mcast_count ; i++ ) {
295 DBGC2_HDA ( snpdev, i, &mcast[i],
296 snpdev->netdev->ll_protocol->ll_addr_len );
299 /* Lie through our teeth, otherwise MNP refuses to accept us */
304 * Set station address
306 * @v snp SNP interface
307 * @v reset Reset to permanent address
308 * @v new New station address
309 * @ret efirc EFI status code
311 static EFI_STATUS EFIAPI
312 efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
313 EFI_MAC_ADDRESS *new ) {
314 struct efi_snp_device *snpdev =
315 container_of ( snp, struct efi_snp_device, snp );
316 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
318 DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
319 ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
321 /* Set the MAC address */
323 new = &snpdev->mode.PermanentAddress;
324 memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
326 /* MAC address changes take effect only on netdev_open() */
327 if ( snpdev->netdev->state & NETDEV_OPEN ) {
328 DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
329 "devive open\n", snpdev );
336 * Get (or reset) statistics
338 * @v snp SNP interface
339 * @v reset Reset statistics
340 * @v stats_len Size of statistics table
341 * @v stats Statistics table
342 * @ret efirc EFI status code
344 static EFI_STATUS EFIAPI
345 efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
346 UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
347 struct efi_snp_device *snpdev =
348 container_of ( snp, struct efi_snp_device, snp );
349 EFI_NETWORK_STATISTICS stats_buf;
351 DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
352 ( reset ? " reset" : "" ) );
354 /* Gather statistics */
355 memset ( &stats_buf, 0, sizeof ( stats_buf ) );
356 stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
357 stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
358 stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
359 snpdev->netdev->tx_stats.bad );
360 stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
361 stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
362 stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
363 snpdev->netdev->rx_stats.bad );
364 if ( *stats_len > sizeof ( stats_buf ) )
365 *stats_len = sizeof ( stats_buf );
367 memcpy ( stats, &stats_buf, *stats_len );
369 /* Reset statistics if requested to do so */
371 memset ( &snpdev->netdev->tx_stats, 0,
372 sizeof ( snpdev->netdev->tx_stats ) );
373 memset ( &snpdev->netdev->rx_stats, 0,
374 sizeof ( snpdev->netdev->rx_stats ) );
381 * Convert multicast IP address to MAC address
383 * @v snp SNP interface
384 * @v ipv6 Address is IPv6
387 * @ret efirc EFI status code
389 static EFI_STATUS EFIAPI
390 efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
391 EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
392 struct efi_snp_device *snpdev =
393 container_of ( snp, struct efi_snp_device, snp );
394 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
398 ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
399 inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
400 DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
402 /* Try to hash the address */
403 if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
405 DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
406 snpdev, ip_str, strerror ( rc ) );
407 return RC_TO_EFIRC ( rc );
414 * Read or write non-volatile storage
416 * @v snp SNP interface
417 * @v read Operation is a read
418 * @v offset Starting offset within NVRAM
419 * @v len Length of data buffer
420 * @v data Data buffer
421 * @ret efirc EFI status code
423 static EFI_STATUS EFIAPI
424 efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
425 UINTN offset, UINTN len, VOID *data ) {
426 struct efi_snp_device *snpdev =
427 container_of ( snp, struct efi_snp_device, snp );
429 DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
430 ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
431 ( ( unsigned long ) len ) );
433 DBGC2_HDA ( snpdev, offset, data, len );
435 return EFI_UNSUPPORTED;
439 * Read interrupt status and TX recycled buffer status
441 * @v snp SNP interface
442 * @v interrupts Interrupt status, or NULL
443 * @v txbufs Recycled transmit buffer address, or NULL
444 * @ret efirc EFI status code
446 static EFI_STATUS EFIAPI
447 efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
448 UINT32 *interrupts, VOID **txbufs ) {
449 struct efi_snp_device *snpdev =
450 container_of ( snp, struct efi_snp_device, snp );
452 DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
454 /* Poll the network device */
455 efi_snp_poll ( snpdev );
457 /* Interrupt status. In practice, this seems to be used only
458 * to detect TX completions.
462 /* Report TX completions once queue is empty; this
463 * avoids having to add hooks in the net device layer.
465 if ( snpdev->tx_count_interrupts &&
466 list_empty ( &snpdev->netdev->tx_queue ) ) {
467 *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
468 snpdev->tx_count_interrupts--;
471 if ( snpdev->rx_count_interrupts ) {
472 *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
473 snpdev->rx_count_interrupts--;
475 DBGC2 ( snpdev, " INTS:%02x", *interrupts );
478 /* TX completions. It would be possible to design a more
479 * idiotic scheme for this, but it would be a challenge.
480 * According to the UEFI header file, txbufs will be filled in
481 * with a list of "recycled transmit buffers" (i.e. completed
482 * TX buffers). Observant readers may care to note that
483 * *txbufs is a void pointer. Precisely how a list of
484 * completed transmit buffers is meant to be represented as an
485 * array of voids is left as an exercise for the reader.
487 * The only users of this interface (MnpDxe/MnpIo.c and
488 * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
489 * seeing a non-NULL result return in txbufs. This is valid
490 * provided that they do not ever attempt to transmit more
491 * than one packet concurrently (and that TX never times out).
494 if ( snpdev->tx_count_txbufs &&
495 list_empty ( &snpdev->netdev->tx_queue ) ) {
496 *txbufs = "Which idiot designed this API?";
497 snpdev->tx_count_txbufs--;
501 DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
504 DBGC2 ( snpdev, "\n" );
509 * Start packet transmission
511 * @v snp SNP interface
512 * @v ll_header_len Link-layer header length, if to be filled in
513 * @v len Length of data buffer
514 * @v data Data buffer
515 * @v ll_src Link-layer source address, if specified
516 * @v ll_dest Link-layer destination address, if specified
517 * @v net_proto Network-layer protocol (in host order)
518 * @ret efirc EFI status code
520 static EFI_STATUS EFIAPI
521 efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
522 UINTN ll_header_len, UINTN len, VOID *data,
523 EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
524 UINT16 *net_proto ) {
525 struct efi_snp_device *snpdev =
526 container_of ( snp, struct efi_snp_device, snp );
527 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
528 struct io_buffer *iobuf;
532 DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
533 ( ( unsigned long ) len ) );
534 if ( ll_header_len ) {
536 DBGC2 ( snpdev, " src %s",
537 ll_protocol->ntoa ( ll_src ) );
540 DBGC2 ( snpdev, " dest %s",
541 ll_protocol->ntoa ( ll_dest ) );
544 DBGC2 ( snpdev, " proto %04x", *net_proto );
547 DBGC2 ( snpdev, "\n" );
550 if ( ll_header_len ) {
551 if ( ll_header_len != ll_protocol->ll_header_len ) {
552 DBGC ( snpdev, "SNPDEV %p TX invalid header length "
554 ( ( unsigned long ) ll_header_len ) );
555 efirc = EFI_INVALID_PARAMETER;
558 if ( len < ll_header_len ) {
559 DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
560 snpdev, ( ( unsigned long ) len ) );
561 efirc = EFI_BUFFER_TOO_SMALL;
565 DBGC ( snpdev, "SNPDEV %p TX missing destination "
566 "address\n", snpdev );
567 efirc = EFI_INVALID_PARAMETER;
571 DBGC ( snpdev, "SNPDEV %p TX missing network "
572 "protocol\n", snpdev );
573 efirc = EFI_INVALID_PARAMETER;
577 ll_src = &snpdev->mode.CurrentAddress;
580 /* Allocate buffer */
581 iobuf = alloc_iob ( len );
583 DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
584 "buffer\n", snpdev, ( ( unsigned long ) len ) );
585 efirc = EFI_DEVICE_ERROR;
588 memcpy ( iob_put ( iobuf, len ), data, len );
590 /* Create link-layer header, if specified */
591 if ( ll_header_len ) {
592 iob_pull ( iobuf, ll_header_len );
593 if ( ( rc = ll_protocol->push ( iobuf, ll_dest, ll_src,
594 htons ( *net_proto ) )) != 0 ){
595 DBGC ( snpdev, "SNPDEV %p TX could not construct "
596 "header: %s\n", snpdev, strerror ( rc ) );
597 efirc = RC_TO_EFIRC ( rc );
602 /* Transmit packet */
603 if ( ( rc = netdev_tx ( snpdev->netdev, iobuf ) ) != 0 ) {
604 DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
605 snpdev, strerror ( rc ) );
607 efirc = RC_TO_EFIRC ( rc );
611 /* Record transmission as outstanding */
612 snpdev->tx_count_interrupts++;
613 snpdev->tx_count_txbufs++;
628 * @v snp SNP interface
629 * @v ll_header_len Link-layer header length, if to be filled in
630 * @v len Length of data buffer
631 * @v data Data buffer
632 * @v ll_src Link-layer source address, if specified
633 * @v ll_dest Link-layer destination address, if specified
634 * @v net_proto Network-layer protocol (in host order)
635 * @ret efirc EFI status code
637 static EFI_STATUS EFIAPI
638 efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
639 UINTN *ll_header_len, UINTN *len, VOID *data,
640 EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
641 UINT16 *net_proto ) {
642 struct efi_snp_device *snpdev =
643 container_of ( snp, struct efi_snp_device, snp );
644 struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
645 struct io_buffer *iobuf;
646 const void *iob_ll_dest;
647 const void *iob_ll_src;
648 uint16_t iob_net_proto;
652 DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
653 ( ( unsigned long ) *len ) );
655 /* Poll the network device */
656 efi_snp_poll ( snpdev );
658 /* Dequeue a packet, if one is available */
659 iobuf = netdev_rx_dequeue ( snpdev->netdev );
661 DBGC2 ( snpdev, "\n" );
662 efirc = EFI_NOT_READY;
665 DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
667 /* Return packet to caller */
668 memcpy ( data, iobuf->data, iob_len ( iobuf ) );
669 *len = iob_len ( iobuf );
671 /* Attempt to decode link-layer header */
672 if ( ( rc = ll_protocol->pull ( iobuf, &iob_ll_dest, &iob_ll_src,
673 &iob_net_proto ) ) != 0 ) {
674 DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
675 snpdev, strerror ( rc ) );
676 efirc = RC_TO_EFIRC ( rc );
677 goto out_bad_ll_header;
680 /* Return link-layer header parameters to caller, if required */
682 *ll_header_len = ll_protocol->ll_header_len;
684 memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
686 memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
688 *net_proto = ntohs ( iob_net_proto );
702 * @v context Event context
704 static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
706 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
707 struct efi_snp_device *snpdev = context;
709 DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
711 /* Do nothing unless the net device is open */
712 if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) )
715 /* Poll the network device */
716 efi_snp_poll ( snpdev );
718 /* Fire event if packets have been received */
719 if ( snpdev->rx_count_events != 0 ) {
720 DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
722 bs->SignalEvent ( event );
723 snpdev->rx_count_events--;
728 static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
729 .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
730 .Start = efi_snp_start,
731 .Stop = efi_snp_stop,
732 .Initialize = efi_snp_initialize,
733 .Reset = efi_snp_reset,
734 .Shutdown = efi_snp_shutdown,
735 .ReceiveFilters = efi_snp_receive_filters,
736 .StationAddress = efi_snp_station_address,
737 .Statistics = efi_snp_statistics,
738 .MCastIpToMac = efi_snp_mcast_ip_to_mac,
739 .NvData = efi_snp_nvdata,
740 .GetStatus = efi_snp_get_status,
741 .Transmit = efi_snp_transmit,
742 .Receive = efi_snp_receive,
746 * Locate net device corresponding to EFI device
748 * @v driver EFI driver
749 * @v device EFI device
750 * @ret netdev Net device, or NULL if not found
752 static struct net_device *
753 efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
754 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
756 EFI_PCI_IO_PROTOCOL *pci;
759 UINTN pci_segment, pci_bus, pci_dev, pci_fn;
760 unsigned int pci_busdevfn;
761 struct net_device *netdev = NULL;
764 /* See if device is a PCI device */
765 if ( ( efirc = bs->OpenProtocol ( device,
766 &efi_pci_io_protocol_guid,
768 driver->DriverBindingHandle,
770 EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
771 DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n",
776 /* Get PCI bus:dev.fn address */
777 if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus,
778 &pci_dev, &pci_fn ) ) != 0 ) {
779 DBGC ( driver, "SNPDRV %p device %p could not get PCI "
781 driver, device, efi_strerror ( efirc ) );
782 goto out_no_pci_location;
784 DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n",
785 driver, device, ( ( unsigned long ) pci_segment ),
786 ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ),
787 ( ( unsigned long ) pci_fn ) );
789 /* Look up corresponding network device */
790 pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) );
791 if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI,
792 pci_busdevfn ) ) == NULL ) {
793 DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network "
794 "device\n", driver, device );
797 DBGC ( driver, "SNPDRV %p device %p is %s\n",
798 driver, device, netdev->name );
802 bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
803 driver->DriverBindingHandle, device );
809 * Locate SNP corresponding to EFI device
811 * @v driver EFI driver
812 * @v device EFI device
813 * @ret snp EFI SNP, or NULL if not found
815 static struct efi_snp_device *
816 efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
817 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
819 EFI_SIMPLE_NETWORK_PROTOCOL *snp;
822 struct efi_snp_device *snpdev = NULL;
825 if ( ( efirc = bs->OpenProtocol ( device,
826 &efi_simple_network_protocol_guid,
828 driver->DriverBindingHandle,
830 EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
831 DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
832 "%s\n", driver, device, efi_strerror ( efirc ) );
836 snpdev = container_of ( u.snp, struct efi_snp_device, snp );
837 DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
838 driver, device, snpdev );
840 bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
841 driver->DriverBindingHandle, device );
847 * Check to see if driver supports a device
849 * @v driver EFI driver
850 * @v device EFI device
851 * @v child Path to child device, if any
852 * @ret efirc EFI status code
854 static EFI_STATUS EFIAPI
855 efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
857 EFI_DEVICE_PATH_PROTOCOL *child ) {
858 struct net_device *netdev;
860 DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n",
861 driver, device, child );
863 netdev = efi_snp_netdev ( driver, device );
864 return ( netdev ? 0 : EFI_UNSUPPORTED );
868 * Attach driver to device
870 * @v driver EFI driver
871 * @v device EFI device
872 * @v child Path to child device, if any
873 * @ret efirc EFI status code
875 static EFI_STATUS EFIAPI
876 efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
878 EFI_DEVICE_PATH_PROTOCOL *child ) {
879 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
880 EFI_DEVICE_PATH_PROTOCOL *path;
881 EFI_DEVICE_PATH_PROTOCOL *subpath;
882 MAC_ADDR_DEVICE_PATH *macpath;
883 struct efi_snp_device *snpdev;
884 struct net_device *netdev;
886 size_t path_prefix_len = 0;
890 DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
891 driver, device, child );
893 /* Determine device path prefix length */
894 if ( ( efirc = bs->OpenProtocol ( device,
895 &efi_device_path_protocol_guid,
897 driver->DriverBindingHandle,
899 EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
900 DBGCP ( driver, "SNPDRV %p device %p has no device path\n",
902 goto err_no_device_path;
905 while ( subpath->Type != END_DEVICE_PATH_TYPE ) {
906 subpath_len = ( ( subpath->Length[1] << 8 ) |
907 subpath->Length[0] );
908 path_prefix_len += subpath_len;
909 subpath = ( ( ( void * ) subpath ) + subpath_len );
912 /* Allocate the SNP device */
913 snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
914 sizeof ( *macpath ) );
916 efirc = EFI_OUT_OF_RESOURCES;
920 /* Identify the net device */
921 netdev = efi_snp_netdev ( driver, device );
923 DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n",
925 efirc = EFI_UNSUPPORTED;
928 snpdev->netdev = netdev_get ( netdev );
931 if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
932 DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
933 "length %d for %s\n", snpdev,
934 netdev->ll_protocol->ll_addr_len, netdev->name );
935 efirc = EFI_INVALID_PARAMETER;
936 goto err_ll_addr_len;
939 /* Populate the SNP structure */
940 memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
941 snpdev->snp.Mode = &snpdev->mode;
942 if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
943 efi_snp_wait_for_packet, snpdev,
944 &snpdev->snp.WaitForPacket ) ) != 0 ){
945 DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
946 snpdev, efi_strerror ( efirc ) );
947 goto err_create_event;
950 /* Populate the SNP mode structure */
951 snpdev->mode.State = EfiSimpleNetworkStopped;
952 efi_snp_set_mode ( snpdev );
954 /* Populate the NII structure */
955 snpdev->nii.Revision =
956 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
957 strncpy ( snpdev->nii.StringId, "gPXE",
958 sizeof ( snpdev->nii.StringId ) );
960 /* Populate the device name */
961 for ( i = 0 ; i < sizeof ( netdev->name ) ; i++ ) {
962 /* Damn Unicode names */
963 assert ( i < ( sizeof ( snpdev->name ) /
964 sizeof ( snpdev->name[0] ) ) );
965 snpdev->name[i] = netdev->name[i];
968 /* Populate the device path */
969 memcpy ( &snpdev->path, path, path_prefix_len );
970 macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
971 subpath = ( ( void * ) ( macpath + 1 ) );
972 memset ( macpath, 0, sizeof ( *macpath ) );
973 macpath->Header.Type = MESSAGING_DEVICE_PATH;
974 macpath->Header.SubType = MSG_MAC_ADDR_DP;
975 macpath->Header.Length[0] = sizeof ( *macpath );
976 memcpy ( &macpath->MacAddress, netdev->ll_addr,
977 sizeof ( macpath->MacAddress ) );
978 macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
979 memset ( subpath, 0, sizeof ( *subpath ) );
980 subpath->Type = END_DEVICE_PATH_TYPE;
981 subpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
982 subpath->Length[0] = sizeof ( *subpath );
984 /* Install the SNP */
985 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
987 &efi_simple_network_protocol_guid, &snpdev->snp,
988 &efi_device_path_protocol_guid, &snpdev->path,
989 &efi_nii_protocol_guid, &snpdev->nii,
991 DBGC ( snpdev, "SNPDEV %p could not install protocols: "
992 "%s\n", snpdev, efi_strerror ( efirc ) );
993 goto err_install_protocol_interface;
996 DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
997 snpdev, netdev->name, snpdev->handle );
1000 bs->UninstallMultipleProtocolInterfaces (
1002 &efi_simple_network_protocol_guid, &snpdev->snp,
1003 &efi_device_path_protocol_guid, &snpdev->path,
1004 &efi_nii_protocol_guid, &snpdev->nii,
1006 err_install_protocol_interface:
1007 bs->CloseEvent ( snpdev->snp.WaitForPacket );
1010 netdev_put ( netdev );
1014 bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
1015 driver->DriverBindingHandle, device );
1021 * Detach driver from device
1023 * @v driver EFI driver
1024 * @v device EFI device
1025 * @v num_children Number of child devices
1026 * @v children List of child devices
1027 * @ret efirc EFI status code
1029 static EFI_STATUS EFIAPI
1030 efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
1033 EFI_HANDLE *children ) {
1034 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
1035 struct efi_snp_device *snpdev;
1037 DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n",
1038 driver, device, ( ( unsigned long ) num_children ), children );
1040 /* Locate SNP device */
1041 snpdev = efi_snp_snpdev ( driver, device );
1043 DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n",
1045 return EFI_DEVICE_ERROR;
1048 /* Uninstall the SNP */
1049 bs->UninstallMultipleProtocolInterfaces (
1051 &efi_simple_network_protocol_guid, &snpdev->snp,
1052 &efi_device_path_protocol_guid, &snpdev->path,
1053 &efi_nii_protocol_guid, &snpdev->nii,
1055 bs->CloseEvent ( snpdev->snp.WaitForPacket );
1056 netdev_put ( snpdev->netdev );
1058 bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
1059 driver->DriverBindingHandle, device );
1063 /** EFI SNP driver binding */
1064 static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
1065 efi_snp_driver_supported,
1066 efi_snp_driver_start,
1067 efi_snp_driver_stop,
1074 * Look up driver name
1076 * @v wtf Component name protocol
1077 * @v language Language to use
1078 * @v driver_name Driver name to fill in
1079 * @ret efirc EFI status code
1081 static EFI_STATUS EFIAPI
1082 efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
1083 CHAR8 *language __unused, CHAR16 **driver_name ) {
1085 *driver_name = L"" PRODUCT_SHORT_NAME " Driver";
1090 * Look up controller name
1092 * @v wtf Component name protocol
1094 * @v child Child device, or NULL
1095 * @v language Language to use
1096 * @v driver_name Device name to fill in
1097 * @ret efirc EFI status code
1099 static EFI_STATUS EFIAPI
1100 efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
1101 EFI_HANDLE device __unused,
1102 EFI_HANDLE child __unused,
1103 CHAR8 *language __unused,
1104 CHAR16 **controller_name __unused ) {
1106 /* Just let EFI use the default Device Path Name */
1107 return EFI_UNSUPPORTED;
1110 /** EFI SNP component name protocol */
1111 static EFI_COMPONENT_NAME2_PROTOCOL efi_snp_name = {
1112 efi_snp_get_driver_name,
1113 efi_snp_get_controller_name,
1118 * Install EFI SNP driver
1120 * @ret rc Return status code
1122 int efi_snp_install ( void ) {
1123 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
1124 EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding;
1127 driver->ImageHandle = efi_image_handle;
1128 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
1129 &driver->DriverBindingHandle,
1130 &efi_driver_binding_protocol_guid, driver,
1131 &efi_component_name2_protocol_guid, &efi_snp_name,
1133 DBGC ( driver, "SNPDRV %p could not install protocols: "
1134 "%s\n", driver, efi_strerror ( efirc ) );
1135 return EFIRC_TO_RC ( efirc );
1138 DBGC ( driver, "SNPDRV %p driver binding installed as %p\n",
1139 driver, driver->DriverBindingHandle );