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