/*
 * This function handles receipt of a packet from the network
 */
static int davinci_eth_rcv_packet (struct eth_device *dev)
{
	volatile emac_desc *rx_curr_desc;
	volatile emac_desc *curr_desc;
	volatile emac_desc *tail_desc;
	int status, ret = -1;

	rx_curr_desc = emac_rx_active_head;
	status = rx_curr_desc->pkt_flag_len;
	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
			/* Error in packet - discard it and requeue desc */
			printf ("WARN: emac_rcv_pkt: Error in packet\n");
		} else {
			NetReceive (rx_curr_desc->buffer,
				    (rx_curr_desc->buff_off_len & 0xffff));
			ret = rx_curr_desc->buff_off_len & 0xffff;
		}

		/* Ack received packet descriptor */
		adap_emac->RX0CP = BD_TO_HW((unsigned int) rx_curr_desc);
		curr_desc = rx_curr_desc;
		emac_rx_active_head =
			(volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next));

		if (status & EMAC_CPPI_EOQ_BIT) {
			if (emac_rx_active_head) {
				adap_emac->RX0HDP =
				BD_TO_HW((unsigned int) emac_rx_active_head);
			} else {
				emac_rx_queue_active = 0;
				printf ("INFO:emac_rcv_packet: RX Queue not active\n");
			}
		}

		/* Recycle RX descriptor */
		rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
		rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
		rx_curr_desc->next = 0;

		if (emac_rx_active_head == 0) {
			printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
			emac_rx_active_head = curr_desc;
			emac_rx_active_tail = curr_desc;
			if (emac_rx_queue_active != 0) {
				adap_emac->RX0HDP =
					BD_TO_HW((unsigned int) emac_rx_active_head);
				printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
				emac_rx_queue_active = 1;
			}
		} else {
			tail_desc = emac_rx_active_tail;
			emac_rx_active_tail = curr_desc;
			tail_desc->next = BD_TO_HW((unsigned int) curr_desc);
			status = tail_desc->pkt_flag_len;
			if (status & EMAC_CPPI_EOQ_BIT) {
				adap_emac->RX0HDP = BD_TO_HW((unsigned int) curr_desc);
				status &= ~EMAC_CPPI_EOQ_BIT;
				tail_desc->pkt_flag_len = status;
			}
		}
		return (ret);
	}

	return (0);
}
示例#2
0
/*
 * This function handles receipt of a packet from the network
 */
static int davinci_eth_rcv_packet (struct eth_device *dev)
{
	volatile emac_desc *rx_curr_desc;
	volatile emac_desc *curr_desc;
	volatile emac_desc *tail_desc;
	int status, ret = -1;

	rx_curr_desc = emac_rx_active_head;
	if (!rx_curr_desc)
		return 0;
	status = rx_curr_desc->pkt_flag_len;
	if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) {
		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
			/* Error in packet - discard it and requeue desc */
			printf ("WARN: emac_rcv_pkt: Error in packet\n");
		} else {
			unsigned long tmp = (unsigned long)rx_curr_desc->buffer;
			unsigned short len =
				rx_curr_desc->buff_off_len & 0xffff;

			invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN));
			net_process_received_packet(rx_curr_desc->buffer, len);
			ret = len;
		}

		/* Ack received packet descriptor */
		writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP);
		curr_desc = rx_curr_desc;
		emac_rx_active_head =
			(volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next));

		if (status & EMAC_CPPI_EOQ_BIT) {
			if (emac_rx_active_head) {
				writel(BD_TO_HW((ulong)emac_rx_active_head),
				       &adap_emac->RX0HDP);
			} else {
				emac_rx_queue_active = 0;
				printf ("INFO:emac_rcv_packet: RX Queue not active\n");
			}
		}

		/* Recycle RX descriptor */
		rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
		rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
		rx_curr_desc->next = 0;

		if (emac_rx_active_head == 0) {
			printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
			emac_rx_active_head = curr_desc;
			emac_rx_active_tail = curr_desc;
			if (emac_rx_queue_active != 0) {
				writel(BD_TO_HW((ulong)emac_rx_active_head),
				       &adap_emac->RX0HDP);
				printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
				emac_rx_queue_active = 1;
			}
		} else {
			tail_desc = emac_rx_active_tail;
			emac_rx_active_tail = curr_desc;
			tail_desc->next = BD_TO_HW((ulong) curr_desc);
			status = tail_desc->pkt_flag_len;
			if (status & EMAC_CPPI_EOQ_BIT) {
				writel(BD_TO_HW((ulong)curr_desc),
				       &adap_emac->RX0HDP);
				status &= ~EMAC_CPPI_EOQ_BIT;
				tail_desc->pkt_flag_len = status;
			}
		}
		return (ret);
	}
	return (0);
}
示例#3
0
/*
 * This function handles receipt of a packet from the network
 */
static int davinci_emac_recv(struct eth_device *edev)
{
	struct davinci_emac_priv *priv = edev->priv;
	void __iomem *rx_curr_desc, *curr_desc, *tail_desc;
	unsigned char *pkt;
	int status, len, ret = -1;

	dev_dbg(priv->dev, "+ emac_recv\n");

	rx_curr_desc = priv->emac_rx_active_head;
	status = readl(rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
	if (status & EMAC_CPPI_OWNERSHIP_BIT) {
		ret = 0;
		goto out;
	}

	if (status & EMAC_CPPI_RX_ERROR_FRAME) {
		/* Error in packet - discard it and requeue desc */
		dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
	} else {
		pkt = (unsigned char *)readl(rx_curr_desc + EMAC_DESC_BUFFER);
		len = readl(rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN) & 0xffff;
		dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
		dma_sync_single_for_cpu((unsigned long)pkt, len, DMA_FROM_DEVICE);
		net_receive(edev, pkt, len);
		dma_sync_single_for_device((unsigned long)pkt, len, DMA_FROM_DEVICE);
		ret = len;
	}

	/* Ack received packet descriptor */
	writel(BD_TO_HW(rx_curr_desc), priv->adap_emac + EMAC_RX0CP);
	curr_desc = rx_curr_desc;
	priv->emac_rx_active_head = HW_TO_BD(readl(rx_curr_desc + EMAC_DESC_NEXT));

	if (status & EMAC_CPPI_EOQ_BIT) {
		if (priv->emac_rx_active_head) {
			writel(BD_TO_HW(priv->emac_rx_active_head),
				priv->adap_emac + EMAC_RX0HDP);
		} else {
			priv->emac_rx_queue_active = 0;
			dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
		}
	}

	/* Recycle RX descriptor */
	writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN);
	writel(EMAC_CPPI_OWNERSHIP_BIT, rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
	writel(0, rx_curr_desc + EMAC_DESC_NEXT);

	if (priv->emac_rx_active_head == 0) {
		dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
		priv->emac_rx_active_head = curr_desc;
		priv->emac_rx_active_tail = curr_desc;
		if (priv->emac_rx_queue_active != 0) {
			writel(BD_TO_HW(priv->emac_rx_active_head), priv->adap_emac + EMAC_RX0HDP);
			dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
			priv->emac_rx_queue_active = 1;
		}
	} else {
		tail_desc = priv->emac_rx_active_tail;
		priv->emac_rx_active_tail = curr_desc;
		writel(BD_TO_HW(curr_desc), tail_desc + EMAC_DESC_NEXT);
		status = readl(tail_desc + EMAC_DESC_PKT_FLAG_LEN);
		if (status & EMAC_CPPI_EOQ_BIT) {
			writel(BD_TO_HW(curr_desc), priv->adap_emac + EMAC_RX0HDP);
			status &= ~EMAC_CPPI_EOQ_BIT;
			writel(status, tail_desc + EMAC_DESC_PKT_FLAG_LEN);
		}
	}

out:
	dev_dbg(priv->dev, "- emac_recv\n");

	return ret;
}