Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c266c71a authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath5k: reduce interrupt load caused by rx/tx interrupts



While the rx/tx tasklet is pending, new unnecessary interrupts may arrive.
Decrease the load by temporarily disabling the interrupts until the tasklet
has completed.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5b7916ad
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -872,6 +872,19 @@ enum ath5k_int {
	AR5K_INT_QTRIG	=	0x40000000, /* Non common */
	AR5K_INT_GLOBAL =	0x80000000,

	AR5K_INT_TX_ALL = AR5K_INT_TXOK
		| AR5K_INT_TXDESC
		| AR5K_INT_TXERR
		| AR5K_INT_TXEOL
		| AR5K_INT_TXURN,

	AR5K_INT_RX_ALL = AR5K_INT_RXOK
		| AR5K_INT_RXDESC
		| AR5K_INT_RXERR
		| AR5K_INT_RXNOFRM
		| AR5K_INT_RXEOL
		| AR5K_INT_RXORN,

	AR5K_INT_COMMON  = AR5K_INT_RXOK
		| AR5K_INT_RXDESC
		| AR5K_INT_RXERR
+42 −3
Original line number Diff line number Diff line
@@ -1443,6 +1443,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
	return true;
}

static void
ath5k_set_current_imask(struct ath5k_softc *sc)
{
	enum ath5k_int imask = sc->imask;
	unsigned long flags;

	spin_lock_irqsave(&sc->irqlock, flags);
	if (sc->rx_pending)
		imask &= ~AR5K_INT_RX_ALL;
	if (sc->tx_pending)
		imask &= ~AR5K_INT_TX_ALL;
	ath5k_hw_set_imr(sc->ah, imask);
	spin_unlock_irqrestore(&sc->irqlock, flags);
}

static void
ath5k_tasklet_rx(unsigned long data)
{
@@ -1506,6 +1521,8 @@ ath5k_tasklet_rx(unsigned long data)
	} while (ath5k_rxbuf_setup(sc, bf) == 0);
unlock:
	spin_unlock(&sc->rxbuflock);
	sc->rx_pending = false;
	ath5k_set_current_imask(sc);
}


@@ -1693,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
	for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
		if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
			ath5k_tx_processq(sc, &sc->txqs[i]);

	sc->tx_pending = false;
	ath5k_set_current_imask(sc);
}


@@ -2122,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
	 * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
}

static void
ath5k_schedule_rx(struct ath5k_softc *sc)
{
	sc->rx_pending = true;
	tasklet_schedule(&sc->rxtq);
}

static void
ath5k_schedule_tx(struct ath5k_softc *sc)
{
	sc->tx_pending = true;
	tasklet_schedule(&sc->txtq);
}

irqreturn_t
ath5k_intr(int irq, void *dev_id)
{
@@ -2164,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
				ieee80211_queue_work(sc->hw, &sc->reset_work);
			}
			else
				tasklet_schedule(&sc->rxtq);
				ath5k_schedule_rx(sc);
		} else {
			if (status & AR5K_INT_SWBA) {
				tasklet_hi_schedule(&sc->beacontq);
@@ -2182,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
				ath5k_hw_update_tx_triglevel(ah, true);
			}
			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
				tasklet_schedule(&sc->rxtq);
				ath5k_schedule_rx(sc);
			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
					| AR5K_INT_TXERR | AR5K_INT_TXEOL))
				tasklet_schedule(&sc->txtq);
				ath5k_schedule_tx(sc);
			if (status & AR5K_INT_BMISS) {
				/* TODO */
			}
@@ -2204,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)

	} while (ath5k_hw_is_intr_pending(ah) && --counter > 0);

	if (sc->rx_pending || sc->tx_pending)
		ath5k_set_current_imask(sc);

	if (unlikely(!counter))
		ATH5K_WARN(sc, "too many interrupts, giving up for now\n");

@@ -2575,6 +2612,8 @@ ath5k_init_hw(struct ath5k_softc *sc)

static void stop_tasklets(struct ath5k_softc *sc)
{
	sc->rx_pending = false;
	sc->tx_pending = false;
	tasklet_kill(&sc->rxtq);
	tasklet_kill(&sc->txtq);
	tasklet_kill(&sc->calib);
+4 −0
Original line number Diff line number Diff line
@@ -207,6 +207,10 @@ struct ath5k_softc {

	enum ath5k_int		imask;		/* interrupt mask copy */

	spinlock_t		irqlock;
	bool			rx_pending;	/* rx tasklet pending */
	bool			tx_pending;	/* tx tasklet pending */

	u8			lladdr[ETH_ALEN];
	u8			bssidmask[ETH_ALEN];