Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 859d914c authored by Johannes Berg's avatar Johannes Berg Committed by Emmanuel Grumbach
Browse files

iwlwifi: prepare for higher API/CAPA bits



Currently, loading the firmware fails when it has higher API or CAPA
bits than the driver supports. That's an issue with integration.

At the same time, actually using api[0] and capa[0] will become
confusing when we also have api[1] and capa[1], and it's almost
certain that we'll mix up the bits and use the bits for api[1] with
api[0] by accident.

Avoid all this by translating the API/CAPA bits to the regular kernel
test_bit() format, and also providing wrapper functions. Also use the
__bitwise__ facility of sparse to check that we're testing the right
one.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent ebf17ff9
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -423,13 +423,19 @@ static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
{
	const struct iwl_ucode_api *ucode_api = (void *)data;
	u32 api_index = le32_to_cpu(ucode_api->api_index);
	u32 api_flags = le32_to_cpu(ucode_api->api_flags);
	int i;

	if (api_index >= IWL_API_ARRAY_SIZE) {
	if (api_index >= IWL_API_MAX_BITS / 32) {
		IWL_ERR(drv, "api_index larger than supported by driver\n");
		return -EINVAL;
		/* don't return an error so we can load FW that has more bits */
		return 0;
	}

	capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
	for (i = 0; i < 32; i++) {
		if (api_flags & BIT(i))
			__set_bit(i + 32 * api_index, capa->_api);
	}

	return 0;
}
@@ -439,13 +445,19 @@ static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
{
	const struct iwl_ucode_capa *ucode_capa = (void *)data;
	u32 api_index = le32_to_cpu(ucode_capa->api_index);
	u32 api_flags = le32_to_cpu(ucode_capa->api_capa);
	int i;

	if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
	if (api_index >= IWL_CAPABILITIES_MAX_BITS / 32) {
		IWL_ERR(drv, "api_index larger than supported by driver\n");
		return -EINVAL;
		/* don't return an error so we can load FW that has more bits */
		return 0;
	}

	capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
	for (i = 0; i < 32; i++) {
		if (api_flags & BIT(i))
			__set_bit(i + 32 * api_index, capa->_capa);
	}

	return 0;
}
@@ -1148,7 +1160,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
	if (err)
		goto try_again;

	if (drv->fw.ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)
	if (fw_has_api(&drv->fw.ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION))
		api_ver = drv->fw.ucode_ver;
	else
		api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
+36 −31
Original line number Diff line number Diff line
@@ -237,6 +237,8 @@ enum iwl_ucode_tlv_flag {
	IWL_UCODE_TLV_FLAGS_GO_UAPSD		= BIT(30),
};

typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;

/**
 * enum iwl_ucode_tlv_api - ucode api
 * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
@@ -259,21 +261,23 @@ enum iwl_ucode_tlv_flag {
 *	instead of 3.
 */
enum iwl_ucode_tlv_api {
	IWL_UCODE_TLV_API_BT_COEX_SPLIT         = BIT(3),
	IWL_UCODE_TLV_API_FRAGMENTED_SCAN	= BIT(8),
	IWL_UCODE_TLV_API_WIFI_MCC_UPDATE	= BIT(9),
	IWL_UCODE_TLV_API_HDC_PHASE_0		= BIT(10),
	IWL_UCODE_TLV_API_TX_POWER_DEV		= BIT(11),
	IWL_UCODE_TLV_API_BASIC_DWELL		= BIT(13),
	IWL_UCODE_TLV_API_SCD_CFG		= BIT(15),
	IWL_UCODE_TLV_API_SINGLE_SCAN_EBS	= BIT(16),
	IWL_UCODE_TLV_API_ASYNC_DTM		= BIT(17),
	IWL_UCODE_TLV_API_LQ_SS_PARAMS		= BIT(18),
	IWL_UCODE_TLV_API_STATS_V10		= BIT(19),
	IWL_UCODE_TLV_API_NEW_VERSION		= BIT(20),
	IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY	= BIT(24),
	IWL_UCODE_TLV_API_BT_COEX_SPLIT         = (__force iwl_ucode_tlv_api_t)3,
	IWL_UCODE_TLV_API_FRAGMENTED_SCAN	= (__force iwl_ucode_tlv_api_t)8,
	IWL_UCODE_TLV_API_WIFI_MCC_UPDATE	= (__force iwl_ucode_tlv_api_t)9,
	IWL_UCODE_TLV_API_HDC_PHASE_0		= (__force iwl_ucode_tlv_api_t)10,
	IWL_UCODE_TLV_API_TX_POWER_DEV		= (__force iwl_ucode_tlv_api_t)11,
	IWL_UCODE_TLV_API_BASIC_DWELL		= (__force iwl_ucode_tlv_api_t)13,
	IWL_UCODE_TLV_API_SCD_CFG		= (__force iwl_ucode_tlv_api_t)15,
	IWL_UCODE_TLV_API_SINGLE_SCAN_EBS	= (__force iwl_ucode_tlv_api_t)16,
	IWL_UCODE_TLV_API_ASYNC_DTM		= (__force iwl_ucode_tlv_api_t)17,
	IWL_UCODE_TLV_API_LQ_SS_PARAMS		= (__force iwl_ucode_tlv_api_t)18,
	IWL_UCODE_TLV_API_STATS_V10		= (__force iwl_ucode_tlv_api_t)19,
	IWL_UCODE_TLV_API_NEW_VERSION		= (__force iwl_ucode_tlv_api_t)20,
	IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY	= (__force iwl_ucode_tlv_api_t)24,
};

typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;

/**
 * enum iwl_ucode_tlv_capa - ucode capabilities
 * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
@@ -302,22 +306,22 @@ enum iwl_ucode_tlv_api {
 * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
 */
enum iwl_ucode_tlv_capa {
	IWL_UCODE_TLV_CAPA_D0I3_SUPPORT			= BIT(0),
	IWL_UCODE_TLV_CAPA_LAR_SUPPORT			= BIT(1),
	IWL_UCODE_TLV_CAPA_UMAC_SCAN			= BIT(2),
	IWL_UCODE_TLV_CAPA_BEAMFORMER			= BIT(3),
	IWL_UCODE_TLV_CAPA_TDLS_SUPPORT			= BIT(6),
	IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT	= BIT(8),
	IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT	= BIT(9),
	IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT	= BIT(10),
	IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT		= BIT(11),
	IWL_UCODE_TLV_CAPA_DQA_SUPPORT			= BIT(12),
	IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH		= BIT(13),
	IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT		= BIT(18),
	IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS		= BIT(22),
	IWL_UCODE_TLV_CAPA_BT_COEX_PLCR			= BIT(28),
	IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC		= BIT(29),
	IWL_UCODE_TLV_CAPA_BT_COEX_RRC			= BIT(30),
	IWL_UCODE_TLV_CAPA_D0I3_SUPPORT			= (__force iwl_ucode_tlv_capa_t)0,
	IWL_UCODE_TLV_CAPA_LAR_SUPPORT			= (__force iwl_ucode_tlv_capa_t)1,
	IWL_UCODE_TLV_CAPA_UMAC_SCAN			= (__force iwl_ucode_tlv_capa_t)2,
	IWL_UCODE_TLV_CAPA_BEAMFORMER			= (__force iwl_ucode_tlv_capa_t)3,
	IWL_UCODE_TLV_CAPA_TDLS_SUPPORT			= (__force iwl_ucode_tlv_capa_t)6,
	IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT	= (__force iwl_ucode_tlv_capa_t)8,
	IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT	= (__force iwl_ucode_tlv_capa_t)9,
	IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT	= (__force iwl_ucode_tlv_capa_t)10,
	IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT		= (__force iwl_ucode_tlv_capa_t)11,
	IWL_UCODE_TLV_CAPA_DQA_SUPPORT			= (__force iwl_ucode_tlv_capa_t)12,
	IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH		= (__force iwl_ucode_tlv_capa_t)13,
	IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT		= (__force iwl_ucode_tlv_capa_t)18,
	IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS		= (__force iwl_ucode_tlv_capa_t)22,
	IWL_UCODE_TLV_CAPA_BT_COEX_PLCR			= (__force iwl_ucode_tlv_capa_t)28,
	IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC		= (__force iwl_ucode_tlv_capa_t)29,
	IWL_UCODE_TLV_CAPA_BT_COEX_RRC			= (__force iwl_ucode_tlv_capa_t)30,
};

/* The default calibrate table size if not specified by firmware file */
@@ -328,13 +332,14 @@ enum iwl_ucode_tlv_capa {
/* The default max probe length if not specified by the firmware file */
#define IWL_DEFAULT_MAX_PROBE_LENGTH	200

#define IWL_API_MAX_BITS		64
#define IWL_CAPABILITIES_MAX_BITS	64

/*
 * For 16.0 uCode and above, there is no differentiation between sections,
 * just an offset to the HW address.
 */
#define IWL_UCODE_SECTION_MAX 12
#define IWL_API_ARRAY_SIZE	1
#define IWL_CAPABILITIES_ARRAY_SIZE	1
#define CPU1_CPU2_SEPARATOR_SECTION	0xFFFFCCCC

/* uCode version contains 4 values: Major/Minor/API/Serial */
+17 −3
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@
 * BSD LICENSE
 *
 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -105,10 +105,24 @@ struct iwl_ucode_capabilities {
	u32 n_scan_channels;
	u32 standard_phy_calibration_size;
	u32 flags;
	u32 api[IWL_API_ARRAY_SIZE];
	u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
	unsigned long _api[BITS_TO_LONGS(IWL_API_MAX_BITS)];
	unsigned long _capa[BITS_TO_LONGS(IWL_CAPABILITIES_MAX_BITS)];
};

static inline bool
fw_has_api(const struct iwl_ucode_capabilities *capabilities,
	   iwl_ucode_tlv_api_t api)
{
	return test_bit((__force long)api, capabilities->_api);
}

static inline bool
fw_has_capa(const struct iwl_ucode_capabilities *capabilities,
	    iwl_ucode_tlv_capa_t capa)
{
	return test_bit((__force long)capa, capabilities->_capa);
}

/* one for each uCode image (inst/data, init/runtime/wowlan) */
struct fw_desc {
	const void *data;	/* vmalloc'ed data */
+12 −10
Original line number Diff line number Diff line
@@ -411,7 +411,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
	struct iwl_bt_coex_cmd bt_cmd = {};
	u32 mode;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_send_bt_init_conf_old(mvm);

	lockdep_assert_held(&mvm->mutex);
@@ -732,7 +732,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd);

	IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
@@ -762,7 +762,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	int ret;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
	if (!fw_has_api(&mvm->fw->ucode_capa,
			IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
		iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event);
		return;
	}
@@ -813,7 +814,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
	struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
	enum iwl_bt_coex_lut_type lut_type;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_coex_agg_time_limit_old(mvm, sta);

	if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
@@ -840,7 +841,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
	struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
	enum iwl_bt_coex_lut_type lut_type;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);

	if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
@@ -870,7 +871,7 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
	if (ant & mvm->cfg->non_shared_ant)
		return true;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);

	return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
@@ -883,7 +884,7 @@ bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
	if (mvm->cfg->bt_shared_single_ant)
		return true;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);

	return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
@@ -894,7 +895,7 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
{
	u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band);

	if (band != IEEE80211_BAND_2GHZ)
@@ -937,7 +938,8 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,

void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
{
	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
	if (!fw_has_api(&mvm->fw->ucode_capa,
			IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
		iwl_mvm_bt_coex_vif_change_old(mvm);
		return;
	}
@@ -955,7 +957,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
	u8 __maybe_unused lower_bound, upper_bound;
	u8 lut;

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
		return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);

	if (!iwl_mvm_bt_is_plcr_supported(mvm))
+6 −3
Original line number Diff line number Diff line
@@ -493,7 +493,8 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,

	mutex_lock(&mvm->mutex);

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
	if (!fw_has_api(&mvm->fw->ucode_capa,
			IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
		struct iwl_bt_coex_profile_notif_old *notif =
			&mvm->last_bt_notif_old;

@@ -550,7 +551,8 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,

	mutex_lock(&mvm->mutex);

	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
	if (!fw_has_api(&mvm->fw->ucode_capa,
			IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
		struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd_old;

		pos += scnprintf(buf+pos, bufsz-pos,
@@ -916,7 +918,8 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,

	if (mvm->scan_rx_ant != scan_rx_ant) {
		mvm->scan_rx_ant = scan_rx_ant;
		if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
		if (fw_has_capa(&mvm->fw->ucode_capa,
				IWL_UCODE_TLV_CAPA_UMAC_SCAN))
			iwl_mvm_config_scan(mvm);
	}

Loading