return (new_bd < base) ? (new_bd + ring_size) : new_bd;
}
+static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp,
+ struct fec_enet_private *fep)
+{
+ return ((const char *)bdp - (const char *)base) / fep->bufdesc_size;
+}
+
static void *swap_buffer(void *bufaddr, int len)
{
int i;
return 0;
}
-static netdev_tx_t
-fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static int txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
status = bdp->cbd_sc;
- if (status & BD_ENET_TX_READY) {
- /* Ooops. All transmit buffers are full. Bail out.
- * This should not happen, since ndev->tbusy should be set.
- */
- netdev_err(ndev, "tx queue full!\n");
- return NETDEV_TX_BUSY;
- }
-
/* Protocol checksum off-load for TCP and UDP. */
if (fec_enet_clear_csum(skb, ndev)) {
dev_kfree_skb_any(skb);
bufaddr = skb->data;
bdp->cbd_datlen = skb->len;
- /*
- * On some FEC implementations data must be aligned on
- * 4-byte boundaries. Use bounce buffers to copy data
- * and get it aligned. Ugh.
- */
- if (fep->bufdesc_ex)
- index = (struct bufdesc_ex *)bdp -
- (struct bufdesc_ex *)fep->tx_bd_base;
- else
- index = bdp - fep->tx_bd_base;
+ index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
memcpy(fep->tx_bounce[index], skb->data, skb->len);
fep->cur_tx = bdp;
- if (fep->cur_tx == fep->dirty_tx)
- netif_stop_queue(ndev);
-
/* Trigger transmission start */
writel(0, fep->hwp + FEC_X_DES_ACTIVE);
return NETDEV_TX_OK;
}
+static netdev_tx_t
+fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct bufdesc *bdp;
+ unsigned short status;
+ int ret;
+
+ /* Fill in a Tx ring entry */
+ bdp = fep->cur_tx;
+
+ status = bdp->cbd_sc;
+
+ if (status & BD_ENET_TX_READY) {
+ /* Ooops. All transmit buffers are full. Bail out.
+ * This should not happen, since ndev->tbusy should be set.
+ */
+ netdev_err(ndev, "tx queue full!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ ret = txq_submit_skb(skb, ndev);
+ if (ret == -EBUSY)
+ return NETDEV_TX_BUSY;
+
+ if (fep->cur_tx == fep->dirty_tx)
+ netif_stop_queue(ndev);
+
+ return NETDEV_TX_OK;
+}
+
/* Init RX & TX buffer descriptors
*/
static void fec_enet_bd_init(struct net_device *dev)
if (bdp == fep->cur_tx)
break;
- if (fep->bufdesc_ex)
- index = (struct bufdesc_ex *)bdp -
- (struct bufdesc_ex *)fep->tx_bd_base;
- else
- index = bdp - fep->tx_bd_base;
+ index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
skb = fep->tx_skbuff[index];
dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, skb->len,
pkt_len = bdp->cbd_datlen;
ndev->stats.rx_bytes += pkt_len;
- if (fep->bufdesc_ex)
- index = (struct bufdesc_ex *)bdp -
- (struct bufdesc_ex *)fep->rx_bd_base;
- else
- index = bdp - fep->rx_bd_base;
+ index = fec_enet_get_bd_index(fep->rx_bd_base, bdp, fep);
data = fep->rx_skbuff[index]->data;
dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
/* Set receive and transmit descriptor base. */
fep->rx_bd_base = cbd_base;
- if (fep->bufdesc_ex)
+ if (fep->bufdesc_ex) {
fep->tx_bd_base = (struct bufdesc *)
(((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size);
- else
+ fep->bufdesc_size = sizeof(struct bufdesc_ex);
+ } else {
fep->tx_bd_base = cbd_base + fep->rx_ring_size;
+ fep->bufdesc_size = sizeof(struct bufdesc);
+ }
/* The FEC Ethernet specific entries in the device structure */
ndev->watchdog_timeo = TX_TIMEOUT;