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 + -
显示快捷键?