mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-19 10:53:58 +00:00
iwm(4) synchronize driver to DragonFlyBSD version and recent f/w update.
Submitted by: Kevin Bowling (kevin.bowling@kev009.com) MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D6967
This commit is contained in:
parent
33c7715f9b
commit
6a5bc1d1ee
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=303327
1784
sys/dev/iwm/if_iwm.c
1784
sys/dev/iwm/if_iwm.c
File diff suppressed because it is too large
Load Diff
@ -148,13 +148,13 @@ iwm_mvm_led_disable(struct iwm_softc *sc)
|
||||
IWM_WRITE(sc, IWM_CSR_LED_REG, IWM_CSR_LED_REG_TURN_OFF);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
iwm_mvm_led_is_enabled(struct iwm_softc *sc)
|
||||
{
|
||||
return (IWM_READ(sc, IWM_CSR_LED_REG) == IWM_CSR_LED_REG_TURN_ON);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
iwm_led_blink_timeout(void *arg)
|
||||
{
|
||||
struct iwm_softc *sc = arg;
|
||||
@ -177,6 +177,6 @@ iwm_led_blink_start(struct iwm_softc *sc)
|
||||
void
|
||||
iwm_led_blink_stop(struct iwm_softc *sc)
|
||||
{
|
||||
callout_drain(&sc->sc_led_blink_to);
|
||||
callout_stop(&sc->sc_led_blink_to);
|
||||
iwm_mvm_led_disable(sc);
|
||||
}
|
||||
|
@ -91,11 +91,9 @@
|
||||
#ifndef __IF_IWM_LED_H__
|
||||
#define __IF_IWM_LED_H__
|
||||
|
||||
void iwm_mvm_led_enable(struct iwm_softc *);
|
||||
void iwm_mvm_led_disable(struct iwm_softc *);
|
||||
int iwm_mvm_led_is_enabled(struct iwm_softc *);
|
||||
void iwm_led_blink_timeout(void *);
|
||||
void iwm_led_blink_start(struct iwm_softc *);
|
||||
void iwm_led_blink_stop(struct iwm_softc *);
|
||||
extern void iwm_mvm_led_enable(struct iwm_softc *);
|
||||
extern void iwm_mvm_led_disable(struct iwm_softc *);
|
||||
extern void iwm_led_blink_start(struct iwm_softc *);
|
||||
extern void iwm_led_blink_stop(struct iwm_softc *);
|
||||
|
||||
#endif /* __IF_IWM_LED_H__ */
|
||||
|
@ -280,12 +280,24 @@ iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
|
||||
/*
|
||||
* XXX should we error out if in_assoc is 1 and ni == NULL?
|
||||
*/
|
||||
#if 0
|
||||
if (in->in_assoc) {
|
||||
IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
|
||||
} else {
|
||||
/* eth broadcast address */
|
||||
memset(cmd->bssid_addr, 0xff, sizeof(cmd->bssid_addr));
|
||||
IEEE80211_ADDR_COPY(cmd->bssid_addr, ieee80211broadcastaddr);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* XXX This workaround makes the firmware behave more correctly once
|
||||
* we are associated, regularly giving us statistics notifications,
|
||||
* as well as signaling missed beacons to us.
|
||||
* Since we only call iwm_mvm_mac_ctxt_add() and
|
||||
* iwm_mvm_mac_ctxt_changed() when already authenticating or
|
||||
* associating, ni->ni_bssid should always make sense here.
|
||||
*/
|
||||
IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default to 2ghz if no node information is given.
|
||||
@ -457,13 +469,7 @@ static int
|
||||
iwm_mvm_mac_ctx_send(struct iwm_softc *sc, struct ieee80211vap *vap,
|
||||
uint32_t action)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iwm_mvm_mac_ctxt_cmd_station(sc, vap, action);
|
||||
if (ret)
|
||||
return (ret);
|
||||
|
||||
return (0);
|
||||
return iwm_mvm_mac_ctxt_cmd_station(sc, vap, action);
|
||||
}
|
||||
|
||||
int
|
||||
@ -489,17 +495,13 @@ int
|
||||
iwm_mvm_mac_ctxt_changed(struct iwm_softc *sc, struct ieee80211vap *vap)
|
||||
{
|
||||
struct iwm_vap *iv = IWM_VAP(vap);
|
||||
int ret;
|
||||
|
||||
if (iv->is_uploaded == 0) {
|
||||
device_printf(sc->sc_dev, "%s: called; uploaded = 0\n",
|
||||
__func__);
|
||||
return (EIO);
|
||||
}
|
||||
ret = iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_MODIFY);
|
||||
if (ret)
|
||||
return (ret);
|
||||
return (0);
|
||||
return iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_MODIFY);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -256,13 +256,18 @@ iwm_nic_lock(struct iwm_softc *sc)
|
||||
IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000)
|
||||
DELAY(2);
|
||||
|
||||
if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
|
||||
IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
||||
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY
|
||||
| IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 15000)) {
|
||||
rv = 1;
|
||||
rv = 1;
|
||||
} else {
|
||||
/* jolt */
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_RESET,
|
||||
"%s: resetting device via NMI\n", __func__);
|
||||
IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_FORCE_NMI);
|
||||
}
|
||||
|
||||
@ -343,13 +348,20 @@ iwm_check_rfkill(struct iwm_softc *sc)
|
||||
int
|
||||
iwm_set_hw_ready(struct iwm_softc *sc)
|
||||
{
|
||||
int ready;
|
||||
|
||||
IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
|
||||
IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
|
||||
|
||||
return iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
|
||||
ready = iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
|
||||
IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
||||
IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
||||
IWM_HW_READY_TIMEOUT);
|
||||
if (ready) {
|
||||
IWM_SETBITS(sc, IWM_CSR_MBOX_SET_REG,
|
||||
IWM_CSR_MBOX_SET_REG_OS_ALIVE);
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
#undef IWM_HW_READY_TIMEOUT
|
||||
|
||||
@ -413,8 +425,10 @@ iwm_apm_init(struct iwm_softc *sc)
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_RESET, "iwm apm start\n");
|
||||
|
||||
/* Disable L0S exit timer (platform NMI Work/Around) */
|
||||
IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
|
||||
IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
|
||||
if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) {
|
||||
IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
|
||||
IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable L0s without affecting L1;
|
||||
@ -435,7 +449,7 @@ iwm_apm_init(struct iwm_softc *sc)
|
||||
|
||||
iwm_apm_config(sc);
|
||||
|
||||
#if 0 /* not for 7k */
|
||||
#if 0 /* not for 7k/8k */
|
||||
/* Configure analog phase-lock-loop before activating to D0A */
|
||||
if (trans->cfg->base_params->pll_cfg_val)
|
||||
IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG,
|
||||
@ -491,18 +505,19 @@ iwm_apm_init(struct iwm_softc *sc)
|
||||
* do not disable clocks. This preserves any hardware bits already
|
||||
* set by default in "CLK_CTRL_REG" after reset.
|
||||
*/
|
||||
iwm_write_prph(sc, IWM_APMG_CLK_EN_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT);
|
||||
//kpause("iwmapm", 0, mstohz(20), NULL);
|
||||
DELAY(20);
|
||||
if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
|
||||
iwm_write_prph(sc, IWM_APMG_CLK_EN_REG,
|
||||
IWM_APMG_CLK_VAL_DMA_CLK_RQT);
|
||||
DELAY(20);
|
||||
|
||||
/* Disable L1-Active */
|
||||
iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
|
||||
IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
|
||||
|
||||
/* Clear the interrupt in APMG if the NIC is in RFKILL */
|
||||
iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
|
||||
IWM_APMG_RTC_INT_STT_RFKILL);
|
||||
/* Disable L1-Active */
|
||||
iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
|
||||
IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
|
||||
|
||||
/* Clear the interrupt in APMG if the NIC is in RFKILL */
|
||||
iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
|
||||
IWM_APMG_RTC_INT_STT_RFKILL);
|
||||
}
|
||||
out:
|
||||
if (error)
|
||||
device_printf(sc->sc_dev, "apm init error %d\n", error);
|
||||
@ -533,9 +548,7 @@ iwm_start_hw(struct iwm_softc *sc)
|
||||
return error;
|
||||
|
||||
/* Reset the entire device */
|
||||
IWM_WRITE(sc, IWM_CSR_RESET,
|
||||
IWM_CSR_RESET_REG_FLAG_SW_RESET |
|
||||
IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
|
||||
IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET);
|
||||
DELAY(10);
|
||||
|
||||
if ((error = iwm_apm_init(sc)) != 0)
|
||||
|
@ -202,8 +202,8 @@ iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *sc,
|
||||
ieee80211_chan2ieee(ic, chan),
|
||||
chains_static,
|
||||
chains_dynamic,
|
||||
IWM_FW_VALID_RX_ANT(sc),
|
||||
IWM_FW_VALID_TX_ANT(sc));
|
||||
iwm_fw_valid_rx_ant(sc),
|
||||
iwm_fw_valid_tx_ant(sc));
|
||||
|
||||
|
||||
cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
|
||||
@ -217,13 +217,13 @@ iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *sc,
|
||||
idle_cnt = chains_static;
|
||||
active_cnt = chains_dynamic;
|
||||
|
||||
cmd->rxchain_info = htole32(IWM_FW_VALID_RX_ANT(sc) <<
|
||||
cmd->rxchain_info = htole32(iwm_fw_valid_rx_ant(sc) <<
|
||||
IWM_PHY_RX_CHAIN_VALID_POS);
|
||||
cmd->rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS);
|
||||
cmd->rxchain_info |= htole32(active_cnt <<
|
||||
IWM_PHY_RX_CHAIN_MIMO_CNT_POS);
|
||||
|
||||
cmd->txchain_info = htole32(IWM_FW_VALID_TX_ANT(sc));
|
||||
cmd->txchain_info = htole32(iwm_fw_valid_tx_ant(sc));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -343,7 +343,6 @@ iwm_send_phy_db_cmd(struct iwm_softc *sc, uint16_t type,
|
||||
cmd.len[0] = sizeof(struct iwm_phy_db_cmd);
|
||||
cmd.data[1] = data;
|
||||
cmd.len[1] = length;
|
||||
cmd.dataflags[1] = IWM_HCMD_DFL_NOCOPY;
|
||||
|
||||
return iwm_send_cmd(sc, &cmd);
|
||||
}
|
||||
@ -374,6 +373,7 @@ iwm_phy_db_send_all_channel_groups(struct iwm_softc *sc,
|
||||
return err;
|
||||
}
|
||||
|
||||
DELAY(1000);
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_CMD,
|
||||
"Sent PHY_DB HCMD, type = %d num = %d\n", type, i);
|
||||
}
|
||||
|
@ -335,14 +335,3 @@ iwm_mvm_disable_beacon_filter(struct iwm_softc *sc)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
iwm_mvm_update_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
|
||||
{
|
||||
if (!sc->sc_bf.bf_enabled)
|
||||
return 0;
|
||||
|
||||
return iwm_mvm_enable_beacon_filter(sc, in);
|
||||
}
|
||||
#endif
|
||||
|
@ -172,7 +172,7 @@ iwm_mvm_scan_rx_chain(struct iwm_softc *sc)
|
||||
uint16_t rx_chain;
|
||||
uint8_t rx_ant;
|
||||
|
||||
rx_ant = IWM_FW_VALID_RX_ANT(sc);
|
||||
rx_ant = iwm_fw_valid_rx_ant(sc);
|
||||
rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS;
|
||||
rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
|
||||
rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS;
|
||||
@ -180,6 +180,7 @@ iwm_mvm_scan_rx_chain(struct iwm_softc *sc)
|
||||
return htole16(rx_chain);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static uint32_t
|
||||
iwm_mvm_scan_max_out_time(struct iwm_softc *sc, uint32_t flags, int is_assoc)
|
||||
{
|
||||
@ -197,15 +198,7 @@ iwm_mvm_scan_suspend_time(struct iwm_softc *sc, int is_assoc)
|
||||
return 0;
|
||||
return htole32(SUSPEND_TIME_PERIOD);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
iwm_mvm_scan_rxon_flags(struct iwm_softc *sc, int flags)
|
||||
{
|
||||
if (flags & IEEE80211_CHAN_2GHZ)
|
||||
return htole32(IWM_PHY_BAND_24);
|
||||
else
|
||||
return htole32(IWM_PHY_BAND_5);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t
|
||||
iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
|
||||
@ -216,7 +209,7 @@ iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
|
||||
for (i = 0, ind = sc->sc_scan_last_antenna;
|
||||
i < IWM_RATE_MCS_ANT_NUM; i++) {
|
||||
ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM;
|
||||
if (IWM_FW_VALID_TX_ANT(sc) & (1 << ind)) {
|
||||
if (iwm_fw_valid_tx_ant(sc) & (1 << ind)) {
|
||||
sc->sc_scan_last_antenna = ind;
|
||||
break;
|
||||
}
|
||||
@ -230,6 +223,7 @@ iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
|
||||
return htole32(IWM_RATE_6M_PLCP | tx_ant);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* If req->n_ssids > 0, it means we should do an active scan.
|
||||
* In case of active scan w/o directed scan, we receive a zero-length SSID
|
||||
@ -253,24 +247,30 @@ iwm_mvm_get_passive_dwell(struct iwm_softc *sc, int flags)
|
||||
{
|
||||
return (flags & IEEE80211_CHAN_2GHZ) ? 100 + 20 : 100 + 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd,
|
||||
int flags, int n_ssids, int basic_ssid)
|
||||
iwm_mvm_scan_skip_channel(struct ieee80211_channel *c)
|
||||
{
|
||||
if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c))
|
||||
return 0;
|
||||
else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc,
|
||||
struct iwm_scan_channel_cfg_lmac *chan, int n_ssids)
|
||||
{
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
uint16_t passive_dwell = iwm_mvm_get_passive_dwell(sc, flags);
|
||||
uint16_t active_dwell = iwm_mvm_get_active_dwell(sc, flags, n_ssids);
|
||||
struct iwm_scan_channel *chan = (struct iwm_scan_channel *)
|
||||
(cmd->data + le16toh(cmd->tx_cmd.len));
|
||||
int type = (1 << n_ssids) - 1;
|
||||
struct ieee80211_channel *c;
|
||||
int nchan, j;
|
||||
uint8_t nchan;
|
||||
int j;
|
||||
|
||||
if (!basic_ssid)
|
||||
type |= (1 << n_ssids);
|
||||
|
||||
for (nchan = j = 0; j < ic->ic_nchans; j++) {
|
||||
for (nchan = j = 0;
|
||||
j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
|
||||
c = &ic->ic_channels[j];
|
||||
/* For 2GHz, only populate 11b channels */
|
||||
/* For 5GHz, only populate 11a channels */
|
||||
@ -278,175 +278,458 @@ iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd,
|
||||
* Catch other channels, in case we have 900MHz channels or
|
||||
* something in the chanlist.
|
||||
*/
|
||||
if ((flags & IEEE80211_CHAN_2GHZ) && (! IEEE80211_IS_CHAN_B(c))) {
|
||||
continue;
|
||||
} else if ((flags & IEEE80211_CHAN_5GHZ) && (! IEEE80211_IS_CHAN_A(c))) {
|
||||
continue;
|
||||
} else {
|
||||
if (iwm_mvm_scan_skip_channel(c)) {
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
|
||||
"%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
|
||||
__func__,
|
||||
c->ic_freq,
|
||||
c->ic_ieee,
|
||||
c->ic_flags);
|
||||
__func__, c->ic_freq, c->ic_ieee, c->ic_flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
|
||||
"Adding channel %d (%d Mhz) to the list\n",
|
||||
nchan, c->ic_freq);
|
||||
chan->channel = htole16(ieee80211_mhz2ieee(c->ic_freq, flags));
|
||||
chan->type = htole32(type);
|
||||
if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
|
||||
chan->type &= htole32(~IWM_SCAN_CHANNEL_TYPE_ACTIVE);
|
||||
chan->active_dwell = htole16(active_dwell);
|
||||
chan->passive_dwell = htole16(passive_dwell);
|
||||
chan->iteration_count = htole16(1);
|
||||
nchan, c->ic_freq);
|
||||
chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0));
|
||||
chan->iter_count = htole16(1);
|
||||
chan->iter_interval = htole32(0);
|
||||
chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL);
|
||||
#if 0 /* makes scanning while associated less useful */
|
||||
if (n_ssids != 0)
|
||||
chan->flags |= htole32(1 << 1); /* select SSID 0 */
|
||||
#endif
|
||||
chan++;
|
||||
nchan++;
|
||||
}
|
||||
if (nchan == 0)
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: NO CHANNEL!\n", __func__);
|
||||
|
||||
return nchan;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in probe request with the following parameters:
|
||||
* TA is our vif HW address, which mac80211 ensures we have.
|
||||
* Packet is broadcasted, so this is both SA and DA.
|
||||
* The probe request IE is made out of two: first comes the most prioritized
|
||||
* SSID if a directed scan is requested. Second comes whatever extra
|
||||
* information was given to us as the scan request IE.
|
||||
*/
|
||||
static uint16_t
|
||||
iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct ieee80211_frame *frame,
|
||||
const uint8_t *ta, int n_ssids, const uint8_t *ssid, int ssid_len,
|
||||
const uint8_t *ie, int ie_len, int left)
|
||||
static uint8_t
|
||||
iwm_mvm_umac_scan_fill_channels(struct iwm_softc *sc,
|
||||
struct iwm_scan_channel_cfg_umac *chan, int n_ssids)
|
||||
{
|
||||
uint8_t *pos = NULL;
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
struct ieee80211_channel *c;
|
||||
uint8_t nchan;
|
||||
int j;
|
||||
|
||||
/* Make sure there is enough space for the probe request,
|
||||
* two mandatory IEs and the data */
|
||||
left -= sizeof(*frame);
|
||||
if (left < 0)
|
||||
return 0;
|
||||
for (nchan = j = 0;
|
||||
j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
|
||||
c = &ic->ic_channels[j];
|
||||
/* For 2GHz, only populate 11b channels */
|
||||
/* For 5GHz, only populate 11a channels */
|
||||
/*
|
||||
* Catch other channels, in case we have 900MHz channels or
|
||||
* something in the chanlist.
|
||||
*/
|
||||
if (iwm_mvm_scan_skip_channel(c)) {
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
|
||||
"%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
|
||||
__func__, c->ic_freq, c->ic_ieee, c->ic_flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
|
||||
IEEE80211_FC0_SUBTYPE_PROBE_REQ;
|
||||
frame->i_fc[1] = IEEE80211_FC1_DIR_NODS;
|
||||
IEEE80211_ADDR_COPY(frame->i_addr1, ieee80211broadcastaddr);
|
||||
IEEE80211_ADDR_COPY(frame->i_addr2, ta);
|
||||
IEEE80211_ADDR_COPY(frame->i_addr3, ieee80211broadcastaddr);
|
||||
|
||||
/* for passive scans, no need to fill anything */
|
||||
if (n_ssids == 0)
|
||||
return sizeof(*frame);
|
||||
|
||||
/* points to the payload of the request */
|
||||
pos = (uint8_t *)frame + sizeof(*frame);
|
||||
|
||||
/* fill in our SSID IE */
|
||||
left -= ssid_len + 2;
|
||||
if (left < 0)
|
||||
return 0;
|
||||
|
||||
pos = ieee80211_add_ssid(pos, ssid, ssid_len);
|
||||
|
||||
if (ie && ie_len && left >= ie_len) {
|
||||
memcpy(pos, ie, ie_len);
|
||||
pos += ie_len;
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
|
||||
"Adding channel %d (%d Mhz) to the list\n",
|
||||
nchan, c->ic_freq);
|
||||
chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0);
|
||||
chan->iter_count = 1;
|
||||
chan->iter_interval = htole16(0);
|
||||
chan->flags = htole32(0);
|
||||
#if 0 /* makes scanning while associated less useful */
|
||||
if (n_ssids != 0)
|
||||
chan->flags = htole32(1 << 0); /* select SSID 0 */
|
||||
#endif
|
||||
chan++;
|
||||
nchan++;
|
||||
}
|
||||
|
||||
return pos - (uint8_t *)frame;
|
||||
return nchan;
|
||||
}
|
||||
|
||||
static int
|
||||
iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq)
|
||||
{
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
||||
struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf;
|
||||
struct ieee80211_rateset *rs;
|
||||
size_t remain = sizeof(preq->buf);
|
||||
uint8_t *frm, *pos;
|
||||
int ssid_len = 0;
|
||||
const uint8_t *ssid = NULL;
|
||||
|
||||
memset(preq, 0, sizeof(*preq));
|
||||
|
||||
/* Ensure enough space for header and SSID IE. */
|
||||
if (remain < sizeof(*wh) + 2 + ssid_len)
|
||||
return ENOBUFS;
|
||||
|
||||
/*
|
||||
* Build a probe request frame. Most of the following code is a
|
||||
* copy & paste of what is done in net80211.
|
||||
*/
|
||||
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;
|
||||
IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap ? vap->iv_myaddr : ic->ic_macaddr);
|
||||
IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr);
|
||||
*(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */
|
||||
*(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */
|
||||
|
||||
frm = (uint8_t *)(wh + 1);
|
||||
frm = ieee80211_add_ssid(frm, ssid, ssid_len);
|
||||
|
||||
/* Tell the firmware where the MAC header is. */
|
||||
preq->mac_header.offset = 0;
|
||||
preq->mac_header.len = htole16(frm - (uint8_t *)wh);
|
||||
remain -= frm - (uint8_t *)wh;
|
||||
|
||||
/* Fill in 2GHz IEs and tell firmware where they are. */
|
||||
rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
|
||||
if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
|
||||
if (remain < 4 + rs->rs_nrates)
|
||||
return ENOBUFS;
|
||||
} else if (remain < 2 + rs->rs_nrates) {
|
||||
return ENOBUFS;
|
||||
}
|
||||
preq->band_data[0].offset = htole16(frm - (uint8_t *)wh);
|
||||
pos = frm;
|
||||
frm = ieee80211_add_rates(frm, rs);
|
||||
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
|
||||
frm = ieee80211_add_xrates(frm, rs);
|
||||
preq->band_data[0].len = htole16(frm - pos);
|
||||
remain -= frm - pos;
|
||||
|
||||
if (isset(sc->sc_enabled_capa,
|
||||
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) {
|
||||
if (remain < 3)
|
||||
return ENOBUFS;
|
||||
*frm++ = IEEE80211_ELEMID_DSPARMS;
|
||||
*frm++ = 1;
|
||||
*frm++ = 0;
|
||||
remain -= 3;
|
||||
}
|
||||
|
||||
if (sc->sc_nvm.sku_cap_band_52GHz_enable) {
|
||||
/* Fill in 5GHz IEs. */
|
||||
rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
|
||||
if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
|
||||
if (remain < 4 + rs->rs_nrates)
|
||||
return ENOBUFS;
|
||||
} else if (remain < 2 + rs->rs_nrates) {
|
||||
return ENOBUFS;
|
||||
}
|
||||
preq->band_data[1].offset = htole16(frm - (uint8_t *)wh);
|
||||
pos = frm;
|
||||
frm = ieee80211_add_rates(frm, rs);
|
||||
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
|
||||
frm = ieee80211_add_xrates(frm, rs);
|
||||
preq->band_data[1].len = htole16(frm - pos);
|
||||
remain -= frm - pos;
|
||||
}
|
||||
|
||||
/* Send 11n IEs on both 2GHz and 5GHz bands. */
|
||||
preq->common_data.offset = htole16(frm - (uint8_t *)wh);
|
||||
pos = frm;
|
||||
#if 0
|
||||
if (ic->ic_flags & IEEE80211_F_HTON) {
|
||||
if (remain < 28)
|
||||
return ENOBUFS;
|
||||
frm = ieee80211_add_htcaps(frm, ic);
|
||||
/* XXX add WME info? */
|
||||
}
|
||||
#endif
|
||||
preq->common_data.len = htole16(frm - pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
|
||||
int n_ssids, uint8_t *ssid, int ssid_len)
|
||||
iwm_mvm_config_umac_scan(struct iwm_softc *sc)
|
||||
{
|
||||
struct iwm_host_cmd hcmd = {
|
||||
.id = IWM_SCAN_REQUEST_CMD,
|
||||
.len = { 0, },
|
||||
.data = { sc->sc_scan_cmd, },
|
||||
.flags = IWM_CMD_SYNC,
|
||||
.dataflags = { IWM_HCMD_DFL_NOCOPY, },
|
||||
};
|
||||
struct iwm_scan_cmd *cmd = sc->sc_scan_cmd;
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
||||
int is_assoc = 0;
|
||||
int ret;
|
||||
uint32_t status;
|
||||
int basic_ssid =
|
||||
!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID);
|
||||
|
||||
sc->sc_scanband = flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ);
|
||||
struct iwm_scan_config *scan_config;
|
||||
int ret, j, nchan;
|
||||
size_t cmd_size;
|
||||
struct ieee80211_channel *c;
|
||||
struct iwm_host_cmd hcmd = {
|
||||
.id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_ALWAYS_LONG_GROUP, 0),
|
||||
.flags = IWM_CMD_SYNC,
|
||||
};
|
||||
static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M |
|
||||
IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M |
|
||||
IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M |
|
||||
IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M |
|
||||
IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M |
|
||||
IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M |
|
||||
IWM_SCAN_CONFIG_RATE_54M);
|
||||
|
||||
cmd_size = sizeof(*scan_config) + sc->sc_capa_n_scan_channels;
|
||||
|
||||
scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
if (scan_config == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
scan_config->tx_chains = htole32(iwm_fw_valid_tx_ant(sc));
|
||||
scan_config->rx_chains = htole32(iwm_fw_valid_rx_ant(sc));
|
||||
scan_config->legacy_rates = htole32(rates |
|
||||
IWM_SCAN_CONFIG_SUPPORTED_RATE(rates));
|
||||
|
||||
/* These timings correspond to iwlwifi's UNASSOC scan. */
|
||||
scan_config->dwell_active = 10;
|
||||
scan_config->dwell_passive = 110;
|
||||
scan_config->dwell_fragmented = 44;
|
||||
scan_config->dwell_extended = 90;
|
||||
scan_config->out_of_channel_time = htole32(0);
|
||||
scan_config->suspend_time = htole32(0);
|
||||
|
||||
IEEE80211_ADDR_COPY(scan_config->mac_addr,
|
||||
vap ? vap->iv_myaddr : ic->ic_macaddr);
|
||||
|
||||
scan_config->bcast_sta_id = sc->sc_aux_sta.sta_id;
|
||||
scan_config->channel_flags = IWM_CHANNEL_FLAG_EBS |
|
||||
IWM_CHANNEL_FLAG_ACCURATE_EBS | IWM_CHANNEL_FLAG_EBS_ADD |
|
||||
IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE;
|
||||
|
||||
for (nchan = j = 0;
|
||||
j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
|
||||
c = &ic->ic_channels[j];
|
||||
/* For 2GHz, only populate 11b channels */
|
||||
/* For 5GHz, only populate 11a channels */
|
||||
/*
|
||||
* Catch other channels, in case we have 900MHz channels or
|
||||
* something in the chanlist.
|
||||
*/
|
||||
if (iwm_mvm_scan_skip_channel(c))
|
||||
continue;
|
||||
scan_config->channel_array[nchan++] =
|
||||
ieee80211_mhz2ieee(c->ic_freq, 0);
|
||||
}
|
||||
|
||||
scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE |
|
||||
IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR |
|
||||
IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
|
||||
IWM_SCAN_CONFIG_N_CHANNELS(nchan) |
|
||||
IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED);
|
||||
|
||||
hcmd.data[0] = scan_config;
|
||||
hcmd.len[0] = cmd_size;
|
||||
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n");
|
||||
|
||||
ret = iwm_send_cmd(sc, &hcmd);
|
||||
if (!ret)
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
|
||||
"UMAC scan config was sent successfully\n");
|
||||
|
||||
free(scan_config, M_DEVBUF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
iwm_mvm_umac_scan(struct iwm_softc *sc)
|
||||
{
|
||||
struct iwm_host_cmd hcmd = {
|
||||
.id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0),
|
||||
.len = { 0, },
|
||||
.data = { NULL, },
|
||||
.flags = IWM_CMD_SYNC,
|
||||
};
|
||||
struct iwm_scan_req_umac *req;
|
||||
struct iwm_scan_req_umac_tail *tail;
|
||||
size_t req_len;
|
||||
int ssid_len = 0;
|
||||
const uint8_t *ssid = NULL;
|
||||
int ret;
|
||||
|
||||
req_len = sizeof(struct iwm_scan_req_umac) +
|
||||
(sizeof(struct iwm_scan_channel_cfg_umac) *
|
||||
sc->sc_capa_n_scan_channels) +
|
||||
sizeof(struct iwm_scan_req_umac_tail);
|
||||
if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
|
||||
return ENOMEM;
|
||||
req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
if (req == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
hcmd.len[0] = (uint16_t)req_len;
|
||||
hcmd.data[0] = (void *)req;
|
||||
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n");
|
||||
|
||||
/* These timings correspond to iwlwifi's UNASSOC scan. */
|
||||
req->active_dwell = 10;
|
||||
req->passive_dwell = 110;
|
||||
req->fragmented_dwell = 44;
|
||||
req->extended_dwell = 90;
|
||||
req->max_out_time = 0;
|
||||
req->suspend_time = 0;
|
||||
|
||||
req->scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
|
||||
req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
|
||||
|
||||
req->n_channels = iwm_mvm_umac_scan_fill_channels(sc,
|
||||
(struct iwm_scan_channel_cfg_umac *)req->data, ssid_len != 0);
|
||||
|
||||
req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL |
|
||||
IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE |
|
||||
IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL);
|
||||
|
||||
tail = (void *)((char *)&req->data +
|
||||
sizeof(struct iwm_scan_channel_cfg_umac) *
|
||||
sc->sc_capa_n_scan_channels);
|
||||
|
||||
/* Check if we're doing an active directed scan. */
|
||||
if (ssid_len != 0) {
|
||||
tail->direct_scan[0].id = IEEE80211_ELEMID_SSID;
|
||||
tail->direct_scan[0].len = ssid_len;
|
||||
memcpy(tail->direct_scan[0].ssid, ssid, ssid_len);
|
||||
req->general_flags |=
|
||||
htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT);
|
||||
} else {
|
||||
req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE);
|
||||
}
|
||||
|
||||
if (isset(sc->sc_enabled_capa,
|
||||
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
|
||||
req->general_flags |=
|
||||
htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED);
|
||||
|
||||
ret = iwm_mvm_fill_probe_req(sc, &tail->preq);
|
||||
if (ret) {
|
||||
free(req, M_DEVBUF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Specify the scan plan: We'll do one iteration. */
|
||||
tail->schedule[0].interval = 0;
|
||||
tail->schedule[0].iter_count = 1;
|
||||
|
||||
ret = iwm_send_cmd(sc, &hcmd);
|
||||
if (!ret)
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
|
||||
"Scan request was sent successfully\n");
|
||||
free(req, M_DEVBUF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
iwm_mvm_lmac_scan(struct iwm_softc *sc)
|
||||
{
|
||||
struct iwm_host_cmd hcmd = {
|
||||
.id = IWM_SCAN_OFFLOAD_REQUEST_CMD,
|
||||
.len = { 0, },
|
||||
.data = { NULL, },
|
||||
.flags = IWM_CMD_SYNC,
|
||||
};
|
||||
struct iwm_scan_req_lmac *req;
|
||||
size_t req_len;
|
||||
int ret;
|
||||
int ssid_len = 0;
|
||||
const uint8_t *ssid = NULL;
|
||||
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
|
||||
"Handling ieee80211 scan request\n");
|
||||
memset(cmd, 0, sc->sc_scan_cmd_len);
|
||||
|
||||
cmd->quiet_time = htole16(IWM_ACTIVE_QUIET_TIME);
|
||||
cmd->quiet_plcp_th = htole16(IWM_PLCP_QUIET_THRESH);
|
||||
cmd->rxchain_sel_flags = iwm_mvm_scan_rx_chain(sc);
|
||||
cmd->max_out_time = iwm_mvm_scan_max_out_time(sc, 0, is_assoc);
|
||||
cmd->suspend_time = iwm_mvm_scan_suspend_time(sc, is_assoc);
|
||||
cmd->rxon_flags = iwm_mvm_scan_rxon_flags(sc, flags);
|
||||
cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP |
|
||||
IWM_MAC_FILTER_IN_BEACON);
|
||||
req_len = sizeof(struct iwm_scan_req_lmac) +
|
||||
(sizeof(struct iwm_scan_channel_cfg_lmac) *
|
||||
sc->sc_capa_n_scan_channels) + sizeof(struct iwm_scan_probe_req);
|
||||
if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
|
||||
return ENOMEM;
|
||||
req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
if (req == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
cmd->type = htole32(IWM_SCAN_TYPE_FORCED);
|
||||
cmd->repeats = htole32(1);
|
||||
hcmd.len[0] = (uint16_t)req_len;
|
||||
hcmd.data[0] = (void *)req;
|
||||
|
||||
/*
|
||||
* If the user asked for passive scan, don't change to active scan if
|
||||
* you see any activity on the channel - remain passive.
|
||||
*/
|
||||
if (n_ssids > 0) {
|
||||
cmd->passive2active = htole16(1);
|
||||
cmd->scan_flags |= IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
|
||||
#if 0
|
||||
if (basic_ssid) {
|
||||
ssid = req->ssids[0].ssid;
|
||||
ssid_len = req->ssids[0].ssid_len;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
cmd->passive2active = 0;
|
||||
cmd->scan_flags &= ~IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
|
||||
/* These timings correspond to iwlwifi's UNASSOC scan. */
|
||||
req->active_dwell = 10;
|
||||
req->passive_dwell = 110;
|
||||
req->fragmented_dwell = 44;
|
||||
req->extended_dwell = 90;
|
||||
req->max_out_time = 0;
|
||||
req->suspend_time = 0;
|
||||
|
||||
req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH);
|
||||
req->rx_chain_select = iwm_mvm_scan_rx_chain(sc);
|
||||
req->iter_num = htole32(1);
|
||||
req->delay = 0;
|
||||
|
||||
req->scan_flags = htole32(IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL |
|
||||
IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE |
|
||||
IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL);
|
||||
if (ssid_len == 0)
|
||||
req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE);
|
||||
else
|
||||
req->scan_flags |=
|
||||
htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION);
|
||||
if (isset(sc->sc_enabled_capa,
|
||||
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
|
||||
req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
|
||||
|
||||
req->flags = htole32(IWM_PHY_BAND_24);
|
||||
if (sc->sc_nvm.sku_cap_band_52GHz_enable)
|
||||
req->flags |= htole32(IWM_PHY_BAND_5);
|
||||
req->filter_flags =
|
||||
htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON);
|
||||
|
||||
/* Tx flags 2 GHz. */
|
||||
req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
|
||||
IWM_TX_CMD_FLG_BT_DIS);
|
||||
req->tx_cmd[0].rate_n_flags =
|
||||
iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/);
|
||||
req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id;
|
||||
|
||||
/* Tx flags 5 GHz. */
|
||||
req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
|
||||
IWM_TX_CMD_FLG_BT_DIS);
|
||||
req->tx_cmd[1].rate_n_flags =
|
||||
iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/);
|
||||
req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id;
|
||||
|
||||
/* Check if we're doing an active directed scan. */
|
||||
if (ssid_len != 0) {
|
||||
req->direct_scan[0].id = IEEE80211_ELEMID_SSID;
|
||||
req->direct_scan[0].len = ssid_len;
|
||||
memcpy(req->direct_scan[0].ssid, ssid, ssid_len);
|
||||
}
|
||||
|
||||
cmd->tx_cmd.tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
|
||||
IWM_TX_CMD_FLG_BT_DIS);
|
||||
cmd->tx_cmd.sta_id = sc->sc_aux_sta.sta_id;
|
||||
cmd->tx_cmd.life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE);
|
||||
cmd->tx_cmd.rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, flags, 1/*XXX*/);
|
||||
req->n_channels = iwm_mvm_lmac_scan_fill_channels(sc,
|
||||
(struct iwm_scan_channel_cfg_lmac *)req->data,
|
||||
ssid_len != 0);
|
||||
|
||||
cmd->tx_cmd.len = htole16(iwm_mvm_fill_probe_req(sc,
|
||||
(struct ieee80211_frame *)cmd->data,
|
||||
vap ? vap->iv_myaddr : ic->ic_macaddr, n_ssids,
|
||||
ssid, ssid_len, NULL, 0,
|
||||
sc->sc_capa_max_probe_len));
|
||||
ret = iwm_mvm_fill_probe_req(sc,
|
||||
(struct iwm_scan_probe_req *)(req->data +
|
||||
(sizeof(struct iwm_scan_channel_cfg_lmac) *
|
||||
sc->sc_capa_n_scan_channels)));
|
||||
if (ret) {
|
||||
free(req, M_DEVBUF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd->channel_count
|
||||
= iwm_mvm_scan_fill_channels(sc, cmd, flags, n_ssids, basic_ssid);
|
||||
/* Specify the scan plan: We'll do one iteration. */
|
||||
req->schedule[0].iterations = 1;
|
||||
req->schedule[0].full_scan_mul = 1;
|
||||
|
||||
cmd->len = htole16(sizeof(struct iwm_scan_cmd) +
|
||||
le16toh(cmd->tx_cmd.len) +
|
||||
(cmd->channel_count * sizeof(struct iwm_scan_channel)));
|
||||
hcmd.len[0] = le16toh(cmd->len);
|
||||
/* Disable EBS. */
|
||||
req->channel_opt[0].non_ebs_ratio = 1;
|
||||
req->channel_opt[1].non_ebs_ratio = 1;
|
||||
|
||||
status = IWM_SCAN_RESPONSE_OK;
|
||||
ret = iwm_mvm_send_cmd_status(sc, &hcmd, &status);
|
||||
if (!ret && status == IWM_SCAN_RESPONSE_OK) {
|
||||
ret = iwm_send_cmd(sc, &hcmd);
|
||||
if (!ret) {
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
|
||||
"Scan request was sent successfully\n");
|
||||
} else {
|
||||
/*
|
||||
* If the scan failed, it usually means that the FW was unable
|
||||
* to allocate the time events. Warn on it, but maybe we
|
||||
* should try to send the command again with different params.
|
||||
*/
|
||||
ret = EIO;
|
||||
}
|
||||
free(req, M_DEVBUF);
|
||||
return ret;
|
||||
}
|
||||
|
@ -106,8 +106,8 @@
|
||||
#ifndef __IF_IWN_SCAN_H__
|
||||
#define __IF_IWN_SCAN_H__
|
||||
|
||||
extern int
|
||||
iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
|
||||
int n_ssids, uint8_t *ssid, int ssid_len);
|
||||
extern int iwm_mvm_lmac_scan(struct iwm_softc *sc);
|
||||
extern int iwm_mvm_config_umac_scan(struct iwm_softc *);
|
||||
extern int iwm_mvm_umac_scan(struct iwm_softc *);
|
||||
|
||||
#endif /* __IF_IWN_SCAN_H__ */
|
||||
|
@ -257,8 +257,7 @@ iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_node *in,
|
||||
htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR));
|
||||
time_cmd.id = htole32(IWM_TE_BSS_STA_AGGRESSIVE_ASSOC);
|
||||
|
||||
time_cmd.apply_time = htole32(iwm_read_prph(sc,
|
||||
IWM_DEVICE_SYSTEM_TIME_REG));
|
||||
time_cmd.apply_time = htole32(0);
|
||||
|
||||
time_cmd.max_frags = IWM_TE_V2_FRAG_NONE;
|
||||
time_cmd.max_delay = htole32(max_delay);
|
||||
@ -268,7 +267,8 @@ iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_node *in,
|
||||
time_cmd.repeat = 1;
|
||||
time_cmd.policy
|
||||
= htole32(IWM_TE_V2_NOTIF_HOST_EVENT_START |
|
||||
IWM_TE_V2_NOTIF_HOST_EVENT_END);
|
||||
IWM_TE_V2_NOTIF_HOST_EVENT_END |
|
||||
IWM_T2_V2_START_IMMEDIATELY);
|
||||
|
||||
iwm_mvm_time_event_send_add(sc, in, /*te_data*/NULL, &time_cmd);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
{
|
||||
struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
|
||||
struct iwm_tfd *desc;
|
||||
struct iwm_tx_data *data;
|
||||
struct iwm_tx_data *txdata = NULL;
|
||||
struct iwm_device_cmd *cmd;
|
||||
struct mbuf *m;
|
||||
bus_dma_segment_t seg;
|
||||
@ -178,11 +178,15 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
int error = 0, i, paylen, off;
|
||||
int code;
|
||||
int async, wantresp;
|
||||
int group_id;
|
||||
int nsegs;
|
||||
size_t hdrlen, datasz;
|
||||
uint8_t *data;
|
||||
|
||||
code = hcmd->id;
|
||||
async = hcmd->flags & IWM_CMD_ASYNC;
|
||||
wantresp = hcmd->flags & IWM_CMD_WANT_SKB;
|
||||
data = NULL;
|
||||
|
||||
for (i = 0, paylen = 0; i < nitems(hcmd->len); i++) {
|
||||
paylen += hcmd->len[i];
|
||||
@ -207,17 +211,27 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
}
|
||||
|
||||
desc = &ring->desc[ring->cur];
|
||||
data = &ring->data[ring->cur];
|
||||
txdata = &ring->data[ring->cur];
|
||||
|
||||
if (paylen > sizeof(cmd->data)) {
|
||||
group_id = iwm_cmd_groupid(code);
|
||||
if (group_id != 0) {
|
||||
hdrlen = sizeof(cmd->hdr_wide);
|
||||
datasz = sizeof(cmd->data_wide);
|
||||
} else {
|
||||
hdrlen = sizeof(cmd->hdr);
|
||||
datasz = sizeof(cmd->data);
|
||||
}
|
||||
|
||||
if (paylen > datasz) {
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_CMD,
|
||||
"large command paylen=%u len0=%u\n",
|
||||
paylen, hcmd->len[0]);
|
||||
/* Command is too large */
|
||||
size_t totlen = hdrlen + paylen;
|
||||
if (paylen > IWM_MAX_CMD_PAYLOAD_SIZE) {
|
||||
device_printf(sc->sc_dev,
|
||||
"firmware command too long (%zd bytes)\n",
|
||||
paylen + sizeof(cmd->hdr));
|
||||
totlen);
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -229,30 +243,41 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
|
||||
m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
|
||||
error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
|
||||
data->map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
|
||||
txdata->map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: can't map mbuf, error %d\n", __func__, error);
|
||||
m_freem(m);
|
||||
goto out;
|
||||
}
|
||||
data->m = m; /* mbuf will be freed in iwm_cmd_done() */
|
||||
txdata->m = m; /* mbuf will be freed in iwm_cmd_done() */
|
||||
cmd = mtod(m, struct iwm_device_cmd *);
|
||||
paddr = seg.ds_addr;
|
||||
} else {
|
||||
cmd = &ring->cmd[ring->cur];
|
||||
paddr = data->cmd_paddr;
|
||||
paddr = txdata->cmd_paddr;
|
||||
}
|
||||
|
||||
cmd->hdr.code = code;
|
||||
cmd->hdr.flags = 0;
|
||||
cmd->hdr.qid = ring->qid;
|
||||
cmd->hdr.idx = ring->cur;
|
||||
if (group_id != 0) {
|
||||
cmd->hdr_wide.opcode = iwm_cmd_opcode(code);
|
||||
cmd->hdr_wide.group_id = group_id;
|
||||
cmd->hdr_wide.qid = ring->qid;
|
||||
cmd->hdr_wide.idx = ring->cur;
|
||||
cmd->hdr_wide.length = htole16(paylen);
|
||||
cmd->hdr_wide.version = iwm_cmd_version(code);
|
||||
data = cmd->data_wide;
|
||||
} else {
|
||||
cmd->hdr.code = iwm_cmd_opcode(code);
|
||||
cmd->hdr.flags = 0;
|
||||
cmd->hdr.qid = ring->qid;
|
||||
cmd->hdr.idx = ring->cur;
|
||||
data = cmd->data;
|
||||
}
|
||||
|
||||
for (i = 0, off = 0; i < nitems(hcmd->data); i++) {
|
||||
if (hcmd->len[i] == 0)
|
||||
continue;
|
||||
memcpy(cmd->data + off, hcmd->data[i], hcmd->len[i]);
|
||||
memcpy(data + off, hcmd->data[i], hcmd->len[i]);
|
||||
off += hcmd->len[i];
|
||||
}
|
||||
KASSERT(off == paylen, ("off %d != paylen %d", off, paylen));
|
||||
@ -261,18 +286,17 @@ iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
addr_lo = htole32((uint32_t)paddr);
|
||||
memcpy(&desc->tbs[0].lo, &addr_lo, sizeof(uint32_t));
|
||||
desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(paddr)
|
||||
| ((sizeof(cmd->hdr) + paylen) << 4));
|
||||
| ((hdrlen + paylen) << 4));
|
||||
desc->num_tbs = 1;
|
||||
|
||||
IWM_DPRINTF(sc, IWM_DEBUG_CMD,
|
||||
"%s: iwm_send_cmd 0x%x size=%lu %s\n",
|
||||
__func__,
|
||||
"iwm_send_cmd 0x%x size=%lu %s\n",
|
||||
code,
|
||||
(unsigned long) (hcmd->len[0] + hcmd->len[1] + sizeof(cmd->hdr)),
|
||||
(unsigned long) (hcmd->len[0] + hcmd->len[1] + hdrlen),
|
||||
async ? " (async)" : "");
|
||||
|
||||
if (paylen > sizeof(cmd->data)) {
|
||||
bus_dmamap_sync(ring->data_dmat, data->map,
|
||||
if (paylen > datasz) {
|
||||
bus_dmamap_sync(ring->data_dmat, txdata->map,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
} else {
|
||||
bus_dmamap_sync(ring->cmd_dma.tag, ring->cmd_dma.map,
|
||||
@ -404,3 +428,31 @@ iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
|
||||
sc->sc_wantresp = -1;
|
||||
wakeup(&sc->sc_wantresp);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
iwm_fw_valid_tx_ant(struct iwm_softc *sc)
|
||||
{
|
||||
uint8_t tx_ant;
|
||||
|
||||
tx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN)
|
||||
>> IWM_FW_PHY_CFG_TX_CHAIN_POS);
|
||||
|
||||
if (sc->sc_nvm.valid_tx_ant)
|
||||
tx_ant &= sc->sc_nvm.valid_tx_ant;
|
||||
|
||||
return tx_ant;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
iwm_fw_valid_rx_ant(struct iwm_softc *sc)
|
||||
{
|
||||
uint8_t rx_ant;
|
||||
|
||||
rx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN)
|
||||
>> IWM_FW_PHY_CFG_RX_CHAIN_POS);
|
||||
|
||||
if (sc->sc_nvm.valid_rx_ant)
|
||||
rx_ant &= sc->sc_nvm.valid_rx_ant;
|
||||
|
||||
return rx_ant;
|
||||
}
|
||||
|
@ -116,4 +116,7 @@ extern int iwm_mvm_send_cmd_pdu_status(struct iwm_softc *sc, uint8_t id,
|
||||
uint16_t len, const void *data, uint32_t *status);
|
||||
extern void iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd);
|
||||
|
||||
extern uint8_t iwm_fw_valid_tx_ant(struct iwm_softc *sc);
|
||||
extern uint8_t iwm_fw_valid_rx_ant(struct iwm_softc *sc);
|
||||
|
||||
#endif /* __IF_IWM_UTIL_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -137,8 +137,9 @@ struct iwm_tx_radiotap_header {
|
||||
(1 << IEEE80211_RADIOTAP_CHANNEL))
|
||||
|
||||
|
||||
#define IWM_UCODE_SECT_MAX 6
|
||||
#define IWM_UCODE_SECT_MAX 16
|
||||
#define IWM_FWDMASEGSZ (192*1024)
|
||||
#define IWM_FWDMASEGSZ_8000 (320*1024)
|
||||
/* sanity check value */
|
||||
#define IWM_FWMAXSIZE (2*1024*1024)
|
||||
|
||||
@ -152,9 +153,10 @@ struct iwm_tx_radiotap_header {
|
||||
#define IWM_FW_STATUS_DONE 2
|
||||
|
||||
enum iwm_ucode_type {
|
||||
IWM_UCODE_TYPE_INIT,
|
||||
IWM_UCODE_TYPE_REGULAR,
|
||||
IWM_UCODE_TYPE_INIT,
|
||||
IWM_UCODE_TYPE_WOW,
|
||||
IWM_UCODE_TYPE_REGULAR_USNIFFER,
|
||||
IWM_UCODE_TYPE_MAX
|
||||
};
|
||||
|
||||
@ -197,8 +199,9 @@ struct iwm_nvm_data {
|
||||
uint8_t radio_cfg_pnum;
|
||||
uint8_t valid_tx_ant, valid_rx_ant;
|
||||
#define IWM_NUM_CHANNELS 39
|
||||
#define IWM_NUM_CHANNELS_8000 51
|
||||
|
||||
uint16_t nvm_ch_flags[IWM_NUM_CHANNELS];
|
||||
uint16_t nvm_ch_flags[IWM_NUM_CHANNELS_8000];
|
||||
|
||||
uint16_t nvm_version;
|
||||
uint8_t max_tx_pwr_half_dbm;
|
||||
@ -216,9 +219,9 @@ struct iwm_host_cmd {
|
||||
int handler_status;
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t id;
|
||||
uint16_t len[IWM_MAX_CMD_TBS_PER_TFD];
|
||||
uint8_t dataflags[IWM_MAX_CMD_TBS_PER_TFD];
|
||||
uint8_t id;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -269,13 +272,6 @@ struct iwm_tx_ring {
|
||||
|
||||
#define IWM_MAX_SCATTER 20
|
||||
|
||||
struct iwm_softc;
|
||||
struct iwm_rbuf {
|
||||
struct iwm_softc *sc;
|
||||
void *vaddr;
|
||||
bus_addr_t paddr;
|
||||
};
|
||||
|
||||
struct iwm_rx_data {
|
||||
struct mbuf *m;
|
||||
bus_dmamap_t map;
|
||||
@ -296,6 +292,7 @@ struct iwm_rx_ring {
|
||||
|
||||
struct iwm_ucode_status {
|
||||
uint32_t uc_error_event_table;
|
||||
uint32_t uc_umac_error_event_table;
|
||||
uint32_t uc_log_event_table;
|
||||
|
||||
int uc_ok;
|
||||
@ -304,7 +301,9 @@ struct iwm_ucode_status {
|
||||
|
||||
#define IWM_CMD_RESP_MAX PAGE_SIZE
|
||||
|
||||
#define IWM_OTP_LOW_IMAGE_SIZE 2048
|
||||
/* lower blocks contain EEPROM image and calibration data */
|
||||
#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000 16384
|
||||
#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 32768
|
||||
|
||||
#define IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500
|
||||
#define IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400
|
||||
@ -329,7 +328,7 @@ enum iwm_hcmd_dataflag {
|
||||
* iwlwifi/iwl-phy-db
|
||||
*/
|
||||
|
||||
#define IWM_NUM_PAPD_CH_GROUPS 4
|
||||
#define IWM_NUM_PAPD_CH_GROUPS 9
|
||||
#define IWM_NUM_TXP_CH_GROUPS 9
|
||||
|
||||
struct iwm_phy_db_entry {
|
||||
@ -386,6 +385,7 @@ struct iwm_node {
|
||||
#define IWM_NODE(_ni) ((struct iwm_node *)(_ni))
|
||||
|
||||
#define IWM_STATION_ID 0
|
||||
#define IWM_AUX_STA_ID 1
|
||||
|
||||
#define IWM_DEFAULT_MACID 0
|
||||
#define IWM_DEFAULT_COLOR 0
|
||||
@ -409,7 +409,7 @@ struct iwm_softc {
|
||||
#define IWM_FLAG_STOPPED (1 << 2)
|
||||
#define IWM_FLAG_RFKILL (1 << 3)
|
||||
#define IWM_FLAG_BUSY (1 << 4)
|
||||
#define IWM_FLAG_DORESUME (1 << 5)
|
||||
#define IWM_FLAG_SCANNING (1 << 5)
|
||||
|
||||
struct intr_config_hook sc_preinit_hook;
|
||||
struct callout sc_watchdog_to;
|
||||
@ -441,7 +441,14 @@ struct iwm_softc {
|
||||
int ict_cur;
|
||||
|
||||
int sc_hw_rev;
|
||||
#define IWM_SILICON_A_STEP 0
|
||||
#define IWM_SILICON_B_STEP 1
|
||||
#define IWM_SILICON_C_STEP 2
|
||||
#define IWM_SILICON_D_STEP 3
|
||||
int sc_hw_id;
|
||||
int sc_device_family;
|
||||
#define IWM_DEVICE_FAMILY_7000 1
|
||||
#define IWM_DEVICE_FAMILY_8000 2
|
||||
|
||||
struct iwm_dma_info kw_dma;
|
||||
struct iwm_dma_info fw_dma;
|
||||
@ -451,10 +458,14 @@ struct iwm_softc {
|
||||
|
||||
struct iwm_ucode_status sc_uc;
|
||||
enum iwm_ucode_type sc_uc_current;
|
||||
int sc_fwver;
|
||||
char sc_fwver[32];
|
||||
|
||||
int sc_capaflags;
|
||||
int sc_capa_max_probe_len;
|
||||
int sc_capa_n_scan_channels;
|
||||
uint32_t sc_ucode_api;
|
||||
uint8_t sc_enabled_capa[howmany(IWM_NUM_UCODE_TLV_CAPA, NBBY)];
|
||||
char sc_fw_mcc[3];
|
||||
|
||||
int sc_intmask;
|
||||
|
||||
@ -482,10 +493,7 @@ struct iwm_softc {
|
||||
|
||||
int sc_tx_timer;
|
||||
|
||||
struct iwm_scan_cmd *sc_scan_cmd;
|
||||
size_t sc_scan_cmd_len;
|
||||
int sc_scan_last_antenna;
|
||||
int sc_scanband;
|
||||
|
||||
int sc_fixed_ridx;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user