📄 if_sc_lpe.c
字号:
static voidsc_lpe_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; int i; regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_STOP; // Brutal regs->w.page0.dcr = DP8390_DCR_INIT; regs->w.page0.rbch = 0; // Remote byte count regs->w.page0.rbcl = 0; regs->w.page0.rcr = DP8390_RCR_MON; // Accept no packets regs->w.page0.tcr = DP8390_TCR_LOCAL; // Transmitter [virtually] off regs->w.page0.tpsr = DP8390_TX_BUF1; // Transmitter start page dp->tx1 = dp->tx2 = 0; dp->tx_next = DP8390_TX_BUF1; dp->tx_started = false; regs->w.page0.pstart = DP8390_RX_START; // Receive ring start page regs->w.page0.bndry = DP8390_RX_STOP-1; // Receive ring boundary regs->w.page0.pstop = DP8390_RX_STOP; // Receive ring end page dp->rx_next = DP8390_RX_START-1; regs->w.page0.isr = 0xFF; // Clear any pending interrupts regs->w.page0.imr = DP8390_IMR_All; // Enable all interrupts regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_PAGE1; // Select page 1 regs->w.page1.curp = DP8390_RX_START; // Current page - next free page for Rx for (i = 0; i < ETHER_ADDR_LEN; i++) { regs->w.page1.par[i] = enaddr[i]; } // Enable and start device regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_START; regs->w.page0.tcr = DP8390_TCR_NORMAL; // Normal transmit operations regs->w.page0.rcr = DP8390_RCR_AB; // Accept broadcast, no errors, no multicast dp->running = true;}//// This routine is called to perform special "control" opertions//static intsc_lpe_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_len){ switch (key) { case ETH_DRV_SET_MAC_ADDRESS: return 0; break; default: return 1; break; }}//// This routine is called to see if it is possible to send another packet.// It will return non-zero if a transmit is possible, zero otherwise.//static intsc_lpe_can_send(struct eth_drv_sc *sc){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; return ((dp->tx1 == 0) || (dp->tx2 == 0));}//// This routine is called to start the transmitter. It is split out from the// data handling routine so it may be called either when data becomes first // available or when an Tx interrupt occurs//static voidsc_lpe_start_xmit(struct eth_drv_sc *sc, int start_page, int len){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START; regs->w.page0.tbcl = len & 0xFF; regs->w.page0.tbch = len >> 8; regs->w.page0.tpsr = start_page; regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_TXPKT | DP8390_CR_START; dp->tx_started = true;}//// This routine is called to send data to the hardware. It is known a-priori// that there is free buffer space (dp->tx_next).//static void sc_lpe_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; int i, len, start_page, pkt_len; unsigned char *data; pkt_len = total_len; if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME; start_page = dp->tx_next; if (dp->tx_next == DP8390_TX_BUF1) { dp->tx1 = start_page; dp->tx1_len = pkt_len; dp->tx1_key = key; dp->tx_next = DP8390_TX_BUF2; } else { dp->tx2 = start_page; dp->tx2_len = pkt_len; dp->tx2_key = key; dp->tx_next = DP8390_TX_BUF1; } // Send data to device buffer(s) regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START; regs->w.page0.rbcl = pkt_len & 0xFF; regs->w.page0.rbch = pkt_len >> 8; regs->w.page0.rsal = 0; regs->w.page0.rsah = start_page; regs->w.page0.isr = DP8390_ISR_RDC; // Clear end of DMA regs->w.page0.cr = DP8390_CR_WDMA | DP8390_CR_START; // Put data into buffer for (i = 0; i < sg_len; i++) { data = (unsigned char *)sg_list[i].buf; len = sg_list[i].len; while (len-- > 0) { regs->w.page0.data = *data++; } } if (total_len < pkt_len) { // Padding to 802.3 length was required for (i = total_len; i < pkt_len; i++) { regs->w.page0.data = 0; } } // Wait for DMA to complete while ((regs->r.page0.isr & DP8390_ISR_RDC) == 0) ; // Start transmit if not already going if (!dp->tx_started) { if (start_page == dp->tx1) { dp->tx_int = 1; // Expecting interrupt from BUF1 } else { dp->tx_int = 2; // Expecting interrupt from BUF2 } sc_lpe_start_xmit(sc, start_page, pkt_len); }}//// This function is called when a packet has been received. It's job is// to prepare to unload the packet from the hardware. Once the length of// the packet is known, the upper layer of the driver can be told. When// the upper layer is ready to unload the packet, the internal function// 'sc_lpe_recv' will be called to actually fetch it from the hardware.//static voidsc_lpe_RxEvent(struct eth_drv_sc *sc, int stat){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; unsigned char rsr; unsigned char rcv_hdr[4]; int i, len, pkt, cur; rsr = regs->r.page0.rsr; while (true) { // Read incoming packet header regs->w.page0.cr = DP8390_CR_PAGE1 | DP8390_CR_NODMA | DP8390_CR_START; cur = regs->r.page1.curp; regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START; pkt = regs->r.page0.bndry + 1; if (pkt == cur) break; if (pkt == DP8390_RX_STOP) pkt = DP8390_RX_START; regs->w.page0.rbcl = sizeof(rcv_hdr); regs->w.page0.rbch = 0; regs->w.page0.rsal = 0; regs->w.page0.rsah = pkt; if (dp->rx_next == pkt) {// printf("sc_lpe - receiver confused, stat: %x, , rsr: %x\n", stat, rsr); regs->w.page0.bndry = cur-1; // Update pointer return; } dp->rx_next = pkt; regs->w.page0.isr = DP8390_ISR_RDC; // Clear end of DMA regs->w.page0.cr = DP8390_CR_RDMA | DP8390_CR_START; for (i = 0; i < sizeof(rcv_hdr); i++) { rcv_hdr[i] = regs->r.page0.data; } len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); (sc->funs->eth_drv->recv)(sc, len); regs->w.page0.bndry = rcv_hdr[1]-1; // Update pointer }}//// This function is called as a result of the "eth_drv_recv()" call above.// It's job is to actually fetch data for a packet from the hardware once// memory buffers have been allocated for the packet. Note that the buffers// may come in pieces, using a scatter-gather list. This allows for more// efficient processing in the upper layers of the stack.//static voidsc_lpe_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; int i, mlen, len; unsigned char *data; // Compute total packet length len = 0; for (i = 0; i < sg_len; i++) { len += sg_list[i].len; } // Read incoming packet data regs->w.page0.cr = DP8390_CR_PAGE0 | DP8390_CR_NODMA | DP8390_CR_START; regs->w.page0.rbcl = len & 0xFF; regs->w.page0.rbch = len >> 8; regs->w.page0.rsal = 4; // Past header regs->w.page0.rsah = dp->rx_next; regs->w.page0.isr = DP8390_ISR_RDC; // Clear end of DMA regs->w.page0.cr = DP8390_CR_RDMA | DP8390_CR_START; for (i = 0; i < sg_len; i++) { data = (unsigned char *)sg_list[i].buf; if (data) { mlen = sg_list[i].len; while (mlen >= sizeof(*data)) { *data++ = regs->r.page0.data; mlen -= sizeof(*data); } } }}static voidsc_lpe_TxEvent(struct eth_drv_sc *sc, int stat){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; unsigned char tsr; unsigned long key; tsr = regs->r.page0.tsr; if (dp->tx_int == 1) { key = dp->tx1_key; dp->tx1 = 0; } else { key = dp->tx2_key; dp->tx2 = 0; } // Start next packet if one is ready dp->tx_started = false; if (dp->tx1) { sc_lpe_start_xmit(sc, dp->tx1, dp->tx1_len); dp->tx_int = 1; } else if (dp->tx2) { sc_lpe_start_xmit(sc, dp->tx2, dp->tx2_len); dp->tx_int = 2; } else { dp->tx_int = 0; } // Tell higher level we sent this packet (sc->funs->eth_drv->tx_done)(sc, key, 0);}static voidsc_lpe_BufEvent(struct eth_drv_sc *sc, int stat){ // What to do if the receive buffers overflow? if (stat & DP8390_ISR_OFLW) { // Note: [so far] it seems safe to just ignore this condition // The Linux driver goes through extraordinary pains to handle // it, including totally shutting down the chip and restarting. }}static voidsc_lpe_int(struct eth_drv_sc *sc){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; dp8390_regs *regs = dp->regs; unsigned char isr; regs->w.page0.cr = DP8390_CR_NODMA | DP8390_CR_PAGE0 | DP8390_CR_START; while ((isr = regs->r.page0.isr) != 0) { regs->w.page0.isr = isr; // Clear set bits if (!dp->running) break; // Is this necessary? if (isr & (DP8390_ISR_TxP|DP8390_ISR_TxE)) { sc_lpe_TxEvent(sc, isr); } if (isr & (DP8390_ISR_RxP|DP8390_ISR_RxE)) { sc_lpe_RxEvent(sc, isr); } if (isr & (DP8390_ISR_OFLW|DP8390_ISR_CNT)) { sc_lpe_BufEvent(sc, isr); } } cf_clear_interrupt(dp->slot);}static intsc_lpe_int_vector(struct eth_drv_sc *sc){ struct sc_lpe_priv_data *dp = (struct sc_lpe_priv_data *)sc->driver_private; return dp->slot->int_num;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -