Home | History | Annotate | Download | only in Lan9118Dxe
      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 STATIC EFI_MAC_ADDRESS mZeroMac = { { 0 } };
     18 
     19 /**
     20   This internal function reverses bits for 32bit data.
     21 
     22   @param  Value                 The data to be reversed.
     23 
     24   @return                       Data reversed.
     25 
     26 **/
     27 UINT32
     28 ReverseBits (
     29   UINT32  Value
     30   )
     31 {
     32   UINTN   Index;
     33   UINT32  NewValue;
     34 
     35   NewValue = 0;
     36   for (Index = 0; Index < 32; Index++) {
     37     if ((Value & (1 << Index)) != 0) {
     38       NewValue = NewValue | (1 << (31 - Index));
     39     }
     40   }
     41 
     42   return NewValue;
     43 }
     44 
     45 /*
     46 **  Create Ethernet CRC
     47 **
     48 **  INFO USED:
     49 **    1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check
     50 **
     51 **    2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html
     52 **
     53 **    3: http://en.wikipedia.org/wiki/Computation_of_CRC
     54 */
     55 UINT32
     56 GenEtherCrc32 (
     57   IN    EFI_MAC_ADDRESS *Mac,
     58   IN    UINT32 AddrLen
     59   )
     60 {
     61   INT32 Iter;
     62   UINT32 Remainder;
     63   UINT8 *Ptr;
     64 
     65   Iter = 0;
     66   Remainder = 0xFFFFFFFF;    // 0xFFFFFFFF is standard seed for Ethernet
     67 
     68   // Convert Mac Address to array of bytes
     69   Ptr = (UINT8*)Mac;
     70 
     71   // Generate the Crc bit-by-bit (LSB first)
     72   while (AddrLen--) {
     73     Remainder ^= *Ptr++;
     74     for (Iter = 0;Iter < 8;Iter++) {
     75       // Check if exponent is set
     76       if (Remainder & 1) {
     77         Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL;
     78       } else {
     79         Remainder = (Remainder >> 1) ^ 0;
     80       }
     81     }
     82   }
     83 
     84   // Reverse the bits before returning (to Big Endian)
     85   //TODO: Need to be reviewed. Do we want to do a bit reverse or a byte reverse (in this case use SwapBytes32())
     86   return ReverseBits (Remainder);
     87 }
     88 
     89 // Function to read from MAC indirect registers
     90 UINT32
     91 IndirectMACRead32 (
     92   UINT32 Index
     93   )
     94 {
     95   UINT32 MacCSR;
     96 
     97   // Check index is in the range
     98   ASSERT(Index <= 12);
     99 
    100   // Wait until CSR busy bit is cleared
    101   while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
    102 
    103   // Set CSR busy bit to ensure read will occur
    104   // Set the R/W bit to indicate we are reading
    105   // Set the index of CSR Address to access desired register
    106   MacCSR = MAC_CSR_BUSY | MAC_CSR_READ | MAC_CSR_ADDR(Index);
    107 
    108   // Write to the register
    109   MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR);
    110 
    111   // Wait until CSR busy bit is cleared
    112   while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
    113 
    114   // Now read from data register to get read value
    115   return MmioRead32 (LAN9118_MAC_CSR_DATA);
    116 }
    117 
    118 // Function to write to MAC indirect registers
    119 UINT32
    120 IndirectMACWrite32 (
    121   UINT32 Index,
    122   UINT32 Value
    123   )
    124 {
    125   UINT32 ValueWritten;
    126   UINT32 MacCSR;
    127 
    128   // Check index is in the range
    129   ASSERT(Index <= 12);
    130 
    131   // Wait until CSR busy bit is cleared
    132   while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
    133 
    134   // Set CSR busy bit to ensure read will occur
    135   // Set the R/W bit to indicate we are writing
    136   // Set the index of CSR Address to access desired register
    137   MacCSR = MAC_CSR_BUSY | MAC_CSR_WRITE | MAC_CSR_ADDR(Index);
    138 
    139   // Now write the value to the register before issuing the write command
    140   ValueWritten = MmioWrite32 (LAN9118_MAC_CSR_DATA, Value);
    141 
    142   // Write the config to the register
    143   MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR);
    144 
    145   // Wait until CSR busy bit is cleared
    146   while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
    147 
    148   return ValueWritten;
    149 }
    150 
    151 // Function to read from MII register (PHY Access)
    152 UINT32
    153 IndirectPHYRead32 (
    154   UINT32 Index
    155   )
    156 {
    157   UINT32 ValueRead;
    158   UINT32 MiiAcc;
    159 
    160   // Check it is a valid index
    161   ASSERT(Index < 31);
    162 
    163   // Wait for busy bit to clear
    164   while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
    165 
    166   // Clear the R/W bit to indicate we are reading
    167   // Set the index of the MII register
    168   // Set the PHY Address
    169   // Set the MII busy bit to allow read
    170   MiiAcc = MII_ACC_MII_READ | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY;
    171 
    172   // Now write this config to register
    173   IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF);
    174 
    175   // Wait for busy bit to clear
    176   while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
    177 
    178   // Now read the value of the register
    179   ValueRead = (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA) & 0xFFFF); // only lower 16 bits are valid for any PHY register
    180 
    181   return ValueRead;
    182 }
    183 
    184 
    185 // Function to write to the MII register (PHY Access)
    186 UINT32
    187 IndirectPHYWrite32 (
    188   UINT32 Index,
    189   UINT32 Value
    190   )
    191 {
    192   UINT32 MiiAcc;
    193   UINT32 ValueWritten;
    194 
    195   // Check it is a valid index
    196   ASSERT(Index < 31);
    197 
    198   // Wait for busy bit to clear
    199   while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
    200 
    201   // Clear the R/W bit to indicate we are reading
    202   // Set the index of the MII register
    203   // Set the PHY Address
    204   // Set the MII busy bit to allow read
    205   MiiAcc = MII_ACC_MII_WRITE | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY;
    206 
    207   // Write the desired value to the register first
    208   ValueWritten = IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA, (Value & 0xFFFF));
    209 
    210   // Now write the config to register
    211   IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF);
    212 
    213   // Wait for operation to terminate
    214   while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
    215 
    216   return ValueWritten;
    217 }
    218 
    219 
    220 /* ---------------- EEPROM Operations ------------------ */
    221 
    222 
    223 // Function to read from EEPROM memory
    224 UINT32
    225 IndirectEEPROMRead32 (
    226   UINT32 Index
    227   )
    228 {
    229   UINT32 EepromCmd;
    230 
    231   // Set the busy bit to ensure read will occur
    232   EepromCmd = E2P_EPC_BUSY | E2P_EPC_CMD_READ;
    233 
    234   // Set the index to access desired EEPROM memory location
    235   EepromCmd |= E2P_EPC_ADDRESS(Index);
    236 
    237   // Write to Eeprom command register
    238   MmioWrite32 (LAN9118_E2P_CMD, EepromCmd);
    239   gBS->Stall (LAN9118_STALL);
    240 
    241   // Wait until operation has completed
    242   while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
    243 
    244   // Check that operation didn't time out
    245   if (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) {
    246     DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Read command on index %x\n",Index));
    247     return 0;
    248   }
    249 
    250   // Wait until operation has completed
    251   while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
    252 
    253   // Finally read the value
    254   return MmioRead32 (LAN9118_E2P_DATA);
    255 }
    256 
    257 // Function to write to EEPROM memory
    258 UINT32
    259 IndirectEEPROMWrite32 (
    260   UINT32 Index,
    261   UINT32 Value
    262   )
    263 {
    264   UINT32 ValueWritten;
    265   UINT32 EepromCmd;
    266 
    267   ValueWritten = 0;
    268 
    269   // Read the EEPROM Command register
    270   EepromCmd = MmioRead32 (LAN9118_E2P_CMD);
    271 
    272   // Set the busy bit to ensure read will occur
    273   EepromCmd |= ((UINT32)1 << 31);
    274 
    275   // Set the EEPROM command to write(0b011)
    276   EepromCmd &= ~(7 << 28);    // Clear the command first
    277   EepromCmd |= (3 << 28);     // Write 011
    278 
    279   // Set the index to access desired EEPROM memory location
    280   EepromCmd |= (Index & 0xF);
    281 
    282   // Write the value to the data register first
    283   ValueWritten = MmioWrite32 (LAN9118_E2P_DATA, Value);
    284 
    285   // Write to Eeprom command register
    286   MmioWrite32 (LAN9118_E2P_CMD, EepromCmd);
    287   gBS->Stall (LAN9118_STALL);
    288 
    289   // Wait until operation has completed
    290   while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
    291 
    292   // Check that operation didn't time out
    293   if (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) {
    294     DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Write command at memloc 0x%x, with value 0x%x\n",Index, Value));
    295     return 0;
    296   }
    297 
    298   // Wait until operation has completed
    299   while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
    300 
    301   return ValueWritten;
    302 }
    303 
    304 /* ---------------- General Operations ----------------- */
    305 
    306 VOID
    307 Lan9118SetMacAddress (
    308   EFI_MAC_ADDRESS             *Mac,
    309   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    310   )
    311 {
    312   IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL,
    313                       (Mac->Addr[0] & 0xFF) |
    314                       ((Mac->Addr[1] & 0xFF) << 8) |
    315                       ((Mac->Addr[2] & 0xFF) << 16) |
    316                       ((Mac->Addr[3] & 0xFF) << 24)
    317                     );
    318 
    319   IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH,
    320                       (UINT32)(Mac->Addr[4] & 0xFF) |
    321                       ((Mac->Addr[5] & 0xFF) << 8)
    322                     );
    323 }
    324 
    325 VOID
    326 Lan9118ReadMacAddress (
    327   OUT EFI_MAC_ADDRESS *MacAddress
    328   )
    329 {
    330   UINT32          MacAddrHighValue;
    331   UINT32          MacAddrLowValue;
    332 
    333   // Read the Mac Addr high register
    334   MacAddrHighValue = (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH) & 0xFFFF);
    335   // Read the Mac Addr low register
    336   MacAddrLowValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL);
    337 
    338   SetMem (MacAddress, sizeof(*MacAddress), 0);
    339   MacAddress->Addr[0] = (MacAddrLowValue & 0xFF);
    340   MacAddress->Addr[1] = (MacAddrLowValue & 0xFF00) >> 8;
    341   MacAddress->Addr[2] = (MacAddrLowValue & 0xFF0000) >> 16;
    342   MacAddress->Addr[3] = (MacAddrLowValue & 0xFF000000) >> 24;
    343   MacAddress->Addr[4] = (MacAddrHighValue & 0xFF);
    344   MacAddress->Addr[5] = (MacAddrHighValue & 0xFF00) >> 8;
    345 }
    346 
    347 /*
    348  *  Power up the 9118 and find its MAC address.
    349  *
    350  *  This operation can be carried out when the LAN9118 is in any power state
    351  *
    352  */
    353 EFI_STATUS
    354 Lan9118Initialize (
    355   IN  EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    356   )
    357 {
    358   UINTN  Timeout;
    359   UINT64 DefaultMacAddress;
    360 
    361   // Attempt to wake-up the device if it is in a lower power state
    362   if (((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12) != 0) {
    363     DEBUG ((DEBUG_NET, "Waking from reduced power state.\n"));
    364     MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF);
    365     gBS->Stall (LAN9118_STALL);
    366   }
    367 
    368   // Check that device is active
    369   Timeout = 20;
    370   while ((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) == 0 && --Timeout) {
    371     gBS->Stall (LAN9118_STALL);
    372   }
    373   if (!Timeout) {
    374     return EFI_TIMEOUT;
    375   }
    376 
    377   // Check that EEPROM isn't active
    378   Timeout = 20;
    379   while ((MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY) && --Timeout){
    380     gBS->Stall (LAN9118_STALL);
    381   }
    382   if (!Timeout) {
    383     return EFI_TIMEOUT;
    384   }
    385 
    386   // Check if a MAC address was loaded from EEPROM, and if it was, set it as the
    387   // current address.
    388   if ((MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_MAC_ADDRESS_LOADED) == 0) {
    389     DEBUG ((EFI_D_ERROR, "Warning: There was an error detecting EEPROM or loading the MAC Address.\n"));
    390 
    391     // If we had an address before (set by StationAddess), continue to use it
    392     if (CompareMem (&Snp->Mode->CurrentAddress, &mZeroMac, NET_ETHER_ADDR_LEN)) {
    393       Lan9118SetMacAddress (&Snp->Mode->CurrentAddress, Snp);
    394     } else {
    395       // If there are no cached addresses, then fall back to a default
    396       DEBUG ((EFI_D_WARN, "Warning: using driver-default MAC address\n"));
    397       DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress);
    398       Lan9118SetMacAddress((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp);
    399       CopyMem (&Snp->Mode->CurrentAddress, &DefaultMacAddress, NET_ETHER_ADDR_LEN);
    400     }
    401   } else {
    402     // Store the MAC address that was loaded from EEPROM
    403     Lan9118ReadMacAddress (&Snp->Mode->CurrentAddress);
    404     CopyMem (&Snp->Mode->PermanentAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
    405   }
    406 
    407   // Clear and acknowledge interrupts
    408   MmioWrite32 (LAN9118_INT_EN, 0);
    409   MmioWrite32 (LAN9118_IRQ_CFG, 0);
    410   MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
    411 
    412   // Do self tests here?
    413 
    414   return EFI_SUCCESS;
    415 }
    416 
    417 
    418 // Perform software reset on the LAN9118
    419 // Return 0 on success, -1 on error
    420 EFI_STATUS
    421 SoftReset (
    422   UINT32 Flags,
    423   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    424   )
    425 {
    426   UINT32 HwConf;
    427   UINT32 ResetTime;
    428 
    429   // Initialize variable
    430   ResetTime = 0;
    431 
    432   // Stop Rx and Tx
    433   StopTx (STOP_TX_MAC | STOP_TX_CFG | STOP_TX_CLEAR, Snp);
    434   StopRx (STOP_RX_CLEAR, Snp); // Clear receiver FIFO
    435 
    436   // Issue the reset
    437   HwConf = MmioRead32 (LAN9118_HW_CFG);
    438   HwConf |= 1;
    439 
    440   // Set the Must Be One (MBO) bit
    441   if (((HwConf & HWCFG_MBO) >> 20) == 0) {
    442     HwConf |= HWCFG_MBO;
    443   }
    444 
    445   // Check that EEPROM isn't active
    446   while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
    447 
    448   // Write the configuration
    449   MmioWrite32 (LAN9118_HW_CFG, HwConf);
    450   gBS->Stall (LAN9118_STALL);
    451 
    452   // Wait for reset to complete
    453   while (MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) {
    454 
    455     gBS->Stall (LAN9118_STALL);
    456     ResetTime += 1;
    457 
    458     // If time taken exceeds 100us, then there was an error condition
    459     if (ResetTime > 1000) {
    460       Snp->Mode->State = EfiSimpleNetworkStopped;
    461       return EFI_TIMEOUT;
    462     }
    463   }
    464 
    465   // Check that EEPROM isn't active
    466   while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
    467 
    468   // TODO we probably need to re-set the mac address here.
    469 
    470   // Clear and acknowledge all interrupts
    471   if (Flags & SOFT_RESET_CLEAR_INT) {
    472     MmioWrite32 (LAN9118_INT_EN, 0);
    473     MmioWrite32 (LAN9118_IRQ_CFG, 0);
    474     MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
    475   }
    476 
    477   // Do self tests here?
    478   if (Flags & SOFT_RESET_SELF_TEST) {
    479 
    480   }
    481 
    482   return EFI_SUCCESS;
    483 }
    484 
    485 
    486 // Perform PHY software reset
    487 EFI_STATUS
    488 PhySoftReset (
    489   UINT32 Flags,
    490   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    491   )
    492 {
    493   UINT32 PmtCtrl = 0;
    494 
    495   // PMT PHY reset takes precedence over BCR
    496   if (Flags & PHY_RESET_PMT) {
    497     PmtCtrl = MmioRead32 (LAN9118_PMT_CTRL);
    498     PmtCtrl |= MPTCTRL_PHY_RST;
    499     MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl);
    500 
    501     // Wait for completion
    502     while (MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) {
    503       gBS->Stall (LAN9118_STALL);
    504     }
    505   // PHY Basic Control Register reset
    506   } else if (Flags & PHY_RESET_BCR) {
    507     IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET);
    508 
    509     // Wait for completion
    510     while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) {
    511       gBS->Stall (LAN9118_STALL);
    512     }
    513   }
    514 
    515   // Clear and acknowledge all interrupts
    516   if (Flags & PHY_SOFT_RESET_CLEAR_INT) {
    517     MmioWrite32 (LAN9118_INT_EN, 0);
    518     MmioWrite32 (LAN9118_IRQ_CFG, 0);
    519     MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
    520   }
    521 
    522   return EFI_SUCCESS;
    523 }
    524 
    525 
    526 // Configure hardware for LAN9118
    527 EFI_STATUS
    528 ConfigureHardware (
    529   UINT32 Flags,
    530   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    531   )
    532 {
    533   UINT32 GpioConf;
    534 
    535   // Check if we want to use LEDs on GPIO
    536   if (Flags & HW_CONF_USE_LEDS) {
    537     GpioConf = MmioRead32 (LAN9118_GPIO_CFG);
    538 
    539     // Enable GPIO as LEDs and Config as Push-Pull driver
    540     GpioConf |= GPIO_GPIO0_PUSH_PULL | GPIO_GPIO1_PUSH_PULL | GPIO_GPIO2_PUSH_PULL |
    541                 GPIO_LED1_ENABLE | GPIO_LED2_ENABLE | GPIO_LED3_ENABLE;
    542 
    543     // Write the configuration
    544     MmioWrite32 (LAN9118_GPIO_CFG, GpioConf);
    545     gBS->Stall (LAN9118_STALL);
    546   }
    547 
    548   return EFI_SUCCESS;
    549 }
    550 
    551 // Configure flow control
    552 EFI_STATUS
    553 ConfigureFlow (
    554   UINT32 Flags,
    555   UINT32 HighTrig,
    556   UINT32 LowTrig,
    557   UINT32 BPDuration,
    558   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    559   )
    560 {
    561   return EFI_SUCCESS;
    562 }
    563 
    564 // Do auto-negotiation
    565 EFI_STATUS
    566 AutoNegotiate (
    567   UINT32 Flags,
    568   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    569   )
    570 {
    571   UINT32 PhyControl;
    572   UINT32 PhyStatus;
    573   UINT32 Features;
    574   UINT32 TimeOut;
    575 
    576   // First check that auto-negotiation is supported
    577   PhyStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS);
    578   if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) {
    579     DEBUG ((EFI_D_ERROR, "Auto-negotiation not supported.\n"));
    580     return EFI_DEVICE_ERROR;
    581   }
    582 
    583   // Check that link is up first
    584   if ((PhyStatus & PHYSTS_LINK_STS) == 0) {
    585     // Wait until it is up or until Time Out
    586     TimeOut = 2000;
    587     while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_LINK_STS) == 0) {
    588       gBS->Stall (LAN9118_STALL);
    589       TimeOut--;
    590       if (!TimeOut) {
    591         DEBUG ((EFI_D_ERROR, "Link timeout in auto-negotiation.\n"));
    592         return EFI_TIMEOUT;
    593       }
    594     }
    595   }
    596 
    597   // Configure features to advertise
    598   Features = IndirectPHYRead32 (PHY_INDEX_AUTO_NEG_ADVERT);
    599 
    600   if ((Flags & AUTO_NEGOTIATE_ADVERTISE_ALL) > 0) {
    601     // Link speed capabilities
    602     Features |= (PHYANA_10BASET | PHYANA_10BASETFD | PHYANA_100BASETX | PHYANA_100BASETXFD);
    603 
    604     // Pause frame capabilities
    605     Features &= ~(PHYANA_PAUSE_OP_MASK);
    606     Features |= 3 << 10;
    607   }
    608 
    609   // Write the features
    610   IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, Features);
    611 
    612   // Read control register
    613   PhyControl = IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL);
    614 
    615   // Enable Auto-Negotiation
    616   if ((PhyControl & PHYCR_AUTO_EN) == 0) {
    617     PhyControl |= PHYCR_AUTO_EN;
    618   }
    619 
    620   // Restart auto-negotiation
    621   PhyControl |= PHYCR_RST_AUTO;
    622 
    623   // Enable collision test if required to do so
    624   if (Flags & AUTO_NEGOTIATE_COLLISION_TEST) {
    625     PhyControl |= PHYCR_COLL_TEST;
    626   } else {
    627     PhyControl &= ~ PHYCR_COLL_TEST;
    628   }
    629 
    630   // Write this configuration
    631   IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl);
    632 
    633   // Wait until process has completed
    634   while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0);
    635 
    636   return EFI_SUCCESS;
    637 }
    638 
    639 // Check the Link Status and take appropriate action
    640 EFI_STATUS
    641 CheckLinkStatus (
    642   UINT32 Flags,
    643   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    644   )
    645 {
    646   // Get the PHY Status
    647   UINT32 PhyBStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS);
    648 
    649   if (PhyBStatus & PHYSTS_LINK_STS) {
    650     return EFI_SUCCESS;
    651   } else {
    652     return EFI_DEVICE_ERROR;
    653   }
    654 }
    655 
    656 // Stop the transmitter
    657 EFI_STATUS
    658 StopTx (
    659   UINT32 Flags,
    660   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    661   )
    662 {
    663   UINT32 MacCsr;
    664   UINT32 TxCfg;
    665 
    666   MacCsr = 0;
    667   TxCfg = 0;
    668 
    669   // Check if we want to clear tx
    670   if (Flags & STOP_TX_CLEAR) {
    671     TxCfg = MmioRead32 (LAN9118_TX_CFG);
    672     TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP;
    673     MmioWrite32 (LAN9118_TX_CFG, TxCfg);
    674     gBS->Stall (LAN9118_STALL);
    675   }
    676 
    677   // Check if already stopped
    678   if (Flags & STOP_TX_MAC) {
    679     MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
    680 
    681     if (MacCsr & MACCR_TX_EN) {
    682       MacCsr &= ~MACCR_TX_EN;
    683       IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
    684     }
    685   }
    686 
    687   if (Flags & STOP_TX_CFG) {
    688     TxCfg = MmioRead32 (LAN9118_TX_CFG);
    689 
    690     if (TxCfg & TXCFG_TX_ON) {
    691       TxCfg |= TXCFG_STOP_TX;
    692       MmioWrite32 (LAN9118_TX_CFG, TxCfg);
    693       gBS->Stall (LAN9118_STALL);
    694 
    695       // Wait for Tx to finish transmitting
    696       while (MmioRead32 (LAN9118_TX_CFG) & TXCFG_STOP_TX);
    697     }
    698   }
    699 
    700   return EFI_SUCCESS;
    701 }
    702 
    703 // Stop the receiver
    704 EFI_STATUS
    705 StopRx (
    706   UINT32 Flags,
    707   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    708   )
    709 {
    710   UINT32 MacCsr;
    711   UINT32 RxCfg;
    712 
    713   RxCfg = 0;
    714 
    715   // Check if already stopped
    716   MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
    717 
    718   if (MacCsr & MACCR_RX_EN) {
    719     MacCsr &= ~ MACCR_RX_EN;
    720     IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
    721   }
    722 
    723   // Check if we want to clear receiver FIFOs
    724   if (Flags & STOP_RX_CLEAR) {
    725     RxCfg = MmioRead32 (LAN9118_RX_CFG);
    726     RxCfg |= RXCFG_RX_DUMP;
    727     MmioWrite32 (LAN9118_RX_CFG, RxCfg);
    728     gBS->Stall (LAN9118_STALL);
    729 
    730     while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP);
    731   }
    732 
    733   return EFI_SUCCESS;
    734 }
    735 
    736 // Start the transmitter
    737 EFI_STATUS
    738 StartTx (
    739   UINT32 Flags,
    740   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    741   )
    742 {
    743   UINT32 MacCsr;
    744   UINT32 TxCfg;
    745 
    746   MacCsr = 0;
    747   TxCfg = 0;
    748 
    749   // Check if we want to clear tx
    750   if (Flags & START_TX_CLEAR) {
    751     TxCfg = MmioRead32 (LAN9118_TX_CFG);
    752     TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP;
    753     MmioWrite32 (LAN9118_TX_CFG, TxCfg);
    754     gBS->Stall (LAN9118_STALL);
    755   }
    756 
    757   // Check if tx was started from MAC and enable if not
    758   if (Flags & START_TX_MAC) {
    759     MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
    760     gBS->Stall (LAN9118_STALL);
    761     if ((MacCsr & MACCR_TX_EN) == 0) {
    762       MacCsr |= MACCR_TX_EN;
    763       IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
    764       gBS->Stall (LAN9118_STALL);
    765     }
    766   }
    767 
    768   // Check if tx was started from TX_CFG and enable if not
    769   if (Flags & START_TX_CFG) {
    770     TxCfg = MmioRead32 (LAN9118_TX_CFG);
    771     gBS->Stall (LAN9118_STALL);
    772     if ((TxCfg & TXCFG_TX_ON) == 0) {
    773       TxCfg |= TXCFG_TX_ON;
    774       MmioWrite32 (LAN9118_TX_CFG, TxCfg);
    775       gBS->Stall (LAN9118_STALL);
    776     }
    777   }
    778 
    779   // Set the tx data trigger level
    780 
    781   return EFI_SUCCESS;
    782 }
    783 
    784 // Start the receiver
    785 EFI_STATUS
    786 StartRx (
    787   UINT32 Flags,
    788   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    789   )
    790 {
    791   UINT32 MacCsr;
    792   UINT32 RxCfg;
    793 
    794   RxCfg = 0;
    795 
    796   // Check if already started
    797   MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
    798 
    799   if ((MacCsr & MACCR_RX_EN) == 0) {
    800     // Check if we want to clear receiver FIFOs before starting
    801     if (Flags & START_RX_CLEAR) {
    802       RxCfg = MmioRead32 (LAN9118_RX_CFG);
    803       RxCfg |= RXCFG_RX_DUMP;
    804       MmioWrite32 (LAN9118_RX_CFG, RxCfg);
    805       gBS->Stall (LAN9118_STALL);
    806 
    807       while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP);
    808     }
    809 
    810     MacCsr |= MACCR_RX_EN;
    811     IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
    812     gBS->Stall (LAN9118_STALL);
    813   }
    814 
    815   return EFI_SUCCESS;
    816 }
    817 
    818 // Check Tx Data available space
    819 UINT32
    820 TxDataFreeSpace (
    821   UINT32 Flags,
    822   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    823   )
    824 {
    825   UINT32 TxInf;
    826   UINT32 FreeSpace;
    827 
    828   // Get the amount of free space from information register
    829   TxInf = MmioRead32 (LAN9118_TX_FIFO_INF);
    830   FreeSpace = (TxInf & TXFIFOINF_TDFREE_MASK);
    831 
    832   return FreeSpace; // Value in bytes
    833 }
    834 
    835 // Check Tx Status used space
    836 UINT32
    837 TxStatusUsedSpace (
    838   UINT32 Flags,
    839   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    840   )
    841 {
    842   UINT32 TxInf;
    843   UINT32 UsedSpace;
    844 
    845   // Get the amount of used space from information register
    846   TxInf = MmioRead32 (LAN9118_TX_FIFO_INF);
    847   UsedSpace = (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16;
    848 
    849   return UsedSpace << 2; // Value in bytes
    850 }
    851 
    852 // Check Rx Data used space
    853 UINT32
    854 RxDataUsedSpace (
    855   UINT32 Flags,
    856   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    857   )
    858 {
    859   UINT32 RxInf;
    860   UINT32 UsedSpace;
    861 
    862   // Get the amount of used space from information register
    863   RxInf = MmioRead32 (LAN9118_RX_FIFO_INF);
    864   UsedSpace = (RxInf & RXFIFOINF_RXDUSED_MASK);
    865 
    866   return UsedSpace; // Value in bytes (rounded up to nearest DWORD)
    867 }
    868 
    869 // Check Rx Status used space
    870 UINT32
    871 RxStatusUsedSpace (
    872   UINT32 Flags,
    873   EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    874   )
    875 {
    876   UINT32 RxInf;
    877   UINT32 UsedSpace;
    878 
    879   // Get the amount of used space from information register
    880   RxInf = MmioRead32 (LAN9118_RX_FIFO_INF);
    881   UsedSpace = (RxInf & RXFIFOINF_RXSUSED_MASK) >> 16;
    882 
    883   return UsedSpace << 2; // Value in bytes
    884 }
    885 
    886 
    887 // Change the allocation of FIFOs
    888 EFI_STATUS
    889 ChangeFifoAllocation (
    890   IN      UINT32 Flags,
    891   IN  OUT UINTN  *TxDataSize    OPTIONAL,
    892   IN  OUT UINTN  *RxDataSize    OPTIONAL,
    893   IN  OUT UINT32 *TxStatusSize  OPTIONAL,
    894   IN  OUT UINT32 *RxStatusSize  OPTIONAL,
    895   IN  OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp
    896   )
    897 {
    898   UINT32 HwConf;
    899   UINT32 TxFifoOption;
    900 
    901   // Check that desired sizes don't exceed limits
    902   if (*TxDataSize > TX_FIFO_MAX_SIZE)
    903     return EFI_INVALID_PARAMETER;
    904 
    905 #if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE)
    906   if (*RxDataSize > RX_FIFO_MAX_SIZE) {
    907     return EFI_INVALID_PARAMETER;
    908   }
    909 #endif
    910 
    911   if (Flags & ALLOC_USE_DEFAULT) {
    912     return EFI_SUCCESS;
    913   }
    914 
    915   // If we use the FIFOs (always use this first)
    916   if (Flags & ALLOC_USE_FIFOS) {
    917     // Read the current value of allocation
    918     HwConf = MmioRead32 (LAN9118_HW_CFG);
    919     TxFifoOption = (HwConf >> 16) & 0xF;
    920 
    921     // Choose the correct size (always use larger than requested if possible)
    922     if (*TxDataSize < TX_FIFO_MIN_SIZE) {
    923       *TxDataSize = TX_FIFO_MIN_SIZE;
    924       *RxDataSize = 13440;
    925       *RxStatusSize = 896;
    926       TxFifoOption = 2;
    927     } else if ((*TxDataSize > TX_FIFO_MIN_SIZE) && (*TxDataSize <= 2560)) {
    928       *TxDataSize = 2560;
    929       *RxDataSize = 12480;
    930       *RxStatusSize = 832;
    931       TxFifoOption = 3;
    932     } else if ((*TxDataSize > 2560) && (*TxDataSize <= 3584)) {
    933       *TxDataSize = 3584;
    934       *RxDataSize = 11520;
    935       *RxStatusSize = 768;
    936       TxFifoOption = 4;
    937     } else if ((*TxDataSize > 3584) && (*TxDataSize <= 4608)) { // default option
    938       *TxDataSize = 4608;
    939       *RxDataSize = 10560;
    940       *RxStatusSize = 704;
    941       TxFifoOption = 5;
    942     } else if ((*TxDataSize > 4608) && (*TxDataSize <= 5632)) {
    943       *TxDataSize = 5632;
    944       *RxDataSize = 9600;
    945       *RxStatusSize = 640;
    946       TxFifoOption = 6;
    947     } else if ((*TxDataSize > 5632) && (*TxDataSize <= 6656)) {
    948       *TxDataSize = 6656;
    949       *RxDataSize = 8640;
    950       *RxStatusSize = 576;
    951       TxFifoOption = 7;
    952     } else if ((*TxDataSize > 6656) && (*TxDataSize <= 7680)) {
    953       *TxDataSize = 7680;
    954       *RxDataSize = 7680;
    955       *RxStatusSize = 512;
    956       TxFifoOption = 8;
    957     } else if ((*TxDataSize > 7680) && (*TxDataSize <= 8704)) {
    958       *TxDataSize = 8704;
    959       *RxDataSize = 6720;
    960       *RxStatusSize = 448;
    961       TxFifoOption = 9;
    962     } else if ((*TxDataSize > 8704) && (*TxDataSize <= 9728)) {
    963       *TxDataSize = 9728;
    964       *RxDataSize = 5760;
    965       *RxStatusSize = 384;
    966       TxFifoOption = 10;
    967     } else if ((*TxDataSize > 9728) && (*TxDataSize <= 10752)) {
    968       *TxDataSize = 10752;
    969       *RxDataSize = 4800;
    970       *RxStatusSize = 320;
    971       TxFifoOption = 11;
    972     } else if ((*TxDataSize > 10752) && (*TxDataSize <= 11776)) {
    973       *TxDataSize = 11776;
    974       *RxDataSize = 3840;
    975       *RxStatusSize = 256;
    976       TxFifoOption = 12;
    977     } else if ((*TxDataSize > 11776) && (*TxDataSize <= 12800)) {
    978       *TxDataSize = 12800;
    979       *RxDataSize = 2880;
    980       *RxStatusSize = 192;
    981       TxFifoOption = 13;
    982     } else if ((*TxDataSize > 12800) && (*TxDataSize <= 13824)) {
    983       *TxDataSize = 13824;
    984       *RxDataSize = 1920;
    985       *RxStatusSize = 128;
    986       TxFifoOption = 14;
    987     }
    988   } else {
    989     ASSERT(0); // Untested code path
    990     HwConf = 0;
    991     TxFifoOption = 0;
    992   }
    993 
    994   // Do we need DMA?
    995   if (Flags & ALLOC_USE_DMA) {
    996     return EFI_UNSUPPORTED; // Unsupported as of now
    997   }
    998   // Clear and assign the new size option
    999   HwConf &= ~(0xF0000);
   1000   HwConf |= ((TxFifoOption & 0xF) << 16);
   1001   MmioWrite32 (LAN9118_HW_CFG, HwConf);
   1002   gBS->Stall (LAN9118_STALL);
   1003 
   1004   return EFI_SUCCESS;
   1005 }
   1006