saa9730.c
来自「linux 内核源代码」· C语言 代码 · 共 1,140 行 · 第 1/3 页
C
1,140 行
return -1; } mdelay(1); /* wait 1 ms. */ } /* Wait for 1 ms. */ mdelay(1); /* Check the link status. */ if (readl(&lp->lan_saa9730_regs->StationMgmtData) & PHY_STATUS_LINK_UP) { /* Link is up. */ return 0; } else { /* Link is down, reset the PHY first. */ /* set PHY address = 'CONTROL' */ writel(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); /* Wait for 1 ms. */ mdelay(1); /* set 'CONTROL' = force reset and renegotiate */ writel(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG | PHY_CONTROL_RESTART_AUTO_NEG, &lp->lan_saa9730_regs->StationMgmtData); /* Wait for 50 ms. */ mdelay(50); /* set 'BUSY' to start operation */ writel(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); /* await completion */ i = 0; while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { i++; if (i > 100) { printk ("Error: lan_saa9730_mii_init: timeout\n"); return -1; } mdelay(1); /* wait 1 ms. */ } /* Wait for 1 ms. */ mdelay(1); for (l = 0; l < 2; l++) { /* set PHY address = 'STATUS' */ writel(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | PHY_STATUS, &lp->lan_saa9730_regs->StationMgmtCtl); /* await completion */ i = 0; while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { i++; if (i > 100) { printk ("Error: lan_saa9730_mii_init: timeout\n"); return -1; } mdelay(1); /* wait 1 ms. */ } /* wait for 3 sec. */ mdelay(3000); /* check the link status */ if (readl(&lp->lan_saa9730_regs->StationMgmtData) & PHY_STATUS_LINK_UP) { /* link is up */ break; } } } return 0;}static int lan_saa9730_control_init(struct lan_saa9730_private *lp){ /* Initialize DMA control register. */ writel((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) | (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) | (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF) | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN | DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN, &lp->lan_saa9730_regs->LanDmaCtl); /* Initial MAC control register. */ writel((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP, &lp->lan_saa9730_regs->MacCtl); /* Initialize CAM control register. */ writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC, &lp->lan_saa9730_regs->CamCtl); /* * Initialize CAM enable register, only turn on first entry, should * contain own addr. */ writel(0x0001, &lp->lan_saa9730_regs->CamEnable); /* Initialize Tx control register */ writel(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl); /* Initialize Rcv control register */ writel(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl); /* Reset DMA engine */ writel(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); return 0;}static int lan_saa9730_stop(struct lan_saa9730_private *lp){ int i; /* Stop DMA first */ writel(readl(&lp->lan_saa9730_regs->LanDmaCtl) & ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA), &lp->lan_saa9730_regs->LanDmaCtl); /* Set the SW Reset bits in DMA and MAC control registers */ writel(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); writel(readl(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET, &lp->lan_saa9730_regs->MacCtl); /* * Wait for MAC reset to have finished. The reset bit is auto cleared * when the reset is done. */ i = 0; while (readl(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) { i++; if (i > 100) { printk ("Error: lan_sa9730_stop: MAC reset timeout\n"); return -1; } mdelay(1); /* wait 1 ms. */ } return 0;}static int lan_saa9730_dma_init(struct lan_saa9730_private *lp){ /* Stop lan controller. */ lan_saa9730_stop(lp); writel(LAN_SAA9730_DEFAULT_TIME_OUT_CNT, &lp->lan_saa9730_regs->Timeout); return 0;}static int lan_saa9730_start(struct lan_saa9730_private *lp){ lan_saa9730_buffer_init(lp); /* Initialize Rx Buffer Index */ lp->NextRcvPacketIndex = 0; lp->NextRcvBufferIndex = 0; /* Set current buffer index & next available packet index */ lp->NextTxmPacketIndex = 0; lp->NextTxmBufferIndex = 0; lp->PendingTxmPacketIndex = 0; lp->PendingTxmBufferIndex = 0; writel(readl(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl); /* For Tx, turn on MAC then DMA */ writel(readl(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN, &lp->lan_saa9730_regs->TxCtl); /* For Rx, turn on DMA then MAC */ writel(readl(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN, &lp->lan_saa9730_regs->RxCtl); /* Set Ok2Use to let hardware own the buffers. */ writel(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); return 0;}static int lan_saa9730_restart(struct lan_saa9730_private *lp){ lan_saa9730_stop(lp); lan_saa9730_start(lp); return 0;}static int lan_saa9730_tx(struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); unsigned int *pPacket; unsigned int tx_status; if (lan_saa9730_debug > 5) printk("lan_saa9730_tx interrupt\n"); /* Clear interrupt. */ writel(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); while (1) { pPacket = lp->TxmBuffer[lp->PendingTxmBufferIndex] [lp->PendingTxmPacketIndex]; /* Get status of first packet transmitted. */ tx_status = le32_to_cpu(*pPacket); /* Check ownership. */ if ((tx_status & TX_STAT_CTL_OWNER_MSK) != (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; /* Check for error. */ if (tx_status & TX_STAT_CTL_ERROR_MSK) { if (lan_saa9730_debug > 1) printk("lan_saa9730_tx: tx error = %x\n", tx_status); dev->stats.tx_errors++; if (tx_status & (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) dev->stats.tx_aborted_errors++; if (tx_status & (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) dev->stats.tx_window_errors++; if (tx_status & (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) dev->stats.tx_carrier_errors++; if (tx_status & (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) dev->stats.tx_fifo_errors++; if (tx_status & (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) dev->stats.tx_heartbeat_errors++; dev->stats.collisions += tx_status & TX_STATUS_TX_COLL_MSK; } /* Free buffer. */ *pPacket = cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); /* Update pending index pointer. */ lp->PendingTxmPacketIndex++; if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { lp->PendingTxmPacketIndex = 0; lp->PendingTxmBufferIndex ^= 1; } } /* The tx buffer is no longer full. */ netif_wake_queue(dev); return 0;}static int lan_saa9730_rx(struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); int len = 0; struct sk_buff *skb = 0; unsigned int rx_status; int BufferIndex; int PacketIndex; unsigned int *pPacket; unsigned char *pData; if (lan_saa9730_debug > 5) printk("lan_saa9730_rx interrupt\n"); /* Clear receive interrupts. */ writel(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); /* Address next packet */ BufferIndex = lp->NextRcvBufferIndex; PacketIndex = lp->NextRcvPacketIndex; pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; rx_status = le32_to_cpu(*pPacket); /* Process each packet. */ while ((rx_status & RX_STAT_CTL_OWNER_MSK) == (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { /* Check the rx status. */ if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { /* Received packet is good. */ len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> RX_STAT_CTL_LENGTH_SHF; pData = (unsigned char *) pPacket; pData += 4; skb = dev_alloc_skb(len + 2); if (skb == 0) { printk ("%s: Memory squeeze, deferring packet.\n", dev->name); dev->stats.rx_dropped++; } else { dev->stats.rx_bytes += len; dev->stats.rx_packets++; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ skb_copy_to_linear_data(skb, (unsigned char *) pData, len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; } } else { /* We got an error packet. */ if (lan_saa9730_debug > 2) printk ("lan_saa9730_rx: We got an error packet = %x\n", rx_status); dev->stats.rx_errors++; if (rx_status & (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) dev->stats.rx_crc_errors++; if (rx_status & (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) dev->stats.rx_frame_errors++; if (rx_status & (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) dev->stats.rx_fifo_errors++; if (rx_status & (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) dev->stats.rx_length_errors++; } /* Indicate we have processed the buffer. */ *pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); /* Make sure A or B is available to hardware as appropriate. */ writel(BufferIndex ? OK2USE_RX_B : OK2USE_RX_A, &lp->lan_saa9730_regs->Ok2Use); /* Go to next packet in sequence. */ lp->NextRcvPacketIndex++; if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { lp->NextRcvPacketIndex = 0; lp->NextRcvBufferIndex ^= 1; } /* Address next packet */ BufferIndex = lp->NextRcvBufferIndex; PacketIndex = lp->NextRcvPacketIndex; pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; rx_status = le32_to_cpu(*pPacket); } return 0;}static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id){ struct net_device *dev = dev_id; struct lan_saa9730_private *lp = netdev_priv(dev); if (lan_saa9730_debug > 5) printk("lan_saa9730_interrupt\n"); /* Disable the EVM LAN interrupt. */ evm_saa9730_block_lan_int(lp);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?