]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c
EmbeddedPkg/Lan9118Dxe: Add or fix input parameter checks
[mirror_edk2.git] / EmbeddedPkg / Drivers / Lan9118Dxe / Lan9118Dxe.c
1 /** @file
2 *
3 * Copyright (c) 2012-2014, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include "Lan9118Dxe.h"
16
17
18 typedef struct {
19 MAC_ADDR_DEVICE_PATH Lan9118;
20 EFI_DEVICE_PATH_PROTOCOL End;
21 } LAN9118_DEVICE_PATH;
22
23 LAN9118_DEVICE_PATH Lan9118PathTemplate = {
24 {
25 {
26 MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,
27 { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) }
28 },
29 { { 0 } },
30 0
31 },
32 {
33 END_DEVICE_PATH_TYPE,
34 END_ENTIRE_DEVICE_PATH_SUBTYPE,
35 { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }
36 }
37 };
38
39 /*
40 ** Entry point for the LAN9118 driver
41 **
42 */
43 EFI_STATUS
44 Lan9118DxeEntry (
45 IN EFI_HANDLE Handle,
46 IN EFI_SYSTEM_TABLE *SystemTable
47 )
48 {
49 EFI_STATUS Status;
50 LAN9118_DRIVER *LanDriver;
51 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
52 EFI_SIMPLE_NETWORK_MODE *SnpMode;
53 LAN9118_DEVICE_PATH *Lan9118Path;
54 EFI_HANDLE ControllerHandle;
55
56 // The PcdLan9118DxeBaseAddress PCD must be defined
57 ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress) != 0);
58
59 // Allocate Resources
60 LanDriver = AllocateZeroPool (sizeof (LAN9118_DRIVER));
61 if (LanDriver == NULL) {
62 return EFI_OUT_OF_RESOURCES;
63 }
64 Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool (sizeof (LAN9118_DEVICE_PATH), &Lan9118PathTemplate);
65 if (Lan9118Path == NULL) {
66 return EFI_OUT_OF_RESOURCES;
67 }
68
69 // Initialize pointers
70 Snp = &(LanDriver->Snp);
71 SnpMode = &(LanDriver->SnpMode);
72 Snp->Mode = SnpMode;
73
74 // Set the signature of the LAN Driver structure
75 LanDriver->Signature = LAN9118_SIGNATURE;
76
77 // Assign fields and func pointers
78 Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
79 Snp->WaitForPacket = NULL;
80 Snp->Initialize = SnpInitialize;
81 Snp->Start = SnpStart;
82 Snp->Stop = SnpStop;
83 Snp->Reset = SnpReset;
84 Snp->Shutdown = SnpShutdown;
85 Snp->ReceiveFilters = SnpReceiveFilters;
86 Snp->StationAddress = SnpStationAddress;
87 Snp->Statistics = SnpStatistics;
88 Snp->MCastIpToMac = SnpMcastIptoMac;
89 Snp->NvData = SnpNvData;
90 Snp->GetStatus = SnpGetStatus;
91 Snp->Transmit = SnpTransmit;
92 Snp->Receive = SnpReceive;
93
94 // Start completing simple network mode structure
95 SnpMode->State = EfiSimpleNetworkStopped;
96 SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes
97 SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Not sure of this
98 SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes)
99 SnpMode->NvRamSize = 0; // No NVRAM with this device
100 SnpMode->NvRamAccessSize = 0; // No NVRAM with this device
101
102 // Update network mode information
103 SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
104 EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
105 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
106 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;/* |
107 EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;*/
108 // Current allowed settings
109 SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
110 EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
111 EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
112
113 // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses
114 SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
115 SnpMode->MCastFilterCount = 0;
116 ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));
117
118 // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)
119 SnpMode->IfType = NET_IFTYPE_ETHERNET;
120
121 // Mac address is changeable as it is loaded from erasable memory
122 SnpMode->MacAddressChangeable = TRUE;
123
124 // Can only transmit one packet at a time
125 SnpMode->MultipleTxSupported = FALSE;
126
127 // MediaPresent checks for cable connection and partner link
128 SnpMode->MediaPresentSupported = TRUE;
129 SnpMode->MediaPresent = FALSE;
130
131 // Set broadcast address
132 SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
133
134 // Power up the device so we can find the MAC address
135 Status = Lan9118Initialize (Snp);
136 if (EFI_ERROR (Status)) {
137 DEBUG ((EFI_D_ERROR, "Lan9118: Error initialising hardware\n"));
138 return EFI_DEVICE_ERROR;
139 }
140
141 // Assign fields for device path
142 CopyMem (&Lan9118Path->Lan9118.MacAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
143 Lan9118Path->Lan9118.IfType = Snp->Mode->IfType;
144
145 // Initialise the protocol
146 ControllerHandle = NULL;
147 Status = gBS->InstallMultipleProtocolInterfaces (
148 &ControllerHandle,
149 &gEfiSimpleNetworkProtocolGuid, Snp,
150 &gEfiDevicePathProtocolGuid, Lan9118Path,
151 NULL
152 );
153 // Say what the status of loading the protocol structure is
154 if (EFI_ERROR(Status)) {
155 FreePool (LanDriver);
156 } else {
157 LanDriver->ControllerHandle = ControllerHandle;
158 }
159
160 return Status;
161 }
162
163 /*
164 * UEFI Start() function
165 *
166 * Parameters:
167 *
168 * @param Snp: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
169 *
170 * Description:
171 *
172 * This function starts a network interface. If the network interface successfully starts, then
173 * EFI_SUCCESS will be returned.
174 */
175 EFI_STATUS
176 EFIAPI
177 SnpStart (
178 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp
179 )
180 {
181 // Check Snp instance
182 if (Snp == NULL) {
183 return EFI_INVALID_PARAMETER;
184 }
185
186 // Check state
187 if ((Snp->Mode->State == EfiSimpleNetworkStarted) ||
188 (Snp->Mode->State == EfiSimpleNetworkInitialized) ) {
189 return EFI_ALREADY_STARTED;
190 }
191
192 // Change state
193 Snp->Mode->State = EfiSimpleNetworkStarted;
194 return EFI_SUCCESS;
195 }
196
197 /*
198 * UEFI Stop() function
199 *
200 */
201 EFI_STATUS
202 EFIAPI
203 SnpStop (
204 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
205 )
206 {
207 // Check Snp Instance
208 if (Snp == NULL) {
209 return EFI_INVALID_PARAMETER;
210 }
211
212 // Check state of the driver
213 if (Snp->Mode->State == EfiSimpleNetworkStopped) {
214 return EFI_NOT_STARTED;
215 }
216
217 // Stop the Tx and Rx
218 StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp);
219 StopRx (0, Snp);
220
221 // Change the state
222 switch (Snp->Mode->State) {
223 case EfiSimpleNetworkStarted:
224 case EfiSimpleNetworkInitialized:
225 Snp->Mode->State = EfiSimpleNetworkStopped;
226 break;
227 default:
228 return EFI_DEVICE_ERROR;
229 }
230
231 // Put the device into a power saving mode ?
232 return EFI_SUCCESS;
233 }
234
235
236 // Allocated receive and transmit buffers
237 STATIC UINT32 gTxBuffer = 0;
238
239 /*
240 * UEFI Initialize() function
241 *
242 */
243 EFI_STATUS
244 EFIAPI
245 SnpInitialize (
246 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
247 IN UINTN RxBufferSize OPTIONAL,
248 IN UINTN TxBufferSize OPTIONAL
249 )
250 {
251 EFI_STATUS Status;
252 UINT32 PmConf;
253 INT32 AllocResult;
254 UINT32 RxStatusSize;
255 UINT32 TxStatusSize;
256
257 // Initialize variables
258 // Global variables to hold tx and rx FIFO allocation
259 gTxBuffer = 0;
260
261 // Check Snp Instance
262 if (Snp == NULL) {
263 return EFI_INVALID_PARAMETER;
264 }
265
266 // First check that driver has not already been initialized
267 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
268 DEBUG ((EFI_D_WARN, "LAN9118 Driver already initialized\n"));
269 return EFI_SUCCESS;
270 } else
271 if (Snp->Mode->State == EfiSimpleNetworkStopped) {
272 DEBUG ((EFI_D_WARN, "LAN9118 Driver not started\n"));
273 return EFI_NOT_STARTED;
274 }
275
276 // Initiate a PHY reset
277 Status = PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp);
278 if (EFI_ERROR (Status)) {
279 Snp->Mode->State = EfiSimpleNetworkStopped;
280 DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n"));
281 return EFI_NOT_STARTED;
282 }
283
284 // Initiate a software reset
285 Status = SoftReset (0, Snp);
286 if (EFI_ERROR(Status)) {
287 DEBUG ((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n"));
288 return EFI_DEVICE_ERROR;
289 }
290
291 // Read the PM register
292 PmConf = MmioRead32 (LAN9118_PMT_CTRL);
293
294 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets
295 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode
296 // MPTCTRL_PME_EN: Allow Power Management Events
297 PmConf = 0;
298 PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);
299
300 // Write the current configuration to the register
301 MmioWrite32 (LAN9118_PMT_CTRL, PmConf);
302 gBS->Stall (LAN9118_STALL);
303 gBS->Stall (LAN9118_STALL);
304
305 // Configure GPIO and HW
306 Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp);
307 if (EFI_ERROR(Status)) {
308 return Status;
309 }
310
311 // Assign the transmitter buffer size (default values)
312 TxStatusSize = LAN9118_TX_STATUS_SIZE;
313 RxStatusSize = LAN9118_RX_STATUS_SIZE;
314
315 // Check that a buff size was specified
316 if (TxBufferSize > 0) {
317 if (RxBufferSize == 0) {
318 RxBufferSize = LAN9118_RX_DATA_SIZE;
319 }
320
321 AllocResult = ChangeFifoAllocation (
322 ALLOC_USE_FIFOS,
323 &TxBufferSize,
324 &RxBufferSize,
325 &TxStatusSize,
326 &RxStatusSize,
327 Snp
328 );
329
330 if (AllocResult < 0) {
331 return EFI_OUT_OF_RESOURCES;
332 }
333 }
334
335 // Do auto-negotiation if supported
336 Status = AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp);
337 if (EFI_ERROR(Status)) {
338 DEBUG ((EFI_D_WARN, "Lan9118: Auto Negociation not supported.\n"));
339 }
340
341 // Configure flow control depending on speed capabilities
342 Status = ConfigureFlow (0, 0, 0, 0, Snp);
343 if (EFI_ERROR(Status)) {
344 return Status;
345 }
346
347 // Enable the receiver and transmitter
348 Status = StartRx (0, Snp);
349 if (EFI_ERROR(Status)) {
350 return Status;
351 }
352
353 Status = StartTx (START_TX_MAC | START_TX_CFG, Snp);
354 if (EFI_ERROR(Status)) {
355 return Status;
356 }
357
358 // Now acknowledge all interrupts
359 MmioWrite32 (LAN9118_INT_STS, ~0);
360
361 // Declare the driver as initialized
362 Snp->Mode->State = EfiSimpleNetworkInitialized;
363
364 return Status;
365 }
366
367 /*
368 * UEFI Reset () function
369 *
370 */
371 EFI_STATUS
372 EFIAPI
373 SnpReset (
374 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
375 IN BOOLEAN Verification
376 )
377 {
378 UINT32 PmConf;
379 UINT32 HwConf;
380 UINT32 ResetFlags;
381 EFI_STATUS Status;
382
383 PmConf = 0;
384 HwConf = 0;
385 ResetFlags = 0;
386
387 // Check Snp Instance
388 if (Snp == NULL) {
389 return EFI_INVALID_PARAMETER;
390 }
391
392 // First check that driver has not already been initialized
393 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
394 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));
395 return EFI_DEVICE_ERROR;
396 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
397 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));
398 return EFI_NOT_STARTED;
399 }
400
401 // Initiate a PHY reset
402 Status = PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp);
403 if (EFI_ERROR (Status)) {
404 Snp->Mode->State = EfiSimpleNetworkStopped;
405 return EFI_NOT_STARTED;
406 }
407
408 // Initiate a software reset
409 ResetFlags |= SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT;
410
411 if (Verification) {
412 ResetFlags |= SOFT_RESET_SELF_TEST;
413 }
414
415 Status = SoftReset (ResetFlags, Snp);
416 if (EFI_ERROR (Status)) {
417 DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));
418 return EFI_DEVICE_ERROR;
419 }
420
421 // Read the PM register
422 PmConf = MmioRead32 (LAN9118_PMT_CTRL);
423
424 // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets
425 // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode
426 // MPTCTRL_PME_EN: Allow Power Management Events
427 PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN);
428
429 // Write the current configuration to the register
430 MmioWrite32 (LAN9118_PMT_CTRL, PmConf);
431 gBS->Stall (LAN9118_STALL);
432
433 // Check that a buffer size was specified in SnpInitialize
434 if (gTxBuffer != 0) {
435 HwConf = MmioRead32 (LAN9118_HW_CFG); // Read the HW register
436 HwConf &= ~HW_CFG_TX_FIFO_SIZE_MASK; // Clear buffer bits first
437 HwConf |= HW_CFG_TX_FIFO_SIZE(gTxBuffer); // assign size chosen in SnpInitialize
438
439 MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf
440 gBS->Stall (LAN9118_STALL);
441 }
442
443 // Enable the receiver and transmitter and clear their contents
444 StartRx (START_RX_CLEAR, Snp);
445 StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp);
446
447 // Now acknowledge all interrupts
448 MmioWrite32 (LAN9118_INT_STS, ~0);
449
450 return EFI_SUCCESS;
451 }
452
453 /*
454 * UEFI Shutdown () function
455 *
456 */
457 EFI_STATUS
458 EFIAPI
459 SnpShutdown (
460 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
461 )
462 {
463 EFI_STATUS Status;
464
465 // Check Snp Instance
466 if (Snp == NULL) {
467 return EFI_INVALID_PARAMETER;
468 }
469
470 // First check that driver has not already been initialized
471 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
472 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n"));
473 return EFI_DEVICE_ERROR;
474 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
475 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n"));
476 return EFI_NOT_STARTED;
477 }
478
479 // Initiate a PHY reset
480 Status = PhySoftReset (PHY_RESET_PMT, Snp);
481 if (EFI_ERROR (Status)) {
482 return Status;
483 }
484
485 // Initiate a software reset
486 Status = SoftReset (0, Snp);
487 if (EFI_ERROR (Status)) {
488 DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n"));
489 return Status;
490 }
491
492 return EFI_SUCCESS;
493 }
494
495 /**
496 Enable and/or disable the receive filters of the LAN9118
497
498 Please refer to the UEFI specification for the precedence rules among the
499 Enable, Disable and ResetMCastFilter parameters.
500
501 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
502 instance.
503 @param[in] Enable A bit mask of receive filters to enable.
504 @param[in] Disable A bit mask of receive filters to disable.
505 @param[in] ResetMCastFilter Set to TRUE to reset the contents of the multicast
506 receive filters on the network interface to
507 their default values.
508 @param[in] MCastFilterCnt Number of multicast HW MAC addresses in the new
509 MCastFilter list. This value must be less than or
510 equal to the MCastFilterCnt field of
511 EFI_SIMPLE_NETWORK_MODE. This field is optional if
512 ResetMCastFilter is TRUE.
513 @param[in] MCastFilter A pointer to a list of new multicast receive
514 filter HW MAC addresses. This list will replace
515 any existing multicast HW MAC address list. This
516 field is optional if ResetMCastFilter is TRUE.
517
518 @retval EFI_SUCCESS The receive filters of the LAN9118 were updated.
519 @retval EFI_NOT_STARTED The LAN9118 has not been started.
520 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :
521 . This is NULL
522 . Multicast is being enabled (the
523 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in
524 Enable, it is not set in Disable, and ResetMCastFilter
525 is FALSE) and MCastFilterCount is zero.
526 . Multicast is being enabled and MCastFilterCount is
527 greater than Snp->Mode->MaxMCastFilterCount.
528 . Multicast is being enabled and MCastFilter is NULL
529 . Multicast is being enabled and one or more of the
530 addresses in the MCastFilter list are not valid
531 multicast MAC addresses.
532 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.
533
534 **/
535 EFI_STATUS
536 EFIAPI
537 SnpReceiveFilters (
538 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
539 IN UINT32 Enable,
540 IN UINT32 Disable,
541 IN BOOLEAN ResetMCastFilter,
542 IN UINTN MCastFilterCnt OPTIONAL,
543 IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
544 )
545 {
546 EFI_SIMPLE_NETWORK_MODE *Mode;
547 UINT32 MultHashTableHigh;
548 UINT32 MultHashTableLow;
549 UINT32 Count;
550 UINT32 Crc;
551 UINT8 HashValue;
552 UINT32 MacCSRValue;
553 EFI_MAC_ADDRESS *Mac;
554
555 // Check Snp Instance
556 if (Snp == NULL) {
557 return EFI_INVALID_PARAMETER;
558 }
559 Mode = Snp->Mode;
560
561 // Check that driver was started and initialised
562 if (Mode->State == EfiSimpleNetworkStarted) {
563 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
564 return EFI_DEVICE_ERROR;
565 } else if (Mode->State == EfiSimpleNetworkStopped) {
566 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
567 return EFI_NOT_STARTED;
568 }
569
570 if ((Enable & (~Mode->ReceiveFilterMask)) ||
571 (Disable & (~Mode->ReceiveFilterMask)) ) {
572 return EFI_INVALID_PARAMETER;
573 }
574
575 //
576 // Check the validity of the multicast setting and compute the
577 // hash values of the multicast mac addresses to listen to.
578 //
579
580 MultHashTableHigh = 0;
581 MultHashTableLow = 0;
582 if ((!ResetMCastFilter) &&
583 ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) == 0) &&
584 ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) ) {
585 if ((MCastFilterCnt == 0) ||
586 (MCastFilterCnt > Mode->MaxMCastFilterCount) ||
587 (MCastFilter == NULL) ) {
588 return EFI_INVALID_PARAMETER;
589 }
590 //
591 // Check the validity of all multicast addresses before to change
592 // anything.
593 //
594 for (Count = 0; Count < MCastFilterCnt; Count++) {
595 if ((MCastFilter[Count].Addr[0] & 1) == 0) {
596 return EFI_INVALID_PARAMETER;
597 }
598 }
599
600 //
601 // Go through each filter address and set appropriate bits on hash table
602 //
603 for (Count = 0; Count < MCastFilterCnt; Count++) {
604 Mac = &(MCastFilter[Count]);
605 CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS));
606
607 Crc = GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN);
608 //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired
609
610 //
611 // The most significant 6 bits of the MAC address CRC constitute the hash
612 // value of the MAC address.
613 //
614 HashValue = (Crc >> 26) & 0x3F;
615
616 // Select hashlow register if MSB is not set
617 if ((HashValue & 0x20) == 0) {
618 MultHashTableLow |= (1 << HashValue);
619 } else {
620 MultHashTableHigh |= (1 << (HashValue & 0x1F));
621 }
622 }
623 Mode->MCastFilterCount = MCastFilterCnt;
624 } else if (ResetMCastFilter) {
625 Mode->MCastFilterCount = 0;
626 } else {
627 MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL);
628 MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH);
629 }
630
631 //
632 // Write the mask of the selected hash values for the multicast filtering.
633 // The two masks are set to zero if the multicast filtering is not enabled.
634 //
635 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow);
636 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh);
637
638 // Read MAC controller
639 MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
640
641 // Set the options for the MAC_CSR
642 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {
643 StartRx (0, Snp);
644 DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n"));
645 }
646
647 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {
648 StopRx (0, Snp);
649 DEBUG ((DEBUG_NET, "Disabling Unicast Frame Reception\n"));
650 }
651
652 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {
653 MacCSRValue |= MACCR_HPFILT;
654 DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n"));
655 }
656
657 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {
658 MacCSRValue &= ~MACCR_HPFILT;
659 DEBUG ((DEBUG_NET, "Disabling Multicast Frame Reception\n"));
660 }
661
662 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {
663 MacCSRValue &= ~(MACCR_BCAST);
664 DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n"));
665 }
666
667 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {
668 MacCSRValue |= MACCR_BCAST;
669 DEBUG ((DEBUG_NET, "Disabling Broadcast Frame Reception\n"));
670 }
671
672 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {
673 MacCSRValue |= MACCR_PRMS;
674 DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n"));
675 }
676
677 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {
678 MacCSRValue &= ~MACCR_PRMS;
679 DEBUG ((DEBUG_NET, "Disabling Promiscuous Mode\n"));
680 }
681
682 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {
683 MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS);
684 DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n"));
685 }
686
687 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {
688 MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS);
689 DEBUG ((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n"));
690 }
691
692 // Write the options to the MAC_CSR
693 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue);
694 gBS->Stall (LAN9118_STALL);
695
696 return EFI_SUCCESS;
697 }
698
699 /**
700 Modify of reset the current station address
701
702 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
703 instance.
704 @param[in] Reset Flag used to reset the station address to the
705 LAN9118's permanent address.
706 @param[in] New New station address to be used for the network interface.
707
708 @retval EFI_SUCCESS The LAN9118's station address was updated.
709 @retval EFI_NOT_STARTED The LAN9118 has not been started.
710 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :
711 . The "New" station address is invalid.
712 . "Reset" is FALSE and "New" is NULL.
713 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.
714
715 **/
716 EFI_STATUS
717 EFIAPI
718 SnpStationAddress (
719 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
720 IN BOOLEAN Reset,
721 IN EFI_MAC_ADDRESS *New
722 )
723 {
724 UINT32 Count;
725 UINT8 PermAddr[NET_ETHER_ADDR_LEN];
726
727 DEBUG ((DEBUG_NET, "SnpStationAddress()\n"));
728
729 // Check Snp instance
730 if (Snp == NULL) {
731 return EFI_INVALID_PARAMETER;
732 }
733
734 // Check that driver was started and initialised
735 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
736 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
737 return EFI_DEVICE_ERROR;
738 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
739 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
740 return EFI_NOT_STARTED;
741 }
742
743 // Get the Permanent MAC address if need reset
744 if (Reset) {
745 // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0
746 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) {
747 for (Count = 0; Count < NET_ETHER_ADDR_LEN; Count++) {
748 PermAddr[Count] = IndirectEEPROMRead32 (Count + 1);
749 }
750 New = (EFI_MAC_ADDRESS *) PermAddr;
751 Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp);
752 } else {
753 DEBUG ((EFI_D_ERROR, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n"));
754 New = (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress));
755 }
756 } else {
757 // Otherwise use the specified new MAC address
758 if (New == NULL) {
759 return EFI_INVALID_PARAMETER;
760 }
761 //
762 // If it is a multicast address, it is not valid.
763 //
764 if (New->Addr[0] & 0x01) {
765 return EFI_INVALID_PARAMETER;
766 }
767 }
768
769 // Write address
770 Lan9118SetMacAddress (New, Snp);
771
772 return EFI_SUCCESS;
773 }
774
775 /*
776 * UEFI Statistics() function
777 *
778 */
779 EFI_STATUS
780 EFIAPI
781 SnpStatistics (
782 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
783 IN BOOLEAN Reset,
784 IN OUT UINTN *StatSize,
785 OUT EFI_NETWORK_STATISTICS *Statistics
786 )
787 {
788 LAN9118_DRIVER *LanDriver;
789 EFI_STATUS Status;
790
791 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
792
793 DEBUG ((DEBUG_NET, "SnpStatistics()\n"));
794
795 // Check Snp instance
796 if (Snp == NULL) {
797 return EFI_INVALID_PARAMETER;
798 }
799
800 // Check that driver was started and initialised
801 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
802 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
803 return EFI_DEVICE_ERROR;
804 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
805 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
806 return EFI_NOT_STARTED;
807 }
808
809 //
810 // Do a reset if required. It is not clearly stated in the UEFI specification
811 // whether the reset has to be done before to copy the statistics in "Statictics"
812 // or after. It is a bit strange to do it before but that is what is expected by
813 // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89,
814 // 0x54,0x7e,0x4f,0xad,0x4f,0x24".
815 //
816 if (Reset) {
817 ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));
818 }
819
820 Status = EFI_SUCCESS;
821 if (StatSize == NULL) {
822 if (Statistics != NULL) {
823 return EFI_INVALID_PARAMETER;
824 }
825 } else {
826 if (Statistics == NULL) {
827 Status = EFI_BUFFER_TOO_SMALL;
828 } else {
829 // Fill in the statistics
830 CopyMem (
831 Statistics, &LanDriver->Stats,
832 MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS))
833 );
834 if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) {
835 Status = EFI_BUFFER_TOO_SMALL;
836 }
837 }
838 *StatSize = sizeof (EFI_NETWORK_STATISTICS);
839 }
840
841 return Status;
842 }
843
844 /*
845 * UEFI MCastIPtoMAC() function
846 *
847 */
848 EFI_STATUS
849 EFIAPI
850 SnpMcastIptoMac (
851 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
852 IN BOOLEAN IsIpv6,
853 IN EFI_IP_ADDRESS *Ip,
854 OUT EFI_MAC_ADDRESS *McastMac
855 )
856 {
857 DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n"));
858
859 // Check Snp instance
860 if (Snp == NULL) {
861 return EFI_INVALID_PARAMETER;
862 }
863
864 // Check that driver was started and initialised
865 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
866 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
867 return EFI_DEVICE_ERROR;
868 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
869 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
870 return EFI_NOT_STARTED;
871 }
872
873 // Check parameters
874 if ((McastMac == NULL) || (Ip == NULL)) {
875 return EFI_INVALID_PARAMETER;
876 }
877
878 // Make sure MAC address is empty
879 ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));
880
881 // If we need ipv4 address
882 if (!IsIpv6) {
883 // Most significant 25 bits of a multicast HW address are set.
884 // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)
885 McastMac->Addr[0] = 0x01;
886 McastMac->Addr[1] = 0x00;
887 McastMac->Addr[2] = 0x5E;
888
889 // Lower 23 bits from ipv4 address
890 McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)
891 McastMac->Addr[4] = Ip->v4.Addr[2];
892 McastMac->Addr[5] = Ip->v4.Addr[3];
893 } else {
894 // Most significant 16 bits of multicast v6 HW address are set
895 // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)
896 McastMac->Addr[0] = 0x33;
897 McastMac->Addr[1] = 0x33;
898
899 // lower four octets are taken from ipv6 address
900 McastMac->Addr[2] = Ip->v6.Addr[8];
901 McastMac->Addr[3] = Ip->v6.Addr[9];
902 McastMac->Addr[4] = Ip->v6.Addr[10];
903 McastMac->Addr[5] = Ip->v6.Addr[11];
904 }
905
906 return EFI_SUCCESS;
907 }
908
909 /*
910 * UEFI NvData() function
911 *
912 */
913 EFI_STATUS
914 EFIAPI
915 SnpNvData (
916 IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,
917 IN BOOLEAN read_write,
918 IN UINTN offset,
919 IN UINTN buff_size,
920 IN OUT VOID *data
921 )
922 {
923 DEBUG ((DEBUG_NET, "SnpNvData()\n"));
924
925 return EFI_UNSUPPORTED;
926 }
927
928
929 /*
930 * UEFI GetStatus () function
931 *
932 */
933 EFI_STATUS
934 EFIAPI
935 SnpGetStatus (
936 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
937 OUT UINT32 *IrqStat OPTIONAL,
938 OUT VOID **TxBuff OPTIONAL
939 )
940 {
941 UINT32 FifoInt;
942 EFI_STATUS Status;
943 UINTN NumTxStatusEntries;
944 UINT32 TxStatus;
945 UINT16 PacketTag;
946 UINT32 Interrupts;
947 LAN9118_DRIVER *LanDriver;
948
949 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
950
951 // Check preliminaries
952 if (Snp == NULL) {
953 return EFI_INVALID_PARAMETER;
954 }
955
956 // Check that driver was started and initialised
957 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
958 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
959 return EFI_DEVICE_ERROR;
960 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
961 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
962 return EFI_NOT_STARTED;
963 }
964
965 // Check and acknowledge TX Status interrupt (this will happen if the
966 // consumer of SNP does not call GetStatus.)
967 // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we
968 // should check for it and dump the TX Status FIFO.
969 FifoInt = MmioRead32 (LAN9118_FIFO_INT);
970
971 // Clear the TX Status FIFO Overflow
972 if ((FifoInt & INSTS_TXSO) == 0) {
973 FifoInt |= INSTS_TXSO;
974 MmioWrite32 (LAN9118_FIFO_INT, FifoInt);
975 }
976
977 // Read interrupt status if IrqStat is not NULL
978 if (IrqStat != NULL) {
979
980 // Check for receive interrupt
981 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO
982 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
983 MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);
984 } else {
985 *IrqStat &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
986 }
987
988 // Check for transmit interrupt
989 if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {
990 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
991 MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);
992 } else {
993 *IrqStat &= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
994 }
995
996 // Check for software interrupt
997 if (MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) {
998 *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;
999 MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT);
1000 } else {
1001 *IrqStat &= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;
1002 }
1003 }
1004
1005 // Check Status of transmitted packets
1006 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)
1007
1008 NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;
1009 if (NumTxStatusEntries > 0) {
1010 TxStatus = MmioRead32 (LAN9118_TX_STATUS);
1011 PacketTag = TxStatus >> 16;
1012 TxStatus = TxStatus & 0xFFFF;
1013 if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) {
1014 DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));
1015 if (TxStatus & TXSTATUS_NO_CA) {
1016 DEBUG ((EFI_D_ERROR, "- No carrier\n"));
1017 }
1018 if (TxStatus & TXSTATUS_DEF) {
1019 DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));
1020 }
1021 if (TxStatus & TXSTATUS_EDEF) {
1022 DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));
1023 }
1024 if (TxStatus & TXSTATUS_ECOLL) {
1025 DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));
1026 }
1027 if (TxStatus & TXSTATUS_LCOLL) {
1028 DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));
1029 }
1030 if (TxStatus & TXSTATUS_LOST_CA) {
1031 DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));
1032 }
1033 return EFI_DEVICE_ERROR;
1034 } else if (TxBuff != NULL) {
1035 LanDriver->Stats.TxTotalFrames += 1;
1036 *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];
1037 }
1038 }
1039
1040 // Check for a TX Error interrupt
1041 Interrupts = MmioRead32 (LAN9118_INT_STS);
1042 if (Interrupts & INSTS_TXE) {
1043 DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));
1044
1045 // Initiate a software reset
1046 Status = SoftReset (0, Snp);
1047 if (EFI_ERROR (Status)) {
1048 DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));
1049 return EFI_DEVICE_ERROR;
1050 }
1051
1052 // Acknowledge the TXE
1053 MmioWrite32 (LAN9118_INT_STS, INSTS_TXE);
1054 gBS->Stall (LAN9118_STALL);
1055
1056 // Restart the transmitter
1057 StartTx (START_TX_MAC | START_TX_CFG, Snp);
1058 }
1059
1060 // Update the media status
1061 Status = CheckLinkStatus (0, Snp);
1062 if (EFI_ERROR(Status)) {
1063 Snp->Mode->MediaPresent = FALSE;
1064 } else {
1065 Snp->Mode->MediaPresent = TRUE;
1066 }
1067
1068 return EFI_SUCCESS;
1069 }
1070
1071
1072 /*
1073 * UEFI Transmit() function
1074 *
1075 */
1076 EFI_STATUS
1077 EFIAPI
1078 SnpTransmit (
1079 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
1080 IN UINTN HdrSize,
1081 IN UINTN BuffSize,
1082 IN VOID* Data,
1083 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
1084 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,
1085 IN UINT16 *Protocol OPTIONAL
1086 )
1087 {
1088 LAN9118_DRIVER *LanDriver;
1089 UINT32 TxFreeSpace;
1090 UINT32 TxStatusSpace;
1091 INT32 Count;
1092 UINT32 CommandA;
1093 UINT32 CommandB;
1094 UINT16 LocalProtocol;
1095 UINT32 *LocalData;
1096 UINT16 PacketTag;
1097
1098 #if defined(EVAL_PERFORMANCE)
1099 UINT64 Perf;
1100 UINT64 StartClock;
1101 UINT64 EndClock;
1102
1103 Perf = GetPerformanceCounterProperties (NULL, NULL);
1104 StartClock = GetPerformanceCounter ();
1105 #endif
1106
1107 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
1108
1109 // Check preliminaries
1110 if ((Snp == NULL) || (Data == NULL)) {
1111 return EFI_INVALID_PARAMETER;
1112 }
1113
1114 // Check that driver was started and initialised
1115 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
1116 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
1117 return EFI_DEVICE_ERROR;
1118 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
1119 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
1120 return EFI_NOT_STARTED;
1121 }
1122
1123 // Ensure header is correct size if non-zero
1124 if (HdrSize) {
1125 if (HdrSize != Snp->Mode->MediaHeaderSize) {
1126 return EFI_INVALID_PARAMETER;
1127 }
1128
1129 if ((DstAddr == NULL) || (Protocol == NULL)) {
1130 return EFI_INVALID_PARAMETER;
1131 }
1132 }
1133
1134 //
1135 // Check validity of BufferSize
1136 //
1137 if (BuffSize < Snp->Mode->MediaHeaderSize) {
1138 return EFI_BUFFER_TOO_SMALL;
1139 }
1140
1141 // Before transmitting check the link status
1142 /*if (CheckLinkStatus (0, Snp) < 0) {
1143 return EFI_NOT_READY;
1144 }*/
1145
1146 // Get DATA FIFO free space in bytes
1147 TxFreeSpace = TxDataFreeSpace (0, Snp);
1148 if (TxFreeSpace < BuffSize) {
1149 return EFI_NOT_READY;
1150 }
1151
1152 // Get STATUS FIFO used space in bytes
1153 TxStatusSpace = TxStatusUsedSpace (0, Snp);
1154 if (TxStatusSpace > 500) {
1155 return EFI_NOT_READY;
1156 }
1157
1158 // If DstAddr is not provided, get it from Buffer (we trust that the caller
1159 // has provided a well-formed frame).
1160 if (DstAddr == NULL) {
1161 DstAddr = (EFI_MAC_ADDRESS *) Data;
1162 }
1163
1164 // Check for the nature of the frame
1165 if ((DstAddr->Addr[0] & 0x1) == 1) {
1166 LanDriver->Stats.TxMulticastFrames += 1;
1167 } else {
1168 LanDriver->Stats.TxUnicastFrames += 1;
1169 }
1170
1171 // Check if broadcast
1172 if (DstAddr->Addr[0] == 0xFF) {
1173 LanDriver->Stats.TxBroadcastFrames += 1;
1174 }
1175
1176 PacketTag = LanDriver->NextPacketTag;
1177 LanDriver->NextPacketTag++;
1178
1179 if (HdrSize) {
1180
1181 // Format pointer
1182 LocalData = (UINT32*) Data;
1183 LocalProtocol = *Protocol;
1184
1185 // Create first buffer to pass to controller (for the header)
1186 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);
1187 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);
1188
1189 // Write the commands first
1190 MmioWrite32 (LAN9118_TX_DATA, CommandA);
1191 MmioWrite32 (LAN9118_TX_DATA, CommandB);
1192
1193 // Write the destination address
1194 MmioWrite32 (LAN9118_TX_DATA,
1195 (DstAddr->Addr[0]) |
1196 (DstAddr->Addr[1] << 8) |
1197 (DstAddr->Addr[2] << 16) |
1198 (DstAddr->Addr[3] << 24)
1199 );
1200
1201 MmioWrite32 (LAN9118_TX_DATA,
1202 (DstAddr->Addr[4]) |
1203 (DstAddr->Addr[5] << 8) |
1204 (SrcAddr->Addr[0] << 16) | // Write the Source Address
1205 (SrcAddr->Addr[1] << 24)
1206 );
1207
1208 MmioWrite32 (LAN9118_TX_DATA,
1209 (SrcAddr->Addr[2]) |
1210 (SrcAddr->Addr[3] << 8) |
1211 (SrcAddr->Addr[4] << 16) |
1212 (SrcAddr->Addr[5] << 24)
1213 );
1214
1215 // Write the Protocol
1216 MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));
1217
1218 // Next buffer is the payload
1219 CommandA = TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize - HdrSize) | TX_CMD_A_COMPLETION_INT | TX_CMD_A_DATA_START_OFFSET (2); // 2 bytes beginning offset
1220
1221 // Write the commands
1222 MmioWrite32 (LAN9118_TX_DATA, CommandA);
1223 MmioWrite32 (LAN9118_TX_DATA, CommandB);
1224
1225 // Write the payload
1226 for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {
1227 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);
1228 }
1229 } else {
1230 // Format pointer
1231 LocalData = (UINT32*) Data;
1232
1233 // Create a buffer to pass to controller
1234 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;
1235 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);
1236
1237 // Write the commands first
1238 MmioWrite32 (LAN9118_TX_DATA, CommandA);
1239 MmioWrite32 (LAN9118_TX_DATA, CommandB);
1240
1241 // Write all the data
1242 for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {
1243 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);
1244 }
1245 }
1246
1247 // Save the address of the submitted packet so we can notify the consumer that
1248 // it has been sent in GetStatus. When the packet tag appears in the Tx Status
1249 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.
1250 LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;
1251
1252 #if defined(EVAL_PERFORMANCE)
1253 EndClock = GetPerformanceCounter ();
1254 DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));
1255 #endif
1256
1257 LanDriver->Stats.TxGoodFrames += 1;
1258
1259 return EFI_SUCCESS;
1260 }
1261
1262
1263 /*
1264 * UEFI Receive() function
1265 *
1266 */
1267 EFI_STATUS
1268 EFIAPI
1269 SnpReceive (
1270 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
1271 OUT UINTN *HdrSize OPTIONAL,
1272 IN OUT UINTN *BuffSize,
1273 OUT VOID *Data,
1274 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
1275 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,
1276 OUT UINT16 *Protocol OPTIONAL
1277 )
1278 {
1279 LAN9118_DRIVER *LanDriver;
1280 UINT32 RxFifoStatus;
1281 UINT32 NumPackets;
1282 UINT32 RxCfgValue;
1283 UINT32 PLength; // Packet length
1284 UINT32 ReadLimit;
1285 UINT32 Count;
1286 UINT32 Padding;
1287 UINT32 *RawData;
1288 EFI_MAC_ADDRESS Dst;
1289 EFI_MAC_ADDRESS Src;
1290 UINTN DroppedFrames;
1291 EFI_STATUS Status;
1292
1293 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
1294
1295 #if defined(EVAL_PERFORMANCE)
1296 UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);
1297 UINT64 StartClock = GetPerformanceCounter ();
1298 #endif
1299
1300 // Check preliminaries
1301 if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) {
1302 return EFI_INVALID_PARAMETER;
1303 }
1304
1305 // Check that driver was started and initialised
1306 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
1307 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
1308 return EFI_DEVICE_ERROR;
1309 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
1310 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
1311 return EFI_NOT_STARTED;
1312 }
1313
1314 // Count dropped frames
1315 DroppedFrames = MmioRead32 (LAN9118_RX_DROP);
1316 LanDriver->Stats.RxDroppedFrames += DroppedFrames;
1317
1318 NumPackets = RxStatusUsedSpace (0, Snp) / 4;
1319 if (!NumPackets) {
1320 return EFI_NOT_READY;
1321 }
1322
1323 // Read Rx Status (only if not empty)
1324 RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS);
1325 LanDriver->Stats.RxTotalFrames += 1;
1326
1327 // First check for errors
1328 if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||
1329 (RxFifoStatus & RXSTATUS_RXW_TO) ||
1330 (RxFifoStatus & RXSTATUS_FTL) ||
1331 (RxFifoStatus & RXSTATUS_LCOLL) ||
1332 (RxFifoStatus & RXSTATUS_LE) ||
1333 (RxFifoStatus & RXSTATUS_DB))
1334 {
1335 DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));
1336 return EFI_DEVICE_ERROR;
1337 }
1338
1339 // Check if we got a CRC error
1340 if (RxFifoStatus & RXSTATUS_CRC_ERROR) {
1341 DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));
1342 LanDriver->Stats.RxCrcErrorFrames += 1;
1343 LanDriver->Stats.RxDroppedFrames += 1;
1344 return EFI_DEVICE_ERROR;
1345 }
1346
1347 // Check if we got a runt frame
1348 if (RxFifoStatus & RXSTATUS_RUNT) {
1349 DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));
1350 LanDriver->Stats.RxUndersizeFrames += 1;
1351 LanDriver->Stats.RxDroppedFrames += 1;
1352 return EFI_DEVICE_ERROR;
1353 }
1354
1355 // Check filtering status for this packet
1356 if (RxFifoStatus & RXSTATUS_FILT_FAIL) {
1357 DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));
1358 // fast forward?
1359 }
1360
1361 // Check if we got a broadcast frame
1362 if (RxFifoStatus & RXSTATUS_BCF) {
1363 LanDriver->Stats.RxBroadcastFrames += 1;
1364 }
1365
1366 // Check if we got a multicast frame
1367 if (RxFifoStatus & RXSTATUS_MCF) {
1368 LanDriver->Stats.RxMulticastFrames += 1;
1369 }
1370
1371 // Check if we got a unicast frame
1372 if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {
1373 LanDriver->Stats.RxUnicastFrames += 1;
1374 }
1375
1376 // Get the received packet length
1377 PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);
1378 LanDriver->Stats.RxTotalBytes += (PLength - 4);
1379
1380 // Check buffer size
1381 if (*BuffSize < PLength) {
1382 *BuffSize = PLength;
1383 return EFI_BUFFER_TOO_SMALL;
1384 }
1385
1386 // If padding is applied, read more DWORDs
1387 if (PLength % 4) {
1388 Padding = 4 - (PLength % 4);
1389 ReadLimit = (PLength + Padding)/4;
1390 } else {
1391 ReadLimit = PLength/4;
1392 Padding = 0;
1393 }
1394
1395 // Set the amount of data to be transfered out of FIFO for THIS packet
1396 // This can be used to trigger an interrupt, and status can be checked
1397 RxCfgValue = MmioRead32 (LAN9118_RX_CFG);
1398 RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);
1399 RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);
1400
1401 // Set end alignment to 4-bytes
1402 RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);
1403 MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);
1404
1405 // Update buffer size
1406 *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as
1407 // 4 bytes longer than packet actually is, unless
1408 // packet is < 64 bytes
1409
1410 if (HdrSize != NULL)
1411 *HdrSize = Snp->Mode->MediaHeaderSize;
1412
1413 // Format the pointer
1414 RawData = (UINT32*)Data;
1415
1416 // Read Rx Packet
1417 for (Count = 0; Count < ReadLimit; Count++) {
1418 RawData[Count] = MmioRead32 (LAN9118_RX_DATA);
1419 }
1420
1421 // Check for Rx errors (worst possible error)
1422 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {
1423 DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));
1424
1425 // Initiate a software reset
1426 Status = SoftReset (0, Snp);
1427 if (EFI_ERROR (Status)) {
1428 DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));
1429 return EFI_DEVICE_ERROR;
1430 }
1431
1432 // Acknowledge the RXE
1433 MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);
1434 gBS->Stall (LAN9118_STALL);
1435
1436 // Restart the rx (and do not clear FIFO)
1437 StartRx (0, Snp);
1438
1439 // Say that command could not be sent
1440 return EFI_DEVICE_ERROR;
1441 }
1442
1443 // Get the destination address
1444 if (DstAddr != NULL) {
1445 Dst.Addr[0] = (RawData[0] & 0xFF);
1446 Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;
1447 Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;
1448 Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;
1449 Dst.Addr[4] = (RawData[1] & 0xFF);
1450 Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;
1451 CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);
1452 }
1453
1454 // Get the source address
1455 if (SrcAddr != NULL) {
1456 Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;
1457 Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;
1458 Src.Addr[2] = (RawData[2] & 0xFF);
1459 Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;
1460 Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;
1461 Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;
1462 CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN);
1463 }
1464
1465 // Get the protocol
1466 if (Protocol != NULL) {
1467 *Protocol = NTOHS (RawData[3] & 0xFFFF);
1468 }
1469
1470 #if defined(EVAL_PERFORMANCE)
1471 UINT64 EndClock = GetPerformanceCounter ();
1472 DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));
1473 #endif
1474
1475 LanDriver->Stats.RxGoodFrames += 1;
1476
1477 return EFI_SUCCESS;
1478 }