drivers/net/wireless/ath/ath9k/link.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/ath/ath9k/link.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/ath/ath9k/link.c
Extension
.c
Size
15160 bytes
Lines
574
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (txq->axq_depth) {
			if (txq->axq_tx_inprogress) {
				ath_txq_unlock(sc, txq);
				goto reset;
			}

			txq->axq_tx_inprogress = true;
		}
		ath_txq_unlock(sc, txq);
	}

	return true;

reset:
	ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
		"tx hung, resetting the chip\n");
	ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
	return false;
}

#define RX_INACTIVE_CHECK_INTERVAL (4 * MSEC_PER_SEC)

static bool ath_hw_rx_inactive_check(struct ath_softc *sc)
{
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	u32 interval, count;

	interval = jiffies_to_msecs(jiffies - sc->rx_active_check_time);
	count = sc->rx_active_count;

	if (interval < RX_INACTIVE_CHECK_INTERVAL)
		return true; /* too soon to check */

	sc->rx_active_count = 0;
	sc->rx_active_check_time = jiffies;

	/* Need at least one interrupt per second, and we should only react if
	 * we are within a factor two of the expected interval
	 */
	if (interval > RX_INACTIVE_CHECK_INTERVAL * 2 ||
	    count >= interval / MSEC_PER_SEC)
		return true;

	ath_dbg(common, RESET,
		"RX inactivity detected. Schedule chip reset\n");
	ath9k_queue_reset(sc, RESET_TYPE_RX_INACTIVE);

	return false;
}

void ath_hw_check_work(struct work_struct *work)
{
	struct ath_softc *sc = container_of(work, struct ath_softc,
					    hw_check_work.work);

	if (!ath_hw_check(sc) || !ath_tx_complete_check(sc) ||
	    !ath_hw_rx_inactive_check(sc))
		return;

	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
}

/*
 * Checks if the BB/MAC is hung.
 */
bool ath_hw_check(struct ath_softc *sc)
{
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	enum ath_reset_type type;
	bool is_alive;

	ath9k_ps_wakeup(sc);

	is_alive = ath9k_hw_check_alive(sc->sc_ah);

	if (!is_alive) {
		ath_dbg(common, RESET,
			"HW hang detected, schedule chip reset\n");
		type = RESET_TYPE_MAC_HANG;
		ath9k_queue_reset(sc, type);
	}

	ath9k_ps_restore(sc);

	return is_alive;
}

/*
 * PLL-WAR for AR9485/AR9340

Annotation

Implementation Notes