lan9115driver_source.c

* Copyright(c) 2005-2007 SMSC
 *
 *  Use of this source code is subject to the terms of the SMSC Software
 *  License Agreement (SLA) under which you licensed this software product.     
 *  If you did not accept the terms of the SLA, you are not authorized to use
 *  this source code.
 * 
 *  This code and information is provided as is without warranty of any kind,
 *  either expressed or implied, including but not limited to the implied
 *  warranties of merchantability and/or fitness for a particular purpose.
 *  
 *  File name   : smsc9118.c
 *  Description : smsc9118 polled driver (non-interrupt driven)
 * 
 *  History        :
 *      09-27-06 MDG        v1.0 (First Release)
 *            modified for ARM platform
 *      08-22-07 MDG        support entire 118/218/9211 family
 *      06-07-08 AH         support entire 9210/9220/9221 family
 *      08-04-08 AH         v1.10 Code cleanup and updates per latest LAN9118 family PAS
 *     09-05-24            www.diffview.com  检查提供 check for offer
 *----------------------------------------------------------------------------*/

#include <common.h>
#include <command.h>
#include <config.h>
#include "smsc9118.h"
#include <net.h>

#ifdef CONFIG_DRIVER_SMSC9118

//*************************************************************************
 //  FUNCTION PROTOTYPES

//*************************************************************************
int    eth_init(bd_t *bd);
void eth_halt(void);
int    eth_rx(void);
int    eth_send(volatile void *packet, int length);
extern void *malloc( unsigned ); // <stdlib.h>
extern void free( void * ); // <stdlib.h>

//*************************************************************************
 //  LOCAL DEFINITIONS AND MACROS

//*************************************************************************
//#define    DEBUG
#define     GPIO_OUT(val)              (*GPIO_CFG = ((*GPIO_CFG & ~GPIO_CFG_GPIOD_MSK) | (val & GPIO_CFG_GPIOD_MSK)))
#define     ENET_MAX_MTU            PKTSIZE
#define     ENET_MAX_MTU_ALIGNED    PKTSIZE_ALIGN
#define     NUM_RX_BUFF               PKTBUFSRX
#define        ENET_ADDR_LENGTH        6
#define        TX_TIMEOUT_COUNT        30    // waiting for TX_FIFO to drain


//*************************************************************************
 // GLOBAL DATA

//*************************************************************************
static const char date_code[] = BUILD_NUMBER;

static char * txbp;                 // TX buffer pointer (only 1 buffer)
static volatile char * rxbp[PKTBUFSRX];   // Receiver buffer queue (IP layers)
static struct rxQue rxAvlQue[PKTBUFSRX]; // Receive buffer available queue
static int rxNdx = 0;                // Current receive buffer index
static int rxNdxIn = 0;             // Used for input
static int rxNdxOut = 0;            // Used for output to protocol layer
static ushort lastTxTag = 0x0;
static unsigned char macAddr[ENET_ADDR_LENGTH];

// Temp variables
//#ifdef        DEBUG
ulong MaxRxFifoSz;
ulong TotalInts = 0;
ulong TotalRXE = 0;
ulong TotalRxPackets = 0;
ulong TotalBytes = 0;
ulong EmptyReads = 0;

ulong RxPacketBuf[400];
ulong SWIntTriggered = FALSE;
ulong TotalRxDrop = 0;
ulong TotalPackets = 0;
ulong TotalWords = 0;
ulong TBLower1, TBLower2;
//#endif
// Temp variables


//*************************************************************************
 // EXTERNS

//*************************************************************************
#ifdef        DEBUG
extern int use_smsc9118;
#endif

static void lan9118_udelay(unsigned long delta)    // Arg is really microseconds
{
    const unsigned long    start = *FREE_RUN,    // Start timing
                        usec = delta * (25000000/1000000);

    // usec adjusted for 25MHz on-chip clock, 1 microsecond (1/1000000) scaling
    do {
        delta = *FREE_RUN;
        if (delta >= start)
            delta = (delta - start);
        else
            delta = (delta - start) + 1;    // use 0x100000000, not 0xffffffff
    } while (delta < usec);
}

static int MacBusy(int ReqTO)
{
      int timeout = ReqTO;
      int RetVal = FALSE;      // No timeout

      while (timeout--) {
            if (!(*MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY)) {
                  goto done;
            }
      }
      RetVal = TRUE;          // Timeout
done:
      return (RetVal);
}

static ulong
GetMacReg(int Reg)
{
      ulong RegVal = 0xffffffff;

      if (*MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
            LAN9118_WARN("GetMacReg: previous command not complete/n");
            goto done;
      }

      *MAC_CSR_CMD = MAC_RD_CMD(Reg);
      DELAY(1);

      if (MacBusy(MAC_TIMEOUT) == TRUE) {
            LAN9118_WARN("GetMacReg: timeout waiting for response "
                  "from MAC/n");
            goto done;
      }

      RegVal = *MAC_CSR_DATA;
done:
      return (RegVal);
}

static int
PhyBusy(int ReqTO)
{
      int timeout = ReqTO;
      int RetVal = FALSE;      // No timeout

      while (timeout--) {
            if (!(GetMacReg(MAC_MIIACC) & MAC_MIIACC_MII_BUSY)) {
                  goto done;
            }
      }

      RetVal = TRUE;          // Timeout
done:
      return (RetVal);
}

static int
SetMacReg(int Reg, ulong Value)
{
      int RetVal = FALSE;

      if (*MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
            LAN9118_WARN("SetMacReg: previous command not complete/n");
            goto done;
      }

      *MAC_CSR_DATA = Value;
      DELAY(1);
      *MAC_CSR_CMD = MAC_WR_CMD(Reg);
      DELAY(1);

      if (MacBusy(MAC_TIMEOUT) == TRUE) {
            LAN9118_WARN("SetMacReg: timeout waiting for response "
                  "from MAC/n");
                  goto done;
      }

      RetVal = TRUE;
done:
      return (RetVal);
}

static ushort
GetPhyReg(unchar Reg)
{
      ushort RegVal = 0xffff;

      if (GetMacReg(MAC_MIIACC) & MAC_MIIACC_MII_BUSY) {
            LAN9118_WARN("GetPhyReg: MII busy/n");
            RegVal = 0;
            goto done;
      }

      SetMacReg(MAC_MIIACC, MAC_MII_RD_CMD((unchar)PHY_ADDR, Reg));
      DELAY(1);

      if (PhyBusy(PHY_TIMEOUT) == TRUE) {
            LAN9118_WARN("GetPhyReg: timeout waiting for MII command/n");
            goto done;
      }

      RegVal = (ushort)GetMacReg(MAC_MIIDATA);
done:
      return (RegVal);
}

static int
SetPhyReg(unchar Reg, ushort Value)
{
      int RetVal = FALSE;

      if (GetMacReg(MAC_MIIACC) & MAC_MIIACC_MII_BUSY) {
            LAN9118_WARN("SetPhyReg: MII busy/n");
            goto done;
      }

      SetMacReg(MAC_MIIDATA, Value);
      DELAY(1);
      SetMacReg(MAC_MIIACC, MAC_MII_WR_CMD((unchar)PHY_ADDR, Reg));
      DELAY(1);

      if (PhyBusy(PHY_TIMEOUT) == TRUE) {
            LAN9118_WARN("SetPhyReg: timeout waiting for MII command/n");
            goto done;
      }

      RetVal = TRUE;
done:
      return (RetVal);
}

// Display directly accessed, Control/Status Registers
static int
DumpCsrRegs(void)
{
      printf("ID_REV:/t/t0x%0.8x/n", *ID_REV);
      printf("IRQ_CFG:/t0x%0.8x/n", *IRQ_CFG);
      printf("INT_STS:/t0x%0.8x/n", *INT_STS);
      printf("INT_EN:/t/t0x%0.8x/n", *INT_EN);
      printf("BYTE_TEST:/t0x%0.8x/n", *BYTE_TEST);
      printf("FIFO_INT:/t0x%0.8x/n", *FIFO_INT);
      printf("RX_CFG:/t/t0x%0.8x/n", *RX_CFG);
      printf("TX_CFG:/t/t0x%0.8x/n", *TX_CFG);
      printf("HW_CFG:/t/t0x%0.8x/n", *HW_CFG);
      printf("RX_DP_CTL:/t0x%0.8x/n", *RX_DP_CTL);
      printf("RX_FIFO_INF:/t0x%0.8x/n", *RX_FIFO_INF);
      printf("TX_FIFO_INF:/t0x%0.8x/n", *TX_FIFO_INF);
      printf("PWR_MGMT:/t0x%0.8x/n", *PWR_MGMT);
      printf("GPIO_CFG:/t0x%0.8x/n", *GPIO_CFG);
      printf("GPT_CFG:/t0x%0.8x/n", *GPT_CFG);
      printf("GPT_CNT:/t0x%0.8x/n", *GPT_CNT);
      printf("FPGA_REV:/t0x%0.8x/n", *FPGA_REV);
      printf("ENDIAN:/t/t0x%0.8x/n", *ENDIAN);
      printf("FREE_RUN/t0x%0.8x/n", *FREE_RUN);
      printf("RX_DROP/t/t0x%0.8x/n", *RX_DROP);
      printf("MAC_CSR_CMD/t0x%0.8x/n", *MAC_CSR_CMD);
      printf("MAC_CSR_DATA/t0x%0.8x/n", *MAC_CSR_DATA);
      printf("AFC_CFG/t/t0x%0.8x/n", *AFC_CFG);
      return (0);
}

// Display Media Access Controller Registers
static int
DumpMacRegs(void)
{
      printf("MAC_CR/t/t0x%0.8x/n", GetMacReg(MAC_CR));
      printf("MAC_ADDRH/t0x%0.8x/n", GetMacReg(MAC_ADDRH));
      printf("MAC_ADDRL/t0x%0.8x/n", GetMacReg(MAC_ADDRL));
      printf("MAC_HASHH/t0x%0.8x/n", GetMacReg(MAC_HASHH));
      printf("MAC_HASHL/t0x%0.8x/n", GetMacReg(MAC_HASHL));
      printf("MAC_MIIACC/t0x%0.8x/n", GetMacReg(MAC_MIIACC));
      printf("MAC_MIIDATA/t0x%0.8x/n", GetMacReg(MAC_MIIDATA));
      printf("MAC_FLOW/t0x%0.8x/n", GetMacReg(MAC_FLOW));
      printf("MAC_VLAN1/t0x%0.8x/n", GetMacReg(MAC_VLAN1));
      printf("MAC_VLAN2/t0x%0.8x/n", GetMacReg(MAC_VLAN2));
      printf("MAC_WUFF/t0x%0.8x/n", GetMacReg(MAC_WUFF));
      printf("MAC_WUCSR/t0x%0.8x/n", GetMacReg(MAC_WUCSR));
      return (0);
}
 
// Display PHYsical media interface registers
static int
DumpPhyRegs(void)
{
      printf("PHY_BCR/t/t0x%0.4x/n", GetPhyReg(PHY_BCR));
      printf("PHY_BSR/t/t0x%0.4x/n", GetPhyReg(PHY_BSR));
      printf("PHY_ID1/t/t0x%0.4x/n", GetPhyReg(PHY_ID1));
      printf("PHY_ID2/t/t0x%0.4x/n", GetPhyReg(PHY_ID2));
      printf("PHY_ANAR/t0x%0.4x/n", GetPhyReg(PHY_ANAR));
      printf("PHY_ANLPAR/t0x%0.4x/n", GetPhyReg(PHY_ANLPAR));
      printf("PHY_ANEXPR/t0x%0.4x/n", GetPhyReg(PHY_ANEXPR));
      printf("PHY_SILREV/t0x%0.4x/n", GetPhyReg(PHY_SILREV));
      printf("PHY_MCSR/t0x%0.4x/n", GetPhyReg(PHY_MCSR));
      printf("PHY_SPMODES/t0x%0.4x/n", GetPhyReg(PHY_SPMODES));
      printf("PHY_CSIR/t0x%0.4x/n", GetPhyReg(PHY_CSIR));
      printf("PHY_ISR/t/t0x%0.4x/n", GetPhyReg(PHY_ISR));
      printf("PHY_IMR/t/t0x%0.4x/n", GetPhyReg(PHY_IMR));
      printf("PHY_PHYSCSR/t0x%0.4x/n", GetPhyReg(PHY_PHYSCSR));
      return (0);
}

static int
lan9118_open(bd_t *bis)
{
      int RetVal = TRUE;
      int timeout;
      int i;

      printf("DRIVER_VERSION : %X, ", DRIVER_VERSION);
      printf("DATECODE : %s/r/n", BUILD_NUMBER);
#ifdef        DEBUG
      TotalInts = 0;
      TotalRXE = 0;
      TotalBytes = 0;

      if (bis->bi_bootflags & 0x40000000) {
            use_smsc9118 = 1;
      }
#endif        //DEBUG

      // Because we just came out of h/w reset we can't be sure that
      // the chip has completed reset and may have to implement the
      // workaround for Errata 5, stepping A0.    Therefore we need to
      // check the ID_REV in little endian, the reset default.
      switch (*ID_REV & ID_REV_ID_MASK) {
      case 0x01180000:
      case 0x01170000:
      case 0x01160000:
      case 0x01150000:
      case 0x118a0000:
      case 0x117a0000:
      case 0x116a0000:
      case 0x115a0000:
      case 0x92100000:
      case 0x92110000:
      case 0x92200000:
      case 0x92210000:
            printf("LAN9x18 (0x%08x) detected./n", *ID_REV);
            break;
      default:
            printf("Failed to detect LAN9118. ID_REV = 0x%08x/n", *ID_REV);
            RetVal = FALSE;
            goto done;
      }

      // Does SoftReset to 118
      *HW_CFG = HW_CFG_SRST;
      DELAY(10);

      // Is the internal PHY running?
      if ((*PWR_MGMT & PWR_MGMT_PM_MODE_MSK) != 0) {
            // Apparently not...
            *BYTE_TEST = 0x0; // Wake it up
            DELAY(1);
            timeout = PHY_TIMEOUT;
            while (timeout-- && ((*PWR_MGMT & PWR_MGMT_PME_READY) == 0)) {
                  lan9118_udelay(1);
            }
            if ((*PWR_MGMT & PWR_MGMT_PME_READY) == 0) {
                  LAN9118_WARN("LAN9118: PHY not ready");
                  LAN9118_WARN(" - aborting/n");
                  RetVal = FALSE;
                  goto done;
            }
      }

      // Setup TX and RX resources.

      // There is one TX buffer.
      if ((txbp = (char *)malloc(ENET_MAX_MTU_ALIGNED)) == NULL) {
            LAN9118_WARN("lan9118_open: can't get TX buffer/n");
            goto cleanup;
      }

      // The receive buffers are allocated and aligned by upper layer
      // software.
      for (i = 0; i < PKTBUFSRX; i++) {
            rxbp[i] = NetRxPackets[i];
            rxAvlQue[i].index = -1;
      }

      rxNdx = 0;
      rxNdxIn = 0;
      rxNdxOut = 0;
      lastTxTag = 0x0;

      // Set TX Fifo Size
      *HW_CFG = 0x00040000;   // 4K for TX

      // This value is dependent on TX Fifo Size since there's a limited
      // amount of Fifo space.
      MaxRxFifoSz = 13440;            // Decimal

      // Set automatic flow control.
      *AFC_CFG = 0x008c46af;

      // Flash LEDs.
      *GPIO_CFG = 0x70700000;

      // Disable interrupts until the rest of initialization is complete.
      *INT_EN = 0x0;                // Clear interrupt enables
      *INT_STS = 0xffffffff;        // Clear pending interrupts
      *IRQ_CFG = 0x00000001;        // IRQ disable

      // Enable flow control and pause frame time
      SetMacReg(MAC_FLOW, 0xffff0002);

      // Set MAC address, if octet 0 is non-null assume it's all good.
      {
            unsigned mac_addrh;
            unsigned mac_addrl;

            memcpy(macAddr, bis->bi_enetaddr, ENET_ADDR_LENGTH);
            mac_addrh = macAddr[5] << 8 | macAddr[4];
            mac_addrl = macAddr[3] << 24 | macAddr[2] << 16 |
                  macAddr[1] << 8 | macAddr[0];
            if (mac_addrh != 0 || mac_addrl != 0) {
                  SetMacReg(MAC_ADDRH, mac_addrh);
                  SetMacReg(MAC_ADDRL, mac_addrl);
            }
      }

      // Dump old status and data
      *TX_CFG = (TX_CFG_TXS_DUMP | TX_CFG_TXD_DUMP);
      *RX_CFG = (RX_CFG_FORCE_DISCARD);

      // Initialize Tx parameters
      *HW_CFG = ((*HW_CFG & HW_CFG_TX_FIF_SZ_MSK) | HW_CFG_MBO);
      *FIFO_INT = FIFO_INT_TDAL_MSK;      // Max out value
      *INT_EN |= INT_EN_TDFA_INT_EN;
      {
            // Disable MAC heartbeat SQE and enable MAC transmitter
            ulong macCR = GetMacReg(MAC_CR);
            macCR |= (MAC_CR_TXEN | MAC_CR_HBDIS);
            macCR &= ~MAC_CR_PRMS;    // Turn off promiscuous mode
            macCR |= MAC_CR_BCAST;    // Don't accept broadcast frames
            SetMacReg(MAC_CR, macCR);
      }

      // Initialize Rx parameters
      *RX_CFG = 0x00000000;            // 4byte end-alignment
      {
            // Enable receiver.
            ulong macCR = GetMacReg(MAC_CR);
            SetMacReg(MAC_CR, (macCR | MAC_CR_RXEN));
      }
      *FIFO_INT = ((*FIFO_INT & 0xffff0000) | 0x00000001);
      *INT_EN |= (INT_EN_RSFL_INT_EN | INT_EN_RXE_INT_EN);
      *INT_EN |= INT_EN_RXDFH_INT_EN;

      // Initialize PHY parameters
      if (((GetPhyReg(PHY_ID1) == PHY_ID1_LAN9118) &&
           (GetPhyReg(PHY_ID2) == PHY_ID2_LAN9118)) ||
          ((GetPhyReg(PHY_ID1) == PHY_ID1_LAN9218) &&
           (GetPhyReg(PHY_ID2) == PHY_ID2_LAN9218)))
      {
          // Reset the PHY
          SetPhyReg(PHY_BCR, PHY_BCR_RST);
          timeout = PHY_TIMEOUT;
          lan9118_udelay(50*1000);    // > 50ms
          while(timeout-- && (GetPhyReg(PHY_BCR) & PHY_BCR_RST))
          {
                lan9118_udelay(10);
          }
          if (timeout == 0)
          {
                LAN9118_WARN("PHY reset incomplete/n");
                RetVal = FALSE;
                goto done;
          }

          // Setup and start auto negotiation
          {
                ushort anar;
                ushort bcr;
                char * spddplx;

                anar = GetPhyReg(PHY_ANAR);
                anar &= ~PHY_ANAR_PAUSE_OP_MSK;
                anar |= PHY_ANAR_PAUSE_OP_BOTH;
                anar |= (PHY_ANAR_10_FDPLX | PHY_ANAR_10_ABLE |
                      PHY_ANAR_100_TX_FDPLX | PHY_ANAR_100_TX_ABLE);
                SetPhyReg(PHY_ANAR, anar);

                DELAY(2);
                bcr = GetPhyReg(PHY_BCR);
                bcr |= (PHY_BCR_SS | PHY_BCR_FDPLX);
                SetPhyReg(PHY_BCR, bcr);
                DELAY(2);

                printf("start Auto negotiation... (take ~2sec)/n");
                bcr = GetPhyReg(PHY_BCR);
                bcr |= (PHY_BCR_ANE | PHY_BCR_RSTAN);
                SetPhyReg(PHY_BCR, bcr);
                DELAY(2);

                timeout = PHY_AN_TIMEOUT;
                while((timeout--) && ((GetPhyReg(PHY_BSR) & PHY_BSR_ANC) == 0)) {
                      lan9118_udelay(500000);
                }
                if ((GetPhyReg(PHY_BSR) & PHY_BSR_ANC) == 0) {
                      LAN9118_WARN("Auto negotiation failed/n");
                      RetVal = FALSE;
                      goto done;
                }

                if ((GetPhyReg(PHY_BSR) & PHY_BSR_LINK_STATUS) == 0) {
                      LAN9118_WARN("Link down/n");
                      RetVal = FALSE;
                      goto done;
                }

                switch ((GetPhyReg(PHY_PHYSCSR) & PHY_PHYSCSR_SPEED_MSK)>>2) {
                      case 0x01:
                            spddplx = "10BaseT, half duplex";
                            break;
                      case 0x02:
                            spddplx = "100BaseTX, half duplex";
                            break;
                      case 0x05:
                            spddplx = "10BaseT, full duplex";
                            break;
                      case 0x06:
                            spddplx = "100BaseTX, full duplex";
                            break;
                      default:
                            spddplx = "Unknown";
                            break;
                }
                printf("Auto negotiation complete, %s/n", spddplx);
          }

          // If PHYs auto negotiated for full duplex, enable full duplex in MAC.
          if ((GetPhyReg(PHY_ANAR) & GetPhyReg(PHY_ANLPAR)) & 0x0140) {
                SetMacReg(MAC_CR, (GetMacReg(MAC_CR) | 0x00100000));
          }
          // correct PHY_ID is detected
          goto done;
      }
      else
      {
            printf("Unknown PHY ID : 0x%x, 0x%x/n", GetPhyReg(PHY_ID1), GetPhyReg(PHY_ID2));
      }

      goto done;

cleanup:
      if (txbp != NULL) {
            free(txbp);
            txbp = (char *)NULL;
      }

done:
      return (RetVal);
}

static void
lan9118_close(void)
{
      // Release the TX buffer.
      if (txbp != NULL) {
            free(txbp);
            txbp = (char *)NULL;
      }
}

static int
lan9118_read()
{
      int curBufNdx;
      int loopCount = 0;
      ulong rxStatus;
      ulong count;
      ulong len;
      int ffwdOk = TRUE;
      int timeout;
      int handled = 0;

      while((*RX_FIFO_INF & 0x00ff0000) != 0) {
            if (loopCount >= NUM_RX_BUFF) {
//printf("read: loopCount exceeded/n");
                  break;      // Packet buffers full
            }

            curBufNdx = rxNdx;
            loopCount++;
            if (++rxNdx >= NUM_RX_BUFF) {
                  rxNdx = 0;  // Wrap buffer slot #
            }

            rxStatus = *RX_STATUS_FIFO_PORT;
            len = count = rxStatus >> 16;

            if (count >= 4*sizeof(ulong)) {
                  ffwdOk = TRUE;    // Use h/w to toss packet
            } else {
                  ffwdOk = FALSE;    // Have to empty manually on error
            }

            if (count != 0) {
                  if (count > ENET_MAX_MTU) {
                        count = 0;
                  } else {
                        if ((rxStatus & TX_STATUS_FIFO_ES) != 0) {
                              count = 0;
                        }
                  }
            }

            if (count == 0) {
                  if (ffwdOk == TRUE) {
                        // Drain it the fast way
                        *RX_DP_CTL = RX_DP_FFWD;
                        timeout = FFWD_TIMEOUT;
                        while (timeout-- && (*RX_DP_CTL & RX_DP_FFWD)) {
                              lan9118_udelay(1);
                        }
                        if ((*RX_DP_CTL & RX_DP_FFWD) != 0) {
                              LAN9118_WARN("lan9118_read: fast "
                                    "forward op failed/n");
                              break;
                        }
                  } else {
                        // Drain it manually
                        while (len--) {
                            volatile ulong tmp = *RX_FIFO_PORT;
                        }
                  }
            } else if (rxAvlQue[rxNdxIn].index != -1) {
                  LAN9118_WARN("lan9118_read: read buffers full!/n");
                  break;
            } else {
                  register ulong *rxbpl;
                  int ndx;

                  TotalRxPackets++;
                  TotalBytes += count;
                  rxAvlQue[rxNdxIn].index = curBufNdx;
                  rxAvlQue[rxNdxIn].len = count;
                  if (++rxNdxIn >= NUM_RX_BUFF) {
                        rxNdxIn = 0;
                  }

                  // Copy this packet to a NetRxPacket buffer
                  handled = 1;
//printf("read: %d empty reads prior to this one/n", EmptyReads);
                  EmptyReads = 0;
                  rxbpl = (ulong *)rxbp[curBufNdx];
                  for (ndx = (count+3)/sizeof(ulong); ndx > 0; ndx--) {
                        *rxbpl++ = *RX_FIFO_PORT;
                  }
#if 0
{
    printf("Received: packet contents follows./n");
    int i;
    for (i = 1; i <= count; i++) {
          printf("0x%02x ", rxbp[curBufNdx][i-1]);
          if (!(i%16))
              printf("/n");
    }
    printf("/n");
}
#endif
                  DELAY(3);
            }
      }

      if (handled) {
            for (;;) {
                  curBufNdx = rxAvlQue[rxNdxOut].index;
                  if (curBufNdx == -1) {
                        len = -1;    // Nothing else received
//printf("read: nothing else received: rxNdxOut: %d curBufNdx: %d/n", rxNdxOut, curBufNdx);
                        break;
                  }
                  len = rxAvlQue[rxNdxOut].len;
//printf("read: sending a packet up: rxNdxOut: %d curBufNdx: %d/n", rxNdxOut, curBufNdx);
                  NetReceive(NetRxPackets[curBufNdx], len - 4);
                  rxAvlQue[rxNdxOut].index = -1;      // Free buffer
                  if (++rxNdxOut >= NUM_RX_BUFF) {
                        rxNdxOut = 0;      // Handle wrap
                  }
            }
      } else {
            EmptyReads++;
            return (-1);      // Nothing was received
      }

      return (len);
}


static int sendToNet(uchar * txbp, int len)
{
      ulong tx_cmd_a, tx_cmd_b;
      int i;
      ulong * txbpl = (ulong *)txbp;

      lastTxTag++;

#if   DEBUG
      {
            printf("sendToNet: packet contents follows./n");
            int i;
            int j = 0;
            for (i = 0; i < len; i++) {
                  if (++j == 20) {
                        j = 0;
                        printf("/n");
                  }
                  printf("%0.1x ", txbp[i]);
            }
            printf("/n");

//            printf("sendToNet: peek TX status: 0x%0.8x/n",
//                  *TX_STATUS_FIFO_PEEK);
      }
#endif        // DEBUG

      tx_cmd_a = (((ulong)txbp & 0x3) << 16) | 0x00003000 | len;
      tx_cmd_b = (lastTxTag << 16) | len;

#if   DEBUG
      printf("sendToNet: tx_cmd_a: 0x%0.8x tx_cmd_b: 0x%0.8x/n",
            tx_cmd_a, tx_cmd_b);
#endif        // DEBUG

      *TX_FIFO_PORT = tx_cmd_a;
      *TX_FIFO_PORT = tx_cmd_b;

      for (i = (len+3)/sizeof(ulong); i > 0; i--) {
            *TX_FIFO_PORT = *txbpl++;
      }

      *TX_CFG = TX_CFG_TX_ON;        // Enable transmitter

      return (TRUE);
}

static int lan9118_write(volatile void *ptr, int len)
{
      ulong startTime;
      ulong timeout;
      char statusStr[64];

      if (len > ENET_MAX_MTU) {
            len = ENET_MAX_MTU;
      }

      // Copy the packet.
      memcpy((void *)txbp, (void *)ptr, len);

      // Drain the TX status fifo just in case there are old (good) statuses.
      for (timeout=0; timeout<TX_TIMEOUT_COUNT; timeout++)
      {
          if ((*TX_FIFO_INF & TX_FIFO_TXSUSED_MSK) == 0) {
                break;
          }
          printf("lan9118_write: discarded old TX status/n");
      }
      if (timeout == TX_TIMEOUT_COUNT)    // timed out?  Yes--
      {
        DumpCsrRegs();
        DumpMacRegs();
        DumpPhyRegs();
      }

      if (sendToNet(txbp, len) == FALSE) {
            return (-1);
      }

//printf("write: sent packet out: len: %d/n", len);

      startTime = get_timer(0);
      while (1) {
            if ((*TX_FIFO_INF & TX_FIFO_TXSUSED_MSK) == 0) {
                  // No status yet
                  if ((get_timer(0) - startTime) > TX_TIMEOUT) {
                        return (-1);
                  }
            } else {
                  ulong txStatus = *TX_STATUS_FIFO_PORT;

                  if ((txStatus & TX_STATUS_FIFO_ES) == TX_STATUS_FIFO_ES) {
                        sprintf(statusStr, "lan9118_write: error "
                              "status: 0x%0.8x/n", txStatus);
                        LAN9118_WARN(statusStr);
                        return (-1);
                  } else {
                        *TX_CFG |= TX_CFG_STOP_TX; // Stop transmitter
                        return (len);                // successful send
                  }
            }
      }
}

int    eth_init(bd_t *bd)
{
    return lan9118_open(bd);
}

void eth_halt(void)
{
    lan9118_close();
}

int    eth_rx(void)
{
    int    r;

    r = lan9118_read();

    return r;
}

int    eth_send(volatile void *packet, int length)
{
    return lan9118_write(packet, length);
}

#endif        // #ifdef CONFIG_DRIVER_SMSC9118

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值