123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229 |
- /** @file
- * SMSC LAN91x series Network Controller Driver.
- *
- * Copyright (c) 2013-2017 Linaro.org
- *
- * Derived from the LAN9118 driver. Original sources
- * Copyright (c) 2012-2013, ARM Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-2-Clause-Patent
- *
- **/
- #include <Uefi.h>
- #include <Uefi/UefiSpec.h>
- #include <Base.h>
- // Protocols used by this driver
- #include <Protocol/SimpleNetwork.h>
- #include <Protocol/ComponentName2.h>
- #include <Protocol/PxeBaseCode.h>
- #include <Protocol/DevicePath.h>
- // Libraries used by this driver
- #include <Library/UefiLib.h>
- #include <Library/DebugLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/IoLib.h>
- #include <Library/PcdLib.h>
- #include <Library/NetLib.h>
- #include <Library/DevicePathLib.h>
- // Hardware register definitions
- #include "Lan91xDxeHw.h"
- // Debugging output options
- //#define LAN91X_PRINT_REGISTERS 1
- //#define LAN91X_PRINT_PACKET_HEADERS 1
- //#define LAN91X_PRINT_RECEIVE_FILTERS 1
- // Chip power-down option -- UNTESTED
- //#define LAN91X_POWER_DOWN 1
- /*---------------------------------------------------------------------------------------------------------------------
- LAN91x Information Structure
- ---------------------------------------------------------------------------------------------------------------------*/
- typedef struct _LAN91X_DRIVER {
- // Driver signature
- UINT32 Signature;
- EFI_HANDLE ControllerHandle;
- // EFI SNP protocol instances
- EFI_SIMPLE_NETWORK_PROTOCOL Snp;
- EFI_SIMPLE_NETWORK_MODE SnpMode;
- // EFI Snp statistics instance
- EFI_NETWORK_STATISTICS Stats;
- // Transmit Buffer recycle queue
- LIST_ENTRY TransmitQueueHead;
- // Register access variables
- UINTN IoBase; // I/O Base Address
- UINT8 Revision; // Chip Revision Number
- INT8 PhyAd; // Phy Address
- UINT8 BankSel; // Currently selected register bank
- } LAN91X_DRIVER;
- #define LAN91X_NO_PHY (-1) // PhyAd value if PHY not detected
- #define LAN91X_SIGNATURE SIGNATURE_32('S', 'M', '9', '1')
- #define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN91X_DRIVER, Snp, LAN91X_SIGNATURE)
- #define LAN91X_STALL 2
- #define LAN91X_MEMORY_ALLOC_POLLS 100 // Max times to poll for memory allocation
- #define LAN91X_PKT_OVERHEAD 6 // Overhead bytes in packet buffer
- // Synchronization TPLs
- #define LAN91X_TPL TPL_CALLBACK
- // Most common CRC32 Polynomial for little endian machines
- #define CRC_POLYNOMIAL 0xEDB88320
- typedef struct {
- MAC_ADDR_DEVICE_PATH Lan91x;
- EFI_DEVICE_PATH_PROTOCOL End;
- } LAN91X_DEVICE_PATH;
- LAN91X_DEVICE_PATH Lan91xPathTemplate = {
- {
- {
- MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,
- { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) }
- },
- { { 0 } },
- 0
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }
- }
- };
- // Chip ID numbers and name strings
- #define CHIP_9192 3
- #define CHIP_9194 4
- #define CHIP_9195 5
- #define CHIP_9196 6
- #define CHIP_91100 7
- #define CHIP_91100FD 8
- #define CHIP_91111FD 9
- STATIC CHAR16 CONST * CONST ChipIds[ 16 ] = {
- NULL, NULL, NULL,
- /* 3 */ L"SMC91C90/91C92",
- /* 4 */ L"SMC91C94",
- /* 5 */ L"SMC91C95",
- /* 6 */ L"SMC91C96",
- /* 7 */ L"SMC91C100",
- /* 8 */ L"SMC91C100FD",
- /* 9 */ L"SMC91C11xFD",
- NULL, NULL, NULL,
- NULL, NULL, NULL
- };
- /* ------------------ TxBuffer Queue structures ------------------- */
- typedef struct {
- VOID *Buf;
- UINTN Length;
- } MSK_SYSTEM_BUF;
- typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
- MSK_SYSTEM_BUF SystemBuf;
- } MSK_LINKED_SYSTEM_BUF;
- #define TX_MBUF_SIGNATURE SIGNATURE_32 ('t','x','m','b')
- /* ------------------ MAC Address Hash Calculations ------------------- */
- /*
- ** Generate a hash value from a multicast address
- **
- ** This uses the Ethernet standard CRC32 algorithm
- **
- ** INFO USED:
- ** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check
- **
- ** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html
- **
- ** 3: http://en.wikipedia.org/wiki/Computation_of_CRC
- */
- STATIC
- UINT32
- MulticastHash (
- IN EFI_MAC_ADDRESS *Mac,
- IN UINT32 AddrLen
- )
- {
- UINT32 Iter;
- UINT32 Remainder;
- UINT32 Crc32;
- UINT8 *Addr;
- // 0xFFFFFFFF is standard seed for Ethernet
- Remainder = 0xFFFFFFFF;
- // Generate the remainder byte-by-byte (LSB first)
- Addr = &Mac->Addr[0];
- while (AddrLen-- > 0) {
- Remainder ^= *Addr++;
- for (Iter = 0; Iter < 8; ++Iter) {
- // Check if exponent is set
- if ((Remainder & 1) != 0) {
- Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL;
- } else {
- Remainder = (Remainder >> 1) ^ 0;
- }
- }
- }
- // Reverse the bits of the remainder
- Crc32 = 0;
- for (Iter = 0; Iter < 32; ++Iter) {
- Crc32 <<= 1;
- Crc32 |= Remainder & 1;
- Remainder >>= 1;
- }
- return Crc32;
- }
- /* ---------------- Banked Register Operations ------------------ */
- // Select the proper I/O bank
- STATIC
- VOID
- SelectIoBank (
- LAN91X_DRIVER *LanDriver,
- UINTN Register
- )
- {
- UINT8 Bank;
- Bank = RegisterToBank (Register);
- // Select the proper I/O bank
- if (LanDriver->BankSel != Bank) {
- MmioWrite16 (LanDriver->IoBase + LAN91X_BANK_OFFSET, Bank);
- LanDriver->BankSel = Bank;
- }
- }
- // Read a 16-bit I/O-space register
- STATIC
- UINT16
- ReadIoReg16 (
- LAN91X_DRIVER *LanDriver,
- UINTN Register
- )
- {
- UINT8 Offset;
- // Select the proper I/O bank
- SelectIoBank (LanDriver, Register);
- // Read the requested register
- Offset = RegisterToOffset (Register);
- return MmioRead16 (LanDriver->IoBase + Offset);
- }
- // Write a 16-bit I/O-space register
- STATIC
- UINT16
- WriteIoReg16 (
- LAN91X_DRIVER *LanDriver,
- UINTN Register,
- UINT16 Value
- )
- {
- UINT8 Offset;
- // Select the proper I/O bank
- SelectIoBank (LanDriver, Register);
- // Write the requested register
- Offset = RegisterToOffset (Register);
- return MmioWrite16 (LanDriver->IoBase + Offset, Value);
- }
- // Read an 8-bit I/O-space register
- STATIC
- UINT8
- ReadIoReg8 (
- LAN91X_DRIVER *LanDriver,
- UINTN Register
- )
- {
- UINT8 Offset;
- // Select the proper I/O bank
- SelectIoBank (LanDriver, Register);
- // Read the requested register
- Offset = RegisterToOffset (Register);
- return MmioRead8 (LanDriver->IoBase + Offset);
- }
- // Write an 8-bit I/O-space register
- STATIC
- UINT8
- WriteIoReg8 (
- LAN91X_DRIVER *LanDriver,
- UINTN Register,
- UINT8 Value
- )
- {
- UINT8 Offset;
- // Select the proper I/O bank
- SelectIoBank (LanDriver, Register);
- // Write the requested register
- Offset = RegisterToOffset (Register);
- return MmioWrite8 (LanDriver->IoBase + Offset, Value);
- }
- /* ---------------- MII/PHY Access Operations ------------------ */
- #define LAN91X_MDIO_STALL 1
- STATIC
- VOID
- MdioOutput (
- LAN91X_DRIVER *LanDriver,
- UINTN Bits,
- UINT32 Value
- )
- {
- UINT16 MgmtReg;
- UINT32 Mask;
- MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);
- MgmtReg &= ~MGMT_MCLK;
- MgmtReg |= MGMT_MDOE;
- for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) {
- if ((Value & Mask) != 0) {
- MgmtReg |= MGMT_MDO;
- } else {
- MgmtReg &= ~MGMT_MDO;
- }
- WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
- gBS->Stall (LAN91X_MDIO_STALL);
- WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK);
- gBS->Stall (LAN91X_MDIO_STALL);
- }
- }
- #define PHY_OUTPUT_TIME (2 * LAN91X_MDIO_STALL)
- STATIC
- UINT32
- MdioInput (
- LAN91X_DRIVER *LanDriver,
- UINTN Bits
- )
- {
- UINT16 MgmtReg;
- UINT32 Mask;
- UINT32 Value;
- MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);
- MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO);
- WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
- Value = 0;
- for (Mask = (1 << (Bits - 1)); Mask != 0; Mask >>= 1) {
- if ((ReadIoReg16 (LanDriver, LAN91X_MGMT) & MGMT_MDI) != 0) {
- Value |= Mask;
- }
- WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
- gBS->Stall (LAN91X_MDIO_STALL);
- WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK);
- gBS->Stall (LAN91X_MDIO_STALL);
- }
- return Value;
- }
- #define PHY_INPUT_TIME (2 * LAN91X_MDIO_STALL)
- STATIC
- VOID
- MdioIdle (
- LAN91X_DRIVER *LanDriver
- )
- {
- UINT16 MgmtReg;
- MgmtReg = ReadIoReg16 (LanDriver, LAN91X_MGMT);
- MgmtReg &= ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO);
- WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg);
- }
- // Write to a PHY register
- STATIC
- VOID
- WritePhyReg16 (
- LAN91X_DRIVER *LanDriver,
- UINTN RegAd,
- UINT16 Value
- )
- {
- // Bit-bang the MII Serial Frame write operation
- MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble
- MdioOutput (LanDriver, 2, 0x01); // Send Start (01)
- MdioOutput (LanDriver, 2, 0x01); // Send Write (01)
- MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0]
- MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0]
- MdioOutput (LanDriver, 2, 0x02); // Send TurnAround (10)
- MdioOutput (LanDriver, 16, Value); // Write 16 data bits
- // Idle the MDIO bus
- MdioIdle (LanDriver);
- }
- // Calculate approximate time to write a PHY register in microseconds
- #define PHY_WRITE_TIME ((32 + 2 + 2 + 5 + 5 + 2 + 16) * PHY_OUTPUT_TIME)
- // Read from a PHY register
- STATIC
- UINT16
- ReadPhyReg16 (
- LAN91X_DRIVER *LanDriver,
- UINTN RegAd
- )
- {
- UINT32 Value;
- // Bit-bang the MII Serial Frame read operation
- MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a preamble
- MdioOutput (LanDriver, 2, 0x01); // Send Start (01)
- MdioOutput (LanDriver, 2, 0x02); // Send Read (10)
- MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0]
- MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0]
- (VOID) MdioInput (LanDriver, 2); // Discard TurnAround bits
- Value = MdioInput (LanDriver, 16); // Read 16 data bits
- // Idle the MDIO bus
- MdioIdle (LanDriver);
- return (Value & 0xffff);
- }
- // Calculate approximate time to read a PHY register in microseconds
- #define PHY_READ_TIME (((32 + 2 + 2 + 5 + 5) * PHY_OUTPUT_TIME) + \
- ((2 + 16) * PHY_INPUT_TIME))
- /* ---------------- Debug Functions ------------------ */
- #ifdef LAN91X_PRINT_REGISTERS
- STATIC
- VOID
- PrintIoRegisters (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINTN Bank;
- UINTN Offset;
- UINT16 Value;
- DEBUG ((DEBUG_ERROR, "\nLAN91x I/O Register Dump:\n"));
- // Print currrent bank select register
- Value = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);
- DEBUG ((DEBUG_ERROR, " BankSel: %d Bank Register %04x (%d)\n",
- LanDriver->BankSel, Value, Value & 0x0007));
- // Print all I/O registers
- for (Offset = 0; Offset < 0x0e; Offset += 2) {
- DEBUG ((DEBUG_ERROR, " %02x:", Offset));
- for (Bank = 0; Bank <= 3; ++Bank) {
- DEBUG ((DEBUG_ERROR, " %04x", ReadIoReg16 (LanDriver, MakeRegister (Bank, Offset))));
- }
- DEBUG ((DEBUG_ERROR, "\n"));
- }
- }
- STATIC
- VOID
- PrintPhyRegisters (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINTN RegNum;
- DEBUG ((DEBUG_ERROR, "\nLAN91x Phy %d Register Dump:\n", LanDriver->PhyAd));
- // Print all Phy registers
- for (RegNum = 0; RegNum <= 5; ++RegNum) {
- DEBUG ((DEBUG_ERROR, " %2d: %04x\n",
- RegNum,
- ReadPhyReg16 (LanDriver, RegNum)
- ));
- }
- for (RegNum = 16; RegNum <= 20; ++RegNum) {
- DEBUG ((DEBUG_ERROR, " %2d: %04x\n",
- RegNum,
- ReadPhyReg16 (LanDriver, RegNum)
- ));
- }
- }
- #endif
- #if LAN91X_PRINT_PACKET_HEADERS
- STATIC
- VOID
- PrintIpDgram (
- IN CONST VOID *DstMac,
- IN CONST VOID *SrcMac,
- IN CONST VOID *Proto,
- IN CONST VOID *IpDgram
- )
- {
- CONST UINT8 *Ptr;
- UINT16 SrcPort;
- UINT16 DstPort;
- Ptr = DstMac;
- DEBUG ((DEBUG_ERROR, " Dst: %02x-%02x-%02x",
- Ptr[0], Ptr[1], Ptr[2]));
- DEBUG ((DEBUG_ERROR, "-%02x-%02x-%02x",
- Ptr[3], Ptr[4], Ptr[5]));
- Ptr = SrcMac;
- DEBUG ((DEBUG_ERROR, " Src: %02x-%02x-%02x",
- Ptr[0], Ptr[1], Ptr[2]));
- DEBUG ((DEBUG_ERROR, "-%02x-%02x-%02x",
- Ptr[3], Ptr[4], Ptr[5]));
- Ptr = Proto;
- DEBUG ((DEBUG_ERROR, " Proto: %02x%02x\n",
- Ptr[0], Ptr[1]));
- Ptr = IpDgram;
- switch (Ptr[9]) {
- case EFI_IP_PROTO_ICMP:
- DEBUG ((DEBUG_ERROR, " ICMP"));
- break;
- case EFI_IP_PROTO_TCP:
- DEBUG ((DEBUG_ERROR, " TCP"));
- break;
- case EFI_IP_PROTO_UDP:
- DEBUG ((DEBUG_ERROR, " UDP"));
- break;
- default:
- DEBUG ((DEBUG_ERROR, " IpProto %d\n", Ptr[9]));
- return;
- }
- DEBUG ((DEBUG_ERROR, " SrcIp: %d.%d.%d.%d",
- Ptr[12], Ptr[13], Ptr[14], Ptr[15]));
- DEBUG ((DEBUG_ERROR, " DstIp: %d.%d.%d.%d",
- Ptr[16], Ptr[17], Ptr[18], Ptr[19]));
- SrcPort = (Ptr[20] << 8) | Ptr[21];
- DstPort = (Ptr[22] << 8) | Ptr[23];
- DEBUG ((DEBUG_ERROR, " SrcPort: %d DstPort: %d\n", SrcPort, DstPort));
- }
- #endif
- /* ---------------- PHY Management Operations ----------------- */
- STATIC
- EFI_STATUS
- PhyDetect (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINT16 PhyId1;
- UINT16 PhyId2;
- for (LanDriver->PhyAd = 0x1f; LanDriver->PhyAd >= 0 ; --LanDriver->PhyAd) {
- PhyId1 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID1);
- PhyId2 = ReadPhyReg16 (LanDriver, PHY_INDEX_ID2);
- if ((PhyId1 != 0x0000) && (PhyId1 != 0xffff) &&
- (PhyId2 != 0x0000) && (PhyId2 != 0xffff)) {
- if ((PhyId1 == 0x0016) && ((PhyId2 & 0xfff0) == 0xf840)) {
- DEBUG ((DEBUG_ERROR, "LAN91x: PHY type LAN83C183 (LAN91C111 Internal)\n"));
- } else if ((PhyId1 == 0x0282) && ((PhyId2 & 0xfff0) == 0x1c50)) {
- DEBUG ((DEBUG_ERROR, "LAN91x: PHY type LAN83C180\n"));
- } else {
- DEBUG ((DEBUG_ERROR, "LAN91x: PHY id %04x:%04x\n", PhyId1, PhyId2));
- }
- return EFI_SUCCESS;
- }
- }
- DEBUG ((DEBUG_ERROR, "LAN91x: PHY detection failed\n"));
- return EFI_NO_MEDIA;
- }
- // Check the Link Status and take appropriate action
- STATIC
- BOOLEAN
- CheckLinkStatus (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINT16 PhyStatus;
- // Get the PHY Status
- PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS);
- return (PhyStatus & PHYSTS_LINK_STS) != 0;
- }
- // Do auto-negotiation
- STATIC
- EFI_STATUS
- PhyAutoNegotiate (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINTN Retries;
- UINT16 PhyControl;
- UINT16 PhyStatus;
- UINT16 PhyAdvert;
- // If there isn't a PHY, don't try to reset it
- if (LanDriver->PhyAd == LAN91X_NO_PHY) {
- return EFI_SUCCESS;
- }
- // Next check that auto-negotiation is supported
- PhyStatus = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS);
- if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) {
- return EFI_SUCCESS;
- }
- // Translate capabilities to advertise
- PhyAdvert = PHYANA_CSMA;
- if ((PhyStatus & PHYSTS_10BASET_HDPLX) != 0) {
- PhyAdvert |= PHYANA_10BASET;
- }
- if ((PhyStatus & PHYSTS_10BASET_FDPLX) != 0) {
- PhyAdvert |= PHYANA_10BASETFD;
- }
- if ((PhyStatus & PHYSTS_100BASETX_HDPLX) != 0) {
- PhyAdvert |= PHYANA_100BASETX;
- }
- if ((PhyStatus & PHYSTS_100BASETX_FDPLX) != 0) {
- PhyAdvert |= PHYANA_100BASETXFD;
- }
- if ((PhyStatus & PHYSTS_100BASE_T4) != 0) {
- PhyAdvert |= PHYANA_100BASET4;
- }
- // Set the capabilities to advertise
- WritePhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert);
- (VOID) ReadPhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT);
- // Restart Auto-Negotiation
- PhyControl = ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL);
- PhyControl &= ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE);
- PhyControl |= PHYCR_AUTO_EN | PHYCR_RST_AUTO;
- WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PhyControl);
- // Wait up to 2 seconds for the process to complete
- Retries = 2000000 / (PHY_READ_TIME + 100);
- while ((ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0) {
- if (--Retries == 0) {
- DEBUG ((DEBUG_ERROR, "LAN91x: PHY auto-negotiation timed-out\n"));
- return EFI_TIMEOUT;
- }
- gBS->Stall (100);
- }
- return EFI_SUCCESS;
- }
- // Perform PHY software reset
- STATIC
- EFI_STATUS
- PhySoftReset (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINTN Retries;
- // If there isn't a PHY, don't try to reset it
- if (LanDriver->PhyAd == LAN91X_NO_PHY) {
- return EFI_SUCCESS;
- }
- // Request a PHY reset
- WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PHYCR_RESET);
- // The internal PHY will reset within 50ms. Allow 100ms.
- Retries = 100000 / (PHY_READ_TIME + 100);
- while (ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) {
- if (--Retries == 0) {
- DEBUG ((DEBUG_ERROR, "LAN91x: PHY reset timed-out\n"));
- return EFI_TIMEOUT;
- }
- gBS->Stall (100);
- }
- return EFI_SUCCESS;
- }
- /* ---------------- General Operations ----------------- */
- STATIC
- EFI_MAC_ADDRESS
- GetCurrentMacAddress (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINTN RegNum;
- UINT8 *Addr;
- EFI_MAC_ADDRESS MacAddress;
- SetMem (&MacAddress, sizeof(MacAddress), 0);
- Addr = &MacAddress.Addr[0];
- for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) {
- *Addr = ReadIoReg8 (LanDriver, RegNum);
- ++Addr;
- }
- return MacAddress;
- }
- STATIC
- EFI_STATUS
- SetCurrentMacAddress (
- IN LAN91X_DRIVER *LanDriver,
- IN EFI_MAC_ADDRESS *MacAddress
- )
- {
- UINTN RegNum;
- UINT8 *Addr;
- Addr = &MacAddress->Addr[0];
- for (RegNum = LAN91X_IAR0; RegNum <= LAN91X_IAR5; ++RegNum) {
- WriteIoReg8 (LanDriver, RegNum, *Addr);
- ++Addr;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- MmuOperation (
- IN LAN91X_DRIVER *LanDriver,
- IN UINTN MmuOp
- )
- {
- UINTN Polls;
- WriteIoReg16 (LanDriver, LAN91X_MMUCR, MmuOp);
- Polls = 100;
- while ((ReadIoReg16 (LanDriver, LAN91X_MMUCR) & MMUCR_BUSY) != 0) {
- if (--Polls == 0) {
- DEBUG ((DEBUG_ERROR, "LAN91x: MMU operation %04x timed-out\n", MmuOp));
- return EFI_TIMEOUT;
- }
- gBS->Stall (LAN91X_STALL);
- }
- return EFI_SUCCESS;
- }
- // Read bytes from the DATA register
- STATIC
- EFI_STATUS
- ReadIoData (
- IN LAN91X_DRIVER *LanDriver,
- IN VOID *Buffer,
- IN UINTN BufLen
- )
- {
- UINT8 *Ptr;
- Ptr = Buffer;
- for (; BufLen > 0; --BufLen) {
- *Ptr = ReadIoReg8 (LanDriver, LAN91X_DATA0);
- ++Ptr;
- }
- return EFI_SUCCESS;
- }
- // Write bytes to the DATA register
- STATIC
- EFI_STATUS
- WriteIoData (
- IN LAN91X_DRIVER *LanDriver,
- IN VOID *Buffer,
- IN UINTN BufLen
- )
- {
- UINT8 *Ptr;
- Ptr = Buffer;
- for (; BufLen > 0; --BufLen) {
- WriteIoReg8 (LanDriver, LAN91X_DATA0, *Ptr);
- ++Ptr;
- }
- return EFI_SUCCESS;
- }
- // Disable the interface
- STATIC
- EFI_STATUS
- ChipDisable (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- #ifdef LAN91X_POWER_DOWN
- UINT16 Val16;
- #endif
- // Stop Rx and Tx operations
- WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);
- WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR);
- #ifdef LAN91X_POWER_DOWN
- // Power-down the chip
- Val16 = ReadIoReg16 (LanDriver, LAN91X_CR);
- Val16 &= ~CR_EPH_POWER_EN;
- WriteIoReg16 (LanDriver, LAN91X_CR, Val16);
- #endif
- return EFI_SUCCESS;
- }
- // Enable the interface
- STATIC
- EFI_STATUS
- ChipEnable (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- #ifdef LAN91X_POWER_DOWN
- UINT16 Val16;
- // Power-up the chip
- Val16 = ReadIoReg16 (LanDriver, LAN91X_CR);
- Val16 |= CR_EPH_POWER_EN;
- WriteIoReg16 (LanDriver, LAN91X_CR, Val16);
- gBS->Stall (LAN91X_STALL);
- #endif
- // Start Rx and Tx operations
- WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_DEFAULT);
- WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_DEFAULT);
- return EFI_SUCCESS;
- }
- // Perform software reset on the LAN91x
- STATIC
- EFI_STATUS
- SoftReset (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINT16 Val16;
- // Issue the reset
- WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_SOFT_RST);
- gBS->Stall (LAN91X_STALL);
- WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);
- // Set the configuration register
- WriteIoReg16 (LanDriver, LAN91X_CR, CR_DEFAULT);
- gBS->Stall (LAN91X_STALL);
- // Stop Rx and Tx
- WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR);
- WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR);
- // Initialize the Control Register
- Val16 = ReadIoReg16 (LanDriver, LAN91X_CTR);
- Val16 |= CTR_AUTO_REL;
- WriteIoReg16 (LanDriver, LAN91X_CTR, Val16);
- // Reset the MMU
- MmuOperation (LanDriver, MMUCR_OP_RESET_MMU);
- return EFI_SUCCESS;
- }
- /*
- ** Probe()
- **
- ** Validate that there is a LAN91x device.
- **
- */
- STATIC
- EFI_STATUS
- Probe (
- IN LAN91X_DRIVER *LanDriver
- )
- {
- UINT16 Bank;
- UINT16 Val16;
- CHAR16 CONST *ChipId;
- UINTN ResetTime;
- // First check that the Bank Select register is valid
- Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);
- if ((Bank & 0xff00) != 0x3300) {
- DEBUG ((DEBUG_ERROR, "LAN91x: signature error: expecting 33xx, read %04x\n", Bank));
- return EFI_DEVICE_ERROR;
- }
- // Try reading the revision register next
- LanDriver->BankSel = 0xff;
- Val16 = ReadIoReg16 (LanDriver, LAN91X_REV);
- Bank = MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET);
- if ((Bank & 0xff03) != 0x3303) {
- DEBUG ((DEBUG_ERROR, "LAN91x: signature error: expecting 33x3, read %04x\n", Bank));
- return EFI_DEVICE_ERROR;
- }
- // Validate the revision register
- if ((Val16 & 0xff00) != 0x3300) {
- DEBUG ((DEBUG_ERROR, "LAN91x: revision error: expecting 33xx, read %04x\n", Val16));
- return EFI_DEVICE_ERROR;
- }
- ChipId = ChipIds[(Val16 >> 4) & 0x0f];
- if (ChipId == NULL) {
- DEBUG ((DEBUG_ERROR, "LAN91x: unrecognized revision: %04x\n", Val16));
- return EFI_DEVICE_ERROR;
- }
- DEBUG ((DEBUG_ERROR, "LAN91x: detected chip %s rev %d\n", ChipId, Val16 & 0xf));
- LanDriver->Revision = Val16 & 0xff;
- // Reload from EEPROM to get the hardware MAC address
- WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED | CTR_RELOAD);
- ResetTime = 1000;
- while ((ReadIoReg16 (LanDriver, LAN91X_CTR) & CTR_RELOAD) != 0) {
- if (--ResetTime == 0) {
- DEBUG ((DEBUG_ERROR, "LAN91x: reload from EEPROM timed-out\n"));
- WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED);
- return EFI_DEVICE_ERROR;
- }
- gBS->Stall (LAN91X_STALL);
- }
- // Read and save the Permanent MAC Address
- LanDriver->SnpMode.PermanentAddress = GetCurrentMacAddress (LanDriver);
- LanDriver->SnpMode.CurrentAddress = LanDriver->SnpMode.PermanentAddress;
- DEBUG ((DEBUG_ERROR, //DEBUG_NET | DEBUG_INFO,
- "LAN91x: HW MAC Address: %02x-%02x-%02x-%02x-%02x-%02x\n",
- LanDriver->SnpMode.PermanentAddress.Addr[0],
- LanDriver->SnpMode.PermanentAddress.Addr[1],
- LanDriver->SnpMode.PermanentAddress.Addr[2],
- LanDriver->SnpMode.PermanentAddress.Addr[3],
- LanDriver->SnpMode.PermanentAddress.Addr[4],
- LanDriver->SnpMode.PermanentAddress.Addr[5]
- ));
- // Reset the device
- SoftReset (LanDriver);
- // Try to detect a PHY
- if (LanDriver->Revision > (CHIP_91100 << 4)) {
- PhyDetect (LanDriver);
- } else {
- LanDriver->PhyAd = LAN91X_NO_PHY;
- }
- return EFI_SUCCESS;
- }
- /*------------------ Simple Network Driver entry point functions ------------------*/
- // Refer to the Simple Network Protocol section (21.1)
- // in the UEFI 2.3.1 Specification for documentation.
- #define ReturnUnlock(s) do { Status = (s); goto exit_unlock; } while(0)
- /*
- ** UEFI Start() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpStart (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
- )
- {
- EFI_SIMPLE_NETWORK_MODE *Mode;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- Mode = Snp->Mode;
- // Check state of the driver
- switch (Mode->State) {
- case EfiSimpleNetworkStopped:
- break;
- case EfiSimpleNetworkStarted:
- case EfiSimpleNetworkInitialized:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver already started\n"));
- ReturnUnlock (EFI_ALREADY_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Change state
- Mode->State = EfiSimpleNetworkStarted;
- Status = EFI_SUCCESS;
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Stop() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpStop (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp Instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check state of the driver
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkStarted:
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Stop the Tx and Rx
- ChipDisable (LanDriver);
- // Change the state
- Snp->Mode->State = EfiSimpleNetworkStopped;
- Status = EFI_SUCCESS;
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Initialize() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpInitialize (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
- IN UINTN RxBufferSize OPTIONAL,
- IN UINTN TxBufferSize OPTIONAL
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp Instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started but not initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkStarted:
- break;
- case EfiSimpleNetworkInitialized:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver already initialized\n"));
- ReturnUnlock (EFI_SUCCESS);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Initiate a software reset
- Status = SoftReset (LanDriver);
- if (EFI_ERROR(Status)) {
- DEBUG ((DEBUG_WARN, "LAN91x: Soft reset failed\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Initiate a PHY reset
- if (PhySoftReset (LanDriver) < 0) {
- Snp->Mode->State = EfiSimpleNetworkStopped;
- DEBUG ((DEBUG_WARN, "LAN91x: PHY soft reset timeout\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- }
- // Do auto-negotiation
- Status = PhyAutoNegotiate (LanDriver);
- if (EFI_ERROR(Status)) {
- DEBUG ((DEBUG_WARN, "LAN91x: PHY auto-negotiation failed\n"));
- }
- // Enable the receiver and transmitter
- ChipEnable (LanDriver);
- // Now acknowledge all interrupts
- WriteIoReg8 (LanDriver, LAN91X_IST, 0xFF);
- // Declare the driver as initialized
- Snp->Mode->State = EfiSimpleNetworkInitialized;
- Status = EFI_SUCCESS;
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Reset () function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpReset (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
- IN BOOLEAN Verification
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp Instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started and initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Initiate a software reset
- if (EFI_ERROR (SoftReset (LanDriver))) {
- DEBUG ((DEBUG_WARN, "LAN91x: Soft reset failed\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Initiate a PHY reset
- if (EFI_ERROR (PhySoftReset (LanDriver))) {
- DEBUG ((DEBUG_WARN, "LAN91x: PHY soft reset failed\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Enable the receiver and transmitter
- Status = ChipEnable (LanDriver);
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Shutdown () function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpShutdown (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp Instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // First check that driver has already been initialized
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver in stopped state\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Disable the interface
- Status = ChipDisable (LanDriver);
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI ReceiveFilters() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpReceiveFilters (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
- IN UINT32 Enable,
- IN UINT32 Disable,
- IN BOOLEAN Reset,
- IN UINTN NumMfilter OPTIONAL,
- IN EFI_MAC_ADDRESS *Mfilter OPTIONAL
- )
- {
- #define MCAST_HASH_BYTES 8
- LAN91X_DRIVER *LanDriver;
- EFI_SIMPLE_NETWORK_MODE *SnpMode;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- UINTN i;
- UINT32 Crc;
- UINT16 RcvCtrl;
- UINT8 McastHash[MCAST_HASH_BYTES];
- // Check Snp Instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // First check that driver has already been initialized
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- SnpMode = Snp->Mode;
- #ifdef LAN91X_PRINT_RECEIVE_FILTERS
- DEBUG ((DEBUG_ERROR, "LAN91x:SnpReceiveFilters()\n"));
- DEBUG ((DEBUG_ERROR, " Enable = %08x\n", Enable));
- DEBUG ((DEBUG_ERROR, " Disable = %08x\n", Disable));
- DEBUG ((DEBUG_ERROR, " Reset = %d\n", Reset));
- DEBUG ((DEBUG_ERROR, " NumMfilter = %d\n", NumMfilter));
- for (i = 0; i < NumMfilter; ++i) {
- DEBUG ((DEBUG_ERROR,
- " [%2d] = %02x-%02x-%02x-%02x-%02x-%02x\n",
- i,
- Mfilter[i].Addr[0],
- Mfilter[i].Addr[1],
- Mfilter[i].Addr[2],
- Mfilter[i].Addr[3],
- Mfilter[i].Addr[4],
- Mfilter[i].Addr[5]));
- }
- #endif
- // Update the Multicast Hash registers
- if (Reset) {
- // Clear the hash table
- SetMem (McastHash, MCAST_HASH_BYTES, 0);
- SnpMode->MCastFilterCount = 0;
- } else {
- // Read the current hash table
- for (i = 0; i < MCAST_HASH_BYTES; ++i) {
- McastHash[i] = ReadIoReg8 (LanDriver, LAN91X_MT0 + i);
- }
- // Set the new additions
- for (i = 0; i < NumMfilter; ++i) {
- Crc = MulticastHash (&Mfilter[i], NET_ETHER_ADDR_LEN);
- McastHash[(Crc >> 29) & 0x3] |= 1 << ((Crc >> 26) & 0x3);
- }
- SnpMode->MCastFilterCount = NumMfilter;
- }
- // If the hash registers need updating, write them
- if (Reset || NumMfilter > 0) {
- for (i = 0; i < MCAST_HASH_BYTES; ++i) {
- WriteIoReg8 (LanDriver, LAN91X_MT0 + i, McastHash[i]);
- }
- }
- RcvCtrl = ReadIoReg16 (LanDriver, LAN91X_RCR);
- if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
- RcvCtrl |= RCR_PRMS;
- SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
- }
- if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
- RcvCtrl &= ~RCR_PRMS;
- SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
- }
- if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
- RcvCtrl |= RCR_ALMUL;
- SnpMode->ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
- }
- if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
- RcvCtrl &= ~RCR_ALMUL;
- SnpMode->ReceiveFilterSetting &= ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
- }
- WriteIoReg16 (LanDriver, LAN91X_RCR, RcvCtrl);
- Status = SetCurrentMacAddress (LanDriver, &SnpMode->CurrentAddress);
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI StationAddress() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpStationAddress (
- IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
- IN BOOLEAN Reset,
- IN EFI_MAC_ADDRESS *NewMac
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started and initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- if (Reset) {
- Snp->Mode->CurrentAddress = Snp->Mode->PermanentAddress;
- } else {
- if (NewMac == NULL) {
- ReturnUnlock (EFI_INVALID_PARAMETER);
- }
- Snp->Mode->CurrentAddress = *NewMac;
- }
- Status = SetCurrentMacAddress (LanDriver, &Snp->Mode->CurrentAddress);
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Statistics() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpStatistics (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
- IN BOOLEAN Reset,
- IN OUT UINTN *StatSize,
- OUT EFI_NETWORK_STATISTICS *Statistics
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- // Check Snp instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Check pointless condition
- if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) {
- return EFI_SUCCESS;
- }
- // Check the parameters
- if ((StatSize == NULL) && (Statistics != NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started and initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Do a reset if required
- if (Reset) {
- ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));
- }
- // Check buffer size
- if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) {
- *StatSize = sizeof(EFI_NETWORK_STATISTICS);
- ReturnUnlock (EFI_BUFFER_TOO_SMALL);
- goto exit_unlock;
- }
- // Fill in the statistics
- CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS));
- Status = EFI_SUCCESS;
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI MCastIPtoMAC() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpMcastIptoMac (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp,
- IN BOOLEAN IsIpv6,
- IN EFI_IP_ADDRESS *Ip,
- OUT EFI_MAC_ADDRESS *McastMac
- )
- {
- // Check Snp instance
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Check parameters
- if ((McastMac == NULL) || (Ip == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- // Make sure MAC address is empty
- ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS));
- // If we need ipv4 address
- if (!IsIpv6) {
- // Most significant 25 bits of a multicast HW address are set
- McastMac->Addr[0] = 0x01;
- McastMac->Addr[1] = 0x00;
- McastMac->Addr[2] = 0x5E;
- // Lower 23 bits from ipv4 address
- McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the ms bit (25th bit of MAC must be 0)
- McastMac->Addr[4] = Ip->v4.Addr[2];
- McastMac->Addr[5] = Ip->v4.Addr[3];
- } else {
- // Most significant 16 bits of multicast v6 HW address are set
- McastMac->Addr[0] = 0x33;
- McastMac->Addr[1] = 0x33;
- // lower four octets are taken from ipv6 address
- McastMac->Addr[2] = Ip->v6.Addr[8];
- McastMac->Addr[3] = Ip->v6.Addr[9];
- McastMac->Addr[4] = Ip->v6.Addr[10];
- McastMac->Addr[5] = Ip->v6.Addr[11];
- }
- return EFI_SUCCESS;
- }
- /*
- ** UEFI NvData() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpNvData (
- IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj,
- IN BOOLEAN read_write,
- IN UINTN offset,
- IN UINTN buff_size,
- IN OUT VOID *data
- )
- {
- DEBUG ((DEBUG_ERROR, "LAN91x: Non-volatile storage not supported\n"));
- return EFI_UNSUPPORTED;
- }
- /*
- ** UEFI GetStatus () function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpGetStatus (
- IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
- OUT UINT32 *IrqStat OPTIONAL,
- OUT VOID **TxBuff OPTIONAL
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- BOOLEAN MediaPresent;
- UINT8 IstReg;
- MSK_LINKED_SYSTEM_BUF *LinkedTXRecycleBuff;
- // Check preliminaries
- if (Snp == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started and initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Arbitrarily set the interrupt status to 0
- if (IrqStat != NULL) {
- *IrqStat = 0;
- IstReg = ReadIoReg8 (LanDriver, LAN91X_IST);
- if ((IstReg & IST_RCV) != 0) {
- *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
- }
- if ((IstReg & IST_TX) != 0) {
- *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
- }
- }
- // Pass back the completed buffer address
- // The transmit buffer status is not read when TxBuf is NULL
- if (TxBuff != NULL) {
- *((UINT8 **) TxBuff) = (UINT8 *) 0;
- if( !IsListEmpty (&LanDriver->TransmitQueueHead))
- {
- LinkedTXRecycleBuff = CR (GetFirstNode (&LanDriver->TransmitQueueHead), MSK_LINKED_SYSTEM_BUF, Link, TX_MBUF_SIGNATURE);
- if(LinkedTXRecycleBuff != NULL) {
- *TxBuff = LinkedTXRecycleBuff->SystemBuf.Buf;
- RemoveEntryList (&LinkedTXRecycleBuff->Link);
- FreePool (LinkedTXRecycleBuff);
- }
- }
- }
- // Update the media status
- MediaPresent = CheckLinkStatus (LanDriver);
- if (MediaPresent != Snp->Mode->MediaPresent) {
- DEBUG ((DEBUG_WARN, "LAN91x: Link %s\n", MediaPresent ? L"up" : L"down"));
- }
- Snp->Mode->MediaPresent = MediaPresent;
- Status = EFI_SUCCESS;
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Transmit() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpTransmit (
- IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
- IN UINTN HdrSize,
- IN UINTN BufSize,
- IN VOID *BufAddr,
- IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
- IN EFI_MAC_ADDRESS *DstAddr OPTIONAL,
- IN UINT16 *Protocol OPTIONAL
- )
- {
- LAN91X_DRIVER *LanDriver;
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- UINT8 *Ptr;
- UINTN Len;
- UINTN MmuPages;
- UINTN Retries;
- UINT16 Proto;
- UINT8 PktNum;
- MSK_LINKED_SYSTEM_BUF *LinkedTXRecycleBuff;
- // Check preliminaries
- if ((Snp == NULL) || (BufAddr == NULL)) {
- DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): NULL Snp (%p) or BufAddr (%p)\n",
- Snp, BufAddr));
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started and initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Ensure header is correct size if non-zero
- if (HdrSize != 0) {
- if (HdrSize != Snp->Mode->MediaHeaderSize) {
- DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): Invalid HdrSize %d\n", HdrSize));
- ReturnUnlock (EFI_INVALID_PARAMETER);
- }
- if ((DstAddr == NULL) || (Protocol == NULL)) {
- DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): NULL DstAddr %p or Protocol %p\n",
- DstAddr, Protocol));
- ReturnUnlock (EFI_INVALID_PARAMETER);
- }
- }
- // Before transmitting check the link status
- if (!Snp->Mode->MediaPresent) {
- DEBUG ((DEBUG_WARN, "LAN91x: SnpTransmit(): Link not ready\n"));
- ReturnUnlock (EFI_NOT_READY);
- }
- // Calculate the request size in 256-byte "pages" minus 1
- // The 91C111 ignores this, but some older devices need it.
- MmuPages = ((BufSize & ~1) + LAN91X_PKT_OVERHEAD - 1) >> 8;
- if (MmuPages > 7) {
- DEBUG ((DEBUG_WARN, "LAN91x: Tx buffer too large (%d bytes)\n", BufSize));
- LanDriver->Stats.TxOversizeFrames += 1;
- LanDriver->Stats.TxDroppedFrames += 1;
- ReturnUnlock (EFI_BAD_BUFFER_SIZE);
- }
- // Request allocation of a transmit buffer
- Status = MmuOperation (LanDriver, MMUCR_OP_TX_ALLOC | MmuPages);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer request failure: %d\n", Status));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Wait for allocation request completion
- Retries = LAN91X_MEMORY_ALLOC_POLLS;
- while ((ReadIoReg8 (LanDriver, LAN91X_IST) & IST_ALLOC) == 0) {
- if (--Retries == 0) {
- DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer allocation timeout\n"));
- ReturnUnlock (EFI_TIMEOUT);
- }
- }
- // Check for successful allocation
- PktNum = ReadIoReg8 (LanDriver, LAN91X_ARR);
- if ((PktNum & ARR_FAILED) != 0) {
- DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer allocation failure: %02x\n", PktNum));
- ReturnUnlock (EFI_NOT_READY);
- }
- PktNum &= ARR_PACKET;
- // Check for the nature of the frame
- // If no destination address, it's ARP broadcast
- if(DstAddr != NULL)
- {
- if (DstAddr->Addr[0] == 0xFF) {
- LanDriver->Stats.TxBroadcastFrames += 1;
- } else if ((DstAddr->Addr[0] & 0x1) == 1) {
- LanDriver->Stats.TxMulticastFrames += 1;
- } else {
- LanDriver->Stats.TxUnicastFrames += 1;
- }
- } else {
- LanDriver->Stats.TxBroadcastFrames += 1;
- }
- // Set the Packet Number and Pointer registers
- WriteIoReg8 (LanDriver, LAN91X_PNR, PktNum);
- WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_AUTO_INCR);
- // Set up mutable buffer information variables
- Ptr = BufAddr;
- Len = BufSize;
- // Write Status and Byte Count first
- WriteIoReg16 (LanDriver, LAN91X_DATA0, 0);
- WriteIoReg16 (LanDriver, LAN91X_DATA0, (Len + LAN91X_PKT_OVERHEAD) & BCW_COUNT);
- // This packet may come with a preconfigured Ethernet header.
- // If not, we need to construct one from optional parameters.
- if (HdrSize) {
- // Write the destination address
- WriteIoData (LanDriver, DstAddr, NET_ETHER_ADDR_LEN);
- // Write the Source Address
- if (SrcAddr != NULL) {
- WriteIoData (LanDriver, SrcAddr, NET_ETHER_ADDR_LEN);
- } else {
- WriteIoData (LanDriver, &LanDriver->SnpMode.CurrentAddress, NET_ETHER_ADDR_LEN);
- }
- // Write the Protocol word
- Proto = HTONS (*Protocol);
- WriteIoReg16 (LanDriver, LAN91X_DATA0, Proto);
- // Adjust the data start and length
- Ptr += sizeof(ETHER_HEAD);
- Len -= sizeof(ETHER_HEAD);
- }
- // Copy the remainder data buffer, except the odd byte
- WriteIoData (LanDriver, Ptr, Len & ~1);
- Ptr += Len & ~1;
- Len &= 1;
- // Write the Packet Control Word and odd byte
- WriteIoReg16 (LanDriver, LAN91X_DATA0,
- (Len != 0) ? (PCW_ODD | PCW_CRC | *Ptr) : PCW_CRC);
- // Release the packet for transmission
- Status = MmuOperation (LanDriver, MMUCR_OP_TX_PUSH);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer release failure: %d\n", Status));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Update the Tx statistics
- LanDriver->Stats.TxTotalBytes += BufSize;
- LanDriver->Stats.TxGoodFrames += 1;
- // Update the Tx Buffer cache
- LinkedTXRecycleBuff = AllocateZeroPool (sizeof (MSK_LINKED_SYSTEM_BUF));
- if (LinkedTXRecycleBuff == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- LinkedTXRecycleBuff->Signature = TX_MBUF_SIGNATURE;
- //
- // Add the passed Buffer to the transmit queue. Don't copy.
- //
- LinkedTXRecycleBuff->SystemBuf.Buf = BufAddr;
- LinkedTXRecycleBuff->SystemBuf.Length = BufSize;
- InsertTailList (&LanDriver->TransmitQueueHead, &LinkedTXRecycleBuff->Link);
- Status = EFI_SUCCESS;
- // Dump the packet header
- #if LAN91X_PRINT_PACKET_HEADERS
- Ptr = BufAddr;
- DEBUG ((DEBUG_ERROR, "LAN91X:SnpTransmit()\n"));
- DEBUG ((DEBUG_ERROR, " HdrSize: %d, SrcAddr: %p, Length: %d, Last byte: %02x\n",
- HdrSize, SrcAddr, BufSize, Ptr[BufSize - 1]));
- PrintIpDgram (
- (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[0] : DstAddr,
- (HdrSize == 0) ? (EFI_MAC_ADDRESS *)&Ptr[6] : (SrcAddr != NULL) ? SrcAddr : &LanDriver->SnpMode.CurrentAddress,
- (HdrSize == 0) ? (UINT16 *)&Ptr[12] : &Proto,
- &Ptr[14]
- );
- #endif
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*
- ** UEFI Receive() function
- **
- */
- EFI_STATUS
- EFIAPI
- SnpReceive (
- IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
- OUT UINTN *HdrSize OPTIONAL,
- IN OUT UINTN *BuffSize,
- OUT VOID *Data,
- OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
- OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,
- OUT UINT16 *Protocol OPTIONAL
- )
- {
- EFI_TPL SavedTpl;
- EFI_STATUS Status;
- LAN91X_DRIVER *LanDriver;
- UINT8 *DataPtr;
- UINT16 PktStatus;
- UINT16 PktLength;
- UINT16 PktControl;
- UINT8 IstReg;
- // Check preliminaries
- if ((Snp == NULL) || (Data == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- // Serialize access to data and registers
- SavedTpl = gBS->RaiseTPL (LAN91X_TPL);
- // Check that driver was started and initialised
- switch (Snp->Mode->State) {
- case EfiSimpleNetworkInitialized:
- break;
- case EfiSimpleNetworkStarted:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n"));
- ReturnUnlock (EFI_DEVICE_ERROR);
- case EfiSimpleNetworkStopped:
- DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n"));
- ReturnUnlock (EFI_NOT_STARTED);
- default:
- DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n",
- (UINTN)Snp->Mode->State));
- ReturnUnlock (EFI_DEVICE_ERROR);
- }
- // Find the LanDriver structure
- LanDriver = INSTANCE_FROM_SNP_THIS(Snp);
- // Check for Rx Overrun
- IstReg = ReadIoReg8 (LanDriver, LAN91X_IST);
- if ((IstReg & IST_RX_OVRN) != 0) {
- LanDriver->Stats.RxTotalFrames += 1;
- LanDriver->Stats.RxDroppedFrames += 1;
- WriteIoReg8 (LanDriver, LAN91X_IST, IST_RX_OVRN);
- DEBUG ((DEBUG_WARN, "LAN91x: Receiver overrun\n"));
- }
- // Check for Rx data available
- if ((IstReg & IST_RCV) == 0) {
- ReturnUnlock (EFI_NOT_READY);
- }
- // Configure the PTR register for reading
- WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_RCV | PTR_AUTO_INCR | PTR_READ);
- // Read the Packet Status and Packet Length words
- PktStatus = ReadIoReg16 (LanDriver, LAN91X_DATA0);
- PktLength = ReadIoReg16 (LanDriver, LAN91X_DATA0) & BCW_COUNT;
- // Check for valid received packet
- if ((PktStatus == 0) && (PktLength == 0)) {
- DEBUG ((DEBUG_WARN, "LAN91x: Received zero-length packet. IST=%04x\n", IstReg));
- ReturnUnlock (EFI_NOT_READY);
- }
- LanDriver->Stats.RxTotalFrames += 1;
- // Check if we got a CRC error
- if ((PktStatus & RX_BAD_CRC) != 0) {
- DEBUG ((DEBUG_WARN, "LAN91x: Received frame CRC error\n"));
- LanDriver->Stats.RxCrcErrorFrames += 1;
- LanDriver->Stats.RxDroppedFrames += 1;
- Status = EFI_DEVICE_ERROR;
- goto exit_release;
- }
- // Check if we got a too-short frame
- if ((PktStatus & RX_TOO_SHORT) != 0) {
- DEBUG ((DEBUG_WARN, "LAN91x: Received frame too short (%d bytes)\n", PktLength));
- LanDriver->Stats.RxUndersizeFrames += 1;
- LanDriver->Stats.RxDroppedFrames += 1;
- Status = EFI_DEVICE_ERROR;
- goto exit_release;
- }
- // Check if we got a too-long frame
- if ((PktStatus & RX_TOO_LONG) != 0) {
- DEBUG ((DEBUG_WARN, "LAN91x: Received frame too long (%d bytes)\n", PktLength));
- LanDriver->Stats.RxOversizeFrames += 1;
- LanDriver->Stats.RxDroppedFrames += 1;
- Status = EFI_DEVICE_ERROR;
- goto exit_release;
- }
- // Check if we got an alignment error
- if ((PktStatus & RX_ALGN_ERR) != 0) {
- DEBUG ((DEBUG_WARN, "LAN91x: Received frame alignment error\n"));
- // Don't seem to keep track of these specifically
- LanDriver->Stats.RxDroppedFrames += 1;
- Status = EFI_DEVICE_ERROR;
- goto exit_release;
- }
- // Classify the received fram
- if ((PktStatus & RX_MULTICAST) != 0) {
- LanDriver->Stats.RxMulticastFrames += 1;
- } else if ((PktStatus & RX_BROADCAST) != 0) {
- LanDriver->Stats.RxBroadcastFrames += 1;
- } else {
- LanDriver->Stats.RxUnicastFrames += 1;
- }
- // Calculate the received packet data length
- PktLength -= LAN91X_PKT_OVERHEAD;
- if ((PktStatus & RX_ODD_FRAME) != 0) {
- PktLength += 1;
- }
- // Check buffer size
- if (*BuffSize < PktLength) {
- DEBUG ((DEBUG_WARN, "LAN91x: Receive buffer too small for packet (%d < %d)\n",
- *BuffSize, PktLength));
- *BuffSize = PktLength;
- Status = EFI_BUFFER_TOO_SMALL;
- goto exit_release;
- }
- // Transfer the data bytes
- DataPtr = Data;
- ReadIoData (LanDriver, DataPtr, PktLength & ~0x0001);
- // Read the PktControl and Odd Byte from the FIFO
- PktControl = ReadIoReg16 (LanDriver, LAN91X_DATA0);
- if ((PktControl & PCW_ODD) != 0) {
- DataPtr[PktLength - 1] = PktControl & PCW_ODD_BYTE;
- }
- // Update buffer size
- *BuffSize = PktLength;
- if (HdrSize != NULL) {
- *HdrSize = LanDriver->SnpMode.MediaHeaderSize;
- }
- // Extract the destination address
- if (DstAddr != NULL) {
- CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN);
- }
- // Get the source address
- if (SrcAddr != NULL) {
- CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN);
- }
- // Get the protocol
- if (Protocol != NULL) {
- *Protocol = NTOHS (*(UINT16*)(&DataPtr[12]));
- }
- // Update the Rx statistics
- LanDriver->Stats.RxTotalBytes += PktLength;
- LanDriver->Stats.RxGoodFrames += 1;
- Status = EFI_SUCCESS;
- #if LAN91X_PRINT_PACKET_HEADERS
- // Dump the packet header
- DEBUG ((DEBUG_ERROR, "LAN91X:SnpReceive()\n"));
- DEBUG ((DEBUG_ERROR, " HdrSize: %p, SrcAddr: %p, DstAddr: %p, Protocol: %p\n",
- HdrSize, SrcAddr, DstAddr, Protocol));
- DEBUG ((DEBUG_ERROR, " Length: %d, Last byte: %02x\n", PktLength, DataPtr[PktLength - 1]));
- PrintIpDgram (&DataPtr[0], &DataPtr[6], &DataPtr[12], &DataPtr[14]);
- #endif
- // Release the FIFO buffer
- exit_release:
- MmuOperation (LanDriver, MMUCR_OP_RX_POP_REL);
- // Restore TPL and return
- exit_unlock:
- gBS->RestoreTPL (SavedTpl);
- return Status;
- }
- /*------------------ Driver Execution Environment main entry point ------------------*/
- /*
- ** Entry point for the LAN91x driver
- **
- */
- EFI_STATUS
- Lan91xDxeEntry (
- IN EFI_HANDLE Handle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- LAN91X_DRIVER *LanDriver;
- EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
- EFI_SIMPLE_NETWORK_MODE *SnpMode;
- LAN91X_DEVICE_PATH *Lan91xPath;
- // The PcdLan91xDxeBaseAddress PCD must be defined
- ASSERT(PcdGet32 (PcdLan91xDxeBaseAddress) != 0);
- // Allocate Resources
- LanDriver = AllocateZeroPool (sizeof(LAN91X_DRIVER));
- Lan91xPath = AllocateCopyPool (sizeof(LAN91X_DEVICE_PATH), &Lan91xPathTemplate);
- // Initialize I/O Space access info
- LanDriver->IoBase = PcdGet32 (PcdLan91xDxeBaseAddress);
- LanDriver->PhyAd = LAN91X_NO_PHY;
- LanDriver->BankSel = 0xff;
- // Initialize pointers
- Snp = &(LanDriver->Snp);
- SnpMode = &(LanDriver->SnpMode);
- Snp->Mode = SnpMode;
- // Set the signature of the LAN Driver structure
- LanDriver->Signature = LAN91X_SIGNATURE;
- // Probe the device
- Status = Probe (LanDriver);
- if (EFI_ERROR(Status)) {
- DEBUG ((DEBUG_ERROR, "LAN91x:Lan91xDxeEntry(): Probe failed with status %d\n", Status));
- return Status;
- }
- #ifdef LAN91X_PRINT_REGISTERS
- PrintIoRegisters (LanDriver);
- PrintPhyRegisters (LanDriver);
- #endif
- // Initialize transmit queue
- InitializeListHead (&LanDriver->TransmitQueueHead);
- // Assign fields and func pointers
- Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
- Snp->WaitForPacket = NULL;
- Snp->Initialize = SnpInitialize;
- Snp->Start = SnpStart;
- Snp->Stop = SnpStop;
- Snp->Reset = SnpReset;
- Snp->Shutdown = SnpShutdown;
- Snp->ReceiveFilters = SnpReceiveFilters;
- Snp->StationAddress = SnpStationAddress;
- Snp->Statistics = SnpStatistics;
- Snp->MCastIpToMac = SnpMcastIptoMac;
- Snp->NvData = SnpNvData;
- Snp->GetStatus = SnpGetStatus;
- Snp->Transmit = SnpTransmit;
- Snp->Receive = SnpReceive;
- // Fill in simple network mode structure
- SnpMode->State = EfiSimpleNetworkStopped;
- SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes
- SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Size of an Ethernet header
- SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Ethernet Frame (with VLAN tag +4 bytes)
- // Supported receive filters
- SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
- EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
- EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
- EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
- EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
- // Initially-enabled receive filters
- SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
- EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
- EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
- // LAN91x has 64bit hash table. We can filter an infinite MACs, but
- // higher-level software must filter out any hash collisions.
- SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
- SnpMode->MCastFilterCount = 0;
- ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));
- // Set the interface type (1: Ethernet or 6: IEEE 802 Networks)
- SnpMode->IfType = NET_IFTYPE_ETHERNET;
- // Mac address is changeable
- SnpMode->MacAddressChangeable = TRUE;
- // We can only transmit one packet at a time
- SnpMode->MultipleTxSupported = FALSE;
- // MediaPresent checks for cable connection and partner link
- SnpMode->MediaPresentSupported = TRUE;
- SnpMode->MediaPresent = FALSE;
- // Set broadcast address
- SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
- // Assign fields for device path
- Lan91xPath->Lan91x.MacAddress = SnpMode->PermanentAddress;
- Lan91xPath->Lan91x.IfType = SnpMode->IfType;
- // Initialise the protocol
- Status = gBS->InstallMultipleProtocolInterfaces (
- &LanDriver->ControllerHandle,
- &gEfiSimpleNetworkProtocolGuid, Snp,
- &gEfiDevicePathProtocolGuid, Lan91xPath,
- NULL
- );
- // Say what the status of loading the protocol structure is
- if (EFI_ERROR(Status)) {
- FreePool (LanDriver);
- }
- return Status;
- }
|