summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/athn.c87
1 files changed, 85 insertions, 2 deletions
diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c
index af5296bfd5e..b7a5e3f2081 100644
--- a/sys/dev/ic/athn.c
+++ b/sys/dev/ic/athn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: athn.c,v 1.101 2019/02/01 16:15:07 stsp Exp $ */
+/* $OpenBSD: athn.c,v 1.102 2019/03/01 07:39:56 stsp Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -136,6 +136,14 @@ int athn_newstate(struct ieee80211com *, enum ieee80211_state,
int);
void athn_updateedca(struct ieee80211com *);
int athn_clock_rate(struct athn_softc *);
+int athn_chan_sifs(struct ieee80211_channel *);
+void athn_setsifs(struct athn_softc *);
+int athn_acktimeout(struct ieee80211_channel *, int);
+void athn_setacktimeout(struct athn_softc *,
+ struct ieee80211_channel *, int);
+void athn_setctstimeout(struct athn_softc *,
+ struct ieee80211_channel *, int);
+void athn_setclockrate(struct athn_softc *);
void athn_updateslot(struct ieee80211com *);
void athn_start(struct ifnet *);
void athn_watchdog(struct ifnet *);
@@ -2403,6 +2411,9 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c,
AR_SETBITS(sc, AR_PCU_MISC, AR_PCU_MIC_NEW_LOC_ENA);
+ athn_setsifs(sc);
+ athn_updateslot(ic);
+ athn_setclockrate(sc);
if (AR_SREV_9287_13_OR_LATER(sc) && !AR_SREV_9380_10_OR_LATER(sc))
ar9287_1_3_setup_async_fifo(sc);
@@ -2713,7 +2724,13 @@ athn_clock_rate(struct athn_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
int clockrate; /* MHz. */
- if (ic->ic_bss->ni_chan != IEEE80211_CHAN_ANYC &&
+ /*
+ * AR9287 v1.3+ MAC runs at 117MHz (instead of 88/44MHz) when
+ * ASYNC FIFO is enabled.
+ */
+ if (AR_SREV_9287_13_OR_LATER(sc) && !AR_SREV_9380_10_OR_LATER(sc))
+ clockrate = 117;
+ else if (ic->ic_bss->ni_chan != IEEE80211_CHAN_ANYC &&
IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
if (sc->flags & ATHN_FLAG_FAST_PLL_CLOCK)
clockrate = AR_CLOCK_RATE_FAST_5GHZ_OFDM;
@@ -2729,6 +2746,69 @@ athn_clock_rate(struct athn_softc *sc)
return (clockrate);
}
+int
+athn_chan_sifs(struct ieee80211_channel *c)
+{
+ return IEEE80211_IS_CHAN_2GHZ(c) ? IEEE80211_DUR_DS_SIFS : 16;
+}
+
+void
+athn_setsifs(struct athn_softc *sc)
+{
+ int sifs = athn_chan_sifs(sc->sc_ic.ic_bss->ni_chan);
+ AR_WRITE(sc, AR_D_GBL_IFS_SIFS, (sifs - 2) * athn_clock_rate(sc));
+ AR_WRITE_BARRIER(sc);
+}
+
+int
+athn_acktimeout(struct ieee80211_channel *c, int slot)
+{
+ int sifs = athn_chan_sifs(c);
+ int ackto = sifs + slot;
+
+ /* Workaround for early ACK timeouts. */
+ if (IEEE80211_IS_CHAN_2GHZ(c))
+ ackto += 64 - sifs - slot;
+
+ return ackto;
+}
+
+void
+athn_setacktimeout(struct athn_softc *sc, struct ieee80211_channel *c, int slot)
+{
+ int ackto = athn_acktimeout(c, slot);
+ uint32_t reg = AR_READ(sc, AR_TIME_OUT);
+ reg = RW(reg, AR_TIME_OUT_ACK, ackto * athn_clock_rate(sc));
+ AR_WRITE(sc, AR_TIME_OUT, reg);
+ AR_WRITE_BARRIER(sc);
+}
+
+void
+athn_setctstimeout(struct athn_softc *sc, struct ieee80211_channel *c, int slot)
+{
+ int ctsto = athn_acktimeout(c, slot);
+ int sifs = athn_chan_sifs(c);
+ uint32_t reg = AR_READ(sc, AR_TIME_OUT);
+
+ /* Workaround for early CTS timeouts. */
+ if (IEEE80211_IS_CHAN_2GHZ(c))
+ ctsto += 48 - sifs - slot;
+
+ reg = RW(reg, AR_TIME_OUT_CTS, ctsto * athn_clock_rate(sc));
+ AR_WRITE(sc, AR_TIME_OUT, reg);
+ AR_WRITE_BARRIER(sc);
+}
+
+void
+athn_setclockrate(struct athn_softc *sc)
+{
+ int clockrate = athn_clock_rate(sc);
+ uint32_t reg = AR_READ(sc, AR_USEC);
+ reg = RW(reg, AR_USEC_USEC, clockrate - 1);
+ AR_WRITE(sc, AR_USEC, reg);
+ AR_WRITE_BARRIER(sc);
+}
+
void
athn_updateslot(struct ieee80211com *ic)
{
@@ -2739,6 +2819,9 @@ athn_updateslot(struct ieee80211com *ic)
IEEE80211_DUR_DS_SHSLOT : IEEE80211_DUR_DS_SLOT;
AR_WRITE(sc, AR_D_GBL_IFS_SLOT, slot * athn_clock_rate(sc));
AR_WRITE_BARRIER(sc);
+
+ athn_setacktimeout(sc, ic->ic_bss->ni_chan, slot);
+ athn_setctstimeout(sc, ic->ic_bss->ni_chan, slot);
}
void