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