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