[iwm] Make ucode capabilities and api flags handling more like iwlwifi.

Obtained from:	dragonflybsd.git 757eecf0e6c92745aa2eee95811e573c8300850e
This commit is contained in:
Adrian Chadd 2017-03-23 04:50:38 +00:00
parent d045c744f1
commit a00bfbb19d
3 changed files with 111 additions and 56 deletions

View File

@ -484,6 +484,56 @@ iwm_set_default_calib(struct iwm_softc *sc, const void *data)
return 0;
}
static int
iwm_set_ucode_api_flags(struct iwm_softc *sc, const uint8_t *data,
struct iwm_ucode_capabilities *capa)
{
const struct iwm_ucode_api *ucode_api = (const void *)data;
uint32_t api_index = le32toh(ucode_api->api_index);
uint32_t api_flags = le32toh(ucode_api->api_flags);
int i;
if (api_index >= howmany(IWM_NUM_UCODE_TLV_API, 32)) {
device_printf(sc->sc_dev,
"api flags index %d larger than supported by driver\n",
api_index);
/* don't return an error so we can load FW that has more bits */
return 0;
}
for (i = 0; i < 32; i++) {
if (api_flags & (1U << i))
setbit(capa->enabled_api, i + 32 * api_index);
}
return 0;
}
static int
iwm_set_ucode_capabilities(struct iwm_softc *sc, const uint8_t *data,
struct iwm_ucode_capabilities *capa)
{
const struct iwm_ucode_capa *ucode_capa = (const void *)data;
uint32_t api_index = le32toh(ucode_capa->api_index);
uint32_t api_flags = le32toh(ucode_capa->api_capa);
int i;
if (api_index >= howmany(IWM_NUM_UCODE_TLV_CAPA, 32)) {
device_printf(sc->sc_dev,
"capa flags index %d larger than supported by driver\n",
api_index);
/* don't return an error so we can load FW that has more bits */
return 0;
}
for (i = 0; i < 32; i++) {
if (api_flags & (1U << i))
setbit(capa->enabled_capa, i + 32 * api_index);
}
return 0;
}
static void
iwm_fw_info_free(struct iwm_fw_info *fw)
{
@ -499,6 +549,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
struct iwm_fw_info *fw = &sc->sc_fw;
const struct iwm_tlv_ucode_header *uhdr;
struct iwm_ucode_tlv tlv;
struct iwm_ucode_capabilities *capa = &sc->ucode_capa;
enum iwm_ucode_tlv_type tlv_type;
const struct firmware *fwp;
const uint8_t *data;
@ -535,9 +586,11 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
fw->fw_fp = fwp;
/* (Re-)Initialize default values. */
sc->sc_capaflags = 0;
sc->sc_capa_n_scan_channels = IWM_DEFAULT_SCAN_CHANNELS;
memset(sc->sc_enabled_capa, 0, sizeof(sc->sc_enabled_capa));
capa->flags = 0;
capa->max_probe_length = IWM_DEFAULT_MAX_PROBE_LENGTH;
capa->n_scan_channels = IWM_DEFAULT_SCAN_CHANNELS;
memset(capa->enabled_capa, 0, sizeof(capa->enabled_capa));
memset(capa->enabled_api, 0, sizeof(capa->enabled_api));
memset(sc->sc_fw_mcc, 0, sizeof(sc->sc_fw_mcc));
/*
@ -590,10 +643,10 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
error = EINVAL;
goto parse_out;
}
sc->sc_capa_max_probe_len
= le32toh(*(const uint32_t *)tlv_data);
capa->max_probe_length =
le32toh(*(const uint32_t *)tlv_data);
/* limit it to something sensible */
if (sc->sc_capa_max_probe_len >
if (capa->max_probe_length >
IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE) {
IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV,
"%s: IWM_UCODE_TLV_PROBE_MAX_LEN "
@ -611,7 +664,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
error = EINVAL;
goto parse_out;
}
sc->sc_capaflags |= IWM_UCODE_TLV_FLAGS_PAN;
capa->flags |= IWM_UCODE_TLV_FLAGS_PAN;
break;
case IWM_UCODE_TLV_FLAGS:
if (tlv_len < sizeof(uint32_t)) {
@ -633,7 +686,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
* 2) TLV_FLAGS contains TLV_FLAGS_PAN
* ==> this resets TLV_PAN to itself... hnnnk
*/
sc->sc_capaflags = le32toh(*(const uint32_t *)tlv_data);
capa->flags = le32toh(*(const uint32_t *)tlv_data);
break;
case IWM_UCODE_TLV_CSCHEME:
if ((error = iwm_store_cscheme(sc,
@ -738,42 +791,26 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
break;
case IWM_UCODE_TLV_API_CHANGES_SET: {
const struct iwm_ucode_api *api;
if (tlv_len != sizeof(*api)) {
if (tlv_len != sizeof(struct iwm_ucode_api)) {
error = EINVAL;
goto parse_out;
}
api = (const struct iwm_ucode_api *)tlv_data;
/* Flags may exceed 32 bits in future firmware. */
if (le32toh(api->api_index) > 0) {
device_printf(sc->sc_dev,
"unsupported API index %d\n",
le32toh(api->api_index));
if (iwm_set_ucode_api_flags(sc, tlv_data, capa)) {
error = EINVAL;
goto parse_out;
}
sc->sc_ucode_api = le32toh(api->api_flags);
break;
}
case IWM_UCODE_TLV_ENABLED_CAPABILITIES: {
const struct iwm_ucode_capa *capa;
int idx, i;
if (tlv_len != sizeof(*capa)) {
if (tlv_len != sizeof(struct iwm_ucode_capa)) {
error = EINVAL;
goto parse_out;
}
capa = (const struct iwm_ucode_capa *)tlv_data;
idx = le32toh(capa->api_index);
if (idx >= howmany(IWM_NUM_UCODE_TLV_CAPA, 32)) {
device_printf(sc->sc_dev,
"unsupported API index %d\n", idx);
if (iwm_set_ucode_capabilities(sc, tlv_data, capa)) {
error = EINVAL;
goto parse_out;
}
for (i = 0; i < 32; i++) {
if ((le32toh(capa->api_capa) & (1U << i)) == 0)
continue;
setbit(sc->sc_enabled_capa, i + (32 * idx));
}
break;
}
@ -827,8 +864,8 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
error = EINVAL;
goto parse_out;
}
sc->sc_capa_n_scan_channels =
le32toh(*(const uint32_t *)tlv_data);
capa->n_scan_channels =
le32toh(*(const uint32_t *)tlv_data);
break;
case IWM_UCODE_TLV_FW_VERSION:
@ -4713,13 +4750,13 @@ iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2)
int n_channels;
uint16_t mcc;
#endif
int resp_v2 = isset(sc->sc_enabled_capa,
int resp_v2 = fw_has_capa(&sc->ucode_capa,
IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2);
memset(&mcc_cmd, 0, sizeof(mcc_cmd));
mcc_cmd.mcc = htole16(alpha2[0] << 8 | alpha2[1]);
if ((sc->sc_ucode_api & IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) ||
isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC))
if (fw_has_api(&sc->ucode_capa, IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) ||
fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC))
mcc_cmd.source_id = IWM_MCC_SOURCE_GET_CURRENT;
else
mcc_cmd.source_id = IWM_MCC_SOURCE_OLD_FW;
@ -4857,12 +4894,12 @@ iwm_init_hw(struct iwm_softc *sc)
if (error)
goto error;
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT)) {
if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT)) {
if ((error = iwm_send_update_mcc_cmd(sc, "ZZ")) != 0)
goto error;
}
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
if ((error = iwm_mvm_config_umac_scan(sc)) != 0)
goto error;
}
@ -6263,7 +6300,7 @@ iwm_scan_start(struct ieee80211com *ic)
device_printf(sc->sc_dev,
"%s: Previous scan not completed yet\n", __func__);
}
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
error = iwm_mvm_umac_scan(sc);
else
error = iwm_mvm_lmac_scan(sc);

View File

@ -272,7 +272,7 @@ iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc,
int j;
for (nchan = j = 0;
j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
j < ic->ic_nchans && nchan < sc->ucode_capa.n_scan_channels; j++) {
c = &ic->ic_channels[j];
/* For 2GHz, only populate 11b channels */
/* For 5GHz, only populate 11a channels */
@ -316,7 +316,7 @@ iwm_mvm_umac_scan_fill_channels(struct iwm_softc *sc,
int j;
for (nchan = j = 0;
j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
j < ic->ic_nchans && nchan < sc->ucode_capa.n_scan_channels; j++) {
c = &ic->ic_channels[j];
/* For 2GHz, only populate 11b channels */
/* For 5GHz, only populate 11a channels */
@ -398,7 +398,7 @@ iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq)
preq->band_data[0].len = htole16(frm - pos);
remain -= frm - pos;
if (isset(sc->sc_enabled_capa,
if (fw_has_capa(&sc->ucode_capa,
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) {
if (remain < 3)
return ENOBUFS;
@ -464,7 +464,7 @@ iwm_mvm_config_umac_scan(struct iwm_softc *sc)
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;
cmd_size = sizeof(*scan_config) + sc->ucode_capa.n_scan_channels;
scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO);
if (scan_config == NULL)
@ -492,7 +492,7 @@ iwm_mvm_config_umac_scan(struct iwm_softc *sc)
IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE;
for (nchan = j = 0;
j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
j < ic->ic_nchans && nchan < sc->ucode_capa.n_scan_channels; j++) {
c = &ic->ic_channels[j];
/* For 2GHz, only populate 11b channels */
/* For 5GHz, only populate 11a channels */
@ -550,7 +550,7 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
req_len = sizeof(struct iwm_scan_req_umac) +
(sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_capa_n_scan_channels) +
sc->ucode_capa.n_scan_channels) +
sizeof(struct iwm_scan_req_umac_tail);
if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
return ENOMEM;
@ -584,7 +584,7 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
tail = (void *)((char *)&req->data +
sizeof(struct iwm_scan_channel_cfg_umac) *
sc->sc_capa_n_scan_channels);
sc->ucode_capa.n_scan_channels);
/* Check if we're doing an active directed scan. */
for (i = 0; i < nssid; i++) {
@ -601,7 +601,7 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
} else
req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE);
if (isset(sc->sc_enabled_capa,
if (fw_has_capa(&sc->ucode_capa,
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
req->general_flags |=
htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED);
@ -644,7 +644,7 @@ iwm_mvm_lmac_scan(struct iwm_softc *sc)
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);
sc->ucode_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);
@ -670,7 +670,7 @@ iwm_mvm_lmac_scan(struct iwm_softc *sc)
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 (isset(sc->sc_enabled_capa,
if (fw_has_capa(&sc->ucode_capa,
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
@ -716,7 +716,7 @@ iwm_mvm_lmac_scan(struct iwm_softc *sc)
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)));
sc->ucode_capa.n_scan_channels)));
if (ret) {
free(req, M_DEVBUF);
return ret;
@ -804,7 +804,7 @@ iwm_mvm_scan_stop_wait(struct iwm_softc *sc)
IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Preparing to stop scan\n");
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
ret = iwm_mvm_umac_scan_abort(sc);
else
ret = iwm_mvm_lmac_scan_abort(sc);

View File

@ -166,6 +166,28 @@ enum iwm_ucode_type {
IWM_UCODE_TYPE_MAX
};
struct iwm_ucode_capabilities {
uint32_t max_probe_length;
uint32_t n_scan_channels;
uint32_t flags;
uint8_t enabled_api[howmany(IWM_NUM_UCODE_TLV_API, NBBY)];
uint8_t enabled_capa[howmany(IWM_NUM_UCODE_TLV_CAPA, NBBY)];
};
static inline int
fw_has_api(const struct iwm_ucode_capabilities *capabilities,
unsigned int api)
{
return isset(capabilities->enabled_api, api);
}
static inline int
fw_has_capa(const struct iwm_ucode_capabilities *capabilities,
unsigned int capa)
{
return isset(capabilities->enabled_capa, capa);
}
/* one for each uCode image (inst/data, init/runtime/wowlan) */
struct iwm_fw_desc {
const void *data; /* vmalloc'ed data */
@ -440,12 +462,8 @@ struct iwm_softc {
int ucode_loaded;
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];
struct iwm_ucode_capabilities ucode_capa;
char sc_fw_mcc[3];
int sc_intmask;