Beispiel #1
0
/*
  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
  'dp83902a_recv' will be called to actually fetch it from the hardware.
*/
static void
dp83902a_RxEvent(void)
{
	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
	cyg_uint8 *base = dp->base;
	unsigned char rsr;
	unsigned char rcv_hdr[4];
	int i, len, pkt, cur;

	DEBUG_FUNCTION();

	DP_IN(base, DP_RSR, rsr);
	while (true) {
		/* Read incoming packet header */
		DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
		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

		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);
		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 */
	}
}
Beispiel #2
0
/*
 * 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
 * 'dp83902a_recv' will be called to actually fetch it from the hardware.
 */
static void dp83902a_RxEvent(struct nic_priv_data *dp)
{
	u8 rsr;
	u8 rcv_hdr[4];
	int i, len, pkt, cur = 0;

	rsr = n2k_inb(dp, DP_RSR);

	if (!(rsr & 0x01)) {
		return;
	}

	while (true) {
		/* Read incoming packet header */
		n2k_outb(dp, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
		n2k_outb(dp, DP_P1_CURP, cur);
		n2k_outb(dp, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
		pkt = n2k_inb(dp, DP_BNDRY);

		pkt += 1;
		if (pkt == dp->rx_buf_end)
			pkt = dp->rx_buf_start;

		if (pkt == cur) {
			break;
		}
		n2k_outb(dp, DP_RBCL, sizeof(rcv_hdr));
		n2k_outb(dp, DP_RBCH, 0);
		n2k_outb(dp, DP_RSAL, 0);
		n2k_outb(dp, DP_RSAH, pkt);
		if (dp->rx_next == pkt) {
			if (cur == dp->rx_buf_start)
				n2k_outb(dp, DP_BNDRY, dp->rx_buf_end - 1);
			else
				n2k_outb(dp, DP_BNDRY, cur - 1); /* Update pointer */
			return;
		}
		dp->rx_next = pkt;
		n2k_outb(dp, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
		n2k_outb(dp, DP_CR, DP_CR_RDMA | DP_CR_START);

		/* read header (get data size)*/
		for (i = 0; i < sizeof(rcv_hdr);) {
			DP_IN_DATA(dp->data, rcv_hdr[i++]);
		}

		len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);

		/* FIXME: Tell that data has been read */
		push_packet_len(dp, len);

		if (rcv_hdr[1] == dp->rx_buf_start)
			n2k_outb(dp, DP_BNDRY, dp->rx_buf_end - 1);
		else
			n2k_outb(dp, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
	}
}
Beispiel #3
0
/*
 * 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 void dp83902a_recv(struct nic_priv_data *dp, int len)
{
	u8 *base = dp->base;
	int i, mlen;
	u8 saved_char = 0;
	bool saved;

	/* 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);

	saved = false;
	for (i = 0; i < 1; i++) {
		mlen = len;
		while (0 < mlen) {
			/* Saved byte from previous loop? */
			if (saved) {
				vmm_ringbuf_enqueue(dp->rx_rb, &saved_char, TRUE);
				mlen--;
				saved = false;
				continue;
			}
			
			{
				u8 tmp;
				DP_IN_DATA(dp->data, tmp);
				vmm_ringbuf_enqueue(dp->rx_rb, &tmp, TRUE);
				mlen--;
			}
		}
	}
}
Beispiel #4
0
/*
  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 void
dp83902a_recv(unsigned char *data, int len)
{
	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
	cyg_uint8 *base = dp->base;
	int i, mlen;
	cyg_uint8 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", (unsigned long) data, mlen);
			dx = 0;
#endif
			while (0 < mlen) {
				/* Saved byte from previous loop? */
				if (saved) {
					*data++ = saved_char;
					mlen--;
					saved = false;
					continue;
				}

				{
					cyg_uint8 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
		}
	}
}
Beispiel #5
0
/*
  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
dp83902a_send(unsigned char *data, int total_len, unsigned long key)
{
	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
	cyg_uint8 *base = dp->base;
	int len, start_page, pkt_len, i, isr;
#if DEBUG & 4
	int dx;
#endif

	DEBUG_FUNCTION();

	len = 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 == dp->tx_buf1) {
		dp->tx1 = start_page;
		dp->tx1_len = pkt_len;
		dp->tx1_key = key;
		dp->tx_next = dp->tx_buf2;
	} else {
		dp->tx2 = start_page;
		dp->tx2_len = pkt_len;
		dp->tx2_key = key;
		dp->tx_next = dp->tx_buf1;
	}

#if DEBUG & 5
	printf("TX prep page %d len %d\n", start_page, pkt_len);
#endif

	DP_OUT(base, DP_ISR, DP_ISR_RDC);  /* Clear end of DMA */
	{
		/* Dummy read. The manual sez something slightly different, */
		/* but the code is extended a bit to do what Hitachi's monitor */
		/* does (i.e., also read data). */

		cyg_uint16 tmp;
		int len = 1;

		DP_OUT(base, DP_RSAL, 0x100-len);
		DP_OUT(base, DP_RSAH, (start_page-1) & 0xff);
		DP_OUT(base, DP_RBCL, len);
		DP_OUT(base, DP_RBCH, 0);
		DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
		DP_IN_DATA(dp->data, tmp);
	}

#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
	/* Stall for a bit before continuing to work around random data */
	/* corruption problems on some platforms. */
	CYGACC_CALL_IF_DELAY_US(1);
#endif

	/* Send data to device buffer(s) */
	DP_OUT(base, DP_RSAL, 0);
	DP_OUT(base, DP_RSAH, start_page);
	DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
	DP_OUT(base, DP_RBCH, pkt_len >> 8);
	DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);

	/* Put data into buffer */
#if DEBUG & 4
	printf(" sg buf %08lx len %08x\n ", (unsigned long) data, len);
	dx = 0;
#endif
	while (len > 0) {
#if DEBUG & 4
		printf(" %02x", *data);
		if (0 == (++dx % 16)) printf("\n ");
#endif
		DP_OUT_DATA(dp->data, *data++);
		len--;
	}
#if DEBUG & 4
	printf("\n");
#endif
	if (total_len < pkt_len) {
#if DEBUG & 4
		printf("  + %d bytes of padding\n", pkt_len - total_len);
#endif
		/* Padding to 802.3 length was required */
		for (i = total_len;  i < pkt_len;) {
			i++;
			DP_OUT_DATA(dp->data, 0);
		}
	}

#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
	/* After last data write, delay for a bit before accessing the */
	/* device again, or we may get random data corruption in the last */
	/* datum (on some platforms). */
	CYGACC_CALL_IF_DELAY_US(1);
#endif

	/* Wait for DMA to complete */
	do {
		DP_IN(base, DP_ISR, isr);
	} while ((isr & DP_ISR_RDC) == 0);
	/* Then disable DMA */
	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);

	/* 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 */
		}
		dp83902a_start_xmit(start_page, pkt_len);
	}
}
Beispiel #6
0
/*
 * 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 dp83902a_send(struct nic_priv_data *dp, u8 *data, int total_len, u32 key)
{
	int len, start_page, pkt_len, i;
	volatile int isr;

	len = 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 == dp->tx_buf1) {
		dp->tx1 = start_page;
		dp->tx1_len = pkt_len;
		dp->tx1_key = key;
		dp->tx_next = dp->tx_buf2;
	} else {
		dp->tx2 = start_page;
		dp->tx2_len = pkt_len;
		dp->tx2_key = key;
		dp->tx_next = dp->tx_buf1;
	}


	n2k_outb(dp, DP_ISR, DP_ISR_RDC);	/* Clear end of DMA */
	{
		/*
		 * Dummy read. The manual sez something slightly different,
		 * but the code is extended a bit to do what Hitachi's monitor
		 * does (i.e., also read data).
		 */

		u16 tmp;
		int len = 1;

		n2k_outb(dp, DP_RSAL, 0x100 - len);
		n2k_outb(dp, DP_RSAH, (start_page - 1) & 0xff);
		n2k_outb(dp, DP_RBCL, len);
		n2k_outb(dp, DP_RBCH, 0);
		n2k_outb(dp, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
		DP_IN_DATA(dp->data, tmp);
	}

	/* Send data to device buffer(s) */
	n2k_outb(dp, DP_RSAL, 0);
	n2k_outb(dp, DP_RSAH, start_page);
	n2k_outb(dp, DP_RBCL, pkt_len & 0xFF);
	n2k_outb(dp, DP_RBCH, pkt_len >> 8);
	n2k_outb(dp, DP_CR, DP_CR_WDMA | DP_CR_START);

	/* Put data into buffer */
	while (len > 0) {
		DP_OUT_DATA(dp->data, *data++);
		len--;
	}

	if (total_len < pkt_len) {
		/* Padding to 802.3 length was required */
		for (i = total_len; i < pkt_len;) {
			i++;
			DP_OUT_DATA(dp->data, 0);
		}
	}

	/* Wait for DMA to complete */
	do {
		isr = n2k_inb(dp, DP_ISR);
	} while ((isr & DP_ISR_RDC) == 0);

	/* Then disable DMA */
	n2k_outb(dp, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);

	/* 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 */
		}
		dp83902a_start_xmit(dp, start_page, pkt_len);
	}
}