Ejemplo n.º 1
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);
	}
}
Ejemplo n.º 2
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);
	}
}