ne2000_base.c
来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 758 行 · 第 1/2 页
C
758 行
DP_IN(base, DP_P1_CURP, cur); DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); DP_IN(base, DP_BNDRY, pkt); pkt += 1; if (pkt == dp->rx_buf_end) pkt = dp->rx_buf_start; if (pkt == cur) { break; } DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); DP_OUT(base, DP_RBCH, 0); DP_OUT(base, DP_RSAL, 0); DP_OUT(base, DP_RSAH, pkt); if (dp->rx_next == pkt) { if (cur == dp->rx_buf_start) DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); else DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */ return; } dp->rx_next = pkt; DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA CYGACC_CALL_IF_DELAY_US(10);#endif /* read header (get data size)*/ for (i = 0; i < sizeof(rcv_hdr);) { DP_IN_DATA(dp->data, rcv_hdr[i++]); }#if DEBUG & 5 printf("rx hdr %02x %02x %02x %02x\n", rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);#endif len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); /* data read */ uboot_push_packet_len(len); if (rcv_hdr[1] == dp->rx_buf_start) DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); else DP_OUT(base, DP_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 voiddp83902a_recv(u8 *data, int len){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; u8 *base = dp->base; int i, mlen; u8 saved_char = 0; bool saved;#if DEBUG & 4 int dx;#endif DEBUG_FUNCTION();#if DEBUG & 5 printf("Rx packet %d length %d\n", dp->rx_next, len);#endif /* Read incoming packet data */ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); DP_OUT(base, DP_RBCL, len & 0xFF); DP_OUT(base, DP_RBCH, len >> 8); DP_OUT(base, DP_RSAL, 4); /* Past header */ DP_OUT(base, DP_RSAH, dp->rx_next); DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA CYGACC_CALL_IF_DELAY_US(10);#endif saved = false; for (i = 0; i < 1; i++) { if (data) { mlen = len;#if DEBUG & 4 printf(" sg buf %08lx len %08x \n", (u32) data, mlen); dx = 0;#endif while (0 < mlen) { /* Saved byte from previous loop? */ if (saved) { *data++ = saved_char; mlen--; saved = false; continue; } { u8 tmp; DP_IN_DATA(dp->data, tmp);#if DEBUG & 4 printf(" %02x", tmp); if (0 == (++dx % 16)) printf("\n ");#endif *data++ = tmp;; mlen--; } }#if DEBUG & 4 printf("\n");#endif } }}static voiddp83902a_TxEvent(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; u8 *base = dp->base; u8 tsr; u32 key; DEBUG_FUNCTION(); DP_IN(base, DP_TSR, 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) { dp83902a_start_xmit(dp->tx1, dp->tx1_len); dp->tx_int = 1; } else if (dp->tx2) { dp83902a_start_xmit(dp->tx2, dp->tx2_len); dp->tx_int = 2; } else { dp->tx_int = 0; } /* Tell higher level we sent this packet */ uboot_push_tx_done(key, 0);}/* * Read the tally counters to clear them. Called in response to a CNT * interrupt. */static voiddp83902a_ClearCounters(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; u8 *base = dp->base; u8 cnt1, cnt2, cnt3; DP_IN(base, DP_FER, cnt1); DP_IN(base, DP_CER, cnt2); DP_IN(base, DP_MISSED, cnt3); DP_OUT(base, DP_ISR, DP_ISR_CNT);}/* * Deal with an overflow condition. This code follows the procedure set * out in section 7.0 of the datasheet. */static voiddp83902a_Overflow(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; u8 *base = dp->base; u8 isr; /* Issue a stop command and wait 1.6ms for it to complete. */ DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); CYGACC_CALL_IF_DELAY_US(1600); /* Clear the remote byte counter registers. */ DP_OUT(base, DP_RBCL, 0); DP_OUT(base, DP_RBCH, 0); /* Enter loopback mode while we clear the buffer. */ DP_OUT(base, DP_TCR, DP_TCR_LOCAL); DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); /* * Read in as many packets as we can and acknowledge any and receive * interrupts. Since the buffer has overflowed, a receive event of * some kind will have occured. */ dp83902a_RxEvent(); DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); /* Clear the overflow condition and leave loopback mode. */ DP_OUT(base, DP_ISR, DP_ISR_OFLW); DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* * If a transmit command was issued, but no transmit event has occured, * restart it here. */ DP_IN(base, DP_ISR, isr); if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); }}static voiddp83902a_poll(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; u8 *base = dp->base; u8 isr; DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); DP_IN(base, DP_ISR, isr); while (0 != isr) { /* * The CNT interrupt triggers when the MSB of one of the error * counters is set. We don't much care about these counters, but * we should read their values to reset them. */ if (isr & DP_ISR_CNT) { dp83902a_ClearCounters(); } /* * Check for overflow. It's a special case, since there's a * particular procedure that must be followed to get back into * a running state.a */ if (isr & DP_ISR_OFLW) { dp83902a_Overflow(); } else { /* * Other kinds of interrupts can be acknowledged simply by * clearing the relevant bits of the ISR. Do that now, then * handle the interrupts we care about. */ DP_OUT(base, DP_ISR, isr); /* Clear set bits */ if (!dp->running) break; /* Is this necessary? */ /* * Check for tx_started on TX event since these may happen * spuriously it seems. */ if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { dp83902a_TxEvent(); } if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { dp83902a_RxEvent(); } } DP_IN(base, DP_ISR, isr); }}/* U-boot specific routines */static u8 *pbuf = NULL;static int pkey = -1;static int initialized = 0;void uboot_push_packet_len(int len) { PRINTK("pushed len = %d\n", len); if (len >= 2000) { printf("NE2000: packet too big\n"); return; } dp83902a_recv(&pbuf[0], len); /*Just pass it to the upper layer*/ NetReceive(&pbuf[0], len);}void uboot_push_tx_done(int key, int val) { PRINTK("pushed key = %d\n", key); pkey = key;}int eth_init(bd_t *bd) { int r; u8 dev_addr[6]; char ethaddr[20]; PRINTK("### eth_init\n"); if (!pbuf) { pbuf = malloc(2000); if (!pbuf) { printf("Cannot allocate rx buffer\n"); return -1; } }#ifdef CONFIG_DRIVER_NE2000_CCR { vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR; PRINTK("CCR before is %x\n", *p); *p = CONFIG_DRIVER_NE2000_VAL; PRINTK("CCR after is %x\n", *p); }#endif nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; r = get_prom(dev_addr, nic.base); if (!r) return -1; sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", dev_addr[0], dev_addr[1], dev_addr[2], dev_addr[3], dev_addr[4], dev_addr[5]) ; PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); setenv ("ethaddr", ethaddr); nic.data = nic.base + DP_DATA; nic.tx_buf1 = START_PG; nic.tx_buf2 = START_PG2; nic.rx_buf_start = RX_START; nic.rx_buf_end = RX_END; if (dp83902a_init() == false) return -1; dp83902a_start(dev_addr); initialized = 1; return 0;}void eth_halt() { PRINTK("### eth_halt\n"); if(initialized) dp83902a_stop(); initialized = 0;}int eth_rx() { dp83902a_poll(); return 1;}int eth_send(volatile void *packet, int length) { int tmo; PRINTK("### eth_send\n"); pkey = -1; dp83902a_send((u8 *) packet, length, 666); tmo = get_timer (0) + TOUT * CFG_HZ; while(1) { dp83902a_poll(); if (pkey != -1) { PRINTK("Packet sucesfully sent\n"); return 0; } if (get_timer (0) >= tmo) { printf("transmission error (timoeut)\n"); return 0; } } return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?