/**
 * gelic_net_xmit - transmits a frame over the device
 * @skb: packet to send out
 * @netdev: interface device structure
 *
 * returns 0 on success, <0 on failure
 */
int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
	struct gelic_card *card = netdev_card(netdev);
	struct gelic_descr *descr;
	int result;
	unsigned long flags;

	spin_lock_irqsave(&card->tx_lock, flags);

	gelic_card_release_tx_chain(card, 0);

	descr = gelic_card_get_next_tx_descr(card);
	if (!descr) {
		/*
		 * no more descriptors free
		 */
		gelic_card_stop_queues(card);
		spin_unlock_irqrestore(&card->tx_lock, flags);
		return NETDEV_TX_BUSY;
	}

	result = gelic_descr_prepare_tx(card, descr, skb);
	if (result) {
		/*
		 * DMA map failed.  As chanses are that failure
		 * would continue, just release skb and return
		 */
		netdev->stats.tx_dropped++;
		dev_kfree_skb_any(skb);
		spin_unlock_irqrestore(&card->tx_lock, flags);
		return NETDEV_TX_OK;
	}
	/*
	 * link this prepared descriptor to previous one
	 * to achieve high performance
	 */
	descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
	/*
	 * as hardware descriptor is modified in the above lines,
	 * ensure that the hardware sees it
	 */
	wmb();
	if (gelic_card_kick_txdma(card, descr)) {
		/*
		 * kick failed.
		 * release descriptors which were just prepared
		 */
		netdev->stats.tx_dropped++;
		gelic_descr_release_tx(card, descr);
		gelic_descr_release_tx(card, descr->next);
		card->tx_chain.tail = descr->next->next;
		dev_info(ctodev(card), "%s: kick failure\n", __func__);
	} else {
		/* OK, DMA started/reserved */
		netdev->trans_start = jiffies;
	}

	spin_unlock_irqrestore(&card->tx_lock, flags);
	return NETDEV_TX_OK;
}
/**
 * gelic_card_release_tx_chain - processes sent tx descriptors
 * @card: adapter structure
 * @stop: net_stop sequence
 *
 * releases the tx descriptors that gelic has finished with
 */
static void gelic_card_release_tx_chain(struct gelic_card *card, int stop)
{
	struct gelic_descr_chain *tx_chain;
	enum gelic_descr_dma_status status;
	struct net_device *netdev;
	int release = 0;

	for (tx_chain = &card->tx_chain;
	     tx_chain->head != tx_chain->tail && tx_chain->tail;
	     tx_chain->tail = tx_chain->tail->next) {
		status = gelic_descr_get_status(tx_chain->tail);
		netdev = tx_chain->tail->skb->dev;
		switch (status) {
		case GELIC_DESCR_DMA_RESPONSE_ERROR:
		case GELIC_DESCR_DMA_PROTECTION_ERROR:
		case GELIC_DESCR_DMA_FORCE_END:
			if (printk_ratelimit())
				dev_info(ctodev(card),
					 "%s: forcing end of tx descriptor " \
					 "with status %x\n",
					 __func__, status);
			netdev->stats.tx_dropped++;
			break;

		case GELIC_DESCR_DMA_COMPLETE:
			if (tx_chain->tail->skb) {
				netdev->stats.tx_packets++;
				netdev->stats.tx_bytes +=
					tx_chain->tail->skb->len;
			}
			break;

		case GELIC_DESCR_DMA_CARDOWNED:
			/* pending tx request */
		default:
			/* any other value (== GELIC_DESCR_DMA_NOT_IN_USE) */
			if (!stop)
				goto out;
		}
		gelic_descr_release_tx(card, tx_chain->tail);
		release ++;
	}
out:
	if (!stop && release)
		gelic_card_wake_queues(card);
}