rename
[people/mcb30/edk2.git] / edk2 / 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 = %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
332 \r
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
353 \r
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
357     }\r
358     return Status;\r
359   }\r
360 \r
361   DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %x\n", Controller));\r
362 \r
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
428   gBS->CloseProtocol (\r
429         Controller,\r
430         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
431         This->DriverBindingHandle,\r
432         Controller\r
433         );\r
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
464   EFI_HANDLE                                Handle;\r
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
508   // Get the NII interface.\r
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
518   if (EFI_ERROR (Status)) {\r
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
528   DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r
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
571   ZeroMem (snp, sizeof (SNP_DRIVER));\r
572 \r
573   snp->IoFncs     = mPciIoFncs;\r
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
643   snp->cpb  = (VOID *) (UINTN) addr;\r
644   snp->db   = (VOID *) ((UINTN) addr + 2048);\r
645 \r
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
663     goto Error_DeleteSNP;\r
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
693     goto Error_DeleteSNP;\r
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
718     goto Error_DeleteSNP;\r
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
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
820     goto Error_DeleteSNP;\r
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
829     goto Error_DeleteSNP;\r
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
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
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
875   gBS->CloseProtocol (\r
876         Controller,\r
877         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
878         This->DriverBindingHandle,\r
879         Controller\r
880         );\r
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
939   Status = gBS->CloseProtocol (\r
940                   Controller,\r
941                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
942                   This->DriverBindingHandle,\r
943                   Controller\r
944                   );\r
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
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
992   return EfiLibInstallDriverBindingComponentName2 (\r
993            ImageHandle,\r
994            SystemTable,\r
995            &mSimpleNetworkDriverBinding,\r
996            NULL,\r
997            &gSimpleNetworkComponentName,\r
998            &gSimpleNetworkComponentName2\r
999            );\r
1000 }\r