diff -ur madwifi.old/ath/if_ath.c madwifi.dev/ath/if_ath.c
--- madwifi.old/ath/if_ath.c	2007-06-01 11:26:04.181689864 +0200
+++ madwifi.dev/ath/if_ath.c	2007-06-01 11:39:53.078678368 +0200
@@ -167,7 +167,7 @@
 	int, u_int32_t);
 static void ath_setdefantenna(struct ath_softc *, u_int);
 static struct ath_txq *ath_txq_setup(struct ath_softc *, int, int);
-static void ath_rx_tasklet(TQUEUE_ARG);
+static int ath_rx_poll(struct net_device *dev, int *budget);
 static int ath_hardstart(struct sk_buff *, struct net_device *);
 static int ath_mgtstart(struct ieee80211com *, struct sk_buff *);
 #ifdef ATH_SUPERG_COMP
@@ -443,7 +443,6 @@
 	ATH_TXBUF_LOCK_INIT(sc);
 	ATH_RXBUF_LOCK_INIT(sc);
 
-	ATH_INIT_TQUEUE(&sc->sc_rxtq,     ath_rx_tasklet,	dev);
 	ATH_INIT_TQUEUE(&sc->sc_txtq,	  ath_tx_tasklet,	dev);
 	ATH_INIT_TQUEUE(&sc->sc_bmisstq,  ath_bmiss_tasklet,	dev);
 	ATH_INIT_TQUEUE(&sc->sc_bstucktq, ath_bstuck_tasklet,	dev);
@@ -700,6 +699,8 @@
 	dev->set_mac_address = ath_set_mac_address;
  	dev->change_mtu = ath_change_mtu;
 	dev->tx_queue_len = ATH_TXBUF - 1;		/* 1 for mgmt frame */
+	dev->poll = ath_rx_poll;
+	dev->weight = 64;
 #ifdef USE_HEADERLEN_RESV
 	dev->hard_header_len += sizeof(struct ieee80211_qosframe) +
 				sizeof(struct llc) +
@@ -1665,6 +1666,7 @@
 	 */
 	ath_hal_getisr(ah, &status);		/* NB: clears ISR too */
 	DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, status);
+	sc->sc_isr = status;
 	status &= sc->sc_imask;			/* discard unasked for bits */
 	if (status & HAL_INT_FATAL) {
 		sc->sc_stats.ast_hardware++;
@@ -1700,7 +1702,12 @@
 		if (status & HAL_INT_RX) {
 			sc->sc_tsf = ath_hal_gettsf64(ah);
 			ath_uapsd_processtriggers(sc);
-			ATH_SCHEDULE_TQUEUE(&sc->sc_rxtq, &needmark);
+			sc->sc_isr &= ~HAL_INT_RX;
+			if (netif_rx_schedule_prep(dev)) {
+				sc->sc_imask &= ~HAL_INT_RX;
+				ath_hal_intrset(ah, sc->sc_imask);
+				__netif_rx_schedule(dev);
+			}
 		}
 		if (status & HAL_INT_TX) {
 #ifdef ATH_SUPERG_DYNTURBO
@@ -1726,6 +1733,11 @@
 				}
 			}
 #endif
+			/* disable transmit interrupt */
+			sc->sc_isr &= ~HAL_INT_TX;
+			ath_hal_intrset(ah, sc->sc_imask & ~HAL_INT_TX);
+			sc->sc_imask &= ~HAL_INT_TX;
+
 			ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, &needmark);
 		}
 		if (status & HAL_INT_BMISS) {
@@ -3296,10 +3308,10 @@
 	 *
 	 * XXX Using in_softirq is not right since we might
 	 * be called from other soft irq contexts than
-	 * ath_rx_tasklet.
+	 * ath_rx_poll
 	 */
 	if (!in_softirq())
-		tasklet_disable(&sc->sc_rxtq);
+		netif_poll_disable(dev);
 	netif_stop_queue(dev);
 }
 
@@ -3312,7 +3324,7 @@
 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
 	netif_start_queue(dev);
 	if (!in_softirq())		/* NB: see above */
-		tasklet_enable(&sc->sc_rxtq);
+		netif_poll_enable(dev);
 }
 
 /*
@@ -5573,13 +5585,12 @@
 	sc->sc_rxotherant = 0;
 }
 
-static void
-ath_rx_tasklet(TQUEUE_ARG data)
+static int
+ath_rx_poll(struct net_device *dev, int *budget)
 {
 #define	PA2DESC(_sc, _pa) \
 	((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
 		((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
-	struct net_device *dev = (struct net_device *)data;
 	struct ath_buf *bf;
 	struct ath_softc *sc = dev->priv;
 	struct ieee80211com *ic = &sc->sc_ic;
@@ -5591,12 +5602,15 @@
 	unsigned int len;
 	int type;
 	u_int phyerr;
+	u_int processed = 0, early_stop = 0;
+	u_int rx_limit = dev->quota;
 
 	/* Let the 802.11 layer know about the new noise floor */
 	sc->sc_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
 	ic->ic_channoise = sc->sc_channoise;
 
 	DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s\n", __func__);
+process_rx_again:
 	do {
 		bf = STAILQ_FIRST(&sc->sc_rxbuf);
 		if (bf == NULL) {		/* XXX ??? can this happen */
@@ -5620,6 +5634,13 @@
 			/* NB: never process the self-linked entry at the end */
 			break;
 		}
+
+		processed++;
+		if (rx_limit-- < 0) {
+			early_stop = 1;
+			break;
+		}
+
 		skb = bf->bf_skb;
 		if (skb == NULL) {		/* XXX ??? can this happen */
 			printk("%s: no skbuff (%s)\n", DEV_NAME(dev), __func__);
@@ -5658,6 +5679,7 @@
 				sc->sc_stats.ast_rx_phyerr++;
 				phyerr = rs->rs_phyerr & 0x1f;
 				sc->sc_stats.ast_rx_phy[phyerr]++;
+				goto rx_next;
 			}
 			if (rs->rs_status & HAL_RXERR_DECRYPT) {
 				/*
@@ -5868,9 +5890,29 @@
 		STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
 		ATH_RXBUF_UNLOCK_IRQ(sc);
 	} while (ath_rxbuf_init(sc, bf) == 0);
+	if (!early_stop) {
+		/* Check if more data is received while we were
+		 * processing the descriptor chain.
+		 */
+		ATH_DISABLE_INTR();
+		if (sc->sc_isr & HAL_INT_RX) {
+			sc->sc_isr &= ~HAL_INT_RX;
+			ATH_ENABLE_INTR();
+			ath_uapsd_processtriggers(sc);
+			goto process_rx_again;
+		}
+		netif_rx_complete(dev);
+
+		sc->sc_imask |= HAL_INT_RX;
+		ath_hal_intrset(ah, sc->sc_imask);
+		ATH_ENABLE_INTR();
+	}
+
+	*budget -= processed;
 
 	/* rx signal state monitoring */
 	ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
+	return early_stop;
 #undef PA2DESC
 }
 
@@ -7487,11 +7529,22 @@
 	struct net_device *dev = (struct net_device *)data;
 	struct ath_softc *sc = dev->priv;
 
+process_tx_again:
 	if (txqactive(sc->sc_ah, 0))
 		ath_tx_processq(sc, &sc->sc_txq[0]);
 	if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
 		ath_tx_processq(sc, sc->sc_cabq);
 
+	ATH_DISABLE_INTR();
+	if (sc->sc_isr & HAL_INT_TX) {
+		sc->sc_isr &= ~HAL_INT_TX;
+		ATH_ENABLE_INTR();
+		goto process_tx_again;
+	}
+	sc->sc_imask |= HAL_INT_TX;
+	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+	ATH_ENABLE_INTR();
+
 	netif_wake_queue(dev);
 
 	if (sc->sc_softled)
@@ -7508,6 +7561,7 @@
 	struct net_device *dev = (struct net_device *)data;
 	struct ath_softc *sc = dev->priv;
 
+process_tx_again:
 	/*
 	 * Process each active queue.
 	 */
@@ -7528,6 +7582,16 @@
 	if (sc->sc_uapsdq && txqactive(sc->sc_ah, sc->sc_uapsdq->axq_qnum))
 		ath_tx_processq(sc, sc->sc_uapsdq);
 
+	ATH_DISABLE_INTR();
+	if (sc->sc_isr & HAL_INT_TX) {
+		sc->sc_isr &= ~HAL_INT_TX;
+		ATH_ENABLE_INTR();
+		goto process_tx_again;
+	}
+	sc->sc_imask |= HAL_INT_TX;
+	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+	ATH_ENABLE_INTR();
+
 	netif_wake_queue(dev);
 
 	if (sc->sc_softled)
@@ -7545,6 +7609,7 @@
 	unsigned int i;
 
 	/* Process each active queue. */
+process_tx_again:
 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
 		if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i))
 			ath_tx_processq(sc, &sc->sc_txq[i]);
@@ -7553,6 +7618,16 @@
 		ath_tx_processq(sc, sc->sc_xrtxq);
 #endif
 
+	ATH_DISABLE_INTR();
+	if (sc->sc_isr & HAL_INT_TX) {
+		sc->sc_isr &= ~HAL_INT_TX;
+		ATH_ENABLE_INTR();
+		goto process_tx_again;
+	}
+	sc->sc_imask |= HAL_INT_TX;
+	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+	ATH_ENABLE_INTR();
+
 	netif_wake_queue(dev);
 
 	if (sc->sc_softled)
@@ -7651,6 +7726,7 @@
 ath_draintxq(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
+	int npend = 0;
 	unsigned int i;
 
 	/* XXX return value */
@@ -9170,9 +9246,9 @@
 	dev->mtu = mtu;
 	if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
 		/* NB: the rx buffers may need to be reallocated */
-		tasklet_disable(&sc->sc_rxtq);
+		netif_poll_disable(dev);
 		error = ath_reset(dev);
-		tasklet_enable(&sc->sc_rxtq);
+		netif_poll_enable(dev);
 	}
 	ATH_UNLOCK(sc);
 
diff -ur madwifi.old/ath/if_athvar.h madwifi.dev/ath/if_athvar.h
--- madwifi.old/ath/if_athvar.h	2007-06-01 11:26:04.158693360 +0200
+++ madwifi.dev/ath/if_athvar.h	2007-06-01 11:33:26.549439744 +0200
@@ -48,6 +48,10 @@
 #include "if_athioctl.h"
 #include "net80211/ieee80211.h"		/* XXX for WME_NUM_AC */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define irqs_disabled()			0
+#endif
+
 /*
  * Deduce if tasklets are available.  If not then
  * fall back to using the immediate work queue.
@@ -621,7 +625,6 @@
 	struct ath_buf *sc_rxbufcur;		/* current rx buffer */
 	u_int32_t *sc_rxlink;			/* link ptr in last RX desc */
 	spinlock_t sc_rxbuflock;
-	struct ATH_TQ_STRUCT sc_rxtq;		/* rx intr tasklet */
 	struct ATH_TQ_STRUCT sc_rxorntq;	/* rxorn intr tasklet */
 	u_int8_t sc_defant;			/* current default antenna */
 	u_int8_t sc_rxotherant;			/* rx's on non-default antenna*/
@@ -634,6 +637,7 @@
 	u_int sc_txintrperiod;			/* tx interrupt batching */
 	struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
 	struct ath_txq *sc_ac2q[WME_NUM_AC];	/* WME AC -> h/w qnum */
+	HAL_INT sc_isr;				/* unmasked ISR state */
 	struct ATH_TQ_STRUCT sc_txtq;		/* tx intr tasklet */
 	u_int8_t sc_grppoll_str[GRPPOLL_RATE_STR_LEN];
 	struct ath_descdma sc_bdma;		/* beacon descriptors */
@@ -714,6 +718,8 @@
 #define	ATH_TXBUF_LOCK_ASSERT(_sc) \
 	KASSERT(spin_is_locked(&(_sc)->sc_txbuflock), ("txbuf not locked!"))
 
+#define ATH_DISABLE_INTR		local_irq_disable
+#define ATH_ENABLE_INTR 		local_irq_enable
 
 #define	ATH_RXBUF_LOCK_INIT(_sc)	spin_lock_init(&(_sc)->sc_rxbuflock)
 #define	ATH_RXBUF_LOCK_DESTROY(_sc)
diff -ur madwifi.old/net80211/ieee80211_input.c madwifi.dev/net80211/ieee80211_input.c
--- madwifi.old/net80211/ieee80211_input.c	2007-06-01 11:26:04.183689560 +0200
+++ madwifi.dev/net80211/ieee80211_input.c	2007-06-01 11:31:46.931583960 +0200
@@ -1144,8 +1144,9 @@
 		if (ni->ni_vlan != 0 && vap->iv_vlgrp != NULL) {
 			/* attach vlan tag */
 			vlan_hwaccel_receive_skb(skb, vap->iv_vlgrp, ni->ni_vlan);
-		} else
-			netif_rx(skb);
+		} else {
+			netif_receive_skb(skb);
+		}
 		dev->last_rx = jiffies;
 	}
 }