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