[efi] Add the "snpnet" driver
[gpxe.git] / src / drivers / net / efi / snpnet.c
1 /*
2  * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <errno.h>
22 #include <string.h>
23 #include <gpxe/io.h>
24 #include <gpxe/iobuf.h>
25 #include <gpxe/netdevice.h>
26 #include <gpxe/if_ether.h>
27 #include <gpxe/ethernet.h>
28 #include <gpxe/efi/efi.h>
29 #include <gpxe/efi/Protocol/SimpleNetwork.h>
30 #include "snp.h"
31 #include "snpnet.h"
32
33 /** @file
34  *
35  * SNP network device driver
36  *
37  */
38
39 /** SNP net device structure */
40 struct snpnet_device {
41         /** The underlying simple network protocol */
42         EFI_SIMPLE_NETWORK_PROTOCOL *snp;
43
44         /** State that the SNP should be in after close */
45         UINT32 close_state;
46 };
47
48 /**
49  * Transmit packet
50  *
51  * @v netdev            Network device
52  * @v iobuf             I/O buffer
53  * @ret rc              Return status code
54  */
55 static int snpnet_transmit ( struct net_device *netdev,
56                              struct io_buffer *iobuf ) {
57         struct snpnet_device *snpnetdev = netdev->priv;
58         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
59         EFI_STATUS efirc;
60         size_t len = iob_len ( iobuf );
61
62         efirc = snp->Transmit ( snp, 0, len, iobuf->data, NULL, NULL, NULL );
63         return EFIRC_TO_RC ( efirc );
64 }
65
66 /**
67  * Find a I/O buffer on the list of outstanding Tx buffers and complete it.
68  *
69  * @v snpnetdev         SNP network device
70  * @v txbuf             Buffer address
71  */
72 static void snpnet_complete ( struct net_device *netdev, void *txbuf ) {
73         struct io_buffer *tmp;
74         struct io_buffer *iobuf;
75
76         list_for_each_entry_safe ( iobuf, tmp, &netdev->tx_queue, list ) {
77                 if ( iobuf->data == txbuf ) {
78                         netdev_tx_complete ( netdev, iobuf );
79                         break;
80                 }
81         }
82 }
83
84 /**
85  * Poll for received packets
86  *
87  * @v netdev            Network device
88  */
89 static void snpnet_poll ( struct net_device *netdev ) {
90         struct snpnet_device *snpnetdev = netdev->priv;
91         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
92         EFI_STATUS efirc;
93         struct io_buffer *iobuf = NULL;
94         UINTN len;
95         void *txbuf;
96
97         /* Process Tx completions */
98         while ( 1 ) {
99                 efirc = snp->GetStatus ( snp, NULL, &txbuf );
100                 if ( efirc ) {
101                         DBGC ( snp, "SNP %p could not get status %s\n", snp,
102                                efi_strerror ( efirc ) );
103                         break;
104                 }
105
106                 if ( txbuf == NULL )
107                         break;
108
109                 snpnet_complete ( netdev, txbuf );
110         }
111
112         /* Process received packets */
113         while ( 1 ) {
114                 /* The spec is not clear if the max packet size refers to the
115                  * payload or the entire packet including headers. The Receive
116                  * function needs a buffer large enough to contain the headers,
117                  * and potentially a 4-byte CRC and 4-byte VLAN tag (?), so add
118                  * some breathing room.
119                  */
120                 len = snp->Mode->MaxPacketSize + ETH_HLEN + 8;
121                 iobuf = alloc_iob ( len );
122                 if ( iobuf == NULL ) {
123                         netdev_rx_err ( netdev, NULL, -ENOMEM );
124                         break;
125                 }
126
127                 efirc = snp->Receive ( snp, NULL, &len, iobuf->data,
128                                        NULL, NULL, NULL );
129
130                 /* No packets left? */
131                 if ( efirc == EFI_NOT_READY ) {
132                         free_iob ( iobuf );
133                         break;
134                 }
135
136                 /* Other error? */
137                 if ( efirc ) {
138                         DBGC ( snp, "SNP %p receive packet error: %s "
139                                     "(len was %zd, is now %zd)\n",
140                                snp, efi_strerror ( efirc ), iob_len(iobuf),
141                                (size_t)len );
142                         netdev_rx_err ( netdev, iobuf, efirc );
143                         break;
144                 }
145
146                 /* Packet is valid, deliver it */
147                 iob_put ( iobuf, len );
148                 netdev_rx ( netdev, iob_disown ( iobuf ) );
149         }
150 }
151
152 /**
153  * Open NIC
154  *
155  * @v netdev            Net device
156  * @ret rc              Return status code
157  */
158 static int snpnet_open ( struct net_device *netdev ) {
159         struct snpnet_device *snpnetdev = netdev->priv;
160         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
161         EFI_STATUS efirc;
162         UINT32 enableFlags, disableFlags;
163
164         snpnetdev->close_state = snp->Mode->State;
165         if ( snp->Mode->State != EfiSimpleNetworkInitialized ) {
166                 efirc = snp->Initialize ( snp, 0, 0 );
167                 if ( efirc ) {
168                         DBGC ( snp, "SNP %p could not initialize: %s\n",
169                                snp, efi_strerror ( efirc ) );
170                         return EFIRC_TO_RC ( efirc );
171                 }
172         }
173
174         /* Use the default MAC address */
175         efirc = snp->StationAddress ( snp, FALSE,
176                                       (EFI_MAC_ADDRESS *)netdev->ll_addr );
177         if ( efirc ) {
178                 DBGC ( snp, "SNP %p could not reset station address: %s\n",
179                        snp, efi_strerror ( efirc ) );
180         }
181
182         /* Set up receive filters to receive unicast and broadcast packets
183          * always. Also, enable either promiscuous multicast (if possible) or
184          * promiscuous operation, in order to catch all multicast packets.
185          */
186         enableFlags = snp->Mode->ReceiveFilterMask &
187                       ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
188                         EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
189         disableFlags = snp->Mode->ReceiveFilterMask &
190                        ( EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
191                          EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
192                          EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST );
193         if ( snp->Mode->ReceiveFilterMask &
194              EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST ) {
195                 enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
196         } else if ( snp->Mode->ReceiveFilterMask &
197                     EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS ) {
198                 enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
199         }
200         disableFlags &= ~enableFlags;
201         efirc = snp->ReceiveFilters ( snp, enableFlags, disableFlags,
202                                       FALSE, 0, NULL );
203         if ( efirc ) {
204                 DBGC ( snp, "SNP %p could not set receive filters: %s\n",
205                        snp, efi_strerror ( efirc ) );
206         }
207
208         DBGC ( snp, "SNP %p opened\n", snp );
209         return 0;
210 }
211
212 /**
213  * Close NIC
214  *
215  * @v netdev            Net device
216  */
217 static void snpnet_close ( struct net_device *netdev ) {
218         struct snpnet_device *snpnetdev = netdev->priv;
219         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
220         EFI_STATUS efirc;
221
222         if ( snpnetdev->close_state != EfiSimpleNetworkInitialized ) {
223                 efirc = snp->Shutdown ( snp );
224                 if ( efirc ) {
225                         DBGC ( snp, "SNP %p could not shut down: %s\n",
226                                snp, efi_strerror ( efirc ) );
227                 }
228         }
229 }
230
231 /**
232  * Enable/disable interrupts
233  *
234  * @v netdev            Net device
235  * @v enable            Interrupts should be enabled
236  */
237 static void snpnet_irq ( struct net_device *netdev, int enable ) {
238         struct snpnet_device *snpnetdev = netdev->priv;
239         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
240
241         /* On EFI, interrupts are never necessary. (This function is only
242          * required for BIOS PXE.) If interrupts were required, they could be
243          * simulated using a fast timer.
244          */
245         DBGC ( snp, "SNP %p cannot %s interrupts\n",
246                snp, ( enable ? "enable" : "disable" ) );
247 }
248
249 /** SNP network device operations */
250 static struct net_device_operations snpnet_operations = {
251         .open           = snpnet_open,
252         .close          = snpnet_close,
253         .transmit       = snpnet_transmit,
254         .poll           = snpnet_poll,
255         .irq            = snpnet_irq,
256 };
257
258 /**
259  * Probe SNP device
260  *
261  * @v snpdev            SNP device
262  * @ret rc              Return status code
263  */
264 int snpnet_probe ( struct snp_device *snpdev ) {
265         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp;
266         EFI_STATUS efirc;
267         struct net_device *netdev;
268         struct snpnet_device *snpnetdev;
269         int rc;
270
271         DBGC ( snp, "SNP %p probing...\n", snp );
272
273         /* Allocate net device */
274         netdev = alloc_etherdev ( sizeof ( struct snpnet_device ) );
275         if ( ! netdev )
276                 return -ENOMEM;
277         netdev_init ( netdev, &snpnet_operations );
278         netdev->dev = &snpdev->dev;
279         snpdev->netdev = netdev;
280         snpnetdev = netdev->priv;
281         snpnetdev->snp = snp;
282         snpdev->removal_state = snp->Mode->State;
283
284         /* Start the interface */
285         if ( snp->Mode->State == EfiSimpleNetworkStopped ) {
286                 efirc = snp->Start ( snp );
287                 if ( efirc ) {
288                         DBGC ( snp, "SNP %p could not start: %s\n", snp,
289                                efi_strerror ( efirc ) );
290                         rc = EFIRC_TO_RC ( efirc );
291                         goto err_start;
292                 }
293         }
294
295         if ( snp->Mode->HwAddressSize > sizeof ( netdev->hw_addr ) ) {
296                 DBGC ( snp, "SNP %p hardware address is too large\n", snp );
297                 rc = -EINVAL;
298                 goto err_hwaddr;
299         }
300         memcpy ( netdev->hw_addr, snp->Mode->PermanentAddress.Addr,
301                  snp->Mode->HwAddressSize );
302
303         /* Mark as link up; we don't handle link state */
304         netdev_link_up ( netdev );
305
306         /* Register network device */
307         if ( ( rc = register_netdev ( netdev ) ) != 0 )
308                 goto err_register;
309
310         DBGC ( snp, "SNP %p added\n", snp );
311         return 0;
312
313 err_register:
314 err_hwaddr:
315         if ( snpdev->removal_state == EfiSimpleNetworkStopped )
316                 snp->Stop ( snp );
317
318 err_start:
319         netdev_nullify ( netdev );
320         netdev_put ( netdev );
321         snpdev->netdev = NULL;
322         return rc;
323 }
324
325 /**
326  * Remove SNP device
327  *
328  * @v snpdev            SNP device
329  */
330 void snpnet_remove ( struct snp_device *snpdev ) {
331         EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp;
332         EFI_STATUS efirc;
333         struct net_device *netdev = snpdev->netdev;
334
335         if ( snp->Mode->State == EfiSimpleNetworkInitialized &&
336              snpdev->removal_state != EfiSimpleNetworkInitialized ) {
337                 DBGC ( snp, "SNP %p shutting down\n", snp );
338                 efirc = snp->Shutdown ( snp );
339                 if ( efirc ) {
340                         DBGC ( snp, "SNP %p could not shut down: %s\n",
341                                snp, efi_strerror ( efirc ) );
342                 }
343         }
344
345         if ( snp->Mode->State == EfiSimpleNetworkStarted &&
346              snpdev->removal_state == EfiSimpleNetworkStopped ) {
347                 DBGC ( snp, "SNP %p stopping\n", snp );
348                 efirc = snp->Stop ( snp );
349                 if ( efirc ) {
350                         DBGC ( snp, "SNP %p could not be stopped\n", snp );
351                 }
352         }
353
354         /* Unregister net device */
355         unregister_netdev ( netdev );
356
357         /* Free network device */
358         netdev_nullify ( netdev );
359         netdev_put ( netdev );
360
361         DBGC ( snp, "SNP %p removed\n", snp );
362 }