wlan: apply iwn,bwi,mwl commits from FreeBSD 13
iwn(4): (partially) rewrite A-MPDU Tx path Generic Tx stats fixes: - do not try to parse "aggregation status" for single frames; send them to iwn_tx_done() instead; - try to attach mbuf / node reference pair to reported BA events; allows to fix reported status for ieee80211_tx_complete() and ifnet counters (previously all A-MPDU frames were counted as failed - see PR 210211); requires few more firmware bug workarounds; - preserve short / long retry counters for wlan_amrr(4) (disabled for now - causes significant performance degradation). - Add new IWN_DEBUG_AMPDU debug category. - Add one more check into iwn_tx_data() to prevent aggregation ring overflow. - Workaround 'seqno % 256' != 'current Tx slot' case (until D9195 is not in the tree). - Improve watchdog timer updates (previously watchdog check was omitted when at least one frame was transmitted). - Stop Tx when memory leak in currently used ring was detected (unlikely to happen). - Few other minor fixes. Was previously tested with: - Intel 6205, STA mode (Tx aggregation behaves much better now). - Intel 4965AGN, STA mode (still unstable). PR: 192641, 210211 Reviewed by: adrian, dhw MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D10728 iwn(4): drop return code from iwn_*attach functions (they cannot fail) While here, add missing trace 'end' marker in iwn5000_attach(). MFC after: 1 week iwn(4): drop i_seq field initialization for A-MPDU frames. It is done by net80211 since r319460. MFC after: 24 days X-MFC-With: 343094 iwn(4): plug initialization path vs interrupt handler races There are few places in interrupt handler where the driver lock is dropped; ensure that device is still running before processing remaining ring entries. PR: 192641 MFC after: 5 days iwn: Set default ampdu parameters. These are from the linux iwlwifi driver ;the default use smaller maximum AMPDUs (8k) and a much smaller density (none.) The latter could cause stability issues. Tested: * Tested on Intel 6300, STA mode. Differential Revision: https://reviews.freebsd.org/D25113 bwi: clean up empty lines in .c and .h files mwl: clean up empty lines in .c and .h files Fix ieee80211_radiotap(9) usage in wireless drivers: - Alignment issues: * Add missing __packed attributes + padding across all drivers; in most places there was an assumption that padding will be always minimally suitable; in few places - e.g., in urtw(4) / rtwn(4) - padding was just missing. * Add __aligned(8) attribute for all Rx radiotap headers since they can contain 64-bit TSF timestamp; it cannot appear in Tx radiotap headers, so just drop the attribute here. Refresh ieee80211_radiotap(9) man page accordingly. - Since net80211 automatically updates channel frequency / flags in ieee80211_radiotap_chan_change() drop duplicate setup for these fields in drivers. Tested with Netgear WG111 v3 (urtw(4)), STA mode. MFC after: 2 weeks Change-Id: I7f194a3b78a058aa598634039cfab27e415a4894 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3917 Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Jérôme Duval
parent
ae0a10cad3
commit
0ba2e27fc4
@@ -373,7 +373,7 @@ struct ath_rx_radiotap_header {
|
|||||||
*/
|
*/
|
||||||
struct ath_radiotap_vendor_hdr wr_v;
|
struct ath_radiotap_vendor_hdr wr_v;
|
||||||
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
|
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
|
||||||
} __packed;
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define ATH_TX_RADIOTAP_PRESENT ( \
|
#define ATH_TX_RADIOTAP_PRESENT ( \
|
||||||
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ static void bwi_phy_config_agc(struct bwi_mac *);
|
|||||||
|
|
||||||
static void bwi_tbl_write_2(struct bwi_mac *mac, uint16_t, uint16_t);
|
static void bwi_tbl_write_2(struct bwi_mac *mac, uint16_t, uint16_t);
|
||||||
static void bwi_tbl_write_4(struct bwi_mac *mac, uint16_t, uint32_t);
|
static void bwi_tbl_write_4(struct bwi_mac *mac, uint16_t, uint32_t);
|
||||||
|
|
||||||
#define SUP_BPHY(num) { .rev = num, .init = bwi_phy_init_11b_rev##num }
|
#define SUP_BPHY(num) { .rev = num, .init = bwi_phy_init_11b_rev##num }
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|||||||
@@ -1734,15 +1734,6 @@ bwi_set_channel(struct ieee80211com *ic)
|
|||||||
bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0);
|
bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0);
|
||||||
|
|
||||||
sc->sc_rates = ieee80211_get_ratetable(c);
|
sc->sc_rates = ieee80211_get_ratetable(c);
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup radio tap channel freq and flags
|
|
||||||
*/
|
|
||||||
sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
|
|
||||||
htole16(c->ic_freq);
|
|
||||||
sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
|
|
||||||
htole16(c->ic_flags & 0xffff);
|
|
||||||
|
|
||||||
BWI_UNLOCK(sc);
|
BWI_UNLOCK(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,6 @@ static device_method_t bwi_pci_methods[] = {
|
|||||||
DEVMETHOD(device_shutdown, bwi_pci_shutdown),
|
DEVMETHOD(device_shutdown, bwi_pci_shutdown),
|
||||||
DEVMETHOD(device_suspend, bwi_pci_suspend),
|
DEVMETHOD(device_suspend, bwi_pci_suspend),
|
||||||
DEVMETHOD(device_resume, bwi_pci_resume),
|
DEVMETHOD(device_resume, bwi_pci_resume),
|
||||||
|
|
||||||
{ 0,0 }
|
{ 0,0 }
|
||||||
};
|
};
|
||||||
static driver_t bwi_driver = {
|
static driver_t bwi_driver = {
|
||||||
|
|||||||
@@ -77,7 +77,6 @@
|
|||||||
#define BWI_CONF_LO_REQTO_MASK __BITS(6, 4) /* request timeout */
|
#define BWI_CONF_LO_REQTO_MASK __BITS(6, 4) /* request timeout */
|
||||||
#define BWI_CONF_LO_REQTO 3
|
#define BWI_CONF_LO_REQTO 3
|
||||||
|
|
||||||
|
|
||||||
#define BWI_ID_LO 0xff8
|
#define BWI_ID_LO 0xff8
|
||||||
#define BWI_ID_LO_BUSREV_MASK __BITS(31, 28)
|
#define BWI_ID_LO_BUSREV_MASK __BITS(31, 28)
|
||||||
/* Bus revision */
|
/* Bus revision */
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ struct bwi_tx_radiotap_hdr {
|
|||||||
uint8_t wt_rate;
|
uint8_t wt_rate;
|
||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#define BWI_RX_RADIOTAP_PRESENT \
|
#define BWI_RX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
||||||
@@ -533,7 +533,7 @@ struct bwi_rx_radiotap_hdr {
|
|||||||
int8_t wr_antsignal;
|
int8_t wr_antsignal;
|
||||||
int8_t wr_antnoise;
|
int8_t wr_antnoise;
|
||||||
/* TODO: sq */
|
/* TODO: sq */
|
||||||
};
|
} __packed __aligned(8);
|
||||||
|
|
||||||
struct bwi_vap {
|
struct bwi_vap {
|
||||||
struct ieee80211vap bv_vap;
|
struct ieee80211vap bv_vap;
|
||||||
|
|||||||
@@ -57,11 +57,12 @@ struct ipw_soft_buf {
|
|||||||
struct ipw_rx_radiotap_header {
|
struct ipw_rx_radiotap_header {
|
||||||
struct ieee80211_radiotap_header wr_ihdr;
|
struct ieee80211_radiotap_header wr_ihdr;
|
||||||
uint8_t wr_flags;
|
uint8_t wr_flags;
|
||||||
|
uint8_t wr_pad;
|
||||||
uint16_t wr_chan_freq;
|
uint16_t wr_chan_freq;
|
||||||
uint16_t wr_chan_flags;
|
uint16_t wr_chan_flags;
|
||||||
int8_t wr_antsignal;
|
int8_t wr_antsignal;
|
||||||
int8_t wr_antnoise;
|
int8_t wr_antnoise;
|
||||||
};
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define IPW_RX_RADIOTAP_PRESENT \
|
#define IPW_RX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
@@ -72,9 +73,10 @@ struct ipw_rx_radiotap_header {
|
|||||||
struct ipw_tx_radiotap_header {
|
struct ipw_tx_radiotap_header {
|
||||||
struct ieee80211_radiotap_header wt_ihdr;
|
struct ieee80211_radiotap_header wt_ihdr;
|
||||||
uint8_t wt_flags;
|
uint8_t wt_flags;
|
||||||
|
uint8_t wt_pad;
|
||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#define IPW_TX_RADIOTAP_PRESENT \
|
#define IPW_TX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ struct iwi_rx_radiotap_header {
|
|||||||
int8_t wr_antsignal;
|
int8_t wr_antsignal;
|
||||||
int8_t wr_antnoise;
|
int8_t wr_antnoise;
|
||||||
uint8_t wr_antenna;
|
uint8_t wr_antenna;
|
||||||
};
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define IWI_RX_RADIOTAP_PRESENT \
|
#define IWI_RX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
@@ -51,9 +51,10 @@ struct iwi_rx_radiotap_header {
|
|||||||
struct iwi_tx_radiotap_header {
|
struct iwi_tx_radiotap_header {
|
||||||
struct ieee80211_radiotap_header wt_ihdr;
|
struct ieee80211_radiotap_header wt_ihdr;
|
||||||
uint8_t wt_flags;
|
uint8_t wt_flags;
|
||||||
|
uint8_t wt_pad;
|
||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#define IWI_TX_RADIOTAP_PRESENT \
|
#define IWI_TX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ struct wpi_rx_radiotap_header {
|
|||||||
int8_t wr_dbm_antsignal;
|
int8_t wr_dbm_antsignal;
|
||||||
int8_t wr_dbm_antnoise;
|
int8_t wr_dbm_antnoise;
|
||||||
uint8_t wr_antenna;
|
uint8_t wr_antenna;
|
||||||
} __packed;
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define WPI_RX_RADIOTAP_PRESENT \
|
#define WPI_RX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ static const struct iwn_ident iwn_ident_table[] = {
|
|||||||
|
|
||||||
static int iwn_probe(device_t);
|
static int iwn_probe(device_t);
|
||||||
static int iwn_attach(device_t);
|
static int iwn_attach(device_t);
|
||||||
static int iwn4965_attach(struct iwn_softc *, uint16_t);
|
static void iwn4965_attach(struct iwn_softc *, uint16_t);
|
||||||
static int iwn5000_attach(struct iwn_softc *, uint16_t);
|
static void iwn5000_attach(struct iwn_softc *, uint16_t);
|
||||||
static int iwn_config_specific(struct iwn_softc *, uint16_t);
|
static int iwn_config_specific(struct iwn_softc *, uint16_t);
|
||||||
static void iwn_radiotap_attach(struct iwn_softc *);
|
static void iwn_radiotap_attach(struct iwn_softc *);
|
||||||
static void iwn_sysctlattach(struct iwn_softc *);
|
static void iwn_sysctlattach(struct iwn_softc *);
|
||||||
@@ -165,6 +165,7 @@ static int iwn_alloc_tx_ring(struct iwn_softc *, struct iwn_tx_ring *,
|
|||||||
int);
|
int);
|
||||||
static void iwn_reset_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
|
static void iwn_reset_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
|
||||||
static void iwn_free_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
|
static void iwn_free_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
|
||||||
|
static void iwn_check_tx_ring(struct iwn_softc *, int);
|
||||||
static void iwn5000_ict_reset(struct iwn_softc *);
|
static void iwn5000_ict_reset(struct iwn_softc *);
|
||||||
static int iwn_read_eeprom(struct iwn_softc *,
|
static int iwn_read_eeprom(struct iwn_softc *,
|
||||||
uint8_t macaddr[IEEE80211_ADDR_LEN]);
|
uint8_t macaddr[IEEE80211_ADDR_LEN]);
|
||||||
@@ -195,6 +196,8 @@ static void iwn_calib_timeout(void *);
|
|||||||
static void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *);
|
static void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *);
|
||||||
static void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
|
static void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
|
||||||
struct iwn_rx_data *);
|
struct iwn_rx_data *);
|
||||||
|
static void iwn_agg_tx_complete(struct iwn_softc *, struct iwn_tx_ring *,
|
||||||
|
int, int, int);
|
||||||
static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *);
|
static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *);
|
||||||
static void iwn5000_rx_calib_results(struct iwn_softc *,
|
static void iwn5000_rx_calib_results(struct iwn_softc *,
|
||||||
struct iwn_rx_desc *);
|
struct iwn_rx_desc *);
|
||||||
@@ -203,10 +206,13 @@ static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
|
|||||||
struct iwn_rx_data *);
|
struct iwn_rx_data *);
|
||||||
static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
|
static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
|
||||||
struct iwn_rx_data *);
|
struct iwn_rx_data *);
|
||||||
|
static void iwn_adj_ampdu_ptr(struct iwn_softc *, struct iwn_tx_ring *);
|
||||||
static void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, int,
|
static void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, int,
|
||||||
uint8_t);
|
uint8_t);
|
||||||
static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, int,
|
static int iwn_ampdu_check_bitmap(uint64_t, int, int);
|
||||||
void *);
|
static int iwn_ampdu_index_check(struct iwn_softc *, struct iwn_tx_ring *,
|
||||||
|
uint64_t, int, int);
|
||||||
|
static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, void *);
|
||||||
static void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
|
static void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
|
||||||
static void iwn_notif_intr(struct iwn_softc *);
|
static void iwn_notif_intr(struct iwn_softc *);
|
||||||
static void iwn_wakeup_intr(struct iwn_softc *);
|
static void iwn_wakeup_intr(struct iwn_softc *);
|
||||||
@@ -487,14 +493,9 @@ iwn_attach(device_t dev)
|
|||||||
* Let's set those up first.
|
* Let's set those up first.
|
||||||
*/
|
*/
|
||||||
if (sc->hw_type == IWN_HW_REV_TYPE_4965)
|
if (sc->hw_type == IWN_HW_REV_TYPE_4965)
|
||||||
error = iwn4965_attach(sc, pci_get_device(dev));
|
iwn4965_attach(sc, pci_get_device(dev));
|
||||||
else
|
else
|
||||||
error = iwn5000_attach(sc, pci_get_device(dev));
|
iwn5000_attach(sc, pci_get_device(dev));
|
||||||
if (error != 0) {
|
|
||||||
device_printf(dev, "could not attach device, error %d\n",
|
|
||||||
error);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next, let's setup the various parameters of each NIC.
|
* Next, let's setup the various parameters of each NIC.
|
||||||
@@ -1220,12 +1221,13 @@ iwn_config_specific(struct iwn_softc *sc, uint16_t pid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
|
iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
|
||||||
{
|
{
|
||||||
struct iwn_ops *ops = &sc->ops;
|
struct iwn_ops *ops = &sc->ops;
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
||||||
|
|
||||||
ops->load_firmware = iwn4965_load_firmware;
|
ops->load_firmware = iwn4965_load_firmware;
|
||||||
ops->read_eeprom = iwn4965_read_eeprom;
|
ops->read_eeprom = iwn4965_read_eeprom;
|
||||||
ops->post_alive = iwn4965_post_alive;
|
ops->post_alive = iwn4965_post_alive;
|
||||||
@@ -1260,11 +1262,9 @@ iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
|
|||||||
sc->sc_flags |= IWN_FLAG_BTCOEX;
|
sc->sc_flags |= IWN_FLAG_BTCOEX;
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
iwn5000_attach(struct iwn_softc *sc, uint16_t pid)
|
iwn5000_attach(struct iwn_softc *sc, uint16_t pid)
|
||||||
{
|
{
|
||||||
struct iwn_ops *ops = &sc->ops;
|
struct iwn_ops *ops = &sc->ops;
|
||||||
@@ -1299,7 +1299,7 @@ iwn5000_attach(struct iwn_softc *sc, uint16_t pid)
|
|||||||
sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN;
|
sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN;
|
||||||
sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN;
|
sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN;
|
||||||
|
|
||||||
return 0;
|
DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1353,6 +1353,8 @@ iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
|
|||||||
ivp->iv_newstate = vap->iv_newstate;
|
ivp->iv_newstate = vap->iv_newstate;
|
||||||
vap->iv_newstate = iwn_newstate;
|
vap->iv_newstate = iwn_newstate;
|
||||||
sc->ivap[IWN_RXON_BSS_CTX] = vap;
|
sc->ivap[IWN_RXON_BSS_CTX] = vap;
|
||||||
|
vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
|
||||||
|
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_4; /* 4uS */
|
||||||
|
|
||||||
ieee80211_ratectl_init(vap);
|
ieee80211_ratectl_init(vap);
|
||||||
/* Complete setup. */
|
/* Complete setup. */
|
||||||
@@ -2079,6 +2081,8 @@ iwn_reset_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring)
|
|||||||
ieee80211_free_node(data->ni);
|
ieee80211_free_node(data->ni);
|
||||||
data->ni = NULL;
|
data->ni = NULL;
|
||||||
}
|
}
|
||||||
|
data->remapped = 0;
|
||||||
|
data->long_retries = 0;
|
||||||
}
|
}
|
||||||
/* Clear TX descriptors. */
|
/* Clear TX descriptors. */
|
||||||
memset(ring->desc, 0, ring->desc_dma.size);
|
memset(ring->desc, 0, ring->desc_dma.size);
|
||||||
@@ -2117,6 +2121,42 @@ iwn_free_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iwn_check_tx_ring(struct iwn_softc *sc, int qid)
|
||||||
|
{
|
||||||
|
struct iwn_tx_ring *ring = &sc->txq[qid];
|
||||||
|
|
||||||
|
KASSERT(ring->queued >= 0, ("%s: ring->queued (%d) for queue %d < 0!",
|
||||||
|
__func__, ring->queued, qid));
|
||||||
|
|
||||||
|
if (qid >= sc->firstaggqueue) {
|
||||||
|
struct iwn_ops *ops = &sc->ops;
|
||||||
|
struct ieee80211_tx_ampdu *tap = sc->qid2tap[qid];
|
||||||
|
|
||||||
|
if (ring->queued == 0 && !IEEE80211_AMPDU_RUNNING(tap)) {
|
||||||
|
uint16_t ssn = tap->txa_start & 0xfff;
|
||||||
|
uint8_t tid = tap->txa_tid;
|
||||||
|
int *res = tap->txa_private;
|
||||||
|
|
||||||
|
iwn_nic_lock(sc);
|
||||||
|
ops->ampdu_tx_stop(sc, qid, tid, ssn);
|
||||||
|
iwn_nic_unlock(sc);
|
||||||
|
|
||||||
|
sc->qid2tap[qid] = NULL;
|
||||||
|
free(res, M_DEVBUF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ring->queued < IWN_TX_RING_LOMARK) {
|
||||||
|
sc->qfullmsk &= ~(1 << qid);
|
||||||
|
|
||||||
|
if (ring->queued == 0)
|
||||||
|
sc->sc_tx_timer = 0;
|
||||||
|
else
|
||||||
|
sc->sc_tx_timer = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iwn5000_ict_reset(struct iwn_softc *sc)
|
iwn5000_ict_reset(struct iwn_softc *sc)
|
||||||
{
|
{
|
||||||
@@ -3163,104 +3203,129 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iwn_agg_tx_complete(struct iwn_softc *sc, struct iwn_tx_ring *ring, int tid,
|
||||||
|
int idx, int success)
|
||||||
|
{
|
||||||
|
struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
|
||||||
|
struct iwn_tx_data *data = &ring->data[idx];
|
||||||
|
struct iwn_node *wn;
|
||||||
|
struct mbuf *m;
|
||||||
|
struct ieee80211_node *ni;
|
||||||
|
|
||||||
|
KASSERT(data->ni != NULL, ("idx %d: no node", idx));
|
||||||
|
KASSERT(data->m != NULL, ("idx %d: no mbuf", idx));
|
||||||
|
|
||||||
|
/* Unmap and free mbuf. */
|
||||||
|
bus_dmamap_sync(ring->data_dmat, data->map,
|
||||||
|
BUS_DMASYNC_POSTWRITE);
|
||||||
|
bus_dmamap_unload(ring->data_dmat, data->map);
|
||||||
|
m = data->m, data->m = NULL;
|
||||||
|
ni = data->ni, data->ni = NULL;
|
||||||
|
wn = (void *)ni;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* XXX causes significant performance degradation. */
|
||||||
|
txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
|
||||||
|
IEEE80211_RATECTL_STATUS_LONG_RETRY;
|
||||||
|
txs->long_retries = data->long_retries - 1;
|
||||||
|
#else
|
||||||
|
txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY;
|
||||||
|
#endif
|
||||||
|
txs->short_retries = wn->agg[tid].short_retries;
|
||||||
|
if (success)
|
||||||
|
txs->status = IEEE80211_RATECTL_TX_SUCCESS;
|
||||||
|
else
|
||||||
|
txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
|
||||||
|
|
||||||
|
wn->agg[tid].short_retries = 0;
|
||||||
|
data->long_retries = 0;
|
||||||
|
|
||||||
|
DPRINTF(sc, IWN_DEBUG_AMPDU, "%s: freeing m %p ni %p idx %d qid %d\n",
|
||||||
|
__func__, m, ni, idx, ring->qid);
|
||||||
|
ieee80211_ratectl_tx_complete(ni, txs);
|
||||||
|
ieee80211_tx_complete(ni, m, !success);
|
||||||
|
}
|
||||||
|
|
||||||
/* Process an incoming Compressed BlockAck. */
|
/* Process an incoming Compressed BlockAck. */
|
||||||
static void
|
static void
|
||||||
iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc)
|
iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc)
|
||||||
{
|
{
|
||||||
struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
|
struct iwn_tx_ring *ring;
|
||||||
struct iwn_ops *ops = &sc->ops;
|
struct iwn_tx_data *data;
|
||||||
struct iwn_node *wn;
|
struct iwn_node *wn;
|
||||||
struct ieee80211_node *ni;
|
|
||||||
struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1);
|
struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1);
|
||||||
struct iwn_tx_ring *txq;
|
|
||||||
struct iwn_tx_data *txdata;
|
|
||||||
struct ieee80211_tx_ampdu *tap;
|
struct ieee80211_tx_ampdu *tap;
|
||||||
struct mbuf *m;
|
|
||||||
uint64_t bitmap;
|
uint64_t bitmap;
|
||||||
uint16_t ssn;
|
|
||||||
uint8_t tid;
|
uint8_t tid;
|
||||||
int i, lastidx, qid, *res, shift;
|
int i, qid, shift;
|
||||||
int tx_ok = 0, tx_err = 0;
|
int tx_ok = 0;
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
||||||
|
|
||||||
qid = le16toh(ba->qid);
|
qid = le16toh(ba->qid);
|
||||||
txq = &sc->txq[ba->qid];
|
tap = sc->qid2tap[qid];
|
||||||
tap = sc->qid2tap[ba->qid];
|
ring = &sc->txq[qid];
|
||||||
tid = tap->txa_tid;
|
tid = tap->txa_tid;
|
||||||
wn = (void *)tap->txa_ni;
|
wn = (void *)tap->txa_ni;
|
||||||
|
|
||||||
res = NULL;
|
DPRINTF(sc, IWN_DEBUG_AMPDU, "%s: qid %d tid %d seq %04X ssn %04X\n"
|
||||||
ssn = 0;
|
"bitmap: ba %016jX wn %016jX, start %d\n",
|
||||||
if (!IEEE80211_AMPDU_RUNNING(tap)) {
|
__func__, qid, tid, le16toh(ba->seq), le16toh(ba->ssn),
|
||||||
res = tap->txa_private;
|
(uintmax_t)le64toh(ba->bitmap), (uintmax_t)wn->agg[tid].bitmap,
|
||||||
ssn = tap->txa_start & 0xfff;
|
wn->agg[tid].startidx);
|
||||||
}
|
|
||||||
|
|
||||||
for (lastidx = le16toh(ba->ssn) & 0xff; txq->read != lastidx;) {
|
|
||||||
txdata = &txq->data[txq->read];
|
|
||||||
|
|
||||||
/* Unmap and free mbuf. */
|
|
||||||
bus_dmamap_sync(txq->data_dmat, txdata->map,
|
|
||||||
BUS_DMASYNC_POSTWRITE);
|
|
||||||
bus_dmamap_unload(txq->data_dmat, txdata->map);
|
|
||||||
m = txdata->m, txdata->m = NULL;
|
|
||||||
ni = txdata->ni, txdata->ni = NULL;
|
|
||||||
|
|
||||||
KASSERT(ni != NULL, ("no node"));
|
|
||||||
KASSERT(m != NULL, ("no mbuf"));
|
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m);
|
|
||||||
ieee80211_tx_complete(ni, m, 1);
|
|
||||||
|
|
||||||
txq->queued--;
|
|
||||||
txq->read = (txq->read + 1) % IWN_TX_RING_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txq->queued == 0 && res != NULL) {
|
|
||||||
iwn_nic_lock(sc);
|
|
||||||
ops->ampdu_tx_stop(sc, qid, tid, ssn);
|
|
||||||
iwn_nic_unlock(sc);
|
|
||||||
sc->qid2tap[qid] = NULL;
|
|
||||||
free(res, M_DEVBUF);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wn->agg[tid].bitmap == 0)
|
if (wn->agg[tid].bitmap == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
shift = wn->agg[tid].startidx - ((le16toh(ba->seq) >> 4) & 0xff);
|
shift = wn->agg[tid].startidx - ((le16toh(ba->seq) >> 4) & 0xff);
|
||||||
if (shift < 0)
|
if (shift <= -64)
|
||||||
shift += 0x100;
|
shift += 0x100;
|
||||||
|
|
||||||
if (wn->agg[tid].nframes > (64 - shift))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk the bitmap and calculate how many successful and failed
|
* Walk the bitmap and calculate how many successful attempts
|
||||||
* attempts are made.
|
* are made.
|
||||||
*
|
*
|
||||||
* Yes, the rate control code doesn't know these are A-MPDU
|
* Yes, the rate control code doesn't know these are A-MPDU
|
||||||
* subframes and that it's okay to fail some of these.
|
* subframes; due to that long_retries stats are not used here.
|
||||||
*/
|
*/
|
||||||
ni = tap->txa_ni;
|
bitmap = le64toh(ba->bitmap);
|
||||||
bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap;
|
if (shift >= 0)
|
||||||
for (i = 0; bitmap; i++) {
|
bitmap >>= shift;
|
||||||
txs->flags = 0; /* XXX TODO */
|
else
|
||||||
if ((bitmap & 1) == 0) {
|
bitmap <<= -shift;
|
||||||
tx_err ++;
|
bitmap &= wn->agg[tid].bitmap;
|
||||||
txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
|
wn->agg[tid].bitmap = 0;
|
||||||
} else {
|
|
||||||
tx_ok ++;
|
for (i = wn->agg[tid].startidx;
|
||||||
txs->status = IEEE80211_RATECTL_TX_SUCCESS;
|
bitmap;
|
||||||
}
|
bitmap >>= 1, i = (i + 1) % IWN_TX_RING_COUNT) {
|
||||||
ieee80211_ratectl_tx_complete(ni, txs);
|
if ((bitmap & 1) == 0)
|
||||||
bitmap >>= 1;
|
continue;
|
||||||
|
|
||||||
|
data = &ring->data[i];
|
||||||
|
if (__predict_false(data->m == NULL)) {
|
||||||
|
/*
|
||||||
|
* There is no frame; skip this entry.
|
||||||
|
*
|
||||||
|
* NB: it is "ok" to have both
|
||||||
|
* 'tx done' + 'compressed BA' replies for frame
|
||||||
|
* with STATE_SCD_QUERY status.
|
||||||
|
*/
|
||||||
|
DPRINTF(sc, IWN_DEBUG_AMPDU,
|
||||||
|
"%s: ring %d: no entry %d\n", __func__, qid, i);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT,
|
tx_ok++;
|
||||||
"->%s: end; %d ok; %d err\n",__func__, tx_ok, tx_err);
|
iwn_agg_tx_complete(sc, ring, tid, i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ring->queued -= tx_ok;
|
||||||
|
iwn_check_tx_ring(sc, qid);
|
||||||
|
|
||||||
|
DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_AMPDU,
|
||||||
|
"->%s: end; %d ok\n",__func__, tx_ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3508,9 +3573,9 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
|
|||||||
stat->rate, le16toh(stat->duration),
|
stat->rate, le16toh(stat->duration),
|
||||||
le32toh(stat->status));
|
le32toh(stat->status));
|
||||||
|
|
||||||
if (qid >= sc->firstaggqueue) {
|
if (qid >= sc->firstaggqueue && stat->nframes != 1) {
|
||||||
iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
|
iwn_ampdu_tx_done(sc, qid, stat->nframes, stat->rtsfailcnt,
|
||||||
stat->rtsfailcnt, stat->ackfailcnt, &stat->status);
|
&stat->status);
|
||||||
} else {
|
} else {
|
||||||
iwn_tx_done(sc, desc, stat->rtsfailcnt, stat->ackfailcnt,
|
iwn_tx_done(sc, desc, stat->rtsfailcnt, stat->ackfailcnt,
|
||||||
le32toh(stat->status) & 0xff);
|
le32toh(stat->status) & 0xff);
|
||||||
@@ -3538,15 +3603,32 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
|
|||||||
iwn5000_reset_sched(sc, qid, desc->idx);
|
iwn5000_reset_sched(sc, qid, desc->idx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (qid >= sc->firstaggqueue) {
|
if (qid >= sc->firstaggqueue && stat->nframes != 1) {
|
||||||
iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
|
iwn_ampdu_tx_done(sc, qid, stat->nframes, stat->rtsfailcnt,
|
||||||
stat->rtsfailcnt, stat->ackfailcnt, &stat->status);
|
&stat->status);
|
||||||
} else {
|
} else {
|
||||||
iwn_tx_done(sc, desc, stat->rtsfailcnt, stat->ackfailcnt,
|
iwn_tx_done(sc, desc, stat->rtsfailcnt, stat->ackfailcnt,
|
||||||
le16toh(stat->status) & 0xff);
|
le16toh(stat->status) & 0xff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iwn_adj_ampdu_ptr(struct iwn_softc *sc, struct iwn_tx_ring *ring)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = ring->read; i != ring->cur; i = (i + 1) % IWN_TX_RING_COUNT) {
|
||||||
|
struct iwn_tx_data *data = &ring->data[i];
|
||||||
|
|
||||||
|
if (data->m != NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
data->remapped = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring->read = i;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adapter-independent backend for TX_DONE firmware notifications.
|
* Adapter-independent backend for TX_DONE firmware notifications.
|
||||||
*/
|
*/
|
||||||
@@ -3560,7 +3642,18 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int rtsfailcnt,
|
|||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
struct ieee80211_node *ni;
|
struct ieee80211_node *ni;
|
||||||
|
|
||||||
|
if (__predict_false(data->m == NULL &&
|
||||||
|
ring->qid >= sc->firstaggqueue)) {
|
||||||
|
/*
|
||||||
|
* There is no frame; skip this entry.
|
||||||
|
*/
|
||||||
|
DPRINTF(sc, IWN_DEBUG_AMPDU, "%s: ring %d: no entry %d\n",
|
||||||
|
__func__, ring->qid, desc->idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
KASSERT(data->ni != NULL, ("no node"));
|
KASSERT(data->ni != NULL, ("no node"));
|
||||||
|
KASSERT(data->m != NULL, ("no mbuf"));
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
||||||
|
|
||||||
@@ -3570,6 +3663,19 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int rtsfailcnt,
|
|||||||
m = data->m, data->m = NULL;
|
m = data->m, data->m = NULL;
|
||||||
ni = data->ni, data->ni = NULL;
|
ni = data->ni, data->ni = NULL;
|
||||||
|
|
||||||
|
data->long_retries = 0;
|
||||||
|
|
||||||
|
if (ring->qid >= sc->firstaggqueue)
|
||||||
|
iwn_adj_ampdu_ptr(sc, ring);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX f/w may hang (device timeout) when desc->idx - ring->read == 64
|
||||||
|
* (aggregation queues only).
|
||||||
|
*/
|
||||||
|
|
||||||
|
ring->queued--;
|
||||||
|
iwn_check_tx_ring(sc, ring->qid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update rate control statistics for the node.
|
* Update rate control statistics for the node.
|
||||||
*/
|
*/
|
||||||
@@ -3618,10 +3724,6 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int rtsfailcnt,
|
|||||||
ieee80211_tx_complete(ni, m,
|
ieee80211_tx_complete(ni, m,
|
||||||
(status & IWN_TX_FAIL) != 0);
|
(status & IWN_TX_FAIL) != 0);
|
||||||
|
|
||||||
sc->sc_tx_timer = 0;
|
|
||||||
if (--ring->queued < IWN_TX_RING_LOMARK)
|
|
||||||
sc->qfullmsk &= ~(1 << ring->qid);
|
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3658,148 +3760,218 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
|
|||||||
wakeup(&ring->desc[desc->idx]);
|
wakeup(&ring->desc[desc->idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
|
iwn_ampdu_check_bitmap(uint64_t bitmap, int start, int idx)
|
||||||
int rtsfailcnt, int ackfailcnt, void *stat)
|
|
||||||
{
|
{
|
||||||
struct iwn_ops *ops = &sc->ops;
|
int bit, shift;
|
||||||
struct iwn_tx_ring *ring = &sc->txq[qid];
|
|
||||||
struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
|
|
||||||
struct iwn_tx_data *data;
|
|
||||||
struct mbuf *m;
|
|
||||||
struct iwn_node *wn;
|
|
||||||
struct ieee80211_node *ni;
|
|
||||||
struct ieee80211_tx_ampdu *tap;
|
|
||||||
uint64_t bitmap;
|
|
||||||
uint32_t *status = stat;
|
|
||||||
uint16_t *aggstatus = stat;
|
|
||||||
uint16_t ssn;
|
|
||||||
uint8_t tid;
|
|
||||||
int bit, i, lastidx, *res, seqno, shift, start;
|
|
||||||
|
|
||||||
/* XXX TODO: status is le16 field! Grr */
|
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
|
||||||
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: nframes=%d, status=0x%08x\n",
|
|
||||||
__func__,
|
|
||||||
nframes,
|
|
||||||
*status);
|
|
||||||
|
|
||||||
tap = sc->qid2tap[qid];
|
|
||||||
tid = tap->txa_tid;
|
|
||||||
wn = (void *)tap->txa_ni;
|
|
||||||
ni = tap->txa_ni;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX TODO: ACK and RTS failures would be nice here!
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A-MPDU single frame status - if we failed to transmit it
|
|
||||||
* in A-MPDU, then it may be a permanent failure.
|
|
||||||
*
|
|
||||||
* XXX TODO: check what the Linux iwlwifi driver does here;
|
|
||||||
* there's some permanent and temporary failures that may be
|
|
||||||
* handled differently.
|
|
||||||
*/
|
|
||||||
if (nframes == 1) {
|
|
||||||
txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
|
|
||||||
IEEE80211_RATECTL_STATUS_LONG_RETRY;
|
|
||||||
txs->short_retries = rtsfailcnt;
|
|
||||||
txs->long_retries = ackfailcnt;
|
|
||||||
if ((*status & 0xff) != 1 && (*status & 0xff) != 2) {
|
|
||||||
#ifdef NOT_YET
|
|
||||||
printf("ieee80211_send_bar()\n");
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* If we completely fail a transmit, make sure a
|
|
||||||
* notification is pushed up to the rate control
|
|
||||||
* layer.
|
|
||||||
*/
|
|
||||||
/* XXX */
|
|
||||||
txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* If nframes=1, then we won't be getting a BA for
|
|
||||||
* this frame. Ensure that we correctly update the
|
|
||||||
* rate control code with how many retries were
|
|
||||||
* needed to send it.
|
|
||||||
*/
|
|
||||||
txs->status = IEEE80211_RATECTL_TX_SUCCESS;
|
|
||||||
}
|
|
||||||
ieee80211_ratectl_tx_complete(ni, txs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap = 0;
|
|
||||||
start = idx;
|
|
||||||
for (i = 0; i < nframes; i++) {
|
|
||||||
if (le16toh(aggstatus[i * 2]) & 0xc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
idx = le16toh(aggstatus[2*i + 1]) & 0xff;
|
|
||||||
bit = idx - start;
|
bit = idx - start;
|
||||||
shift = 0;
|
shift = 0;
|
||||||
if (bit >= 64) {
|
if (bit >= 64) {
|
||||||
shift = 0x100 - idx + start;
|
shift = 0x100 - bit;
|
||||||
bit = 0;
|
bit = 0;
|
||||||
start = idx;
|
|
||||||
} else if (bit <= -64)
|
} else if (bit <= -64)
|
||||||
bit = 0x100 - start + idx;
|
bit = 0x100 + bit;
|
||||||
else if (bit < 0) {
|
else if (bit < 0) {
|
||||||
shift = start - idx;
|
shift = -bit;
|
||||||
start = idx;
|
bit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit - shift >= 64)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
return ((bitmap & (1ULL << (bit - shift))) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Firmware bug workaround: in case if 'retries' counter
|
||||||
|
* overflows 'seqno' field will be incremented:
|
||||||
|
* status|sequence|status|sequence|status|sequence
|
||||||
|
* 0000 0A48 0001 0A49 0000 0A6A
|
||||||
|
* 1000 0A48 1000 0A49 1000 0A6A
|
||||||
|
* 2000 0A48 2000 0A49 2000 0A6A
|
||||||
|
* ...
|
||||||
|
* E000 0A48 E000 0A49 E000 0A6A
|
||||||
|
* F000 0A48 F000 0A49 F000 0A6A
|
||||||
|
* 0000 0A49 0000 0A49 0000 0A6B
|
||||||
|
* 1000 0A49 1000 0A49 1000 0A6B
|
||||||
|
* ...
|
||||||
|
* D000 0A49 D000 0A49 D000 0A6B
|
||||||
|
* E000 0A49 E001 0A49 E000 0A6B
|
||||||
|
* F000 0A49 F001 0A49 F000 0A6B
|
||||||
|
* 0000 0A4A 0000 0A4B 0000 0A6A
|
||||||
|
* 1000 0A4A 1000 0A4B 1000 0A6A
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* Odd 'seqno' numbers are incremened by 2 every 2 overflows.
|
||||||
|
* For even 'seqno' % 4 != 0 overflow is cyclic (0 -> +1 -> 0).
|
||||||
|
* Not checked with nretries >= 64.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
iwn_ampdu_index_check(struct iwn_softc *sc, struct iwn_tx_ring *ring,
|
||||||
|
uint64_t bitmap, int start, int idx)
|
||||||
|
{
|
||||||
|
struct ieee80211com *ic = &sc->sc_ic;
|
||||||
|
struct iwn_tx_data *data;
|
||||||
|
int diff, min_retries, max_retries, new_idx, loop_end;
|
||||||
|
|
||||||
|
new_idx = idx - IWN_LONG_RETRY_LIMIT_LOG;
|
||||||
|
if (new_idx < 0)
|
||||||
|
new_idx += IWN_TX_RING_COUNT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Corner case: check if retry count is not too big;
|
||||||
|
* reset device otherwise.
|
||||||
|
*/
|
||||||
|
if (!iwn_ampdu_check_bitmap(bitmap, start, new_idx)) {
|
||||||
|
data = &ring->data[new_idx];
|
||||||
|
if (data->long_retries > IWN_LONG_RETRY_LIMIT) {
|
||||||
|
device_printf(sc->sc_dev,
|
||||||
|
"%s: retry count (%d) for idx %d/%d overflow, "
|
||||||
|
"resetting...\n", __func__, data->long_retries,
|
||||||
|
ring->qid, new_idx);
|
||||||
|
ieee80211_restart_all(ic);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Correct index if needed. */
|
||||||
|
loop_end = idx;
|
||||||
|
do {
|
||||||
|
data = &ring->data[new_idx];
|
||||||
|
diff = idx - new_idx;
|
||||||
|
if (diff < 0)
|
||||||
|
diff += IWN_TX_RING_COUNT;
|
||||||
|
|
||||||
|
min_retries = IWN_LONG_RETRY_FW_OVERFLOW * diff;
|
||||||
|
if ((new_idx % 2) == 0)
|
||||||
|
max_retries = IWN_LONG_RETRY_FW_OVERFLOW * (diff + 1);
|
||||||
|
else
|
||||||
|
max_retries = IWN_LONG_RETRY_FW_OVERFLOW * (diff + 2);
|
||||||
|
|
||||||
|
if (!iwn_ampdu_check_bitmap(bitmap, start, new_idx) &&
|
||||||
|
((data->long_retries >= min_retries &&
|
||||||
|
data->long_retries < max_retries) ||
|
||||||
|
(diff == 1 &&
|
||||||
|
(new_idx & 0x03) == 0x02 &&
|
||||||
|
data->long_retries >= IWN_LONG_RETRY_FW_OVERFLOW))) {
|
||||||
|
DPRINTF(sc, IWN_DEBUG_AMPDU,
|
||||||
|
"%s: correcting index %d -> %d in queue %d"
|
||||||
|
" (retries %d)\n", __func__, idx, new_idx,
|
||||||
|
ring->qid, data->long_retries);
|
||||||
|
return (new_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_idx = (new_idx + 1) % IWN_TX_RING_COUNT;
|
||||||
|
} while (new_idx != loop_end);
|
||||||
|
|
||||||
|
return (idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int nframes, int rtsfailcnt,
|
||||||
|
void *stat)
|
||||||
|
{
|
||||||
|
struct iwn_tx_ring *ring = &sc->txq[qid];
|
||||||
|
struct ieee80211_tx_ampdu *tap = sc->qid2tap[qid];
|
||||||
|
struct iwn_node *wn = (void *)tap->txa_ni;
|
||||||
|
struct iwn_tx_data *data;
|
||||||
|
uint64_t bitmap = 0;
|
||||||
|
uint16_t *aggstatus = stat;
|
||||||
|
uint8_t tid = tap->txa_tid;
|
||||||
|
int bit, i, idx, shift, start, tx_err;
|
||||||
|
|
||||||
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
|
||||||
|
|
||||||
|
start = le16toh(*(aggstatus + nframes * 2)) & 0xff;
|
||||||
|
|
||||||
|
for (i = 0; i < nframes; i++) {
|
||||||
|
uint16_t status = le16toh(aggstatus[i * 2]);
|
||||||
|
|
||||||
|
if (status & IWN_AGG_TX_STATE_IGNORE_MASK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
idx = le16toh(aggstatus[i * 2 + 1]) & 0xff;
|
||||||
|
data = &ring->data[idx];
|
||||||
|
if (data->remapped) {
|
||||||
|
idx = iwn_ampdu_index_check(sc, ring, bitmap, start, idx);
|
||||||
|
if (idx == -1) {
|
||||||
|
/* skip error (device will be restarted anyway). */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Index may have changed. */
|
||||||
|
data = &ring->data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Sometimes (rarely) some frames are excluded from events.
|
||||||
|
* XXX Due to that long_retries counter may be wrong.
|
||||||
|
*/
|
||||||
|
data->long_retries &= ~0x0f;
|
||||||
|
data->long_retries += IWN_AGG_TX_TRY_COUNT(status) + 1;
|
||||||
|
|
||||||
|
if (data->long_retries >= IWN_LONG_RETRY_FW_OVERFLOW) {
|
||||||
|
int diff, wrong_idx;
|
||||||
|
|
||||||
|
diff = data->long_retries / IWN_LONG_RETRY_FW_OVERFLOW;
|
||||||
|
wrong_idx = (idx + diff) % IWN_TX_RING_COUNT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark the entry so the above code will check it
|
||||||
|
* next time.
|
||||||
|
*/
|
||||||
|
ring->data[wrong_idx].remapped = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & IWN_AGG_TX_STATE_UNDERRUN_MSK) {
|
||||||
|
/*
|
||||||
|
* NB: count retries but postpone - it was not
|
||||||
|
* transmitted.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit = idx - start;
|
||||||
|
shift = 0;
|
||||||
|
if (bit >= 64) {
|
||||||
|
shift = 0x100 - bit;
|
||||||
|
bit = 0;
|
||||||
|
} else if (bit <= -64)
|
||||||
|
bit = 0x100 + bit;
|
||||||
|
else if (bit < 0) {
|
||||||
|
shift = -bit;
|
||||||
bit = 0;
|
bit = 0;
|
||||||
}
|
}
|
||||||
bitmap = bitmap << shift;
|
bitmap = bitmap << shift;
|
||||||
bitmap |= 1ULL << bit;
|
bitmap |= 1ULL << bit;
|
||||||
}
|
}
|
||||||
tap = sc->qid2tap[qid];
|
|
||||||
tid = tap->txa_tid;
|
|
||||||
wn = (void *)tap->txa_ni;
|
|
||||||
wn->agg[tid].bitmap = bitmap;
|
|
||||||
wn->agg[tid].startidx = start;
|
wn->agg[tid].startidx = start;
|
||||||
wn->agg[tid].nframes = nframes;
|
wn->agg[tid].bitmap = bitmap;
|
||||||
|
wn->agg[tid].short_retries = rtsfailcnt;
|
||||||
|
|
||||||
res = NULL;
|
DPRINTF(sc, IWN_DEBUG_AMPDU, "%s: nframes %d start %d bitmap %016jX\n",
|
||||||
ssn = 0;
|
__func__, nframes, start, (uintmax_t)bitmap);
|
||||||
if (!IEEE80211_AMPDU_RUNNING(tap)) {
|
|
||||||
res = tap->txa_private;
|
i = ring->read;
|
||||||
ssn = tap->txa_start & 0xfff;
|
|
||||||
|
for (tx_err = 0;
|
||||||
|
i != wn->agg[tid].startidx;
|
||||||
|
i = (i + 1) % IWN_TX_RING_COUNT) {
|
||||||
|
data = &ring->data[i];
|
||||||
|
data->remapped = 0;
|
||||||
|
if (data->m == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tx_err++;
|
||||||
|
iwn_agg_tx_complete(sc, ring, tid, i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is going nframes DWORDS into the descriptor? */
|
ring->read = wn->agg[tid].startidx;
|
||||||
seqno = le32toh(*(status + nframes)) & 0xfff;
|
ring->queued -= tx_err;
|
||||||
for (lastidx = (seqno & 0xff); ring->read != lastidx;) {
|
|
||||||
data = &ring->data[ring->read];
|
|
||||||
|
|
||||||
/* Unmap and free mbuf. */
|
iwn_check_tx_ring(sc, qid);
|
||||||
bus_dmamap_sync(ring->data_dmat, data->map,
|
|
||||||
BUS_DMASYNC_POSTWRITE);
|
|
||||||
bus_dmamap_unload(ring->data_dmat, data->map);
|
|
||||||
m = data->m, data->m = NULL;
|
|
||||||
ni = data->ni, data->ni = NULL;
|
|
||||||
|
|
||||||
KASSERT(ni != NULL, ("no node"));
|
|
||||||
KASSERT(m != NULL, ("no mbuf"));
|
|
||||||
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m);
|
|
||||||
ieee80211_tx_complete(ni, m, 1);
|
|
||||||
|
|
||||||
ring->queued--;
|
|
||||||
ring->read = (ring->read + 1) % IWN_TX_RING_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ring->queued == 0 && res != NULL) {
|
|
||||||
iwn_nic_lock(sc);
|
|
||||||
ops->ampdu_tx_stop(sc, qid, tid, ssn);
|
|
||||||
iwn_nic_unlock(sc);
|
|
||||||
sc->qid2tap[qid] = NULL;
|
|
||||||
free(res, M_DEVBUF);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc->sc_tx_timer = 0;
|
|
||||||
if (ring->queued < IWN_TX_RING_LOMARK)
|
|
||||||
sc->qfullmsk &= ~(1 << ring->qid);
|
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
|
||||||
}
|
}
|
||||||
@@ -3814,6 +3986,7 @@ iwn_notif_intr(struct iwn_softc *sc)
|
|||||||
struct ieee80211com *ic = &sc->sc_ic;
|
struct ieee80211com *ic = &sc->sc_ic;
|
||||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
||||||
uint16_t hw;
|
uint16_t hw;
|
||||||
|
int is_stopped;
|
||||||
|
|
||||||
bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map,
|
bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map,
|
||||||
BUS_DMASYNC_POSTREAD);
|
BUS_DMASYNC_POSTREAD);
|
||||||
@@ -3845,6 +4018,11 @@ iwn_notif_intr(struct iwn_softc *sc)
|
|||||||
case IWN_MPDU_RX_DONE:
|
case IWN_MPDU_RX_DONE:
|
||||||
/* An 802.11 frame has been received. */
|
/* An 802.11 frame has been received. */
|
||||||
iwn_rx_done(sc, desc, data);
|
iwn_rx_done(sc, desc, data);
|
||||||
|
|
||||||
|
is_stopped = (sc->sc_flags & IWN_FLAG_RUNNING) == 0;
|
||||||
|
if (__predict_false(is_stopped))
|
||||||
|
return;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IWN_RX_COMPRESSED_BA:
|
case IWN_RX_COMPRESSED_BA:
|
||||||
@@ -3885,6 +4063,11 @@ iwn_notif_intr(struct iwn_softc *sc)
|
|||||||
IWN_UNLOCK(sc);
|
IWN_UNLOCK(sc);
|
||||||
ieee80211_beacon_miss(ic);
|
ieee80211_beacon_miss(ic);
|
||||||
IWN_LOCK(sc);
|
IWN_LOCK(sc);
|
||||||
|
|
||||||
|
is_stopped = (sc->sc_flags &
|
||||||
|
IWN_FLAG_RUNNING) == 0;
|
||||||
|
if (__predict_false(is_stopped))
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3951,6 +4134,11 @@ iwn_notif_intr(struct iwn_softc *sc)
|
|||||||
IWN_UNLOCK(sc);
|
IWN_UNLOCK(sc);
|
||||||
ieee80211_scan_next(vap);
|
ieee80211_scan_next(vap);
|
||||||
IWN_LOCK(sc);
|
IWN_LOCK(sc);
|
||||||
|
|
||||||
|
is_stopped = (sc->sc_flags & IWN_FLAG_RUNNING) == 0;
|
||||||
|
if (__predict_false(is_stopped))
|
||||||
|
return;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IWN5000_CALIBRATION_RESULT:
|
case IWN5000_CALIBRATION_RESULT:
|
||||||
@@ -4368,7 +4556,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
|
|||||||
struct ieee80211_frame *wh;
|
struct ieee80211_frame *wh;
|
||||||
struct ieee80211_key *k = NULL;
|
struct ieee80211_key *k = NULL;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint16_t seqno, qos;
|
uint16_t qos;
|
||||||
uint8_t tid, type;
|
uint8_t tid, type;
|
||||||
int ac, totlen, rate;
|
int ac, totlen, rate;
|
||||||
|
|
||||||
@@ -4410,25 +4598,13 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ac = M_WME_GETAC(m);
|
ac = M_WME_GETAC(m);
|
||||||
seqno = ni->ni_txseqs[tid];
|
|
||||||
if (m->m_flags & M_AMPDU_MPDU) {
|
if (m->m_flags & M_AMPDU_MPDU) {
|
||||||
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
|
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
|
||||||
|
|
||||||
if (!IEEE80211_AMPDU_RUNNING(tap)) {
|
if (!IEEE80211_AMPDU_RUNNING(tap))
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Queue this frame to the hardware ring that we've
|
|
||||||
* negotiated AMPDU TX on.
|
|
||||||
*
|
|
||||||
* Note that the sequence number must match the TX slot
|
|
||||||
* being used!
|
|
||||||
*/
|
|
||||||
ac = *(int *)tap->txa_private;
|
ac = *(int *)tap->txa_private;
|
||||||
*(uint16_t *)wh->i_seq =
|
|
||||||
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
|
|
||||||
ni->ni_txseqs[tid]++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encrypt the frame if need be. */
|
/* Encrypt the frame if need be. */
|
||||||
@@ -4497,8 +4673,25 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ring = &sc->txq[ac];
|
ring = &sc->txq[ac];
|
||||||
if ((m->m_flags & M_AMPDU_MPDU) != 0 &&
|
if (m->m_flags & M_AMPDU_MPDU) {
|
||||||
(seqno % 256) != ring->cur) {
|
uint16_t seqno = ni->ni_txseqs[tid];
|
||||||
|
|
||||||
|
if (ring->queued > IWN_TX_RING_COUNT / 2 &&
|
||||||
|
(ring->cur + 1) % IWN_TX_RING_COUNT == ring->read) {
|
||||||
|
DPRINTF(sc, IWN_DEBUG_AMPDU, "%s: no more space "
|
||||||
|
"(queued %d) left in %d queue!\n",
|
||||||
|
__func__, ring->queued, ac);
|
||||||
|
return (ENOBUFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Queue this frame to the hardware ring that we've
|
||||||
|
* negotiated AMPDU TX on.
|
||||||
|
*
|
||||||
|
* Note that the sequence number must match the TX slot
|
||||||
|
* being used!
|
||||||
|
*/
|
||||||
|
if ((seqno % 256) != ring->cur) {
|
||||||
device_printf(sc->sc_dev,
|
device_printf(sc->sc_dev,
|
||||||
"%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n",
|
"%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n",
|
||||||
__func__,
|
__func__,
|
||||||
@@ -4506,6 +4699,16 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
|
|||||||
seqno,
|
seqno,
|
||||||
seqno % 256,
|
seqno % 256,
|
||||||
ring->cur);
|
ring->cur);
|
||||||
|
|
||||||
|
/* XXX until D9195 will not be committed */
|
||||||
|
ni->ni_txseqs[tid] &= ~0xff;
|
||||||
|
ni->ni_txseqs[tid] += ring->cur;
|
||||||
|
seqno = ni->ni_txseqs[tid];
|
||||||
|
}
|
||||||
|
|
||||||
|
*(uint16_t *)wh->i_seq =
|
||||||
|
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
|
||||||
|
ni->ni_txseqs[tid]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare TX firmware command. */
|
/* Prepare TX firmware command. */
|
||||||
@@ -4667,6 +4870,13 @@ iwn_tx_cmd(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
|
|||||||
desc = &ring->desc[ring->cur];
|
desc = &ring->desc[ring->cur];
|
||||||
data = &ring->data[ring->cur];
|
data = &ring->data[ring->cur];
|
||||||
|
|
||||||
|
if (__predict_false(data->m != NULL || data->ni != NULL)) {
|
||||||
|
device_printf(sc->sc_dev, "%s: ni (%p) or m (%p) for idx %d "
|
||||||
|
"in queue %d is not NULL!\n", __func__, data->ni, data->m,
|
||||||
|
ring->cur, ring->qid);
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prepare TX firmware command. */
|
/* Prepare TX firmware command. */
|
||||||
cmd = &ring->cmd[ring->cur];
|
cmd = &ring->cmd[ring->cur];
|
||||||
cmd->code = IWN_CMD_TX_DATA;
|
cmd->code = IWN_CMD_TX_DATA;
|
||||||
@@ -8895,18 +9105,12 @@ iwn_scan_end(struct ieee80211com *ic)
|
|||||||
static void
|
static void
|
||||||
iwn_set_channel(struct ieee80211com *ic)
|
iwn_set_channel(struct ieee80211com *ic)
|
||||||
{
|
{
|
||||||
const struct ieee80211_channel *c = ic->ic_curchan;
|
|
||||||
struct iwn_softc *sc = ic->ic_softc;
|
struct iwn_softc *sc = ic->ic_softc;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
|
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
|
||||||
|
|
||||||
IWN_LOCK(sc);
|
IWN_LOCK(sc);
|
||||||
sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq);
|
|
||||||
sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags);
|
|
||||||
sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq);
|
|
||||||
sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only need to set the channel in Monitor mode. AP scanning and auth
|
* Only need to set the channel in Monitor mode. AP scanning and auth
|
||||||
* are already taken care of by their respective firmware commands.
|
* are already taken care of by their respective firmware commands.
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ enum {
|
|||||||
IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */
|
IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */
|
||||||
IWN_DEBUG_SCAN = 0x00008000, /* Scan related operations */
|
IWN_DEBUG_SCAN = 0x00008000, /* Scan related operations */
|
||||||
IWN_DEBUG_STATS = 0x00010000, /* Statistics updates */
|
IWN_DEBUG_STATS = 0x00010000, /* Statistics updates */
|
||||||
|
IWN_DEBUG_AMPDU = 0x00020000, /* A-MPDU specific Tx */
|
||||||
IWN_DEBUG_REGISTER = 0x20000000, /* print chipset register */
|
IWN_DEBUG_REGISTER = 0x20000000, /* print chipset register */
|
||||||
IWN_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */
|
IWN_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */
|
||||||
IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */
|
IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */
|
||||||
|
|||||||
@@ -1378,11 +1378,18 @@ struct iwn_ucode_info {
|
|||||||
|
|
||||||
#define IWN_AGG_TX_STATUS_MSK 0x00000fff
|
#define IWN_AGG_TX_STATUS_MSK 0x00000fff
|
||||||
#define IWN_AGG_TX_TRY_MSK 0x0000f000
|
#define IWN_AGG_TX_TRY_MSK 0x0000f000
|
||||||
|
#define IWN_AGG_TX_TRY_POS 12
|
||||||
|
#define IWN_AGG_TX_TRY_COUNT(status) \
|
||||||
|
(((status) & IWN_AGG_TX_TRY_MSK) >> IWN_AGG_TX_TRY_POS)
|
||||||
|
|
||||||
#define IWN_AGG_TX_STATE_LAST_SENT_MSK \
|
#define IWN_AGG_TX_STATE_LAST_SENT_MSK \
|
||||||
(IWN_AGG_TX_STATE_LAST_SENT_TTL_MSK | \
|
(IWN_AGG_TX_STATE_LAST_SENT_TTL_MSK | \
|
||||||
IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK)
|
IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK)
|
||||||
|
|
||||||
|
#define IWN_AGG_TX_STATE_IGNORE_MASK \
|
||||||
|
(IWN_AGG_TX_STATE_FEW_BYTES_MSK | \
|
||||||
|
IWN_AGG_TX_STATE_ABORT_MSK)
|
||||||
|
|
||||||
/* # tx attempts for first frame in aggregation */
|
/* # tx attempts for first frame in aggregation */
|
||||||
#define IWN_AGG_TX_STATE_TRY_CNT_POS 12
|
#define IWN_AGG_TX_STATE_TRY_CNT_POS 12
|
||||||
#define IWN_AGG_TX_STATE_TRY_CNT_MSK 0xf000
|
#define IWN_AGG_TX_STATE_TRY_CNT_MSK 0xf000
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ struct iwn_rx_radiotap_header {
|
|||||||
uint16_t wr_chan_flags;
|
uint16_t wr_chan_flags;
|
||||||
int8_t wr_dbm_antsignal;
|
int8_t wr_dbm_antsignal;
|
||||||
int8_t wr_dbm_antnoise;
|
int8_t wr_dbm_antnoise;
|
||||||
} __packed;
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define IWN_RX_RADIOTAP_PRESENT \
|
#define IWN_RX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
||||||
@@ -100,6 +100,11 @@ struct iwn_tx_data {
|
|||||||
bus_addr_t scratch_paddr;
|
bus_addr_t scratch_paddr;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
struct ieee80211_node *ni;
|
struct ieee80211_node *ni;
|
||||||
|
unsigned int remapped:1;
|
||||||
|
unsigned int long_retries:7;
|
||||||
|
#define IWN_LONG_RETRY_FW_OVERFLOW 0x10
|
||||||
|
#define IWN_LONG_RETRY_LIMIT_LOG 7
|
||||||
|
#define IWN_LONG_RETRY_LIMIT ((1 << IWN_LONG_RETRY_LIMIT_LOG) - 3)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwn_tx_ring {
|
struct iwn_tx_ring {
|
||||||
@@ -138,8 +143,8 @@ struct iwn_node {
|
|||||||
uint8_t id;
|
uint8_t id;
|
||||||
struct {
|
struct {
|
||||||
uint64_t bitmap;
|
uint64_t bitmap;
|
||||||
|
int short_retries;
|
||||||
int startidx;
|
int startidx;
|
||||||
int nframes;
|
|
||||||
} agg[IEEE80211_TID_SIZE];
|
} agg[IEEE80211_TID_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ struct malo_rx_radiotap_header {
|
|||||||
int8_t wr_antsignal;
|
int8_t wr_antsignal;
|
||||||
int8_t wr_antnoise;
|
int8_t wr_antnoise;
|
||||||
u_int8_t wr_antenna;
|
u_int8_t wr_antenna;
|
||||||
};
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define MALO_TX_RADIOTAP_PRESENT ( \
|
#define MALO_TX_RADIOTAP_PRESENT ( \
|
||||||
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
@@ -111,6 +111,6 @@ struct malo_tx_radiotap_header {
|
|||||||
u_int16_t wt_chan_flags;
|
u_int16_t wt_chan_flags;
|
||||||
u_int8_t wt_txpower;
|
u_int8_t wt_txpower;
|
||||||
u_int8_t wt_antenna;
|
u_int8_t wt_antenna;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#endif /* _DEV_MALO_MVIOCTL_H */
|
#endif /* _DEV_MALO_MVIOCTL_H */
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ static const struct mwl_pci_ident mwl_pci_ids[] = {
|
|||||||
{ 0x11ab, 0x2a0c, "Marvell 88W8363" },
|
{ 0x11ab, 0x2a0c, "Marvell 88W8363" },
|
||||||
{ 0x11ab, 0x2a21, "Marvell 88W8363" },
|
{ 0x11ab, 0x2a21, "Marvell 88W8363" },
|
||||||
{ 0x11ab, 0x2a24, "Marvell 88W8363" },
|
{ 0x11ab, 0x2a24, "Marvell 88W8363" },
|
||||||
|
|
||||||
{ 0, 0, NULL }
|
{ 0, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -280,7 +279,6 @@ static device_method_t mwl_pci_methods[] = {
|
|||||||
DEVMETHOD(device_shutdown, mwl_pci_shutdown),
|
DEVMETHOD(device_shutdown, mwl_pci_shutdown),
|
||||||
DEVMETHOD(device_suspend, mwl_pci_suspend),
|
DEVMETHOD(device_suspend, mwl_pci_suspend),
|
||||||
DEVMETHOD(device_resume, mwl_pci_resume),
|
DEVMETHOD(device_resume, mwl_pci_resume),
|
||||||
|
|
||||||
{ 0,0 }
|
{ 0,0 }
|
||||||
};
|
};
|
||||||
static driver_t mwl_pci_driver = {
|
static driver_t mwl_pci_driver = {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ struct mwl_rx_radiotap_header {
|
|||||||
int8_t wr_antsignal;
|
int8_t wr_antsignal;
|
||||||
int8_t wr_antnoise;
|
int8_t wr_antnoise;
|
||||||
u_int8_t wr_antenna;
|
u_int8_t wr_antenna;
|
||||||
};
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define MWL_TX_RADIOTAP_PRESENT ( \
|
#define MWL_TX_RADIOTAP_PRESENT ( \
|
||||||
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
@@ -133,6 +133,6 @@ struct mwl_tx_radiotap_header {
|
|||||||
u_int16_t wt_chan_flags;
|
u_int16_t wt_chan_flags;
|
||||||
u_int8_t wt_txpower;
|
u_int8_t wt_txpower;
|
||||||
u_int8_t wt_antenna;
|
u_int8_t wt_antenna;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#endif /* _DEV_MWL_MVIOCTL_H */
|
#endif /* _DEV_MWL_MVIOCTL_H */
|
||||||
|
|||||||
@@ -57,7 +57,6 @@
|
|||||||
#define MACREG_REG_A2H_INTERRUPT_CLEAR_SEL 0x00000C38 // (From ARM to host)
|
#define MACREG_REG_A2H_INTERRUPT_CLEAR_SEL 0x00000C38 // (From ARM to host)
|
||||||
#define MACREG_REG_A2H_INTERRUPT_STATUS_MASK 0x00000C3C // (From ARM to host)
|
#define MACREG_REG_A2H_INTERRUPT_STATUS_MASK 0x00000C3C // (From ARM to host)
|
||||||
|
|
||||||
|
|
||||||
// Map to 0x80000000 on BAR1
|
// Map to 0x80000000 on BAR1
|
||||||
#define MACREG_REG_GEN_PTR 0x00000C10
|
#define MACREG_REG_GEN_PTR 0x00000C10
|
||||||
#define MACREG_REG_INT_CODE 0x00000C14
|
#define MACREG_REG_INT_CODE 0x00000C14
|
||||||
@@ -101,7 +100,6 @@
|
|||||||
|
|
||||||
#define MACREG_A2HRIC_BIT_MASK ISR_SRC_BITS
|
#define MACREG_A2HRIC_BIT_MASK ISR_SRC_BITS
|
||||||
|
|
||||||
|
|
||||||
// Bit definitio for MACREG_REG_H2A_INTERRUPT_CAUSE (H2ARIC)
|
// Bit definitio for MACREG_REG_H2A_INTERRUPT_CAUSE (H2ARIC)
|
||||||
#define MACREG_H2ARIC_BIT_PPA_READY 0x00000001 // bit 0
|
#define MACREG_H2ARIC_BIT_PPA_READY 0x00000001 // bit 0
|
||||||
#define MACREG_H2ARIC_BIT_DOOR_BELL 0x00000002 // bit 1
|
#define MACREG_H2ARIC_BIT_DOOR_BELL 0x00000002 // bit 1
|
||||||
@@ -341,7 +339,6 @@ struct mwl_rxdesc {
|
|||||||
#define HostCmd_RESULT_BUSY 0x0004 // System is busy (command ignored)
|
#define HostCmd_RESULT_BUSY 0x0004 // System is busy (command ignored)
|
||||||
#define HostCmd_RESULT_PARTIAL_DATA 0x0005 // Data buffer is not big enough
|
#define HostCmd_RESULT_PARTIAL_DATA 0x0005 // Data buffer is not big enough
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Definition of action or option for each command
|
// Definition of action or option for each command
|
||||||
//
|
//
|
||||||
@@ -377,7 +374,6 @@ struct mwl_rxdesc {
|
|||||||
|
|
||||||
#define HostCmd_WEP_KEY_INDEX_MASK 0x3fffffff
|
#define HostCmd_WEP_KEY_INDEX_MASK 0x3fffffff
|
||||||
|
|
||||||
|
|
||||||
// Define action or option for HostCmd_CMD_802_11_RESET
|
// Define action or option for HostCmd_CMD_802_11_RESET
|
||||||
#define HostCmd_ACT_HALT 0x0001
|
#define HostCmd_ACT_HALT 0x0001
|
||||||
#define HostCmd_ACT_RESTART 0x0002
|
#define HostCmd_ACT_RESTART 0x0002
|
||||||
@@ -485,7 +481,6 @@ typedef struct {
|
|||||||
u_int32_t Enable; /* FALSE: Disable or TRUE: Enable */
|
u_int32_t Enable; /* FALSE: Disable or TRUE: Enable */
|
||||||
} __packed HostCmd_DS_BSS_START;
|
} __packed HostCmd_DS_BSS_START;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_int8_t ElemId;
|
u_int8_t ElemId;
|
||||||
u_int8_t Len;
|
u_int8_t Len;
|
||||||
@@ -745,7 +740,6 @@ typedef struct {
|
|||||||
uint8_t Slot; // Slot=0 if regular, Slot=1 if short.
|
uint8_t Slot; // Slot=0 if regular, Slot=1 if short.
|
||||||
} __packed HostCmd_FW_SET_SLOT;
|
} __packed HostCmd_FW_SET_SLOT;
|
||||||
|
|
||||||
|
|
||||||
// Define data structure for HostCmd_CMD_802_11_GET_STAT
|
// Define data structure for HostCmd_CMD_802_11_GET_STAT
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FWCmdHdr CmdHdr;
|
FWCmdHdr CmdHdr;
|
||||||
@@ -778,7 +772,6 @@ typedef struct {
|
|||||||
uint32_t RxExcludedFrames;
|
uint32_t RxExcludedFrames;
|
||||||
} __packed HostCmd_DS_802_11_GET_STAT;
|
} __packed HostCmd_DS_802_11_GET_STAT;
|
||||||
|
|
||||||
|
|
||||||
// Define data structure for HostCmd_CMD_MAC_REG_ACCESS
|
// Define data structure for HostCmd_CMD_MAC_REG_ACCESS
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FWCmdHdr CmdHdr;
|
FWCmdHdr CmdHdr;
|
||||||
@@ -806,7 +799,6 @@ typedef struct {
|
|||||||
uint8_t Reserverd[3];
|
uint8_t Reserverd[3];
|
||||||
} __packed HostCmd_DS_RF_REG_ACCESS;
|
} __packed HostCmd_DS_RF_REG_ACCESS;
|
||||||
|
|
||||||
|
|
||||||
// Define data structure for HostCmd_CMD_802_11_RADIO_CONTROL
|
// Define data structure for HostCmd_CMD_802_11_RADIO_CONTROL
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FWCmdHdr CmdHdr;
|
FWCmdHdr CmdHdr;
|
||||||
@@ -815,7 +807,6 @@ typedef struct {
|
|||||||
uint16_t RadioOn;
|
uint16_t RadioOn;
|
||||||
} __packed HostCmd_DS_802_11_RADIO_CONTROL;
|
} __packed HostCmd_DS_802_11_RADIO_CONTROL;
|
||||||
|
|
||||||
|
|
||||||
#define TX_POWER_LEVEL_TOTAL 8
|
#define TX_POWER_LEVEL_TOTAL 8
|
||||||
// Define data structure for HostCmd_CMD_802_11_RF_TX_POWER
|
// Define data structure for HostCmd_CMD_802_11_RF_TX_POWER
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -1141,7 +1132,6 @@ typedef struct {
|
|||||||
uint8_t ActionData[1];
|
uint8_t ActionData[1];
|
||||||
} __packed HostCmd_FW_UPDATE_ENCRYPTION;
|
} __packed HostCmd_FW_UPDATE_ENCRYPTION;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FWCmdHdr CmdHdr;
|
FWCmdHdr CmdHdr;
|
||||||
uint32_t ActionType; // ENCR_ACTION_TYPE
|
uint32_t ActionType; // ENCR_ACTION_TYPE
|
||||||
@@ -1272,8 +1262,6 @@ typedef struct {
|
|||||||
uint8_t Watchdogbitmap; // for SW/BA
|
uint8_t Watchdogbitmap; // for SW/BA
|
||||||
} __packed HostCmd_FW_GET_WATCHDOG_BITMAP;
|
} __packed HostCmd_FW_GET_WATCHDOG_BITMAP;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Define data structure for HostCmd_CMD_SET_REGION_POWER
|
// Define data structure for HostCmd_CMD_SET_REGION_POWER
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FWCmdHdr CmdHdr;
|
FWCmdHdr CmdHdr;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ struct rt2560_rx_radiotap_header {
|
|||||||
int8_t wr_antsignal;
|
int8_t wr_antsignal;
|
||||||
int8_t wr_antnoise;
|
int8_t wr_antnoise;
|
||||||
uint8_t wr_antenna;
|
uint8_t wr_antenna;
|
||||||
};
|
} __packed __aligned(8);
|
||||||
|
|
||||||
#define RT2560_RX_RADIOTAP_PRESENT \
|
#define RT2560_RX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
((1 << IEEE80211_RADIOTAP_TSFT) | \
|
||||||
@@ -45,7 +45,7 @@ struct rt2560_tx_radiotap_header {
|
|||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
uint8_t wt_antenna;
|
uint8_t wt_antenna;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#define RT2560_TX_RADIOTAP_PRESENT \
|
#define RT2560_TX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ struct rt2661_tx_radiotap_header {
|
|||||||
uint8_t wt_rate;
|
uint8_t wt_rate;
|
||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
} __packed __aligned(8);
|
} __packed;
|
||||||
|
|
||||||
#define RT2661_TX_RADIOTAP_PRESENT \
|
#define RT2661_TX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ struct rt2860_tx_radiotap_header {
|
|||||||
uint8_t wt_rate;
|
uint8_t wt_rate;
|
||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
} __packed __aligned(8);
|
} __packed;
|
||||||
|
|
||||||
#define RT2860_TX_RADIOTAP_PRESENT \
|
#define RT2860_TX_RADIOTAP_PRESENT \
|
||||||
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
((1 << IEEE80211_RADIOTAP_FLAGS) | \
|
||||||
|
|||||||
@@ -1564,10 +1564,6 @@ rtwn_set_channel(struct ieee80211com *ic)
|
|||||||
|
|
||||||
RTWN_LOCK(sc);
|
RTWN_LOCK(sc);
|
||||||
rtwn_set_chan(sc, c);
|
rtwn_set_chan(sc, c);
|
||||||
sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq);
|
|
||||||
sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags);
|
|
||||||
sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq);
|
|
||||||
sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags);
|
|
||||||
RTWN_UNLOCK(sc);
|
RTWN_UNLOCK(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,10 @@ struct rtwn_rx_radiotap_header {
|
|||||||
struct rtwn_tx_radiotap_header {
|
struct rtwn_tx_radiotap_header {
|
||||||
struct ieee80211_radiotap_header wt_ihdr;
|
struct ieee80211_radiotap_header wt_ihdr;
|
||||||
uint8_t wt_flags;
|
uint8_t wt_flags;
|
||||||
|
uint8_t wt_pad;
|
||||||
uint16_t wt_chan_freq;
|
uint16_t wt_chan_freq;
|
||||||
uint16_t wt_chan_flags;
|
uint16_t wt_chan_flags;
|
||||||
} __packed __aligned(8);
|
} __packed;
|
||||||
|
|
||||||
#define RTWN_TX_RADIOTAP_PRESENT \
|
#define RTWN_TX_RADIOTAP_PRESENT \
|
||||||
(1 << IEEE80211_RADIOTAP_FLAGS | \
|
(1 << IEEE80211_RADIOTAP_FLAGS | \
|
||||||
|
|||||||
Reference in New Issue
Block a user