]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c
EmbeddedPkg/Lan9118Dxe: Switch back the driver in stopped state after shutdown
[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 // Back to the started and thus not initialized state
493 Snp->Mode->State = EfiSimpleNetworkStarted;
494
495 return EFI_SUCCESS;
496 }
497
498 /**
499 Enable and/or disable the receive filters of the LAN9118
500
501 Please refer to the UEFI specification for the precedence rules among the
502 Enable, Disable and ResetMCastFilter parameters.
503
504 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
505 instance.
506 @param[in] Enable A bit mask of receive filters to enable.
507 @param[in] Disable A bit mask of receive filters to disable.
508 @param[in] ResetMCastFilter Set to TRUE to reset the contents of the multicast
509 receive filters on the network interface to
510 their default values.
511 @param[in] MCastFilterCnt Number of multicast HW MAC addresses in the new
512 MCastFilter list. This value must be less than or
513 equal to the MCastFilterCnt field of
514 EFI_SIMPLE_NETWORK_MODE. This field is optional if
515 ResetMCastFilter is TRUE.
516 @param[in] MCastFilter A pointer to a list of new multicast receive
517 filter HW MAC addresses. This list will replace
518 any existing multicast HW MAC address list. This
519 field is optional if ResetMCastFilter is TRUE.
520
521 @retval EFI_SUCCESS The receive filters of the LAN9118 were updated.
522 @retval EFI_NOT_STARTED The LAN9118 has not been started.
523 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :
524 . This is NULL
525 . Multicast is being enabled (the
526 EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is set in
527 Enable, it is not set in Disable, and ResetMCastFilter
528 is FALSE) and MCastFilterCount is zero.
529 . Multicast is being enabled and MCastFilterCount is
530 greater than Snp->Mode->MaxMCastFilterCount.
531 . Multicast is being enabled and MCastFilter is NULL
532 . Multicast is being enabled and one or more of the
533 addresses in the MCastFilter list are not valid
534 multicast MAC addresses.
535 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.
536
537 **/
538 EFI_STATUS
539 EFIAPI
540 SnpReceiveFilters (
541 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
542 IN UINT32 Enable,
543 IN UINT32 Disable,
544 IN BOOLEAN ResetMCastFilter,
545 IN UINTN MCastFilterCnt OPTIONAL,
546 IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
547 )
548 {
549 EFI_SIMPLE_NETWORK_MODE *Mode;
550 UINT32 MultHashTableHigh;
551 UINT32 MultHashTableLow;
552 UINT32 Count;
553 UINT32 Crc;
554 UINT8 HashValue;
555 UINT32 MacCSRValue;
556 EFI_MAC_ADDRESS *Mac;
557
558 // Check Snp Instance
559 if (Snp == NULL) {
560 return EFI_INVALID_PARAMETER;
561 }
562 Mode = Snp->Mode;
563
564 // Check that driver was started and initialised
565 if (Mode->State == EfiSimpleNetworkStarted) {
566 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
567 return EFI_DEVICE_ERROR;
568 } else if (Mode->State == EfiSimpleNetworkStopped) {
569 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
570 return EFI_NOT_STARTED;
571 }
572
573 if ((Enable & (~Mode->ReceiveFilterMask)) ||
574 (Disable & (~Mode->ReceiveFilterMask)) ) {
575 return EFI_INVALID_PARAMETER;
576 }
577
578 //
579 // Check the validity of the multicast setting and compute the
580 // hash values of the multicast mac addresses to listen to.
581 //
582
583 MultHashTableHigh = 0;
584 MultHashTableLow = 0;
585 if ((!ResetMCastFilter) &&
586 ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) == 0) &&
587 ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) ) {
588 if ((MCastFilterCnt == 0) ||
589 (MCastFilterCnt > Mode->MaxMCastFilterCount) ||
590 (MCastFilter == NULL) ) {
591 return EFI_INVALID_PARAMETER;
592 }
593 //
594 // Check the validity of all multicast addresses before to change
595 // anything.
596 //
597 for (Count = 0; Count < MCastFilterCnt; Count++) {
598 if ((MCastFilter[Count].Addr[0] & 1) == 0) {
599 return EFI_INVALID_PARAMETER;
600 }
601 }
602
603 //
604 // Go through each filter address and set appropriate bits on hash table
605 //
606 for (Count = 0; Count < MCastFilterCnt; Count++) {
607 Mac = &(MCastFilter[Count]);
608 CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS));
609
610 Crc = GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN);
611 //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired
612
613 //
614 // The most significant 6 bits of the MAC address CRC constitute the hash
615 // value of the MAC address.
616 //
617 HashValue = (Crc >> 26) & 0x3F;
618
619 // Select hashlow register if MSB is not set
620 if ((HashValue & 0x20) == 0) {
621 MultHashTableLow |= (1 << HashValue);
622 } else {
623 MultHashTableHigh |= (1 << (HashValue & 0x1F));
624 }
625 }
626 Mode->MCastFilterCount = MCastFilterCnt;
627 } else if (ResetMCastFilter) {
628 Mode->MCastFilterCount = 0;
629 } else {
630 MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL);
631 MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH);
632 }
633
634 //
635 // Write the mask of the selected hash values for the multicast filtering.
636 // The two masks are set to zero if the multicast filtering is not enabled.
637 //
638 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow);
639 IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh);
640
641 // Read MAC controller
642 MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
643
644 // Set the options for the MAC_CSR
645 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {
646 StartRx (0, Snp);
647 DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n"));
648 }
649
650 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) {
651 StopRx (0, Snp);
652 DEBUG ((DEBUG_NET, "Disabling Unicast Frame Reception\n"));
653 }
654
655 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {
656 MacCSRValue |= MACCR_HPFILT;
657 DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n"));
658 }
659
660 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) {
661 MacCSRValue &= ~MACCR_HPFILT;
662 DEBUG ((DEBUG_NET, "Disabling Multicast Frame Reception\n"));
663 }
664
665 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {
666 MacCSRValue &= ~(MACCR_BCAST);
667 DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n"));
668 }
669
670 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) {
671 MacCSRValue |= MACCR_BCAST;
672 DEBUG ((DEBUG_NET, "Disabling Broadcast Frame Reception\n"));
673 }
674
675 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {
676 MacCSRValue |= MACCR_PRMS;
677 DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n"));
678 }
679
680 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) {
681 MacCSRValue &= ~MACCR_PRMS;
682 DEBUG ((DEBUG_NET, "Disabling Promiscuous Mode\n"));
683 }
684
685 if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {
686 MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS);
687 DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n"));
688 }
689
690 if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {
691 MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS);
692 DEBUG ((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n"));
693 }
694
695 // Write the options to the MAC_CSR
696 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue);
697 gBS->Stall (LAN9118_STALL);
698
699 return EFI_SUCCESS;
700 }
701
702 /**
703 Modify of reset the current station address
704
705 @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
706 instance.
707 @param[in] Reset Flag used to reset the station address to the
708 LAN9118's permanent address.
709 @param[in] New New station address to be used for the network interface.
710
711 @retval EFI_SUCCESS The LAN9118's station address was updated.
712 @retval EFI_NOT_STARTED The LAN9118 has not been started.
713 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE :
714 . The "New" station address is invalid.
715 . "Reset" is FALSE and "New" is NULL.
716 @retval EFI_DEVICE_ERROR The LAN9118 has been started but not initialized.
717
718 **/
719 EFI_STATUS
720 EFIAPI
721 SnpStationAddress (
722 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
723 IN BOOLEAN Reset,
724 IN EFI_MAC_ADDRESS *New
725 )
726 {
727 UINT32 Count;
728 UINT8 PermAddr[NET_ETHER_ADDR_LEN];
729
730 DEBUG ((DEBUG_NET, "SnpStationAddress()\n"));
731
732 // Check Snp instance
733 if (Snp == NULL) {
734 return EFI_INVALID_PARAMETER;
735 }
736
737 // Check that driver was started and initialised
738 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
739 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
740 return EFI_DEVICE_ERROR;
741 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
742 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
743 return EFI_NOT_STARTED;
744 }
745
746 // Get the Permanent MAC address if need reset
747 if (Reset) {
748 // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0
749 if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) {
750 for (Count = 0; Count < NET_ETHER_ADDR_LEN; Count++) {
751 PermAddr[Count] = IndirectEEPROMRead32 (Count + 1);
752 }
753 New = (EFI_MAC_ADDRESS *) PermAddr;
754 Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp);
755 } else {
756 DEBUG ((EFI_D_ERROR, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n"));
757 New = (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddress));
758 }
759 } else {
760 // Otherwise use the specified new MAC address
761 if (New == NULL) {
762 return EFI_INVALID_PARAMETER;
763 }
764 //
765 // If it is a multicast address, it is not valid.
766 //
767 if (New->Addr[0] & 0x01) {
768 return EFI_INVALID_PARAMETER;
769 }
770 }
771
772 // Write address
773 Lan9118SetMacAddress (New, Snp);
774
775 return EFI_SUCCESS;
776 }
777
778 /*
779 * UEFI Statistics() function
780 *
781 */
782 EFI_STATUS
783 EFIAPI
784 SnpStatistics (
785 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
786 IN BOOLEAN Reset,
787 IN OUT UINTN *StatSize,
788 OUT EFI_NETWORK_STATISTICS *Statistics
789 )
790 {
791 LAN9118_DRIVER *LanDriver;
792 EFI_STATUS Status;
793
794 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
795
796 DEBUG ((DEBUG_NET, "SnpStatistics()\n"));
797
798 // Check Snp instance
799 if (Snp == NULL) {
800 return EFI_INVALID_PARAMETER;
801 }
802
803 // Check that driver was started and initialised
804 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
805 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
806 return EFI_DEVICE_ERROR;
807 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
808 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
809 return EFI_NOT_STARTED;
810 }
811
812 //
813 // Do a reset if required. It is not clearly stated in the UEFI specification
814 // whether the reset has to be done before to copy the statistics in "Statictics"
815 // or after. It is a bit strange to do it before but that is what is expected by
816 // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0x8c,0x89,
817 // 0x54,0x7e,0x4f,0xad,0x4f,0x24".
818 //
819 if (Reset) {
820 ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));
821 }
822
823 Status = EFI_SUCCESS;
824 if (StatSize == NULL) {
825 if (Statistics != NULL) {
826 return EFI_INVALID_PARAMETER;
827 }
828 } else {
829 if (Statistics == NULL) {
830 Status = EFI_BUFFER_TOO_SMALL;
831 } else {
832 // Fill in the statistics
833 CopyMem (
834 Statistics, &LanDriver->Stats,
835 MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS))
836 );
837 if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) {
838 Status = EFI_BUFFER_TOO_SMALL;
839 }
840 }
841 *StatSize = sizeof (EFI_NETWORK_STATISTICS);
842 }
843
844 return Status;
845 }
846
847 /*
848 * UEFI MCastIPtoMAC() function
849 *
850 */
851 EFI_STATUS
852 EFIAPI
853 SnpMcastIptoMac (
854 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
855 IN BOOLEAN IsIpv6,
856 IN EFI_IP_ADDRESS *Ip,
857 OUT EFI_MAC_ADDRESS *McastMac
858 )
859 {
860 DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n"));
861
862 // Check Snp instance
863 if (Snp == NULL) {
864 return EFI_INVALID_PARAMETER;
865 }
866
867 // Check that driver was started and initialised
868 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
869 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
870 return EFI_DEVICE_ERROR;
871 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
872 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
873 return EFI_NOT_STARTED;
874 }
875
876 // Check parameters
877 if ((McastMac == NULL) || (Ip == NULL)) {
878 return EFI_INVALID_PARAMETER;
879 }
880
881 // Make sure MAC address is empty
882 ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));
883
884 // If we need ipv4 address
885 if (!IsIpv6) {
886 // Most significant 25 bits of a multicast HW address are set.
887 // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112)
888 McastMac->Addr[0] = 0x01;
889 McastMac->Addr[1] = 0x00;
890 McastMac->Addr[2] = 0x5E;
891
892 // Lower 23 bits from ipv4 address
893 McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0)
894 McastMac->Addr[4] = Ip->v4.Addr[2];
895 McastMac->Addr[5] = Ip->v4.Addr[3];
896 } else {
897 // Most significant 16 bits of multicast v6 HW address are set
898 // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464)
899 McastMac->Addr[0] = 0x33;
900 McastMac->Addr[1] = 0x33;
901
902 // lower four octets are taken from ipv6 address
903 McastMac->Addr[2] = Ip->v6.Addr[8];
904 McastMac->Addr[3] = Ip->v6.Addr[9];
905 McastMac->Addr[4] = Ip->v6.Addr[10];
906 McastMac->Addr[5] = Ip->v6.Addr[11];
907 }
908
909 return EFI_SUCCESS;
910 }
911
912 /*
913 * UEFI NvData() function
914 *
915 */
916 EFI_STATUS
917 EFIAPI
918 SnpNvData (
919 IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,
920 IN BOOLEAN read_write,
921 IN UINTN offset,
922 IN UINTN buff_size,
923 IN OUT VOID *data
924 )
925 {
926 DEBUG ((DEBUG_NET, "SnpNvData()\n"));
927
928 return EFI_UNSUPPORTED;
929 }
930
931
932 /*
933 * UEFI GetStatus () function
934 *
935 */
936 EFI_STATUS
937 EFIAPI
938 SnpGetStatus (
939 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
940 OUT UINT32 *IrqStat OPTIONAL,
941 OUT VOID **TxBuff OPTIONAL
942 )
943 {
944 UINT32 FifoInt;
945 EFI_STATUS Status;
946 UINTN NumTxStatusEntries;
947 UINT32 TxStatus;
948 UINT16 PacketTag;
949 UINT32 Interrupts;
950 LAN9118_DRIVER *LanDriver;
951
952 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
953
954 // Check preliminaries
955 if (Snp == NULL) {
956 return EFI_INVALID_PARAMETER;
957 }
958
959 // Check that driver was started and initialised
960 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
961 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
962 return EFI_DEVICE_ERROR;
963 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
964 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
965 return EFI_NOT_STARTED;
966 }
967
968 // Check and acknowledge TX Status interrupt (this will happen if the
969 // consumer of SNP does not call GetStatus.)
970 // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we
971 // should check for it and dump the TX Status FIFO.
972 FifoInt = MmioRead32 (LAN9118_FIFO_INT);
973
974 // Clear the TX Status FIFO Overflow
975 if ((FifoInt & INSTS_TXSO) == 0) {
976 FifoInt |= INSTS_TXSO;
977 MmioWrite32 (LAN9118_FIFO_INT, FifoInt);
978 }
979
980 // Read interrupt status if IrqStat is not NULL
981 if (IrqStat != NULL) {
982
983 // Check for receive interrupt
984 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO
985 *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
986 MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL);
987 } else {
988 *IrqStat &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
989 }
990
991 // Check for transmit interrupt
992 if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) {
993 *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
994 MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL);
995 } else {
996 *IrqStat &= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
997 }
998
999 // Check for software interrupt
1000 if (MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) {
1001 *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;
1002 MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT);
1003 } else {
1004 *IrqStat &= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT;
1005 }
1006 }
1007
1008 // Check Status of transmitted packets
1009 // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex)
1010
1011 NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK;
1012 if (NumTxStatusEntries > 0) {
1013 TxStatus = MmioRead32 (LAN9118_TX_STATUS);
1014 PacketTag = TxStatus >> 16;
1015 TxStatus = TxStatus & 0xFFFF;
1016 if ((TxStatus & TXSTATUS_ES) && (TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA))) {
1017 DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus));
1018 if (TxStatus & TXSTATUS_NO_CA) {
1019 DEBUG ((EFI_D_ERROR, "- No carrier\n"));
1020 }
1021 if (TxStatus & TXSTATUS_DEF) {
1022 DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n"));
1023 }
1024 if (TxStatus & TXSTATUS_EDEF) {
1025 DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n"));
1026 }
1027 if (TxStatus & TXSTATUS_ECOLL) {
1028 DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n"));
1029 }
1030 if (TxStatus & TXSTATUS_LCOLL) {
1031 DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n"));
1032 }
1033 if (TxStatus & TXSTATUS_LOST_CA) {
1034 DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n"));
1035 }
1036 return EFI_DEVICE_ERROR;
1037 } else if (TxBuff != NULL) {
1038 LanDriver->Stats.TxTotalFrames += 1;
1039 *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES];
1040 }
1041 }
1042
1043 // Check for a TX Error interrupt
1044 Interrupts = MmioRead32 (LAN9118_INT_STS);
1045 if (Interrupts & INSTS_TXE) {
1046 DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting..."));
1047
1048 // Initiate a software reset
1049 Status = SoftReset (0, Snp);
1050 if (EFI_ERROR (Status)) {
1051 DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n"));
1052 return EFI_DEVICE_ERROR;
1053 }
1054
1055 // Acknowledge the TXE
1056 MmioWrite32 (LAN9118_INT_STS, INSTS_TXE);
1057 gBS->Stall (LAN9118_STALL);
1058
1059 // Restart the transmitter
1060 StartTx (START_TX_MAC | START_TX_CFG, Snp);
1061 }
1062
1063 // Update the media status
1064 Status = CheckLinkStatus (0, Snp);
1065 if (EFI_ERROR(Status)) {
1066 Snp->Mode->MediaPresent = FALSE;
1067 } else {
1068 Snp->Mode->MediaPresent = TRUE;
1069 }
1070
1071 return EFI_SUCCESS;
1072 }
1073
1074
1075 /*
1076 * UEFI Transmit() function
1077 *
1078 */
1079 EFI_STATUS
1080 EFIAPI
1081 SnpTransmit (
1082 IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
1083 IN UINTN HdrSize,
1084 IN UINTN BuffSize,
1085 IN VOID* Data,
1086 IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
1087 IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,
1088 IN UINT16 *Protocol OPTIONAL
1089 )
1090 {
1091 LAN9118_DRIVER *LanDriver;
1092 UINT32 TxFreeSpace;
1093 UINT32 TxStatusSpace;
1094 INT32 Count;
1095 UINT32 CommandA;
1096 UINT32 CommandB;
1097 UINT16 LocalProtocol;
1098 UINT32 *LocalData;
1099 UINT16 PacketTag;
1100
1101 #if defined(EVAL_PERFORMANCE)
1102 UINT64 Perf;
1103 UINT64 StartClock;
1104 UINT64 EndClock;
1105
1106 Perf = GetPerformanceCounterProperties (NULL, NULL);
1107 StartClock = GetPerformanceCounter ();
1108 #endif
1109
1110 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
1111
1112 // Check preliminaries
1113 if ((Snp == NULL) || (Data == NULL)) {
1114 return EFI_INVALID_PARAMETER;
1115 }
1116
1117 // Check that driver was started and initialised
1118 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
1119 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
1120 return EFI_DEVICE_ERROR;
1121 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
1122 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
1123 return EFI_NOT_STARTED;
1124 }
1125
1126 // Ensure header is correct size if non-zero
1127 if (HdrSize) {
1128 if (HdrSize != Snp->Mode->MediaHeaderSize) {
1129 return EFI_INVALID_PARAMETER;
1130 }
1131
1132 if ((DstAddr == NULL) || (Protocol == NULL)) {
1133 return EFI_INVALID_PARAMETER;
1134 }
1135 }
1136
1137 //
1138 // Check validity of BufferSize
1139 //
1140 if (BuffSize < Snp->Mode->MediaHeaderSize) {
1141 return EFI_BUFFER_TOO_SMALL;
1142 }
1143
1144 // Before transmitting check the link status
1145 /*if (CheckLinkStatus (0, Snp) < 0) {
1146 return EFI_NOT_READY;
1147 }*/
1148
1149 // Get DATA FIFO free space in bytes
1150 TxFreeSpace = TxDataFreeSpace (0, Snp);
1151 if (TxFreeSpace < BuffSize) {
1152 return EFI_NOT_READY;
1153 }
1154
1155 // Get STATUS FIFO used space in bytes
1156 TxStatusSpace = TxStatusUsedSpace (0, Snp);
1157 if (TxStatusSpace > 500) {
1158 return EFI_NOT_READY;
1159 }
1160
1161 // If DstAddr is not provided, get it from Buffer (we trust that the caller
1162 // has provided a well-formed frame).
1163 if (DstAddr == NULL) {
1164 DstAddr = (EFI_MAC_ADDRESS *) Data;
1165 }
1166
1167 // Check for the nature of the frame
1168 if ((DstAddr->Addr[0] & 0x1) == 1) {
1169 LanDriver->Stats.TxMulticastFrames += 1;
1170 } else {
1171 LanDriver->Stats.TxUnicastFrames += 1;
1172 }
1173
1174 // Check if broadcast
1175 if (DstAddr->Addr[0] == 0xFF) {
1176 LanDriver->Stats.TxBroadcastFrames += 1;
1177 }
1178
1179 PacketTag = LanDriver->NextPacketTag;
1180 LanDriver->NextPacketTag++;
1181
1182 if (HdrSize) {
1183
1184 // Format pointer
1185 LocalData = (UINT32*) Data;
1186 LocalProtocol = *Protocol;
1187
1188 // Create first buffer to pass to controller (for the header)
1189 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize);
1190 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);
1191
1192 // Write the commands first
1193 MmioWrite32 (LAN9118_TX_DATA, CommandA);
1194 MmioWrite32 (LAN9118_TX_DATA, CommandB);
1195
1196 // Write the destination address
1197 MmioWrite32 (LAN9118_TX_DATA,
1198 (DstAddr->Addr[0]) |
1199 (DstAddr->Addr[1] << 8) |
1200 (DstAddr->Addr[2] << 16) |
1201 (DstAddr->Addr[3] << 24)
1202 );
1203
1204 MmioWrite32 (LAN9118_TX_DATA,
1205 (DstAddr->Addr[4]) |
1206 (DstAddr->Addr[5] << 8) |
1207 (SrcAddr->Addr[0] << 16) | // Write the Source Address
1208 (SrcAddr->Addr[1] << 24)
1209 );
1210
1211 MmioWrite32 (LAN9118_TX_DATA,
1212 (SrcAddr->Addr[2]) |
1213 (SrcAddr->Addr[3] << 8) |
1214 (SrcAddr->Addr[4] << 16) |
1215 (SrcAddr->Addr[5] << 24)
1216 );
1217
1218 // Write the Protocol
1219 MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol)));
1220
1221 // Next buffer is the payload
1222 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
1223
1224 // Write the commands
1225 MmioWrite32 (LAN9118_TX_DATA, CommandA);
1226 MmioWrite32 (LAN9118_TX_DATA, CommandB);
1227
1228 // Write the payload
1229 for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) {
1230 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]);
1231 }
1232 } else {
1233 // Format pointer
1234 LocalData = (UINT32*) Data;
1235
1236 // Create a buffer to pass to controller
1237 CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT;
1238 CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize);
1239
1240 // Write the commands first
1241 MmioWrite32 (LAN9118_TX_DATA, CommandA);
1242 MmioWrite32 (LAN9118_TX_DATA, CommandB);
1243
1244 // Write all the data
1245 for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) {
1246 MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]);
1247 }
1248 }
1249
1250 // Save the address of the submitted packet so we can notify the consumer that
1251 // it has been sent in GetStatus. When the packet tag appears in the Tx Status
1252 // Fifo, we will return Buffer in the TxBuff parameter of GetStatus.
1253 LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data;
1254
1255 #if defined(EVAL_PERFORMANCE)
1256 EndClock = GetPerformanceCounter ();
1257 DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));
1258 #endif
1259
1260 LanDriver->Stats.TxGoodFrames += 1;
1261
1262 return EFI_SUCCESS;
1263 }
1264
1265
1266 /*
1267 * UEFI Receive() function
1268 *
1269 */
1270 EFI_STATUS
1271 EFIAPI
1272 SnpReceive (
1273 IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
1274 OUT UINTN *HdrSize OPTIONAL,
1275 IN OUT UINTN *BuffSize,
1276 OUT VOID *Data,
1277 OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
1278 OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,
1279 OUT UINT16 *Protocol OPTIONAL
1280 )
1281 {
1282 LAN9118_DRIVER *LanDriver;
1283 UINT32 RxFifoStatus;
1284 UINT32 NumPackets;
1285 UINT32 RxCfgValue;
1286 UINT32 PLength; // Packet length
1287 UINT32 ReadLimit;
1288 UINT32 Count;
1289 UINT32 Padding;
1290 UINT32 *RawData;
1291 EFI_MAC_ADDRESS Dst;
1292 EFI_MAC_ADDRESS Src;
1293 UINTN DroppedFrames;
1294 EFI_STATUS Status;
1295
1296 LanDriver = INSTANCE_FROM_SNP_THIS (Snp);
1297
1298 #if defined(EVAL_PERFORMANCE)
1299 UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL);
1300 UINT64 StartClock = GetPerformanceCounter ();
1301 #endif
1302
1303 // Check preliminaries
1304 if ((Snp == NULL) || (Data == NULL) || (BuffSize == NULL)) {
1305 return EFI_INVALID_PARAMETER;
1306 }
1307
1308 // Check that driver was started and initialised
1309 if (Snp->Mode->State == EfiSimpleNetworkStarted) {
1310 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n"));
1311 return EFI_DEVICE_ERROR;
1312 } else if (Snp->Mode->State == EfiSimpleNetworkStopped) {
1313 DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n"));
1314 return EFI_NOT_STARTED;
1315 }
1316
1317 // Count dropped frames
1318 DroppedFrames = MmioRead32 (LAN9118_RX_DROP);
1319 LanDriver->Stats.RxDroppedFrames += DroppedFrames;
1320
1321 NumPackets = RxStatusUsedSpace (0, Snp) / 4;
1322 if (!NumPackets) {
1323 return EFI_NOT_READY;
1324 }
1325
1326 // Read Rx Status (only if not empty)
1327 RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS);
1328 LanDriver->Stats.RxTotalFrames += 1;
1329
1330 // First check for errors
1331 if ((RxFifoStatus & RXSTATUS_MII_ERROR) ||
1332 (RxFifoStatus & RXSTATUS_RXW_TO) ||
1333 (RxFifoStatus & RXSTATUS_FTL) ||
1334 (RxFifoStatus & RXSTATUS_LCOLL) ||
1335 (RxFifoStatus & RXSTATUS_LE) ||
1336 (RxFifoStatus & RXSTATUS_DB))
1337 {
1338 DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n"));
1339 return EFI_DEVICE_ERROR;
1340 }
1341
1342 // Check if we got a CRC error
1343 if (RxFifoStatus & RXSTATUS_CRC_ERROR) {
1344 DEBUG ((EFI_D_WARN, "Warning: Crc Error\n"));
1345 LanDriver->Stats.RxCrcErrorFrames += 1;
1346 LanDriver->Stats.RxDroppedFrames += 1;
1347 return EFI_DEVICE_ERROR;
1348 }
1349
1350 // Check if we got a runt frame
1351 if (RxFifoStatus & RXSTATUS_RUNT) {
1352 DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n"));
1353 LanDriver->Stats.RxUndersizeFrames += 1;
1354 LanDriver->Stats.RxDroppedFrames += 1;
1355 return EFI_DEVICE_ERROR;
1356 }
1357
1358 // Check filtering status for this packet
1359 if (RxFifoStatus & RXSTATUS_FILT_FAIL) {
1360 DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n"));
1361 // fast forward?
1362 }
1363
1364 // Check if we got a broadcast frame
1365 if (RxFifoStatus & RXSTATUS_BCF) {
1366 LanDriver->Stats.RxBroadcastFrames += 1;
1367 }
1368
1369 // Check if we got a multicast frame
1370 if (RxFifoStatus & RXSTATUS_MCF) {
1371 LanDriver->Stats.RxMulticastFrames += 1;
1372 }
1373
1374 // Check if we got a unicast frame
1375 if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) {
1376 LanDriver->Stats.RxUnicastFrames += 1;
1377 }
1378
1379 // Get the received packet length
1380 PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus);
1381 LanDriver->Stats.RxTotalBytes += (PLength - 4);
1382
1383 // Check buffer size
1384 if (*BuffSize < PLength) {
1385 *BuffSize = PLength;
1386 return EFI_BUFFER_TOO_SMALL;
1387 }
1388
1389 // If padding is applied, read more DWORDs
1390 if (PLength % 4) {
1391 Padding = 4 - (PLength % 4);
1392 ReadLimit = (PLength + Padding)/4;
1393 } else {
1394 ReadLimit = PLength/4;
1395 Padding = 0;
1396 }
1397
1398 // Set the amount of data to be transfered out of FIFO for THIS packet
1399 // This can be used to trigger an interrupt, and status can be checked
1400 RxCfgValue = MmioRead32 (LAN9118_RX_CFG);
1401 RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK);
1402 RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit);
1403
1404 // Set end alignment to 4-bytes
1405 RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK);
1406 MmioWrite32 (LAN9118_RX_CFG, RxCfgValue);
1407
1408 // Update buffer size
1409 *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as
1410 // 4 bytes longer than packet actually is, unless
1411 // packet is < 64 bytes
1412
1413 if (HdrSize != NULL)
1414 *HdrSize = Snp->Mode->MediaHeaderSize;
1415
1416 // Format the pointer
1417 RawData = (UINT32*)Data;
1418
1419 // Read Rx Packet
1420 for (Count = 0; Count < ReadLimit; Count++) {
1421 RawData[Count] = MmioRead32 (LAN9118_RX_DATA);
1422 }
1423
1424 // Check for Rx errors (worst possible error)
1425 if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) {
1426 DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n"));
1427
1428 // Initiate a software reset
1429 Status = SoftReset (0, Snp);
1430 if (EFI_ERROR (Status)) {
1431 DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n"));
1432 return EFI_DEVICE_ERROR;
1433 }
1434
1435 // Acknowledge the RXE
1436 MmioWrite32 (LAN9118_INT_STS, INSTS_RXE);
1437 gBS->Stall (LAN9118_STALL);
1438
1439 // Restart the rx (and do not clear FIFO)
1440 StartRx (0, Snp);
1441
1442 // Say that command could not be sent
1443 return EFI_DEVICE_ERROR;
1444 }
1445
1446 // Get the destination address
1447 if (DstAddr != NULL) {
1448 Dst.Addr[0] = (RawData[0] & 0xFF);
1449 Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8;
1450 Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16;
1451 Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24;
1452 Dst.Addr[4] = (RawData[1] & 0xFF);
1453 Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8;
1454 CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN);
1455 }
1456
1457 // Get the source address
1458 if (SrcAddr != NULL) {
1459 Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16;
1460 Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24;
1461 Src.Addr[2] = (RawData[2] & 0xFF);
1462 Src.Addr[3] = (RawData[2] & 0xFF00) >> 8;
1463 Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16;
1464 Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24;
1465 CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN);
1466 }
1467
1468 // Get the protocol
1469 if (Protocol != NULL) {
1470 *Protocol = NTOHS (RawData[3] & 0xFFFF);
1471 }
1472
1473 #if defined(EVAL_PERFORMANCE)
1474 UINT64 EndClock = GetPerformanceCounter ();
1475 DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf));
1476 #endif
1477
1478 LanDriver->Stats.RxGoodFrames += 1;
1479
1480 return EFI_SUCCESS;
1481 }