Home | History | Annotate | Download | only in efi
      1 /*
      2  * Copyright (C) 2008 Michael Brown <mbrown (at) 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., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <errno.h>
     24 #include <assert.h>
     25 #include <byteswap.h>
     26 #include <gpxe/netdevice.h>
     27 #include <gpxe/iobuf.h>
     28 #include <gpxe/in.h>
     29 #include <gpxe/pci.h>
     30 #include <gpxe/efi/efi.h>
     31 #include <gpxe/efi/Protocol/DriverBinding.h>
     32 #include <gpxe/efi/Protocol/PciIo.h>
     33 #include <gpxe/efi/Protocol/SimpleNetwork.h>
     34 #include <gpxe/efi/Protocol/ComponentName2.h>
     35 #include <gpxe/efi/Protocol/NetworkInterfaceIdentifier.h>
     36 #include <config/general.h>
     37 
     38 /** @file
     39  *
     40  * gPXE EFI SNP interface
     41  *
     42  */
     43 
     44 /** An SNP device */
     45 struct efi_snp_device {
     46 	/** The underlying gPXE network device */
     47 	struct net_device *netdev;
     48 	/** EFI device handle */
     49 	EFI_HANDLE handle;
     50 	/** The SNP structure itself */
     51 	EFI_SIMPLE_NETWORK_PROTOCOL snp;
     52 	/** The SNP "mode" (parameters) */
     53 	EFI_SIMPLE_NETWORK_MODE mode;
     54 	/** Outstanding TX packet count (via "interrupt status")
     55 	 *
     56 	 * Used in order to generate TX completions.
     57 	 */
     58 	unsigned int tx_count_interrupts;
     59 	/** Outstanding TX packet count (via "recycled tx buffers")
     60 	 *
     61 	 * Used in order to generate TX completions.
     62 	 */
     63 	unsigned int tx_count_txbufs;
     64 	/** Outstanding RX packet count (via "interrupt status") */
     65 	unsigned int rx_count_interrupts;
     66 	/** Outstanding RX packet count (via WaitForPacket event) */
     67 	unsigned int rx_count_events;
     68 	/** The network interface identifier */
     69 	EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
     70 	/** Device name */
     71 	wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
     72 	/** The device path
     73 	 *
     74 	 * This field is variable in size and must appear at the end
     75 	 * of the structure.
     76 	 */
     77 	EFI_DEVICE_PATH_PROTOCOL path;
     78 };
     79 
     80 /** EFI simple network protocol GUID */
     81 static EFI_GUID efi_simple_network_protocol_guid
     82 	= EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
     83 
     84 /** EFI driver binding protocol GUID */
     85 static EFI_GUID efi_driver_binding_protocol_guid
     86 	= EFI_DRIVER_BINDING_PROTOCOL_GUID;
     87 
     88 /** EFI component name protocol GUID */
     89 static EFI_GUID efi_component_name2_protocol_guid
     90 	= EFI_COMPONENT_NAME2_PROTOCOL_GUID;
     91 
     92 /** EFI device path protocol GUID */
     93 static EFI_GUID efi_device_path_protocol_guid
     94 	= EFI_DEVICE_PATH_PROTOCOL_GUID;
     95 
     96 /** EFI network interface identifier GUID */
     97 static EFI_GUID efi_nii_protocol_guid
     98 	= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
     99 
    100 /** EFI network interface identifier GUID (extra special version) */
    101 static EFI_GUID efi_nii31_protocol_guid = {
    102 	/* At some point, it seems that someone decided to change the
    103 	 * GUID.  Current EFI builds ignore the older GUID, older EFI
    104 	 * builds ignore the newer GUID, so we have to expose both.
    105 	 */
    106 	0x1ACED566, 0x76ED, 0x4218,
    107 	{ 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
    108 };
    109 
    110 /** EFI PCI I/O protocol GUID */
    111 static EFI_GUID efi_pci_io_protocol_guid
    112 	= EFI_PCI_IO_PROTOCOL_GUID;
    113 
    114 /**
    115  * Set EFI SNP mode based on gPXE net device parameters
    116  *
    117  * @v snp		SNP interface
    118  */
    119 static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
    120 	struct net_device *netdev = snpdev->netdev;
    121 	EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
    122 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
    123 	unsigned int ll_addr_len = ll_protocol->ll_addr_len;
    124 
    125 	mode->HwAddressSize = ll_addr_len;
    126 	mode->MediaHeaderSize = ll_protocol->ll_header_len;
    127 	mode->MaxPacketSize = netdev->max_pkt_len;
    128 	mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
    129 				    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
    130 				    EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
    131 	assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
    132 	memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
    133 	memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
    134 	ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
    135 	mode->IfType = ntohs ( ll_protocol->ll_proto );
    136 	mode->MacAddressChangeable = TRUE;
    137 	mode->MediaPresentSupported = TRUE;
    138 	mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
    139 }
    140 
    141 /**
    142  * Poll net device and count received packets
    143  *
    144  * @v snpdev		SNP device
    145  */
    146 static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
    147 	struct io_buffer *iobuf;
    148 	unsigned int before = 0;
    149 	unsigned int after = 0;
    150 	unsigned int arrived;
    151 
    152 	/* We have to report packet arrivals, and this is the easiest
    153 	 * way to fake it.
    154 	 */
    155 	list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
    156 		before++;
    157 	netdev_poll ( snpdev->netdev );
    158 	list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
    159 		after++;
    160 	arrived = ( after - before );
    161 
    162 	snpdev->rx_count_interrupts += arrived;
    163 	snpdev->rx_count_events += arrived;
    164 }
    165 
    166 /**
    167  * Change SNP state from "stopped" to "started"
    168  *
    169  * @v snp		SNP interface
    170  * @ret efirc		EFI status code
    171  */
    172 static EFI_STATUS EFIAPI
    173 efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
    174 	struct efi_snp_device *snpdev =
    175 		container_of ( snp, struct efi_snp_device, snp );
    176 
    177 	DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
    178 
    179 	snpdev->mode.State = EfiSimpleNetworkStarted;
    180 	return 0;
    181 }
    182 
    183 /**
    184  * Change SNP state from "started" to "stopped"
    185  *
    186  * @v snp		SNP interface
    187  * @ret efirc		EFI status code
    188  */
    189 static EFI_STATUS EFIAPI
    190 efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
    191 	struct efi_snp_device *snpdev =
    192 		container_of ( snp, struct efi_snp_device, snp );
    193 
    194 	DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
    195 
    196 	snpdev->mode.State = EfiSimpleNetworkStopped;
    197 	return 0;
    198 }
    199 
    200 /**
    201  * Open the network device
    202  *
    203  * @v snp		SNP interface
    204  * @v extra_rx_bufsize	Extra RX buffer size, in bytes
    205  * @v extra_tx_bufsize	Extra TX buffer size, in bytes
    206  * @ret efirc		EFI status code
    207  */
    208 static EFI_STATUS EFIAPI
    209 efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
    210 		     UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
    211 	struct efi_snp_device *snpdev =
    212 		container_of ( snp, struct efi_snp_device, snp );
    213 	int rc;
    214 
    215 	DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
    216 		snpdev, ( ( unsigned long ) extra_rx_bufsize ),
    217 		( ( unsigned long ) extra_tx_bufsize ) );
    218 
    219 	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
    220 		DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
    221 		       snpdev, snpdev->netdev->name, strerror ( rc ) );
    222 		return RC_TO_EFIRC ( rc );
    223 	}
    224 
    225 	snpdev->mode.State = EfiSimpleNetworkInitialized;
    226 	return 0;
    227 }
    228 
    229 /**
    230  * Reset the network device
    231  *
    232  * @v snp		SNP interface
    233  * @v ext_verify	Extended verification required
    234  * @ret efirc		EFI status code
    235  */
    236 static EFI_STATUS EFIAPI
    237 efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
    238 	struct efi_snp_device *snpdev =
    239 		container_of ( snp, struct efi_snp_device, snp );
    240 	int rc;
    241 
    242 	DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
    243 		snpdev, ( ext_verify ? "with" : "without" ) );
    244 
    245 	netdev_close ( snpdev->netdev );
    246 	snpdev->mode.State = EfiSimpleNetworkStarted;
    247 
    248 	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
    249 		DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
    250 		       snpdev, snpdev->netdev->name, strerror ( rc ) );
    251 		return RC_TO_EFIRC ( rc );
    252 	}
    253 
    254 	snpdev->mode.State = EfiSimpleNetworkInitialized;
    255 	return 0;
    256 }
    257 
    258 /**
    259  * Shut down the network device
    260  *
    261  * @v snp		SNP interface
    262  * @ret efirc		EFI status code
    263  */
    264 static EFI_STATUS EFIAPI
    265 efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
    266 	struct efi_snp_device *snpdev =
    267 		container_of ( snp, struct efi_snp_device, snp );
    268 
    269 	DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
    270 
    271 	netdev_close ( snpdev->netdev );
    272 	snpdev->mode.State = EfiSimpleNetworkStarted;
    273 	return 0;
    274 }
    275 
    276 /**
    277  * Manage receive filters
    278  *
    279  * @v snp		SNP interface
    280  * @v enable		Receive filters to enable
    281  * @v disable		Receive filters to disable
    282  * @v mcast_reset	Reset multicast filters
    283  * @v mcast_count	Number of multicast filters
    284  * @v mcast		Multicast filters
    285  * @ret efirc		EFI status code
    286  */
    287 static EFI_STATUS EFIAPI
    288 efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
    289 			  UINT32 disable, BOOLEAN mcast_reset,
    290 			  UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
    291 	struct efi_snp_device *snpdev =
    292 		container_of ( snp, struct efi_snp_device, snp );
    293 	unsigned int i;
    294 
    295 	DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
    296 		snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
    297 		( ( unsigned long ) mcast_count ) );
    298 	for ( i = 0 ; i < mcast_count ; i++ ) {
    299 		DBGC2_HDA ( snpdev, i, &mcast[i],
    300 			    snpdev->netdev->ll_protocol->ll_addr_len );
    301 	}
    302 
    303 	/* Lie through our teeth, otherwise MNP refuses to accept us */
    304 	return 0;
    305 }
    306 
    307 /**
    308  * Set station address
    309  *
    310  * @v snp		SNP interface
    311  * @v reset		Reset to permanent address
    312  * @v new		New station address
    313  * @ret efirc		EFI status code
    314  */
    315 static EFI_STATUS EFIAPI
    316 efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
    317 			  EFI_MAC_ADDRESS *new ) {
    318 	struct efi_snp_device *snpdev =
    319 		container_of ( snp, struct efi_snp_device, snp );
    320 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
    321 
    322 	DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
    323 		( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
    324 
    325 	/* Set the MAC address */
    326 	if ( reset )
    327 		new = &snpdev->mode.PermanentAddress;
    328 	memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
    329 
    330 	/* MAC address changes take effect only on netdev_open() */
    331 	if ( snpdev->netdev->state & NETDEV_OPEN ) {
    332 		DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
    333 		       "devive open\n", snpdev );
    334 	}
    335 
    336 	return 0;
    337 }
    338 
    339 /**
    340  * Get (or reset) statistics
    341  *
    342  * @v snp		SNP interface
    343  * @v reset		Reset statistics
    344  * @v stats_len		Size of statistics table
    345  * @v stats		Statistics table
    346  * @ret efirc		EFI status code
    347  */
    348 static EFI_STATUS EFIAPI
    349 efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
    350 		     UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
    351 	struct efi_snp_device *snpdev =
    352 		container_of ( snp, struct efi_snp_device, snp );
    353 	EFI_NETWORK_STATISTICS stats_buf;
    354 
    355 	DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
    356 		( reset ? " reset" : "" ) );
    357 
    358 	/* Gather statistics */
    359 	memset ( &stats_buf, 0, sizeof ( stats_buf ) );
    360 	stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
    361 	stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
    362 	stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
    363 				    snpdev->netdev->tx_stats.bad );
    364 	stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
    365 	stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
    366 	stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
    367 				    snpdev->netdev->rx_stats.bad );
    368 	if ( *stats_len > sizeof ( stats_buf ) )
    369 		*stats_len = sizeof ( stats_buf );
    370 	if ( stats )
    371 		memcpy ( stats, &stats_buf, *stats_len );
    372 
    373 	/* Reset statistics if requested to do so */
    374 	if ( reset ) {
    375 		memset ( &snpdev->netdev->tx_stats, 0,
    376 			 sizeof ( snpdev->netdev->tx_stats ) );
    377 		memset ( &snpdev->netdev->rx_stats, 0,
    378 			 sizeof ( snpdev->netdev->rx_stats ) );
    379 	}
    380 
    381 	return 0;
    382 }
    383 
    384 /**
    385  * Convert multicast IP address to MAC address
    386  *
    387  * @v snp		SNP interface
    388  * @v ipv6		Address is IPv6
    389  * @v ip		IP address
    390  * @v mac		MAC address
    391  * @ret efirc		EFI status code
    392  */
    393 static EFI_STATUS EFIAPI
    394 efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
    395 			  EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
    396 	struct efi_snp_device *snpdev =
    397 		container_of ( snp, struct efi_snp_device, snp );
    398 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
    399 	const char *ip_str;
    400 	int rc;
    401 
    402 	ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
    403 		   inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
    404 	DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
    405 
    406 	/* Try to hash the address */
    407 	if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
    408 					   ip, mac ) ) != 0 ) {
    409 		DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
    410 		       snpdev, ip_str, strerror ( rc ) );
    411 		return RC_TO_EFIRC ( rc );
    412 	}
    413 
    414 	return 0;
    415 }
    416 
    417 /**
    418  * Read or write non-volatile storage
    419  *
    420  * @v snp		SNP interface
    421  * @v read		Operation is a read
    422  * @v offset		Starting offset within NVRAM
    423  * @v len		Length of data buffer
    424  * @v data		Data buffer
    425  * @ret efirc		EFI status code
    426  */
    427 static EFI_STATUS EFIAPI
    428 efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
    429 		 UINTN offset, UINTN len, VOID *data ) {
    430 	struct efi_snp_device *snpdev =
    431 		container_of ( snp, struct efi_snp_device, snp );
    432 
    433 	DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
    434 		( read ? "read" : "write" ), ( ( unsigned long ) offset ),
    435 		( ( unsigned long ) len ) );
    436 	if ( ! read )
    437 		DBGC2_HDA ( snpdev, offset, data, len );
    438 
    439 	return EFI_UNSUPPORTED;
    440 }
    441 
    442 /**
    443  * Read interrupt status and TX recycled buffer status
    444  *
    445  * @v snp		SNP interface
    446  * @v interrupts	Interrupt status, or NULL
    447  * @v txbufs		Recycled transmit buffer address, or NULL
    448  * @ret efirc		EFI status code
    449  */
    450 static EFI_STATUS EFIAPI
    451 efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
    452 		     UINT32 *interrupts, VOID **txbufs ) {
    453 	struct efi_snp_device *snpdev =
    454 		container_of ( snp, struct efi_snp_device, snp );
    455 
    456 	DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
    457 
    458 	/* Poll the network device */
    459 	efi_snp_poll ( snpdev );
    460 
    461 	/* Interrupt status.  In practice, this seems to be used only
    462 	 * to detect TX completions.
    463 	 */
    464 	if ( interrupts ) {
    465 		*interrupts = 0;
    466 		/* Report TX completions once queue is empty; this
    467 		 * avoids having to add hooks in the net device layer.
    468 		 */
    469 		if ( snpdev->tx_count_interrupts &&
    470 		     list_empty ( &snpdev->netdev->tx_queue ) ) {
    471 			*interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
    472 			snpdev->tx_count_interrupts--;
    473 		}
    474 		/* Report RX */
    475 		if ( snpdev->rx_count_interrupts ) {
    476 			*interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
    477 			snpdev->rx_count_interrupts--;
    478 		}
    479 		DBGC2 ( snpdev, " INTS:%02x", *interrupts );
    480 	}
    481 
    482 	/* TX completions.  It would be possible to design a more
    483 	 * idiotic scheme for this, but it would be a challenge.
    484 	 * According to the UEFI header file, txbufs will be filled in
    485 	 * with a list of "recycled transmit buffers" (i.e. completed
    486 	 * TX buffers).  Observant readers may care to note that
    487 	 * *txbufs is a void pointer.  Precisely how a list of
    488 	 * completed transmit buffers is meant to be represented as an
    489 	 * array of voids is left as an exercise for the reader.
    490 	 *
    491 	 * The only users of this interface (MnpDxe/MnpIo.c and
    492 	 * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
    493 	 * seeing a non-NULL result return in txbufs.  This is valid
    494 	 * provided that they do not ever attempt to transmit more
    495 	 * than one packet concurrently (and that TX never times out).
    496 	 */
    497 	if ( txbufs ) {
    498 		if ( snpdev->tx_count_txbufs &&
    499 		     list_empty ( &snpdev->netdev->tx_queue ) ) {
    500 			*txbufs = "Which idiot designed this API?";
    501 			snpdev->tx_count_txbufs--;
    502 		} else {
    503 			*txbufs = NULL;
    504 		}
    505 		DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
    506 	}
    507 
    508 	DBGC2 ( snpdev, "\n" );
    509 	return 0;
    510 }
    511 
    512 /**
    513  * Start packet transmission
    514  *
    515  * @v snp		SNP interface
    516  * @v ll_header_len	Link-layer header length, if to be filled in
    517  * @v len		Length of data buffer
    518  * @v data		Data buffer
    519  * @v ll_src		Link-layer source address, if specified
    520  * @v ll_dest		Link-layer destination address, if specified
    521  * @v net_proto		Network-layer protocol (in host order)
    522  * @ret efirc		EFI status code
    523  */
    524 static EFI_STATUS EFIAPI
    525 efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
    526 		   UINTN ll_header_len, UINTN len, VOID *data,
    527 		   EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
    528 		   UINT16 *net_proto ) {
    529 	struct efi_snp_device *snpdev =
    530 		container_of ( snp, struct efi_snp_device, snp );
    531 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
    532 	struct io_buffer *iobuf;
    533 	int rc;
    534 	EFI_STATUS efirc;
    535 
    536 	DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
    537 		( ( unsigned long ) len ) );
    538 	if ( ll_header_len ) {
    539 		if ( ll_src ) {
    540 			DBGC2 ( snpdev, " src %s",
    541 				ll_protocol->ntoa ( ll_src ) );
    542 		}
    543 		if ( ll_dest ) {
    544 			DBGC2 ( snpdev, " dest %s",
    545 				ll_protocol->ntoa ( ll_dest ) );
    546 		}
    547 		if ( net_proto ) {
    548 			DBGC2 ( snpdev, " proto %04x", *net_proto );
    549 		}
    550 	}
    551 	DBGC2 ( snpdev, "\n" );
    552 
    553 	/* Sanity checks */
    554 	if ( ll_header_len ) {
    555 		if ( ll_header_len != ll_protocol->ll_header_len ) {
    556 			DBGC ( snpdev, "SNPDEV %p TX invalid header length "
    557 			       "%ld\n", snpdev,
    558 			       ( ( unsigned long ) ll_header_len ) );
    559 			efirc = EFI_INVALID_PARAMETER;
    560 			goto err_sanity;
    561 		}
    562 		if ( len < ll_header_len ) {
    563 			DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
    564 			       snpdev, ( ( unsigned long ) len ) );
    565 			efirc = EFI_BUFFER_TOO_SMALL;
    566 			goto err_sanity;
    567 		}
    568 		if ( ! ll_dest ) {
    569 			DBGC ( snpdev, "SNPDEV %p TX missing destination "
    570 			       "address\n", snpdev );
    571 			efirc = EFI_INVALID_PARAMETER;
    572 			goto err_sanity;
    573 		}
    574 		if ( ! net_proto ) {
    575 			DBGC ( snpdev, "SNPDEV %p TX missing network "
    576 			       "protocol\n", snpdev );
    577 			efirc = EFI_INVALID_PARAMETER;
    578 			goto err_sanity;
    579 		}
    580 		if ( ! ll_src )
    581 			ll_src = &snpdev->mode.CurrentAddress;
    582 	}
    583 
    584 	/* Allocate buffer */
    585 	iobuf = alloc_iob ( len );
    586 	if ( ! iobuf ) {
    587 		DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
    588 		       "buffer\n", snpdev, ( ( unsigned long ) len ) );
    589 		efirc = EFI_DEVICE_ERROR;
    590 		goto err_alloc_iob;
    591 	}
    592 	memcpy ( iob_put ( iobuf, len ), data, len );
    593 
    594 	/* Create link-layer header, if specified */
    595 	if ( ll_header_len ) {
    596 		iob_pull ( iobuf, ll_header_len );
    597 		if ( ( rc = ll_protocol->push ( snpdev->netdev,
    598 						iobuf, ll_dest, ll_src,
    599 						htons ( *net_proto ) )) != 0 ){
    600 			DBGC ( snpdev, "SNPDEV %p TX could not construct "
    601 			       "header: %s\n", snpdev, strerror ( rc ) );
    602 			efirc = RC_TO_EFIRC ( rc );
    603 			goto err_ll_push;
    604 		}
    605 	}
    606 
    607 	/* Transmit packet */
    608 	if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
    609 		DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
    610 		       snpdev, strerror ( rc ) );
    611 		efirc = RC_TO_EFIRC ( rc );
    612 		goto err_tx;
    613 	}
    614 
    615 	/* Record transmission as outstanding */
    616 	snpdev->tx_count_interrupts++;
    617 	snpdev->tx_count_txbufs++;
    618 
    619 	return 0;
    620 
    621  err_tx:
    622  err_ll_push:
    623 	free_iob ( iobuf );
    624  err_alloc_iob:
    625  err_sanity:
    626 	return efirc;
    627 }
    628 
    629 /**
    630  * Receive packet
    631  *
    632  * @v snp		SNP interface
    633  * @v ll_header_len	Link-layer header length, if to be filled in
    634  * @v len		Length of data buffer
    635  * @v data		Data buffer
    636  * @v ll_src		Link-layer source address, if specified
    637  * @v ll_dest		Link-layer destination address, if specified
    638  * @v net_proto		Network-layer protocol (in host order)
    639  * @ret efirc		EFI status code
    640  */
    641 static EFI_STATUS EFIAPI
    642 efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
    643 		  UINTN *ll_header_len, UINTN *len, VOID *data,
    644 		  EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
    645 		  UINT16 *net_proto ) {
    646 	struct efi_snp_device *snpdev =
    647 		container_of ( snp, struct efi_snp_device, snp );
    648 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
    649 	struct io_buffer *iobuf;
    650 	const void *iob_ll_dest;
    651 	const void *iob_ll_src;
    652 	uint16_t iob_net_proto;
    653 	int rc;
    654 	EFI_STATUS efirc;
    655 
    656 	DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
    657 		( ( unsigned long ) *len ) );
    658 
    659 	/* Poll the network device */
    660 	efi_snp_poll ( snpdev );
    661 
    662 	/* Dequeue a packet, if one is available */
    663 	iobuf = netdev_rx_dequeue ( snpdev->netdev );
    664 	if ( ! iobuf ) {
    665 		DBGC2 ( snpdev, "\n" );
    666 		efirc = EFI_NOT_READY;
    667 		goto out_no_packet;
    668 	}
    669 	DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
    670 
    671 	/* Return packet to caller */
    672 	memcpy ( data, iobuf->data, iob_len ( iobuf ) );
    673 	*len = iob_len ( iobuf );
    674 
    675 	/* Attempt to decode link-layer header */
    676 	if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
    677 					&iob_ll_src, &iob_net_proto ) ) != 0 ){
    678 		DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
    679 		       snpdev, strerror ( rc ) );
    680 		efirc = RC_TO_EFIRC ( rc );
    681 		goto out_bad_ll_header;
    682 	}
    683 
    684 	/* Return link-layer header parameters to caller, if required */
    685 	if ( ll_header_len )
    686 		*ll_header_len = ll_protocol->ll_header_len;
    687 	if ( ll_src )
    688 		memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
    689 	if ( ll_dest )
    690 		memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
    691 	if ( net_proto )
    692 		*net_proto = ntohs ( iob_net_proto );
    693 
    694 	efirc = 0;
    695 
    696  out_bad_ll_header:
    697 	free_iob ( iobuf );
    698 out_no_packet:
    699 	return efirc;
    700 }
    701 
    702 /**
    703  * Poll event
    704  *
    705  * @v event		Event
    706  * @v context		Event context
    707  */
    708 static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
    709 					     VOID *context ) {
    710 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
    711 	struct efi_snp_device *snpdev = context;
    712 
    713 	DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
    714 
    715 	/* Do nothing unless the net device is open */
    716 	if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) )
    717 		return;
    718 
    719 	/* Poll the network device */
    720 	efi_snp_poll ( snpdev );
    721 
    722 	/* Fire event if packets have been received */
    723 	if ( snpdev->rx_count_events != 0 ) {
    724 		DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
    725 			snpdev );
    726 		bs->SignalEvent ( event );
    727 		snpdev->rx_count_events--;
    728 	}
    729 }
    730 
    731 /** SNP interface */
    732 static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
    733 	.Revision	= EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
    734 	.Start		= efi_snp_start,
    735 	.Stop		= efi_snp_stop,
    736 	.Initialize	= efi_snp_initialize,
    737 	.Reset		= efi_snp_reset,
    738 	.Shutdown	= efi_snp_shutdown,
    739 	.ReceiveFilters	= efi_snp_receive_filters,
    740 	.StationAddress	= efi_snp_station_address,
    741 	.Statistics	= efi_snp_statistics,
    742 	.MCastIpToMac	= efi_snp_mcast_ip_to_mac,
    743 	.NvData		= efi_snp_nvdata,
    744 	.GetStatus	= efi_snp_get_status,
    745 	.Transmit	= efi_snp_transmit,
    746 	.Receive	= efi_snp_receive,
    747 };
    748 
    749 /**
    750  * Locate net device corresponding to EFI device
    751  *
    752  * @v driver		EFI driver
    753  * @v device		EFI device
    754  * @ret netdev		Net device, or NULL if not found
    755  */
    756 static struct net_device *
    757 efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
    758 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
    759 	union {
    760 		EFI_PCI_IO_PROTOCOL *pci;
    761 		void *interface;
    762 	} u;
    763 	UINTN pci_segment, pci_bus, pci_dev, pci_fn;
    764 	unsigned int pci_busdevfn;
    765 	struct net_device *netdev = NULL;
    766 	EFI_STATUS efirc;
    767 
    768 	/* See if device is a PCI device */
    769 	if ( ( efirc = bs->OpenProtocol ( device,
    770 					  &efi_pci_io_protocol_guid,
    771 					  &u.interface,
    772 					  driver->DriverBindingHandle,
    773 					  device,
    774 					  EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
    775 		DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n",
    776 			driver, device );
    777 		goto out_no_pci_io;
    778 	}
    779 
    780 	/* Get PCI bus:dev.fn address */
    781 	if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus,
    782 					    &pci_dev, &pci_fn ) ) != 0 ) {
    783 		DBGC ( driver, "SNPDRV %p device %p could not get PCI "
    784 		       "location: %s\n",
    785 		       driver, device, efi_strerror ( efirc ) );
    786 		goto out_no_pci_location;
    787 	}
    788 	DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n",
    789 		driver, device, ( ( unsigned long ) pci_segment ),
    790 		( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ),
    791 		( ( unsigned long ) pci_fn ) );
    792 
    793 	/* Look up corresponding network device */
    794 	pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) );
    795 	if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI,
    796 						  pci_busdevfn ) ) == NULL ) {
    797 		DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network "
    798 			"device\n", driver, device );
    799 		goto out_no_netdev;
    800 	}
    801 	DBGC ( driver, "SNPDRV %p device %p is %s\n",
    802 	       driver, device, netdev->name );
    803 
    804  out_no_netdev:
    805  out_no_pci_location:
    806 	bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
    807 			    driver->DriverBindingHandle, device );
    808  out_no_pci_io:
    809 	return netdev;
    810 }
    811 
    812 /**
    813  * Locate SNP corresponding to EFI device
    814  *
    815  * @v driver		EFI driver
    816  * @v device		EFI device
    817  * @ret snp		EFI SNP, or NULL if not found
    818  */
    819 static struct efi_snp_device *
    820 efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
    821 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
    822 	union {
    823 		EFI_SIMPLE_NETWORK_PROTOCOL *snp;
    824 		void *interface;
    825 	} u;
    826 	struct efi_snp_device *snpdev = NULL;
    827 	EFI_STATUS efirc;
    828 
    829 	if ( ( efirc = bs->OpenProtocol ( device,
    830 					  &efi_simple_network_protocol_guid,
    831 					  &u.interface,
    832 					  driver->DriverBindingHandle,
    833 					  device,
    834 					  EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
    835 		DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
    836 		       "%s\n", driver, device, efi_strerror ( efirc ) );
    837 		goto err_no_snp;
    838 	}
    839 
    840 	snpdev =  container_of ( u.snp, struct efi_snp_device, snp );
    841 	DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
    842 		driver, device, snpdev );
    843 
    844 	bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
    845 			    driver->DriverBindingHandle, device );
    846  err_no_snp:
    847 	return snpdev;
    848 }
    849 
    850 /**
    851  * Check to see if driver supports a device
    852  *
    853  * @v driver		EFI driver
    854  * @v device		EFI device
    855  * @v child		Path to child device, if any
    856  * @ret efirc		EFI status code
    857  */
    858 static EFI_STATUS EFIAPI
    859 efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
    860 			   EFI_HANDLE device,
    861 			   EFI_DEVICE_PATH_PROTOCOL *child ) {
    862 	struct net_device *netdev;
    863 
    864 	DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n",
    865 		driver, device, child );
    866 
    867 	netdev = efi_snp_netdev ( driver, device );
    868 	return ( netdev ? 0 : EFI_UNSUPPORTED );
    869 }
    870 
    871 /**
    872  * Attach driver to device
    873  *
    874  * @v driver		EFI driver
    875  * @v device		EFI device
    876  * @v child		Path to child device, if any
    877  * @ret efirc		EFI status code
    878  */
    879 static EFI_STATUS EFIAPI
    880 efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
    881 		       EFI_HANDLE device,
    882 		       EFI_DEVICE_PATH_PROTOCOL *child ) {
    883 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
    884 	EFI_DEVICE_PATH_PROTOCOL *path;
    885 	EFI_DEVICE_PATH_PROTOCOL *subpath;
    886 	MAC_ADDR_DEVICE_PATH *macpath;
    887 	struct efi_snp_device *snpdev;
    888 	struct net_device *netdev;
    889 	size_t subpath_len;
    890 	size_t path_prefix_len = 0;
    891 	unsigned int i;
    892 	EFI_STATUS efirc;
    893 
    894 	DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
    895 		driver, device, child );
    896 
    897 	/* Determine device path prefix length */
    898 	if ( ( efirc = bs->OpenProtocol ( device,
    899 					  &efi_device_path_protocol_guid,
    900 					  ( void * ) &path,
    901 					  driver->DriverBindingHandle,
    902 					  device,
    903 					  EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
    904 		DBGCP ( driver, "SNPDRV %p device %p has no device path\n",
    905 			driver, device );
    906 		goto err_no_device_path;
    907 	}
    908 	subpath = path;
    909 	while ( subpath->Type != END_DEVICE_PATH_TYPE ) {
    910 		subpath_len = ( ( subpath->Length[1] << 8 ) |
    911 				subpath->Length[0] );
    912 		path_prefix_len += subpath_len;
    913 		subpath = ( ( ( void * ) subpath ) + subpath_len );
    914 	}
    915 
    916 	/* Allocate the SNP device */
    917 	snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
    918 			  sizeof ( *macpath ) );
    919 	if ( ! snpdev ) {
    920 		efirc = EFI_OUT_OF_RESOURCES;
    921 		goto err_alloc_snp;
    922 	}
    923 
    924 	/* Identify the net device */
    925 	netdev = efi_snp_netdev ( driver, device );
    926 	if ( ! netdev ) {
    927 		DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n",
    928 		       snpdev, device );
    929 		efirc = EFI_UNSUPPORTED;
    930 		goto err_no_netdev;
    931 	}
    932 	snpdev->netdev = netdev_get ( netdev );
    933 
    934 	/* Sanity check */
    935 	if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
    936 		DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
    937 		       "length %d for %s\n", snpdev,
    938 		       netdev->ll_protocol->ll_addr_len, netdev->name );
    939 		efirc = EFI_INVALID_PARAMETER;
    940 		goto err_ll_addr_len;
    941 	}
    942 
    943 	/* Populate the SNP structure */
    944 	memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
    945 	snpdev->snp.Mode = &snpdev->mode;
    946 	if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
    947 					 efi_snp_wait_for_packet, snpdev,
    948 					 &snpdev->snp.WaitForPacket ) ) != 0 ){
    949 		DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
    950 		       snpdev, efi_strerror ( efirc ) );
    951 		goto err_create_event;
    952 	}
    953 
    954 	/* Populate the SNP mode structure */
    955 	snpdev->mode.State = EfiSimpleNetworkStopped;
    956 	efi_snp_set_mode ( snpdev );
    957 
    958 	/* Populate the NII structure */
    959 	snpdev->nii.Revision =
    960 		EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
    961 	strncpy ( snpdev->nii.StringId, "gPXE",
    962 		  sizeof ( snpdev->nii.StringId ) );
    963 
    964 	/* Populate the device name */
    965 	for ( i = 0 ; i < sizeof ( netdev->name ) ; i++ ) {
    966 		/* Damn Unicode names */
    967 		assert ( i < ( sizeof ( snpdev->name ) /
    968 			       sizeof ( snpdev->name[0] ) ) );
    969 		snpdev->name[i] = netdev->name[i];
    970 	}
    971 
    972 	/* Populate the device path */
    973 	memcpy ( &snpdev->path, path, path_prefix_len );
    974 	macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
    975 	subpath = ( ( void * ) ( macpath + 1 ) );
    976 	memset ( macpath, 0, sizeof ( *macpath ) );
    977 	macpath->Header.Type = MESSAGING_DEVICE_PATH;
    978 	macpath->Header.SubType = MSG_MAC_ADDR_DP;
    979 	macpath->Header.Length[0] = sizeof ( *macpath );
    980 	memcpy ( &macpath->MacAddress, netdev->ll_addr,
    981 		 sizeof ( macpath->MacAddress ) );
    982 	macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
    983 	memset ( subpath, 0, sizeof ( *subpath ) );
    984 	subpath->Type = END_DEVICE_PATH_TYPE;
    985 	subpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
    986 	subpath->Length[0] = sizeof ( *subpath );
    987 
    988 	/* Install the SNP */
    989 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
    990 			&snpdev->handle,
    991 			&efi_simple_network_protocol_guid, &snpdev->snp,
    992 			&efi_device_path_protocol_guid, &snpdev->path,
    993 			&efi_nii_protocol_guid, &snpdev->nii,
    994 			&efi_nii31_protocol_guid, &snpdev->nii,
    995 			NULL ) ) != 0 ) {
    996 		DBGC ( snpdev, "SNPDEV %p could not install protocols: "
    997 		       "%s\n", snpdev, efi_strerror ( efirc ) );
    998 		goto err_install_protocol_interface;
    999 	}
   1000 
   1001 	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
   1002 	       snpdev, netdev->name, snpdev->handle );
   1003 	return 0;
   1004 
   1005 	bs->UninstallMultipleProtocolInterfaces (
   1006 			snpdev->handle,
   1007 			&efi_simple_network_protocol_guid, &snpdev->snp,
   1008 			&efi_device_path_protocol_guid, &snpdev->path,
   1009 			&efi_nii_protocol_guid, &snpdev->nii,
   1010 			&efi_nii31_protocol_guid, &snpdev->nii,
   1011 			NULL );
   1012  err_install_protocol_interface:
   1013 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
   1014  err_create_event:
   1015  err_ll_addr_len:
   1016 	netdev_put ( netdev );
   1017  err_no_netdev:
   1018 	free ( snpdev );
   1019  err_alloc_snp:
   1020 	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
   1021 			    driver->DriverBindingHandle, device );
   1022  err_no_device_path:
   1023 	return efirc;
   1024 }
   1025 
   1026 /**
   1027  * Detach driver from device
   1028  *
   1029  * @v driver		EFI driver
   1030  * @v device		EFI device
   1031  * @v num_children	Number of child devices
   1032  * @v children		List of child devices
   1033  * @ret efirc		EFI status code
   1034  */
   1035 static EFI_STATUS EFIAPI
   1036 efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
   1037 		      EFI_HANDLE device,
   1038 		      UINTN num_children,
   1039 		      EFI_HANDLE *children ) {
   1040 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
   1041 	struct efi_snp_device *snpdev;
   1042 
   1043 	DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n",
   1044 		driver, device, ( ( unsigned long ) num_children ), children );
   1045 
   1046 	/* Locate SNP device */
   1047 	snpdev = efi_snp_snpdev ( driver, device );
   1048 	if ( ! snpdev ) {
   1049 		DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n",
   1050 		       driver, device );
   1051 		return EFI_DEVICE_ERROR;
   1052 	}
   1053 
   1054 	/* Uninstall the SNP */
   1055 	bs->UninstallMultipleProtocolInterfaces (
   1056 			snpdev->handle,
   1057 			&efi_simple_network_protocol_guid, &snpdev->snp,
   1058 			&efi_device_path_protocol_guid, &snpdev->path,
   1059 			&efi_nii_protocol_guid, &snpdev->nii,
   1060 			&efi_nii31_protocol_guid, &snpdev->nii,
   1061 			NULL );
   1062 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
   1063 	netdev_put ( snpdev->netdev );
   1064 	free ( snpdev );
   1065 	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
   1066 			    driver->DriverBindingHandle, device );
   1067 	return 0;
   1068 }
   1069 
   1070 /** EFI SNP driver binding */
   1071 static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
   1072 	efi_snp_driver_supported,
   1073 	efi_snp_driver_start,
   1074 	efi_snp_driver_stop,
   1075 	0x10,
   1076 	NULL,
   1077 	NULL
   1078 };
   1079 
   1080 /**
   1081  * Look up driver name
   1082  *
   1083  * @v wtf		Component name protocol
   1084  * @v language		Language to use
   1085  * @v driver_name	Driver name to fill in
   1086  * @ret efirc		EFI status code
   1087  */
   1088 static EFI_STATUS EFIAPI
   1089 efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
   1090 			  CHAR8 *language __unused, CHAR16 **driver_name ) {
   1091 
   1092 	*driver_name = L"" PRODUCT_SHORT_NAME " Driver";
   1093 	return 0;
   1094 }
   1095 
   1096 /**
   1097  * Look up controller name
   1098  *
   1099  * @v wtf		Component name protocol
   1100  * @v device		Device
   1101  * @v child		Child device, or NULL
   1102  * @v language		Language to use
   1103  * @v driver_name	Device name to fill in
   1104  * @ret efirc		EFI status code
   1105  */
   1106 static EFI_STATUS EFIAPI
   1107 efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
   1108 			      EFI_HANDLE device __unused,
   1109 			      EFI_HANDLE child __unused,
   1110 			      CHAR8 *language __unused,
   1111 			      CHAR16 **controller_name __unused ) {
   1112 
   1113 	/* Just let EFI use the default Device Path Name */
   1114 	return EFI_UNSUPPORTED;
   1115 }
   1116 
   1117 /** EFI SNP component name protocol */
   1118 static EFI_COMPONENT_NAME2_PROTOCOL efi_snp_name = {
   1119 	efi_snp_get_driver_name,
   1120 	efi_snp_get_controller_name,
   1121 	"en"
   1122 };
   1123 
   1124 /**
   1125  * Install EFI SNP driver
   1126  *
   1127  * @ret rc		Return status code
   1128  */
   1129 int efi_snp_install ( void ) {
   1130 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
   1131 	EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding;
   1132 	EFI_STATUS efirc;
   1133 
   1134 	driver->ImageHandle = efi_image_handle;
   1135 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
   1136 			&driver->DriverBindingHandle,
   1137 			&efi_driver_binding_protocol_guid, driver,
   1138 			&efi_component_name2_protocol_guid, &efi_snp_name,
   1139 			NULL ) ) != 0 ) {
   1140 		DBGC ( driver, "SNPDRV %p could not install protocols: "
   1141 		       "%s\n", driver, efi_strerror ( efirc ) );
   1142 		return EFIRC_TO_RC ( efirc );
   1143 	}
   1144 
   1145 	DBGC ( driver, "SNPDRV %p driver binding installed as %p\n",
   1146 	       driver, driver->DriverBindingHandle );
   1147 	return 0;
   1148 }
   1149