diff --git a/drivers/net/ibm_emac/Config.in b/drivers/net/ibm_emac/Config.in --- a/drivers/net/ibm_emac/Config.in +++ b/drivers/net/ibm_emac/Config.in @@ -14,6 +14,7 @@ if [ "$CONFIG_IBM_OCP" = "y" ]; then if [ "$CONFIG_405EP" = "y" -o "$CONFIG_440GX" = "y" ]; then bool ' PHY Rx clock workaround' CONFIG_IBM_EMAC_PHY_RX_CLK_FIX fi + bool ' Disable TX interrupts' CONFIG_IBM_EMAC_NO_TX_IRQ bool ' Debugging' CONFIG_IBM_EMAC_DEBUG if [ "$CONFIG_44x" = "y" ]; then diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -126,6 +126,8 @@ static inline void emac_report_timeout_e #define PHY_POLL_LINK_ON HZ #define PHY_POLL_LINK_OFF (HZ / 5) +#define TX_CLEAN_INTERVAL HZ + /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", @@ -859,6 +861,9 @@ static int emac_open(struct net_device * emac_tx_enable(dev); emac_rx_enable(dev); netif_start_queue(ndev); +#ifdef CONFIG_IBM_EMAC_NO_TX_IRQ + mod_timer(&dev->tx_clean_timer, jiffies + TX_CLEAN_INTERVAL); +#endif local_bh_enable(); return 0; @@ -965,6 +970,7 @@ static int emac_close(struct net_device if (dev->phy.address >= 0) del_timer_sync(&dev->link_timer); + del_timer_sync(&dev->tx_clean_timer); netif_stop_queue(ndev); emac_rx_disable(dev); emac_tx_disable(dev); @@ -1000,11 +1006,13 @@ static inline int emac_xmit_finish(struc /* Send the packet out */ out_be32(&p->tmr0, EMAC_TMR0_XMIT); - if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { + ++dev->tx_cnt; +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ + if (unlikely(dev->tx_cnt == NUM_TX_BUFF)) { netif_stop_queue(ndev); DBG2("%d: stopped TX queue" NL, dev->def->index); } - +#endif ndev->trans_start = jiffies; ++dev->stats.tx_packets; dev->stats.tx_bytes += len; @@ -1013,6 +1021,7 @@ static inline int emac_xmit_finish(struc } /* BHs disabled */ +static void emac_poll_tx(void* param); static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ocp_enet_private *dev = ndev->priv; @@ -1022,6 +1031,17 @@ static int emac_start_xmit(struct sk_buf u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); +#ifdef CONFIG_IBM_EMAC_NO_TX_IRQ + if (dev->tx_cnt >= NUM_TX_BUFF / 2) { + emac_poll_tx(dev); + if (unlikely(dev->tx_cnt == NUM_TX_BUFF)) { + DBG2("%d: xmit drop packet"NL, dev->def->index); + dev_kfree_skb(skb); + ++dev->estats.tx_dropped; + return 0; + } + } +#endif consistent_sync((void *)skb->data, len, PCI_DMA_TODEVICE); slot = dev->tx_slot++; @@ -1041,6 +1061,16 @@ static int emac_start_xmit(struct sk_buf return emac_xmit_finish(dev, len); } +/* BHs disabled */ +static void emac_tx_clean_timer(unsigned long data) +{ + struct ocp_enet_private* dev = (struct ocp_enet_private*)data; + DBG2("%d: tx clean timer"NL, dev->def->index); + + emac_poll_tx(dev); + mod_timer(&dev->tx_clean_timer, jiffies + TX_CLEAN_INTERVAL); +} + #if defined(CONFIG_IBM_EMAC_TAH) static inline int emac_xmit_split(struct ocp_enet_private *dev, int slot, u32 pd, int len, int last, u16 base_ctrl) @@ -1216,10 +1246,11 @@ static void emac_poll_tx(void *param) } if (n) { dev->ack_slot = slot; +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ if (netif_queue_stopped(dev->ndev) && dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) netif_wake_queue(dev->ndev); - +#endif DBG2("%d: tx %d pkts" NL, dev->def->index, n); } } @@ -2019,6 +2050,10 @@ static int __init emac_probe(struct ocp_ dev->link_timer.function = emac_link_timer; dev->link_timer.data = (unsigned long)dev; + init_timer(&dev->tx_clean_timer); + dev->tx_clean_timer.function = emac_tx_clean_timer; + dev->tx_clean_timer.data = (unsigned long)dev; + /* Find PHY if any */ dev->phy.dev = ndev; dev->phy.mode = emacdata->phy_mode; diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -187,6 +187,8 @@ struct ocp_enet_private { struct mii_phy phy; struct timer_list link_timer; int reset_failed; + + struct timer_list tx_clean_timer; struct ibm_emac_error_stats estats; struct net_device_stats nstats; diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -215,6 +215,7 @@ static inline void mal_schedule_poll(str MAL_DBG2("%d: already in poll" NL, mal->def->index); } +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ static void mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; @@ -223,6 +224,7 @@ static void mal_txeob(int irq, void *dev mal_schedule_poll(mal); set_mal_dcrn(mal, MAL_TXEOBISR, r); } +#endif static void mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) { @@ -276,13 +278,14 @@ static int mal_poll(struct net_device *n MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, rx_work_limit); again: +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ /* Process TX skbs */ list_for_each(l, &mal->poll_list) { struct mal_commac *mc = list_entry(l, struct mal_commac, poll_list); mc->ops->poll_tx(mc->dev); } - +#endif /* Process RX skbs. * We _might_ need something more smart here to enforce polling fairness. */ @@ -325,7 +328,9 @@ static int mal_poll(struct net_device *n else goto more_work; } +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ mc->ops->poll_tx(mc->dev); +#endif } more_work: @@ -470,9 +475,11 @@ static int __init mal_probe(struct ocp_d err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal); if (err) goto fail3; +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); if (err) goto fail4; +#endif err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); if (err) goto fail5; @@ -495,8 +502,10 @@ static int __init mal_probe(struct ocp_d fail6: free_irq(maldata->rxde_irq, mal); fail5: +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ free_irq(maldata->txeob_irq, mal); fail4: +#endif free_irq(maldata->txde_irq, mal); fail3: free_irq(maldata->serr_irq, mal); @@ -531,7 +540,9 @@ static void __exit mal_remove(struct ocp free_irq(maldata->serr_irq, mal); free_irq(maldata->txde_irq, mal); +#ifndef CONFIG_IBM_EMAC_NO_TX_IRQ free_irq(maldata->txeob_irq, mal); +#endif free_irq(maldata->rxde_irq, mal); free_irq(maldata->rxeob_irq, mal);