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

Commit 4edd761f authored by Bruno Randolf's avatar Bruno Randolf Committed by John W. Linville
Browse files

ath5k: Add watchdog for stuck TX queues



Since we do not know any better solution to the problem that TX queues can get
stuck, this adds a timer-based watchdog, which will check for stuck queues and
reset the hardware if necessary.

Ported from ath9k commit 164ace38.

Signed-off-by: default avatarBruno Randolf <br1@einfach.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 1440401e
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -206,6 +206,8 @@
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI	1000	/* 1 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI	1000	/* 1 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF	60000	/* 60 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF	60000	/* 60 sec */


#define ATH5K_TX_COMPLETE_POLL_INT		3000	/* 3 sec */

#define AR5K_INIT_CARR_SENSE_EN			1
#define AR5K_INIT_CARR_SENSE_EN			1


/*Swap RX/TX Descriptor for big endian archs*/
/*Swap RX/TX Descriptor for big endian archs*/
+51 −0
Original line number Original line Diff line number Diff line
@@ -891,6 +891,7 @@ ath5k_txq_setup(struct ath5k_softc *sc,
		spin_lock_init(&txq->lock);
		spin_lock_init(&txq->lock);
		txq->setup = true;
		txq->setup = true;
		txq->txq_len = 0;
		txq->txq_len = 0;
		txq->txq_poll_mark = false;
	}
	}
	return &sc->txqs[qnum];
	return &sc->txqs[qnum];
}
}
@@ -989,6 +990,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
		spin_unlock_bh(&sc->txbuflock);
		spin_unlock_bh(&sc->txbuflock);
	}
	}
	txq->link = NULL;
	txq->link = NULL;
	txq->txq_poll_mark = false;
	spin_unlock_bh(&txq->lock);
	spin_unlock_bh(&txq->lock);
}
}


@@ -1616,6 +1618,8 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
		sc->txbuf_len++;
		sc->txbuf_len++;
		txq->txq_len--;
		txq->txq_len--;
		spin_unlock(&sc->txbuflock);
		spin_unlock(&sc->txbuflock);

		txq->txq_poll_mark = false;
	}
	}
	if (likely(list_empty(&txq->q)))
	if (likely(list_empty(&txq->q)))
		txq->link = NULL;
		txq->link = NULL;
@@ -2170,6 +2174,46 @@ ath5k_tasklet_ani(unsigned long data)
}
}




static void
ath5k_tx_complete_poll_work(struct work_struct *work)
{
	struct ath5k_softc *sc = container_of(work, struct ath5k_softc,
			tx_complete_work.work);
	struct ath5k_txq *txq;
	int i;
	bool needreset = false;

	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
		if (sc->txqs[i].setup) {
			txq = &sc->txqs[i];
			spin_lock_bh(&txq->lock);
			if (txq->txq_len > 0) {
				if (txq->txq_poll_mark) {
					ATH5K_DBG(sc, ATH5K_DEBUG_XMIT,
						  "TX queue stuck %d\n",
						  txq->qnum);
					needreset = true;
					spin_unlock_bh(&txq->lock);
					break;
				} else {
					txq->txq_poll_mark = true;
				}
			}
			spin_unlock_bh(&txq->lock);
		}
	}

	if (needreset) {
		ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
			  "TX queues stuck, resetting\n");
		ath5k_reset(sc, sc->curchan);
	}

	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
		msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
}


/*************************\
/*************************\
* Initialization routines *
* Initialization routines *
\*************************/
\*************************/
@@ -2261,6 +2305,10 @@ ath5k_init(struct ath5k_softc *sc)
done:
done:
	mmiowb();
	mmiowb();
	mutex_unlock(&sc->lock);
	mutex_unlock(&sc->lock);

	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
			msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));

	return ret;
	return ret;
}
}


@@ -2319,6 +2367,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)


	stop_tasklets(sc);
	stop_tasklets(sc);


	cancel_delayed_work_sync(&sc->tx_complete_work);

	ath5k_rfkill_hw_stop(sc->ah);
	ath5k_rfkill_hw_stop(sc->ah);


	return ret;
	return ret;
@@ -2505,6 +2555,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
	tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
	tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);


	INIT_WORK(&sc->reset_work, ath5k_reset_work);
	INIT_WORK(&sc->reset_work, ath5k_reset_work);
	INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);


	ret = ath5k_eeprom_read_mac(ah, mac);
	ret = ath5k_eeprom_read_mac(ah, mac);
	if (ret) {
	if (ret) {
+3 −0
Original line number Original line Diff line number Diff line
@@ -87,6 +87,7 @@ struct ath5k_txq {
	spinlock_t		lock;	/* lock on q and link */
	spinlock_t		lock;	/* lock on q and link */
	bool			setup;
	bool			setup;
	int			txq_len; /* number of queued buffers */
	int			txq_len; /* number of queued buffers */
	bool			txq_poll_mark;
};
};


#define ATH5K_LED_MAX_NAME_LEN 31
#define ATH5K_LED_MAX_NAME_LEN 31
@@ -233,6 +234,8 @@ struct ath5k_softc {


	struct ath5k_ani_state	ani_state;
	struct ath5k_ani_state	ani_state;
	struct tasklet_struct	ani_tasklet;	/* ANI calibration */
	struct tasklet_struct	ani_tasklet;	/* ANI calibration */

	struct delayed_work	tx_complete_work;
};
};


#define ath5k_hw_hasbssidmask(_ah) \
#define ath5k_hw_hasbssidmask(_ah) \