int eth_rx (void) { int nLen = 0; unsigned int unStatus; unStatus = *get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_RX_MA; if (!unStatus) /* no packet available, return immediately */ return 0; DEBUG_FN (DEBUG_RX); /* unLen always < max(nLen) and discard checksum */ nLen = (int) aRxBufferDesc[0].unLen - 4; /* acknowledge status register */ *get_eth_reg_addr (NS9750_ETH_EINTR) = unStatus; aRxBufferDesc[0].unLen = 1522; aRxBufferDesc[0].s.bits.uFull = 0; /* Buffer A descriptor available again */ *get_eth_reg_addr (NS9750_ETH_RXFREE) |= 0x1; /* NetReceive may call eth_send. Due to a possible bug of the NS9750 we * have to acknowledge the received frame before sending a new one */ if (unStatus & NS9750_ETH_EINTR_RXDONEA) NetReceive (NetRxPackets[0], nLen); return nLen; }
static void na_mii_reset(struct net_device *dev) { struct netarmeth_dev *na_dev; NA_PRINTK("na_mii_reset\n"); if (dev == NULL) { NA_PRINTK("na_mii_reset - NULL parameter\n"); return; } na_dev = dev->priv; na_dev->phy_type = na_mii_identify_phy(); if ((na_dev->phy_type != NA_ENABLE_PHY) && (na_dev->phy_type != NA_HOME_PHY)) { printk(KERN_WARNING "%s: Found other than Enable, Lucent or Home PHY.\n", dev->name); } /* select appropriate Control register */ if (na_dev->phy_type == NA_HOME_PHY) outl_t(0x100, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); else outl_t(0x400, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t(0x8000, get_eth_reg_addr(NETARM_ETH_MII_WRITE)); na_mii_poll_busy(); outl_t(0, get_eth_reg_addr(NETARM_ETH_MII_WRITE)); na_mii_poll_busy(); }
void eth_halt (void) { DEBUG_FN (DEBUG_INIT); *get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_RXEN; *get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~(NS9750_ETH_EGCR1_ERX | NS9750_ETH_EGCR1_ERXDMA | NS9750_ETH_EGCR1_ETX | NS9750_ETH_EGCR1_ETXDMA); }
int eth_init(bd_t * pbis) { unsigned char aucMACAddr[6]; char *pcTmp = getenv("ethaddr"); char *pcEnd; int i; DEBUG_FN(DEBUG_INIT); /* no need to check for hardware */ if (!ns7520_eth_reset()) return -1; if (NULL == pcTmp) return -1; for (i = 0; i < 6; i++) { aucMACAddr[i] = pcTmp ? simple_strtoul(pcTmp, &pcEnd, 16) : 0; pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd; } /* configure ethernet address */ *get_eth_reg_addr(NS7520_ETH_SA1) = aucMACAddr[5] << 8 | aucMACAddr[4]; *get_eth_reg_addr(NS7520_ETH_SA2) = aucMACAddr[3] << 8 | aucMACAddr[2]; *get_eth_reg_addr(NS7520_ETH_SA3) = aucMACAddr[1] << 8 | aucMACAddr[0]; /* enable hardware */ *get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN; *get_eth_reg_addr(NS7520_ETH_SUPP) = NS7520_ETH_SUPP_JABBER; *get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN; /* the linux kernel may give packets < 60 bytes, for example arp */ *get_eth_reg_addr(NS7520_ETH_MAC2) = NS7520_ETH_MAC2_CRCEN | NS7520_ETH_MAC2_PADEN | NS7520_ETH_MAC2_HUGE; /* Broadcast/multicast allowed; if you don't set this even unicast chokes */ /* Based on NS7520 errata documentation */ *get_eth_reg_addr(NS7520_ETH_SAFR) = NS7520_ETH_SAFR_BROAD | NS7520_ETH_SAFR_PRM; /* enable receive and transmit FIFO, use 10/100 Mbps MII */ *get_eth_reg_addr(NS7520_ETH_EGCR) |= NS7520_ETH_EGCR_ETXWM_75 | NS7520_ETH_EGCR_ERX | NS7520_ETH_EGCR_ERXREG | NS7520_ETH_EGCR_ERXBR | NS7520_ETH_EGCR_ETX; return 0; }
static void ns9750_mii_write (unsigned short uiRegister, unsigned short uiData) { DEBUG_FN (DEBUG_MII_LOW); /* write MII register to be written */ *get_eth_reg_addr (NS9750_ETH_MADR) = NS9750_ETH_PHY_ADDRESS << 8 | uiRegister; *get_eth_reg_addr (NS9750_ETH_MWTD) = uiData; if (!ns9750_mii_poll_busy ()) { printf (KERN_WARNING NS9750_DRIVER_NAME ": MII still busy in write\n"); } }
static void na_get_mac_addr(struct net_device *dev) { unsigned short *p; NA_PRINTK("na_get_mac_addr\n"); p = (unsigned short *) dev->dev_addr; p[0] = (unsigned short) inl_t(get_eth_reg_addr(NETARM_ETH_SAL_STATION_ADDR_1)); p[1] = (unsigned short) inl_t(get_eth_reg_addr(NETARM_ETH_SAL_STATION_ADDR_2)); p[2] = (unsigned short) inl_t(get_eth_reg_addr(NETARM_ETH_SAL_STATION_ADDR_3)); NA_PRINTK2(" %X %X %X %X %X %X\n", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); }
static unsigned short ns9750_mii_read (unsigned short uiRegister) { DEBUG_FN (DEBUG_MII_LOW); /* write MII register to be read */ *get_eth_reg_addr (NS9750_ETH_MADR) = NS9750_ETH_PHY_ADDRESS << 8 | uiRegister; *get_eth_reg_addr (NS9750_ETH_MCMD) = NS9750_ETH_MCMD_READ; if (!ns9750_mii_poll_busy ()) printk (KERN_WARNING NS9750_DRIVER_NAME ": MII still busy in read\n"); /* continue to read */ *get_eth_reg_addr (NS9750_ETH_MCMD) = 0; return (unsigned short) (*get_eth_reg_addr (NS9750_ETH_MRDD)); }
static void na_rx_fifo_reset(unsigned long ldev) { struct net_device *dev = (struct net_device *)ldev; struct netarmeth_dev *na_dev = dev->priv; /* If we're still receiving packets, keep going. */ if (na_dev->stats.rx_packets != na_dev->rx_fifo_packets) { na_dev->rx_fifo_packets = na_dev->stats.rx_packets; NA_PRINTK2("na_rx_fifo_reset 1\n"); } else if (inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) & NETARM_ETH_GCR_ERXDMA && !(inl_t(get_dma_reg_addr(NETARM_DMA1A_STATUS)) & 0xdf000000) && ((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_STAT)) & 0x0a000000) == 0x02000000)) { na_reset_rx_fifo(na_dev); } na_enable_timer(dev); }
static unsigned int ns9750_mii_poll_busy (void) { unsigned int unTimeout = 10000; DEBUG_FN (DEBUG_MII_LOW); while (((*get_eth_reg_addr (NS9750_ETH_MIND) & NS9750_ETH_MIND_BUSY) == NS9750_ETH_MIND_BUSY) && unTimeout) unTimeout--; return unTimeout; }
static unsigned long na_mii_check_speed(struct netarmeth_dev *na_dev) { // Check link status. If 0, default to 100 Mbps. NA_PRINTK("na_mii_check_speed\n"); if (na_dev->phy_type == NA_HOME_PHY) { /* The AMD Home PHY only supports 10 Mbps anyway */ NA_PRINTK(" returning NA_10MBPS (HomePHY)\n"); na_dev->media_100BaseT = NA_10MBPS; } else { /* Read Status register */ outl_t(0x401, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT), get_eth_reg_addr(NETARM_ETH_MII_CMD)); na_mii_poll_busy(); if ((inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)) & 0x0004) == 0) { NA_PRINTK(" returning NA_100MBPS (link is down)\n"); na_dev->media_100BaseT = NA_100MBPS; } else { /* Now it's OK to check the normal speed status */ outl_t(0x417, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT), get_eth_reg_addr(NETARM_ETH_MII_CMD)); na_mii_poll_busy(); if ((inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)) & 0x0200) != 0) { NA_PRINTK(" returning NA_100MBPS (b)\n"); na_dev->media_100BaseT = NA_100MBPS; } else { NA_PRINTK(" returning NA_10MBPS\n"); na_dev->media_100BaseT = NA_10MBPS; } } } return(na_dev->media_100BaseT); }
static unsigned long na_mii_poll_busy(void) { unsigned long start_time, current_time; // Poll until the busy bit is clear or one second has elapsed. // (this is PHY-type-independent) start_time = current_time = jiffies; while ((current_time < start_time + NA_MII_POLL_BUSY_DELAY) && (inl_t(get_eth_reg_addr(NETARM_ETH_MII_IND)) & NETARM_ETH_MIII_BUSY)) { current_time = jiffies; } if (current_time < start_time + NA_MII_POLL_BUSY_DELAY) { return (1); } else { NA_PRINTK("na_mii_poll_busy - one second elapsed.\n"); return (0); } }
int eth_send (volatile void *pPacket, int nLen) { ulong ulTimeout; DEBUG_FN (DEBUG_TX); /* clear old status values */ *get_eth_reg_addr (NS9750_ETH_EINTR) &= *get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_TX_MA; /* prepare Tx Descriptors */ pTxBufferDesc->punSrc = (unsigned int *) pPacket; /* pPacket is 32bit * aligned */ pTxBufferDesc->unLen = nLen; /* only 32bit accesses allowed. wrap, full, interrupt and enabled to 1 */ pTxBufferDesc->s.unReg = 0xf0000000; /* pTxBufferDesc is the first possible buffer descriptor */ *get_eth_reg_addr (NS9750_ETH_TXPTR) = 0x0; /* enable processor for next frame */ *get_eth_reg_addr (NS9750_ETH_EGCR2) &= ~NS9750_ETH_EGCR2_TCLER; *get_eth_reg_addr (NS9750_ETH_EGCR2) |= NS9750_ETH_EGCR2_TCLER; ulTimeout = get_timer (0); DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR, "Waiting for transmission to finish\n"); while (! (*get_eth_reg_addr (NS9750_ETH_EINTR) & (NS9750_ETH_EINTR_TXDONE | NS9750_ETH_EINTR_TXERR))) { /* do nothing, wait for completion */ if (get_timer (0) - ulTimeout > TX_TIMEOUT) { DEBUG_ARGS0 (DEBUG_TX, "Transmit Timed out\n"); return -1; } } DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR, "transmitted...\n"); return 0; }
static void ns9750_link_update_egcr (void) { unsigned int unEGCR; unsigned int unMAC2; unsigned int unIPGT; DEBUG_FN (DEBUG_LINK); unEGCR = *get_eth_reg_addr (NS9750_ETH_EGCR1); unMAC2 = *get_eth_reg_addr (NS9750_ETH_MAC2); unIPGT = *get_eth_reg_addr (NS9750_ETH_IPGT) & ~NS9750_ETH_IPGT_MA; unMAC2 &= ~NS9750_ETH_MAC2_FULLD; if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE) == PHY_LXT971_STAT2_DUPLEX_MODE) { unMAC2 |= NS9750_ETH_MAC2_FULLD; unIPGT |= 0x15; /* see [1] p. 339 */ } else unIPGT |= 0x12; /* see [1] p. 339 */ *get_eth_reg_addr (NS9750_ETH_MAC2) = unMAC2; *get_eth_reg_addr (NS9750_ETH_EGCR1) = unEGCR; *get_eth_reg_addr (NS9750_ETH_IPGT) = unIPGT; }
/* the PHY stuff */ static char ns9750_mii_identify_phy( void ); static unsigned short ns9750_mii_read( unsigned short uiRegister ); static void ns9750_mii_write( unsigned short uiRegister, unsigned short uiData ); static unsigned int ns9750_mii_get_clock_divisor( unsigned int unMaxMDIOClk ); static unsigned int ns9750_mii_poll_busy( void ); static unsigned int nPhyMaxMdioClock = PHY_MDIO_MAX_CLK; static unsigned char ucLinkMode = FS_EEPROM_AUTONEG_ENABLE; static unsigned int uiLastLinkStatus; static PhyType phyDetected = PHY_NONE; /* we use only one tx buffer descriptor */ static tx_buffer_desc_t* pTxBufferDesc = (tx_buffer_desc_t*) get_eth_reg_addr( NS9750_ETH_TXBD ); /* we use only one rx buffer descriptor of the 4 */ static rx_buffer_desc_t aRxBufferDesc[ 4 ]; /*********************************************************************** * @Function: eth_init * @Return: -1 on failure otherwise 0 * @Descr: Initializes the ethernet engine and uses either FS Forth's default * MAC addr or the one in environment ***********************************************************************/ int eth_init (bd_t * pbis) { /* This default MAC Addr is reserved by FS Forth-Systeme for the case of EEPROM failures */
static unsigned long na_mii_negotiate(struct netarmeth_dev *na_dev) { unsigned long start_time, current_time; unsigned long read_data; NA_PRINTK("na_mii_negotiate\n"); /* Select Autonegotiation Advertisement register */ if (na_dev->phy_type == NA_HOME_PHY) outl_t(0x101, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); else outl_t(0x404, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); /* Enable auto-negotiation */ outl_t(0x01E1, get_eth_reg_addr(NETARM_ETH_MII_WRITE)); na_mii_poll_busy(); /* Select Control register */ if (na_dev->phy_type == NA_HOME_PHY) outl_t(0x100, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); else outl_t(0x400, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); /* Restart auto-negotiation */ outl_t(0x1200, get_eth_reg_addr(NETARM_ETH_MII_WRITE)); na_mii_poll_busy(); // Wait for auto-negotiation to complete or for predefined delay to elapse. start_time = current_time = jiffies; do { /* Select Status register */ if (na_dev->phy_type == NA_HOME_PHY) outl_t(0x101, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); else outl_t(0x401, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT), get_eth_reg_addr(NETARM_ETH_MII_CMD)); na_mii_poll_busy(); read_data = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)); if ((read_data & 0x0024) == 0x0024) { return (0); } current_time = jiffies; } while (current_time < start_time + NA_MII_NEGOTIATE_DELAY); NA_PRINTK(" MII negotiation delay elapsed\n"); return (1); }
static na_phy_type na_mii_identify_phy(void) { int id_reg_a, id_reg_b; NA_PRINTK("na_mii_identify_phy\n"); /* check for Enable PHY */ outl_t(0x402, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT), get_eth_reg_addr(NETARM_ETH_MII_CMD)); na_mii_poll_busy(); id_reg_a = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)); if (id_reg_a == 0x0043) { /* This must be an Enable or a Lucent LU3X31 PHY chip */ NA_PRINTK(" Enable PHY\n"); return (NA_ENABLE_PHY); } /* check for AMD 79C901 HomePHY */ outl_t(0x102, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT), get_eth_reg_addr(NETARM_ETH_MII_CMD)); na_mii_poll_busy(); id_reg_a = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)); outl_t(0x103, get_eth_reg_addr(NETARM_ETH_MII_ADDR)); outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_MII_CMD)) | NETARM_ETH_MIIC_RSTAT), get_eth_reg_addr(NETARM_ETH_MII_CMD)); na_mii_poll_busy(); id_reg_b = inl_t(get_eth_reg_addr(NETARM_ETH_MII_READ)); if ((id_reg_a == 0x0000) && (id_reg_b == 0x6b71)) { /* This must be an AMD Home PHY chip */ NA_PRINTK(" Home PHY\n"); return (NA_HOME_PHY); } /* else, i.e. default */ NA_PRINTK(" Level 1 PHY\n"); return (NA_LEVEL1_PHY); }
static void na_reset_rx_fifo(struct netarmeth_dev *na_dev) { unsigned long reg; int i; NA_PRINTK("na_reset_rx_fifo\n"); // Disable receive DMA. outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) & ~NETARM_ETH_GCR_ERXDMA), get_eth_reg_addr(NETARM_ETH_GEN_CTRL)); // Disable receive FIFO. outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) & ~NETARM_ETH_GCR_ERX), get_eth_reg_addr(NETARM_ETH_GEN_CTRL)); // Disable DMA outl_t((inl_t(get_dma_reg_addr(NETARM_DMA1A_CONTROL)) & 0x7ffffc00), get_dma_reg_addr(NETARM_DMA1A_CONTROL)); // Delay 20 microsconds. udelay(20); // If NRIP or CAIP is set, reset them. reg = inl_t(get_dma_reg_addr(NETARM_DMA1A_CONTROL)); if (reg & 0x20000000) { reg &= 0x20f00000; outl_t(reg, get_dma_reg_addr(NETARM_DMA1A_CONTROL)); } // Reset DMA descriptors for (i = 0; i < NA_MAX_RX_BUF; i++) { na_dev->rx_dma_desc[i].src_buf_ptr = (unsigned long) virt_to_bus(na_dev->rx_skb[i]->data); na_dev->rx_dma_desc[i].src_buf_ptr &= ~(NETARM_DMA_BD0_LAST | NETARM_DMA_BD0_IDONE); na_dev->rx_dma_desc[i].buf_len = NA_MAX_ETH_FRAME; na_dev->rx_dma_desc[i].stat = 0; // Clear the F bit. na_dev->rx_dma_desc[i].buf_len &= ~NETARM_DMA_BD1_FULL; } na_dev->rx_dma_desc[NA_MAX_RX_BUF-1].src_buf_ptr |= NETARM_DMA_BD0_WRAP; na_dev->rx_sw_index = 0; // Reenable DMA outl_t((inl_t(get_dma_reg_addr(NETARM_DMA1A_CONTROL)) | 0x80000000), get_dma_reg_addr(NETARM_DMA1A_CONTROL)); // Reenable receive FIFO. outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) | NETARM_ETH_GCR_ERX), get_eth_reg_addr(NETARM_ETH_GEN_CTRL)); // Reenable receive DMA. outl_t((inl_t(get_eth_reg_addr(NETARM_ETH_GEN_CTRL)) | NETARM_ETH_GCR_ERXDMA), get_eth_reg_addr(NETARM_ETH_GEN_CTRL)); }
static int ns9750_eth_reset (void) { DEBUG_FN (DEBUG_MINOR); /* Reset MAC */ *get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_MAC_HRST; udelay (5); /* according to [1], p.322 */ *get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_MAC_HRST; /* reset and initialize PHY */ *get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_SRST; /* we don't support hot plugging of PHY, therefore we don't reset phyDetected and nPhyMaxMdioClock here. The risk is if the setting is incorrect the first open may detect the PHY correctly but succeding will fail For reseting the PHY and identifying we have to use the standard MDIO CLOCK value 2.5 MHz only after hardware reset After having identified the PHY we will do faster */ *get_eth_reg_addr (NS9750_ETH_MCFG) = ns9750_mii_get_clock_divisor (nPhyMaxMdioClock); /* reset PHY */ ns9750_mii_write (PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET); ns9750_mii_write (PHY_COMMON_CTRL, 0); /* @TODO check time */ udelay (3000); /* [2] p.70 says at least 300us reset recovery time. But go sure, it didn't worked stable at higher timer frequencies under LxNETES-2.x */ /* MII clock has been setup to default, ns9750_mii_identify_phy should work for all */ if (!ns9750_mii_identify_phy ()) { printk (KERN_ERR NS9750_DRIVER_NAME ": Unsupported PHY, aborting\n"); return 0; } /* now take the highest MDIO clock possible after detection */ *get_eth_reg_addr (NS9750_ETH_MCFG) = ns9750_mii_get_clock_divisor (nPhyMaxMdioClock); /* PHY has been detected, so there can be no abort reason and we can finish initializing ethernet */ uiLastLinkStatus = 0xff; /* undefined */ if ((ucLinkMode & FS_EEPROM_AUTONEG_ENABLE_MASK) == FS_EEPROM_AUTONEG_DISABLE) /* use parameters defined */ ns9750_link_force (); else ns9750_link_auto_negotiate (); if (phyDetected == PHY_LXT971A) /* set LED2 to link mode */ ns9750_mii_write (PHY_LXT971_LED_CFG, PHY_LXT971_LED_CFG_LINK_ACT << PHY_LXT971_LED_CFG_SHIFT_LED2); return 1; }
int eth_rx(void) { int i; unsigned short rxlen; unsigned short totrxlen = 0; unsigned int *addr; unsigned int rxstatus, lastrxlen; char *pa; /* If RXBR is 1, data block was received */ while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) & NS7520_ETH_EGSR_RXBR) == NS7520_ETH_EGSR_RXBR) { /* get status register and the length of received block */ rxstatus = *get_eth_reg_addr(NS7520_ETH_ERSR); rxlen = (rxstatus & NS7520_ETH_ERSR_RXSIZE) >> 16; /* clear RXBR to make fifo available */ *get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_RXBR; if (rxstatus & NS7520_ETH_ERSR_ROVER) { printf("Receive overrun, resetting FIFO.\n"); *get_eth_reg_addr(NS7520_ETH_EGCR) &= ~NS7520_ETH_EGCR_ERX; udelay(20); *get_eth_reg_addr(NS7520_ETH_EGCR) |= NS7520_ETH_EGCR_ERX; } if (rxlen == 0) { printf("Nothing.\n"); return 0; } addr = (unsigned int *) NetRxPackets[0]; pa = (char *) NetRxPackets[0]; /* read the fifo */ for (i = 0; i < rxlen / 4; i++) { *addr = *get_eth_reg_addr(NS7520_ETH_FIFO); addr++; } if ((*get_eth_reg_addr(NS7520_ETH_EGSR)) & NS7520_ETH_EGSR_RXREGR) { /* RXFDB indicates wether the last word is 1,2,3 or 4 bytes long */ lastrxlen = ((*get_eth_reg_addr(NS7520_ETH_EGSR)) & NS7520_ETH_EGSR_RXFDB_MA) >> 28; *addr = *get_eth_reg_addr(NS7520_ETH_FIFO); switch (lastrxlen) { case 1: *addr &= 0xff000000; break; case 2: *addr &= 0xffff0000; break; case 3: *addr &= 0xffffff00; break; } } /* Pass the packet up to the protocol layers. */ NetReceive(NetRxPackets[0], rxlen - 4); totrxlen += rxlen - 4; }
int eth_send(volatile void *pPacket, int nLen) { int i, length32, retval = 1; char *pa; unsigned int *pa32, lastp = 0, rest; unsigned int status; pa = (char *) pPacket; pa32 = (unsigned int *) pPacket; length32 = nLen / 4; rest = nLen % 4; /* make sure there's no garbage in the last word */ switch (rest) { case 0: lastp = pa32[length32 - 1]; length32--; break; case 1: lastp = pa32[length32] & 0x000000ff; break; case 2: lastp = pa32[length32] & 0x0000ffff; break; case 3: lastp = pa32[length32] & 0x00ffffff; break; } while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) & NS7520_ETH_EGSR_TXREGE) == 0) { } /* write to the fifo */ for (i = 0; i < length32; i++) *get_eth_reg_addr(NS7520_ETH_FIFO) = pa32[i]; /* the last word is written to an extra register, this starts the transmission */ *get_eth_reg_addr(NS7520_ETH_FIFOL) = lastp; /* Wait for it to be done */ while ((*get_eth_reg_addr(NS7520_ETH_EGSR) & NS7520_ETH_EGSR_TXBC) == 0) { } status = (*get_eth_reg_addr(NS7520_ETH_ETSR)); *get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_TXBC; /* Clear it now */ if (status & NS7520_ETH_ETSR_TXOK) { retval = 0; /* We're OK! */ } else if (status & NS7520_ETH_ETSR_TXDEF) { printf("Deferred, we'll see.\n"); retval = 0; } else if (status & NS7520_ETH_ETSR_TXAL) { printf("Late collision error, %d collisions.\n", (*get_eth_reg_addr(NS7520_ETH_ETSR)) & NS7520_ETH_ETSR_TXCOLC); } else if (status & NS7520_ETH_ETSR_TXAEC) { printf("Excessive collisions: %d\n", (*get_eth_reg_addr(NS7520_ETH_ETSR)) & NS7520_ETH_ETSR_TXCOLC); } else if (status & NS7520_ETH_ETSR_TXAED) { printf("Excessive deferral on xmit.\n"); } else if (status & NS7520_ETH_ETSR_TXAUR) { printf("Packet underrun.\n"); } else if (status & NS7520_ETH_ETSR_TXAJ) { printf("Jumbo packet error.\n"); } else { printf("Error: Should never get here.\n"); } return (retval); }
int eth_init (bd_t * pbis) { /* This default MAC Addr is reserved by FS Forth-Systeme for the case of EEPROM failures */ unsigned char aucMACAddr[6] = { 0x00, 0x04, 0xf3, 0x00, 0x06, 0x35 }; char *pcTmp = getenv ("ethaddr"); char *pcEnd; int i; DEBUG_FN (DEBUG_INIT); /* no need to check for hardware */ if (!ns9750_eth_reset ()) return -1; if (pcTmp != NULL) for (i = 0; i < 6; i++) { aucMACAddr[i] = pcTmp ? simple_strtoul (pcTmp, &pcEnd, 16) : 0; pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd; } /* configure ethernet address */ *get_eth_reg_addr (NS9750_ETH_SA1) = aucMACAddr[5] << 8 | aucMACAddr[4]; *get_eth_reg_addr (NS9750_ETH_SA2) = aucMACAddr[3] << 8 | aucMACAddr[2]; *get_eth_reg_addr (NS9750_ETH_SA3) = aucMACAddr[1] << 8 | aucMACAddr[0]; /* enable hardware */ *get_eth_reg_addr (NS9750_ETH_MAC1) = NS9750_ETH_MAC1_RXEN; /* the linux kernel may give packets < 60 bytes, for example arp */ *get_eth_reg_addr (NS9750_ETH_MAC2) = NS9750_ETH_MAC2_CRCEN | NS9750_ETH_MAC2_PADEN | NS9750_ETH_MAC2_HUGE; /* enable receive and transmit FIFO, use 10/100 Mbps MII */ *get_eth_reg_addr (NS9750_ETH_EGCR1) = NS9750_ETH_EGCR1_ETXWM | NS9750_ETH_EGCR1_ERX | NS9750_ETH_EGCR1_ERXDMA | NS9750_ETH_EGCR1_ETX | NS9750_ETH_EGCR1_ETXDMA | NS9750_ETH_EGCR1_ITXA; /* prepare DMA descriptors */ for (i = 0; i < 4; i++) { aRxBufferDesc[i].punSrc = 0; aRxBufferDesc[i].unLen = 0; aRxBufferDesc[i].s.bits.uWrap = 1; aRxBufferDesc[i].s.bits.uInt = 1; aRxBufferDesc[i].s.bits.uEnable = 0; aRxBufferDesc[i].s.bits.uFull = 0; } /* NetRxPackets[ 0 ] is initialized before eth_init is called and never changes. NetRxPackets is 32bit aligned */ aRxBufferDesc[0].punSrc = (unsigned int *) NetRxPackets[0]; aRxBufferDesc[0].s.bits.uEnable = 1; aRxBufferDesc[0].unLen = 1522; /* as stated in [1] p.307 */ *get_eth_reg_addr (NS9750_ETH_RXAPTR) = (unsigned int) &aRxBufferDesc[0]; /* [1] Tab. 221 states less than 5us */ *get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_ERXINIT; while (! (*get_eth_reg_addr (NS9750_ETH_EGSR) & NS9750_ETH_EGSR_RXINIT)) /* wait for finish */ udelay (1); /* @TODO do we need to clear RXINIT? */ *get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_ERXINIT; *get_eth_reg_addr (NS9750_ETH_RXFREE) = 0x1; return 0; }