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