-/*
- * eth_port_send - Send an Ethernet packet
- *
- * DESCRIPTION:
- * This routine send a given packet described by p_pktinfo parameter. It
- * supports transmitting of a packet spaned over multiple buffers. The
- * routine updates 'curr' and 'first' indexes according to the packet
- * segment passed to the routine. In case the packet segment is first,
- * the 'first' index is update. In any case, the 'curr' index is updated.
- * If the routine get into Tx resource error it assigns 'curr' index as
- * 'first'. This way the function can abort Tx process of multiple
- * descriptors per packet.
- *
- * INPUT:
- * struct mv643xx_private *mp Ethernet Port Control srtuct.
- * struct pkt_info *p_pkt_info User packet buffer.
- *
- * OUTPUT:
- * Tx ring 'curr' and 'first' indexes are updated.
- *
- * RETURN:
- * ETH_QUEUE_FULL in case of Tx resource error.
- * ETH_ERROR in case the routine can not access Tx desc ring.
- * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource.
- * ETH_OK otherwise.
- *
- */
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-/*
- * Modified to include the first descriptor pointer in case of SG
- */
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
- struct pkt_info *p_pkt_info)
-{
- int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc;
- struct eth_tx_desc *current_descriptor;
- struct eth_tx_desc *first_descriptor;
- u32 command;
-
- /* Do not process Tx ring in case of Tx ring resource error */
- if (mp->tx_resource_err)
- return ETH_QUEUE_FULL;
-
- /*
- * The hardware requires that each buffer that is <= 8 bytes
- * in length must be aligned on an 8 byte boundary.
- */
- if (p_pkt_info->byte_cnt <= 8 && p_pkt_info->buf_ptr & 0x7) {
- printk(KERN_ERR
- "mv643xx_eth port %d: packet size <= 8 problem\n",
- mp->port_num);
- return ETH_ERROR;
- }
-
- mp->tx_desc_count++;
- BUG_ON(mp->tx_desc_count > mp->tx_ring_size);
-
- /* Get the Tx Desc ring indexes */
- tx_desc_curr = mp->tx_curr_desc_q;
- tx_desc_used = mp->tx_used_desc_q;
-
- current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
-
- tx_next_desc = (tx_desc_curr + 1) % mp->tx_ring_size;
-
- current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
- current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
- current_descriptor->l4i_chk = p_pkt_info->l4i_chk;
- mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info;
-
- command = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC |
- ETH_BUFFER_OWNED_BY_DMA;
- if (command & ETH_TX_FIRST_DESC) {
- tx_first_desc = tx_desc_curr;
- mp->tx_first_desc_q = tx_first_desc;
- first_descriptor = current_descriptor;
- mp->tx_first_command = command;
- } else {
- tx_first_desc = mp->tx_first_desc_q;
- first_descriptor = &mp->p_tx_desc_area[tx_first_desc];
- BUG_ON(first_descriptor == NULL);
- current_descriptor->cmd_sts = command;
- }
-
- if (command & ETH_TX_LAST_DESC) {
- wmb();
- first_descriptor->cmd_sts = mp->tx_first_command;
-
- wmb();
- mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
-
- /*
- * Finish Tx packet. Update first desc in case of Tx resource
- * error */
- tx_first_desc = tx_next_desc;
- mp->tx_first_desc_q = tx_first_desc;
- }
-
- /* Check for ring index overlap in the Tx desc ring */
- if (tx_next_desc == tx_desc_used) {
- mp->tx_resource_err = 1;
- mp->tx_curr_desc_q = tx_first_desc;
-
- return ETH_QUEUE_LAST_RESOURCE;
- }
-
- mp->tx_curr_desc_q = tx_next_desc;
-
- return ETH_OK;
-}
-#else
-static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
- struct pkt_info *p_pkt_info)
-{
- int tx_desc_curr;
- int tx_desc_used;
- struct eth_tx_desc *current_descriptor;
- unsigned int command_status;
-
- /* Do not process Tx ring in case of Tx ring resource error */
- if (mp->tx_resource_err)
- return ETH_QUEUE_FULL;
-
- mp->tx_desc_count++;
- BUG_ON(mp->tx_desc_count > mp->tx_ring_size);
-
- /* Get the Tx Desc ring indexes */
- tx_desc_curr = mp->tx_curr_desc_q;
- tx_desc_used = mp->tx_used_desc_q;
- current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
-
- command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
- current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
- current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
- mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info;
-
- /* Set last desc with DMA ownership and interrupt enable. */
- wmb();
- current_descriptor->cmd_sts = command_status |
- ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT;
-
- wmb();
- mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command);
-
- /* Finish Tx packet. Update first desc in case of Tx resource error */
- tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size;
-
- /* Update the current descriptor */
- mp->tx_curr_desc_q = tx_desc_curr;
-
- /* Check for ring index overlap in the Tx desc ring */
- if (tx_desc_curr == tx_desc_used) {
- mp->tx_resource_err = 1;
- return ETH_QUEUE_LAST_RESOURCE;
- }
-
- return ETH_OK;
-}
-#endif
-
-/*
- * eth_tx_return_desc - Free all used Tx descriptors
- *
- * DESCRIPTION:
- * This routine returns the transmitted packet information to the caller.
- * It uses the 'first' index to support Tx desc return in case a transmit
- * of a packet spanned over multiple buffer still in process.
- * In case the Tx queue was in "resource error" condition, where there are
- * no available Tx resources, the function resets the resource error flag.
- *
- * INPUT:
- * struct mv643xx_private *mp Ethernet Port Control srtuct.
- * struct pkt_info *p_pkt_info User packet buffer.
- *
- * OUTPUT:
- * Tx ring 'first' and 'used' indexes are updated.
- *
- * RETURN:
- * ETH_OK on success
- * ETH_ERROR otherwise.
- *
- */
-static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp,
- struct pkt_info *p_pkt_info)
-{
- int tx_desc_used;
- int tx_busy_desc;
- struct eth_tx_desc *p_tx_desc_used;
- unsigned int command_status;
- unsigned long flags;
- int err = ETH_OK;
-
- spin_lock_irqsave(&mp->lock, flags);
-
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
- tx_busy_desc = mp->tx_first_desc_q;
-#else
- tx_busy_desc = mp->tx_curr_desc_q;
-#endif
-
- /* Get the Tx Desc ring indexes */
- tx_desc_used = mp->tx_used_desc_q;
-
- p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used];
-
- /* Sanity check */
- if (p_tx_desc_used == NULL) {
- err = ETH_ERROR;
- goto out;
- }
-
- /* Stop release. About to overlap the current available Tx descriptor */
- if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err) {
- err = ETH_ERROR;
- goto out;
- }
-
- command_status = p_tx_desc_used->cmd_sts;
-
- /* Still transmitting... */
- if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) {
- err = ETH_ERROR;
- goto out;
- }
-
- /* Pass the packet information to the caller */
- p_pkt_info->cmd_sts = command_status;
- p_pkt_info->return_info = mp->tx_skb[tx_desc_used];
- p_pkt_info->buf_ptr = p_tx_desc_used->buf_ptr;
- p_pkt_info->byte_cnt = p_tx_desc_used->byte_cnt;
- mp->tx_skb[tx_desc_used] = NULL;
-
- /* Update the next descriptor to release. */
- mp->tx_used_desc_q = (tx_desc_used + 1) % mp->tx_ring_size;
-
- /* Any Tx return cancels the Tx resource error status */
- mp->tx_resource_err = 0;
-
- BUG_ON(mp->tx_desc_count == 0);
- mp->tx_desc_count--;
-
-out:
- spin_unlock_irqrestore(&mp->lock, flags);
-
- return err;
-}
-