static int iwm_phy_db_send_all_channel_groups(struct iwm_softc *sc, enum iwm_phy_db_section_type type, uint8_t max_ch_groups) { uint16_t i; int err; struct iwm_phy_db_entry *entry; /* Send all the channel-specific groups to operational fw */ for (i = 0; i < max_ch_groups; i++) { entry = iwm_phy_db_get_section(sc, type, i); if (!entry) return EINVAL; if (!entry->size) continue; /* Send the requested PHY DB section */ err = iwm_send_phy_db_cmd(sc, type, entry->size, entry->data); if (err) { IWM_DPRINTF(sc, IWM_DEBUG_CMD, "%s: Can't SEND phy_db section %d (%d), " "err %d\n", __func__, type, i, err); return err; } IWM_DPRINTF(sc, IWM_DEBUG_CMD, "Sent PHY_DB HCMD, type = %d num = %d\n", type, i); } return 0; }
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; }
static int iwm_phy_db_get_section_data(struct iwm_softc *sc, uint32_t type, uint8_t **data, uint16_t *size, uint16_t ch_id) { struct iwm_phy_db_entry *entry; uint16_t ch_group_id = 0; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "->%s\n", __func__); /* find wanted channel group */ if (type == IWM_PHY_DB_CALIB_CHG_PAPD) ch_group_id = iwm_channel_id_to_papd(ch_id); else if (type == IWM_PHY_DB_CALIB_CHG_TXP) ch_group_id = iwm_channel_id_to_txp(sc, ch_id); entry = iwm_phy_db_get_section(sc, type, ch_group_id); if (!entry) return EINVAL; *data = entry->data; *size = entry->size; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", __func__, __LINE__, type, *size); return 0; }
int iwm_prepare_card_hw(struct iwm_softc *sc) { int rv = 0; int t = 0; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "->%s\n", __func__); if (iwm_set_hw_ready(sc)) goto out; /* If HW is not ready, prepare the conditions to check again */ IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_PREPARE); do { if (iwm_set_hw_ready(sc)) goto out; DELAY(200); t += 200; } while (t < 150000); rv = ETIMEDOUT; out: IWM_DPRINTF(sc, IWM_DEBUG_RESET, "<-%s\n", __func__); return rv; }
/* * 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. */ 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"); } }
static int iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd, int flags, int n_ssids, int basic_ssid) { 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; if (!basic_ssid) type |= (1 << n_ssids); for (nchan = j = 0; j < ic->ic_nchans; 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 ((flags & IEEE80211_CHAN_2GHZ) && (! IEEE80211_IS_CHAN_B(c))) { continue; } else if ((flags & IEEE80211_CHAN_5GHZ) && (! IEEE80211_IS_CHAN_A(c))) { continue; } else { 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); } 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); chan++; nchan++; } if (nchan == 0) device_printf(sc->sc_dev, "%s: NO CHANNEL!\n", __func__); return nchan; }
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_TE, "Add new TE, duration %d TU\n", le32toh(te_cmd->duration)); 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, NELEM(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_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; }
/* * Send a command * only if something in the configuration changed: in case that this is the * first time that the phy configuration is applied or in case that the phy * configuration changed from the previous apply. */ static int iwm_mvm_phy_ctxt_apply(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt, uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint32_t apply_time) { struct iwm_phy_context_cmd cmd; int ret; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD, "%s: called; channel=%p\n", __func__, ctxt->channel); /* Set the command header fields */ iwm_mvm_phy_ctxt_cmd_hdr(sc, ctxt, &cmd, action, apply_time); /* Set the command data */ iwm_mvm_phy_ctxt_cmd_data(sc, &cmd, ctxt->channel, chains_static, chains_dynamic); ret = iwm_mvm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(struct iwm_phy_context_cmd), &cmd); if (ret) { device_printf(sc->sc_dev, "PHY ctxt cmd error. ret=%d\n", ret); } return ret; }
static int iwm_mvm_mac_ctxt_cmd_station(struct iwm_softc *sc, struct ieee80211vap *vap, uint32_t action) { struct ieee80211_node *ni = vap->iv_bss; struct iwm_node *in = (struct iwm_node *) ni; struct iwm_mac_ctx_cmd cmd; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s: called; action=%d\n", __func__, action); memset(&cmd, 0, sizeof(cmd)); /* Fill the common data for all mac context types */ iwm_mvm_mac_ctxt_cmd_common(sc, in, &cmd, action); /* Allow beacons to pass through as long as we are not associated,or we * do not have dtim period information */ if (!in->in_assoc || !vap->iv_dtim_period) cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON); else cmd.filter_flags &= ~htole32(IWM_MAC_FILTER_IN_BEACON); /* Fill the data specific for station mode */ iwm_mvm_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, action == IWM_FW_CTXT_ACTION_ADD); return iwm_mvm_mac_ctxt_send_cmd(sc, &cmd); }
int iwm_nic_lock(struct iwm_softc *sc) { int rv = 0; if (sc->cmd_hold_nic_awake) return 1; IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); if (sc->cfg->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; } 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); } return rv; }
static int iwm_send_phy_db_cmd(struct iwm_phy_db *phy_db, uint16_t type, uint16_t length, void *data) { struct iwm_phy_db_cmd phy_db_cmd; struct iwm_host_cmd cmd = { .id = PHY_DB_CMD, }; IWM_DPRINTF(phy_db->sc, IWM_DEBUG_RESET, "Sending PHY-DB hcmd of type %d, of length %d\n", type, length); /* Set phy db cmd variables */ phy_db_cmd.type = htole16(type); phy_db_cmd.length = htole16(length); /* Set hcmd variables */ cmd.data[0] = &phy_db_cmd; cmd.len[0] = sizeof(struct iwm_phy_db_cmd); cmd.data[1] = data; cmd.len[1] = length; #ifdef notyet cmd.dataflags[1] = IWM_HCMD_DFL_NOCOPY; #endif return iwm_send_cmd(phy_db->sc, &cmd); }
static int iwm_send_phy_db_cmd(struct iwm_softc *sc, uint16_t type, uint16_t length, void *data) { struct iwm_phy_db_cmd phy_db_cmd; struct iwm_host_cmd cmd = { .id = IWM_PHY_DB_CMD, .flags = IWM_CMD_SYNC, }; IWM_DPRINTF(sc, IWM_DEBUG_CMD, "Sending PHY-DB hcmd of type %d, of length %d\n", type, length); /* Set phy db cmd variables */ phy_db_cmd.type = le16toh(type); phy_db_cmd.length = le16toh(length); /* Set hcmd variables */ cmd.data[0] = &phy_db_cmd; 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); }
int iwm_phy_db_set_section(struct iwm_softc *sc, struct iwm_calib_res_notif_phy_db *phy_db_notif) { enum iwm_phy_db_section_type type = le16toh(phy_db_notif->type); uint16_t size = le16toh(phy_db_notif->length); struct iwm_phy_db_entry *entry; uint16_t chg_id = 0; if (type == IWM_PHY_DB_CALIB_CHG_PAPD || type == IWM_PHY_DB_CALIB_CHG_TXP) chg_id = le16toh(*(uint16_t *)phy_db_notif->data); entry = iwm_phy_db_get_section(sc, type, chg_id); if (!entry) return EINVAL; if (entry->data) kfree(entry->data, M_DEVBUF); entry->data = kmalloc(size, M_DEVBUF, M_INTWAIT); if (!entry->data) { entry->size = 0; return ENOMEM; } memcpy(entry->data, phy_db_notif->data, size); entry->size = size; IWM_DPRINTF(sc, IWM_DEBUG_RESET, "%s(%d): [PHYDB]SET: Type %d , Size: %d, data: %p\n", __func__, __LINE__, type, size, entry->data); return 0; }
void iwm_mvm_rx_lmac_scan_complete_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { struct iwm_periodic_scan_complete *scan_notif = (void *)pkt->data; /* 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)) { device_printf(sc->sc_dev, "%s: Mistakenly got LMAC notification during UMAC scan\n", __func__); return; } IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Regular scan %s, EBS status %s (FW)\n", iwm_mvm_offload_status_str(scan_notif->status), iwm_mvm_ebs_status_str(scan_notif->ebs_status)); sc->last_ebs_successful = scan_notif->ebs_status == IWM_SCAN_EBS_SUCCESS || scan_notif->ebs_status == IWM_SCAN_EBS_INACTIVE; }
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) { int ret; IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "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); if (ret) { IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "%s: Couldn't send IWM_TIME_EVENT_CMD: %d\n", __func__, ret); } return ret; }
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; struct ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211_channel *c; uint8_t nchan; int j; for (nchan = j = 0; j < ss->ss_last && nchan < sc->ucode_capa.n_scan_channels; j++) { c = ss->ss_chans[j]; /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (!IEEE80211_IS_CHAN_2GHZ(c) && !IEEE80211_IS_CHAN_5GHZ(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; } 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 = 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); chan->flags |= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids)); /* XXX IEEE80211_SCAN_NOBCAST flag is never set. */ if (!IEEE80211_IS_CHAN_PASSIVE(c) && (!(ss->ss_flags & IEEE80211_SCAN_NOBCAST) || n_ssids != 0)) chan->flags |= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE); chan++; nchan++; } return nchan; }
int iwm_mvm_binding_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action) { struct iwm_binding_cmd cmd; struct iwm_mvm_phy_ctxt *phyctxt = in->in_phyctxt; int i, ret; uint32_t status; memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color)); cmd.action = htole32(action); cmd.phy = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color)); cmd.macs[0] = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR)); /* We use MACID 0 here.. */ for (i = 1; i < IWM_MAX_MACS_IN_BINDING; i++) cmd.macs[i] = htole32(IWM_FW_CTXT_INVALID); status = 0; ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_BINDING_CONTEXT_CMD, sizeof(cmd), &cmd, &status); if (ret) { IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "%s: Failed to send binding (action:%d): %d\n", __func__, action, ret); return ret; } if (status) { IWM_DPRINTF(sc, IWM_DEBUG_CMD | IWM_DEBUG_RESET, "%s: Binding command failed: %u\n", __func__, status); ret = EIO; } return ret; }
/* iwlwifi/pcie/trans.c */ void iwm_apm_stop(struct iwm_softc *sc) { /* stop device's busmaster DMA activity */ IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER); if (!iwm_poll_bit(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100)) device_printf(sc->sc_dev, "timeout waiting for master\n"); IWM_DPRINTF(sc, IWM_DEBUG_TRANS, "%s: iwm apm stop\n", __func__); }
/* * 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 void iwm_mvm_power_log(struct iwm_softc *sc, struct iwm_mac_power_cmd *cmd) { IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "Sending power table command on mac id 0x%X for " "power level %d, flags = 0x%X\n", cmd->id_and_color, IWM_POWER_SCHEME_CAM, le16toh(cmd->flags)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "Keep alive = %u sec\n", le16toh(cmd->keep_alive_seconds)); if (!(cmd->flags & htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) { IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "Disable power management\n"); return; } KASSERT(0, ("unhandled power management")); #if 0 DPRINTF(mvm, "Rx timeout = %u usec\n", le32_to_cpu(cmd->rx_data_timeout)); DPRINTF(mvm, "Tx timeout = %u usec\n", le32_to_cpu(cmd->tx_data_timeout)); if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK)) DPRINTF(mvm, "DTIM periods to skip = %u\n", cmd->skip_dtim_periods); if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_LPRX_ENA_MSK)) DPRINTF(mvm, "LP RX RSSI threshold = %u\n", cmd->lprx_rssi_threshold); if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { DPRINTF(mvm, "uAPSD enabled\n"); DPRINTF(mvm, "Rx timeout (uAPSD) = %u usec\n", le32_to_cpu(cmd->rx_data_timeout_uapsd)); DPRINTF(mvm, "Tx timeout (uAPSD) = %u usec\n", le32_to_cpu(cmd->tx_data_timeout_uapsd)); DPRINTF(mvm, "QNDP TID = %d\n", cmd->qndp_tid); DPRINTF(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags); DPRINTF(mvm, "Max SP = %d\n", cmd->uapsd_max_sp); } #endif }
/* * Send a command to modify the PHY context based on the current HW * configuration. Note that the function does not check that the configuration * changed. */ int iwm_mvm_phy_ctxt_changed(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt, struct ieee80211_channel *chan, uint8_t chains_static, uint8_t chains_dynamic) { ctxt->channel = chan; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD, "%s: called; channel=%d\n", __func__, ieee80211_chan2ieee(&sc->sc_ic, chan)); return iwm_mvm_phy_ctxt_apply(sc, ctxt, chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_MODIFY, 0); }
void iwm_mvm_rx_umac_scan_complete_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { struct iwm_umac_scan_complete *notif = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan completed, uid %u, status %s, EBS status %s\n", le32toh(notif->uid), iwm_mvm_offload_status_str(notif->status), iwm_mvm_ebs_status_str(notif->ebs_status)); if (notif->ebs_status != IWM_SCAN_EBS_SUCCESS && notif->ebs_status != IWM_SCAN_EBS_INACTIVE) sc->last_ebs_successful = FALSE; }
int iwm_mvm_power_update_device(struct iwm_softc *sc) { struct iwm_device_power_cmd cmd = { .flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), }; if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) return 0; cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_CAM_MSK); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "Sending device power command with flags = 0x%X\n", cmd.flags); return iwm_mvm_send_cmd_pdu(sc, IWM_POWER_TABLE_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd); }
/* * Construct the generic fields of the PHY context command */ static void iwm_mvm_phy_ctxt_cmd_hdr(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt, struct iwm_phy_context_cmd *cmd, uint32_t action, uint32_t apply_time) { memset(cmd, 0, sizeof(struct iwm_phy_context_cmd)); IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD, "%s: id=%d, colour=%d, action=%d, apply_time=%d\n", __func__, ctxt->id, ctxt->color, action, apply_time); cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ctxt->id, ctxt->color)); cmd->action = htole32(action); cmd->apply_time = htole32(apply_time); }
/* iwlwifi: pcie/trans.c */ int iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords) { int offs; const uint32_t *vals = buf; if (iwm_nic_lock(sc)) { IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WADDR, addr); /* WADDR auto-increments */ for (offs = 0; offs < dwords; offs++) { uint32_t val = vals ? vals[offs] : 0; IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WDAT, val); } iwm_nic_unlock(sc); } else { IWM_DPRINTF(sc, IWM_DEBUG_TRANS, "%s: write_mem failed\n", __func__); return EBUSY; } return 0; }
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); }
/* * Add the phy configuration to the PHY context command */ static void iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd, struct ieee80211_channel *chan, uint8_t chains_static, uint8_t chains_dynamic) { struct ieee80211com *ic = &sc->sc_ic; uint8_t active_cnt, idle_cnt; IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_CMD, "%s: 2ghz=%d, channel=%d, chains static=0x%x, dynamic=0x%x, " "rx_ant=0x%x, tx_ant=0x%x\n", __func__, !! IEEE80211_IS_CHAN_2GHZ(chan), ieee80211_chan2ieee(ic, chan), chains_static, chains_dynamic, iwm_fw_valid_rx_ant(sc), iwm_fw_valid_tx_ant(sc)); cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWM_PHY_BAND_24 : IWM_PHY_BAND_5; cmd->ci.channel = ieee80211_chan2ieee(ic, chan); cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20; cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW; /* Set rx the chains */ idle_cnt = chains_static; active_cnt = chains_dynamic; 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)); }
static int iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta, const uint8_t *addr, uint16_t mac_id, uint16_t color) { struct iwm_mvm_add_sta_cmd cmd; int ret; uint32_t status; memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta->sta_id; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color)); cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk); cmd.tid_disable_tx = htole16(0xffff); if (addr) IEEE80211_ADDR_COPY(cmd.addr, addr); ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, iwm_mvm_add_sta_cmd_size(sc), &cmd, &status); if (ret) return ret; switch (status & IWM_ADD_STA_STATUS_MASK) { case IWM_ADD_STA_SUCCESS: IWM_DPRINTF(sc, IWM_DEBUG_NODE, "Internal station added.\n"); return 0; default: ret = EIO; device_printf(sc->sc_dev, "Add internal station failed, status=0x%x\n", status); break; } return ret; }
void iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_vap *ivp, 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)); time_cmd.id = htole32(IWM_TE_BSS_STA_AGGRESSIVE_ASSOC); time_cmd.apply_time = htole32(0); time_cmd.max_frags = IWM_TE_V2_FRAG_NONE; time_cmd.max_delay = htole32(max_delay); /* TODO: why do we need to interval = bi if it is not periodic? */ time_cmd.interval = htole32(1); time_cmd.duration = htole32(duration); time_cmd.repeat = 1; time_cmd.policy = htole16(IWM_TE_V2_NOTIF_HOST_EVENT_START | IWM_TE_V2_NOTIF_HOST_EVENT_END | IWM_T2_V2_START_IMMEDIATELY); 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, NELEM(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); } }