diff options
Diffstat (limited to 'drivers/net/wireless/intel')
23 files changed, 387 insertions, 143 deletions
| diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index bfa542c8d6f1..64176090b196 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -6035,7 +6035,6 @@ static const struct net_device_ops ipw2100_netdev_ops = {  	.ndo_open		= ipw2100_open,  	.ndo_stop		= ipw2100_close,  	.ndo_start_xmit		= libipw_xmit, -	.ndo_change_mtu		= libipw_change_mtu,  	.ndo_tx_timeout		= ipw2100_tx_timeout,  	.ndo_set_mac_address	= ipw2100_set_address,  	.ndo_validate_addr	= eth_validate_addr, @@ -6071,6 +6070,8 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,  	dev->wireless_data = &priv->wireless_data;  	dev->watchdog_timeo = 3 * HZ;  	dev->irq = 0; +	dev->min_mtu = 68; +	dev->max_mtu = LIBIPW_DATA_LEN;  	/* NOTE: We don't use the wireless_handlers hook  	 * in dev as the system will start throwing WX requests diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index bfd68612a535..ef9af8a29cad 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -11561,7 +11561,6 @@ static const struct net_device_ops ipw_prom_netdev_ops = {  	.ndo_open 		= ipw_prom_open,  	.ndo_stop		= ipw_prom_stop,  	.ndo_start_xmit		= ipw_prom_hard_start_xmit, -	.ndo_change_mtu		= libipw_change_mtu,  	.ndo_set_mac_address 	= eth_mac_addr,  	.ndo_validate_addr	= eth_validate_addr,  }; @@ -11587,6 +11586,9 @@ static int ipw_prom_alloc(struct ipw_priv *priv)  	priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;  	priv->prom_net_dev->netdev_ops = &ipw_prom_netdev_ops; +	priv->prom_net_dev->min_mtu = 68; +	priv->prom_net_dev->max_mtu = LIBIPW_DATA_LEN; +  	priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;  	SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev); @@ -11619,7 +11621,6 @@ static const struct net_device_ops ipw_netdev_ops = {  	.ndo_set_rx_mode	= ipw_net_set_multicast_list,  	.ndo_set_mac_address	= ipw_net_set_mac_address,  	.ndo_start_xmit		= libipw_xmit, -	.ndo_change_mtu		= libipw_change_mtu,  	.ndo_validate_addr	= eth_validate_addr,  }; @@ -11729,6 +11730,9 @@ static int ipw_pci_probe(struct pci_dev *pdev,  	net_dev->wireless_handlers = &ipw_wx_handler_def;  	net_dev->ethtool_ops = &ipw_ethtool_ops; +	net_dev->min_mtu = 68; +	net_dev->max_mtu = LIBIPW_DATA_LEN; +  	err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);  	if (err) {  		IPW_ERROR("failed to create sysfs device attributes\n"); diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h index b0571618c2ed..b51355134e04 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw.h +++ b/drivers/net/wireless/intel/ipw2x00/libipw.h @@ -948,7 +948,6 @@ static inline int libipw_is_cck_rate(u8 rate)  /* libipw.c */  void free_libipw(struct net_device *dev, int monitor);  struct net_device *alloc_libipw(int sizeof_priv, int monitor); -int libipw_change_mtu(struct net_device *dev, int new_mtu);  void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs); diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index 60f28740f6af..2332075565f2 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -118,15 +118,6 @@ static void libipw_networks_initialize(struct libipw_device *ieee)  			      &ieee->network_free_list);  } -int libipw_change_mtu(struct net_device *dev, int new_mtu) -{ -	if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN)) -		return -EINVAL; -	dev->mtu = new_mtu; -	return 0; -} -EXPORT_SYMBOL(libipw_change_mtu); -  struct net_device *alloc_libipw(int sizeof_priv, int monitor)  {  	struct libipw_device *ieee; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index cef7f7d79cd9..1c1ec7bb9302 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -507,7 +507,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,  		memcpy(dst, hdr->addr3, ETH_ALEN);  		memcpy(src, hdr->addr4, ETH_ALEN);  		break; -	case 0: +	default:  		memcpy(dst, hdr->addr1, ETH_ALEN);  		memcpy(src, hdr->addr2, ETH_ALEN);  		break; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index ceec5ca2b1ab..1ad0ec180d5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -293,6 +293,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;   *	is supported.   * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC   * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan + * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification   * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement   * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts   * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT @@ -342,6 +343,7 @@ enum iwl_ucode_tlv_capa {  	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,  	IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT		= (__force iwl_ucode_tlv_capa_t)31, +	IWL_UCODE_TLV_CAPA_STA_PM_NOTIF			= (__force iwl_ucode_tlv_capa_t)38,  	IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE		= (__force iwl_ucode_tlv_capa_t)64,  	IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS		= (__force iwl_ucode_tlv_capa_t)65,  	IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT		= (__force iwl_ucode_tlv_capa_t)67, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 4fdc3dad3e85..b88e2048ae0b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1087,6 +1087,15 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,  		ret = iwl_mvm_switch_to_d3(mvm);  		if (ret)  			return ret; +	} else { +		/* In theory, we wouldn't have to stop a running sched +		 * scan in order to start another one (for +		 * net-detect).  But in practice this doesn't seem to +		 * work properly, so stop any running sched_scan now. +		 */ +		ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); +		if (ret) +			return ret;  	}  	/* rfkill release can be either for wowlan or netdetect */ @@ -1254,7 +1263,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,   out:  	if (ret < 0) {  		iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); -		ieee80211_restart_hw(mvm->hw); +		if (mvm->restart_fw > 0) { +			mvm->restart_fw--; +			ieee80211_restart_hw(mvm->hw); +		}  		iwl_mvm_free_nd(mvm);  	}   out_noreset: @@ -2088,6 +2100,16 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)  	iwl_mvm_update_changed_regdom(mvm);  	if (mvm->net_detect) { +		/* If this is a non-unified image, we restart the FW, +		 * so no need to stop the netdetect scan.  If that +		 * fails, continue and try to get the wake-up reasons, +		 * but trigger a HW restart by keeping a failure code +		 * in ret. +		 */ +		if (unified_image) +			ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_NETDETECT, +						false); +  		iwl_mvm_query_netdetect_reasons(mvm, vif);  		/* has unlocked the mutex, so skip that */  		goto out; @@ -2271,7 +2293,8 @@ static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,  static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)  {  	struct iwl_mvm *mvm = inode->i_private; -	int remaining_time = 10; +	bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, +					 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);  	mvm->d3_test_active = false; @@ -2282,17 +2305,21 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)  	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;  	iwl_abort_notification_waits(&mvm->notif_wait); -	ieee80211_restart_hw(mvm->hw); +	if (!unified_image) { +		int remaining_time = 10; -	/* wait for restart and disconnect all interfaces */ -	while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && -	       remaining_time > 0) { -		remaining_time--; -		msleep(1000); -	} +		ieee80211_restart_hw(mvm->hw); + +		/* wait for restart and disconnect all interfaces */ +		while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && +		       remaining_time > 0) { +			remaining_time--; +			msleep(1000); +		} -	if (remaining_time == 0) -		IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n"); +		if (remaining_time == 0) +			IWL_ERR(mvm, "Timed out waiting for HW restart!\n"); +	}  	ieee80211_iterate_active_interfaces_atomic(  		mvm->hw, IEEE80211_IFACE_ITER_NORMAL, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 07da4efe8458..7b7d2a146e30 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1529,8 +1529,8 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,  		.data = { &cmd, },  		.len = { sizeof(cmd) },  	}; -	size_t delta, len; -	ssize_t ret; +	size_t delta; +	ssize_t ret, len;  	hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,  			     DEBUG_GROUP, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index acc5cd53e4ba..b530fa47d68a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -474,4 +474,30 @@ struct iwl_mvm_internal_rxq_notif {  	u8 data[];  } __packed; +/** + * enum iwl_mvm_pm_event - type of station PM event + * @IWL_MVM_PM_EVENT_AWAKE: station woke up + * @IWL_MVM_PM_EVENT_ASLEEP: station went to sleep + * @IWL_MVM_PM_EVENT_UAPSD: station sent uAPSD trigger + * @IWL_MVM_PM_EVENT_PS_POLL: station sent PS-Poll + */ +enum iwl_mvm_pm_event { +	IWL_MVM_PM_EVENT_AWAKE, +	IWL_MVM_PM_EVENT_ASLEEP, +	IWL_MVM_PM_EVENT_UAPSD, +	IWL_MVM_PM_EVENT_PS_POLL, +}; /* PEER_PM_NTFY_API_E_VER_1 */ + +/** + * struct iwl_mvm_pm_state_notification - station PM state notification + * @sta_id: station ID of the station changing state + * @type: the new powersave state, see IWL_MVM_PM_EVENT_ above + */ +struct iwl_mvm_pm_state_notification { +	u8 sta_id; +	u8 type; +	/* private: */ +	u16 reserved; +} __packed; /* PEER_PM_NTFY_API_S_VER_1 */ +  #endif /* __fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 6c8e3ca79323..3b5150e9975d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -179,7 +179,7 @@ enum iwl_sta_key_flag {   * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed   * @STA_MODIFY_QUEUE_REMOVAL: this command removes a queue   * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx - * @STA_MODIFY_TX_RATE: unused + * @STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_trigger_acs   * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid   * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid   * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count @@ -189,7 +189,7 @@ enum iwl_sta_key_flag {  enum iwl_sta_modify_flag {  	STA_MODIFY_QUEUE_REMOVAL		= BIT(0),  	STA_MODIFY_TID_DISABLE_TX		= BIT(1), -	STA_MODIFY_TX_RATE			= BIT(2), +	STA_MODIFY_UAPSD_ACS			= BIT(2),  	STA_MODIFY_ADD_BA_TID			= BIT(3),  	STA_MODIFY_REMOVE_BA_TID		= BIT(4),  	STA_MODIFY_SLEEPING_STA_TX_COUNT	= BIT(5), @@ -353,6 +353,8 @@ struct iwl_mvm_add_sta_cmd_v7 {   * @beamform_flags: beam forming controls   * @tfd_queue_msk: tfd queues used by this station   * @rx_ba_window: aggregation window size + * @scd_queue_bank: queue bank in used. Each bank contains 32 queues. 0 means + *	that the queues used by this station are in the first 32.   *   * The device contains an internal table of per-station information, with info   * on security keys, aggregation parameters, and Tx rates for initial Tx @@ -382,7 +384,8 @@ struct iwl_mvm_add_sta_cmd {  	__le16 beamform_flags;  	__le32 tfd_queue_msk;  	__le16 rx_ba_window; -	__le16 reserved; +	u8 scd_queue_bank; +	u8 uapsd_trigger_acs;  } __packed; /* ADD_STA_CMD_API_S_VER_8 */  /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 97633690f3d5..ae12badc0c2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -332,6 +332,7 @@ enum iwl_data_path_subcmd_ids {  	DQA_ENABLE_CMD = 0x0,  	UPDATE_MU_GROUPS_CMD = 0x1,  	TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, +	STA_PM_NOTIF = 0xFD,  	MU_GROUP_MGMT_NOTIF = 0xFE,  	RX_QUEUES_NOTIFICATION = 0xFF,  }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index d89d0a1fd34e..2e8e3e8e30a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -70,49 +70,6 @@  #include "iwl-prph.h"  #include "iwl-csr.h" -static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count, -				     void *data, size_t datalen) -{ -	const struct iwl_mvm_dump_ptrs *dump_ptrs = data; -	ssize_t bytes_read; -	ssize_t bytes_read_trans; - -	if (offset < dump_ptrs->op_mode_len) { -		bytes_read = min_t(ssize_t, count, -				   dump_ptrs->op_mode_len - offset); -		memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset, -		       bytes_read); -		offset += bytes_read; -		count -= bytes_read; - -		if (count == 0) -			return bytes_read; -	} else { -		bytes_read = 0; -	} - -	if (!dump_ptrs->trans_ptr) -		return bytes_read; - -	offset -= dump_ptrs->op_mode_len; -	bytes_read_trans = min_t(ssize_t, count, -				 dump_ptrs->trans_ptr->len - offset); -	memcpy(buffer + bytes_read, -	       (u8 *)dump_ptrs->trans_ptr->data + offset, -	       bytes_read_trans); - -	return bytes_read + bytes_read_trans; -} - -static void iwl_mvm_free_coredump(void *data) -{ -	const struct iwl_mvm_dump_ptrs *fw_error_dump = data; - -	vfree(fw_error_dump->op_mode_ptr); -	vfree(fw_error_dump->trans_ptr); -	kfree(fw_error_dump); -} -  #define RADIO_REG_MAX_READ 0x2ad  static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm,  				   struct iwl_fw_error_dump_data **dump_data) @@ -491,6 +448,43 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,  	return prph_len;  } +/* + * alloc_sgtable - allocates scallerlist table in the given size, + * fills it with pages and returns it + * @size: the size (in bytes) of the table +*/ +static struct scatterlist *alloc_sgtable(int size) +{ +	int alloc_size, nents, i; +	struct page *new_page; +	struct scatterlist *iter; +	struct scatterlist *table; + +	nents = DIV_ROUND_UP(size, PAGE_SIZE); +	table = kcalloc(nents, sizeof(*table), GFP_KERNEL); +	if (!table) +		return NULL; +	sg_init_table(table, nents); +	iter = table; +	for_each_sg(table, iter, sg_nents(table), i) { +		new_page = alloc_page(GFP_KERNEL); +		if (!new_page) { +			/* release all previous allocated pages in the table */ +			iter = table; +			for_each_sg(table, iter, sg_nents(table), i) { +				new_page = sg_page(iter); +				if (new_page) +					__free_page(new_page); +			} +			return NULL; +		} +		alloc_size = min_t(int, size, PAGE_SIZE); +		size -= PAGE_SIZE; +		sg_set_page(iter, new_page, alloc_size, 0); +	} +	return table; +} +  void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  {  	struct iwl_fw_error_dump_file *dump_file; @@ -499,6 +493,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  	struct iwl_fw_error_dump_mem *dump_mem;  	struct iwl_fw_error_dump_trigger_desc *dump_trig;  	struct iwl_mvm_dump_ptrs *fw_error_dump; +	struct scatterlist *sg_dump_data;  	u32 sram_len, sram_ofs;  	struct iwl_fw_dbg_mem_seg_tlv * const *fw_dbg_mem =  		mvm->fw->dbg_mem_tlv; @@ -815,8 +810,23 @@ dump_trans_data:  		file_len += fw_error_dump->trans_ptr->len;  	dump_file->file_len = cpu_to_le32(file_len); -	dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, -		      GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); +	sg_dump_data = alloc_sgtable(file_len); +	if (sg_dump_data) { +		sg_pcopy_from_buffer(sg_dump_data, +				     sg_nents(sg_dump_data), +				     fw_error_dump->op_mode_ptr, +				     fw_error_dump->op_mode_len, 0); +		sg_pcopy_from_buffer(sg_dump_data, +				     sg_nents(sg_dump_data), +				     fw_error_dump->trans_ptr->data, +				     fw_error_dump->trans_ptr->len, +				     fw_error_dump->op_mode_len); +		dev_coredumpsg(mvm->trans->dev, sg_dump_data, file_len, +			       GFP_KERNEL); +	} +	vfree(fw_error_dump->op_mode_ptr); +	vfree(fw_error_dump->trans_ptr); +	kfree(fw_error_dump);  out:  	iwl_mvm_free_fw_dump_desc(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 6b962d6b067a..4a0874e40731 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -499,23 +499,21 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	if (ret)  		return ret; +	/* If DQA is supported - queues will be enabled when needed */ +	if (iwl_mvm_is_dqa_supported(mvm)) +		return 0; +  	switch (vif->type) {  	case NL80211_IFTYPE_P2P_DEVICE: -		if (!iwl_mvm_is_dqa_supported(mvm)) -			iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, -					      IWL_MVM_OFFCHANNEL_QUEUE, -					      IWL_MVM_TX_FIFO_VO, 0, -					      wdg_timeout); +		iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, +				      IWL_MVM_OFFCHANNEL_QUEUE, +				      IWL_MVM_TX_FIFO_VO, 0, wdg_timeout);  		break;  	case NL80211_IFTYPE_AP:  		iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, vif->cab_queue,  				      IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);  		/* fall through */  	default: -		/* If DQA is supported - queues will be enabled when needed */ -		if (iwl_mvm_is_dqa_supported(mvm)) -			break; -  		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)  			iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],  					      vif->hw_queue[ac], @@ -899,9 +897,11 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,  	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); -	for (i = 0; i < IEEE80211_NUM_ACS; i++) -		if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) -			tfd_queue_msk |= BIT(vif->hw_queue[i]); +	if (!iwl_mvm_is_dqa_supported(mvm)) { +		for (i = 0; i < IEEE80211_NUM_ACS; i++) +			if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) +				tfd_queue_msk |= BIT(vif->hw_queue[i]); +	}  	cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |  				       MAC_FILTER_IN_CONTROL_AND_MGMT | diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 318efd814037..45122dafe922 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -445,6 +445,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);  	if (iwl_mvm_has_new_rx_api(mvm))  		ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); +	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF)) +		ieee80211_hw_set(hw, AP_LINK_PS);  	if (mvm->trans->num_rx_queues > 1)  		ieee80211_hw_set(hw, USES_RSS); @@ -2097,6 +2099,22 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,  	if (ret)  		goto out_unbind; +	/* enable the multicast queue, now that we have a station for it */ +	if (iwl_mvm_is_dqa_supported(mvm)) { +		unsigned int wdg_timeout = +			iwl_mvm_get_wd_timeout(mvm, vif, false, false); +		struct iwl_trans_txq_scd_cfg cfg = { +			.fifo = IWL_MVM_TX_FIFO_MCAST, +			.sta_id = mvmvif->bcast_sta.sta_id, +			.tid = IWL_MAX_TID_COUNT, +			.aggregate = false, +			.frame_limit = IWL_FRAME_LIMIT, +		}; + +		iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, +				   &cfg, wdg_timeout); +	} +  	/* must be set before quota calculations */  	mvmvif->ap_ibss_active = true; @@ -2318,10 +2336,9 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,  					  tids, more_data, true);  } -static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, -				   struct ieee80211_vif *vif, -				   enum sta_notify_cmd cmd, -				   struct ieee80211_sta *sta) +static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, +				     enum sta_notify_cmd cmd, +				     struct ieee80211_sta *sta)  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -2374,6 +2391,67 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,  	spin_unlock_bh(&mvmsta->lock);  } +static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, +				   struct ieee80211_vif *vif, +				   enum sta_notify_cmd cmd, +				   struct ieee80211_sta *sta) +{ +	__iwl_mvm_mac_sta_notify(hw, cmd, sta); +} + +void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +{ +	struct iwl_rx_packet *pkt = rxb_addr(rxb); +	struct iwl_mvm_pm_state_notification *notif = (void *)pkt->data; +	struct ieee80211_sta *sta; +	struct iwl_mvm_sta *mvmsta; +	bool sleeping = (notif->type != IWL_MVM_PM_EVENT_AWAKE); + +	if (WARN_ON(notif->sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) +		return; + +	rcu_read_lock(); +	sta = mvm->fw_id_to_mac_id[notif->sta_id]; +	if (WARN_ON(IS_ERR_OR_NULL(sta))) { +		rcu_read_unlock(); +		return; +	} + +	mvmsta = iwl_mvm_sta_from_mac80211(sta); + +	if (!mvmsta->vif || +	    mvmsta->vif->type != NL80211_IFTYPE_AP) { +		rcu_read_unlock(); +		return; +	} + +	if (mvmsta->sleeping != sleeping) { +		mvmsta->sleeping = sleeping; +		__iwl_mvm_mac_sta_notify(mvm->hw, +			sleeping ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, +			sta); +		ieee80211_sta_ps_transition(sta, sleeping); +	} + +	if (sleeping) { +		switch (notif->type) { +		case IWL_MVM_PM_EVENT_AWAKE: +		case IWL_MVM_PM_EVENT_ASLEEP: +			break; +		case IWL_MVM_PM_EVENT_UAPSD: +			ieee80211_sta_uapsd_trigger(sta, IEEE80211_NUM_TIDS); +			break; +		case IWL_MVM_PM_EVENT_PS_POLL: +			ieee80211_sta_pspoll(sta); +			break; +		default: +			break; +		} +	} + +	rcu_read_unlock(); +} +  static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,  				       struct ieee80211_vif *vif,  				       struct ieee80211_sta *sta) @@ -4121,7 +4199,6 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,  				     struct iwl_mvm_internal_rxq_notif *notif,  				     u32 size)  { -	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq);  	u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;  	int ret; @@ -4143,7 +4220,7 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,  	}  	if (notif->sync) -		ret = wait_event_timeout(notif_waitq, +		ret = wait_event_timeout(mvm->rx_sync_waitq,  					 atomic_read(&mvm->queue_sync_counter) == 0,  					 HZ);  	WARN_ON_ONCE(!ret); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index d17cbf603f7c..4a9cb76b7611 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -937,6 +937,7 @@ struct iwl_mvm {  	/* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */  	spinlock_t d0i3_tx_lock;  	wait_queue_head_t d0i3_exit_waitq; +	wait_queue_head_t rx_sync_waitq;  	/* BT-Coex */  	struct iwl_bt_coex_profile_notif last_bt_notif; @@ -1111,9 +1112,8 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)  static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)  { -	/* Make sure DQA isn't allowed in driver until feature is complete */ -	return false && fw_has_capa(&mvm->fw->ucode_capa, -				    IWL_UCODE_TLV_CAPA_DQA_SUPPORT); +	return fw_has_capa(&mvm->fw->ucode_capa, +			   IWL_UCODE_TLV_CAPA_DQA_SUPPORT);  }  static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) @@ -1418,6 +1418,7 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,  				    struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,  			       struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,  				 struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 05fe6dd1a2c8..f14aada390c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -306,6 +306,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  		       iwl_mvm_rx_stored_beacon_notif, RX_HANDLER_SYNC),  	RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF,  		       iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC), +	RX_HANDLER_GRP(DATA_PATH_GROUP, STA_PM_NOTIF, +		       iwl_mvm_sta_pm_notif, RX_HANDLER_SYNC),  };  #undef RX_HANDLER  #undef RX_HANDLER_GRP @@ -452,6 +454,7 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {  static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {  	HCMD_NAME(UPDATE_MU_GROUPS_CMD),  	HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), +	HCMD_NAME(STA_PM_NOTIF),  	HCMD_NAME(MU_GROUP_MGMT_NOTIF),  	HCMD_NAME(RX_QUEUES_NOTIFICATION),  }; @@ -619,6 +622,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	spin_lock_init(&mvm->refs_lock);  	skb_queue_head_init(&mvm->d0i3_tx);  	init_waitqueue_head(&mvm->d0i3_exit_waitq); +	init_waitqueue_head(&mvm->rx_sync_waitq);  	atomic_set(&mvm->queue_sync_counter, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index a57c6ef5bc14..6c802cee900c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -547,7 +547,8 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  				  "Received expired RX queue sync message\n");  			return;  		} -		atomic_dec(&mvm->queue_sync_counter); +		if (!atomic_dec_return(&mvm->queue_sync_counter)) +			wake_up(&mvm->rx_sync_waitq);  	}  	switch (internal_notif->type) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index f279fdd6eb44..fa9743205491 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1199,6 +1199,9 @@ static int iwl_mvm_num_scans(struct iwl_mvm *mvm)  static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)  { +	bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, +					 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); +  	/* This looks a bit arbitrary, but the idea is that if we run  	 * out of possible simultaneous scans and the userspace is  	 * trying to run a scan type that is already running, we @@ -1225,12 +1228,30 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)  			return -EBUSY;  		return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);  	case IWL_MVM_SCAN_NETDETECT: -		/* No need to stop anything for net-detect since the -		 * firmware is restarted anyway.  This way, any sched -		 * scans that were running will be restarted when we -		 * resume. -		*/ -		return 0; +		/* For non-unified images, there's no need to stop +		 * anything for net-detect since the firmware is +		 * restarted anyway.  This way, any sched scans that +		 * were running will be restarted when we resume. +		 */ +		if (!unified_image) +			return 0; + +		/* If this is a unified image and we ran out of scans, +		 * we need to stop something.  Prefer stopping regular +		 * scans, because the results are useless at this +		 * point, and we should be able to keep running +		 * another scheduled scan while suspended. +		 */ +		if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK) +			return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, +						 true); +		if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK) +			return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, +						 true); + +		/* fall through, something is wrong if no scan was +		 * running but we ran out of scans. +		 */  	default:  		WARN_ON(1);  		break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index fc771885e383..636c8b03e318 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -202,6 +202,20 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT);  	add_sta_cmd.station_flags |=  		cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); +	add_sta_cmd.assoc_id = cpu_to_le16(sta->aid); + +	if (sta->wme) { +		add_sta_cmd.modify_mask |= STA_MODIFY_UAPSD_ACS; + +		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) +			add_sta_cmd.uapsd_trigger_acs |= BIT(AC_BK); +		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) +			add_sta_cmd.uapsd_trigger_acs |= BIT(AC_BE); +		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) +			add_sta_cmd.uapsd_trigger_acs |= BIT(AC_VI); +		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) +			add_sta_cmd.uapsd_trigger_acs |= BIT(AC_VO); +	}  	status = ADD_STA_SUCCESS;  	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, @@ -875,12 +889,17 @@ static void iwl_mvm_change_queue_owner(struct iwl_mvm *mvm, int queue)  	cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];  	ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd); -	if (ret) +	if (ret) {  		IWL_ERR(mvm, "Failed to update owner of TXQ %d (ret=%d)\n",  			queue, ret); -	else -		IWL_DEBUG_TX_QUEUES(mvm, "Changed TXQ %d ownership to tid %d\n", -				    queue, tid); +		return; +	} + +	spin_lock_bh(&mvm->queue_info_lock); +	mvm->queue_info[queue].txq_tid = tid; +	spin_unlock_bh(&mvm->queue_info_lock); +	IWL_DEBUG_TX_QUEUES(mvm, "Changed TXQ %d ownership to tid %d\n", +			    queue, tid);  }  static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) @@ -1010,6 +1029,7 @@ static void iwl_mvm_tx_deferred_stream(struct iwl_mvm *mvm,  	local_bh_disable();  	spin_lock(&mvmsta->lock);  	skb_queue_splice_init(&tid_data->deferred_tx_frames, &deferred_tx); +	mvmsta->deferred_traffic_tid_map &= ~BIT(tid);  	spin_unlock(&mvmsta->lock);  	while ((skb = __skb_dequeue(&deferred_tx))) @@ -1489,12 +1509,15 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,  		ret = iwl_mvm_drain_sta(mvm, mvm_sta, false);  		/* If DQA is supported - the queues can be disabled now */ -		if (iwl_mvm_is_dqa_supported(mvm)) { +		if (iwl_mvm_is_dqa_supported(mvm)) +			iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); + +		/* If there is a TXQ still marked as reserved - free it */ +		if (iwl_mvm_is_dqa_supported(mvm) && +		    mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) {  			u8 reserved_txq = mvm_sta->reserved_queue;  			enum iwl_mvm_queue_status *status; -			iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); -  			/*  			 * If no traffic has gone through the reserved TXQ - it  			 * is still marked as IWL_MVM_QUEUE_RESERVED, and diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index e068d5355865..b45c7b9937c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -436,6 +436,7 @@ struct iwl_mvm_sta {  	bool disable_tx;  	bool tlc_amsdu; +	bool sleeping;  	u8 agg_tids;  	u8 sleep_tx_count;  	u8 avg_energy; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 001be406a3d3..2f8134b2a504 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -541,48 +541,64 @@ static const struct pci_device_id iwl_hw_card_ids[] = {  MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);  #ifdef CONFIG_ACPI -#define SPL_METHOD		"SPLC" -#define SPL_DOMAINTYPE_MODULE	BIT(0) -#define SPL_DOMAINTYPE_WIFI	BIT(1) -#define SPL_DOMAINTYPE_WIGIG	BIT(2) -#define SPL_DOMAINTYPE_RFEM	BIT(3) +#define ACPI_SPLC_METHOD	"SPLC" +#define ACPI_SPLC_DOMAIN_WIFI	(0x07) -static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx) +static u64 splc_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splc)  { -	union acpi_object *limits, *domain_type, *power_limit; - -	if (splx->type != ACPI_TYPE_PACKAGE || -	    splx->package.count != 2 || -	    splx->package.elements[0].type != ACPI_TYPE_INTEGER || -	    splx->package.elements[0].integer.value != 0) { -		IWL_ERR(trans, "Unsupported splx structure\n"); +	union acpi_object *data_pkg, *dflt_pwr_limit; +	int i; + +	/* We need at least two elements, one for the revision and one +	 * for the data itself.  Also check that the revision is +	 * supported (currently only revision 0). +	*/ +	if (splc->type != ACPI_TYPE_PACKAGE || +	    splc->package.count < 2 || +	    splc->package.elements[0].type != ACPI_TYPE_INTEGER || +	    splc->package.elements[0].integer.value != 0) { +		IWL_DEBUG_INFO(trans, +			       "Unsupported structure returned by the SPLC method.  Ignoring.\n");  		return 0;  	} -	limits = &splx->package.elements[1]; -	if (limits->type != ACPI_TYPE_PACKAGE || -	    limits->package.count < 2 || -	    limits->package.elements[0].type != ACPI_TYPE_INTEGER || -	    limits->package.elements[1].type != ACPI_TYPE_INTEGER) { -		IWL_ERR(trans, "Invalid limits element\n"); -		return 0; +	/* loop through all the packages to find the one for WiFi */ +	for (i = 1; i < splc->package.count; i++) { +		union acpi_object *domain; + +		data_pkg = &splc->package.elements[i]; + +		/* Skip anything that is not a package with the right +		 * amount of elements (i.e. at least 2 integers). +		 */ +		if (data_pkg->type != ACPI_TYPE_PACKAGE || +		    data_pkg->package.count < 2 || +		    data_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || +		    data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) +			continue; + +		domain = &data_pkg->package.elements[0]; +		if (domain->integer.value == ACPI_SPLC_DOMAIN_WIFI) +			break; + +		data_pkg = NULL;  	} -	domain_type = &limits->package.elements[0]; -	power_limit = &limits->package.elements[1]; -	if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) { -		IWL_DEBUG_INFO(trans, "WiFi power is not limited\n"); +	if (!data_pkg) { +		IWL_DEBUG_INFO(trans, +			       "No element for the WiFi domain returned by the SPLC method.\n");  		return 0;  	} -	return power_limit->integer.value; +	dflt_pwr_limit = &data_pkg->package.elements[1]; +	return dflt_pwr_limit->integer.value;  }  static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)  {  	acpi_handle pxsx_handle;  	acpi_handle handle; -	struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL}; +	struct acpi_buffer splc = {ACPI_ALLOCATE_BUFFER, NULL};  	acpi_status status;  	pxsx_handle = ACPI_HANDLE(&pdev->dev); @@ -593,23 +609,24 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)  	}  	/* Get the method's handle */ -	status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle); +	status = acpi_get_handle(pxsx_handle, (acpi_string)ACPI_SPLC_METHOD, +				 &handle);  	if (ACPI_FAILURE(status)) { -		IWL_DEBUG_INFO(trans, "SPL method not found\n"); +		IWL_DEBUG_INFO(trans, "SPLC method not found\n");  		return;  	}  	/* Call SPLC with no arguments */ -	status = acpi_evaluate_object(handle, NULL, NULL, &splx); +	status = acpi_evaluate_object(handle, NULL, NULL, &splc);  	if (ACPI_FAILURE(status)) {  		IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status);  		return;  	} -	trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer); +	trans->dflt_pwr_limit = splc_get_pwr_limit(trans, splc.pointer);  	IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n",  		       trans->dflt_pwr_limit); -	kfree(splx.pointer); +	kfree(splc.pointer);  }  #else /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index ae95533e587d..b10e3633df1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1598,6 +1598,29 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans)  	}  } +static const char *queue_name(struct device *dev, +			      struct iwl_trans_pcie *trans_p, int i) +{ +	if (trans_p->shared_vec_mask) { +		int vec = trans_p->shared_vec_mask & +			  IWL_SHARED_IRQ_FIRST_RSS ? 1 : 0; + +		if (i == 0) +			return DRV_NAME ": shared IRQ"; + +		return devm_kasprintf(dev, GFP_KERNEL, +				      DRV_NAME ": queue %d", i + vec); +	} +	if (i == 0) +		return DRV_NAME ": default queue"; + +	if (i == trans_p->alloc_vecs - 1) +		return DRV_NAME ": exception"; + +	return devm_kasprintf(dev, GFP_KERNEL, +			      DRV_NAME  ": queue %d", i); +} +  static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,  				      struct iwl_trans_pcie *trans_pcie)  { @@ -1606,6 +1629,10 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,  	for (i = 0; i < trans_pcie->alloc_vecs; i++) {  		int ret;  		struct msix_entry *msix_entry; +		const char *qname = queue_name(&pdev->dev, trans_pcie, i); + +		if (!qname) +			return -ENOMEM;  		msix_entry = &trans_pcie->msix_entries[i];  		ret = devm_request_threaded_irq(&pdev->dev, @@ -1615,7 +1642,7 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,  						iwl_pcie_irq_msix_handler :  						iwl_pcie_irq_rx_msix_handler,  						IRQF_SHARED, -						DRV_NAME, +						qname,  						msix_entry);  		if (ret) {  			IWL_ERR(trans_pcie->trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index e9a278b60dfd..e44e5adc2b95 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -592,6 +592,7 @@ error:  static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,  			      int slots_num, u32 txq_id)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	int ret;  	txq->need_update = false; @@ -606,6 +607,13 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,  		return ret;  	spin_lock_init(&txq->lock); + +	if (txq_id == trans_pcie->cmd_queue) { +		static struct lock_class_key iwl_pcie_cmd_queue_lock_class; + +		lockdep_set_class(&txq->lock, &iwl_pcie_cmd_queue_lock_class); +	} +  	__skb_queue_head_init(&txq->overflow_q);  	/* @@ -2188,7 +2196,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,  			memcpy(skb_put(csum_skb, tcp_hdrlen(skb)),  			       tcph, tcp_hdrlen(skb)); -			skb_set_transport_header(csum_skb, 0); +			skb_reset_transport_header(csum_skb);  			csum_skb->csum_start =  				(unsigned char *)tcp_hdr(csum_skb) -  						 csum_skb->head; |