267dde67d58dc0e55f8f3e70932946b9ee8d1ce3
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Snp.c
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 = %r\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 = %r\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 EFI_STATUS\r
246 issue_hwundi_command (\r
247   UINT64 cdb\r
248   )\r
249 /*++\r
250 \r
251 Routine Description:\r
252 \r
253 Arguments:\r
254 \r
255 Returns:\r
256 \r
257 --*/\r
258 {\r
259   DEBUG ((EFI_D_ERROR, "\nissue_hwundi_command() - This should not be called!"));\r
260 \r
261   if (cdb == 0) {\r
262     return EFI_INVALID_PARAMETER;\r
263 \r
264   }\r
265   //\r
266   //  %%TBD - For now, nothing is done.\r
267   //\r
268   return EFI_UNSUPPORTED;\r
269 }\r
270 \r
271 \r
272 /**\r
273   Compute 8-bit checksum of a buffer.\r
274 \r
275   @param  ptr                  Pointer to buffer.\r
276   @param  len                  Length of buffer in bytes.\r
277 \r
278   @return 8-bit checksum of all bytes in buffer.\r
279   @return If ptr is NULL or len is zero, zero is returned.\r
280 \r
281 **/\r
282 UINT8\r
283 calc_8bit_cksum (\r
284   VOID  *ptr,\r
285   UINTN len\r
286   )\r
287 {\r
288   UINT8 *bptr;\r
289   UINT8 cksum;\r
290 \r
291   bptr  = ptr;\r
292   cksum = 0;\r
293 \r
294   if (ptr == NULL || len == 0) {\r
295     return 0;\r
296   }\r
297 \r
298   while (len--) {\r
299     cksum = (UINT8) (cksum +*bptr++);\r
300   }\r
301 \r
302   return cksum;\r
303 }\r
304 \r
305 \r
306 /**\r
307   Test to see if this driver supports Controller. Any Controller\r
308   that contains a Nii protocol can be supported.\r
309 \r
310   @param  This                 Protocol instance pointer.\r
311   @param  Controller           Handle of device to test.\r
312   @param  RemainingDevicePath  Not used.\r
313 \r
314   @retval EFI_SUCCESS          This driver supports this device.\r
315   @retval EFI_ALREADY_STARTED  This driver is already running on this device.\r
316   @retval other                This driver does not support this device.\r
317 \r
318 **/\r
319 EFI_STATUS\r
320 EFIAPI\r
321 SimpleNetworkDriverSupported (\r
322   IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
323   IN EFI_HANDLE                     Controller,\r
324   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
325   )\r
326 {\r
327   EFI_STATUS                                Status;\r
328   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r
329   PXE_UNDI                                  *pxe;\r
330 \r
331   Status = gBS->OpenProtocol (\r
332                   Controller,\r
333                   &gEfiDevicePathProtocolGuid,\r
334                   NULL,\r
335                   This->DriverBindingHandle,\r
336                   Controller,\r
337                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
338                   );\r
339   if (EFI_ERROR (Status)) {\r
340     return Status;\r
341   }\r
342 \r
343   Status = gBS->OpenProtocol (\r
344                   Controller,\r
345                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
346                   (VOID **) &NiiProtocol,\r
347                   This->DriverBindingHandle,\r
348                   Controller,\r
349                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
350                   );\r
351 \r
352   if (EFI_ERROR (Status)) {\r
353     if (Status == EFI_ALREADY_STARTED) {\r
354       DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));\r
355     }\r
356     return Status;\r
357   }\r
358 \r
359   DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));\r
360 \r
361   //\r
362   // check the version, we don't want to connect to the undi16\r
363   //\r
364   if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r
365     Status = EFI_UNSUPPORTED;\r
366     goto Done;\r
367   }\r
368   //\r
369   // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r
370   //\r
371   if (NiiProtocol->ID & 0x0F) {\r
372     DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
373     Status = EFI_UNSUPPORTED;\r
374     goto Done;\r
375   }\r
376 \r
377   pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);\r
378 \r
379   //\r
380   //  Verify !PXE revisions.\r
381   //\r
382   if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
383     DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
384     Status = EFI_UNSUPPORTED;\r
385     goto Done;\r
386   }\r
387 \r
388   if (pxe->hw.Rev < PXE_ROMID_REV) {\r
389     DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
390     Status = EFI_UNSUPPORTED;\r
391     goto Done;\r
392   }\r
393 \r
394   if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
395 \r
396     DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
397     Status = EFI_UNSUPPORTED;\r
398     goto Done;\r
399 \r
400   } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
401     DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
402     Status = EFI_UNSUPPORTED;\r
403     goto Done;\r
404   }\r
405   //\r
406   // Do S/W UNDI specific checks.\r
407   //\r
408   if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
409     if (pxe->sw.EntryPoint < pxe->sw.Len) {\r
410       DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
411       Status = EFI_UNSUPPORTED;\r
412       goto Done;\r
413     }\r
414 \r
415     if (pxe->sw.BusCnt == 0) {\r
416       DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
417       Status = EFI_UNSUPPORTED;\r
418       goto Done;\r
419     }\r
420   }\r
421 \r
422   Status = EFI_SUCCESS;\r
423   DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));\r
424 \r
425 Done:\r
426   gBS->CloseProtocol (\r
427         Controller,\r
428         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
429         This->DriverBindingHandle,\r
430         Controller\r
431         );\r
432 \r
433   return Status;\r
434 }\r
435 \r
436 \r
437 /**\r
438   called for any handle that we said "supported" in the above call!\r
439 \r
440   @param  This                 Protocol instance pointer.\r
441   @param  Controller           Handle of device to start\r
442   @param  RemainingDevicePath  Not used.\r
443 \r
444   @retval EFI_SUCCESS          This driver supports this device.\r
445   @retval other                This driver failed to start this device.\r
446 \r
447 **/\r
448 EFI_STATUS\r
449 EFIAPI\r
450 SimpleNetworkDriverStart (\r
451   IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
452   IN EFI_HANDLE                     Controller,\r
453   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
454   )\r
455 {\r
456   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
457   EFI_DEVICE_PATH_PROTOCOL                  *NiiDevicePath;\r
458   EFI_STATUS                                Status;\r
459   PXE_UNDI                                  *pxe;\r
460   SNP_DRIVER                                *snp;\r
461   VOID                                      *addr;\r
462   EFI_HANDLE                                Handle;\r
463   PXE_PCI_CONFIG_INFO                       ConfigInfo;\r
464   PCI_TYPE00                                *ConfigHeader;\r
465   UINT32                                    *TempBar;\r
466   UINT8                                     BarIndex;\r
467   PXE_STATFLAGS                             InitStatFlags;\r
468 \r
469   DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier()  "));\r
470 \r
471   Status = gBS->OpenProtocol (\r
472                   Controller,\r
473                   &gEfiDevicePathProtocolGuid,\r
474                   (VOID **) &NiiDevicePath,\r
475                   This->DriverBindingHandle,\r
476                   Controller,\r
477                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
478                   );\r
479 \r
480   if (EFI_ERROR (Status)) {\r
481     return Status;\r
482   }\r
483 \r
484   Status = gBS->LocateDevicePath (\r
485                   &gEfiPciIoProtocolGuid,\r
486                   &NiiDevicePath,\r
487                   &Handle\r
488                   );\r
489 \r
490   if (EFI_ERROR (Status)) {\r
491     return Status;\r
492   }\r
493 \r
494   Status = gBS->OpenProtocol (\r
495                   Handle,\r
496                   &gEfiPciIoProtocolGuid,\r
497                   (VOID **) &mPciIoFncs,\r
498                   This->DriverBindingHandle,\r
499                   Controller,\r
500                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
501                   );\r
502   if (EFI_ERROR (Status)) {\r
503     return Status;\r
504   }\r
505   //\r
506   // Get the NII interface.\r
507   //\r
508   Status = gBS->OpenProtocol (\r
509                   Controller,\r
510                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
511                   (VOID **) &Nii,\r
512                   This->DriverBindingHandle,\r
513                   Controller,\r
514                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
515                   );\r
516   if (EFI_ERROR (Status)) {\r
517     gBS->CloseProtocol (\r
518           Controller,\r
519           &gEfiDevicePathProtocolGuid,\r
520           This->DriverBindingHandle,\r
521           Controller\r
522           );\r
523     return Status;\r
524   }\r
525 \r
526   DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r
527 \r
528   pxe = (PXE_UNDI *) (UINTN) (Nii->ID);\r
529 \r
530   if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {\r
531     DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
532     goto NiiError;\r
533   }\r
534 \r
535   if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
536     //\r
537     //  We can get any packets.\r
538     //\r
539   } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
540     //\r
541     //  We need to be able to get broadcast packets for DHCP.\r
542     //  If we do not have promiscuous support, we must at least have\r
543     //  broadcast support or we cannot do DHCP!\r
544     //\r
545   } else {\r
546     DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
547     goto NiiError;\r
548   }\r
549   //\r
550   // OK, we like this UNDI, and we know snp is not already there on this handle\r
551   // Allocate and initialize a new simple network protocol structure.\r
552   //\r
553   Status = mPciIoFncs->AllocateBuffer (\r
554                         mPciIoFncs,\r
555                         AllocateAnyPages,\r
556                         EfiBootServicesData,\r
557                         SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
558                         &addr,\r
559                         0\r
560                         );\r
561 \r
562   if (Status != EFI_SUCCESS) {\r
563     DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
564     goto NiiError;\r
565   }\r
566 \r
567   snp = (SNP_DRIVER *) (UINTN) addr;\r
568 \r
569   ZeroMem (snp, sizeof (SNP_DRIVER));\r
570 \r
571   snp->IoFncs     = mPciIoFncs;\r
572   snp->Signature  = SNP_DRIVER_SIGNATURE;\r
573 \r
574   EfiInitializeLock (&snp->lock, TPL_NOTIFY);\r
575 \r
576   snp->snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
577   snp->snp.Start          = snp_undi32_start;\r
578   snp->snp.Stop           = snp_undi32_stop;\r
579   snp->snp.Initialize     = snp_undi32_initialize;\r
580   snp->snp.Reset          = snp_undi32_reset;\r
581   snp->snp.Shutdown       = snp_undi32_shutdown;\r
582   snp->snp.ReceiveFilters = snp_undi32_receive_filters;\r
583   snp->snp.StationAddress = snp_undi32_station_address;\r
584   snp->snp.Statistics     = snp_undi32_statistics;\r
585   snp->snp.MCastIpToMac   = snp_undi32_mcast_ip_to_mac;\r
586   snp->snp.NvData         = snp_undi32_nvdata;\r
587   snp->snp.GetStatus      = snp_undi32_get_status;\r
588   snp->snp.Transmit       = snp_undi32_transmit;\r
589   snp->snp.Receive        = snp_undi32_receive;\r
590   snp->snp.WaitForPacket  = NULL;\r
591 \r
592   snp->snp.Mode           = &snp->mode;\r
593 \r
594   snp->tx_rx_bufsize      = 0;\r
595   snp->tx_rx_buffer       = NULL;\r
596 \r
597   snp->if_num             = Nii->IfNum;\r
598 \r
599   if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
600     snp->is_swundi            = FALSE;\r
601     snp->issue_undi32_command = &issue_hwundi_command;\r
602   } else {\r
603     snp->is_swundi = TRUE;\r
604 \r
605     if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
606       snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;\r
607     } else {\r
608       snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);\r
609     }\r
610   }\r
611   //\r
612   // Allocate a global CPB and DB buffer for this UNDI interface.\r
613   // we do this because:\r
614   //\r
615   // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
616   // within 2GB limit, create them here and map them so that when undi calls\r
617   // v2p callback to check if the physical address is < 2gb, we will pass.\r
618   //\r
619   // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
620   // simpler if we use the same cpb, db variables for both old and new undi\r
621   // interfaces from all the SNP interface calls (we don't map the buffers\r
622   // for the newer undi interfaces though)\r
623   // .\r
624   // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
625   // interface as EFI does not multi-task and so SNP will not be re-entered!\r
626   //\r
627   Status = mPciIoFncs->AllocateBuffer (\r
628                         mPciIoFncs,\r
629                         AllocateAnyPages,\r
630                         EfiBootServicesData,\r
631                         SNP_MEM_PAGES (4096),\r
632                         &addr,\r
633                         0\r
634                         );\r
635 \r
636   if (Status != EFI_SUCCESS) {\r
637     DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
638     goto Error_DeleteSNP;\r
639   }\r
640 \r
641   snp->cpb  = (VOID *) (UINTN) addr;\r
642   snp->db   = (VOID *) ((UINTN) addr + 2048);\r
643 \r
644   //\r
645   // pxe_start call is going to give the callback functions to UNDI, these callback\r
646   // functions use the BarIndex values from the snp structure, so these must be initialized\r
647   // with default values before doing a pxe_start. The correct values can be obtained after\r
648   // getting the config information from UNDI\r
649   //\r
650   snp->MemoryBarIndex = 0;\r
651   snp->IoBarIndex     = 1;\r
652 \r
653   //\r
654   // we need the undi init information many times in this snp code, just get it\r
655   // once here and store it in the snp driver structure. to get Init Info\r
656   // from UNDI we have to start undi first.\r
657   //\r
658   Status = pxe_start (snp);\r
659 \r
660   if (Status != EFI_SUCCESS) {\r
661     goto Error_DeleteSNP;\r
662   }\r
663 \r
664   snp->cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;\r
665   snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
666 \r
667   snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
668   snp->cdb.CPBaddr    = PXE_DBADDR_NOT_USED;\r
669 \r
670   snp->cdb.DBsize     = sizeof snp->init_info;\r
671   snp->cdb.DBaddr     = (UINT64)(UINTN) &snp->init_info;\r
672 \r
673   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
674   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
675 \r
676   snp->cdb.IFnum      = snp->if_num;\r
677   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
678 \r
679   DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info()  "));\r
680 \r
681   (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
682 \r
683   //\r
684   // Save the INIT Stat Code...\r
685   //\r
686   InitStatFlags = snp->cdb.StatFlags;\r
687 \r
688   if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
689     DEBUG ((EFI_D_NET, "\nsnp->undi.init_info()  %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
690     pxe_stop (snp);\r
691     goto Error_DeleteSNP;\r
692   }\r
693 \r
694   snp->cdb.OpCode     = PXE_OPCODE_GET_CONFIG_INFO;\r
695   snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
696 \r
697   snp->cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
698   snp->cdb.CPBaddr    = PXE_DBADDR_NOT_USED;\r
699 \r
700   snp->cdb.DBsize     = sizeof ConfigInfo;\r
701   snp->cdb.DBaddr     = (UINT64)(UINTN) &ConfigInfo;\r
702 \r
703   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
704   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
705 \r
706   snp->cdb.IFnum      = snp->if_num;\r
707   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
708 \r
709   DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info()  "));\r
710 \r
711   (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
712 \r
713   if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
714     DEBUG ((EFI_D_NET, "\nsnp->undi.config_info()  %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
715     pxe_stop (snp);\r
716     goto Error_DeleteSNP;\r
717   }\r
718   //\r
719   // Find the correct BAR to do IO.\r
720   //\r
721   //\r
722   // Enumerate through the PCI BARs for the device to determine which one is\r
723   // the IO BAR.  Save the index of the BAR into the adapter info structure.\r
724   // for  regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
725   //\r
726   ConfigHeader  = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r
727   TempBar       = (UINT32 *) &ConfigHeader->Device.Bar[0];\r
728   for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r
729     if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r
730       //\r
731       // This is a 64-bit memory bar, skip this and the\r
732       // next bar as well.\r
733       //\r
734       TempBar++;\r
735     }\r
736 \r
737     if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r
738       snp->IoBarIndex = BarIndex;\r
739       break;\r
740     }\r
741 \r
742     TempBar++;\r
743   }\r
744 \r
745   //\r
746   //  Initialize simple network protocol mode structure\r
747   //\r
748   snp->mode.State               = EfiSimpleNetworkStopped;\r
749   snp->mode.HwAddressSize       = snp->init_info.HWaddrLen;\r
750   snp->mode.MediaHeaderSize     = snp->init_info.MediaHeaderLen;\r
751   snp->mode.MaxPacketSize       = snp->init_info.FrameDataLen;\r
752   snp->mode.NvRamAccessSize     = snp->init_info.NvWidth;\r
753   snp->mode.NvRamSize           = snp->init_info.NvCount * snp->mode.NvRamAccessSize;\r
754   snp->mode.IfType              = snp->init_info.IFtype;\r
755   snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;\r
756   snp->mode.MCastFilterCount    = 0;\r
757 \r
758   switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
759   case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
760     snp->mode.MediaPresentSupported = TRUE;\r
761     break;\r
762 \r
763   case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
764   default:\r
765     snp->mode.MediaPresentSupported = FALSE;\r
766   }\r
767 \r
768   if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
769     snp->mode.MacAddressChangeable = TRUE;\r
770   } else {\r
771     snp->mode.MacAddressChangeable = FALSE;\r
772   }\r
773 \r
774   if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
775     snp->mode.MultipleTxSupported = TRUE;\r
776   } else {\r
777     snp->mode.MultipleTxSupported = FALSE;\r
778   }\r
779 \r
780   snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
781 \r
782   if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
783     snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
784 \r
785   }\r
786 \r
787   if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
788     snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
789 \r
790   }\r
791 \r
792   if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
793     snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
794 \r
795   }\r
796 \r
797   if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
798     snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
799 \r
800   }\r
801 \r
802   if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {\r
803     snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
804 \r
805   }\r
806 \r
807   snp->mode.ReceiveFilterSetting = 0;\r
808 \r
809   //\r
810   //  need to get the station address to save in the mode structure. we need to\r
811   // initialize the UNDI first for this.\r
812   //\r
813   snp->tx_rx_bufsize  = snp->init_info.MemoryRequired;\r
814   Status              = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
815 \r
816   if (Status) {\r
817     pxe_stop (snp);\r
818     goto Error_DeleteSNP;\r
819   }\r
820 \r
821   Status = pxe_get_stn_addr (snp);\r
822 \r
823   if (Status != EFI_SUCCESS) {\r
824     DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr()  failed.\n"));\r
825     pxe_shutdown (snp);\r
826     pxe_stop (snp);\r
827     goto Error_DeleteSNP;\r
828   }\r
829 \r
830   snp->mode.MediaPresent = FALSE;\r
831 \r
832   //\r
833   // We should not leave UNDI started and initialized here. this DriverStart()\r
834   // routine must only find and attach the SNP interface to UNDI layer that it\r
835   // finds on the given handle!\r
836   // The UNDI layer will be started when upper layers call snp->start.\r
837   // How ever, this DriverStart() must fill up the snp mode structure which\r
838   // contains the MAC address of the NIC. For this reason we started and\r
839   // initialized UNDI here, now we are done, do a shutdown and stop of the\r
840   // UNDI interface!\r
841   //\r
842   pxe_shutdown (snp);\r
843   pxe_stop (snp);\r
844 \r
845   //\r
846   //  add SNP to the undi handle\r
847   //\r
848   Status = gBS->InstallProtocolInterface (\r
849                   &Controller,\r
850                   &gEfiSimpleNetworkProtocolGuid,\r
851                   EFI_NATIVE_INTERFACE,\r
852                   &(snp->snp)\r
853                   );\r
854 \r
855   if (!EFI_ERROR (Status)) {\r
856     return Status;\r
857   }\r
858 \r
859   Status = mPciIoFncs->FreeBuffer (\r
860                         mPciIoFncs,\r
861                         SNP_MEM_PAGES (4096),\r
862                         snp->cpb\r
863                         );\r
864 \r
865 Error_DeleteSNP:\r
866 \r
867   mPciIoFncs->FreeBuffer (\r
868                 mPciIoFncs,\r
869                 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
870                 snp\r
871                 );\r
872 NiiError:\r
873   gBS->CloseProtocol (\r
874         Controller,\r
875         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
876         This->DriverBindingHandle,\r
877         Controller\r
878         );\r
879 \r
880   gBS->CloseProtocol (\r
881         Controller,\r
882         &gEfiDevicePathProtocolGuid,\r
883         This->DriverBindingHandle,\r
884         Controller\r
885         );\r
886 \r
887   return Status;\r
888 }\r
889 \r
890 \r
891 /**\r
892 \r
893 \r
894 \r
895 **/\r
896 EFI_STATUS\r
897 EFIAPI\r
898 SimpleNetworkDriverStop (\r
899   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
900   IN  EFI_HANDLE                     Controller,\r
901   IN  UINTN                          NumberOfChildren,\r
902   IN  EFI_HANDLE                     *ChildHandleBuffer\r
903   )\r
904 {\r
905   EFI_STATUS                  Status;\r
906   EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
907   SNP_DRIVER                  *Snp;\r
908 \r
909   //\r
910   // Get our context back.\r
911   //\r
912   Status = gBS->OpenProtocol (\r
913                   Controller,\r
914                   &gEfiSimpleNetworkProtocolGuid,\r
915                   (VOID **) &SnpProtocol,\r
916                   This->DriverBindingHandle,\r
917                   Controller,\r
918                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
919                   );\r
920 \r
921   if (EFI_ERROR (Status)) {\r
922     return EFI_UNSUPPORTED;\r
923   }\r
924 \r
925   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
926 \r
927   Status = gBS->UninstallProtocolInterface (\r
928                   Controller,\r
929                   &gEfiSimpleNetworkProtocolGuid,\r
930                   &Snp->snp\r
931                   );\r
932 \r
933   if (EFI_ERROR (Status)) {\r
934     return Status;\r
935   }\r
936 \r
937   Status = gBS->CloseProtocol (\r
938                   Controller,\r
939                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
940                   This->DriverBindingHandle,\r
941                   Controller\r
942                   );\r
943 \r
944   Status = gBS->CloseProtocol (\r
945                   Controller,\r
946                   &gEfiDevicePathProtocolGuid,\r
947                   This->DriverBindingHandle,\r
948                   Controller\r
949                   );\r
950 \r
951   pxe_shutdown (Snp);\r
952   pxe_stop (Snp);\r
953 \r
954   mPciIoFncs->FreeBuffer (\r
955                 mPciIoFncs,\r
956                 SNP_MEM_PAGES (4096),\r
957                 Snp->cpb\r
958                 );\r
959 \r
960   mPciIoFncs->FreeBuffer (\r
961                 mPciIoFncs,\r
962                 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
963                 Snp\r
964                 );\r
965 \r
966   return Status;\r
967 }\r
968 \r
969 \r
970 /**\r
971   Install all the driver protocol\r
972 \r
973   @param  entry                EFI_IMAGE_ENTRY_POINT)\r
974 \r
975   @retval EFI_SUCEESS          Initialization routine has found UNDI hardware,\r
976                                loaded it's ROM, and installed a notify event for\r
977                                the Network Indentifier Interface Protocol\r
978                                successfully.\r
979   @retval Other                Return value from HandleProtocol for\r
980                                DeviceIoProtocol or LoadedImageProtocol\r
981 \r
982 **/\r
983 EFI_STATUS\r
984 EFIAPI\r
985 InitializeSnpNiiDriver (\r
986   IN EFI_HANDLE       ImageHandle,\r
987   IN EFI_SYSTEM_TABLE *SystemTable\r
988   )\r
989 {\r
990   return EfiLibInstallDriverBindingComponentName2 (\r
991            ImageHandle,\r
992            SystemTable,\r
993            &mSimpleNetworkDriverBinding,\r
994            NULL,\r
995            &gSimpleNetworkComponentName,\r
996            &gSimpleNetworkComponentName2\r
997            );\r
998 }\r