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