Beispiel #1
0
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;
}
Beispiel #4
0
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");
	}
}
Beispiel #7
0
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;
}
Beispiel #9
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;
}
Beispiel #10
0
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);
}
Beispiel #11
0
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);
}
Beispiel #13
0
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);
}
Beispiel #14
0
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;
}
Beispiel #15
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;

}
Beispiel #16
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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
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__);
}
Beispiel #20
0
/*
 * 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);
}
Beispiel #21
0
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
}
Beispiel #22
0
/*
 * 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);
}
Beispiel #23
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;
}
Beispiel #24
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);
}
Beispiel #25
0
/*
 * 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;
}
Beispiel #27
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);
}
Beispiel #28
0
/*
 * 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));
}
Beispiel #29
0
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;
}
Beispiel #30
0
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);
	}
}