X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fsmc91x.c;h=1438fdd20826487a0d8d0535143f484b1111a3be;hb=4851d3aaa550b7b62553dd19fcadc7b586da4f17;hp=a6c0628fdb21b2167ebb04ecfcb928f19b5274bb;hpb=8de901150f3c58b019b2a3ce497d23ab662dbb8b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index a6c0628..1438fdd 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -129,7 +129,7 @@ MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); /* * Transmit timeout, default 5 seconds. */ -static int watchdog = 5000; +static int watchdog = 1000; module_param(watchdog, int, 0400); MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); @@ -315,15 +315,25 @@ static void smc_reset(struct net_device *dev) struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int ctl, cfg; + struct sk_buff *pending_skb; DBG(2, "%s: %s\n", dev->name, __FUNCTION__); - /* Disable all interrupts */ + /* Disable all interrupts, block TX tasklet */ spin_lock(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); + pending_skb = lp->pending_tx_skb; + lp->pending_tx_skb = NULL; spin_unlock(&lp->lock); + /* free any pending tx skb */ + if (pending_skb) { + dev_kfree_skb(pending_skb); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + } + /* * This resets the registers mostly to defaults, but doesn't * affect EEPROM. That seems unnecessary @@ -389,14 +399,6 @@ static void smc_reset(struct net_device *dev) SMC_SELECT_BANK(2); SMC_SET_MMU_CMD(MC_RESET); SMC_WAIT_MMU_BUSY(); - - /* clear anything saved */ - if (lp->pending_tx_skb != NULL) { - dev_kfree_skb (lp->pending_tx_skb); - lp->pending_tx_skb = NULL; - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - } } /* @@ -440,6 +442,7 @@ static void smc_shutdown(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; + struct sk_buff *pending_skb; DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); @@ -447,7 +450,11 @@ static void smc_shutdown(struct net_device *dev) spin_lock(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); + pending_skb = lp->pending_tx_skb; + lp->pending_tx_skb = NULL; spin_unlock(&lp->lock); + if (pending_skb) + dev_kfree_skb(pending_skb); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK(0); @@ -627,7 +634,12 @@ static void smc_hardware_send_pkt(unsigned long data) } skb = lp->pending_tx_skb; + if (unlikely(!skb)) { + smc_special_unlock(&lp->lock); + return; + } lp->pending_tx_skb = NULL; + packet_no = SMC_GET_AR(); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); @@ -660,15 +672,14 @@ static void smc_hardware_send_pkt(unsigned long data) SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG); /* - * If THROTTLE_TX_PKTS is set, we look at the TX_EMPTY flag - * before queueing this packet for TX, and if it's clear then - * we stop the queue here. This will have the effect of - * having at most 2 packets queued for TX in the chip's memory - * at all time. If THROTTLE_TX_PKTS is not set then the queue - * is stopped only when memory allocation (MC_ALLOC) does not - * succeed right away. + * If THROTTLE_TX_PKTS is set, we stop the queue here. This will + * have the effect of having at most one packet queued for TX + * in the chip's memory at all time. + * + * If THROTTLE_TX_PKTS is not set then the queue is stopped only + * when memory allocation (MC_ALLOC) does not succeed right away. */ - if (THROTTLE_TX_PKTS && !(SMC_GET_INT() & IM_TX_EMPTY_INT)) + if (THROTTLE_TX_PKTS) netif_stop_queue(dev); /* queue the packet for TX */ @@ -703,7 +714,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) DBG(3, "%s: %s\n", dev->name, __FUNCTION__); BUG_ON(lp->pending_tx_skb != NULL); - lp->pending_tx_skb = skb; /* * The MMU wants the number of pages to be the number of 256 bytes @@ -719,7 +729,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk("%s: Far too big packet error.\n", dev->name); - lp->pending_tx_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_dropped++; dev_kfree_skb(skb); @@ -746,6 +755,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc_special_unlock(&lp->lock); + lp->pending_tx_skb = skb; if (!poll_count) { /* oh well, wait until the chip finds memory later */ netif_stop_queue(dev); @@ -1063,7 +1073,7 @@ static void smc_phy_powerdown(struct net_device *dev) above). linkwatch_event() also wants the netlink semaphore. */ while(lp->work_pending) - schedule(); + yield(); bmcr = smc_phy_read(dev, phy, MII_BMCR); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); @@ -1311,15 +1321,16 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!status) break; - if (status & IM_RCV_INT) { - DBG(3, "%s: RX irq\n", dev->name); - smc_rcv(dev); - } else if (status & IM_TX_INT) { + if (status & IM_TX_INT) { + /* do this before RX as it will free memory quickly */ DBG(3, "%s: TX int\n", dev->name); smc_tx(dev); SMC_ACK_INT(IM_TX_INT); if (THROTTLE_TX_PKTS) netif_wake_queue(dev); + } else if (status & IM_RCV_INT) { + DBG(3, "%s: RX irq\n", dev->name); + smc_rcv(dev); } else if (status & IM_ALLOC_INT) { DBG(3, "%s: Allocation irq\n", dev->name); tasklet_hi_schedule(&lp->tx_task); @@ -1606,14 +1617,8 @@ static int smc_close(struct net_device *dev) /* clear everything */ smc_shutdown(dev); - + tasklet_kill(&lp->tx_task); smc_phy_powerdown(dev); - - if (lp->pending_tx_skb) { - dev_kfree_skb(lp->pending_tx_skb); - lp->pending_tx_skb = NULL; - } - return 0; } @@ -1993,7 +1998,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (retval) goto err_out; - set_irq_type(dev->irq, IRQT_RISING); + set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); #ifdef SMC_USE_PXA_DMA {