idualwifi7260: Merge new changes from FreeBSD.

These seem to greatly improve driver stability.
This commit is contained in:
Augustin Cavalier
2019-01-23 23:40:46 -05:00
parent 478aa96dd7
commit 3288c09996
15 changed files with 844 additions and 632 deletions
File diff suppressed because it is too large Load Diff
@@ -80,6 +80,8 @@ enum iwm_device_family {
IWM_DEVICE_FAMILY_8000,
};
#define IWM_DEFAULT_MAX_TX_POWER 22
/* Antenna presence definitions */
#define IWM_ANT_NONE 0x0
#define IWM_ANT_A (1 << 0)
@@ -44,6 +44,7 @@ enum {
IWM_DEBUG_TEMP = 0x00100000, /* Thermal Sensor handling */
IWM_DEBUG_FW = 0x00200000, /* Firmware management */
IWM_DEBUG_LAR = 0x00400000, /* Location Aware Regulatory */
IWM_DEBUG_TE = 0x00800000, /* Time Event handling */
IWM_DEBUG_REGISTER = 0x20000000, /* print chipset register */
IWM_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */
IWM_DEBUG_FATAL = 0x80000000, /* fatal errors */
@@ -141,7 +141,7 @@ iwm_free_fw_paging(struct iwm_softc *sc)
}
static int
iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_img *image)
{
int sec_idx, idx;
uint32_t offset = 0;
@@ -158,7 +158,7 @@ iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
* CPU2 paging image (including instruction and data)
*/
for (sec_idx = 0; sec_idx < IWM_UCODE_SECTION_MAX; sec_idx++) {
if (image->fw_sect[sec_idx].offset == IWM_PAGING_SEPARATOR_SECTION) {
if (image->sec[sec_idx].offset == IWM_PAGING_SEPARATOR_SECTION) {
sec_idx++;
break;
}
@@ -168,7 +168,7 @@ iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
* If paging is enabled there should be at least 2 more sections left
* (one for CSS and one for Paging data)
*/
if (sec_idx >= nitems(image->fw_sect) - 1) {
if (sec_idx >= nitems(image->sec) - 1) {
device_printf(sc->sc_dev,
"Paging: Missing CSS and/or paging sections\n");
iwm_free_fw_paging(sc);
@@ -181,7 +181,7 @@ iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
sec_idx);
memcpy(sc->fw_paging_db[0].fw_paging_block.vaddr,
image->fw_sect[sec_idx].data,
image->sec[sec_idx].data,
sc->fw_paging_db[0].fw_paging_size);
IWM_DPRINTF(sc, IWM_DEBUG_FW,
@@ -198,7 +198,7 @@ iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
*/
for (idx = 1; idx < sc->num_of_paging_blk; idx++) {
memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr,
(const char *)image->fw_sect[sec_idx].data + offset,
(const char *)image->sec[sec_idx].data + offset,
sc->fw_paging_db[idx].fw_paging_size);
IWM_DPRINTF(sc, IWM_DEBUG_FW,
@@ -212,7 +212,7 @@ iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
/* copy the last paging block */
if (sc->num_of_pages_in_last_blk > 0) {
memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr,
(const char *)image->fw_sect[sec_idx].data + offset,
(const char *)image->sec[sec_idx].data + offset,
IWM_FW_PAGING_SIZE * sc->num_of_pages_in_last_blk);
IWM_DPRINTF(sc, IWM_DEBUG_FW,
@@ -224,7 +224,7 @@ iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
}
static int
iwm_alloc_fw_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
iwm_alloc_fw_paging_mem(struct iwm_softc *sc, const struct iwm_fw_img *image)
{
int blk_idx = 0;
int error, num_of_pages;
@@ -298,7 +298,7 @@ iwm_alloc_fw_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image)
}
int
iwm_save_fw_paging(struct iwm_softc *sc, const struct iwm_fw_sects *fw)
iwm_save_fw_paging(struct iwm_softc *sc, const struct iwm_fw_img *fw)
{
int ret;
@@ -311,7 +311,7 @@ iwm_save_fw_paging(struct iwm_softc *sc, const struct iwm_fw_sects *fw)
/* send paging cmd to FW in case CPU2 has paging image */
int
iwm_send_paging_cmd(struct iwm_softc *sc, const struct iwm_fw_sects *fw)
iwm_send_paging_cmd(struct iwm_softc *sc, const struct iwm_fw_img *fw)
{
int blk_idx;
uint32_t dev_phy_addr;
@@ -107,7 +107,7 @@
#define IWM_PAGING_TLV_SECURE_MASK 1
extern void iwm_free_fw_paging(struct iwm_softc *);
extern int iwm_save_fw_paging(struct iwm_softc *, const struct iwm_fw_sects *);
extern int iwm_send_paging_cmd(struct iwm_softc *, const struct iwm_fw_sects *);
extern int iwm_save_fw_paging(struct iwm_softc *, const struct iwm_fw_img *);
extern int iwm_send_paging_cmd(struct iwm_softc *, const struct iwm_fw_img *);
#endif /* __IF_IWM_FW_H__ */
@@ -162,6 +162,9 @@ iwm_led_blink_timeout(void *arg)
{
struct iwm_softc *sc = arg;
if (sc->sc_attached == 0)
return;
if (iwm_mvm_led_is_enabled(sc))
iwm_mvm_led_disable(sc);
else
@@ -309,7 +309,12 @@ iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
* 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);
if (ivp->iv_auth) {
IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
} else {
/* XXX Or maybe all zeroes address? */
IEEE80211_ADDR_COPY(cmd->bssid_addr, ieee80211broadcastaddr);
}
#endif
/*
@@ -406,18 +406,39 @@ iwm_prepare_card_hw(struct iwm_softc *sc)
void
iwm_apm_config(struct iwm_softc *sc)
{
uint16_t reg;
uint16_t lctl, cap;
int pcie_ptr;
reg = pci_read_config(sc->sc_dev, PCIER_LINK_CTL, sizeof(reg));
if (reg & PCIEM_LINK_CTL_ASPMC_L1) {
/* Um the Linux driver prints "Disabling L0S for this one ... */
/*
* HW bug W/A for instability in PCIe bus L0S->L1 transition.
* Check if BIOS (or OS) enabled L1-ASPM on this device.
* If so (likely), disable L0S, so device moves directly L0->L1;
* costs negligible amount of power savings.
* If not (unlikely), enable L0S, so there is at least some
* power savings, even without L1.
*/
int error;
error = pci_find_cap(sc->sc_dev, PCIY_EXPRESS, &pcie_ptr);
if (error != 0)
return;
lctl = pci_read_config(sc->sc_dev, pcie_ptr + PCIER_LINK_CTL,
sizeof(lctl));
if (lctl & PCIEM_LINK_CTL_ASPMC_L1) {
IWM_SETBITS(sc, IWM_CSR_GIO_REG,
IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
} else {
/* ... and "Enabling" here */
IWM_CLRBITS(sc, IWM_CSR_GIO_REG,
IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
}
cap = pci_read_config(sc->sc_dev, pcie_ptr + PCIER_DEVICE_CTL2,
sizeof(cap));
sc->sc_ltr_enabled = (cap & PCIEM_CTL2_LTR_ENABLE) ? 1 : 0;
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_PWRSAVE,
"L1 %sabled - LTR %sabled\n",
(lctl & PCIEM_LINK_CTL_ASPMC_L1) ? "En" : "Dis",
sc->sc_ltr_enabled ? "En" : "Dis");
}
/*
@@ -390,7 +390,7 @@ static uint8_t
ch_id_to_ch_index(uint16_t ch_id)
{
if (!is_valid_channel(ch_id))
return 0xff;
return 0xff;
if (ch_id <= 14)
return ch_id - 1;
@@ -509,7 +509,7 @@ iwm_phy_db_send_all_channel_groups(struct iwm_phy_db *phy_db,
int err;
struct iwm_phy_db_entry *entry;
/* Send all the channel specific groups to operational fw */
/* Send all the channel specific groups to operational fw */
for (i = 0; i < max_ch_groups; i++) {
entry = iwm_phy_db_get_section(phy_db,
type,
@@ -215,7 +215,7 @@ static inline boolean_t
iwm_mvm_rrm_scan_needed(struct iwm_softc *sc)
{
/* require rrm scan whenever the fw supports it */
return fw_has_capa(&sc->ucode_capa,
return fw_has_capa(&sc->sc_fw.ucode_capa,
IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT);
}
@@ -251,7 +251,7 @@ iwm_mvm_rx_lmac_scan_complete_notif(struct iwm_softc *sc,
/* If this happens, the firmware has mistakenly sent an LMAC
* notification during UMAC scans -- warn and ignore it.
*/
if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
if (fw_has_capa(&sc->sc_fw.ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
device_printf(sc->sc_dev,
"%s: Mistakenly got LMAC notification during UMAC scan\n",
__func__);
@@ -307,7 +307,8 @@ iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc,
int j;
for (nchan = j = 0;
j < ss->ss_last && nchan < sc->ucode_capa.n_scan_channels; j++) {
j < ss->ss_last && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
j++) {
c = ss->ss_chans[j];
/*
* Catch other channels, in case we have 900MHz channels or
@@ -350,7 +351,8 @@ iwm_mvm_umac_scan_fill_channels(struct iwm_softc *sc,
int j;
for (nchan = j = 0;
j < ss->ss_last && nchan < sc->ucode_capa.n_scan_channels; j++) {
j < ss->ss_last && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
j++) {
c = ss->ss_chans[j];
/*
* Catch other channels, in case we have 900MHz channels or
@@ -495,7 +497,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->ucode_capa.n_scan_channels;
cmd_size = sizeof(*scan_config) + sc->sc_fw.ucode_capa.n_scan_channels;
scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO);
if (scan_config == NULL)
@@ -523,7 +525,8 @@ 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->ucode_capa.n_scan_channels; j++) {
j < ic->ic_nchans && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
j++) {
c = &ic->ic_channels[j];
/* For 2GHz, only populate 11b channels */
/* For 5GHz, only populate 11a channels */
@@ -566,7 +569,7 @@ iwm_mvm_config_umac_scan(struct iwm_softc *sc)
static boolean_t
iwm_mvm_scan_use_ebs(struct iwm_softc *sc)
{
const struct iwm_ucode_capabilities *capa = &sc->ucode_capa;
const struct iwm_ucode_capabilities *capa = &sc->sc_fw.ucode_capa;
/* We can only use EBS if:
* 1. the feature is supported;
@@ -596,7 +599,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->ucode_capa.n_scan_channels) +
sc->sc_fw.ucode_capa.n_scan_channels) +
sizeof(struct iwm_scan_req_umac_tail);
if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
return ENOMEM;
@@ -630,7 +633,7 @@ iwm_mvm_umac_scan(struct iwm_softc *sc)
tail = (void *)((char *)&req->data +
sizeof(struct iwm_scan_channel_cfg_umac) *
sc->ucode_capa.n_scan_channels);
sc->sc_fw.ucode_capa.n_scan_channels);
/* Check if we're doing an active directed scan. */
for (i = 0; i < nssid; i++) {
@@ -694,7 +697,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->ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_probe_req);
sc->sc_fw.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);
@@ -764,7 +767,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->ucode_capa.n_scan_channels)));
sc->sc_fw.ucode_capa.n_scan_channels)));
if (ret) {
free(req, M_DEVBUF);
return ret;
@@ -863,7 +866,7 @@ iwm_mvm_scan_stop_wait(struct iwm_softc *sc)
IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Preparing to stop scan\n");
if (fw_has_capa(&sc->ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
if (fw_has_capa(&sc->sc_fw.ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
ret = iwm_mvm_umac_scan_abort(sc);
else
ret = iwm_mvm_lmac_scan_abort(sc);
@@ -286,7 +286,7 @@ iwm_mvm_rm_sta(struct iwm_softc *sc, struct ieee80211vap *vap,
for (ac = 0; ac < WME_NUM_AC; ac++) {
tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]);
}
ret = iwm_mvm_flush_tx_path(sc, tfd_queue_msk, 0);
ret = iwm_mvm_flush_tx_path(sc, tfd_queue_msk, IWM_CMD_SYNC);
if (ret)
return ret;
#ifdef notyet /* function not yet implemented */
@@ -155,31 +155,188 @@ __FBSDID("$FreeBSD: releng/12.0/sys/dev/iwm/if_iwm_time_event.c 318212 2017-05-1
#include <dev/iwm/if_iwmvar.h>
#include <dev/iwm/if_iwm_debug.h>
#include <dev/iwm/if_iwm_util.h>
#include <dev/iwm/if_iwm_notif_wait.h>
#include <dev/iwm/if_iwm_pcie_trans.h>
#include <dev/iwm/if_iwm_time_event.h>
#define TU_TO_HZ(tu) (((uint64_t)(tu) * 1024 * hz) / 1000000)
static void
iwm_mvm_te_clear_data(struct iwm_softc *sc)
{
sc->sc_time_event_uid = 0;
sc->sc_time_event_duration = 0;
sc->sc_time_event_end_ticks = 0;
sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
}
/*
* For the high priority TE use a time event type that has similar priority to
* the FW's action scan priority.
* Handles a FW notification for an event that is known to the driver.
*
* @mvm: the mvm component
* @te_data: the time event data
* @notif: the notification data corresponding the time event data.
*/
#define IWM_MVM_ROC_TE_TYPE_NORMAL IWM_TE_P2P_DEVICE_DISCOVERABLE
#define IWM_MVM_ROC_TE_TYPE_MGMT_TX IWM_TE_P2P_CLIENT_ASSOC
static void
iwm_mvm_te_handle_notif(struct iwm_softc *sc,
struct iwm_time_event_notif *notif)
{
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Handle time event notif - UID = 0x%x action %d\n",
le32toh(notif->unique_id),
le32toh(notif->action));
if (!le32toh(notif->status)) {
const char *msg;
if (notif->action & htole32(IWM_TE_V2_NOTIF_HOST_EVENT_START))
msg = "Time Event start notification failure";
else
msg = "Time Event end notification failure";
IWM_DPRINTF(sc, IWM_DEBUG_TE, "%s\n", msg);
}
if (le32toh(notif->action) & IWM_TE_V2_NOTIF_HOST_EVENT_END) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"TE ended - current time %d, estimated end %d\n",
ticks, sc->sc_time_event_end_ticks);
iwm_mvm_te_clear_data(sc);
} else if (le32toh(notif->action) & IWM_TE_V2_NOTIF_HOST_EVENT_START) {
sc->sc_time_event_end_ticks =
ticks + TU_TO_HZ(sc->sc_time_event_duration);
} else {
device_printf(sc->sc_dev, "Got TE with unknown action\n");
}
}
/*
* The Rx handler for time event notifications
*/
void
iwm_mvm_rx_time_event_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt)
{
struct iwm_time_event_notif *notif = (void *)pkt->data;
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Time event notification - UID = 0x%x action %d\n",
le32toh(notif->unique_id),
le32toh(notif->action));
iwm_mvm_te_handle_notif(sc, notif);
}
static int
iwm_mvm_te_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
void *data)
{
struct iwm_time_event_notif *resp;
int resp_len = iwm_rx_packet_payload_len(pkt);
if (pkt->hdr.code != IWM_TIME_EVENT_NOTIFICATION ||
resp_len != sizeof(*resp)) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Invalid TIME_EVENT_NOTIFICATION response\n");
return 1;
}
resp = (void *)pkt->data;
/* te_data->uid is already set in the TIME_EVENT_CMD response */
if (le32toh(resp->unique_id) != sc->sc_time_event_uid)
return false;
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"TIME_EVENT_NOTIFICATION response - UID = 0x%x\n",
sc->sc_time_event_uid);
if (!resp->status) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"TIME_EVENT_NOTIFICATION received but not executed\n");
}
return 1;
}
static int
iwm_mvm_time_event_response(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
void *data)
{
struct iwm_time_event_resp *resp;
int resp_len = iwm_rx_packet_payload_len(pkt);
if (pkt->hdr.code != IWM_TIME_EVENT_CMD ||
resp_len != sizeof(*resp)) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Invalid TIME_EVENT_CMD response\n");
return 1;
}
resp = (void *)pkt->data;
/* we should never get a response to another TIME_EVENT_CMD here */
if (le32toh(resp->id) != IWM_TE_BSS_STA_AGGRESSIVE_ASSOC) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Got TIME_EVENT_CMD response with wrong id: %d\n",
le32toh(resp->id));
return 0;
}
sc->sc_time_event_uid = le32toh(resp->unique_id);
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"TIME_EVENT_CMD response - UID = 0x%x\n", sc->sc_time_event_uid);
return 1;
}
/* XXX Use the te_data function argument properly, like in iwlwifi's code. */
static int
iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_vap *ivp,
void *te_data, struct iwm_time_event_cmd *te_cmd)
{
static const uint16_t time_event_response[] = { IWM_TIME_EVENT_CMD };
struct iwm_notification_wait wait_time_event;
int ret;
IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET,
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Add new TE, duration %d TU\n", le32toh(te_cmd->duration));
ret = iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD, IWM_CMD_SYNC,
sizeof(*te_cmd), te_cmd);
sc->sc_time_event_duration = le32toh(te_cmd->duration);
/*
* Use a notification wait, which really just processes the
* command response and doesn't wait for anything, in order
* to be able to process the response and get the UID inside
* the RX path. Using CMD_WANT_SKB doesn't work because it
* stores the buffer and then wakes up this thread, by which
* time another notification (that the time event started)
* might already be processed unsuccessfully.
*/
iwm_init_notification_wait(sc->sc_notif_wait, &wait_time_event,
time_event_response,
nitems(time_event_response),
iwm_mvm_time_event_response, /*te_data*/NULL);
ret = iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD, 0, sizeof(*te_cmd),
te_cmd);
if (ret) {
IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET,
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"%s: Couldn't send IWM_TIME_EVENT_CMD: %d\n",
__func__, ret);
iwm_remove_notification(sc->sc_notif_wait, &wait_time_event);
return ret;
}
/* No need to wait for anything, so just pass 1 (0 isn't valid) */
IWM_UNLOCK(sc);
ret = iwm_wait_notification(sc->sc_notif_wait, &wait_time_event, 1);
IWM_LOCK(sc);
/* should never fail */
if (ret) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"%s: Failed to get response for IWM_TIME_EVENT_CMD: %d\n",
__func__, ret);
}
return ret;
@@ -187,10 +344,16 @@ iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_vap *ivp,
void
iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_vap *ivp,
uint32_t duration, uint32_t max_delay)
uint32_t duration, uint32_t max_delay, boolean_t wait_for_notif)
{
const uint16_t te_notif_response[] = { IWM_TIME_EVENT_NOTIFICATION };
struct iwm_notification_wait wait_te_notif;
struct iwm_time_event_cmd time_cmd = {};
/* Do nothing if a time event is already scheduled. */
if (sc->sc_flags & IWM_FLAG_TE_ACTIVE)
return;
time_cmd.action = htole32(IWM_FW_CTXT_ACTION_ADD);
time_cmd.id_and_color =
htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color));
@@ -209,5 +372,58 @@ iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_vap *ivp,
IWM_TE_V2_NOTIF_HOST_EVENT_END |
IWM_T2_V2_START_IMMEDIATELY);
iwm_mvm_time_event_send_add(sc, ivp, /*te_data*/NULL, &time_cmd);
if (!wait_for_notif) {
iwm_mvm_time_event_send_add(sc, ivp, /*te_data*/NULL, &time_cmd);
DELAY(100);
sc->sc_flags |= IWM_FLAG_TE_ACTIVE;
return;
}
/*
* Create notification_wait for the TIME_EVENT_NOTIFICATION to use
* right after we send the time event
*/
iwm_init_notification_wait(sc->sc_notif_wait, &wait_te_notif,
te_notif_response, nitems(te_notif_response),
iwm_mvm_te_notif, /*te_data*/NULL);
/* If TE was sent OK - wait for the notification that started */
if (iwm_mvm_time_event_send_add(sc, ivp, /*te_data*/NULL, &time_cmd)) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"%s: Failed to add TE to protect session\n", __func__);
iwm_remove_notification(sc->sc_notif_wait, &wait_te_notif);
} else {
sc->sc_flags |= IWM_FLAG_TE_ACTIVE;
IWM_UNLOCK(sc);
if (iwm_wait_notification(sc->sc_notif_wait, &wait_te_notif,
TU_TO_HZ(max_delay))) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"%s: Failed to protect session until TE\n",
__func__);
}
IWM_LOCK(sc);
}
}
void
iwm_mvm_stop_session_protection(struct iwm_softc *sc, struct iwm_vap *ivp)
{
struct iwm_time_event_cmd time_cmd = {};
/* Do nothing if the time event has already ended. */
if ((sc->sc_flags & IWM_FLAG_TE_ACTIVE) == 0)
return;
time_cmd.id = htole32(sc->sc_time_event_uid);
time_cmd.action = htole32(IWM_FW_CTXT_ACTION_REMOVE);
time_cmd.id_and_color =
htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color));
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"%s: Removing TE 0x%x\n", __func__, le32toh(time_cmd.id));
if (iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD, 0, sizeof(time_cmd),
&time_cmd) == 0)
iwm_mvm_te_clear_data(sc);
DELAY(100);
}
@@ -107,7 +107,11 @@
#ifndef __IF_IWM_TIME_EVENT_H__
#define __IF_IWM_TIME_EVENT_H__
extern void iwm_mvm_rx_time_event_notif(struct iwm_softc *sc,
struct iwm_rx_packet *pkt);
extern void iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_vap *ivp,
uint32_t duration, uint32_t max_delay);
uint32_t duration, uint32_t max_delay, boolean_t wait_for_notif);
extern void iwm_mvm_stop_session_protection(struct iwm_softc *sc,
struct iwm_vap *ivp);
#endif /* __IF_IWM_TIME_EVENT_H__ */
@@ -702,8 +702,9 @@ enum iwm_ucode_tlv_api {
* @IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared
* memory addresses from the firmware.
* @IWM_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement
* @IWM_UCODE_TLV_CAPA_LMAC_UPLOAD: supports upload mode in lmac (1=supported,
* 0=no support)
* @IWM_UCODE_TLV_CAPA_TX_POWER_ACK: reduced TX power API has larger
* command size (command version 4) that supports toggling ACK TX
* power reduction.
*
* @IWM_NUM_UCODE_TLV_CAPA: number of bits used
*/
@@ -744,9 +745,9 @@ enum iwm_ucode_tlv_capa {
IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = 75,
IWM_UCODE_TLV_CAPA_CTDP_SUPPORT = 76,
IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED = 77,
IWM_UCODE_TLV_CAPA_LMAC_UPLOAD = 79,
IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = 80,
IWM_UCODE_TLV_CAPA_LQM_SUPPORT = 81,
IWM_UCODE_TLV_CAPA_TX_POWER_ACK = 84,
IWM_NUM_UCODE_TLV_CAPA = 128
};
@@ -1790,15 +1791,11 @@ enum {
/* Power - legacy power table command */
IWM_POWER_TABLE_CMD = 0x77,
IWM_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
IWM_LTR_CONFIG = 0xee,
/* Thermal Throttling*/
IWM_REPLY_THERMAL_MNG_BACKOFF = 0x7e,
/* Scanning */
IWM_SCAN_ABORT_CMD = 0x81,
IWM_SCAN_START_NOTIFICATION = 0x82,
IWM_SCAN_RESULTS_NOTIFICATION = 0x83,
/* NVM */
IWM_NVM_ACCESS_CMD = 0x88,
@@ -1869,8 +1866,6 @@ enum {
IWM_NET_DETECT_PROFILES_CMD = 0x57,
IWM_NET_DETECT_HOTSPOTS_CMD = 0x58,
IWM_NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59,
IWM_REPLY_MAX = 0xff,
};
enum iwm_phy_ops_subcmd_ids {
@@ -1921,6 +1916,51 @@ struct iwm_reduce_tx_power_cmd {
uint16_t pwr_restriction;
} __packed; /* IWM_TX_REDUCED_POWER_API_S_VER_1 */
enum iwm_dev_tx_power_cmd_mode {
IWM_TX_POWER_MODE_SET_MAC = 0,
IWM_TX_POWER_MODE_SET_DEVICE = 1,
IWM_TX_POWER_MODE_SET_CHAINS = 2,
IWM_TX_POWER_MODE_SET_ACK = 3,
}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_4 */;
#define IWM_NUM_CHAIN_LIMITS 2
#define IWM_NUM_SUB_BANDS 5
/**
* struct iwm_dev_tx_power_cmd - TX power reduction command
* @set_mode: see &enum iwl_dev_tx_power_cmd_mode
* @mac_context_id: id of the mac ctx for which we are reducing TX power.
* @pwr_restriction: TX power restriction in 1/8 dBms.
* @dev_24: device TX power restriction in 1/8 dBms
* @dev_52_low: device TX power restriction upper band - low
* @dev_52_high: device TX power restriction upper band - high
* @per_chain_restriction: per chain restrictions
*/
struct iwm_dev_tx_power_cmd_v3 {
uint32_t set_mode;
uint32_t mac_context_id;
uint16_t pwr_restriction;
uint16_t dev_24;
uint16_t dev_52_low;
uint16_t dev_52_high;
uint16_t per_chain_restriction[IWM_NUM_CHAIN_LIMITS][IWM_NUM_SUB_BANDS];
} __packed; /* TX_REDUCED_POWER_API_S_VER_3 */
#define IWM_DEV_MAX_TX_POWER 0x7FFF
/**
* struct iwm_dev_tx_power_cmd - TX power reduction command
* @v3: version 3 of the command, embedded here for easier software handling
* @enable_ack_reduction: enable or disable close range ack TX power
* reduction.
*/
struct iwm_dev_tx_power_cmd {
/* v4 is just an extension of v3 - keep this here */
struct iwm_dev_tx_power_cmd_v3 v3;
uint8_t enable_ack_reduction;
uint8_t reserved[3];
} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */
/*
* Calibration control struct.
* Sent as part of the phy configuration command.
@@ -2102,41 +2142,13 @@ enum {
#define IWM_ALIVE_FLG_RFKILL (1 << 0)
struct iwm_mvm_alive_resp_ver1 {
uint16_t status;
uint16_t flags;
uint8_t ucode_minor;
uint8_t ucode_major;
uint16_t id;
uint8_t api_minor;
uint8_t api_major;
struct iwm_lmac_alive {
uint32_t ucode_major;
uint32_t ucode_minor;
uint8_t ver_subtype;
uint8_t ver_type;
uint8_t mac;
uint8_t opt;
uint16_t reserved2;
uint32_t timestamp;
uint32_t error_event_table_ptr; /* SRAM address for error log */
uint32_t log_event_table_ptr; /* SRAM address for event log */
uint32_t cpu_register_ptr;
uint32_t dbgm_config_ptr;
uint32_t alive_counter_ptr;
uint32_t scd_base_ptr; /* SRAM address for SCD */
} __packed; /* IWM_ALIVE_RES_API_S_VER_1 */
struct iwm_mvm_alive_resp_ver2 {
uint16_t status;
uint16_t flags;
uint8_t ucode_minor;
uint8_t ucode_major;
uint16_t id;
uint8_t api_minor;
uint8_t api_major;
uint8_t ver_subtype;
uint8_t ver_type;
uint8_t mac;
uint8_t opt;
uint16_t reserved2;
uint32_t timestamp;
uint32_t error_event_table_ptr; /* SRAM address for error log */
uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */
@@ -2146,36 +2158,28 @@ struct iwm_mvm_alive_resp_ver2 {
uint32_t scd_base_ptr; /* SRAM address for SCD */
uint32_t st_fwrd_addr; /* pointer to Store and forward */
uint32_t st_fwrd_size;
uint8_t umac_minor; /* UMAC version: minor */
uint8_t umac_major; /* UMAC version: major */
uint16_t umac_id; /* UMAC version: id */
} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_3 */
struct iwm_umac_alive {
uint32_t umac_major; /* UMAC version: major */
uint32_t umac_minor; /* UMAC version: minor */
uint32_t error_info_addr; /* SRAM address for UMAC error log */
uint32_t dbg_print_buff_addr;
} __packed; /* ALIVE_RES_API_S_VER_2 */
} __packed; /* UMAC_ALIVE_DATA_API_S_VER_2 */
struct iwm_mvm_alive_resp_v3 {
uint16_t status;
uint16_t flags;
struct iwm_lmac_alive lmac_data;
struct iwm_umac_alive umac_data;
} __packed; /* ALIVE_RES_API_S_VER_3 */
struct iwm_mvm_alive_resp {
uint16_t status;
uint16_t flags;
uint32_t ucode_minor;
uint32_t ucode_major;
uint8_t ver_subtype;
uint8_t ver_type;
uint8_t mac;
uint8_t opt;
uint32_t timestamp;
uint32_t error_event_table_ptr; /* SRAM address for error log */
uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */
uint32_t cpu_register_ptr;
uint32_t dbgm_config_ptr;
uint32_t alive_counter_ptr;
uint32_t scd_base_ptr; /* SRAM address for SCD */
uint32_t st_fwrd_addr; /* pointer to Store and forward */
uint32_t st_fwrd_size;
uint32_t umac_minor; /* UMAC version: minor */
uint32_t umac_major; /* UMAC version: major */
uint32_t error_info_addr; /* SRAM address for UMAC error log */
uint32_t dbg_print_buff_addr;
} __packed; /* ALIVE_RES_API_S_VER_3 */
struct iwm_lmac_alive lmac_data[2];
struct iwm_umac_alive umac_data;
} __packed; /* ALIVE_RES_API_S_VER_4 */
/* Error response/notification */
enum {
@@ -3527,6 +3531,57 @@ struct iwm_nonqos_seq_query_cmd {
/* Power Management Commands, Responses, Notifications */
/**
* enum iwm_ltr_config_flags - masks for LTR config command flags
* @IWM_LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status
* @IWM_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow
* memory access
* @IWM_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR
* reg change
* @IWM_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from
* D0 to D3
* @IWM_LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register
* @IWM_LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register
* @IWM_LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD
*/
enum iwm_ltr_config_flags {
IWM_LTR_CFG_FLAG_FEATURE_ENABLE = (1 << 0),
IWM_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = (1 << 1),
IWM_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = (1 << 2),
IWM_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = (1 << 3),
IWM_LTR_CFG_FLAG_SW_SET_SHORT = (1 << 4),
IWM_LTR_CFG_FLAG_SW_SET_LONG = (1 << 5),
IWM_LTR_CFG_FLAG_DENIE_C10_ON_PD = (1 << 6),
};
/**
* struct iwm_ltr_config_cmd_v1 - configures the LTR
* @flags: See %enum iwm_ltr_config_flags
*/
struct iwm_ltr_config_cmd_v1 {
uint32_t flags;
uint32_t static_long;
uint32_t static_short;
} __packed; /* LTR_CAPABLE_API_S_VER_1 */
#define IWM_LTR_VALID_STATES_NUM 4
/**
* struct iwm_ltr_config_cmd - configures the LTR
* @flags: See %enum iwm_ltr_config_flags
* @static_long:
* @static_short:
* @ltr_cfg_values:
* @ltr_short_idle_timeout:
*/
struct iwm_ltr_config_cmd {
uint32_t flags;
uint32_t static_long;
uint32_t static_short;
uint32_t ltr_cfg_values[IWM_LTR_VALID_STATES_NUM];
uint32_t ltr_short_idle_timeout;
} __packed; /* LTR_CAPABLE_API_S_VER_2 */
/* Radio LP RX Energy Threshold measured in dBm */
#define IWM_POWER_LPRX_RSSI_THRESHOLD 75
#define IWM_POWER_LPRX_RSSI_THRESHOLD_MAX 94
@@ -4228,29 +4283,6 @@ enum iwm_tx_pm_timeouts {
#define IWM_TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
#define IWM_TX_CMD_SEC_KEY128 0x08
/* TODO: how does these values are OK with only 16 bit variable??? */
/*
* TX command next frame info
*
* bits 0:2 - security control (IWM_TX_CMD_SEC_*)
* bit 3 - immediate ACK required
* bit 4 - rate is taken from STA table
* bit 5 - frame belongs to BA stream
* bit 6 - immediate BA response expected
* bit 7 - unused
* bits 8:15 - Station ID
* bits 16:31 - rate
*/
#define IWM_TX_CMD_NEXT_FRAME_ACK_MSK (0x8)
#define IWM_TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10)
#define IWM_TX_CMD_NEXT_FRAME_BA_MSK (0x20)
#define IWM_TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40)
#define IWM_TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8)
#define IWM_TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00)
#define IWM_TX_CMD_NEXT_FRAME_STA_ID_POS (8)
#define IWM_TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000)
#define IWM_TX_CMD_NEXT_FRAME_RATE_POS (16)
/*
* TX command Frame life time in us - to be written in pm_frame_timeout
*/
@@ -4288,7 +4320,7 @@ enum iwm_tx_pm_timeouts {
* @initial_rate_index: index into the rate table for initial TX attempt.
* Applied if IWM_TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames.
* @key: security key
* @next_frame_flags: IWM_TX_CMD_SEC_* and IWM_TX_CMD_NEXT_FRAME_*
* @reserved3: reserved
* @life_time: frame life time (usecs??)
* @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt +
* btkill_cnd + reserved), first 32 bits. "0" disables usage.
@@ -4952,50 +4984,14 @@ struct iwm_periodic_scan_complete {
uint32_t reserved;
} __packed;
/* How many statistics are gathered for each channel */
#define IWM_SCAN_RESULTS_STATISTICS 1
/**
* enum iwm_scan_complete_status - status codes for scan complete notifications
* @IWM_SCAN_COMP_STATUS_OK: scan completed successfully
* @IWM_SCAN_COMP_STATUS_ABORT: scan was aborted by user
* @IWM_SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed
* @IWM_SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready
* @IWM_SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed
* @IWM_SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed
* @IWM_SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command
* @IWM_SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort
* @IWM_SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax
* @IWM_SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful
* (not an error!)
* @IWM_SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver
* asked for
* @IWM_SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events
*/
enum iwm_scan_complete_status {
IWM_SCAN_COMP_STATUS_OK = 0x1,
IWM_SCAN_COMP_STATUS_ABORT = 0x2,
IWM_SCAN_COMP_STATUS_ERR_SLEEP = 0x3,
IWM_SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4,
IWM_SCAN_COMP_STATUS_ERR_PROBE = 0x5,
IWM_SCAN_COMP_STATUS_ERR_WAKEUP = 0x6,
IWM_SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7,
IWM_SCAN_COMP_STATUS_ERR_INTERNAL = 0x8,
IWM_SCAN_COMP_STATUS_ERR_COEX = 0x9,
IWM_SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA,
IWM_SCAN_COMP_STATUS_ITERATION_END = 0x0B,
IWM_SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C,
};
/**
* struct iwm_scan_results_notif - scan results for one channel
* ( IWM_SCAN_RESULTS_NOTIFICATION = 0x83 )
* struct iwm_scan_results_notif - scan results for one channel -
* SCAN_RESULT_NTF_API_S_VER_3
* @channel: which channel the results are from
* @band: 0 for 5.2 GHz, 1 for 2.4 GHz
* @probe_status: IWM_SCAN_PROBE_STATUS_*, indicates success of probe request
* @num_probe_not_sent: # of request that weren't sent due to not enough time
* @duration: duration spent in channel, in usecs
* @statistics: statistics gathered for this channel
*/
struct iwm_scan_results_notif {
uint8_t channel;
@@ -5003,8 +4999,7 @@ struct iwm_scan_results_notif {
uint8_t probe_status;
uint8_t num_probe_not_sent;
uint32_t duration;
uint32_t statistics[IWM_SCAN_RESULTS_STATISTICS];
} __packed; /* IWM_SCAN_RESULT_NTF_API_S_VER_2 */
} __packed;
enum iwm_scan_framework_client {
IWM_SCAN_CLIENT_SCHED_SCAN = (1 << 0),
@@ -139,15 +139,6 @@ struct iwm_tx_radiotap_header {
#define IWM_UCODE_SECTION_MAX 16
/*
* fw_status is used to determine if we've already parsed the firmware file
*
* In addition to the following, status < 0 ==> -error
*/
#define IWM_FW_STATUS_NONE 0
#define IWM_FW_STATUS_INPROGRESS 1
#define IWM_FW_STATUS_DONE 2
/**
* enum iwm_ucode_type
*
@@ -195,16 +186,20 @@ struct iwm_fw_desc {
uint32_t offset; /* offset in the device */
};
struct iwm_fw_img {
struct iwm_fw_desc sec[IWM_UCODE_SECTION_MAX];
int fw_count;
int is_dual_cpus;
uint32_t paging_mem_size;
};
struct iwm_fw_info {
const struct firmware *fw_fp;
int fw_status;
struct iwm_fw_sects {
struct iwm_fw_desc fw_sect[IWM_UCODE_SECTION_MAX];
int fw_count;
int is_dual_cpus;
uint32_t paging_mem_size;
} fw_sects[IWM_UCODE_TYPE_MAX];
/* ucode images */
struct iwm_fw_img img[IWM_UCODE_TYPE_MAX];
struct iwm_ucode_capabilities ucode_capa;
uint32_t phy_config;
uint8_t valid_tx_ant;
@@ -370,6 +365,7 @@ struct iwm_bf_data {
struct iwm_vap {
struct ieee80211vap iv_vap;
int is_uploaded;
int iv_auth;
int (*iv_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -404,8 +400,6 @@ struct iwm_node {
int in_assoc;
struct iwm_lq_cmd in_lq;
uint8_t in_ridx[IEEE80211_RATE_MAXSIZE];
};
#define IWM_NODE(_ni) ((struct iwm_node *)(_ni))
@@ -440,6 +434,7 @@ struct iwm_softc {
#define IWM_FLAG_BUSY (1 << 4)
#define IWM_FLAG_SCANNING (1 << 5)
#define IWM_FLAG_SCAN_RUNNING (1 << 6)
#define IWM_FLAG_TE_ACTIVE (1 << 7)
struct intr_config_hook sc_preinit_hook;
struct callout sc_watchdog_to;
@@ -482,7 +477,6 @@ struct iwm_softc {
int ucode_loaded;
char sc_fwver[32];
struct iwm_ucode_capabilities ucode_capa;
char sc_fw_mcc[3];
int sc_intmask;
@@ -544,7 +538,7 @@ struct iwm_softc {
int cmd_hold_nic_awake;
/* Firmware status */
uint32_t error_event_table;
uint32_t error_event_table[2];
uint32_t log_event_table;
uint32_t umac_error_event_table;
int support_umac_log;
@@ -565,6 +559,20 @@ struct iwm_softc {
/* Indicate if device power save is allowed */
boolean_t sc_ps_disabled;
int sc_ltr_enabled;
/* Track firmware state for STA association. */
int sc_firmware_state;
/* Unique ID (assigned by the firmware) of the current Time Event. */
uint32_t sc_time_event_uid;
/* Duration of the Time Event in TU. */
uint32_t sc_time_event_duration;
/* Expected end of the Time Event in HZ ticks. */
int sc_time_event_end_ticks;
#ifdef __HAIKU__
uint32_t sc_intr_status_1;
uint32_t sc_intr_status_2;