Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
/* 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;
}