unsigned long estatus;
unsigned long flags;
+ spin_lock_irqsave(&fep->hw_lock, flags);
if (!fep->link) {
/* Link is down or autonegotiation is in progress. */
+ netif_stop_queue(ndev);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return NETDEV_TX_BUSY;
}
- spin_lock_irqsave(&fep->hw_lock, flags);
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
* This should not happen, since ndev->tbusy should be set.
*/
printk("%s: tx queue full!.\n", ndev->name);
+ netif_stop_queue(ndev);
spin_unlock_irqrestore(&fep->hw_lock, flags);
return NETDEV_TX_BUSY;
}
if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
unsigned int index;
index = bdp - fep->tx_bd_base;
- memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len);
- bufaddr = fep->tx_bounce[index];
+ bufaddr = PTR_ALIGN(fep->tx_bounce[index], FEC_ALIGNMENT + 1);
+ memcpy(bufaddr, (void *)skb->data, skb->len);
}
if (fep->ptimer_present) {
ndev->stats.tx_errors++;
fec_restart(ndev, fep->full_duplex);
- netif_wake_queue(ndev);
+ if (fep->link && !fep->tx_full)
+ netif_wake_queue(ndev);
}
static void
bdp->cbd_bufaddr = 0;
skb = fep->tx_skbuff[fep->skb_dirty];
+ if (!skb)
+ break;
/* Check for errors. */
if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN |
/* Link on or off change */
if (phy_dev->link != fep->link) {
fep->link = phy_dev->link;
- if (phy_dev->link)
+ if (phy_dev->link) {
fec_restart(ndev, phy_dev->duplex);
- else
+ if (!fep->tx_full)
+ netif_wake_queue(ndev);
+ } else
fec_stop(ndev);
status_change = 1;
}
bdp = fep->tx_bd_base;
for (i = 0; i < TX_RING_SIZE; i++) {
fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
+ if (!fep->tx_bounce[i]) {
+ fec_enet_free_buffers(ndev);
+ return -ENOMEM;
+ }
bdp->cbd_sc = 0;
bdp->cbd_bufaddr = 0;