Merge from vendor branch AWK:
[dragonfly.git] / sys / boot / efi / libefi / efinet.c
1 /*-
2  * Copyright (c) 2001 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/boot/efi/libefi/efinet.c,v 1.5 2002/07/20 03:52:18 peter Exp $
27  * $DragonFly: src/sys/boot/efi/libefi/efinet.c,v 1.1 2003/11/10 06:08:33 dillon Exp $
28  */
29
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33
34 #include <stand.h>
35 #include <net.h>
36 #include <netif.h>
37
38 #include <efi.h>
39 #include <efilib.h>
40
41 extern struct netif_driver efi_net;
42
43 #ifdef EFINET_DEBUG
44 static void
45 dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
46 {
47         int i;
48
49         printf("State                 = %x\n", mode->State);
50         printf("HwAddressSize         = %u\n", mode->HwAddressSize);
51         printf("MediaHeaderSize       = %u\n", mode->MediaHeaderSize);
52         printf("MaxPacketSize         = %u\n", mode->MaxPacketSize);
53         printf("NvRamSize             = %u\n", mode->NvRamSize);
54         printf("NvRamAccessSize       = %u\n", mode->NvRamAccessSize);
55         printf("ReceiveFilterMask     = %x\n", mode->ReceiveFilterMask);
56         printf("ReceiveFilterSetting  = %u\n", mode->ReceiveFilterSetting);
57         printf("MaxMCastFilterCount   = %u\n", mode->MaxMCastFilterCount);
58         printf("MCastFilterCount      = %u\n", mode->MCastFilterCount);
59         printf("MCastFilter           = {");
60         for (i = 0; i < mode->MCastFilterCount; i++)
61                 printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
62         printf(" }\n");
63         printf("CurrentAddress        = %s\n",
64             ether_sprintf(mode->CurrentAddress.Addr));
65         printf("BroadcastAddress      = %s\n",
66             ether_sprintf(mode->BroadcastAddress.Addr));
67         printf("PermanentAddress      = %s\n",
68             ether_sprintf(mode->PermanentAddress.Addr));
69         printf("IfType                = %u\n", mode->IfType);
70         printf("MacAddressChangeable  = %d\n", mode->MacAddressChangeable);
71         printf("MultipleTxSupported   = %d\n", mode->MultipleTxSupported);
72         printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
73         printf("MediaPresent          = %d\n", mode->MediaPresent);
74 }
75 #endif
76
77 int
78 efinet_match(struct netif *nif, void *machdep_hint)
79 {
80
81         return (1);
82 }
83
84 int
85 efinet_probe(struct netif *nif, void *machdep_hint)
86 {
87
88         return (0);
89 }
90
91 int
92 efinet_put(struct iodesc *desc, void *pkt, size_t len)
93 {
94         struct netif *nif = desc->io_netif;
95         EFI_SIMPLE_NETWORK *net;
96         EFI_STATUS status;
97         void *buf;
98
99         net = nif->nif_devdata;
100
101         status = net->Transmit(net, 0, len, pkt, 0, 0, 0);
102         if (status != EFI_SUCCESS)
103                 return -1;
104
105         /* Wait for the buffer to be transmitted */
106         do {
107                 buf = 0;        /* XXX Is this needed? */
108                 status = net->GetStatus(net, 0, &buf);
109                 /*
110                  * XXX EFI1.1 and the E1000 card returns a different 
111                  * address than we gave.  Sigh.
112                  */
113         } while (status == EFI_SUCCESS && buf == 0);
114
115         /* XXX How do we deal with status != EFI_SUCCESS now? */
116         return (status == EFI_SUCCESS) ? len : -1;
117 }
118
119
120 int
121 efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
122 {
123         struct netif *nif = desc->io_netif;
124         EFI_SIMPLE_NETWORK *net;
125         EFI_STATUS status;
126         UINTN bufsz;
127         time_t t;
128         char buf[2048];
129
130         net = nif->nif_devdata;
131
132         t = time(0);
133         while ((time(0) - t) < timeout) {
134                 bufsz = sizeof(buf);
135                 status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0);
136                 if (status == EFI_SUCCESS) {
137                         /*
138                          * XXX EFI1.1 and the E1000 card trash our
139                          * workspace if we do not do this silly copy.
140                          * Either they are not respecting the len
141                          * value or do not like the alignment.
142                          */
143                         if (bufsz > len)
144                                 bufsz = len;
145                         bcopy(buf, pkt, bufsz);
146                         return bufsz;
147                 }
148                 if (status != EFI_NOT_READY)
149                         return 0;
150         }
151
152         return 0;
153 }
154
155 void
156 efinet_init(struct iodesc *desc, void *machdep_hint)
157 {
158         struct netif *nif = desc->io_netif;
159         EFI_SIMPLE_NETWORK *net;
160         EFI_STATUS status;
161
162         net = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
163         nif->nif_devdata = net;
164
165         if (net->Mode->State == EfiSimpleNetworkStopped) {
166                 status = net->Start(net);
167                 if (status != EFI_SUCCESS) {
168                         printf("net%d: cannot start interface (status=%ld)\n",
169                             nif->nif_unit, status);
170                         return;
171                 }
172         }
173
174         if (net->Mode->State != EfiSimpleNetworkInitialized) {
175                 status = net->Initialize(net, 0, 0);
176                 if (status != EFI_SUCCESS) {
177                         printf("net%d: cannot init. interface (status=%ld)\n",
178                             nif->nif_unit, status);
179                         return;
180                 }
181         }
182
183         if (net->Mode->ReceiveFilterSetting == 0) {
184                 UINT32 mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
185                     EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
186
187                 status = net->ReceiveFilters(net, mask, 0, FALSE, 0, 0);
188                 if (status != EFI_SUCCESS) {
189                         printf("net%d: cannot set rx. filters (status=%ld)\n",
190                             nif->nif_unit, status);
191                         return;
192                 }
193         }
194
195 #ifdef EFINET_DEBUG
196         dump_mode(net->Mode);
197 #endif
198
199         bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
200         desc->xid = 1;
201
202         return;
203 }
204
205 void
206 efinet_init_driver()
207 {
208         EFI_STATUS      status;
209         UINTN           sz;
210         static EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
211         EFI_HANDLE      *handles;
212         int             nifs, i;
213 #define MAX_INTERFACES  4
214         static struct netif_dif difs[MAX_INTERFACES];
215         static struct netif_stats stats[MAX_INTERFACES];
216
217         sz = 0;
218         status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, 0);
219         if (status != EFI_BUFFER_TOO_SMALL)
220                 return;
221         handles = (EFI_HANDLE *) malloc(sz);
222         status = BS->LocateHandle(ByProtocol, &netid, 0, &sz, handles);
223         if (EFI_ERROR(status)) {
224                 free(handles);
225                 return;
226         }
227
228         nifs = sz / sizeof(EFI_HANDLE);
229         if (nifs > MAX_INTERFACES)
230                 nifs = MAX_INTERFACES;
231
232         efi_net.netif_nifs = nifs;
233         efi_net.netif_ifs = difs;
234
235         bzero(stats, sizeof(stats));
236         for (i = 0; i < nifs; i++) {
237                 struct netif_dif *dif = &efi_net.netif_ifs[i];
238                 dif->dif_unit = i;
239                 dif->dif_nsel = 1;
240                 dif->dif_stats = &stats[i];
241
242                 BS->HandleProtocol(handles[i], &netid,
243                                    (VOID**) &dif->dif_private);
244         }
245
246         return;
247 }
248
249 void
250 efinet_end(struct netif *nif)
251 {
252         EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
253
254         net->Shutdown(net);
255 }
256
257 struct netif_driver efi_net = {
258         "net",                  /* netif_bname */
259         efinet_match,           /* netif_match */
260         efinet_probe,           /* netif_probe */
261         efinet_init,            /* netif_init */
262         efinet_get,             /* netif_get */
263         efinet_put,             /* netif_put */
264         efinet_end,             /* netif_end */
265         0,                      /* netif_ifs */
266         0                       /* netif_nifs */
267 };
268