|
|
1.1 root 1: /*
2: * Copyright (C) 2008 Michael Brown <[email protected]>.
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 <ipxe/netdevice.h>
27: #include <ipxe/iobuf.h>
28: #include <ipxe/in.h>
29: #include <ipxe/pci.h>
30: #include <ipxe/efi/efi.h>
31: #include <ipxe/efi/efi_pci.h>
32: #include <ipxe/efi/efi_driver.h>
33: #include <ipxe/efi/efi_strings.h>
34: #include <ipxe/efi/efi_hii.h>
35: #include <ipxe/efi/Protocol/SimpleNetwork.h>
36: #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
37: #include <ipxe/efi/Protocol/DevicePath.h>
38: #include <ipxe/efi/Protocol/HiiConfigAccess.h>
39: #include <ipxe/efi/Protocol/HiiDatabase.h>
40: #include <config/general.h>
41:
42: /** @file
43: *
44: * iPXE EFI SNP interface
45: *
46: */
47:
48: /** An SNP device */
49: struct efi_snp_device {
50: /** List of SNP devices */
51: struct list_head list;
52: /** The underlying iPXE network device */
53: struct net_device *netdev;
54: /** The underlying EFI PCI device */
55: struct efi_pci_device *efipci;
56: /** EFI device handle */
57: EFI_HANDLE handle;
58: /** The SNP structure itself */
59: EFI_SIMPLE_NETWORK_PROTOCOL snp;
60: /** The SNP "mode" (parameters) */
61: EFI_SIMPLE_NETWORK_MODE mode;
62: /** Outstanding TX packet count (via "interrupt status")
63: *
64: * Used in order to generate TX completions.
65: */
66: unsigned int tx_count_interrupts;
67: /** Outstanding TX packet count (via "recycled tx buffers")
68: *
69: * Used in order to generate TX completions.
70: */
71: unsigned int tx_count_txbufs;
72: /** Outstanding RX packet count (via "interrupt status") */
73: unsigned int rx_count_interrupts;
74: /** Outstanding RX packet count (via WaitForPacket event) */
75: unsigned int rx_count_events;
76: /** The network interface identifier */
77: EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
78: /** HII configuration access protocol */
79: EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
80: /** HII package list */
81: EFI_HII_PACKAGE_LIST_HEADER *package_list;
82: /** HII handle */
83: EFI_HII_HANDLE hii_handle;
84: /** Device name */
85: wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
86: /** The device path
87: *
88: * This field is variable in size and must appear at the end
89: * of the structure.
90: */
91: EFI_DEVICE_PATH_PROTOCOL path;
92: };
93:
94: /** EFI simple network protocol GUID */
95: static EFI_GUID efi_simple_network_protocol_guid
96: = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
97:
98: /** EFI device path protocol GUID */
99: static EFI_GUID efi_device_path_protocol_guid
100: = EFI_DEVICE_PATH_PROTOCOL_GUID;
101:
102: /** EFI network interface identifier GUID */
103: static EFI_GUID efi_nii_protocol_guid
104: = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
105:
106: /** EFI network interface identifier GUID (extra special version) */
107: static EFI_GUID efi_nii31_protocol_guid = {
108: /* At some point, it seems that someone decided to change the
109: * GUID. Current EFI builds ignore the older GUID, older EFI
110: * builds ignore the newer GUID, so we have to expose both.
111: */
112: 0x1ACED566, 0x76ED, 0x4218,
113: { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
114: };
115:
116: /** List of SNP devices */
117: static LIST_HEAD ( efi_snp_devices );
118:
119: /**
120: * Set EFI SNP mode based on iPXE net device parameters
121: *
122: * @v snp SNP interface
123: */
124: static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
125: struct net_device *netdev = snpdev->netdev;
126: EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
127: struct ll_protocol *ll_protocol = netdev->ll_protocol;
128: unsigned int ll_addr_len = ll_protocol->ll_addr_len;
129:
130: mode->HwAddressSize = ll_addr_len;
131: mode->MediaHeaderSize = ll_protocol->ll_header_len;
132: mode->MaxPacketSize = netdev->max_pkt_len;
133: mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
134: EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
135: EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
136: assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
137: memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
138: memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
139: ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
140: mode->IfType = ntohs ( ll_protocol->ll_proto );
141: mode->MacAddressChangeable = TRUE;
142: mode->MediaPresentSupported = TRUE;
143: mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
144: }
145:
146: /**
147: * Poll net device and count received packets
148: *
149: * @v snpdev SNP device
150: */
151: static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
152: struct io_buffer *iobuf;
153: unsigned int before = 0;
154: unsigned int after = 0;
155: unsigned int arrived;
156:
157: /* We have to report packet arrivals, and this is the easiest
158: * way to fake it.
159: */
160: list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
161: before++;
162: netdev_poll ( snpdev->netdev );
163: list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
164: after++;
165: arrived = ( after - before );
166:
167: snpdev->rx_count_interrupts += arrived;
168: snpdev->rx_count_events += arrived;
169: }
170:
171: /**
172: * Change SNP state from "stopped" to "started"
173: *
174: * @v snp SNP interface
175: * @ret efirc EFI status code
176: */
177: static EFI_STATUS EFIAPI
178: efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
179: struct efi_snp_device *snpdev =
180: container_of ( snp, struct efi_snp_device, snp );
181:
182: DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
183:
184: snpdev->mode.State = EfiSimpleNetworkStarted;
185: return 0;
186: }
187:
188: /**
189: * Change SNP state from "started" to "stopped"
190: *
191: * @v snp SNP interface
192: * @ret efirc EFI status code
193: */
194: static EFI_STATUS EFIAPI
195: efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
196: struct efi_snp_device *snpdev =
197: container_of ( snp, struct efi_snp_device, snp );
198:
199: DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
200:
201: snpdev->mode.State = EfiSimpleNetworkStopped;
202: return 0;
203: }
204:
205: /**
206: * Open the network device
207: *
208: * @v snp SNP interface
209: * @v extra_rx_bufsize Extra RX buffer size, in bytes
210: * @v extra_tx_bufsize Extra TX buffer size, in bytes
211: * @ret efirc EFI status code
212: */
213: static EFI_STATUS EFIAPI
214: efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
215: UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
216: struct efi_snp_device *snpdev =
217: container_of ( snp, struct efi_snp_device, snp );
218: int rc;
219:
220: DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
221: snpdev, ( ( unsigned long ) extra_rx_bufsize ),
222: ( ( unsigned long ) extra_tx_bufsize ) );
223:
224: if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
225: DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
226: snpdev, snpdev->netdev->name, strerror ( rc ) );
227: return RC_TO_EFIRC ( rc );
228: }
229:
230: snpdev->mode.State = EfiSimpleNetworkInitialized;
231: return 0;
232: }
233:
234: /**
235: * Reset the network device
236: *
237: * @v snp SNP interface
238: * @v ext_verify Extended verification required
239: * @ret efirc EFI status code
240: */
241: static EFI_STATUS EFIAPI
242: efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
243: struct efi_snp_device *snpdev =
244: container_of ( snp, struct efi_snp_device, snp );
245: int rc;
246:
247: DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
248: snpdev, ( ext_verify ? "with" : "without" ) );
249:
250: netdev_close ( snpdev->netdev );
251: snpdev->mode.State = EfiSimpleNetworkStarted;
252:
253: if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
254: DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
255: snpdev, snpdev->netdev->name, strerror ( rc ) );
256: return RC_TO_EFIRC ( rc );
257: }
258:
259: snpdev->mode.State = EfiSimpleNetworkInitialized;
260: return 0;
261: }
262:
263: /**
264: * Shut down the network device
265: *
266: * @v snp SNP interface
267: * @ret efirc EFI status code
268: */
269: static EFI_STATUS EFIAPI
270: efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
271: struct efi_snp_device *snpdev =
272: container_of ( snp, struct efi_snp_device, snp );
273:
274: DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
275:
276: netdev_close ( snpdev->netdev );
277: snpdev->mode.State = EfiSimpleNetworkStarted;
278: return 0;
279: }
280:
281: /**
282: * Manage receive filters
283: *
284: * @v snp SNP interface
285: * @v enable Receive filters to enable
286: * @v disable Receive filters to disable
287: * @v mcast_reset Reset multicast filters
288: * @v mcast_count Number of multicast filters
289: * @v mcast Multicast filters
290: * @ret efirc EFI status code
291: */
292: static EFI_STATUS EFIAPI
293: efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
294: UINT32 disable, BOOLEAN mcast_reset,
295: UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
296: struct efi_snp_device *snpdev =
297: container_of ( snp, struct efi_snp_device, snp );
298: unsigned int i;
299:
300: DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
301: snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
302: ( ( unsigned long ) mcast_count ) );
303: for ( i = 0 ; i < mcast_count ; i++ ) {
304: DBGC2_HDA ( snpdev, i, &mcast[i],
305: snpdev->netdev->ll_protocol->ll_addr_len );
306: }
307:
308: /* Lie through our teeth, otherwise MNP refuses to accept us */
309: return 0;
310: }
311:
312: /**
313: * Set station address
314: *
315: * @v snp SNP interface
316: * @v reset Reset to permanent address
317: * @v new New station address
318: * @ret efirc EFI status code
319: */
320: static EFI_STATUS EFIAPI
321: efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
322: EFI_MAC_ADDRESS *new ) {
323: struct efi_snp_device *snpdev =
324: container_of ( snp, struct efi_snp_device, snp );
325: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
326:
327: DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
328: ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
329:
330: /* Set the MAC address */
331: if ( reset )
332: new = &snpdev->mode.PermanentAddress;
333: memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
334:
335: /* MAC address changes take effect only on netdev_open() */
336: if ( netdev_is_open ( snpdev->netdev ) ) {
337: DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
338: "devive open\n", snpdev );
339: }
340:
341: return 0;
342: }
343:
344: /**
345: * Get (or reset) statistics
346: *
347: * @v snp SNP interface
348: * @v reset Reset statistics
349: * @v stats_len Size of statistics table
350: * @v stats Statistics table
351: * @ret efirc EFI status code
352: */
353: static EFI_STATUS EFIAPI
354: efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
355: UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
356: struct efi_snp_device *snpdev =
357: container_of ( snp, struct efi_snp_device, snp );
358: EFI_NETWORK_STATISTICS stats_buf;
359:
360: DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
361: ( reset ? " reset" : "" ) );
362:
363: /* Gather statistics */
364: memset ( &stats_buf, 0, sizeof ( stats_buf ) );
365: stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
366: stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
367: stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
368: snpdev->netdev->tx_stats.bad );
369: stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
370: stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
371: stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
372: snpdev->netdev->rx_stats.bad );
373: if ( *stats_len > sizeof ( stats_buf ) )
374: *stats_len = sizeof ( stats_buf );
375: if ( stats )
376: memcpy ( stats, &stats_buf, *stats_len );
377:
378: /* Reset statistics if requested to do so */
379: if ( reset ) {
380: memset ( &snpdev->netdev->tx_stats, 0,
381: sizeof ( snpdev->netdev->tx_stats ) );
382: memset ( &snpdev->netdev->rx_stats, 0,
383: sizeof ( snpdev->netdev->rx_stats ) );
384: }
385:
386: return 0;
387: }
388:
389: /**
390: * Convert multicast IP address to MAC address
391: *
392: * @v snp SNP interface
393: * @v ipv6 Address is IPv6
394: * @v ip IP address
395: * @v mac MAC address
396: * @ret efirc EFI status code
397: */
398: static EFI_STATUS EFIAPI
399: efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
400: EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
401: struct efi_snp_device *snpdev =
402: container_of ( snp, struct efi_snp_device, snp );
403: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
404: const char *ip_str;
405: int rc;
406:
407: ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
408: inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
409: DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
410:
411: /* Try to hash the address */
412: if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
413: ip, mac ) ) != 0 ) {
414: DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
415: snpdev, ip_str, strerror ( rc ) );
416: return RC_TO_EFIRC ( rc );
417: }
418:
419: return 0;
420: }
421:
422: /**
423: * Read or write non-volatile storage
424: *
425: * @v snp SNP interface
426: * @v read Operation is a read
427: * @v offset Starting offset within NVRAM
428: * @v len Length of data buffer
429: * @v data Data buffer
430: * @ret efirc EFI status code
431: */
432: static EFI_STATUS EFIAPI
433: efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
434: UINTN offset, UINTN len, VOID *data ) {
435: struct efi_snp_device *snpdev =
436: container_of ( snp, struct efi_snp_device, snp );
437:
438: DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
439: ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
440: ( ( unsigned long ) len ) );
441: if ( ! read )
442: DBGC2_HDA ( snpdev, offset, data, len );
443:
444: return EFI_UNSUPPORTED;
445: }
446:
447: /**
448: * Read interrupt status and TX recycled buffer status
449: *
450: * @v snp SNP interface
451: * @v interrupts Interrupt status, or NULL
452: * @v txbufs Recycled transmit buffer address, or NULL
453: * @ret efirc EFI status code
454: */
455: static EFI_STATUS EFIAPI
456: efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
457: UINT32 *interrupts, VOID **txbufs ) {
458: struct efi_snp_device *snpdev =
459: container_of ( snp, struct efi_snp_device, snp );
460:
461: DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
462:
463: /* Poll the network device */
464: efi_snp_poll ( snpdev );
465:
466: /* Interrupt status. In practice, this seems to be used only
467: * to detect TX completions.
468: */
469: if ( interrupts ) {
470: *interrupts = 0;
471: /* Report TX completions once queue is empty; this
472: * avoids having to add hooks in the net device layer.
473: */
474: if ( snpdev->tx_count_interrupts &&
475: list_empty ( &snpdev->netdev->tx_queue ) ) {
476: *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
477: snpdev->tx_count_interrupts--;
478: }
479: /* Report RX */
480: if ( snpdev->rx_count_interrupts ) {
481: *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
482: snpdev->rx_count_interrupts--;
483: }
484: DBGC2 ( snpdev, " INTS:%02x", *interrupts );
485: }
486:
487: /* TX completions. It would be possible to design a more
488: * idiotic scheme for this, but it would be a challenge.
489: * According to the UEFI header file, txbufs will be filled in
490: * with a list of "recycled transmit buffers" (i.e. completed
491: * TX buffers). Observant readers may care to note that
492: * *txbufs is a void pointer. Precisely how a list of
493: * completed transmit buffers is meant to be represented as an
494: * array of voids is left as an exercise for the reader.
495: *
496: * The only users of this interface (MnpDxe/MnpIo.c and
497: * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
498: * seeing a non-NULL result return in txbufs. This is valid
499: * provided that they do not ever attempt to transmit more
500: * than one packet concurrently (and that TX never times out).
501: */
502: if ( txbufs ) {
503: if ( snpdev->tx_count_txbufs &&
504: list_empty ( &snpdev->netdev->tx_queue ) ) {
505: *txbufs = "Which idiot designed this API?";
506: snpdev->tx_count_txbufs--;
507: } else {
508: *txbufs = NULL;
509: }
510: DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
511: }
512:
513: DBGC2 ( snpdev, "\n" );
514: return 0;
515: }
516:
517: /**
518: * Start packet transmission
519: *
520: * @v snp SNP interface
521: * @v ll_header_len Link-layer header length, if to be filled in
522: * @v len Length of data buffer
523: * @v data Data buffer
524: * @v ll_src Link-layer source address, if specified
525: * @v ll_dest Link-layer destination address, if specified
526: * @v net_proto Network-layer protocol (in host order)
527: * @ret efirc EFI status code
528: */
529: static EFI_STATUS EFIAPI
530: efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
531: UINTN ll_header_len, UINTN len, VOID *data,
532: EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
533: UINT16 *net_proto ) {
534: struct efi_snp_device *snpdev =
535: container_of ( snp, struct efi_snp_device, snp );
536: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
537: struct io_buffer *iobuf;
538: size_t ll_headroom;
539: int rc;
540: EFI_STATUS efirc;
541:
542: DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
543: ( ( unsigned long ) len ) );
544: if ( ll_header_len ) {
545: if ( ll_src ) {
546: DBGC2 ( snpdev, " src %s",
547: ll_protocol->ntoa ( ll_src ) );
548: }
549: if ( ll_dest ) {
550: DBGC2 ( snpdev, " dest %s",
551: ll_protocol->ntoa ( ll_dest ) );
552: }
553: if ( net_proto ) {
554: DBGC2 ( snpdev, " proto %04x", *net_proto );
555: }
556: }
557: DBGC2 ( snpdev, "\n" );
558:
559: /* Sanity checks */
560: if ( ll_header_len ) {
561: if ( ll_header_len != ll_protocol->ll_header_len ) {
562: DBGC ( snpdev, "SNPDEV %p TX invalid header length "
563: "%ld\n", snpdev,
564: ( ( unsigned long ) ll_header_len ) );
565: efirc = EFI_INVALID_PARAMETER;
566: goto err_sanity;
567: }
568: if ( len < ll_header_len ) {
569: DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
570: snpdev, ( ( unsigned long ) len ) );
571: efirc = EFI_BUFFER_TOO_SMALL;
572: goto err_sanity;
573: }
574: if ( ! ll_dest ) {
575: DBGC ( snpdev, "SNPDEV %p TX missing destination "
576: "address\n", snpdev );
577: efirc = EFI_INVALID_PARAMETER;
578: goto err_sanity;
579: }
580: if ( ! net_proto ) {
581: DBGC ( snpdev, "SNPDEV %p TX missing network "
582: "protocol\n", snpdev );
583: efirc = EFI_INVALID_PARAMETER;
584: goto err_sanity;
585: }
586: if ( ! ll_src )
587: ll_src = &snpdev->mode.CurrentAddress;
588: }
589:
590: /* Allocate buffer */
591: ll_headroom = ( MAX_LL_HEADER_LEN - ll_header_len );
592: iobuf = alloc_iob ( ll_headroom + len );
593: if ( ! iobuf ) {
594: DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
595: "buffer\n", snpdev, ( ( unsigned long ) len ) );
596: efirc = EFI_DEVICE_ERROR;
597: goto err_alloc_iob;
598: }
599: iob_reserve ( iobuf, ll_headroom );
600: memcpy ( iob_put ( iobuf, len ), data, len );
601:
602: /* Create link-layer header, if specified */
603: if ( ll_header_len ) {
604: iob_pull ( iobuf, ll_header_len );
605: if ( ( rc = ll_protocol->push ( snpdev->netdev,
606: iobuf, ll_dest, ll_src,
607: htons ( *net_proto ) )) != 0 ){
608: DBGC ( snpdev, "SNPDEV %p TX could not construct "
609: "header: %s\n", snpdev, strerror ( rc ) );
610: efirc = RC_TO_EFIRC ( rc );
611: goto err_ll_push;
612: }
613: }
614:
615: /* Transmit packet */
616: if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
617: DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
618: snpdev, strerror ( rc ) );
619: efirc = RC_TO_EFIRC ( rc );
620: goto err_tx;
621: }
622:
623: /* Record transmission as outstanding */
624: snpdev->tx_count_interrupts++;
625: snpdev->tx_count_txbufs++;
626:
627: return 0;
628:
629: err_tx:
630: err_ll_push:
631: free_iob ( iobuf );
632: err_alloc_iob:
633: err_sanity:
634: return efirc;
635: }
636:
637: /**
638: * Receive packet
639: *
640: * @v snp SNP interface
641: * @v ll_header_len Link-layer header length, if to be filled in
642: * @v len Length of data buffer
643: * @v data Data buffer
644: * @v ll_src Link-layer source address, if specified
645: * @v ll_dest Link-layer destination address, if specified
646: * @v net_proto Network-layer protocol (in host order)
647: * @ret efirc EFI status code
648: */
649: static EFI_STATUS EFIAPI
650: efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
651: UINTN *ll_header_len, UINTN *len, VOID *data,
652: EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
653: UINT16 *net_proto ) {
654: struct efi_snp_device *snpdev =
655: container_of ( snp, struct efi_snp_device, snp );
656: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
657: struct io_buffer *iobuf;
658: const void *iob_ll_dest;
659: const void *iob_ll_src;
660: uint16_t iob_net_proto;
661: int rc;
662: EFI_STATUS efirc;
663:
664: DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
665: ( ( unsigned long ) *len ) );
666:
667: /* Poll the network device */
668: efi_snp_poll ( snpdev );
669:
670: /* Dequeue a packet, if one is available */
671: iobuf = netdev_rx_dequeue ( snpdev->netdev );
672: if ( ! iobuf ) {
673: DBGC2 ( snpdev, "\n" );
674: efirc = EFI_NOT_READY;
675: goto out_no_packet;
676: }
677: DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
678:
679: /* Return packet to caller */
680: memcpy ( data, iobuf->data, iob_len ( iobuf ) );
681: *len = iob_len ( iobuf );
682:
683: /* Attempt to decode link-layer header */
684: if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
685: &iob_ll_src, &iob_net_proto ) ) != 0 ){
686: DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
687: snpdev, strerror ( rc ) );
688: efirc = RC_TO_EFIRC ( rc );
689: goto out_bad_ll_header;
690: }
691:
692: /* Return link-layer header parameters to caller, if required */
693: if ( ll_header_len )
694: *ll_header_len = ll_protocol->ll_header_len;
695: if ( ll_src )
696: memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
697: if ( ll_dest )
698: memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
699: if ( net_proto )
700: *net_proto = ntohs ( iob_net_proto );
701:
702: efirc = 0;
703:
704: out_bad_ll_header:
705: free_iob ( iobuf );
706: out_no_packet:
707: return efirc;
708: }
709:
710: /**
711: * Poll event
712: *
713: * @v event Event
714: * @v context Event context
715: */
716: static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
717: VOID *context ) {
718: EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
719: struct efi_snp_device *snpdev = context;
720:
721: DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
722:
723: /* Do nothing unless the net device is open */
724: if ( ! netdev_is_open ( snpdev->netdev ) )
725: return;
726:
727: /* Poll the network device */
728: efi_snp_poll ( snpdev );
729:
730: /* Fire event if packets have been received */
731: if ( snpdev->rx_count_events != 0 ) {
732: DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
733: snpdev );
734: bs->SignalEvent ( event );
735: snpdev->rx_count_events--;
736: }
737: }
738:
739: /** SNP interface */
740: static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
741: .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
742: .Start = efi_snp_start,
743: .Stop = efi_snp_stop,
744: .Initialize = efi_snp_initialize,
745: .Reset = efi_snp_reset,
746: .Shutdown = efi_snp_shutdown,
747: .ReceiveFilters = efi_snp_receive_filters,
748: .StationAddress = efi_snp_station_address,
749: .Statistics = efi_snp_statistics,
750: .MCastIpToMac = efi_snp_mcast_ip_to_mac,
751: .NvData = efi_snp_nvdata,
752: .GetStatus = efi_snp_get_status,
753: .Transmit = efi_snp_transmit,
754: .Receive = efi_snp_receive,
755: };
756:
757: /******************************************************************************
758: *
759: * Human Interface Infrastructure
760: *
761: ******************************************************************************
762: */
763:
764: /** EFI configuration access protocol GUID */
765: static EFI_GUID efi_hii_config_access_protocol_guid
766: = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
767:
768: /** EFI HII database protocol */
769: static EFI_HII_DATABASE_PROTOCOL *efihii;
770: EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
771:
772: /** Local GUID used for our EFI SNP formset */
773: #define EFI_SNP_FORMSET_GUID \
774: { 0xc4f84019, 0x6dfd, 0x4a27, \
775: { 0x9b, 0x94, 0xb7, 0x2e, 0x1f, 0xbc, 0xad, 0xca } }
776:
777: /** Form identifiers used for our EFI SNP HII */
778: enum efi_snp_hii_form_id {
779: EFI_SNP_FORM = 0x0001, /**< The only form */
780: };
781:
782: /** String identifiers used for our EFI SNP HII */
783: enum efi_snp_hii_string_id {
784: /* Language name */
785: EFI_SNP_LANGUAGE_NAME = 0x0001,
786: /* Formset */
787: EFI_SNP_FORMSET_TITLE, EFI_SNP_FORMSET_HELP,
788: /* Product name */
789: EFI_SNP_PRODUCT_PROMPT, EFI_SNP_PRODUCT_HELP, EFI_SNP_PRODUCT_TEXT,
790: /* Version */
791: EFI_SNP_VERSION_PROMPT, EFI_SNP_VERSION_HELP, EFI_SNP_VERSION_TEXT,
792: /* Driver */
793: EFI_SNP_DRIVER_PROMPT, EFI_SNP_DRIVER_HELP, EFI_SNP_DRIVER_TEXT,
794: /* Device */
795: EFI_SNP_DEVICE_PROMPT, EFI_SNP_DEVICE_HELP, EFI_SNP_DEVICE_TEXT,
796: /* End of list */
797: EFI_SNP_MAX_STRING_ID
798: };
799:
800: /** EFI SNP formset */
801: struct efi_snp_formset {
802: EFI_HII_PACKAGE_HEADER Header;
803: EFI_IFR_FORM_SET_TYPE(1) FormSet;
804: EFI_IFR_GUID_CLASS Class;
805: EFI_IFR_GUID_SUBCLASS SubClass;
806: EFI_IFR_FORM Form;
807: EFI_IFR_TEXT ProductText;
808: EFI_IFR_TEXT VersionText;
809: EFI_IFR_TEXT DriverText;
810: EFI_IFR_TEXT DeviceText;
811: EFI_IFR_END EndForm;
812: EFI_IFR_END EndFormSet;
813: } __attribute__ (( packed )) efi_snp_formset = {
814: .Header = {
815: .Length = sizeof ( efi_snp_formset ),
816: .Type = EFI_HII_PACKAGE_FORMS,
817: },
818: .FormSet = EFI_IFR_FORM_SET ( EFI_SNP_FORMSET_GUID,
819: EFI_SNP_FORMSET_TITLE,
820: EFI_SNP_FORMSET_HELP,
821: typeof ( efi_snp_formset.FormSet ),
822: EFI_HII_PLATFORM_SETUP_FORMSET_GUID ),
823: .Class = EFI_IFR_GUID_CLASS ( EFI_NETWORK_DEVICE_CLASS ),
824: .SubClass = EFI_IFR_GUID_SUBCLASS ( 0x03 ),
825: .Form = EFI_IFR_FORM ( EFI_SNP_FORM, EFI_SNP_FORMSET_TITLE ),
826: .ProductText = EFI_IFR_TEXT ( EFI_SNP_PRODUCT_PROMPT,
827: EFI_SNP_PRODUCT_HELP,
828: EFI_SNP_PRODUCT_TEXT ),
829: .VersionText = EFI_IFR_TEXT ( EFI_SNP_VERSION_PROMPT,
830: EFI_SNP_VERSION_HELP,
831: EFI_SNP_VERSION_TEXT ),
832: .DriverText = EFI_IFR_TEXT ( EFI_SNP_DRIVER_PROMPT,
833: EFI_SNP_DRIVER_HELP,
834: EFI_SNP_DRIVER_TEXT ),
835: .DeviceText = EFI_IFR_TEXT ( EFI_SNP_DEVICE_PROMPT,
836: EFI_SNP_DEVICE_HELP,
837: EFI_SNP_DEVICE_TEXT ),
838: .EndForm = EFI_IFR_END(),
839: .EndFormSet = EFI_IFR_END(),
840: };
841:
842: /**
843: * Generate EFI SNP string
844: *
845: * @v wbuf Buffer
846: * @v swlen Size of buffer (in wide characters)
847: * @v snpdev SNP device
848: * @ret wlen Length of string (in wide characters)
849: */
850: static int efi_snp_string ( wchar_t *wbuf, ssize_t swlen,
851: enum efi_snp_hii_string_id id,
852: struct efi_snp_device *snpdev ) {
853: struct net_device *netdev = snpdev->netdev;
854: struct device *dev = netdev->dev;
855:
856: switch ( id ) {
857: case EFI_SNP_LANGUAGE_NAME:
858: return efi_ssnprintf ( wbuf, swlen, "English" );
859: case EFI_SNP_FORMSET_TITLE:
860: return efi_ssnprintf ( wbuf, swlen, "%s (%s)",
861: ( PRODUCT_NAME[0] ?
862: PRODUCT_NAME : PRODUCT_SHORT_NAME ),
863: netdev_addr ( netdev ) );
864: case EFI_SNP_FORMSET_HELP:
865: return efi_ssnprintf ( wbuf, swlen,
866: "Configure " PRODUCT_SHORT_NAME );
867: case EFI_SNP_PRODUCT_PROMPT:
868: return efi_ssnprintf ( wbuf, swlen, "Name" );
869: case EFI_SNP_PRODUCT_HELP:
870: return efi_ssnprintf ( wbuf, swlen, "Firmware product name" );
871: case EFI_SNP_PRODUCT_TEXT:
872: return efi_ssnprintf ( wbuf, swlen, "%s",
873: ( PRODUCT_NAME[0] ?
874: PRODUCT_NAME : PRODUCT_SHORT_NAME ) );
875: case EFI_SNP_VERSION_PROMPT:
876: return efi_ssnprintf ( wbuf, swlen, "Version" );
877: case EFI_SNP_VERSION_HELP:
878: return efi_ssnprintf ( wbuf, swlen, "Firmware version" );
879: case EFI_SNP_VERSION_TEXT:
880: return efi_ssnprintf ( wbuf, swlen, VERSION );
881: case EFI_SNP_DRIVER_PROMPT:
882: return efi_ssnprintf ( wbuf, swlen, "Driver" );
883: case EFI_SNP_DRIVER_HELP:
884: return efi_ssnprintf ( wbuf, swlen, "Firmware driver" );
885: case EFI_SNP_DRIVER_TEXT:
886: return efi_ssnprintf ( wbuf, swlen, "%s", dev->driver_name );
887: case EFI_SNP_DEVICE_PROMPT:
888: return efi_ssnprintf ( wbuf, swlen, "Device" );
889: case EFI_SNP_DEVICE_HELP:
890: return efi_ssnprintf ( wbuf, swlen, "Hardware device" );
891: case EFI_SNP_DEVICE_TEXT:
892: return efi_ssnprintf ( wbuf, swlen, "%s", dev->name );
893: default:
894: assert ( 0 );
895: return 0;
896: }
897: }
898:
899: /**
900: * Generate EFI SNP string package
901: *
902: * @v strings String package header buffer
903: * @v max_len Buffer length
904: * @v snpdev SNP device
905: * @ret len Length of string package
906: */
907: static int efi_snp_strings ( EFI_HII_STRING_PACKAGE_HDR *strings,
908: size_t max_len, struct efi_snp_device *snpdev ) {
909: static const char language[] = "en-us";
910: void *buf = strings;
911: ssize_t remaining = max_len;
912: size_t hdrsize;
913: EFI_HII_SIBT_STRING_UCS2_BLOCK *string;
914: ssize_t wremaining;
915: size_t string_wlen;
916: unsigned int id;
917: EFI_HII_STRING_BLOCK *end;
918: size_t len;
919:
920: /* Calculate header size */
921: hdrsize = ( offsetof ( typeof ( *strings ), Language ) +
922: sizeof ( language ) );
923: buf += hdrsize;
924: remaining -= hdrsize;
925:
926: /* Fill in strings */
927: for ( id = 1 ; id < EFI_SNP_MAX_STRING_ID ; id++ ) {
928: string = buf;
929: if ( remaining >= ( ( ssize_t ) sizeof ( string->Header ) ) )
930: string->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
931: buf += offsetof ( typeof ( *string ), StringText );
932: remaining -= offsetof ( typeof ( *string ), StringText );
933: wremaining = ( remaining /
934: ( ( ssize_t ) sizeof ( string->StringText[0] )));
935: assert ( ! ( ( remaining <= 0 ) && ( wremaining > 0 ) ) );
936: string_wlen = efi_snp_string ( string->StringText, wremaining,
937: id, snpdev );
938: buf += ( ( string_wlen + 1 /* wNUL */ ) *
939: sizeof ( string->StringText[0] ) );
940: remaining -= ( ( string_wlen + 1 /* wNUL */ ) *
941: sizeof ( string->StringText[0] ) );
942: }
943:
944: /* Fill in end marker */
945: end = buf;
946: if ( remaining >= ( ( ssize_t ) sizeof ( *end ) ) )
947: end->BlockType = EFI_HII_SIBT_END;
948: buf += sizeof ( *end );
949: remaining -= sizeof ( *end );
950:
951: /* Calculate overall length */
952: len = ( max_len - remaining );
953:
954: /* Fill in string package header */
955: if ( strings ) {
956: memset ( strings, 0, sizeof ( *strings ) );
957: strings->Header.Length = len;
958: strings->Header.Type = EFI_HII_PACKAGE_STRINGS;
959: strings->HdrSize = hdrsize;
960: strings->StringInfoOffset = hdrsize;
961: strings->LanguageName = EFI_SNP_LANGUAGE_NAME;
962: memcpy ( strings->Language, language, sizeof ( language ) );
963: }
964:
965: return len;
966: }
967:
968: /**
969: * Generate EFI SNP package list
970: *
971: * @v snpdev SNP device
972: * @ret package_list Package list, or NULL on error
973: *
974: * The package list is allocated using malloc(), and must eventually
975: * be freed by the caller.
976: */
977: static EFI_HII_PACKAGE_LIST_HEADER *
978: efi_snp_package_list ( struct efi_snp_device *snpdev ) {
979: size_t strings_len = efi_snp_strings ( NULL, 0, snpdev );
980: struct {
981: EFI_HII_PACKAGE_LIST_HEADER header;
982: struct efi_snp_formset formset;
983: union {
984: EFI_HII_STRING_PACKAGE_HDR strings;
985: uint8_t pad[strings_len];
986: } __attribute__ (( packed )) strings;
987: EFI_HII_PACKAGE_HEADER end;
988: } __attribute__ (( packed )) *package_list;
989:
990: /* Allocate package list */
991: package_list = zalloc ( sizeof ( *package_list ) );
992: if ( ! package_list )
993: return NULL;
994:
995: /* Populate package list */
996: memcpy ( &package_list->header.PackageListGuid,
997: &efi_snp_formset.FormSet.FormSet.Guid,
998: sizeof ( package_list->header.PackageListGuid ) );
999: package_list->header.PackageLength = sizeof ( *package_list );
1000: memcpy ( &package_list->formset, &efi_snp_formset,
1001: sizeof ( package_list->formset ) );
1002: efi_snp_strings ( &package_list->strings.strings,
1003: sizeof ( package_list->strings ), snpdev );
1004: package_list->end.Length = sizeof ( package_list->end );
1005: package_list->end.Type = EFI_HII_PACKAGE_END;
1006:
1007: return &package_list->header;
1008: }
1009:
1010: /**
1011: * Fetch configuration
1012: *
1013: * @v hii HII configuration access protocol
1014: * @v request Configuration to fetch
1015: * @ret progress Progress made through configuration to fetch
1016: * @ret results Query results
1017: * @ret efirc EFI status code
1018: */
1019: static EFI_STATUS EFIAPI
1020: efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
1021: EFI_STRING request, EFI_STRING *progress,
1022: EFI_STRING *results __unused ) {
1023: struct efi_snp_device *snpdev =
1024: container_of ( hii, struct efi_snp_device, hii );
1025:
1026: DBGC ( snpdev, "SNPDEV %p ExtractConfig\n", snpdev );
1027:
1028: *progress = request;
1029: return EFI_INVALID_PARAMETER;
1030: }
1031:
1032: /**
1033: * Store configuration
1034: *
1035: * @v hii HII configuration access protocol
1036: * @v config Configuration to store
1037: * @ret progress Progress made through configuration to store
1038: * @ret efirc EFI status code
1039: */
1040: static EFI_STATUS EFIAPI
1041: efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
1042: EFI_STRING config, EFI_STRING *progress ) {
1043: struct efi_snp_device *snpdev =
1044: container_of ( hii, struct efi_snp_device, hii );
1045:
1046: DBGC ( snpdev, "SNPDEV %p RouteConfig\n", snpdev );
1047:
1048: *progress = config;
1049: return EFI_INVALID_PARAMETER;
1050: }
1051:
1052: /**
1053: * Handle form actions
1054: *
1055: * @v hii HII configuration access protocol
1056: * @v action Form browser action
1057: * @v question_id Question ID
1058: * @v type Type of value
1059: * @v value Value
1060: * @ret action_request Action requested by driver
1061: * @ret efirc EFI status code
1062: */
1063: static EFI_STATUS EFIAPI
1064: efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
1065: EFI_BROWSER_ACTION action __unused,
1066: EFI_QUESTION_ID question_id __unused,
1067: UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
1068: EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
1069: struct efi_snp_device *snpdev =
1070: container_of ( hii, struct efi_snp_device, hii );
1071:
1072: DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
1073: return EFI_UNSUPPORTED;
1074: }
1075:
1076: /** HII configuration access protocol */
1077: static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
1078: .ExtractConfig = efi_snp_hii_extract_config,
1079: .RouteConfig = efi_snp_hii_route_config,
1080: .Callback = efi_snp_hii_callback,
1081: };
1082:
1083: /******************************************************************************
1084: *
1085: * iPXE network driver
1086: *
1087: ******************************************************************************
1088: */
1089:
1090: /**
1091: * Locate SNP device corresponding to network device
1092: *
1093: * @v netdev Network device
1094: * @ret snp SNP device, or NULL if not found
1095: */
1096: static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
1097: struct efi_snp_device *snpdev;
1098:
1099: list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
1100: if ( snpdev->netdev == netdev )
1101: return snpdev;
1102: }
1103: return NULL;
1104: }
1105:
1106: /**
1107: * Create SNP device
1108: *
1109: * @v netdev Network device
1110: * @ret rc Return status code
1111: */
1112: static int efi_snp_probe ( struct net_device *netdev ) {
1113: EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
1114: struct efi_pci_device *efipci;
1115: struct efi_snp_device *snpdev;
1116: EFI_DEVICE_PATH_PROTOCOL *path_end;
1117: MAC_ADDR_DEVICE_PATH *macpath;
1118: size_t path_prefix_len = 0;
1119: EFI_STATUS efirc;
1120: int rc;
1121:
1122: /* Find EFI PCI device */
1123: efipci = efipci_find ( netdev->dev );
1124: if ( ! efipci ) {
1125: DBG ( "SNP skipping non-PCI device %s\n", netdev->name );
1126: rc = 0;
1127: goto err_no_pci;
1128: }
1129:
1130: /* Calculate device path prefix length */
1131: path_end = efi_devpath_end ( efipci->path );
1132: path_prefix_len = ( ( ( void * ) path_end ) -
1133: ( ( void * ) efipci->path ) );
1134:
1135: /* Allocate the SNP device */
1136: snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
1137: sizeof ( *macpath ) );
1138: if ( ! snpdev ) {
1139: rc = -ENOMEM;
1140: goto err_alloc_snp;
1141: }
1142: snpdev->netdev = netdev_get ( netdev );
1143: snpdev->efipci = efipci;
1144:
1145: /* Sanity check */
1146: if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
1147: DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
1148: "length %d for %s\n", snpdev,
1149: netdev->ll_protocol->ll_addr_len, netdev->name );
1150: rc = -ENOTSUP;
1151: goto err_ll_addr_len;
1152: }
1153:
1154: /* Populate the SNP structure */
1155: memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
1156: snpdev->snp.Mode = &snpdev->mode;
1157: if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
1158: efi_snp_wait_for_packet, snpdev,
1159: &snpdev->snp.WaitForPacket ) ) != 0 ){
1160: DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
1161: snpdev, efi_strerror ( efirc ) );
1162: rc = EFIRC_TO_RC ( efirc );
1163: goto err_create_event;
1164: }
1165:
1166: /* Populate the SNP mode structure */
1167: snpdev->mode.State = EfiSimpleNetworkStopped;
1168: efi_snp_set_mode ( snpdev );
1169:
1170: /* Populate the NII structure */
1171: snpdev->nii.Revision =
1172: EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
1173: strncpy ( snpdev->nii.StringId, "iPXE",
1174: sizeof ( snpdev->nii.StringId ) );
1175:
1176: /* Populate the HII configuration access structure */
1177: memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
1178:
1179: /* Populate the device name */
1180: efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
1181: sizeof ( snpdev->name[0] ) ),
1182: "%s", netdev->name );
1183:
1184: /* Populate the device path */
1185: memcpy ( &snpdev->path, efipci->path, path_prefix_len );
1186: macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
1187: path_end = ( ( void * ) ( macpath + 1 ) );
1188: memset ( macpath, 0, sizeof ( *macpath ) );
1189: macpath->Header.Type = MESSAGING_DEVICE_PATH;
1190: macpath->Header.SubType = MSG_MAC_ADDR_DP;
1191: macpath->Header.Length[0] = sizeof ( *macpath );
1192: memcpy ( &macpath->MacAddress, netdev->ll_addr,
1193: sizeof ( macpath->MacAddress ) );
1194: macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
1195: memset ( path_end, 0, sizeof ( *path_end ) );
1196: path_end->Type = END_DEVICE_PATH_TYPE;
1197: path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
1198: path_end->Length[0] = sizeof ( *path_end );
1199:
1200: /* Install the SNP */
1201: if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
1202: &snpdev->handle,
1203: &efi_simple_network_protocol_guid, &snpdev->snp,
1204: &efi_device_path_protocol_guid, &snpdev->path,
1205: &efi_nii_protocol_guid, &snpdev->nii,
1206: &efi_nii31_protocol_guid, &snpdev->nii,
1207: &efi_hii_config_access_protocol_guid, &snpdev->hii,
1208: NULL ) ) != 0 ) {
1209: DBGC ( snpdev, "SNPDEV %p could not install protocols: "
1210: "%s\n", snpdev, efi_strerror ( efirc ) );
1211: rc = EFIRC_TO_RC ( efirc );
1212: goto err_install_protocol_interface;
1213: }
1214:
1215: /* Add as child of PCI device */
1216: if ( ( efirc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) {
1217: DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT
1218: ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ),
1219: efi_strerror ( efirc ) );
1220: rc = EFIRC_TO_RC ( efirc );
1221: goto err_efipci_child_add;
1222: }
1223:
1224: /* Create HII package list */
1225: snpdev->package_list = efi_snp_package_list ( snpdev );
1226: if ( ! snpdev->package_list ) {
1227: DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
1228: snpdev );
1229: rc = -ENOMEM;
1230: goto err_create_hii;
1231: }
1232:
1233: /* Add HII packages */
1234: if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
1235: snpdev->handle,
1236: &snpdev->hii_handle ) ) != 0 ) {
1237: DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
1238: snpdev, efi_strerror ( efirc ) );
1239: rc = EFIRC_TO_RC ( efirc );
1240: goto err_register_hii;
1241: }
1242:
1243: /* Add to list of SNP devices */
1244: list_add ( &snpdev->list, &efi_snp_devices );
1245:
1246: DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
1247: snpdev, netdev->name, snpdev->handle );
1248: return 0;
1249:
1250: efihii->RemovePackageList ( efihii, snpdev->hii_handle );
1251: err_register_hii:
1252: free ( snpdev->package_list );
1253: err_create_hii:
1254: efipci_child_del ( efipci, snpdev->handle );
1255: err_efipci_child_add:
1256: bs->UninstallMultipleProtocolInterfaces (
1257: snpdev->handle,
1258: &efi_simple_network_protocol_guid, &snpdev->snp,
1259: &efi_device_path_protocol_guid, &snpdev->path,
1260: &efi_nii_protocol_guid, &snpdev->nii,
1261: &efi_nii31_protocol_guid, &snpdev->nii,
1262: &efi_hii_config_access_protocol_guid, &snpdev->hii,
1263: NULL );
1264: err_install_protocol_interface:
1265: bs->CloseEvent ( snpdev->snp.WaitForPacket );
1266: err_create_event:
1267: err_ll_addr_len:
1268: netdev_put ( netdev );
1269: free ( snpdev );
1270: err_alloc_snp:
1271: err_no_pci:
1272: return rc;
1273: }
1274:
1275: /**
1276: * Handle SNP device or link state change
1277: *
1278: * @v netdev Network device
1279: */
1280: static void efi_snp_notify ( struct net_device *netdev __unused ) {
1281: /* Nothing to do */
1282: }
1283:
1284: /**
1285: * Destroy SNP device
1286: *
1287: * @v netdev Network device
1288: */
1289: static void efi_snp_remove ( struct net_device *netdev ) {
1290: EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
1291: struct efi_snp_device *snpdev;
1292:
1293: /* Locate SNP device */
1294: snpdev = efi_snp_demux ( netdev );
1295: if ( ! snpdev ) {
1296: DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
1297: return;
1298: }
1299:
1300: /* Uninstall the SNP */
1301: efihii->RemovePackageList ( efihii, snpdev->hii_handle );
1302: free ( snpdev->package_list );
1303: efipci_child_del ( snpdev->efipci, snpdev->handle );
1304: list_del ( &snpdev->list );
1305: bs->UninstallMultipleProtocolInterfaces (
1306: snpdev->handle,
1307: &efi_simple_network_protocol_guid, &snpdev->snp,
1308: &efi_device_path_protocol_guid, &snpdev->path,
1309: &efi_nii_protocol_guid, &snpdev->nii,
1310: &efi_nii31_protocol_guid, &snpdev->nii,
1311: &efi_hii_config_access_protocol_guid, &snpdev->hii,
1312: NULL );
1313: bs->CloseEvent ( snpdev->snp.WaitForPacket );
1314: netdev_put ( snpdev->netdev );
1315: free ( snpdev );
1316: }
1317:
1318: /** SNP driver */
1319: struct net_driver efi_snp_driver __net_driver = {
1320: .name = "SNP",
1321: .probe = efi_snp_probe,
1322: .notify = efi_snp_notify,
1323: .remove = efi_snp_remove,
1324: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.