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