Ejemplo n.º 1
0
static int dwc_ether_rx(struct eth_device *dev)
{
	struct dw_eth_dev *priv = dev->priv;
	u32 desc_num = priv->rx_currdescnum;
	struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];

	u32 status = desc_p->txrx_status;
	int length = 0;

	/* Check  if the owner is the CPU */
	if (status & DESC_RXSTS_OWNBYDMA)
		return 0;

	length = (status & DESC_RXSTS_FRMLENMSK) >> \
		 DESC_RXSTS_FRMLENSHFT;

	net_receive(desc_p->dmamac_addr, length);

	/*
	 * Make the current descriptor valid again and go to
	 * the next one
	 */
	dma_inv_range((unsigned long)desc_p->dmamac_addr,
		      (unsigned long)desc_p->dmamac_addr + length);
	desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;

	/* Test the wrap-around condition. */
	if (++desc_num >= CONFIG_RX_DESCR_NUM)
		desc_num = 0;

	priv->rx_currdescnum = desc_num;

	return length;
}
Ejemplo n.º 2
0
static void rx_descs_init(struct eth_device *dev)
{
	struct dw_eth_dev *priv = dev->priv;
	struct eth_dma_regs *dma_p = priv->dma_regs_p;
	struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
	char *rxbuffs = &priv->rxbuffs[0];
	struct dmamacdescr *desc_p;
	u32 idx;

	for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
		desc_p = &desc_table_p[idx];
		desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
		desc_p->dmamac_next = &desc_table_p[idx + 1];

		desc_p->dmamac_cntl =
			(MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
				      DESC_RXCTRL_RXCHAIN;

		dma_inv_range((unsigned long)desc_p->dmamac_addr,
			      (unsigned long)desc_p->dmamac_addr + CONFIG_ETH_BUFSIZE);
		desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
	}

	/* Correcting the last pointer of the chain */
	desc_p->dmamac_next = &desc_table_p[0];

	writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
}
Ejemplo n.º 3
0
static int arc_emac_recv(struct eth_device *edev)
{
	struct arc_emac_priv *priv = edev->priv;
	unsigned int work_done;

	for (work_done = 0; work_done < RX_BD_NUM; work_done++) {
		unsigned int *last_rx_bd = &priv->last_rx_bd;
		struct arc_emac_bd *rxbd = &priv->rxbd[*last_rx_bd];
		unsigned int pktlen, info = le32_to_cpu(rxbd->info);

		if (unlikely((info & OWN_MASK) == FOR_EMAC))
			break;

		/*
		 * Make a note that we saw a packet at this BD.
		 * So next time, driver starts from this + 1
		 */
		*last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;

		if (unlikely((info & FIRST_OR_LAST_MASK) !=
			     FIRST_OR_LAST_MASK)) {
			/*
			 * We pre-allocate buffers of MTU size so incoming
			 * packets won't be split/chained.
			 */
			printk(KERN_DEBUG "incomplete packet received\n");

			/* Return ownership to EMAC */
			rxbd->info = cpu_to_le32(FOR_EMAC | PKTSIZE);
			continue;
		}

		pktlen = info & LEN_MASK;

		/* invalidate current receive buffer */
		dma_inv_range((unsigned long)rxbd->data,
			      (unsigned long)rxbd->data + pktlen);

		net_receive(edev, (unsigned char *)rxbd->data, pktlen);

		rxbd->info = cpu_to_le32(FOR_EMAC | PKTSIZE);
	}

	return work_done;
}
Ejemplo n.º 4
0
static inline void __dma_sync_mips(unsigned long addr, size_t size,
				   enum dma_data_direction direction)
{
	switch (direction) {
	case DMA_TO_DEVICE:
		dma_flush_range(addr, addr + size);
		break;

	case DMA_FROM_DEVICE:
		dma_inv_range(addr, addr + size);
		break;

	case DMA_BIDIRECTIONAL:
		dma_flush_range(addr, addr + size);
		break;

	default:
		BUG();
	}
}
Ejemplo n.º 5
0
static int
dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
{
	struct dwmci_host *host = to_dwmci_host(mci);
	int flags = 0;
	uint32_t mask, ctrl;
	uint64_t start;
	int ret;
	unsigned int num_bytes = 0;
	const void *writebuf = NULL;

	start = get_time_ns();
	while (1) {
		if (!(dwmci_readl(host, DWMCI_STATUS) & DWMCI_STATUS_BUSY))
			break;

		if (is_timeout(start, 100 * MSECOND)) {
			dev_dbg(host->dev, "Timeout on data busy\n");
			return -ETIMEDOUT;
		}
	}

	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);

	if (data) {
		num_bytes = data->blocks * data->blocksize;

		if (data->flags & MMC_DATA_WRITE) {
			dma_flush_range((unsigned long)data->src,
				(unsigned long)(data->src + data->blocks * 512));

			writebuf = data->src;
		}

		ret = dwmci_prepare_data(host, data);
		if (ret)
			return ret;
	}

	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);

	if (data)
		flags = dwmci_set_transfer_mode(host, data);

	if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
		return -EINVAL;

	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
		flags |= DWMCI_CMD_ABORT_STOP;
	else
		flags |= DWMCI_CMD_PRV_DAT_WAIT;

	if (cmd->resp_type & MMC_RSP_PRESENT) {
		flags |= DWMCI_CMD_RESP_EXP;
		if (cmd->resp_type & MMC_RSP_136)
			flags |= DWMCI_CMD_RESP_LENGTH;
	}

	if (cmd->resp_type & MMC_RSP_CRC)
		flags |= DWMCI_CMD_CHECK_CRC;

	flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG);

	dev_dbg(host->dev, "Sending CMD%d\n", cmd->cmdidx);

	dwmci_writel(host, DWMCI_CMD, flags);

	start = get_time_ns();
	while (1) {
		mask = dwmci_readl(host, DWMCI_RINTSTS);
		if (mask & DWMCI_INTMSK_CDONE) {
			if (!data)
				dwmci_writel(host, DWMCI_RINTSTS, mask);
			break;
		}
		if (is_timeout(start, 100 * MSECOND))
			return -ETIMEDOUT;
	}

	if (mask & DWMCI_INTMSK_RTO) {
		dev_dbg(host->dev, "Response Timeout..\n");
		return -ETIMEDOUT;
	} else if (mask & DWMCI_INTMSK_RE) {
		dev_dbg(host->dev, "Response Error..\n");
		return -EIO;
	}

	if (cmd->resp_type & MMC_RSP_PRESENT) {
		if (cmd->resp_type & MMC_RSP_136) {
			cmd->response[0] = dwmci_readl(host, DWMCI_RESP3);
			cmd->response[1] = dwmci_readl(host, DWMCI_RESP2);
			cmd->response[2] = dwmci_readl(host, DWMCI_RESP1);
			cmd->response[3] = dwmci_readl(host, DWMCI_RESP0);
		} else {
			cmd->response[0] = dwmci_readl(host, DWMCI_RESP0);
		}
	}

	if (data) {
		start = get_time_ns();
		do {
			mask = dwmci_readl(host, DWMCI_RINTSTS);
			if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
				dev_dbg(host->dev, "DATA ERROR!\n");
				return -EIO;
			}
			if (is_timeout(start, SECOND))
				return -ETIMEDOUT;
		} while (!(mask & DWMCI_INTMSK_DTO));

		dwmci_writel(host, DWMCI_RINTSTS, mask);

		ctrl = dwmci_readl(host, DWMCI_CTRL);
		ctrl &= ~(DWMCI_DMA_EN);
		dwmci_writel(host, DWMCI_CTRL, ctrl);

		if (data->flags & MMC_DATA_READ) {
			dma_inv_range((unsigned long)data->dest,
					(unsigned long)(data->dest + data->blocks * 512));
		}
	}

	udelay(100);

	return 0;
}
Ejemplo n.º 6
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_inv_range((ulong)pkt,
				(ulong)readl(rx_curr_desc + EMAC_DESC_BUFFER) + len);
		net_receive(pkt, len);
		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;
}