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