8a67d61d |
1 | /** @file\r |
2 | Copyright (c) 2004 - 2005, Intel Corporation\r |
3 | All rights reserved. This program and the accompanying materials\r |
4 | are licensed and made available under the terms and conditions of the BSD License\r |
5 | which accompanies this distribution. The full text of the license may be found at\r |
6 | http://opensource.org/licenses/bsd-license.php\r |
7 | \r |
8 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
9 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
10 | \r |
11 | Module name:\r |
12 | snp.c\r |
13 | \r |
14 | Abstract:\r |
15 | \r |
16 | \r |
17 | **/\r |
18 | \r |
19 | #include "Snp.h"\r |
20 | \r |
21 | EFI_STATUS\r |
22 | pxe_start (\r |
23 | SNP_DRIVER *snp\r |
24 | );\r |
25 | EFI_STATUS\r |
26 | pxe_stop (\r |
27 | SNP_DRIVER *snp\r |
28 | );\r |
29 | EFI_STATUS\r |
30 | pxe_init (\r |
31 | SNP_DRIVER *snp,\r |
32 | UINT16 OpFlags\r |
33 | );\r |
34 | EFI_STATUS\r |
35 | pxe_shutdown (\r |
36 | SNP_DRIVER *snp\r |
37 | );\r |
38 | EFI_STATUS\r |
39 | pxe_get_stn_addr (\r |
40 | SNP_DRIVER *snp\r |
41 | );\r |
42 | \r |
43 | EFI_STATUS\r |
44 | EFIAPI\r |
45 | InitializeSnpNiiDriver (\r |
46 | IN EFI_HANDLE image_handle,\r |
47 | IN EFI_SYSTEM_TABLE *system_table\r |
48 | );\r |
49 | \r |
50 | EFI_STATUS\r |
51 | EFIAPI\r |
52 | SimpleNetworkDriverSupported (\r |
53 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
54 | IN EFI_HANDLE Controller,\r |
55 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
56 | );\r |
57 | \r |
58 | EFI_STATUS\r |
59 | EFIAPI\r |
60 | SimpleNetworkDriverStart (\r |
61 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
62 | IN EFI_HANDLE Controller,\r |
63 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
64 | );\r |
65 | \r |
66 | EFI_STATUS\r |
67 | EFIAPI\r |
68 | SimpleNetworkDriverStop (\r |
69 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
70 | IN EFI_HANDLE Controller,\r |
71 | IN UINTN NumberOfChildren,\r |
72 | IN EFI_HANDLE *ChildHandleBuffer\r |
73 | );\r |
74 | \r |
75 | //\r |
76 | // Simple Network Protocol Driver Global Variables\r |
77 | //\r |
78 | EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {\r |
79 | SimpleNetworkDriverSupported,\r |
80 | SimpleNetworkDriverStart,\r |
81 | SimpleNetworkDriverStop,\r |
82 | 0xa,\r |
83 | NULL,\r |
84 | NULL\r |
85 | };\r |
86 | \r |
87 | //\r |
88 | // Module global variables needed to support undi 3.0 interface\r |
89 | //\r |
90 | EFI_PCI_IO_PROTOCOL *mPciIoFncs;\r |
91 | struct s_v2p *_v2p = NULL; // undi3.0 map_list head\r |
92 | // End Global variables\r |
93 | //\r |
94 | \r |
95 | /**\r |
96 | This routine maps the given CPU address to a Device address. It creates a\r |
97 | an entry in the map list with the virtual and physical addresses and the\r |
98 | un map cookie.\r |
99 | \r |
100 | @param v2p pointer to return a map list node pointer.\r |
101 | @param type the direction in which the data flows from the given\r |
102 | virtual address device->cpu or cpu->device or both\r |
103 | ways.\r |
104 | @param vaddr virtual address (or CPU address) to be mapped\r |
105 | @param bsize size of the buffer to be mapped.\r |
106 | \r |
107 | @retval EFI_SUCEESS routine has completed the mapping\r |
108 | @retval other error as indicated.\r |
109 | \r |
110 | **/\r |
111 | EFI_STATUS\r |
112 | add_v2p (\r |
113 | IN OUT struct s_v2p **v2p,\r |
114 | EFI_PCI_IO_PROTOCOL_OPERATION type,\r |
115 | VOID *vaddr,\r |
116 | UINTN bsize\r |
117 | )\r |
118 | {\r |
119 | EFI_STATUS Status;\r |
120 | \r |
121 | if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) {\r |
122 | return EFI_INVALID_PARAMETER;\r |
123 | }\r |
124 | \r |
125 | *v2p = AllocatePool (sizeof (struct s_v2p));\r |
126 | if (*v2p != NULL) {\r |
127 | return EFI_OUT_OF_RESOURCES;\r |
128 | }\r |
129 | \r |
130 | Status = mPciIoFncs->Map (\r |
131 | mPciIoFncs,\r |
132 | type,\r |
133 | vaddr,\r |
134 | &bsize,\r |
135 | &(*v2p)->paddr,\r |
136 | &(*v2p)->unmap\r |
137 | );\r |
138 | if (Status != EFI_SUCCESS) {\r |
139 | FreePool (*v2p);\r |
140 | return Status;\r |
141 | }\r |
142 | (*v2p)->vaddr = vaddr;\r |
143 | (*v2p)->bsize = bsize;\r |
144 | (*v2p)->next = _v2p;\r |
145 | _v2p = *v2p;\r |
146 | \r |
147 | return EFI_SUCCESS;\r |
148 | }\r |
149 | \r |
150 | \r |
151 | /**\r |
152 | This routine searches the linked list of mapped address nodes (for undi3.0\r |
153 | interface) to find the node that corresponds to the given virtual address and\r |
154 | returns a pointer to that node.\r |
155 | \r |
156 | @param v2p pointer to return a map list node pointer.\r |
157 | @param vaddr virtual address (or CPU address) to be searched in\r |
158 | the map list\r |
159 | \r |
160 | @retval EFI_SUCEESS if a match found!\r |
161 | @retval Other match not found\r |
162 | \r |
163 | **/\r |
164 | EFI_STATUS\r |
165 | find_v2p (\r |
166 | struct s_v2p **v2p,\r |
167 | VOID *vaddr\r |
168 | )\r |
169 | {\r |
170 | struct s_v2p *v;\r |
171 | \r |
172 | if (v2p == NULL || vaddr == NULL) {\r |
173 | return EFI_INVALID_PARAMETER;\r |
174 | }\r |
175 | \r |
176 | for (v = _v2p; v != NULL; v = v->next) {\r |
177 | if (v->vaddr == vaddr) {\r |
178 | *v2p = v;\r |
179 | return EFI_SUCCESS;\r |
180 | }\r |
181 | }\r |
182 | \r |
183 | return EFI_NOT_FOUND;\r |
184 | }\r |
185 | \r |
186 | \r |
187 | /**\r |
188 | This routine unmaps the given virtual address and frees the memory allocated\r |
189 | for the map list node corresponding to that address.\r |
190 | \r |
191 | @param vaddr virtual address (or CPU address) to be unmapped\r |
192 | \r |
193 | @retval EFI_SUCEESS if successfully unmapped\r |
194 | @retval Other as indicated by the error\r |
195 | \r |
196 | **/\r |
197 | EFI_STATUS\r |
198 | del_v2p (\r |
199 | VOID *vaddr\r |
200 | )\r |
201 | {\r |
202 | struct s_v2p *v;\r |
203 | struct s_v2p *t;\r |
204 | EFI_STATUS Status;\r |
205 | \r |
206 | if (vaddr == NULL) {\r |
207 | return EFI_INVALID_PARAMETER;\r |
208 | }\r |
209 | \r |
210 | if (_v2p == NULL) {\r |
211 | return EFI_NOT_FOUND;\r |
212 | }\r |
213 | //\r |
214 | // Is our node at the head of the list??\r |
215 | //\r |
216 | if ((v = _v2p)->vaddr == vaddr) {\r |
217 | _v2p = _v2p->next;\r |
218 | \r |
219 | Status = mPciIoFncs->Unmap (mPciIoFncs, v->unmap);\r |
220 | \r |
221 | FreePool (v);\r |
222 | \r |
223 | if (Status) {\r |
224 | DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));\r |
225 | }\r |
226 | return Status;\r |
227 | }\r |
228 | \r |
229 | for (; v->next != NULL; v = t) {\r |
230 | if ((t = v->next)->vaddr == vaddr) {\r |
231 | v->next = t->next;\r |
232 | Status = mPciIoFncs->Unmap (mPciIoFncs, t->unmap);\r |
233 | FreePool (t);\r |
234 | \r |
235 | if (Status) {\r |
236 | DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));\r |
237 | }\r |
238 | return Status;\r |
239 | }\r |
240 | }\r |
241 | \r |
242 | return EFI_NOT_FOUND;\r |
243 | }\r |
244 | \r |
245 | STATIC\r |
246 | EFI_STATUS\r |
247 | issue_hwundi_command (\r |
248 | UINT64 cdb\r |
249 | )\r |
250 | /*++\r |
251 | \r |
252 | Routine Description:\r |
253 | \r |
254 | Arguments:\r |
255 | \r |
256 | Returns:\r |
257 | \r |
258 | --*/\r |
259 | {\r |
260 | DEBUG ((EFI_D_ERROR, "\nissue_hwundi_command() - This should not be called!"));\r |
261 | \r |
262 | if (cdb == 0) {\r |
263 | return EFI_INVALID_PARAMETER;\r |
264 | \r |
265 | }\r |
266 | //\r |
267 | // %%TBD - For now, nothing is done.\r |
268 | //\r |
269 | return EFI_UNSUPPORTED;\r |
270 | }\r |
271 | \r |
272 | \r |
273 | /**\r |
274 | Compute 8-bit checksum of a buffer.\r |
275 | \r |
276 | @param ptr Pointer to buffer.\r |
277 | @param len Length of buffer in bytes.\r |
278 | \r |
279 | @return 8-bit checksum of all bytes in buffer.\r |
280 | @return If ptr is NULL or len is zero, zero is returned.\r |
281 | \r |
282 | **/\r |
283 | STATIC\r |
284 | UINT8\r |
285 | calc_8bit_cksum (\r |
286 | VOID *ptr,\r |
287 | UINTN len\r |
288 | )\r |
289 | {\r |
290 | UINT8 *bptr;\r |
291 | UINT8 cksum;\r |
292 | \r |
293 | bptr = ptr;\r |
294 | cksum = 0;\r |
295 | \r |
296 | if (ptr == NULL || len == 0) {\r |
297 | return 0;\r |
298 | }\r |
299 | \r |
300 | while (len--) {\r |
301 | cksum = (UINT8) (cksum +*bptr++);\r |
302 | }\r |
303 | \r |
304 | return cksum;\r |
305 | }\r |
306 | \r |
307 | \r |
308 | /**\r |
309 | Test to see if this driver supports Controller. Any Controller\r |
310 | that contains a Nii protocol can be supported.\r |
311 | \r |
312 | @param This Protocol instance pointer.\r |
313 | @param Controller Handle of device to test.\r |
314 | @param RemainingDevicePath Not used.\r |
315 | \r |
316 | @retval EFI_SUCCESS This driver supports this device.\r |
317 | @retval EFI_ALREADY_STARTED This driver is already running on this device.\r |
318 | @retval other This driver does not support this device.\r |
319 | \r |
320 | **/\r |
321 | EFI_STATUS\r |
322 | EFIAPI\r |
323 | SimpleNetworkDriverSupported (\r |
324 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
325 | IN EFI_HANDLE Controller,\r |
326 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
327 | )\r |
328 | {\r |
329 | EFI_STATUS Status;\r |
330 | EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r |
331 | PXE_UNDI *pxe;\r |
8a67d61d |
332 | \r |
8a67d61d |
333 | Status = gBS->OpenProtocol (\r |
334 | Controller,\r |
335 | &gEfiDevicePathProtocolGuid,\r |
336 | NULL,\r |
337 | This->DriverBindingHandle,\r |
338 | Controller,\r |
339 | EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r |
340 | );\r |
341 | if (EFI_ERROR (Status)) {\r |
342 | return Status;\r |
343 | }\r |
344 | \r |
345 | Status = gBS->OpenProtocol (\r |
346 | Controller,\r |
347 | &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r |
348 | (VOID **) &NiiProtocol,\r |
349 | This->DriverBindingHandle,\r |
350 | Controller,\r |
351 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
352 | );\r |
8a67d61d |
353 | \r |
41057d77 |
354 | if (EFI_ERROR (Status)) {\r |
355 | if (Status == EFI_ALREADY_STARTED) {\r |
356 | DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %x\n", Controller));\r |
8a67d61d |
357 | }\r |
41057d77 |
358 | return Status;\r |
8a67d61d |
359 | }\r |
41057d77 |
360 | \r |
361 | DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %x\n", Controller));\r |
362 | \r |
8a67d61d |
363 | //\r |
364 | // check the version, we don't want to connect to the undi16\r |
365 | //\r |
366 | if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r |
367 | Status = EFI_UNSUPPORTED;\r |
368 | goto Done;\r |
369 | }\r |
370 | //\r |
371 | // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r |
372 | //\r |
373 | if (NiiProtocol->ID & 0x0F) {\r |
374 | DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r |
375 | Status = EFI_UNSUPPORTED;\r |
376 | goto Done;\r |
377 | }\r |
378 | \r |
379 | pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);\r |
380 | \r |
381 | //\r |
382 | // Verify !PXE revisions.\r |
383 | //\r |
384 | if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r |
385 | DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r |
386 | Status = EFI_UNSUPPORTED;\r |
387 | goto Done;\r |
388 | }\r |
389 | \r |
390 | if (pxe->hw.Rev < PXE_ROMID_REV) {\r |
391 | DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r |
392 | Status = EFI_UNSUPPORTED;\r |
393 | goto Done;\r |
394 | }\r |
395 | \r |
396 | if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r |
397 | \r |
398 | DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r |
399 | Status = EFI_UNSUPPORTED;\r |
400 | goto Done;\r |
401 | \r |
402 | } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r |
403 | DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r |
404 | Status = EFI_UNSUPPORTED;\r |
405 | goto Done;\r |
406 | }\r |
407 | //\r |
408 | // Do S/W UNDI specific checks.\r |
409 | //\r |
410 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r |
411 | if (pxe->sw.EntryPoint < pxe->sw.Len) {\r |
412 | DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r |
413 | Status = EFI_UNSUPPORTED;\r |
414 | goto Done;\r |
415 | }\r |
416 | \r |
417 | if (pxe->sw.BusCnt == 0) {\r |
418 | DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r |
419 | Status = EFI_UNSUPPORTED;\r |
420 | goto Done;\r |
421 | }\r |
422 | }\r |
423 | \r |
424 | Status = EFI_SUCCESS;\r |
425 | DEBUG ((EFI_D_INFO, "Support(): supported on %x\n", Controller));\r |
426 | \r |
427 | Done:\r |
41057d77 |
428 | gBS->CloseProtocol (\r |
429 | Controller,\r |
430 | &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r |
431 | This->DriverBindingHandle,\r |
432 | Controller\r |
433 | );\r |
8a67d61d |
434 | \r |
435 | return Status;\r |
436 | }\r |
437 | \r |
438 | \r |
439 | /**\r |
440 | called for any handle that we said "supported" in the above call!\r |
441 | \r |
442 | @param This Protocol instance pointer.\r |
443 | @param Controller Handle of device to start\r |
444 | @param RemainingDevicePath Not used.\r |
445 | \r |
446 | @retval EFI_SUCCESS This driver supports this device.\r |
447 | @retval other This driver failed to start this device.\r |
448 | \r |
449 | **/\r |
450 | EFI_STATUS\r |
451 | EFIAPI\r |
452 | SimpleNetworkDriverStart (\r |
453 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
454 | IN EFI_HANDLE Controller,\r |
455 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r |
456 | )\r |
457 | {\r |
458 | EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r |
459 | EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;\r |
460 | EFI_STATUS Status;\r |
461 | PXE_UNDI *pxe;\r |
462 | SNP_DRIVER *snp;\r |
463 | VOID *addr;\r |
8a67d61d |
464 | EFI_HANDLE Handle;\r |
8a67d61d |
465 | PXE_PCI_CONFIG_INFO ConfigInfo;\r |
466 | PCI_TYPE00 *ConfigHeader;\r |
467 | UINT32 *TempBar;\r |
468 | UINT8 BarIndex;\r |
469 | PXE_STATFLAGS InitStatFlags;\r |
470 | \r |
471 | DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));\r |
472 | \r |
473 | Status = gBS->OpenProtocol (\r |
474 | Controller,\r |
475 | &gEfiDevicePathProtocolGuid,\r |
476 | (VOID **) &NiiDevicePath,\r |
477 | This->DriverBindingHandle,\r |
478 | Controller,\r |
479 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
480 | );\r |
481 | \r |
482 | if (EFI_ERROR (Status)) {\r |
483 | return Status;\r |
484 | }\r |
485 | \r |
486 | Status = gBS->LocateDevicePath (\r |
487 | &gEfiPciIoProtocolGuid,\r |
488 | &NiiDevicePath,\r |
489 | &Handle\r |
490 | );\r |
491 | \r |
492 | if (EFI_ERROR (Status)) {\r |
493 | return Status;\r |
494 | }\r |
495 | \r |
496 | Status = gBS->OpenProtocol (\r |
497 | Handle,\r |
498 | &gEfiPciIoProtocolGuid,\r |
499 | (VOID **) &mPciIoFncs,\r |
500 | This->DriverBindingHandle,\r |
501 | Controller,\r |
502 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r |
503 | );\r |
504 | if (EFI_ERROR (Status)) {\r |
505 | return Status;\r |
506 | }\r |
507 | //\r |
41057d77 |
508 | // Get the NII interface.\r |
8a67d61d |
509 | //\r |
510 | Status = gBS->OpenProtocol (\r |
511 | Controller,\r |
512 | &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r |
513 | (VOID **) &Nii,\r |
514 | This->DriverBindingHandle,\r |
515 | Controller,\r |
516 | EFI_OPEN_PROTOCOL_BY_DRIVER\r |
517 | );\r |
41057d77 |
518 | if (EFI_ERROR (Status)) {\r |
8a67d61d |
519 | gBS->CloseProtocol (\r |
520 | Controller,\r |
521 | &gEfiDevicePathProtocolGuid,\r |
522 | This->DriverBindingHandle,\r |
523 | Controller\r |
524 | );\r |
525 | return Status;\r |
526 | }\r |
527 | \r |
41057d77 |
528 | DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r |
8a67d61d |
529 | \r |
530 | pxe = (PXE_UNDI *) (UINTN) (Nii->ID);\r |
531 | \r |
532 | if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {\r |
533 | DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r |
534 | goto NiiError;\r |
535 | }\r |
536 | \r |
537 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r |
538 | //\r |
539 | // We can get any packets.\r |
540 | //\r |
541 | } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r |
542 | //\r |
543 | // We need to be able to get broadcast packets for DHCP.\r |
544 | // If we do not have promiscuous support, we must at least have\r |
545 | // broadcast support or we cannot do DHCP!\r |
546 | //\r |
547 | } else {\r |
548 | DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r |
549 | goto NiiError;\r |
550 | }\r |
551 | //\r |
552 | // OK, we like this UNDI, and we know snp is not already there on this handle\r |
553 | // Allocate and initialize a new simple network protocol structure.\r |
554 | //\r |
555 | Status = mPciIoFncs->AllocateBuffer (\r |
556 | mPciIoFncs,\r |
557 | AllocateAnyPages,\r |
558 | EfiBootServicesData,\r |
559 | SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r |
560 | &addr,\r |
561 | 0\r |
562 | );\r |
563 | \r |
564 | if (Status != EFI_SUCCESS) {\r |
565 | DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r |
566 | goto NiiError;\r |
567 | }\r |
568 | \r |
569 | snp = (SNP_DRIVER *) (UINTN) addr;\r |
570 | \r |
8a67d61d |
571 | ZeroMem (snp, sizeof (SNP_DRIVER));\r |
572 | \r |
573 | snp->IoFncs = mPciIoFncs;\r |
8a67d61d |
574 | snp->Signature = SNP_DRIVER_SIGNATURE;\r |
575 | \r |
576 | EfiInitializeLock (&snp->lock, TPL_NOTIFY);\r |
577 | \r |
578 | snp->snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r |
579 | snp->snp.Start = snp_undi32_start;\r |
580 | snp->snp.Stop = snp_undi32_stop;\r |
581 | snp->snp.Initialize = snp_undi32_initialize;\r |
582 | snp->snp.Reset = snp_undi32_reset;\r |
583 | snp->snp.Shutdown = snp_undi32_shutdown;\r |
584 | snp->snp.ReceiveFilters = snp_undi32_receive_filters;\r |
585 | snp->snp.StationAddress = snp_undi32_station_address;\r |
586 | snp->snp.Statistics = snp_undi32_statistics;\r |
587 | snp->snp.MCastIpToMac = snp_undi32_mcast_ip_to_mac;\r |
588 | snp->snp.NvData = snp_undi32_nvdata;\r |
589 | snp->snp.GetStatus = snp_undi32_get_status;\r |
590 | snp->snp.Transmit = snp_undi32_transmit;\r |
591 | snp->snp.Receive = snp_undi32_receive;\r |
592 | snp->snp.WaitForPacket = NULL;\r |
593 | \r |
594 | snp->snp.Mode = &snp->mode;\r |
595 | \r |
596 | snp->tx_rx_bufsize = 0;\r |
597 | snp->tx_rx_buffer = NULL;\r |
598 | \r |
599 | snp->if_num = Nii->IfNum;\r |
600 | \r |
601 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r |
602 | snp->is_swundi = FALSE;\r |
603 | snp->issue_undi32_command = &issue_hwundi_command;\r |
604 | } else {\r |
605 | snp->is_swundi = TRUE;\r |
606 | \r |
607 | if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r |
608 | snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;\r |
609 | } else {\r |
610 | snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);\r |
611 | }\r |
612 | }\r |
613 | //\r |
614 | // Allocate a global CPB and DB buffer for this UNDI interface.\r |
615 | // we do this because:\r |
616 | //\r |
617 | // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r |
618 | // within 2GB limit, create them here and map them so that when undi calls\r |
619 | // v2p callback to check if the physical address is < 2gb, we will pass.\r |
620 | //\r |
621 | // -This is not a requirement for 3.1 or later UNDIs but the code looks\r |
622 | // simpler if we use the same cpb, db variables for both old and new undi\r |
623 | // interfaces from all the SNP interface calls (we don't map the buffers\r |
624 | // for the newer undi interfaces though)\r |
625 | // .\r |
626 | // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r |
627 | // interface as EFI does not multi-task and so SNP will not be re-entered!\r |
628 | //\r |
629 | Status = mPciIoFncs->AllocateBuffer (\r |
630 | mPciIoFncs,\r |
631 | AllocateAnyPages,\r |
632 | EfiBootServicesData,\r |
633 | SNP_MEM_PAGES (4096),\r |
634 | &addr,\r |
635 | 0\r |
636 | );\r |
637 | \r |
638 | if (Status != EFI_SUCCESS) {\r |
639 | DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r |
640 | goto Error_DeleteSNP;\r |
641 | }\r |
642 | \r |
41057d77 |
643 | snp->cpb = (VOID *) (UINTN) addr;\r |
644 | snp->db = (VOID *) ((UINTN) addr + 2048);\r |
8a67d61d |
645 | \r |
8a67d61d |
646 | //\r |
647 | // pxe_start call is going to give the callback functions to UNDI, these callback\r |
648 | // functions use the BarIndex values from the snp structure, so these must be initialized\r |
649 | // with default values before doing a pxe_start. The correct values can be obtained after\r |
650 | // getting the config information from UNDI\r |
651 | //\r |
652 | snp->MemoryBarIndex = 0;\r |
653 | snp->IoBarIndex = 1;\r |
654 | \r |
655 | //\r |
656 | // we need the undi init information many times in this snp code, just get it\r |
657 | // once here and store it in the snp driver structure. to get Init Info\r |
658 | // from UNDI we have to start undi first.\r |
659 | //\r |
660 | Status = pxe_start (snp);\r |
661 | \r |
662 | if (Status != EFI_SUCCESS) {\r |
41057d77 |
663 | goto Error_DeleteSNP;\r |
8a67d61d |
664 | }\r |
665 | \r |
666 | snp->cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;\r |
667 | snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r |
668 | \r |
669 | snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r |
670 | snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r |
671 | \r |
672 | snp->cdb.DBsize = sizeof snp->init_info;\r |
673 | snp->cdb.DBaddr = (UINT64)(UINTN) &snp->init_info;\r |
674 | \r |
675 | snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r |
676 | snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r |
677 | \r |
678 | snp->cdb.IFnum = snp->if_num;\r |
679 | snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r |
680 | \r |
681 | DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info() "));\r |
682 | \r |
683 | (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r |
684 | \r |
685 | //\r |
686 | // Save the INIT Stat Code...\r |
687 | //\r |
688 | InitStatFlags = snp->cdb.StatFlags;\r |
689 | \r |
690 | if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r |
691 | DEBUG ((EFI_D_NET, "\nsnp->undi.init_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r |
692 | pxe_stop (snp);\r |
41057d77 |
693 | goto Error_DeleteSNP;\r |
8a67d61d |
694 | }\r |
695 | \r |
696 | snp->cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;\r |
697 | snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r |
698 | \r |
699 | snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r |
700 | snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r |
701 | \r |
702 | snp->cdb.DBsize = sizeof ConfigInfo;\r |
703 | snp->cdb.DBaddr = (UINT64)(UINTN) &ConfigInfo;\r |
704 | \r |
705 | snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r |
706 | snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r |
707 | \r |
708 | snp->cdb.IFnum = snp->if_num;\r |
709 | snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r |
710 | \r |
711 | DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info() "));\r |
712 | \r |
713 | (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r |
714 | \r |
715 | if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r |
716 | DEBUG ((EFI_D_NET, "\nsnp->undi.config_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r |
717 | pxe_stop (snp);\r |
41057d77 |
718 | goto Error_DeleteSNP;\r |
8a67d61d |
719 | }\r |
720 | //\r |
721 | // Find the correct BAR to do IO.\r |
722 | //\r |
723 | //\r |
724 | // Enumerate through the PCI BARs for the device to determine which one is\r |
725 | // the IO BAR. Save the index of the BAR into the adapter info structure.\r |
726 | // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r |
727 | //\r |
728 | ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r |
729 | TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];\r |
730 | for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r |
731 | if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r |
732 | //\r |
733 | // This is a 64-bit memory bar, skip this and the\r |
734 | // next bar as well.\r |
735 | //\r |
736 | TempBar++;\r |
737 | }\r |
738 | \r |
739 | if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r |
740 | snp->IoBarIndex = BarIndex;\r |
741 | break;\r |
742 | }\r |
743 | \r |
744 | TempBar++;\r |
745 | }\r |
746 | \r |
8a67d61d |
747 | //\r |
748 | // Initialize simple network protocol mode structure\r |
749 | //\r |
750 | snp->mode.State = EfiSimpleNetworkStopped;\r |
751 | snp->mode.HwAddressSize = snp->init_info.HWaddrLen;\r |
752 | snp->mode.MediaHeaderSize = snp->init_info.MediaHeaderLen;\r |
753 | snp->mode.MaxPacketSize = snp->init_info.FrameDataLen;\r |
754 | snp->mode.NvRamAccessSize = snp->init_info.NvWidth;\r |
755 | snp->mode.NvRamSize = snp->init_info.NvCount * snp->mode.NvRamAccessSize;\r |
756 | snp->mode.IfType = snp->init_info.IFtype;\r |
757 | snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;\r |
758 | snp->mode.MCastFilterCount = 0;\r |
759 | \r |
760 | switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r |
761 | case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r |
762 | snp->mode.MediaPresentSupported = TRUE;\r |
763 | break;\r |
764 | \r |
765 | case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r |
766 | default:\r |
767 | snp->mode.MediaPresentSupported = FALSE;\r |
768 | }\r |
769 | \r |
770 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r |
771 | snp->mode.MacAddressChangeable = TRUE;\r |
772 | } else {\r |
773 | snp->mode.MacAddressChangeable = FALSE;\r |
774 | }\r |
775 | \r |
776 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r |
777 | snp->mode.MultipleTxSupported = TRUE;\r |
778 | } else {\r |
779 | snp->mode.MultipleTxSupported = FALSE;\r |
780 | }\r |
781 | \r |
782 | snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r |
783 | \r |
784 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r |
785 | snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r |
786 | \r |
787 | }\r |
788 | \r |
789 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r |
790 | snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r |
791 | \r |
792 | }\r |
793 | \r |
794 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r |
795 | snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r |
796 | \r |
797 | }\r |
798 | \r |
799 | if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r |
800 | snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r |
801 | \r |
802 | }\r |
803 | \r |
804 | if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {\r |
805 | snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r |
806 | \r |
807 | }\r |
808 | \r |
809 | snp->mode.ReceiveFilterSetting = 0;\r |
810 | \r |
811 | //\r |
812 | // need to get the station address to save in the mode structure. we need to\r |
813 | // initialize the UNDI first for this.\r |
814 | //\r |
815 | snp->tx_rx_bufsize = snp->init_info.MemoryRequired;\r |
816 | Status = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r |
817 | \r |
818 | if (Status) {\r |
819 | pxe_stop (snp);\r |
41057d77 |
820 | goto Error_DeleteSNP;\r |
8a67d61d |
821 | }\r |
822 | \r |
823 | Status = pxe_get_stn_addr (snp);\r |
824 | \r |
825 | if (Status != EFI_SUCCESS) {\r |
826 | DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr() failed.\n"));\r |
827 | pxe_shutdown (snp);\r |
828 | pxe_stop (snp);\r |
41057d77 |
829 | goto Error_DeleteSNP;\r |
8a67d61d |
830 | }\r |
831 | \r |
832 | snp->mode.MediaPresent = FALSE;\r |
833 | \r |
834 | //\r |
835 | // We should not leave UNDI started and initialized here. this DriverStart()\r |
836 | // routine must only find and attach the SNP interface to UNDI layer that it\r |
837 | // finds on the given handle!\r |
838 | // The UNDI layer will be started when upper layers call snp->start.\r |
839 | // How ever, this DriverStart() must fill up the snp mode structure which\r |
840 | // contains the MAC address of the NIC. For this reason we started and\r |
841 | // initialized UNDI here, now we are done, do a shutdown and stop of the\r |
842 | // UNDI interface!\r |
843 | //\r |
844 | pxe_shutdown (snp);\r |
845 | pxe_stop (snp);\r |
846 | \r |
847 | //\r |
848 | // add SNP to the undi handle\r |
849 | //\r |
850 | Status = gBS->InstallProtocolInterface (\r |
851 | &Controller,\r |
852 | &gEfiSimpleNetworkProtocolGuid,\r |
853 | EFI_NATIVE_INTERFACE,\r |
854 | &(snp->snp)\r |
855 | );\r |
856 | \r |
857 | if (!EFI_ERROR (Status)) {\r |
858 | return Status;\r |
859 | }\r |
860 | \r |
8a67d61d |
861 | Status = mPciIoFncs->FreeBuffer (\r |
862 | mPciIoFncs,\r |
863 | SNP_MEM_PAGES (4096),\r |
864 | snp->cpb\r |
865 | );\r |
866 | \r |
867 | Error_DeleteSNP:\r |
8a67d61d |
868 | \r |
869 | mPciIoFncs->FreeBuffer (\r |
870 | mPciIoFncs,\r |
871 | SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r |
872 | snp\r |
873 | );\r |
874 | NiiError:\r |
41057d77 |
875 | gBS->CloseProtocol (\r |
876 | Controller,\r |
877 | &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r |
878 | This->DriverBindingHandle,\r |
879 | Controller\r |
880 | );\r |
8a67d61d |
881 | \r |
882 | gBS->CloseProtocol (\r |
883 | Controller,\r |
884 | &gEfiDevicePathProtocolGuid,\r |
885 | This->DriverBindingHandle,\r |
886 | Controller\r |
887 | );\r |
888 | \r |
889 | return Status;\r |
890 | }\r |
891 | \r |
892 | \r |
893 | /**\r |
894 | \r |
895 | \r |
896 | \r |
897 | **/\r |
898 | EFI_STATUS\r |
899 | EFIAPI\r |
900 | SimpleNetworkDriverStop (\r |
901 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r |
902 | IN EFI_HANDLE Controller,\r |
903 | IN UINTN NumberOfChildren,\r |
904 | IN EFI_HANDLE *ChildHandleBuffer\r |
905 | )\r |
906 | {\r |
907 | EFI_STATUS Status;\r |
908 | EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r |
909 | SNP_DRIVER *Snp;\r |
910 | \r |
911 | //\r |
912 | // Get our context back.\r |
913 | //\r |
914 | Status = gBS->OpenProtocol (\r |
915 | Controller,\r |
916 | &gEfiSimpleNetworkProtocolGuid,\r |
917 | (VOID **) &SnpProtocol,\r |
918 | This->DriverBindingHandle,\r |
919 | Controller,\r |
920 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r |
921 | );\r |
922 | \r |
923 | if (EFI_ERROR (Status)) {\r |
924 | return EFI_UNSUPPORTED;\r |
925 | }\r |
926 | \r |
927 | Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r |
928 | \r |
929 | Status = gBS->UninstallProtocolInterface (\r |
930 | Controller,\r |
931 | &gEfiSimpleNetworkProtocolGuid,\r |
932 | &Snp->snp\r |
933 | );\r |
934 | \r |
935 | if (EFI_ERROR (Status)) {\r |
936 | return Status;\r |
937 | }\r |
938 | \r |
41057d77 |
939 | Status = gBS->CloseProtocol (\r |
940 | Controller,\r |
941 | &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r |
942 | This->DriverBindingHandle,\r |
943 | Controller\r |
944 | );\r |
8a67d61d |
945 | \r |
946 | Status = gBS->CloseProtocol (\r |
947 | Controller,\r |
948 | &gEfiDevicePathProtocolGuid,\r |
949 | This->DriverBindingHandle,\r |
950 | Controller\r |
951 | );\r |
952 | \r |
953 | pxe_shutdown (Snp);\r |
954 | pxe_stop (Snp);\r |
955 | \r |
8a67d61d |
956 | mPciIoFncs->FreeBuffer (\r |
957 | mPciIoFncs,\r |
958 | SNP_MEM_PAGES (4096),\r |
959 | Snp->cpb\r |
960 | );\r |
961 | \r |
962 | mPciIoFncs->FreeBuffer (\r |
963 | mPciIoFncs,\r |
964 | SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r |
965 | Snp\r |
966 | );\r |
967 | \r |
968 | return Status;\r |
969 | }\r |
970 | \r |
971 | \r |
972 | /**\r |
973 | Install all the driver protocol\r |
974 | \r |
975 | @param entry EFI_IMAGE_ENTRY_POINT)\r |
976 | \r |
977 | @retval EFI_SUCEESS Initialization routine has found UNDI hardware,\r |
978 | loaded it's ROM, and installed a notify event for\r |
979 | the Network Indentifier Interface Protocol\r |
980 | successfully.\r |
981 | @retval Other Return value from HandleProtocol for\r |
982 | DeviceIoProtocol or LoadedImageProtocol\r |
983 | \r |
984 | **/\r |
985 | EFI_STATUS\r |
986 | EFIAPI\r |
987 | InitializeSnpNiiDriver (\r |
988 | IN EFI_HANDLE ImageHandle,\r |
989 | IN EFI_SYSTEM_TABLE *SystemTable\r |
990 | )\r |
991 | {\r |
83cbd279 |
992 | return EfiLibInstallDriverBindingComponentName2 (\r |
993 | ImageHandle,\r |
994 | SystemTable,\r |
995 | &mSimpleNetworkDriverBinding,\r |
996 | NULL,\r |
997 | &gSimpleNetworkComponentName,\r |
998 | &gSimpleNetworkComponentName2\r |
999 | );\r |
8a67d61d |
1000 | }\r |