summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_iwn.c1009
-rw-r--r--sys/dev/pci/if_iwnreg.h381
-rw-r--r--sys/dev/pci/if_iwnvar.h11
3 files changed, 868 insertions, 533 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c
index 4f269abc64a..e8d56992b95 100644
--- a/sys/dev/pci/if_iwn.c
+++ b/sys/dev/pci/if_iwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwn.c,v 1.24 2008/10/13 16:37:10 damien Exp $ */
+/* $OpenBSD: if_iwn.c,v 1.25 2008/10/22 06:25:07 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -88,10 +88,6 @@ void iwn_radiotap_attach(struct iwn_softc *);
#endif
void iwn_power(int, void *);
int iwn_nic_lock(struct iwn_softc *);
-void iwn_prph_write_region_4(struct iwn_softc *, uint32_t,
- const uint32_t *, int);
-void iwn_mem_set_region_4(struct iwn_softc *, uint32_t, uint32_t,
- int);
int iwn_eeprom_lock(struct iwn_softc *);
int iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int);
int iwn_dma_contig_alloc(bus_dma_tag_t, struct iwn_dma_info *,
@@ -126,7 +122,7 @@ int iwn_media_change(struct ifnet *);
int iwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
void iwn_iter_func(void *, struct ieee80211_node *);
void iwn_calib_timeout(void *);
-void iwn_ampdu_rx_start(struct iwn_softc *, struct iwn_rx_desc *);
+void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *);
void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
void iwn5000_rx_calib_results(struct iwn_softc *,
@@ -135,10 +131,11 @@ void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *);
void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *);
void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *);
void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int,
- uint32_t);
+ uint8_t);
void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
void iwn_notif_intr(struct iwn_softc *);
void iwn_wakeup_intr(struct iwn_softc *);
+void iwn_fatal_intr(struct iwn_softc *);
int iwn_intr(void *);
void iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t,
uint16_t);
@@ -156,9 +153,9 @@ int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *,
int);
int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *,
int);
-int iwn_setup_node_mrr(struct iwn_softc *,
- const struct ieee80211_node *, uint8_t);
-int iwn_set_fixed_rate(struct iwn_softc *, uint8_t, uint8_t, int);
+int iwn_set_link_quality(struct iwn_softc *,
+ struct ieee80211_node *);
+int iwn_add_broadcast_node(struct iwn_softc *, int);
void iwn_updateedca(struct ieee80211com *);
void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
int iwn_set_critical_temp(struct iwn_softc *);
@@ -186,12 +183,26 @@ int iwn_config(struct iwn_softc *);
int iwn_scan(struct iwn_softc *, uint16_t);
int iwn_auth(struct iwn_softc *);
int iwn_run(struct iwn_softc *);
-int iwn4965_addba(struct iwn_softc *, struct ieee80211_node *,
- int, int, int);
-int iwn4965_delba(struct iwn_softc *, int, int, int);
-int iwn5000_addba(struct iwn_softc *, struct ieee80211_node *,
- int, int, int);
-int iwn5000_delba(struct iwn_softc *, int, int, int);
+int iwn_set_key(struct ieee80211com *, struct ieee80211_node *,
+ struct ieee80211_key *);
+void iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
+ struct ieee80211_key *);
+int iwn_ampdu_rx_start(struct ieee80211com *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+void iwn_ampdu_rx_stop(struct ieee80211com *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+int iwn_ampdu_tx_start(struct ieee80211com *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+void iwn_ampdu_tx_stop(struct ieee80211com *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+void iwn4965_ampdu_tx_start(struct iwn_softc *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+void iwn4965_ampdu_tx_stop(struct iwn_softc *,
+ uint8_t, uint16_t);
+void iwn5000_ampdu_tx_start(struct iwn_softc *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+void iwn5000_ampdu_tx_stop(struct iwn_softc *,
+ uint8_t, uint16_t);
int iwn5000_query_calibration(struct iwn_softc *);
int iwn5000_send_calibration(struct iwn_softc *);
int iwn4965_post_alive(struct iwn_softc *);
@@ -238,6 +249,8 @@ static const struct iwn_hal iwn4965_hal = {
iwn4965_set_gains,
iwn4965_add_node,
iwn4965_tx_done,
+ iwn4965_ampdu_tx_start,
+ iwn4965_ampdu_tx_stop,
"iwn-4965",
&iwn4965_sensitivity_limits,
IWN4965_NTXQUEUES,
@@ -264,6 +277,8 @@ static const struct iwn_hal iwn5000_hal = {
iwn5000_set_gains,
iwn5000_add_node,
iwn5000_tx_done,
+ iwn5000_ampdu_tx_start,
+ iwn5000_ampdu_tx_stop,
"iwn-5000",
&iwn5000_sensitivity_limits,
IWN5000_NTXQUEUES,
@@ -319,7 +334,7 @@ iwn_attach(struct device *parent, struct device *self, void *aux)
return;
}
- /* Clear device-specific "PCI retry timeout" register (41H). */
+ /* Clear device-specific "PCI retry timeout" register (41h). */
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
reg &= ~0xff00;
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg);
@@ -406,8 +421,8 @@ iwn_attach(struct device *parent, struct device *self, void *aux)
/* Power OFF adapter. */
iwn_apm_stop(sc);
- printf(", %dT%dR, %.4s, address %s\n", sc->ntxchains, sc->nrxchains,
- sc->eeprom_domain, ether_sprintf(ic->ic_myaddr));
+ printf(", MIMO %dT%dR, %.4s, address %s\n", sc->ntxchains,
+ sc->nrxchains, sc->eeprom_domain, ether_sprintf(ic->ic_myaddr));
/* Initialization firmware has not been loaded yet. */
sc->sc_flags |= IWN_FLAG_FIRST_BOOT;
@@ -422,7 +437,8 @@ iwn_attach(struct device *parent, struct device *self, void *aux)
IEEE80211_C_RSN | /* WPA/RSN */
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_SHPREAMBLE; /* short preamble supported */
+ IEEE80211_C_SHPREAMBLE | /* short preamble supported */
+ IEEE80211_C_PMGT; /* power saving supported */
/* Set supported rates. */
ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
@@ -450,6 +466,10 @@ iwn_attach(struct device *parent, struct device *self, void *aux)
/* Override 802.11 state transition machine. */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = iwn_newstate;
+#ifdef notyet
+ ic->ic_set_key = iwn_set_key;
+ ic->ic_delete_key = iwn_delete_key;
+#endif
ieee80211_media_init(ifp, iwn_media_change, ieee80211_media_status);
sc->amrr.amrr_min_success_threshold = 1;
@@ -484,27 +504,16 @@ iwn_hal_attach(struct iwn_softc *sc)
switch (sc->hw_type) {
case IWN_HW_REV_TYPE_4965:
sc->sc_hal = &iwn4965_hal;
- sc->ntxchains = 2;
- sc->nrxchains = 2; /* XXX should be 3? */
sc->critical_temp = IWN_CTOK(110);
break;
- case IWN_HW_REV_TYPE_5100:
- sc->sc_hal = &iwn5000_hal;
- sc->ntxchains = 1;
- sc->nrxchains = 2;
- sc->critical_temp = 110;
- break;
case IWN_HW_REV_TYPE_5150:
sc->sc_hal = &iwn5000_hal;
- sc->ntxchains = 1;
- sc->nrxchains = 2;
sc->critical_temp = IWN_CTOK(110);
break;
+ case IWN_HW_REV_TYPE_5100:
case IWN_HW_REV_TYPE_5300:
case IWN_HW_REV_TYPE_5350:
sc->sc_hal = &iwn5000_hal;
- sc->ntxchains = 3;
- sc->nrxchains = 3;
sc->critical_temp = 110;
break;
default:
@@ -563,7 +572,7 @@ iwn_power(int why, void *arg)
if (why != PWR_RESUME)
return;
- /* Clear device-specific "PCI retry timeout" register (41H). */
+ /* Clear device-specific "PCI retry timeout" register (41h). */
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
reg &= ~0xff00;
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg);
@@ -617,7 +626,19 @@ iwn_prph_write(struct iwn_softc *sc, uint32_t addr, uint32_t data)
IWN_WRITE(sc, IWN_PRPH_WDATA, data);
}
-void
+static __inline void
+iwn_prph_setbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask)
+{
+ iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) | mask);
+}
+
+static __inline void
+iwn_prph_clrbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask)
+{
+ iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) & ~mask);
+}
+
+static __inline void
iwn_prph_write_region_4(struct iwn_softc *sc, uint32_t addr,
const uint32_t *data, int count)
{
@@ -652,7 +673,15 @@ iwn_mem_write_2(struct iwn_softc *sc, uint32_t addr, uint16_t data)
iwn_mem_write(sc, addr & ~3, tmp);
}
-void
+static __inline void
+iwn_mem_read_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t *data,
+ int count)
+{
+ for (; count > 0; count--, addr += 4)
+ *data++ = iwn_mem_read(sc, addr);
+}
+
+static __inline void
iwn_mem_set_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t val,
int count)
{
@@ -1101,6 +1130,17 @@ iwn_read_eeprom(struct iwn_softc *sc)
iwn_read_prom_data(sc, IWN_EEPROM_RFCFG, &val, 2);
sc->rfcfg = letoh16(val);
DPRINTF(("radio config=0x%04x\n", sc->rfcfg));
+ sc->txantmsk = IWN_RFCFG_TXANTMSK(sc->rfcfg);
+ sc->rxantmsk = IWN_RFCFG_RXANTMSK(sc->rfcfg);
+ /* Count the number of TX and RX chains. */
+ sc->ntxchains =
+ ((sc->txantmsk >> 2) & 1) +
+ ((sc->txantmsk >> 1) & 1) +
+ ((sc->txantmsk >> 0) & 1);
+ sc->nrxchains =
+ ((sc->rxantmsk >> 2) & 1) +
+ ((sc->rxantmsk >> 1) & 1) +
+ ((sc->rxantmsk >> 0) & 1);
/* Read MAC address. */
iwn_read_prom_data(sc, IWN_EEPROM_MAC, ic->ic_myaddr, 6);
@@ -1325,7 +1365,7 @@ iwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
switch (nstate) {
case IEEE80211_S_SCAN:
/* Make the link LED blink while we're scanning. */
- iwn_set_led(sc, IWN_LED_LINK, 20, 2);
+ iwn_set_led(sc, IWN_LED_LINK, 10, 10);
if ((error = iwn_scan(sc, IEEE80211_CHAN_2GHZ)) != 0) {
printf("%s: could not initiate scan\n",
@@ -1406,24 +1446,24 @@ iwn_calib_timeout(void *arg)
}
/*
- * Process an AMPDU_RX_START firmware notification. This is usually
- * immediately followed by an AMPDU_RX_DONE notification.
+ * Process an RX_PHY firmware notification. This is usually immediately
+ * followed by an MPDU_RX_DONE notification.
*/
void
-iwn_ampdu_rx_start(struct iwn_softc *sc, struct iwn_rx_desc *desc)
+iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc)
{
struct iwn_rx_stat *stat;
- DPRINTFN(2, ("received AMPDU stats\n"));
- /* Save RX statistics, they will be used on AMPDU_RX_DONE. */
+ DPRINTFN(2, ("received PHY stats\n"));
+ /* Save RX statistics, they will be used on MPDU_RX_DONE. */
stat = (struct iwn_rx_stat *)(desc + 1);
memcpy(&sc->last_rx_stat, stat, sizeof (*stat));
sc->last_rx_valid = 1;
}
/*
- * Process an RX_DONE (4965AGN only) or AMPDU_RX_DONE firmware notification.
- * Each AMPDU_RX_DONE notification must be preceded by an AMPDU_RX_START.
+ * Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification.
+ * Each MPDU_RX_DONE notification must be preceded by an RX_PHY one.
*/
void
iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
@@ -1443,10 +1483,10 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
uint32_t *tail;
int len, rssi;
- if (desc->type == IWN_AMPDU_RX_DONE) {
- /* Check for prior AMPDU_RX_START. */
+ if (desc->type == IWN_MPDU_RX_DONE) {
+ /* Check for prior RX_PHY. */
if (!sc->last_rx_valid) {
- DPRINTF(("missing AMPDU_RX_START\n"));
+ DPRINTF(("missing RX_PHY\n"));
ifp->if_ierrors++;
return;
}
@@ -1461,11 +1501,11 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
ifp->if_ierrors++;
return;
}
- if (desc->type == IWN_AMPDU_RX_DONE) {
- struct iwn_rx_ampdu *ampdu =
- (struct iwn_rx_ampdu *)(desc + 1);
- head = (caddr_t)(ampdu + 1);
- len = letoh16(ampdu->len);
+ if (desc->type == IWN_MPDU_RX_DONE) {
+ struct iwn_rx_mpdu *mpdu =
+ (struct iwn_rx_mpdu *)(desc + 1);
+ head = (caddr_t)(mpdu + 1);
+ len = letoh16(mpdu->len);
} else {
head = (caddr_t)(stat + 1) + stat->cfg_phy_len;
len = letoh16(stat->len);
@@ -1528,6 +1568,8 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap;
tap->wr_flags = 0;
+ if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE))
+ tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
tap->wr_chan_freq =
htole16(ic->ic_channels[stat->chan].ic_freq);
tap->wr_chan_flags =
@@ -1585,7 +1627,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
void
iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc)
{
- struct iwn5000_calib *calib = (struct iwn5000_calib *)(desc + 1);
+ struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
u_int idx, len;
/* No initial calibration required for 5150! */
@@ -1688,7 +1730,7 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
{
struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1);
- iwn_tx_done(sc, desc, stat->retrycnt, letoh32(stat->status));
+ iwn_tx_done(sc, desc, stat->retrycnt, letoh32(stat->status) & 0xff);
}
void
@@ -1698,7 +1740,7 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
/* Reset TX scheduler slot. */
iwn5000_reset_sched(sc, desc->qid & 0xf, desc->idx);
- iwn_tx_done(sc, desc, stat->retrycnt, letoh16(stat->status));
+ iwn_tx_done(sc, desc, stat->retrycnt, letoh16(stat->status) & 0xff);
}
/*
@@ -1706,7 +1748,7 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
*/
void
iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int retrycnt,
- uint32_t status)
+ uint8_t status)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
@@ -1786,12 +1828,12 @@ iwn_notif_intr(struct iwn_softc *sc)
iwn_cmd_done(sc, desc);
switch (desc->type) {
- case IWN_AMPDU_RX_START:
- iwn_ampdu_rx_start(sc, desc);
+ case IWN_RX_PHY:
+ iwn_rx_phy(sc, desc);
break;
case IWN_RX_DONE: /* 4965AGN only. */
- case IWN_AMPDU_RX_DONE:
+ case IWN_MPDU_RX_DONE:
/* An 802.11 frame has been received. */
iwn_rx_done(sc, desc, data);
break;
@@ -1840,6 +1882,8 @@ iwn_notif_intr(struct iwn_softc *sc)
/* Save microcontroller's report. */
memcpy(&sc->ucode_info, uc, sizeof (*uc));
}
+ /* Save the address of the error log in SRAM. */
+ sc->errptr = letoh32(uc->errptr);
break;
}
case IWN_STATE_CHANGED:
@@ -1928,6 +1972,68 @@ iwn_wakeup_intr(struct iwn_softc *sc)
}
}
+/*
+ * Dump the error log of the firmware when a firmware panic occurs. Although
+ * we can't debug the firmware because it is neither open source nor free, it
+ * can help us to identify certain classes of problems.
+ */
+void
+iwn_fatal_intr(struct iwn_softc *sc)
+{
+#define N(a) (sizeof (a) / sizeof ((a)[0]))
+ const struct iwn_hal *hal = sc->sc_hal;
+ struct iwn_fw_dump dump;
+ int i;
+
+ /* Check that the error log address is valid. */
+ if (sc->errptr < IWN_FW_DATA_BASE ||
+ sc->errptr + sizeof (dump) >
+ IWN_FW_DATA_BASE + hal->fw_data_maxsz) {
+ printf("%s: bad firmware error log address 0x%08x\n",
+ sc->sc_dev.dv_xname, sc->errptr);
+ return;
+ }
+ if (iwn_nic_lock(sc) != 0) {
+ printf("%s: could not read firmware error log\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ /* Read firmware error log from SRAM. */
+ iwn_mem_read_region_4(sc, sc->errptr, (uint32_t *)&dump,
+ sizeof (dump) / sizeof (uint32_t));
+ iwn_nic_unlock(sc);
+
+ if (dump.valid == 0) {
+ printf("%s: firmware error log is empty\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ printf("firmware error log:\n");
+ printf("\error type = \"%s\" (0x%08X)\n",
+ dump.id < N(iwn_fw_errmsg) ? iwn_fw_errmsg[dump.id] : "UNKNOWN",
+ dump.id);
+ printf("\tprogram counter = 0x%08X\n", dump.pc);
+ printf("\tsource line = 0x%08X\n", dump.src_line);
+ printf("\terror data = 0x%08X%08X\n",
+ dump.error_data[0], dump.error_data[1]);
+ printf("\tbranch link = 0x%08X%08X\n",
+ dump.branch_link[0], dump.branch_link[1]);
+ printf("\tinterrupt link = 0x%08X\n",
+ dump.interrupt_link[0], dump.interrupt_link[1]);
+ printf("\ttime = %u\n", dump.time[0]);
+
+ /* Dump driver status (TX and RX rings) while we're here. */
+ printf("driver status:\n");
+ for (i = 0; i < hal->ntxqs; i++) {
+ struct iwn_tx_ring *ring = &sc->txq[i];
+ printf("\ttx ring %2d: qid=%2d cur=%3d queued=%3d\n",
+ i, ring->qid, ring->cur, ring->queued);
+ }
+ printf("\trx ring: cur=%d\n", sc->rxq.cur);
+ printf("\t802.11 state %d\n", sc->sc_ic.ic_state);
+#undef N
+}
+
int
iwn_intr(void *arg)
{
@@ -1961,10 +2067,12 @@ iwn_intr(void *arg)
if (r1 & IWN_INT_CT_REACHED) {
printf("%s: critical temperature reached!\n",
sc->sc_dev.dv_xname);
- /* XXX reduce TX power? */
+ /* XXX Reduce TX power? */
}
if (r1 & (IWN_INT_SW_ERR | IWN_INT_HW_ERR)) {
printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname);
+ /* Dump firmware error log and stop. */
+ iwn_fatal_intr(sc);
ifp->if_flags &= ~IFF_UP;
iwn_stop(ifp, 1);
return 1;
@@ -2054,6 +2162,75 @@ iwn_plcp_signal(int rate)
/* Determine if a given rate is CCK or OFDM. */
#define IWN_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
+#ifdef notyet
+void
+iwn_ccmp_encap(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_key *k)
+{
+ u_int8_t *ivp;
+
+ M_PREPEND(m0, IEEE80211_CCMP_HDRLEN, M_NOWAIT);
+ /* NB: Can't fail because of previous m_adj() call. */
+
+ k->k_tsc++; /* Increment the 48-bit PN. */
+
+ /* Construct CCMP header. */
+ ivp = mtod(m0, u_int8_t *);
+ ivp[0] = k->k_tsc; /* PN0 */
+ ivp[1] = k->k_tsc >> 8; /* PN1 */
+ ivp[2] = 0; /* Rsvd */
+ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */
+ ivp[4] = k->k_tsc >> 16; /* PN2 */
+ ivp[5] = k->k_tsc >> 24; /* PN3 */
+ ivp[6] = k->k_tsc >> 32; /* PN4 */
+ ivp[7] = k->k_tsc >> 40; /* PN5 */
+}
+
+void
+iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_key *k)
+{
+ struct ieee80211_frame *wh;
+ uint64_t pn, *prsc;
+ uint8_t *ivp;
+ uint8_t tid;
+ int hdrlen;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
+ ivp = (uint8_t *)wh + hdrlen;
+
+ /* Check that ExtIV bit is be set. */
+ if (!(ivp[3] & IEEE80211_WEP_EXTIV))
+ return 1;
+
+ tid = ieee80211_has_qos(wh) ?
+ ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+ prsc = &k->k_rsc[tid];
+
+ /* Extract the 48-bit PN from the CCMP header. */
+ pn = (u_int64_t)ivp[0] |
+ (u_int64_t)ivp[1] << 8 |
+ (u_int64_t)ivp[4] << 16 |
+ (u_int64_t)ivp[5] << 24 |
+ (u_int64_t)ivp[6] << 32 |
+ (u_int64_t)ivp[7] << 40;
+ if (pn <= *prsc) {
+ /* Replayed frame, discard. */
+ ic->ic_stats.is_ccmp_replays++;
+ return 1;
+ }
+ /* Update last seen packet number. */
+ *prsc = pn;
+
+ /* Clear Protected bit and strip IV. */
+ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+ ovbcopy(wh, mtod(m0, caddr_t) + IEEE80211_CCMP_HDRLEN, hdrlen);
+ m_adj(m0, IEEE80211_CCMP_HDRLEN);
+ /* Strip MIC. */
+ m_adj(m0, -IEEE80211_CCMP_MICLEN);
+ return 0;
+}
+#endif
+
int
iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
@@ -2070,7 +2247,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
struct mbuf *mnew;
uint32_t flags;
uint16_t qos;
- uint8_t tid, type;
+ uint8_t tid, txant, type;
u_int hdrlen;
int i, hasqos, rate, error, pad;
@@ -2146,7 +2323,8 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
cmd->idx = ring->cur;
tx = (struct iwn_cmd_data *)cmd->data;
- /* NB: No need to bzero tx, all fields are reinitialized here. */
+ /* NB: No need to clear tx, all fields are reinitialized here. */
+ tx->scratch = 0; /* clear "scratch" area */
flags = 0;
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
@@ -2179,9 +2357,9 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
}
if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) {
if (sc->hw_type != IWN_HW_REV_TYPE_4965) {
- /* 5000 autoselect RTS/CTS or CTS-to-self. */
+ /* 5000 autoselects RTS/CTS or CTS-to-self. */
flags &= ~(IWN_TX_NEED_RTS | IWN_TX_NEED_CTS);
- flags |= IWN5000_TX_NEED_RTS_CTS;
+ flags |= IWN_TX_NEED_PROTECTION;
} else
flags |= IWN_TX_FULL_TXOP;
}
@@ -2191,7 +2369,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
type != IEEE80211_FC0_TYPE_DATA)
tx->id = hal->broadcast_id;
else
- tx->id = IWN_ID_BSS;
+ tx->id = ((struct iwn_node *)ni)->id;
if (type == IEEE80211_FC0_TYPE_MGT) {
uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
@@ -2230,7 +2408,8 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
/* Group or management frame. */
tx->ridx = IWN_MAX_TX_RETRIES - 1;
/* XXX Alternate between antenna A and B? */
- tx->rflags |= IWN_RFLAG_ANT_B;
+ txant = IWN_LSB(sc->txantmsk);
+ tx->rflags |= IWN_RFLAG_ANT(txant);
} else {
tx->ridx = ni->ni_rates.rs_nrates - ni->ni_txrate - 1;
/* Tell adapter to ignore rflags. */
@@ -2297,7 +2476,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
/* Other DMA segments are for data payload. */
for (i = 1; i <= data->map->dm_nsegs; i++) {
IWN_SET_DESC_SEG(desc, i, data->map->dm_segs[i - 1].ds_addr,
- data->map->dm_segs[i - 1].ds_len);
+ data->map->dm_segs[i - 1].ds_len);
}
/* Update TX scheduler. */
@@ -2442,6 +2621,22 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
break;
+ case SIOCS80211POWER:
+ error = ieee80211_ioctl(ifp, cmd, data);
+ if (error != ENETRESET)
+ break;
+ if (ic->ic_state == IEEE80211_S_RUN &&
+ sc->calib.state == IWN_CALIB_STATE_RUN) {
+ if (ic->ic_flags & IEEE80211_F_PMGTON)
+ error = iwn_set_pslevel(sc, 0, 3, 0);
+ else /* back to CAM */
+ error = iwn_set_pslevel(sc, 0, 0, 0);
+ } else {
+ /* Defer until transition to IWN_CALIB_STATE_RUN. */
+ error = 0;
+ }
+ break;
+
default:
error = ieee80211_ioctl(ifp, cmd, data);
}
@@ -2454,7 +2649,6 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
(void)iwn_init(ifp);
}
}
-
splx(s);
return error;
}
@@ -2529,15 +2723,18 @@ int
iwn4965_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async)
{
struct iwn4965_node_info hnode;
+ caddr_t src, dst;
- /* We use the node structure for 5000 internally, convert it. */
- memset(&hnode, 0, sizeof hnode);
- hnode.control = node->control;
- IEEE80211_ADDR_COPY(hnode.macaddr, node->macaddr);
- hnode.id = node->id;
- hnode.flags = node->flags;
- hnode.htflags = node->htflags;
- /* XXX More fields. */
+ /*
+ * We use the node structure for 5000 Series internally (it is
+ * a superset of the one for 4965AGN). We thus copy the common
+ * fields before sending the command.
+ */
+ src = (caddr_t)node;
+ dst = (caddr_t)&hnode;
+ memcpy(dst, src, 48);
+ /* Skip TSC, RX MIC and TX MIC fields from ``src''. */
+ memcpy(dst + 48, src + 72, 20);
return iwn_cmd(sc, IWN_CMD_ADD_NODE, &hnode, sizeof hnode, async);
}
@@ -2548,71 +2745,86 @@ iwn5000_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async)
return iwn_cmd(sc, IWN_CMD_ADD_NODE, node, sizeof (*node), async);
}
-/*
- * Configure hardware multi-rate retries for one node.
- */
int
-iwn_setup_node_mrr(struct iwn_softc *sc, const struct ieee80211_node *ni,
- uint8_t id)
-{
- const struct ieee80211_rateset *rs = &ni->ni_rates;
- struct iwn_cmd_mrr mrr;
- uint8_t rate;
- int i, r;
-
- memset(&mrr, 0, sizeof mrr);
- mrr.id = id;
- mrr.ssmask = 2;
- mrr.dsmask = 3;
- mrr.ampdu_max = 64;
- mrr.ampdu_disable = 3;
- mrr.ampdu_limit = htole16(4000);
-
- r = rs->rs_nrates - 1;
- for (i = 0; i < IWN_MAX_TX_RETRIES && r >= 0; i++, r--) {
- rate = rs->rs_rates[r] & IEEE80211_RATE_VAL;
- DPRINTF(("retry %d: rate %d\n", i, rate));
- mrr.table[i].rate = iwn_plcp_signal(rate);
- mrr.table[i].rflags = IWN_RFLAG_ANT_B;
- if (!IWN_RATE_IS_OFDM(rate))
- mrr.table[i].rflags |= IWN_RFLAG_CCK;
- }
- /* Pad with the lowest available bit-rate. */
- rate = rs->rs_rates[0] & IEEE80211_RATE_VAL;
- for (; i < IWN_MAX_TX_RETRIES; i++) {
- DPRINTF(("retry %d: rate %d\n", i, rate));
- mrr.table[i].rate = iwn_plcp_signal(rate);
- mrr.table[i].rflags = IWN_RFLAG_ANT_B;
+iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
+{
+ struct iwn_node *wn = (void *)ni;
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ struct iwn_cmd_link_quality linkq;
+ uint8_t txant, rate;
+ int i, ridx;
+
+ memset(&linkq, 0, sizeof linkq);
+ linkq.id = wn->id;
+ linkq.antmsk_1stream = IWN_ANT_B;
+ linkq.antmsk_2stream = IWN_ANT_A | IWN_ANT_B;
+ linkq.ampdu_max = 64;
+ linkq.ampdu_threshold = 3;
+ linkq.ampdu_limit = htole16(4000); /* 4ms */
+
+ /* Use the first valid TX antenna. */
+ txant = IWN_LSB(sc->txantmsk);
+
+ /* Start at highest available bit-rate. */
+ ridx = rs->rs_nrates - 1;
+ for (i = 0; i < IWN_MAX_TX_RETRIES; i++) {
+ rate = rs->rs_rates[ridx] & IEEE80211_RATE_VAL;
+ DPRINTF(("retry %d, rate %d\n", i, rate));
+ linkq.retry[i].rate = iwn_plcp_signal(rate);
+ linkq.retry[i].rflags = IWN_RFLAG_ANT(txant);
if (!IWN_RATE_IS_OFDM(rate))
- mrr.table[i].rflags |= IWN_RFLAG_CCK;
+ linkq.retry[i].rflags |= IWN_RFLAG_CCK;
+ /* Next retry at immediate lower bit-rate. */
+ if (ridx > 0)
+ ridx--;
}
- return iwn_cmd(sc, IWN_CMD_NODE_MRR_SETUP, &mrr, sizeof mrr, 1);
+ return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1);
}
int
-iwn_set_fixed_rate(struct iwn_softc *sc, uint8_t id, uint8_t rate, int async)
+iwn_add_broadcast_node(struct iwn_softc *sc, int async)
{
- struct iwn_cmd_mrr mrr;
- int i;
+ const struct iwn_hal *hal = sc->sc_hal;
+ struct iwn_node_info node;
+ struct iwn_cmd_link_quality linkq;
+ uint8_t txant;
+ int i, error;
- memset(&mrr, 0, sizeof mrr);
- mrr.id = id;
- mrr.ssmask = 2;
- mrr.dsmask = 3;
- mrr.ampdu_max = 64;
- mrr.ampdu_disable = 3;
- mrr.ampdu_limit = htole16(4000);
-
- /* To set a fixed rate, we make all retries use the same rate. */
- mrr.table[0].rate = iwn_plcp_signal(rate);
- mrr.table[0].rflags = IWN_RFLAG_ANT_B;
- if (!IWN_RATE_IS_OFDM(rate))
- mrr.table[0].rflags |= IWN_RFLAG_CCK;
+ memset(&node, 0, sizeof node);
+ IEEE80211_ADDR_COPY(node.macaddr, etherbroadcastaddr);
+ node.id = hal->broadcast_id;
+ DPRINTF(("adding broadcast node\n"));
+ if ((error = hal->add_node(sc, &node, async)) != 0)
+ return error;
+
+ /*
+ * Setup link quality for broadcast node. The broadcast node is
+ * used to send group-addressed and management frames.
+ */
+ memset(&linkq, 0, sizeof linkq);
+ linkq.id = hal->broadcast_id;
+ linkq.antmsk_1stream = IWN_ANT_B;
+ linkq.antmsk_2stream = IWN_ANT_A | IWN_ANT_B;
+ linkq.ampdu_max = 64;
+ linkq.ampdu_threshold = 3;
+ linkq.ampdu_limit = htole16(4000); /* 4ms */
+
+ /* Use the first valid TX antenna. */
+ txant = IWN_LSB(sc->txantmsk);
+
+ /* Use lowest mandatory bit-rate. */
+ if (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) {
+ linkq.retry[0].rate = iwn_ridx_to_plcp[IWN_CCK1];
+ linkq.retry[0].rflags = IWN_RFLAG_CCK;
+ } else
+ linkq.retry[0].rate = iwn_ridx_to_plcp[IWN_OFDM6];
+ linkq.retry[0].rflags |= IWN_RFLAG_ANT(txant);
+ /* Use same bit-rate for all TX retries. */
for (i = 1; i < IWN_MAX_TX_RETRIES; i++) {
- mrr.table[i].rate = mrr.table[0].rate;
- mrr.table[i].rflags = mrr.table[0].rflags;
+ linkq.retry[i].rate = linkq.retry[0].rate;
+ linkq.retry[i].rflags = linkq.retry[0].rflags;
}
- return iwn_cmd(sc, IWN_CMD_NODE_MRR_SETUP, &mrr, sizeof mrr, async);
+ return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async);
}
void
@@ -2647,7 +2859,7 @@ iwn_set_led(struct iwn_softc *sc, uint8_t which, uint8_t off, uint8_t on)
IWN_CLRBITS(sc, IWN_LED, IWN_LED_BSM_CTRL);
led.which = which;
- led.unit = htole32(1000); /* on/off in unit of 100ms */
+ led.unit = htole32(10000); /* on/off in unit of 100ms */
led.off = off;
led.on = on;
(void)iwn_cmd(sc, IWN_CMD_SET_LED, &led, sizeof led, 1);
@@ -2858,9 +3070,9 @@ iwn5000_set_txpower(struct iwn_softc *sc, int async)
* for 5000 Series.
*/
memset(&cmd, 0, sizeof cmd);
- cmd.global_limit = 2 * IWN5000_TX_POWER_MAX_DBM; /* 16 dBm */
- cmd.flags = IWN5000_TX_POWER_NO_CLOSED;
- cmd.srv_limit = IWN5000_TX_POWER_AUTO;
+ cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */
+ cmd.flags = IWN5000_TXPOWER_NO_CLOSED;
+ cmd.srv_limit = IWN5000_TXPOWER_AUTO;
DPRINTF(("setting TX power\n"));
return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async);
}
@@ -2879,11 +3091,11 @@ iwn4965_get_rssi(const struct iwn_rx_stat *stat)
agc = (letoh16(phy->agc) >> 7) & 0x7f;
rssi = 0;
- if (mask & (1 << 0)) /* Ant A */
+ if (mask & IWN_ANT_A)
rssi = MAX(rssi, phy->rssi[0]);
- if (mask & (1 << 1)) /* Ant B */
+ if (mask & IWN_ANT_B)
rssi = MAX(rssi, phy->rssi[2]);
- if (mask & (1 << 2)) /* Ant C */
+ if (mask & IWN_ANT_C)
rssi = MAX(rssi, phy->rssi[4]);
return rssi - agc - IWN_RSSI_TO_DBM;
@@ -3032,9 +3244,9 @@ iwn_collect_noise(struct iwn_softc *sc,
for (i = 0; i < 3; i++)
if (val - calib->rssi[i] <= 15 * 20)
sc->antmsk |= 1 << i;
- /* If neither antenna A nor antenna B are connected... */
- if ((sc->antmsk & (1 << 0 | 1 << 1)) == 0)
- sc->antmsk |= 1 << 1; /* ...mark antenna B as connected! */
+ /* If none of the TX antennas are connected, keep at least one. */
+ if ((sc->antmsk & sc->txantmsk) == 0)
+ sc->antmsk |= IWN_LSB(sc->txantmsk);
(void)hal->set_gains(sc);
calib->state = IWN_CALIB_STATE_RUN;
@@ -3043,40 +3255,41 @@ iwn_collect_noise(struct iwn_softc *sc,
/* XXX Disable RX chains with no antennas connected. */
sc->rxon.rxchain = htole16(IWN_RXCHAIN_SEL(sc->antmsk));
(void)iwn_cmd(sc, IWN_CMD_CONFIGURE, &sc->rxon, hal->rxonsz, 1);
+#endif
- /* XXX Enable power-saving mode. */
- if (ic->ic_flags & IEEE80211_F_PMGTON)
+ /* Enable power-saving mode if requested by user. */
+ if (sc->sc_ic.ic_flags & IEEE80211_F_PMGTON)
(void)iwn_set_pslevel(sc, 0, 3, 1);
-#endif
}
int
iwn4965_init_gains(struct iwn_softc *sc)
{
- struct iwn_phy_calib_cmd cmd;
+ struct iwn_phy_calib_gain cmd;
memset(&cmd, 0, sizeof cmd);
- cmd.code = IWN4965_SET_DIFF_GAIN;
+ cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN;
/* Differential gains initially set to 0 for all 3 antennas. */
DPRINTF(("setting initial differential gains\n"));
- return iwn_cmd(sc, IWN_PHY_CALIB, &cmd, sizeof cmd, 1);
+ return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
}
int
iwn5000_init_gains(struct iwn_softc *sc)
{
- uint32_t code;
+ struct iwn_phy_calib cmd;
- code = htole32(IWN5000_PHY_CALIB_RESET_NOISE_GAIN);
+ memset(&cmd, 0, sizeof cmd);
+ cmd.code = IWN5000_PHY_CALIB_RESET_NOISE_GAIN;
DPRINTF(("setting initial differential gains\n"));
- return iwn_cmd(sc, IWN_PHY_CALIB, &code, sizeof code, 1);
+ return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
}
int
iwn4965_set_gains(struct iwn_softc *sc)
{
struct iwn_calib_state *calib = &sc->calib;
- struct iwn_phy_calib_cmd cmd;
+ struct iwn_phy_calib_gain cmd;
int i, delta, noise;
/* Get minimal noise among connected antennas. */
@@ -3086,25 +3299,29 @@ iwn4965_set_gains(struct iwn_softc *sc)
noise = MIN(calib->noise[i], noise);
memset(&cmd, 0, sizeof cmd);
- cmd.code = IWN4965_SET_DIFF_GAIN;
+ cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN;
/* Set differential gains for connected antennas. */
for (i = 0; i < 3; i++) {
if (sc->antmsk & (1 << i)) {
- delta = ((int32_t)calib->noise[i] - noise) / 30;
- cmd.gain[i] = MIN(delta, 3);
- cmd.gain[i] |= 1 << 2;
+ /* Compute attenuation (in unit of 1.5dB). */
+ delta = (noise - (int32_t)calib->noise[i]) / 30;
+ /* NB: delta <= 0 */
+ /* Limit to [-4.5dB,0]. */
+ cmd.gain[i] = MIN(abs(delta), 3);
+ if (delta < 0)
+ cmd.gain[i] |= 1 << 2; /* sign bit */
}
}
DPRINTF(("setting differential gains Ant A/B/C: %x/%x/%x (%x)\n",
cmd.gain[0], cmd.gain[1], cmd.gain[2], sc->antmsk));
- return iwn_cmd(sc, IWN_PHY_CALIB, &cmd, sizeof cmd, 1);
+ return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
}
int
iwn5000_set_gains(struct iwn_softc *sc)
{
struct iwn_calib_state *calib = &sc->calib;
- struct iwn_phy_calib_cmd cmd;
+ struct iwn_phy_calib_gain cmd;
int i, delta;
memset(&cmd, 0, sizeof cmd);
@@ -3115,7 +3332,7 @@ iwn5000_set_gains(struct iwn_softc *sc)
/* The delta is relative to antenna A. */
delta = ((int32_t)calib->noise[0] -
(int32_t)calib->noise[i]) / 30;
- /* Limit differential gain to [-3,+3]. */
+ /* Limit to [-4.5dB,+4.5dB]. */
cmd.gain[i] = MIN(abs(delta), 3);
if (delta < 0)
cmd.gain[i] |= 1 << 2; /* sign bit */
@@ -3123,7 +3340,7 @@ iwn5000_set_gains(struct iwn_softc *sc)
}
DPRINTF(("setting differential gains Ant A/B/C: %x/%x/%x (%x)\n",
cmd.gain[0], cmd.gain[1], cmd.gain[2], sc->antmsk));
- return iwn_cmd(sc, IWN_PHY_CALIB, &cmd, sizeof cmd, 1);
+ return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
}
/*
@@ -3265,7 +3482,7 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats)
calib->noise_ref = noise_ref;
if (calib->cck_state == IWN_CCK_STATE_HIFA) {
- /* previous interval had many false alarms */
+ /* Previous interval had many false alarms. */
dec(calib->energy_cck, 8, energy_min);
}
calib->cck_state = IWN_CCK_STATE_INIT;
@@ -3305,7 +3522,7 @@ iwn_send_sensitivity(struct iwn_softc *sc)
calib->ofdm_x1, calib->ofdm_mrc_x1, calib->ofdm_x4,
calib->ofdm_mrc_x4, calib->cck_x4, calib->cck_mrc_x4,
calib->energy_cck));
- return iwn_cmd(sc, IWN_SENSITIVITY, &cmd, sizeof cmd, 1);
+ return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, sizeof cmd, 1);
}
/*
@@ -3370,12 +3587,10 @@ iwn_config(struct iwn_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
struct iwn_bluetooth bluetooth;
- struct iwn_node_info node;
uint16_t rxchain;
- uint8_t rate;
int error;
- /* Set power-saving level to CAM during initialization. */
+ /* Set power saving level to CAM during initialization. */
if ((error = iwn_set_pslevel(sc, 0, 0, 0)) != 0) {
printf("%s: could not set power saving level\n",
sc->sc_dev.dv_xname);
@@ -3410,17 +3625,6 @@ iwn_config(struct iwn_softc *sc)
sc->rxon.mode = IWN_MODE_STA;
sc->rxon.filter = htole32(IWN_FILTER_MULTICAST);
break;
-#ifndef IEEE80211_STA_ONLY
-#ifdef notyet
- case IEEE80211_M_IBSS:
- case IEEE80211_M_AHDEMO:
- sc->rxon.mode = IWN_MODE_IBSS;
- break;
- case IEEE80211_M_HOSTAP:
- sc->rxon.mode = IWN_MODE_HOSTAP;
- break;
-#endif
-#endif
case IEEE80211_M_MONITOR:
sc->rxon.mode = IWN_MODE_MONITOR;
sc->rxon.filter = htole32(IWN_FILTER_MULTICAST |
@@ -3450,24 +3654,11 @@ iwn_config(struct iwn_softc *sc)
return error;
}
- /* Add broadcast node. */
- memset(&node, 0, sizeof node);
- IEEE80211_ADDR_COPY(node.macaddr, etherbroadcastaddr);
- node.id = hal->broadcast_id;
- DPRINTF(("adding broadcast node\n"));
- error = hal->add_node(sc, &node, 0);
- if (error != 0) {
+ if ((error = iwn_add_broadcast_node(sc, 0)) != 0) {
printf("%s: could not add broadcast node\n",
sc->sc_dev.dv_xname);
return error;
}
- DPRINTF(("setting fixed rate for node %d\n", node.id));
- rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 12 : 2;
- if ((error = iwn_set_fixed_rate(sc, node.id, rate, 0)) != 0) {
- printf("%s: could not setup MRR for node %d\n",
- sc->sc_dev.dv_xname, node.id);
- return error;
- }
if ((error = iwn_set_critical_temp(sc)) != 0) {
printf("%s: could not set critical temperature\n",
@@ -3477,60 +3668,32 @@ iwn_config(struct iwn_softc *sc)
return 0;
}
-/*
- * Send a scan request to the firmware. Since this command is huge, we map
- * it into an mbuf instead of using the pre-allocated set of commands.
- */
int
iwn_scan(struct iwn_softc *sc, uint16_t flags)
{
- const struct iwn_hal *hal = sc->sc_hal;
struct ieee80211com *ic = &sc->sc_ic;
- struct iwn_tx_ring *ring = &sc->txq[4];
- struct iwn_tx_desc *desc;
- struct iwn_tx_data *data;
- struct iwn_tx_cmd *cmd;
- struct iwn_cmd_data *tx;
struct iwn_scan_hdr *hdr;
+ struct iwn_cmd_data *tx;
struct iwn_scan_essid *essid;
struct iwn_scan_chan *chan;
struct ieee80211_frame *wh;
struct ieee80211_rateset *rs;
struct ieee80211_channel *c;
- uint8_t *frm;
+ uint8_t *buf, *frm;
uint16_t rxchain;
- int pktlen, error;
+ uint8_t txant;
+ int buflen, error;
- desc = &ring->desc[ring->cur];
- data = &ring->data[ring->cur];
-
- MGETHDR(data->m, M_DONTWAIT, MT_DATA);
- if (data->m == NULL) {
- printf("%s: could not allocate mbuf for scan command\n",
+ buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (buf == NULL) {
+ printf("%s: could not allocate buffer for scan command\n",
sc->sc_dev.dv_xname);
return ENOMEM;
}
- MCLGET(data->m, M_DONTWAIT);
- if (!(data->m->m_flags & M_EXT)) {
- m_freem(data->m);
- data->m = NULL;
- printf("%s: could not allocate mbuf for scan command\n",
- sc->sc_dev.dv_xname);
- return ENOMEM;
- }
-
- cmd = mtod(data->m, struct iwn_tx_cmd *);
- cmd->code = IWN_CMD_SCAN;
- cmd->flags = 0;
- cmd->qid = ring->qid;
- cmd->idx = ring->cur;
-
- hdr = (struct iwn_scan_hdr *)cmd->data;
- memset(hdr, 0, sizeof (struct iwn_scan_hdr));
+ hdr = (struct iwn_scan_hdr *)buf;
/*
- * Move to the next channel if no packets are received within 10 msecs
- * after sending the probe request (this helps to reduce the duration
- * of active scans).
+ * Move to the next channel if no frames are received within 10ms
+ * after sending the probe request.
*/
hdr->quiet_time = htole16(10); /* timeout in milliseconds */
hdr->quiet_threshold = htole16(1); /* min # of packets */
@@ -3538,18 +3701,18 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags)
/* Select antennas for scanning. */
rxchain = IWN_RXCHAIN_FORCE | IWN_RXCHAIN_VALID(IWN_ANT_ABC) |
IWN_RXCHAIN_MIMO(IWN_ANT_ABC);
- if (sc->hw_type == IWN_HW_REV_TYPE_4965) {
- /* Ant A must be avoided because of an HW bug in 5GHz. */
+ if ((flags & IEEE80211_CHAN_5GHZ) &&
+ sc->hw_type == IWN_HW_REV_TYPE_4965) {
+ /* Ant A must be avoided in 5GHz because of an HW bug. */
rxchain |= IWN_RXCHAIN_SEL(IWN_ANT_B | IWN_ANT_C);
} else /* Use all available RX antennas. */
- rxchain |= IWN_RXCHAIN_SEL((1 << sc->nrxchains) - 1);
+ rxchain |= IWN_RXCHAIN_SEL(IWN_ANT_ABC);
hdr->rxchain = htole16(rxchain);
hdr->filter = htole32(IWN_FILTER_MULTICAST | IWN_FILTER_BEACON);
tx = (struct iwn_cmd_data *)(hdr + 1);
- memset(tx, 0, sizeof (struct iwn_cmd_data));
tx->flags = htole32(IWN_TX_AUTO_SEQ);
- tx->id = hal->broadcast_id;
+ tx->id = sc->sc_hal->broadcast_id;
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
if (flags & IEEE80211_CHAN_5GHZ) {
@@ -3564,19 +3727,21 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags)
tx->rflags = IWN_RFLAG_CCK;
rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
}
- tx->rflags |= IWN_RFLAG_ANT_B;
+ /* Use the first valid TX antenna. */
+ txant = IWN_LSB(sc->txantmsk);
+ tx->rflags |= IWN_RFLAG_ANT(txant);
essid = (struct iwn_scan_essid *)(tx + 1);
- memset(essid, 0, 20 * sizeof (struct iwn_scan_essid));
- essid[0].id = IEEE80211_ELEMID_SSID;
- essid[0].len = ic->ic_des_esslen;
- memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen);
-
+ if (ic->ic_des_esslen != 0) {
+ essid[0].id = IEEE80211_ELEMID_SSID;
+ essid[0].len = ic->ic_des_esslen;
+ memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen);
+ }
/*
* Build a probe request frame. Most of the following code is a
* copy & paste of what is done in net80211.
*/
- wh = (struct ieee80211_frame *)&essid[20];
+ wh = (struct ieee80211_frame *)(essid + 20);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
IEEE80211_FC0_SUBTYPE_PROBE_REQ;
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
@@ -3587,7 +3752,7 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags)
*(u_int16_t *)&wh->i_seq[0] = 0; /* filled by HW */
frm = (uint8_t *)(wh + 1);
- frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
+ frm = ieee80211_add_ssid(frm, NULL, 0);
frm = ieee80211_add_rates(frm, rs);
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
frm = ieee80211_add_xrates(frm, rs);
@@ -3602,20 +3767,20 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags)
continue;
chan->chan = htole16(ieee80211_chan2ieee(ic, c));
- chan->type = 0;
- if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) {
- chan->type |= IWN_CHAN_ACTIVE;
- if (ic->ic_des_esslen != 0)
- chan->type |= IWN_CHAN_DIRECT;
- }
+ DPRINTFN(2, ("adding channel %d\n", chan->chan));
+ chan->flags = 0;
+ if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE))
+ chan->flags |= htole32(IWN_CHAN_ACTIVE);
+ if (ic->ic_des_esslen != 0)
+ chan->flags |= htole32(IWN_CHAN_NPBREQS(1));
chan->dsp_gain = 0x6e;
if (IEEE80211_IS_CHAN_5GHZ(c)) {
chan->rf_gain = 0x3b;
- chan->active = htole16(10);
+ chan->active = htole16(24);
chan->passive = htole16(110);
} else {
chan->rf_gain = 0x28;
- chan->active = htole16(20);
+ chan->active = htole16(36);
chan->passive = htole16(120);
}
hdr->nchan++;
@@ -3624,31 +3789,13 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags)
frm += sizeof (struct iwn_scan_chan);
}
- hdr->len = htole16(frm - (uint8_t *)hdr);
- pktlen = frm - (uint8_t *)cmd;
+ buflen = frm - (uint8_t *)hdr;
+ hdr->len = htole16(buflen);
- error = bus_dmamap_load(sc->sc_dmat, data->map, cmd, pktlen, NULL,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- printf("%s: could not map scan command\n",
- sc->sc_dev.dv_xname);
- m_freem(data->m);
- data->m = NULL;
- return error;
- }
-
- IWN_SET_DESC_NSEGS(desc, 1);
- IWN_SET_DESC_SEG(desc, 0, data->map->dm_segs[0].ds_addr,
- data->map->dm_segs[0].ds_len);
-
- /* Update TX scheduler. */
- hal->update_sched(sc, ring->qid, ring->cur, 0, 0);
-
- /* Kick command ring. */
- ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
- IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
-
- return 0;
+ DPRINTF(("sending scan command nchan=%d\n", hdr->nchan));
+ error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1);
+ free(buf, M_DEVBUF);
+ return error;
}
int
@@ -3657,8 +3804,6 @@ iwn_auth(struct iwn_softc *sc)
const struct iwn_hal *hal = sc->sc_hal;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = ic->ic_bss;
- struct iwn_node_info node;
- uint8_t rate;
int error;
/* Update adapter's configuration. */
@@ -3697,28 +3842,15 @@ iwn_auth(struct iwn_softc *sc)
printf("%s: could not set TX power\n", sc->sc_dev.dv_xname);
return error;
}
-
/*
- * Reconfiguring clears the adapter's nodes table so we must add
- * the broadcast node again.
+ * Reconfiguring RXON clears the firmware's nodes table so we must
+ * add the broadcast node again.
*/
- memset(&node, 0, sizeof node);
- IEEE80211_ADDR_COPY(node.macaddr, etherbroadcastaddr);
- node.id = hal->broadcast_id;
- DPRINTF(("adding broadcast node\n"));
- error = hal->add_node(sc, &node, 1);
- if (error != 0) {
+ if ((error = iwn_add_broadcast_node(sc, 1)) != 0) {
printf("%s: could not add broadcast node\n",
sc->sc_dev.dv_xname);
return error;
}
- DPRINTF(("setting fixed rate for node %d\n", node.id));
- rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 12 : 2;
- if ((error = iwn_set_fixed_rate(sc, node.id, rate, 1)) != 0) {
- printf("%s: could not setup MRR for broadcast node\n",
- sc->sc_dev.dv_xname, node.id);
- return error;
- }
return 0;
}
@@ -3732,7 +3864,7 @@ iwn_run(struct iwn_softc *sc)
int error;
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
- /* link LED blinks while monitoring */
+ /* Link LED blinks while monitoring. */
iwn_set_led(sc, IWN_LED_LINK, 5, 5);
return 0;
}
@@ -3765,6 +3897,7 @@ iwn_run(struct iwn_softc *sc)
}
/* Add BSS node. */
+ ((struct iwn_node *)ni)->id = IWN_ID_BSS;
memset(&node, 0, sizeof node);
IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr);
node.id = IWN_ID_BSS;
@@ -3778,17 +3911,15 @@ iwn_run(struct iwn_softc *sc)
printf("%s: could not add BSS node\n", sc->sc_dev.dv_xname);
return error;
}
- DPRINTF(("setting MRR for node %d\n", node.id));
- if ((error = iwn_setup_node_mrr(sc, ni, node.id)) != 0) {
- printf("%s: could not setup MRR for node %d\n",
+ DPRINTF(("setting link quality for node %d\n", node.id));
+ if ((error = iwn_set_link_quality(sc, ni)) != 0) {
+ printf("%s: could not setup link quality for node %d\n",
sc->sc_dev.dv_xname, node.id);
return error;
}
- if (ic->ic_opmode == IEEE80211_M_STA) {
- /* Fake a join to initialize the TX rate. */
- iwn_newassoc(ic, ni, 1);
- }
+ /* Fake a join to initialize the TX rate. */
+ iwn_newassoc(ic, ni, 1);
if ((error = iwn_init_sensitivity(sc)) != 0) {
printf("%s: could not set sensitivity\n",
@@ -3806,38 +3937,168 @@ iwn_run(struct iwn_softc *sc)
}
int
-iwn4965_addba(struct iwn_softc *sc, struct ieee80211_node *ni, int qid,
- int tid, int ssn)
+iwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
{
+ struct iwn_softc *sc = (void *)ic;
+ const struct iwn_hal *hal = sc->sc_hal;
+ struct iwn_node *wn = (void *)ni;
+ struct iwn_node_info node;
+ uint16_t kflags;
+
+ /*
+ * We support CCMP hardware encryption/decryption only. Hardware
+ * support for TKIP really sucks and it is not worth implementing.
+ * We should leave TKIP die anyway.
+ */
+ if (k->k_cipher != IEEE80211_CIPHER_CCMP)
+ return ieee80211_set_key(ic, ni, k);
+
+ kflags = IWN_KFLAG_CCMP | IWN_KFLAG_MAP | IWN_KFLAG_KID(k->k_id);
+ if (k->k_flags & IEEE80211_KEY_GROUP)
+ kflags |= IWN_KFLAG_GROUP;
+
+ memset(&node, 0, sizeof node);
+ node.id = (k->k_flags & IEEE80211_KEY_GROUP) ?
+ hal->broadcast_id : wn->id;
+ node.control = IWN_NODE_UPDATE;
+ node.flags = IWN_FLAG_SET_KEY;
+ node.kflags = htole16(kflags);
+ node.kid = k->k_id;
+ memcpy(node.key, k->k_key, k->k_len);
+ return hal->add_node(sc, &node, 1);
+}
+
+void
+iwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
+{
+ struct iwn_softc *sc = (void *)ic;
+ const struct iwn_hal *hal = sc->sc_hal;
+ struct iwn_node *wn = (void *)ni;
+ struct iwn_node_info node;
+
+ if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
+ /* See comment about other ciphers above. */
+ ieee80211_delete_key(ic, ni, k);
+ return;
+ }
+ if (ic->ic_state != IEEE80211_S_RUN)
+ return; /* Nothing to do. */
+ memset(&node, 0, sizeof node);
+ node.id = (k->k_flags & IEEE80211_KEY_GROUP) ?
+ hal->broadcast_id : wn->id;
+ node.control = IWN_NODE_UPDATE;
+ node.flags = IWN_FLAG_SET_KEY;
+ node.kflags = htole16(IWN_KFLAG_INVALID);
+ node.kid = 0xff;
+ (void)hal->add_node(sc, &node, 1);
+}
+
+/*
+ * This function is called by upper layer when a ADDBA request is received
+ * from another STA and before the ADDBA response is sent.
+ */
+int
+iwn_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
+ uint8_t tid, uint16_t ssn)
+{
+ struct iwn_softc *sc = (void *)ic;
+ struct iwn_node *wn = (void *)ni;
+ struct iwn_node_info node;
+
+ memset(&node, 0, sizeof node);
+ node.id = wn->id;
+ node.control = IWN_NODE_UPDATE;
+ node.flags = IWN_FLAG_SET_ADDBA;
+ node.addba_tid = tid;
+ node.addba_ssn = htole16(ssn);
+ DPRINTFN(2, ("ADDBA RA=%d TID=%d SSN=%d\n", wn->id, tid, ssn));
+ return sc->sc_hal->add_node(sc, &node, 1);
+}
+
+/*
+ * This function is called by upper layer on teardown of an HT-immediate
+ * Block Ack (eg. uppon receipt of a DELBA frame.)
+ */
+void
+iwn_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
+ uint8_t tid, uint16_t ssn)
+{
+ struct iwn_softc *sc = (void *)ic;
+ struct iwn_node *wn = (void *)ni;
+ struct iwn_node_info node;
+
+ memset(&node, 0, sizeof node);
+ node.id = wn->id;
+ node.control = IWN_NODE_UPDATE;
+ node.flags = IWN_FLAG_SET_DELBA;
+ node.delba_tid = tid;
+ DPRINTFN(2, ("DELBA RA=%d TID=%d\n", wn->id, tid));
+ (void)sc->sc_hal->add_node(sc, &node, 1);
+}
+
+/*
+ * This function is called by upper layer when a ADDBA response is received
+ * from another STA.
+ */
+int
+iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
+ uint8_t tid, uint16_t ssn)
+{
+ struct iwn_softc *sc = (void *)ic;
const struct iwn_hal *hal = sc->sc_hal;
struct iwn_node *wn = (void *)ni;
struct iwn_node_info node;
- uint32_t tmp;
int error;
- /* Enable TID for RA. */
+ /* Enable TX for the specified RA/TID. */
wn->disable_tid &= ~(1 << tid);
memset(&node, 0, sizeof node);
+ node.id = wn->id;
node.control = IWN_NODE_UPDATE;
node.flags = IWN_FLAG_SET_DISABLE_TID;
node.disable_tid = htole16(wn->disable_tid);
- if ((error = hal->add_node(sc, &node, 1)) != 0)
+ error = hal->add_node(sc, &node, 1);
+ if (error != 0)
return error;
if ((error = iwn_nic_lock(sc)) != 0)
return error;
+ hal->ampdu_tx_start(sc, ni, tid, ssn);
+ iwn_nic_unlock(sc);
+ return 0;
+}
+
+void
+iwn_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
+ uint8_t tid, uint16_t ssn)
+{
+ struct iwn_softc *sc = (void *)ic;
+
+ if (iwn_nic_lock(sc) != 0)
+ return;
+ sc->sc_hal->ampdu_tx_stop(sc, tid, ssn);
+ iwn_nic_unlock(sc);
+}
+
+void
+iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
+ uint8_t tid, uint16_t ssn)
+{
+ struct iwn_node *wn = (void *)ni;
+ int qid = 7 + tid;
/* Stop TX scheduler while we're changing its configuration. */
iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
IWN4965_TXQ_STATUS_CHGACT);
- /* Assign (RA,TID) translation to the queue. */
+ /* Assign RA/TID translation to the queue. */
iwn_mem_write_2(sc, sc->sched_base + IWN4965_SCHED_TRANS_TBL(qid),
wn->id << 4 | tid);
/* Enable chain mode for the queue. */
- tmp = iwn_prph_read(sc, IWN4965_SCHED_QCHAIN_SEL);
- iwn_prph_write(sc, IWN4965_SCHED_QCHAIN_SEL, tmp | 1 << qid);
+ iwn_prph_setbits(sc, IWN4965_SCHED_QCHAIN_SEL, 1 << qid);
/* Set starting sequence number from the ADDBA request. */
IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ssn);
@@ -3851,26 +4112,18 @@ iwn4965_addba(struct iwn_softc *sc, struct ieee80211_node *ni, int qid,
IWN_SCHED_LIMIT << 16);
/* Enable interrupts for the queue. */
- tmp = iwn_prph_read(sc, IWN4965_SCHED_INTR_MASK);
- iwn_prph_write(sc, IWN4965_SCHED_INTR_MASK, tmp | 1 << qid);
+ iwn_prph_setbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid);
/* Mark the queue as active. */
- iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
+ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
IWN4965_TXQ_STATUS_ACTIVE | IWN4965_TXQ_STATUS_AGGR_ENA |
iwn_tid2fifo[tid] << 1);
-
- iwn_nic_unlock(sc);
- return 0;
}
-int
-iwn4965_delba(struct iwn_softc *sc, int qid, int tid, int ssn)
+void
+iwn4965_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
{
- uint32_t tmp;
- int error;
-
- if ((error = iwn_nic_lock(sc)) != 0)
- return error;
+ int qid = 7 + tid;
/* Stop TX scheduler while we're changing its configuration. */
iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
@@ -3881,54 +4134,33 @@ iwn4965_delba(struct iwn_softc *sc, int qid, int tid, int ssn)
iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn);
/* Disable interrupts for the queue. */
- tmp = iwn_prph_read(sc, IWN4965_SCHED_INTR_MASK);
- iwn_prph_write(sc, IWN4965_SCHED_INTR_MASK, tmp & ~(1 << qid));
+ iwn_prph_clrbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid);
/* Mark the queue as inactive. */
iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
IWN4965_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid] << 1);
-
- iwn_nic_unlock(sc);
- return 0;
}
-int
-iwn5000_addba(struct iwn_softc *sc, struct ieee80211_node *ni, int qid,
- int tid, int ssn)
+void
+iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
+ uint8_t tid, uint16_t ssn)
{
- const struct iwn_hal *hal = sc->sc_hal;
struct iwn_node *wn = (void *)ni;
- struct iwn_node_info node;
- uint32_t tmp;
- int error;
-
- /* Enable TID for RA. */
- wn->disable_tid &= ~(1 << tid);
- memset(&node, 0, sizeof node);
- node.control = IWN_NODE_UPDATE;
- node.flags = IWN_FLAG_SET_DISABLE_TID;
- node.disable_tid = htole16(wn->disable_tid);
- if ((error = hal->add_node(sc, &node, 1)) != 0)
- return error;
-
- if ((error = iwn_nic_lock(sc)) != 0)
- return error;
+ int qid = 10 + tid;
/* Stop TX scheduler while we're changing its configuration. */
iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
IWN5000_TXQ_STATUS_CHGACT);
- /* Assign (RA,TID) translation to the queue. */
+ /* Assign RA/TID translation to the queue. */
iwn_mem_write_2(sc, sc->sched_base + IWN5000_SCHED_TRANS_TBL(qid),
wn->id << 4 | tid);
/* Enable chain mode for the queue. */
- tmp = iwn_prph_read(sc, IWN5000_SCHED_QCHAIN_SEL);
- iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, tmp | 1 << qid);
+ iwn_prph_setbits(sc, IWN5000_SCHED_QCHAIN_SEL, 1 << qid);
/* Enable aggregation for the queue. */
- tmp = iwn_prph_read(sc, IWN5000_SCHED_AGGR_SEL);
- iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, tmp | 1 << qid);
+ iwn_prph_setbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid);
/* Set starting sequence number from the ADDBA request. */
IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ssn);
@@ -3939,48 +4171,35 @@ iwn5000_addba(struct iwn_softc *sc, struct ieee80211_node *ni, int qid,
IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ);
/* Enable interrupts for the queue. */
- tmp = iwn_prph_read(sc, IWN5000_SCHED_INTR_MASK);
- iwn_prph_write(sc, IWN5000_SCHED_INTR_MASK, tmp | 1 << qid);
+ iwn_prph_setbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid);
/* Mark the queue as active. */
iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
IWN5000_TXQ_STATUS_ACTIVE | iwn_tid2fifo[tid]);
-
- iwn_nic_unlock(sc);
- return 0;
}
-int
-iwn5000_delba(struct iwn_softc *sc, int qid, int tid, int ssn)
+void
+iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
{
- uint32_t tmp;
- int error;
-
- if ((error = iwn_nic_lock(sc)) != 0)
- return error;
+ int qid = 10 + tid;
/* Stop TX scheduler while we're changing its configuration. */
iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
IWN5000_TXQ_STATUS_CHGACT);
/* Disable aggregation for the queue. */
- tmp = iwn_prph_read(sc, IWN5000_SCHED_AGGR_SEL);
- iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, tmp & ~(1 << qid));
+ iwn_prph_clrbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid);
/* Set starting sequence number from the ADDBA request. */
IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ssn);
iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn);
/* Disable interrupts for the queue. */
- tmp = iwn_prph_read(sc, IWN5000_SCHED_INTR_MASK);
- iwn_prph_write(sc, IWN5000_SCHED_INTR_MASK, tmp & ~(1 << qid));
+ iwn_prph_clrbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid);
/* Mark the queue as inactive. */
iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
IWN5000_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid]);
-
- iwn_nic_unlock(sc);
- return 0;
}
/*
@@ -4021,7 +4240,7 @@ iwn5000_send_calibration(struct iwn_softc *sc)
continue; /* No results available. */
DPRINTF(("send calibration result idx=%d len=%d\n",
idx, sc->calibcmd[idx].len));
- error = iwn_cmd(sc, IWN_PHY_CALIB, sc->calibcmd[idx].buf,
+ error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf,
sc->calibcmd[idx].len, 0);
if (error != 0) {
printf("%s: could not send calibration result\n",
@@ -4034,7 +4253,7 @@ iwn5000_send_calibration(struct iwn_softc *sc)
/*
* This function is called after the runtime firmware notifies us of its
- * readiness (called in a process context).
+ * readiness (called in a process context.)
*/
int
iwn4965_post_alive(struct iwn_softc *sc)
@@ -4084,7 +4303,7 @@ iwn4965_post_alive(struct iwn_softc *sc)
/*
* This function is called after the initialization or runtime firmware
- * notifies us of its readiness (called in a process context).
+ * notifies us of its readiness (called in a process context.)
*/
int
iwn5000_post_alive(struct iwn_softc *sc)
@@ -4127,31 +4346,31 @@ iwn5000_post_alive(struct iwn_softc *sc)
for (qid = 0; qid < 7; qid++) {
static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
- IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid] << 0);
+ IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
}
iwn_nic_unlock(sc);
- /* Configure WiMax (IEEE 802.16) coexistence. */
+ /* Configure WiMAX (IEEE 802.16e) coexistence. */
memset(&wimax, 0, sizeof wimax);
- DPRINTF(("Configuring WiMax coexistence\n"));
+ DPRINTF(("Configuring WiMAX coexistence\n"));
error = iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0);
if (error != 0) {
- printf("%s: could not configure WiMax coexistence\n",
+ printf("%s: could not configure WiMAX coexistence\n",
sc->sc_dev.dv_xname);
return error;
}
if (sc->hw_type != IWN_HW_REV_TYPE_5150) {
- struct iwn5000_phy_calib calib;
+ struct iwn5000_phy_calib_crystal cmd;
/* Perform crystal calibration. */
- memset(&calib, 0, sizeof calib);
- calib.code = IWN5000_PHY_CALIB_CRYSTAL;
- calib.data[0] = letoh32(sc->eeprom_crystal) & 0xff;
- calib.data[1] = (letoh32(sc->eeprom_crystal) >> 16) & 0xff;
+ memset(&cmd, 0, sizeof cmd);
+ cmd.code = IWN5000_PHY_CALIB_CRYSTAL;
+ cmd.data[0] = letoh32(sc->eeprom_crystal) & 0xff;
+ cmd.data[1] = (letoh32(sc->eeprom_crystal) >> 16) & 0xff;
DPRINTF(("sending crystal calibration %d, %d\n",
- calib.data[0], calib.data[1]));
- error = iwn_cmd(sc, IWN_PHY_CALIB, &calib, sizeof calib, 0);
+ cmd.data[0], cmd.data[1]));
+ error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
if (error != 0) {
printf("%s: crystal calibration failed\n",
sc->sc_dev.dv_xname);
@@ -4234,12 +4453,12 @@ iwn4965_load_firmware(struct iwn_softc *sc)
struct iwn_dma_info *dma = &sc->fw_dma;
int error;
- /* Copy initialization images into pre-allocated DMA-safe memory. */
+ /* Copy initialization sections into pre-allocated DMA-safe memory. */
memcpy(dma->vaddr, fw->init.data, fw->init.datasz);
memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ,
fw->init.text, fw->init.textsz);
- /* Tell adapter where to find initialization images. */
+ /* Tell adapter where to find initialization sections. */
if ((error = iwn_nic_lock(sc)) != 0)
return error;
iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4);
@@ -4289,9 +4508,6 @@ iwn4965_load_firmware(struct iwn_softc *sc)
return 0;
}
-/*
- * Load a firmware text or data section through Flow Handler DMA.
- */
int
iwn5000_load_firmware_section(struct iwn_softc *sc, uint32_t dst,
const uint8_t *section, int size)
@@ -4343,7 +4559,6 @@ iwn5000_load_firmware(struct iwn_softc *sc)
sc->sc_dev.dv_xname, ".text");
return error;
}
-
error = iwn5000_load_firmware_section(sc, IWN_FW_DATA_BASE,
fw->data, fw->datasz);
if (error != 0) {
@@ -4408,7 +4623,7 @@ iwn_read_firmware(struct iwn_softc *sc)
return EINVAL;
}
- /* get pointers to firmware sections */
+ /* Get pointers to firmware sections. */
fw->main.text = (const uint8_t *)(hdr + 1);
fw->main.data = fw->main.text + fw->main.textsz;
fw->init.text = fw->main.data + fw->main.datasz;
@@ -4440,7 +4655,6 @@ iwn_clock_wait(struct iwn_softc *sc)
int
iwn4965_apm_init(struct iwn_softc *sc)
{
- uint32_t tmp;
int error;
/* Disable L0s. */
@@ -4457,8 +4671,7 @@ iwn4965_apm_init(struct iwn_softc *sc)
IWN_APMG_CLK_CTRL_DMA_CLK_RQT | IWN_APMG_CLK_CTRL_BSM_CLK_RQT);
DELAY(20);
/* Disable L1. */
- tmp = iwn_prph_read(sc, IWN_APMG_PCI_STT);
- iwn_prph_write(sc, IWN_APMG_PCI_STT, tmp | IWN_APMG_PCI_STT_L1A_DIS);
+ iwn_prph_setbits(sc, IWN_APMG_PCI_STT, IWN_APMG_PCI_STT_L1A_DIS);
iwn_nic_unlock(sc);
return 0;
@@ -4467,7 +4680,6 @@ iwn4965_apm_init(struct iwn_softc *sc)
int
iwn5000_apm_init(struct iwn_softc *sc)
{
- uint32_t tmp;
int error;
/* Disable L0s. */
@@ -4490,8 +4702,7 @@ iwn5000_apm_init(struct iwn_softc *sc)
iwn_prph_write(sc, IWN_APMG_CLK_CTRL, IWN_APMG_CLK_CTRL_DMA_CLK_RQT);
DELAY(20);
/* Disable L1. */
- tmp = iwn_prph_read(sc, IWN_APMG_PCI_STT);
- iwn_prph_write(sc, IWN_APMG_PCI_STT, tmp | IWN_APMG_PCI_STT_L1A_DIS);
+ iwn_prph_setbits(sc, IWN_APMG_PCI_STT, IWN_APMG_PCI_STT_L1A_DIS);
iwn_nic_unlock(sc);
return 0;
@@ -4566,11 +4777,10 @@ iwn4965_nic_config(struct iwn_softc *sc)
int
iwn5000_nic_config(struct iwn_softc *sc)
{
- uint32_t tmp;
pcireg_t reg;
int error;
- /* Retrieve Active State Power Management (ASPM). */
+ /* Retrieve PCIe Active State Power Management (ASPM). */
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag,
sc->sc_cap_off + PCI_PCIE_LCSR);
if (reg & PCI_PCIE_LCSR_ASPM_L1) /* L1 Entry enabled. */
@@ -4589,8 +4799,7 @@ iwn5000_nic_config(struct iwn_softc *sc)
if ((error = iwn_nic_lock(sc)) != 0)
return error;
- tmp = iwn_prph_read(sc, IWN_APMG_PS);
- iwn_prph_write(sc, IWN_APMG_PS, tmp | IWN_APMG_PS_EARLY_PWROFF_DIS);
+ iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_EARLY_PWROFF_DIS);
iwn_nic_unlock(sc);
return 0;
}
@@ -4599,7 +4808,6 @@ int
iwn_hw_init(struct iwn_softc *sc)
{
const struct iwn_hal *hal = sc->sc_hal;
- uint32_t tmp;
int error, qid;
/* Clear any pending interrupts. */
@@ -4614,10 +4822,7 @@ iwn_hw_init(struct iwn_softc *sc)
/* Select VMAIN power source. */
if ((error = iwn_nic_lock(sc)) != 0)
return error;
- tmp = iwn_prph_read(sc, IWN_APMG_PS);
- tmp &= ~IWN_APMG_PS_PWR_SRC_MASK;
- tmp |= IWN_APMG_PS_PWR_SRC(IWN_APMG_PS_PWR_SRC_VMAIN);
- iwn_prph_write(sc, IWN_APMG_PS, tmp);
+ iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_PWR_SRC_MASK);
iwn_nic_unlock(sc);
/* Perform adapter-specific initialization. */
diff --git a/sys/dev/pci/if_iwnreg.h b/sys/dev/pci/if_iwnreg.h
index 8f0444b94b0..e17c7e0fb21 100644
--- a/sys/dev/pci/if_iwnreg.h
+++ b/sys/dev/pci/if_iwnreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwnreg.h,v 1.11 2008/10/13 16:37:10 damien Exp $ */
+/* $OpenBSD: if_iwnreg.h,v 1.12 2008/10/22 06:25:07 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -138,30 +138,30 @@
#define IWN_BSM_DRAM_DATA_SIZE 0x349c
#define IWN_BSM_SRAM_BASE 0x3800
-/* possible values for IWN_APMG_CLK_DIS */
+/* Possible values for IWN_APMG_CLK_DIS. */
#define IWN_APMG_CLK_DMA_RQT (1 << 9)
-/* possible flags for register IWN_HW_IF_CONFIG */
+/* Possible flags for register IWN_HW_IF_CONFIG. */
#define IWN_HW_IF_CONFIG_4965_R (1 << 4)
#define IWN_HW_IF_CONFIG_MAC_SI (1 << 8)
#define IWN_HW_IF_CONFIG_RADIO_SI (1 << 9)
#define IWN_HW_IF_CONFIG_EEPROM_LOCKED (1 << 21)
#define IWN_HW_IF_CONFIG_HAP_WAKE_L1A (1 << 23)
-/* possible flags for registers IWN_PRPH_RADDR/IWN_PRPH_WADDR */
+/* Possible flags for registers IWN_PRPH_RADDR/IWN_PRPH_WADDR. */
#define IWN_PRPH_DWORD ((sizeof (uint32_t) - 1) << 24)
-/* possible values for IWN_BSM_WR_MEM_DST */
+/* Possible values for IWN_BSM_WR_MEM_DST. */
#define IWN_FW_TEXT_BASE 0x00000000
#define IWN_FW_DATA_BASE 0x00800000
-/* possible flags for register IWN_RESET */
+/* Possible flags for register IWN_RESET. */
#define IWN_RESET_NEVO (1 << 0)
#define IWN_RESET_SW (1 << 7)
#define IWN_RESET_MASTER_DISABLED (1 << 8)
#define IWN_RESET_STOP_MASTER (1 << 9)
-/* possible flags for register IWN_GP_CNTRL */
+/* Possible flags for register IWN_GP_CNTRL. */
#define IWN_GP_CNTRL_MAC_ACCESS_ENA (1 << 0)
#define IWN_GP_CNTRL_MAC_CLOCK_READY (1 << 0)
#define IWN_GP_CNTRL_INIT_DONE (1 << 2)
@@ -169,7 +169,7 @@
#define IWN_GP_CNTRL_SLEEP (1 << 4)
#define IWN_GP_CNTRL_RFKILL (1 << 27)
-/* possibles flags for register IWN_HW_REV */
+/* Possible flags for register IWN_HW_REV. */
#define IWN_HW_REV_TYPE_SHIFT 4
#define IWN_HW_REV_TYPE_MASK 0x000000f0
#define IWN_HW_REV_TYPE_4965 0
@@ -178,32 +178,34 @@
#define IWN_HW_REV_TYPE_5150 4
#define IWN_HW_REV_TYPE_5100 5
-/* possible flags for register IWN_GIO_CHICKEN */
+/* Possible flags for register IWN_GIO_CHICKEN. */
#define IWN_GIO_CHICKEN_L1A_NO_L0S_RX (1 << 23)
#define IWN_GIO_CHICKEN_DIS_L0S_TIMER (1 << 29)
-/* possible flags for register IWN_GIO */
+/* Possible flags for register IWN_GIO. */
#define IWN_GIO_L0S_ENA (1 << 1)
-/* possible flags for register IWN_UCODE_GP1_CLR */
+/* Possible flags for register IWN_UCODE_GP1_CLR. */
#define IWN_UCODE_GP1_RFKILL (1 << 1)
#define IWN_UCODE_GP1_CMD_BLOCKED (1 << 2)
#define IWN_UCODE_GP1_CTEMP_STOP_RF (1 << 3)
-/* possible flags for register IWN_LED */
+/* Possible flags/values for register IWN_LED. */
#define IWN_LED_BSM_CTRL (1 << 5)
+#define IWN_LED_OFF 0x00000038
+#define IWN_LED_ON 0x00000078
-/* possible values for register IWN_ANA_PLL */
+/* Possible values for register IWN_ANA_PLL. */
#define IWN_ANA_PLL_INIT 0x00880300
-/* possible flags for register IWN_FH_RX_STATUS */
+/* Possible flags for register IWN_FH_RX_STATUS. */
#define IWN_FH_RX_STATUS_IDLE (1 << 24)
-/* possible flags for register IWN_BSM_WR_CTRL */
+/* Possible flags for register IWN_BSM_WR_CTRL. */
#define IWN_BSM_WR_CTRL_START_EN (1 << 30)
#define IWN_BSM_WR_CTRL_START (1 << 31)
-/* possible flags for register IWN_INT */
+/* Possible flags for register IWN_INT. */
#define IWN_INT_ALIVE (1 << 0)
#define IWN_INT_WAKEUP (1 << 1)
#define IWN_INT_SW_RX (1 << 3)
@@ -214,36 +216,37 @@
#define IWN_INT_HW_ERR (1 << 29)
#define IWN_INT_FH_RX (1 << 31)
+/* Shortcut. */
#define IWN_INT_MASK \
(IWN_INT_SW_ERR | IWN_INT_HW_ERR | IWN_INT_FH_TX | \
IWN_INT_FH_RX | IWN_INT_ALIVE | IWN_INT_WAKEUP | \
IWN_INT_SW_RX | IWN_INT_CT_REACHED | IWN_INT_RF_TOGGLED)
-/* possible flags for register IWN_FH_INT */
+/* Possible flags for register IWN_FH_INT. */
#define IWN_FH_INT_TX_CHNL(x) (1 << (x))
#define IWN_FH_INT_RX_CHNL(x) (1 << ((x) + 16))
#define IWN_FH_INT_HI_PRIOR (1 << 30)
-/* shortcuts for the above */
+/* Shortcuts for the above. */
#define IWN_FH_INT_TX \
(IWN_FH_INT_TX_CHNL(0) | IWN_FH_INT_TX_CHNL(1))
#define IWN_FH_INT_RX \
(IWN_FH_INT_RX_CHNL(0) | IWN_FH_INT_RX_CHNL(1) | IWN_FH_INT_HI_PRIOR)
-/* possible flags/values for register IWN_FH_TX_CONFIG */
+/* Possible flags/values for register IWN_FH_TX_CONFIG. */
#define IWN_FH_TX_CONFIG_DMA_PAUSE 0
#define IWN_FH_TX_CONFIG_DMA_ENA (1 << 31)
#define IWN_FH_TX_CONFIG_CIRQ_HOST_ENDTFD (1 << 20)
-/* possible values for register IWN_FH_TXBUF_STATUS */
+/* Possible flags/values for register IWN_FH_TXBUF_STATUS. */
#define IWN_FH_TXBUF_STATUS_TBNUM(x) ((x) << 20)
#define IWN_FH_TXBUF_STATUS_TBIDX(x) ((x) << 12)
#define IWN_FH_TXBUF_STATUS_TFBD_VALID 3
-/* possible flags for register IWN_FH_TX_STATUS */
+/* Possible flags for register IWN_FH_TX_STATUS. */
#define IWN_FH_TX_STATUS_IDLE(chnl) \
(1 << ((chnl) + 24) | 1 << ((chnl) + 16))
-/* possible flags for register IWN_FH_RX_CONFIG */
+/* Possible flags for register IWN_FH_RX_CONFIG. */
#define IWN_FH_RX_CONFIG_ENA (1 << 31)
#define IWN_FH_RX_CONFIG_NRBD(x) ((x) << 20)
#define IWN_FH_RX_CONFIG_RB_SIZE_8K (1 << 16)
@@ -251,15 +254,15 @@
#define IWN_FH_RX_CONFIG_RB_TIMEOUT(x) ((x) << 4)
#define IWN_FH_RX_CONFIG_IGN_RXF_EMPTY (1 << 2)
-/* possible flags for register IWN_FH_TX_CONFIG */
+/* Possible flags for register IWN_FH_TX_CONFIG. */
#define IWN_FH_TX_CONFIG_DMA_ENA (1 << 31)
#define IWN_FH_TX_CONFIG_DMA_CREDIT_ENA (1 << 3)
-/* possible flags for register IWN_EEPROM */
+/* Possible flags for register IWN_EEPROM. */
#define IWN_EEPROM_READ_VALID (1 << 0)
#define IWN_EEPROM_CMD (1 << 1)
-/* possible flags for register IWN5000_SCHED_QUEUE_STATUS */
+/* Possible flags for register IWN_SCHED_QUEUE_STATUS. */
#define IWN4965_TXQ_STATUS_ACTIVE 0x0007fc01
#define IWN4965_TXQ_STATUS_INACTIVE 0x0007fc00
#define IWN4965_TXQ_STATUS_AGGR_ENA (1 << 5 | 1 << 8)
@@ -268,20 +271,20 @@
#define IWN5000_TXQ_STATUS_INACTIVE 0x00ff0010
#define IWN5000_TXQ_STATUS_CHGACT (1 << 19)
-/* possible flags for register IWN_APMG_CLK_CTRL */
+/* Possible flags for register IWN_APMG_CLK_CTRL. */
#define IWN_APMG_CLK_CTRL_DMA_CLK_RQT (1 << 9)
#define IWN_APMG_CLK_CTRL_BSM_CLK_RQT (1 << 11)
-/* possible flags for register IWN_APMG_PS */
+/* Possible flags for register IWN_APMG_PS. */
#define IWN_APMG_PS_EARLY_PWROFF_DIS (1 << 22)
#define IWN_APMG_PS_PWR_SRC_MASK (3 << 24)
#define IWN_APMG_PS_PWR_SRC(x) ((x) << 24)
#define IWN_APMG_PS_PWR_SRC_VMAIN 0
-/* possible flags for IWN_APMG_PCI_STT */
+/* Possible flags for IWN_APMG_PCI_STT. */
#define IWN_APMG_PCI_STT_L1A_DIS (1 << 11)
-/* possible flags for register IWN_BSM_DRAM_TEXT_SIZE */
+/* Possible flags for register IWN_BSM_DRAM_TEXT_SIZE. */
#define IWN_FW_UPDATED (1 << 31)
#define IWN_SCHED_WINSZ 64
@@ -292,20 +295,21 @@
#define IWN5000_SCHEDSZ (IWN5000_NTXQUEUES * IWN5000_SCHED_COUNT * 2)
struct iwn_tx_desc {
- uint32_t flags;
+ uint8_t reserved1[3];
+ uint8_t nsegs;
struct {
uint32_t w1;
uint32_t w2;
uint32_t w3;
} __packed segs[IWN_MAX_SCATTER / 2];
- /* pad to 128 bytes */
- uint32_t reserved;
+ /* Pad to 128 bytes. */
+ uint32_t reserved2;
} __packed;
#define IWN_SET_DESC_NSEGS(d, x) \
- (d)->flags = htole32(((x) & 0x1f) << 24)
+ (d)->nsegs = (x)
-/* set a segment physical address and length in a Tx descriptor */
+/* Set a segment physical address and length in a TX descriptor. */
#define IWN_SET_DESC_SEG(d, n, addr, size) do { \
if ((n) & 1) { \
(d)->segs[(n) / 2].w2 |= \
@@ -340,8 +344,8 @@ struct iwn_rx_desc {
#define IWN_BEACON_STATISTICS 157
#define IWN_STATE_CHANGED 161
#define IWN_BEACON_MISSED 162
-#define IWN_AMPDU_RX_START 192
-#define IWN_AMPDU_RX_DONE 193
+#define IWN_RX_PHY 192
+#define IWN_MPDU_RX_DONE 193
#define IWN_RX_DONE 195
uint8_t flags;
@@ -349,10 +353,10 @@ struct iwn_rx_desc {
uint8_t qid;
} __packed;
-/* possible Rx status flags */
+/* Possible RX status flags. */
#define IWN_RX_NO_CRC_ERR (1 << 0)
#define IWN_RX_NO_OVFL_ERR (1 << 1)
-/* shortcut for the above */
+/* Shortcut for the above. */
#define IWN_RX_NOERROR (IWN_RX_NO_CRC_ERR | IWN_RX_NO_OVFL_ERR)
struct iwn_tx_cmd {
@@ -363,7 +367,7 @@ struct iwn_tx_cmd {
#define IWN_CMD_TIMING 20
#define IWN_CMD_ADD_NODE 24
#define IWN_CMD_TX_DATA 28
-#define IWN_CMD_NODE_MRR_SETUP 78
+#define IWN_CMD_LINK_QUALITY 78
#define IWN_CMD_SET_LED 72
#define IWN5000_CMD_WIMAX_COEX 90
#define IWN5000_CMD_CALIB_CONFIG 101
@@ -374,8 +378,8 @@ struct iwn_tx_cmd {
#define IWN_CMD_BT_COEX 155
#define IWN_CMD_GET_STATISTICS 156
#define IWN_CMD_SET_CRITICAL_TEMP 164
-#define IWN_SENSITIVITY 168
-#define IWN_PHY_CALIB 176
+#define IWN_CMD_SET_SENSITIVITY 168
+#define IWN_CMD_PHY_CALIB 176
uint8_t flags;
uint8_t idx;
@@ -383,7 +387,14 @@ struct iwn_tx_cmd {
uint8_t data[136];
} __packed;
-/* structure for command IWN_CMD_CONFIGURE */
+/* Antenna flags, used in various commands. */
+#define IWN_ANT_A (1 << 0)
+#define IWN_ANT_B (1 << 1)
+#define IWN_ANT_C (1 << 2)
+/* Shortcut. */
+#define IWN_ANT_ABC (IWN_ANT_A | IWN_ANT_B | IWN_ANT_C)
+
+/* Structure for command IWN_CMD_CONFIGURE. */
struct iwn_rxon {
uint8_t myaddr[IEEE80211_ADDR_LEN];
uint16_t reserved1;
@@ -399,12 +410,6 @@ struct iwn_rxon {
uint8_t air;
uint16_t rxchain;
-#define IWN_ANT_A (1 << 0)
-#define IWN_ANT_B (1 << 1)
-#define IWN_ANT_C (1 << 2)
-/* Shortcut. */
-#define IWN_ANT_ABC (IWN_ANT_A | IWN_ANT_B | IWN_ANT_C)
-
#define IWN_RXCHAIN_FORCE (1 << 0)
#define IWN_RXCHAIN_VALID(x) ((x) << 1)
#define IWN_RXCHAIN_SEL(x) ((x) << 4)
@@ -413,7 +418,6 @@ struct iwn_rxon {
#define IWN_RXCHAIN_MIMO_COUNT(x) ((x) << 12)
#define IWN_RXCHAIN_MIMO_FORCE (1 << 14)
-
uint8_t ofdm_mask;
uint8_t cck_mask;
uint16_t associd;
@@ -441,7 +445,7 @@ struct iwn_rxon {
uint8_t reserved4;
uint8_t ht_single_mask;
uint8_t ht_dual_mask;
- /* the following fields are for 5000 Series only */
+ /* The following fields are for 5000 Series only. */
uint8_t ht_triple_mask;
uint8_t reserved5;
uint16_t acquisition;
@@ -451,7 +455,7 @@ struct iwn_rxon {
#define IWN4965_RXONSZ (sizeof (struct iwn_rxon) - 6)
#define IWN5000_RXONSZ (sizeof (struct iwn_rxon))
-/* structure for command IWN_CMD_ASSOCIATE */
+/* Structure for command IWN_CMD_ASSOCIATE. */
struct iwn_assoc {
uint32_t flags;
uint32_t filter;
@@ -460,7 +464,7 @@ struct iwn_assoc {
uint16_t reserved;
} __packed;
-/* structure for command IWN_CMD_EDCA_PARAMS */
+/* Structure for command IWN_CMD_EDCA_PARAMS. */
struct iwn_edca_params {
uint32_t flags;
#define IWN_EDCA_UPDATE (1 << 0)
@@ -475,7 +479,7 @@ struct iwn_edca_params {
} __packed ac[EDCA_NUM_AC];
} __packed;
-/* structure for command IWN_CMD_TIMING */
+/* Structure for command IWN_CMD_TIMING. */
struct iwn_cmd_timing {
uint64_t tstamp;
uint16_t bintval;
@@ -485,7 +489,7 @@ struct iwn_cmd_timing {
uint16_t reserved;
} __packed;
-/* structure for command IWN_CMD_ADD_NODE */
+/* Structure for command IWN_CMD_ADD_NODE. */
struct iwn_node_info {
uint8_t control;
#define IWN_NODE_UPDATE (1 << 0)
@@ -502,16 +506,25 @@ struct iwn_node_info {
uint8_t flags;
#define IWN_FLAG_SET_KEY (1 << 0)
#define IWN_FLAG_SET_DISABLE_TID (1 << 1)
+#define IWN_FLAG_SET_TXRATE (1 << 2)
+#define IWN_FLAG_SET_ADDBA (1 << 3)
+#define IWN_FLAG_SET_DELBA (1 << 4)
uint16_t reserved3;
+ uint16_t kflags;
+#define IWN_KFLAG_CCMP (1 << 1)
+#define IWN_KFLAG_MAP (1 << 3)
+#define IWN_KFLAG_KID(kid) ((kid) << 8)
+#define IWN_KFLAG_INVALID (1 << 11)
+#define IWN_KFLAG_GROUP (1 << 14)
- uint16_t keyflags;
uint8_t tsc2; /* TKIP TSC2 */
uint8_t reserved4;
uint16_t ttak[5];
uint8_t kid;
uint8_t reserved5;
uint8_t key[16];
+ /* The following 3 fields are for 5000 Series only. */
uint64_t tsc;
uint8_t rxmic[IEEE80211_TKIP_MICLEN];
uint8_t txmic[IEEE80211_TKIP_MICLEN];
@@ -523,9 +536,8 @@ struct iwn_node_info {
uint32_t mask;
uint16_t disable_tid;
uint16_t reserved6;
-
- uint8_t addba;
- uint8_t delba;
+ uint8_t addba_tid;
+ uint8_t delba_tid;
uint16_t addba_ssn;
uint32_t reserved7;
} __packed;
@@ -538,7 +550,7 @@ struct iwn4965_node_info {
uint8_t id;
uint8_t flags;
uint16_t reserved3;
- uint16_t keyflags;
+ uint16_t kflags;
uint8_t tsc2; /* TKIP TSC2 */
uint8_t reserved4;
uint16_t ttak[5];
@@ -549,22 +561,21 @@ struct iwn4965_node_info {
uint32_t mask;
uint16_t disable_tid;
uint16_t reserved6;
- uint8_t addba;
- uint8_t delba;
+ uint8_t addba_tid;
+ uint8_t delba_tid;
uint16_t addba_ssn;
uint32_t reserved7;
} __packed;
-#define IWN_RFLAG_CCK (1 << 1)
-#define IWN_RFLAG_ANT_A (1 << 6)
-#define IWN_RFLAG_ANT_B (1 << 7)
+#define IWN_RFLAG_CCK (1 << 1)
+#define IWN_RFLAG_ANT(x) ((x) << 6)
-/* structure for command IWN_CMD_TX_DATA */
+/* Structure for command IWN_CMD_TX_DATA. */
struct iwn_cmd_data {
uint16_t len;
uint16_t lnext;
uint32_t flags;
-#define IWN5000_TX_NEED_RTS_CTS (1 << 0) /* 5000 only */
+#define IWN_TX_NEED_PROTECTION (1 << 0) /* 5000 only */
#define IWN_TX_NEED_RTS (1 << 1)
#define IWN_TX_NEED_CTS (1 << 2)
#define IWN_TX_NEED_ACK (1 << 3)
@@ -577,10 +588,7 @@ struct iwn_cmd_data {
#define IWN_TX_INSERT_TSTAMP (1 << 16)
#define IWN_TX_NEED_PADDING (1 << 20)
- uint8_t ntries;
- uint8_t bluetooth;
- uint16_t reserved1;
-
+ uint32_t scratch;
uint8_t rate;
uint8_t rflags;
uint16_t xrflags;
@@ -609,19 +617,19 @@ struct iwn_cmd_data {
uint16_t txop;
} __packed;
-/* structure for command IWN_CMD_MRR_NODE_SETUP */
+/* Structure for command IWN_CMD_LINK_QUALITY. */
#define IWN_MAX_TX_RETRIES 16
-struct iwn_cmd_mrr {
+struct iwn_cmd_link_quality {
uint8_t id;
uint8_t reserved1;
uint16_t ctl;
uint8_t flags;
uint8_t mimo;
- uint8_t ssmask;
- uint8_t dsmask;
+ uint8_t antmsk_1stream;
+ uint8_t antmsk_2stream;
uint8_t ridx[EDCA_NUM_AC];
uint16_t ampdu_limit;
- uint8_t ampdu_disable;
+ uint8_t ampdu_threshold;
uint8_t ampdu_max;
uint32_t reserved2;
struct {
@@ -632,11 +640,11 @@ struct iwn_cmd_mrr {
#define IWN_CCK11 3
#define IWN_OFDM6 4
#define IWN_OFDM54 11
- } __packed table[IWN_MAX_TX_RETRIES];
+ } __packed retry[IWN_MAX_TX_RETRIES];
uint32_t reserved3;
} __packed;
-/* structure for command IWN_CMD_SET_LED */
+/* Structure for command IWN_CMD_SET_LED. */
struct iwn_cmd_led {
uint32_t unit; /* multiplier (in usecs) */
uint8_t which;
@@ -648,7 +656,7 @@ struct iwn_cmd_led {
uint8_t reserved;
} __packed;
-/* structure for command IWN5000_CMD_WIMAX_COEX */
+/* Structure for command IWN5000_CMD_WIMAX_COEX. */
struct iwn5000_wimax_coex {
uint32_t flags;
struct {
@@ -659,7 +667,7 @@ struct iwn5000_wimax_coex {
} __packed events[16];
} __packed;
-/* structures for command IWN5000_CMD_CALIB_CONFIG */
+/* Structures for command IWN5000_CMD_CALIB_CONFIG. */
struct iwn5000_calib_elem {
uint32_t enable;
uint32_t start;
@@ -680,7 +688,7 @@ struct iwn5000_calib_config {
uint32_t reserved;
} __packed;
-/* structure for command IWN_CMD_SET_POWER_MODE */
+/* Structure for command IWN_CMD_SET_POWER_MODE. */
struct iwn_pmgt_cmd {
uint16_t flags;
#define IWN_PS_ALLOW_SLEEP (1 << 0)
@@ -697,7 +705,7 @@ struct iwn_pmgt_cmd {
uint32_t beacons;
} __packed;
-/* structures for command IWN_CMD_SCAN */
+/* Structures for command IWN_CMD_SCAN. */
struct iwn_scan_essid {
uint8_t id;
uint8_t len;
@@ -717,16 +725,16 @@ struct iwn_scan_hdr {
uint32_t flags;
uint32_t filter;
- /* followed by a struct iwn_cmd_data */
- /* followed by an array of 20 struct iwn_scan_essid */
- /* followed by probe request body */
- /* followed by nchan x struct iwn_scan_chan */
+ /* Followed by a struct iwn_cmd_data. */
+ /* Followed by an array of 20 structs iwn_scan_essid. */
+ /* Followed by probe request body. */
+ /* Followed by an array of ``nchan'' structs iwn_scan_chan. */
} __packed;
struct iwn_scan_chan {
- uint32_t type;
-#define IWN_CHAN_ACTIVE (1 << 0)
-#define IWN_CHAN_DIRECT (1 << 1)
+ uint32_t flags;
+#define IWN_CHAN_ACTIVE (1 << 0)
+#define IWN_CHAN_NPBREQS(x) (((1 << (x)) - 1) << 1)
uint16_t chan;
uint8_t rf_gain;
@@ -735,7 +743,10 @@ struct iwn_scan_chan {
uint16_t passive; /* msecs */
} __packed;
-/* structure for command IWN_CMD_TXPOWER */
+/* Maximum size of a scan command. */
+#define IWN_SCAN_MAXSZ (MCLBYTES - 4)
+
+/* Structure for command IWN_CMD_TXPOWER (4965AGN only.) */
#define IWN_RIDX_MAX 32
struct iwn4965_cmd_txpower {
uint8_t band;
@@ -748,20 +759,20 @@ struct iwn4965_cmd_txpower {
} __packed power[IWN_RIDX_MAX + 1];
} __packed;
-/* structure for command IWN_CMD_TXPOWER_DBM */
+/* Structure for command IWN_CMD_TXPOWER_DBM (5000 Series only.) */
struct iwn5000_cmd_txpower {
int8_t global_limit; /* in half-dBm */
-#define IWN5000_TX_POWER_AUTO 0x7f
-#define IWN5000_TX_POWER_MAX_DBM 16
+#define IWN5000_TXPOWER_AUTO 0x7f
+#define IWN5000_TXPOWER_MAX_DBM 16
uint8_t flags;
-#define IWN5000_TX_POWER_NO_CLOSED (1 << 6)
+#define IWN5000_TXPOWER_NO_CLOSED (1 << 6)
int8_t srv_limit; /* in half-dBm */
uint8_t reserved;
} __packed;
-/* structure for command IWN_CMD_BLUETOOTH */
+/* Structure for command IWN_CMD_BLUETOOTH. */
struct iwn_bluetooth {
uint8_t flags;
uint8_t lead;
@@ -771,18 +782,18 @@ struct iwn_bluetooth {
uint32_t cts;
} __packed;
-/* structure for command IWN_CMD_SET_CRITICAL_TEMP */
+/* Structure for command IWN_CMD_SET_CRITICAL_TEMP. */
struct iwn_critical_temp {
uint32_t reserved;
uint32_t tempM;
uint32_t tempR;
-/* degK <-> degC conversion macros */
+/* degK <-> degC conversion macros. */
#define IWN_CTOK(c) ((c) + 273)
#define IWN_KTOC(k) ((k) - 273)
#define IWN_CTOMUK(c) (((c) * 1000000) + 273150000)
} __packed;
-/* structure for command IWN_SENSITIVITY */
+/* Structure for command IWN_CMD_SET_SENSITIVITY. */
struct iwn_sensitivity_cmd {
uint16_t which;
#define IWN_SENSITIVITY_DEFAULTTBL 0
@@ -801,19 +812,10 @@ struct iwn_sensitivity_cmd {
uint16_t energy_ofdm_th;
} __packed;
-/* structure for command IWN_PHY_CALIB */
-struct iwn_phy_calib_cmd {
- uint8_t code;
-
- uint8_t flags;
- uint16_t reserved1;
- int8_t gain[3];
- uint8_t reserved2;
-} __packed;
-
-struct iwn5000_calib {
+/* Structures for command IWN_CMD_PHY_CALIB. */
+struct iwn_phy_calib {
uint8_t code;
-#define IWN4965_SET_DIFF_GAIN 7
+#define IWN4965_PHY_CALIB_DIFF_GAIN 7
#define IWN5000_PHY_CALIB_LO 9
#define IWN5000_PHY_CALIB_LO_TX_IQ 11
#define IWN5000_PHY_CALIB_CRYSTAL 15
@@ -826,18 +828,55 @@ struct iwn5000_calib {
uint8_t valid;
} __packed;
-/* structure for command IWN_PHY_CALIB */
-struct iwn5000_phy_calib {
+struct iwn5000_phy_calib_crystal {
uint8_t code;
-
uint8_t group;
uint8_t ngroups;
uint8_t valid;
+
uint8_t data[2];
} __packed;
+struct iwn_phy_calib_gain {
+ uint8_t code;
+ uint8_t group;
+ uint8_t ngroups;
+ uint8_t valid;
+
+ int8_t gain[3];
+ uint8_t reserved2;
+} __packed;
-/* structure for IWN_UC_READY notification */
+/* Structure for command IWN_CMD_SPECTRUM_MEASUREMENT. */
+struct iwn_spectrum_cmd {
+ uint16_t len;
+ uint8_t token;
+ uint8_t id;
+ uint8_t origin;
+ uint8_t periodic;
+ uint16_t timeout;
+ uint32_t start;
+ uint32_t reserved1;
+ uint32_t flags;
+ uint32_t filter;
+ uint16_t nchan;
+ uint16_t reserved2;
+ struct {
+ uint32_t duration;
+ uint8_t chan;
+ uint8_t type;
+#define IWN_MEASUREMENT_BASIC (1 << 0)
+#define IWN_MEASUREMENT_CCA (1 << 1)
+#define IWN_MEASUREMENT_RPI_HISTOGRAM (1 << 2)
+#define IWN_MEASUREMENT_NOISE_HISTOGRAM (1 << 3)
+#define IWN_MEASUREMENT_FRAME (1 << 4)
+#define IWN_MEASUREMENT_IDLE (1 << 7)
+
+ uint16_t reserved;
+ } __packed chan[10];
+} __packed;
+
+/* Structure for IWN_UC_READY notification. */
#define IWN_NATTEN_GROUPS 5
struct iwn_ucode_info {
uint8_t minor;
@@ -851,11 +890,11 @@ struct iwn_ucode_info {
uint16_t reserved2;
uint32_t logptr;
- uint32_t errorptr;
+ uint32_t errptr;
uint32_t tstamp;
uint32_t valid;
- /* the following fields are for UCODE_INIT only */
+ /* The following fields are for UCODE_INIT only. */
int32_t volt;
struct {
int32_t chan20MHz;
@@ -864,7 +903,7 @@ struct iwn_ucode_info {
int32_t atten[IWN_NATTEN_GROUPS][2];
} __packed;
-/* structure for IWN_TX_DONE notification */
+/* Structures for IWN_TX_DONE notification. */
struct iwn4965_tx_stat {
uint8_t nframes;
uint8_t killcnt;
@@ -898,7 +937,7 @@ struct iwn5000_tx_stat {
uint16_t sequence;
} __packed;
-/* structure for IWN_BEACON_MISSED notification */
+/* Structure for IWN_BEACON_MISSED notification. */
struct iwn_beacon_missed {
uint32_t consecutive;
uint32_t total;
@@ -906,14 +945,13 @@ struct iwn_beacon_missed {
uint32_t received;
} __packed;
-/* structure for IWN_AMPDU_RX_DONE notification */
-struct iwn_rx_ampdu {
+/* Structure for IWN_MPDU_RX_DONE notification. */
+struct iwn_rx_mpdu {
uint16_t len;
uint16_t reserved;
} __packed;
-/* structures for IWN_RX_DONE and IWN_AMPDU_RX_START notifications */
-
+/* Structures for IWN_RX_DONE and IWN_MPDU_RX_DONE notifications. */
struct iwn4965_rx_phystat {
uint16_t antenna;
uint16_t agc;
@@ -936,6 +974,8 @@ struct iwn_rx_stat {
uint64_t tstamp;
uint32_t beacon;
uint16_t flags;
+#define IWN_STAT_FLAG_SHPREAMBLE (1 << 2)
+
uint16_t chan;
uint8_t phybuf[32];
uint8_t rate;
@@ -947,7 +987,7 @@ struct iwn_rx_stat {
#define IWN_RSSI_TO_DBM 44
-/* structure for IWN_START_SCAN notification */
+/* Structure for IWN_START_SCAN notification. */
struct iwn_start_scan {
uint64_t tstamp;
uint32_t tbeacon;
@@ -957,7 +997,7 @@ struct iwn_start_scan {
uint32_t status;
} __packed;
-/* structure for IWN_STOP_SCAN notification */
+/* Structure for IWN_STOP_SCAN notification. */
struct iwn_stop_scan {
uint8_t nchan;
uint8_t status;
@@ -966,7 +1006,39 @@ struct iwn_stop_scan {
uint64_t tsf;
} __packed;
-/* structure for IWN_{RX,BEACON}_STATISTICS notification */
+/* Structure for IWN_SPECTRUM_MEASUREMENT notification. */
+struct iwn_spectrum_notif {
+ uint8_t id;
+ uint8_t token;
+ uint8_t idx;
+ uint8_t state;
+#define IWN_MEASUREMENT_START 0
+#define IWN_MEASUREMENT_STOP 1
+
+ uint32_t start;
+ uint8_t band;
+ uint8_t chan;
+ uint8_t type;
+ uint8_t reserved1;
+ uint32_t cca_ofdm;
+ uint32_t cca_cck;
+ uint32_t cca_time;
+ uint8_t basic;
+ uint8_t reserved2[3];
+ uint32_t ofdm[8];
+ uint32_t cck[8];
+ uint32_t stop;
+ uint32_t status;
+#define IWN_MEASUREMENT_OK 0
+#define IWN_MEASUREMENT_CONCURRENT 1
+#define IWN_MEASUREMENT_CSA_CONFLICT 2
+#define IWN_MEASUREMENT_TGH_CONFLICT 3
+#define IWN_MEASUREMENT_STOPPED 6
+#define IWN_MEASUREMENT_TIMEOUT 7
+#define IWN_MEASUREMENT_FAILED 8
+} __packed;
+
+/* Structure for IWN_{RX,BEACON}_STATISTICS notification. */
struct iwn_rx_phy_stats {
uint32_t ina;
uint32_t fina;
@@ -1083,7 +1155,20 @@ struct iwn_stats {
} __packed;
-/* firmware image header */
+/* Firmware error dump. */
+struct iwn_fw_dump {
+ uint32_t valid;
+ uint32_t id;
+ uint32_t pc;
+ uint32_t branch_link[2];
+ uint32_t interrupt_link[2];
+ uint32_t error_data[2];
+ uint32_t src_line;
+ uint32_t tsf;
+ uint32_t time[2];
+} __packed;
+
+/* Firmware image file header. */
struct iwn_firmware_hdr {
uint32_t version;
uint32_t main_textsz;
@@ -1130,10 +1215,12 @@ struct iwn_firmware_hdr {
#define IWN5000_EEPROM_BAND7 0x049
#define IWN5000_EEPROM_CRYSTAL 0x094
-/* possible flags for IWN_EEPROM_RFCFG */
-#define IWN_RFCFG_TYPE(x) (((x) >> 0) & 3)
-#define IWN_RFCFG_STEP(x) (((x) >> 2) & 3)
-#define IWN_RFCFG_DASH(x) (((x) >> 4) & 3)
+/* Possible flags for IWN_EEPROM_RFCFG. */
+#define IWN_RFCFG_TYPE(x) (((x) >> 0) & 0x3)
+#define IWN_RFCFG_STEP(x) (((x) >> 2) & 0x3)
+#define IWN_RFCFG_DASH(x) (((x) >> 4) & 0x3)
+#define IWN_RFCFG_TXANTMSK(x) (((x) >> 8) & 0xf)
+#define IWN_RFCFG_RXANTMSK(x) (((x) >> 12) & 0xf)
struct iwn_eeprom_chan {
uint8_t flags;
@@ -1358,6 +1445,42 @@ static const uint8_t iwn_tid2fifo[] = {
1, 0, 0, 1, 2, 2, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 3
};
+/* Firmware errors. */
+static const char * const iwn_fw_errmsg[] = {
+ "OK",
+ "FAIL",
+ "BAD_PARAM",
+ "BAD_CHECKSUM",
+ "NMI_INTERRUPT_WDG",
+ "SYSASSERT",
+ "FATAL_ERROR",
+ "BAD_COMMAND",
+ "HW_ERROR_TUNE_LOCK",
+ "HW_ERROR_TEMPERATURE",
+ "ILLEGAL_CHAN_FREQ",
+ "VCC_NOT_STABLE",
+ "FH_ERROR",
+ "NMI_INTERRUPT_HOST",
+ "NMI_INTERRUPT_ACTION_PT",
+ "NMI_INTERRUPT_UNKNOWN",
+ "UCODE_VERSION_MISMATCH",
+ "HW_ERROR_ABS_LOCK",
+ "HW_ERROR_CAL_LOCK_FAIL",
+ "NMI_INTERRUPT_INST_ACTION_PT",
+ "NMI_INTERRUPT_DATA_ACTION_PT",
+ "NMI_TRM_HW_ER",
+ "NMI_INTERRUPT_TRM",
+ "NMI_INTERRUPT_BREAKPOINT"
+ "DEBUG_0",
+ "DEBUG_1",
+ "DEBUG_2",
+ "DEBUG_3",
+ "UNKNOWN"
+};
+
+/* Find least significant bit that is set. */
+#define IWN_LSB(x) ((((x) - 1) & (x)) ^ (x))
+
#define IWN_READ(sc, reg) \
bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h
index 41b04bf0961..70c155f02ea 100644
--- a/sys/dev/pci/if_iwnvar.h
+++ b/sys/dev/pci/if_iwnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwnvar.h,v 1.3 2008/10/13 16:37:10 damien Exp $ */
+/* $OpenBSD: if_iwnvar.h,v 1.4 2008/10/22 06:25:07 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -181,6 +181,10 @@ struct iwn_hal {
int (*add_node)(struct iwn_softc *, struct iwn_node_info *,
int);
void (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *);
+ void (*ampdu_tx_start)(struct iwn_softc *,
+ struct ieee80211_node *, uint8_t, uint16_t);
+ void (*ampdu_tx_stop)(struct iwn_softc *, uint8_t,
+ uint16_t);
const char *fwname;
const struct iwn_sensitivity_limits *limits;
int ntxqs;
@@ -242,6 +246,7 @@ struct iwn_softc {
struct iwn_fw_info fw;
struct iwn_calib_info calibcmd[3];
+ uint32_t errptr;
struct iwn_rx_stat last_rx_stat;
int last_rx_valid;
@@ -250,7 +255,6 @@ struct iwn_softc {
uint32_t rawtemp;
int temp;
int noise;
- uint8_t antmsk;
uint32_t qfullmsk;
struct iwn4965_eeprom_band
@@ -266,6 +270,9 @@ struct iwn_softc {
uint32_t critical_temp;
uint8_t ntxchains;
uint8_t nrxchains;
+ uint8_t txantmsk;
+ uint8_t rxantmsk;
+ uint8_t antmsk;
int sc_tx_timer;
void *powerhook;