static int iwm_mvm_mac_ctxt_remove(struct iwm_softc *sc, struct iwm_node *in) { struct iwm_mac_ctx_cmd cmd; int ret; if (!in->in_uploaded) { device_printf(sc->sc_dev, "attempt to remove !uploaded node %p", in); return EIO; } memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_COLOR)); cmd.action = htole32(IWM_FW_CTXT_ACTION_REMOVE); ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd); if (ret) { device_printf(sc->sc_dev, "Failed to remove MAC context: %d\n", ret); return ret; } in->in_uploaded = 0; return 0; }
/* * 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_send_cmd(struct iwm_softc *sc, struct iwm_mac_ctx_cmd *cmd) { int ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(*cmd), cmd); if (ret) device_printf(sc->sc_dev, "%s: Failed to send MAC context (action:%d): %d\n", __func__, le32toh(cmd->action), ret); return ret; }
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; }
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); }
static int iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *sc, struct iwm_beacon_filter_cmd *cmd) { int ret; ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_BEACON_FILTERING_CMD, IWM_CMD_SYNC, sizeof(struct iwm_beacon_filter_cmd), cmd); if (!ret) { IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "ba_enable_beacon_abort is: %d\n", le32toh(cmd->ba_enable_beacon_abort)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "ba_escape_timer is: %d\n", le32toh(cmd->ba_escape_timer)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_debug_flag is: %d\n", le32toh(cmd->bf_debug_flag)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_enable_beacon_filter is: %d\n", le32toh(cmd->bf_enable_beacon_filter)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_energy_delta is: %d\n", le32toh(cmd->bf_energy_delta)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_escape_timer is: %d\n", le32toh(cmd->bf_escape_timer)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_roaming_energy_delta is: %d\n", le32toh(cmd->bf_roaming_energy_delta)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_roaming_state is: %d\n", le32toh(cmd->bf_roaming_state)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_temp_threshold is: %d\n", le32toh(cmd->bf_temp_threshold)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_temp_fast_filter is: %d\n", le32toh(cmd->bf_temp_fast_filter)); IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE | IWM_DEBUG_CMD, "bf_temp_slow_filter is: %d\n", le32toh(cmd->bf_temp_slow_filter)); } return ret; }
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; }
int iwm_mvm_power_mac_update_mode(struct iwm_softc *sc, struct iwm_node *in) { int ret; int ba_enable; struct iwm_mac_power_cmd cmd; memset(&cmd, 0, sizeof(cmd)); iwm_mvm_power_build_cmd(sc, in, &cmd); iwm_mvm_power_log(sc, &cmd); if ((ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE, IWM_CMD_SYNC, sizeof(cmd), &cmd)) != 0) return ret; ba_enable = !!(cmd.flags & htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwm_mvm_update_beacon_abort(sc, in, ba_enable); }
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); }
/* send station add/update command to firmware */ int iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, boolean_t update) { struct iwm_vap *ivp = IWM_VAP(in->in_ni.ni_vap); struct iwm_mvm_add_sta_cmd add_sta_cmd = { .sta_id = IWM_STATION_ID, .mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)), .add_modify = update ? 1 : 0, .station_flags_msk = htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK), .tid_disable_tx = htole16(0xffff), }; int ret; uint32_t status; uint32_t agg_size = 0, mpdu_dens = 0; if (!update) { int ac; for (ac = 0; ac < WME_NUM_AC; ac++) { add_sta_cmd.tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); } IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid); } add_sta_cmd.station_flags |= htole32(agg_size << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT); add_sta_cmd.station_flags |= htole32(mpdu_dens << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT); status = IWM_ADD_STA_SUCCESS; ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, iwm_mvm_add_sta_cmd_size(sc), &add_sta_cmd, &status); if (ret) return ret; switch (status & IWM_ADD_STA_STATUS_MASK) { case IWM_ADD_STA_SUCCESS: IWM_DPRINTF(sc, IWM_DEBUG_NODE, "IWM_ADD_STA PASSED\n"); break; default: ret = EIO; device_printf(sc->sc_dev, "IWM_ADD_STA failed\n"); break; } return ret; } int iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in) { return iwm_mvm_sta_send_to_fw(sc, in, FALSE); } int iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in) { return iwm_mvm_sta_send_to_fw(sc, in, TRUE); } int iwm_mvm_drain_sta(struct iwm_softc *sc, struct iwm_vap *ivp, boolean_t drain) { struct iwm_mvm_add_sta_cmd cmd = {}; int ret; uint32_t status; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)); cmd.sta_id = IWM_STATION_ID; cmd.add_modify = IWM_STA_MODE_MODIFY; cmd.station_flags = drain ? htole32(IWM_STA_FLG_DRAIN_FLOW) : 0; cmd.station_flags_msk = htole32(IWM_STA_FLG_DRAIN_FLOW); status = IWM_ADD_STA_SUCCESS; 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, "Frames for staid %d will drained in fw\n", IWM_STATION_ID); break; default: ret = EIO; device_printf(sc->sc_dev, "Couldn't drain frames for staid %d\n", IWM_STATION_ID); break; } return ret; } /* * Remove a station from the FW table. Before sending the command to remove * the station validate that the station is indeed known to the driver (sanity * only). */ static int iwm_mvm_rm_sta_common(struct iwm_softc *sc) { struct iwm_mvm_rm_sta_cmd rm_sta_cmd = { .sta_id = IWM_STATION_ID, }; int ret; ret = iwm_mvm_send_cmd_pdu(sc, IWM_REMOVE_STA, 0, sizeof(rm_sta_cmd), &rm_sta_cmd); if (ret) { device_printf(sc->sc_dev, "Failed to remove station. Id=%d\n", IWM_STATION_ID); return ret; } return 0; } int iwm_mvm_rm_sta(struct iwm_softc *sc, struct ieee80211vap *vap, boolean_t is_assoc) { uint32_t tfd_queue_msk = 0; int ret; int ac; ret = iwm_mvm_drain_sta(sc, IWM_VAP(vap), TRUE); if (ret) return ret; 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); if (ret) return ret; #ifdef notyet /* function not yet implemented */ ret = iwl_trans_wait_tx_queue_empty(mvm->trans, mvm_sta->tfd_queue_msk); if (ret) return ret; #endif ret = iwm_mvm_drain_sta(sc, IWM_VAP(vap), FALSE); /* if we are associated - we can't remove the AP STA now */ if (is_assoc) return ret; /* XXX wait until STA is drained */ ret = iwm_mvm_rm_sta_common(sc); return ret; }