diff options
Diffstat (limited to 'drivers/net/wireless/quantenna')
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/bus.h | 25 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 86 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/commands.c | 379 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/commands.h | 7 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/core.c | 91 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/core.h | 7 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/debug.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/event.c | 16 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c | 32 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c | 23 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c | 31 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/qlink.h | 87 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/qlink_util.c | 117 | ||||
| -rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/qlink_util.h | 5 | 
15 files changed, 579 insertions, 334 deletions
| diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 14b569b6d1b5..7cea08f71838 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -13,12 +13,11 @@  #define QTNF_MAX_MAC		3  enum qtnf_fw_state { -	QTNF_FW_STATE_RESET, -	QTNF_FW_STATE_FW_DNLD_DONE, +	QTNF_FW_STATE_DETACHED,  	QTNF_FW_STATE_BOOT_DONE,  	QTNF_FW_STATE_ACTIVE, -	QTNF_FW_STATE_DETACHED, -	QTNF_FW_STATE_EP_DEAD, +	QTNF_FW_STATE_RUNNING, +	QTNF_FW_STATE_DEAD,  };  struct qtnf_bus; @@ -50,6 +49,7 @@ struct qtnf_bus {  	struct napi_struct mux_napi;  	struct net_device mux_dev;  	struct workqueue_struct *workqueue; +	struct workqueue_struct *hprio_workqueue;  	struct work_struct fw_work;  	struct work_struct event_work;  	struct mutex bus_lock; /* lock during command/event processing */ @@ -58,6 +58,23 @@ struct qtnf_bus {  	char bus_priv[0] __aligned(sizeof(void *));  }; +static inline bool qtnf_fw_is_up(struct qtnf_bus *bus) +{ +	enum qtnf_fw_state state = bus->fw_state; + +	return ((state == QTNF_FW_STATE_ACTIVE) || +		(state == QTNF_FW_STATE_RUNNING)); +} + +static inline bool qtnf_fw_is_attached(struct qtnf_bus *bus) +{ +	enum qtnf_fw_state state = bus->fw_state; + +	return ((state == QTNF_FW_STATE_ACTIVE) || +		(state == QTNF_FW_STATE_RUNNING) || +		(state == QTNF_FW_STATE_DEAD)); +} +  static inline void *get_bus_priv(struct qtnf_bus *bus)  {  	if (WARN(!bus, "qtnfmac: invalid bus pointer")) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index dcb0991432f4..d90016125dfc 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -144,6 +144,7 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)  {  	struct net_device *netdev =  wdev->netdev;  	struct qtnf_vif *vif; +	struct sk_buff *skb;  	if (WARN_ON(!netdev))  		return -EFAULT; @@ -157,6 +158,11 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)  	if (netif_carrier_ok(netdev))  		netif_carrier_off(netdev); +	while ((skb = skb_dequeue(&vif->high_pri_tx_queue))) +		dev_kfree_skb_any(skb); + +	cancel_work_sync(&vif->high_pri_tx_work); +  	if (netdev->reg_state == NETREG_REGISTERED)  		unregister_netdevice(netdev); @@ -424,13 +430,13 @@ qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,  	*cookie = short_cookie;  	if (params->offchan) -		flags |= QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN; +		flags |= QLINK_FRAME_TX_FLAG_OFFCHAN;  	if (params->no_cck) -		flags |= QLINK_MGMT_FRAME_TX_FLAG_NO_CCK; +		flags |= QLINK_FRAME_TX_FLAG_NO_CCK;  	if (params->dont_wait_for_ack) -		flags |= QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT; +		flags |= QLINK_FRAME_TX_FLAG_ACK_NOWAIT;  	/* If channel is not specified, pass "freq = 0" to tell device  	 * firmware to use current channel. @@ -445,9 +451,8 @@ qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,  		 le16_to_cpu(mgmt_frame->frame_control), mgmt_frame->da,  		 params->len, short_cookie, flags); -	return qtnf_cmd_send_mgmt_frame(vif, short_cookie, flags, -					freq, -					params->buf, params->len); +	return qtnf_cmd_send_frame(vif, short_cookie, flags, +				   freq, params->buf, params->len);  }  static int @@ -993,53 +998,31 @@ static struct cfg80211_ops qtn_cfg80211_ops = {  #endif  }; -static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in, +static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy,  				       struct regulatory_request *req)  { -	struct qtnf_wmac *mac = wiphy_priv(wiphy_in); -	struct qtnf_bus *bus = mac->bus; -	struct wiphy *wiphy; -	unsigned int mac_idx; +	struct qtnf_wmac *mac = wiphy_priv(wiphy);  	enum nl80211_band band;  	int ret;  	pr_debug("MAC%u: initiator=%d alpha=%c%c\n", mac->macid, req->initiator,  		 req->alpha2[0], req->alpha2[1]); -	ret = qtnf_cmd_reg_notify(bus, req); +	ret = qtnf_cmd_reg_notify(mac, req, qtnf_mac_slave_radar_get(wiphy));  	if (ret) { -		if (ret == -EOPNOTSUPP) { -			pr_warn("reg update not supported\n"); -		} else if (ret == -EALREADY) { -			pr_info("regulatory domain is already set to %c%c", -				req->alpha2[0], req->alpha2[1]); -		} else { -			pr_err("failed to update reg domain to %c%c\n", -			       req->alpha2[0], req->alpha2[1]); -		} - +		pr_err("MAC%u: failed to update region to %c%c: %d\n", +		       mac->macid, req->alpha2[0], req->alpha2[1], ret);  		return;  	} -	for (mac_idx = 0; mac_idx < QTNF_MAX_MAC; ++mac_idx) { -		if (!(bus->hw_info.mac_bitmap & (1 << mac_idx))) +	for (band = 0; band < NUM_NL80211_BANDS; ++band) { +		if (!wiphy->bands[band])  			continue; -		mac = bus->mac[mac_idx]; -		if (!mac) -			continue; - -		wiphy = priv_to_wiphy(mac); - -		for (band = 0; band < NUM_NL80211_BANDS; ++band) { -			if (!wiphy->bands[band]) -				continue; - -			ret = qtnf_cmd_band_info_get(mac, wiphy->bands[band]); -			if (ret) -				pr_err("failed to get chan info for mac %u band %u\n", -				       mac_idx, band); -		} +		ret = qtnf_cmd_band_info_get(mac, wiphy->bands[band]); +		if (ret) +			pr_err("MAC%u: failed to update band %u\n", +			       mac->macid, band);  	}  } @@ -1095,6 +1078,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  	struct wiphy *wiphy = priv_to_wiphy(mac);  	struct qtnf_mac_info *macinfo = &mac->macinfo;  	int ret; +	bool regdomain_is_known;  	if (!wiphy) {  		pr_err("invalid wiphy pointer\n"); @@ -1127,7 +1111,8 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  			WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |  			WIPHY_FLAG_AP_UAPSD |  			WIPHY_FLAG_HAS_CHANNEL_SWITCH | -			WIPHY_FLAG_4ADDR_STATION; +			WIPHY_FLAG_4ADDR_STATION | +			WIPHY_FLAG_NETNS_OK;  	wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;  	if (hw_info->hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD) @@ -1166,11 +1151,19 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  		wiphy->wowlan = macinfo->wowlan;  #endif +	regdomain_is_known = isalpha(mac->rd->alpha2[0]) && +				isalpha(mac->rd->alpha2[1]); +  	if (hw_info->hw_capab & QLINK_HW_CAPAB_REG_UPDATE) { -		wiphy->regulatory_flags |= REGULATORY_STRICT_REG | -			REGULATORY_CUSTOM_REG;  		wiphy->reg_notifier = qtnf_cfg80211_reg_notifier; -		wiphy_apply_custom_regulatory(wiphy, hw_info->rd); + +		if (mac->rd->alpha2[0] == '9' && mac->rd->alpha2[1] == '9') { +			wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | +				REGULATORY_STRICT_REG; +			wiphy_apply_custom_regulatory(wiphy, mac->rd); +		} else if (regdomain_is_known) { +			wiphy->regulatory_flags |= REGULATORY_STRICT_REG; +		}  	} else {  		wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;  	} @@ -1193,10 +1186,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  		goto out;  	if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) -		ret = regulatory_set_wiphy_regd(wiphy, hw_info->rd); -	else if (isalpha(hw_info->rd->alpha2[0]) && -		 isalpha(hw_info->rd->alpha2[1])) -		ret = regulatory_hint(wiphy, hw_info->rd->alpha2); +		ret = regulatory_set_wiphy_regd(wiphy, mac->rd); +	else if (regdomain_is_known) +		ret = regulatory_hint(wiphy, mac->rd->alpha2);  out:  	return ret; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 85a2a58f4c16..459f6b81d2eb 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -11,6 +11,13 @@  #include "bus.h"  #include "commands.h" +#define QTNF_SCAN_TIME_AUTO	0 + +/* Let device itself to select best values for current conditions */ +#define QTNF_SCAN_DWELL_ACTIVE_DEFAULT		QTNF_SCAN_TIME_AUTO +#define QTNF_SCAN_DWELL_PASSIVE_DEFAULT		QTNF_SCAN_TIME_AUTO +#define QTNF_SCAN_SAMPLE_DURATION_DEFAULT	QTNF_SCAN_TIME_AUTO +  static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp,  				       u16 cmd_id, u8 mac_id, u8 vif_id,  				       size_t resp_size) @@ -89,8 +96,7 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,  	pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, cmd_id); -	if (bus->fw_state != QTNF_FW_STATE_ACTIVE && -	    cmd_id != QLINK_CMD_FW_INIT) { +	if (!qtnf_fw_is_up(bus) && cmd_id != QLINK_CMD_FW_INIT) {  		pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n",  			mac_id, vif_id, cmd_id, bus->fw_state);  		dev_kfree_skb(cmd_skb); @@ -177,14 +183,6 @@ static void qtnf_cmd_tlv_ie_set_add(struct sk_buff *cmd_skb, u8 frame_type,  		memcpy(tlv->ie_data, buf, len);  } -static inline size_t qtnf_cmd_acl_data_size(const struct cfg80211_acl_data *acl) -{ -	size_t size = sizeof(struct qlink_acl_data) + -		      acl->n_acl_entries * sizeof(struct qlink_mac_address); - -	return size; -} -  static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,  				      const struct cfg80211_ap_settings *s)  { @@ -203,7 +201,7 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,  	if (s->acl)  		len += sizeof(struct qlink_tlv_hdr) + -		       qtnf_cmd_acl_data_size(s->acl); +		       struct_size(s->acl, mac_addrs, s->acl->n_acl_entries);  	if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {  		pr_err("VIF%u.%u: can not fit AP settings: %u\n", @@ -310,7 +308,8 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,  	}  	if (s->acl) { -		size_t acl_size = qtnf_cmd_acl_data_size(s->acl); +		size_t acl_size = struct_size(s->acl, mac_addrs, +					      s->acl->n_acl_entries);  		struct qlink_tlv_hdr *tlv =  			skb_put(cmd_skb, sizeof(*tlv) + acl_size); @@ -382,11 +381,11 @@ out:  	return ret;  } -int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, -			     u16 freq, const u8 *buf, size_t len) +int qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, +			u16 freq, const u8 *buf, size_t len)  {  	struct sk_buff *cmd_skb; -	struct qlink_cmd_mgmt_frame_tx *cmd; +	struct qlink_cmd_frame_tx *cmd;  	int ret;  	if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { @@ -396,14 +395,14 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,  	}  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, -					    QLINK_CMD_SEND_MGMT_FRAME, +					    QLINK_CMD_SEND_FRAME,  					    sizeof(*cmd));  	if (!cmd_skb)  		return -ENOMEM;  	qtnf_bus_lock(vif->mac->bus); -	cmd = (struct qlink_cmd_mgmt_frame_tx *)cmd_skb->data; +	cmd = (struct qlink_cmd_frame_tx *)cmd_skb->data;  	cmd->cookie = cpu_to_le32(cookie);  	cmd->freq = cpu_to_le16(freq);  	cmd->flags = cpu_to_le16(flags); @@ -786,8 +785,25 @@ int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif,  				   int use4addr,  				   u8 *mac_addr)  { -	return qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr, -					     QLINK_CMD_CHANGE_INTF); +	int ret; + +	ret = qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr, +					    QLINK_CMD_CHANGE_INTF); + +	/* Regulatory settings may be different for different interface types */ +	if (ret == 0 && vif->wdev.iftype != iftype) { +		enum nl80211_band band; +		struct wiphy *wiphy = priv_to_wiphy(vif->mac); + +		for (band = 0; band < NUM_NL80211_BANDS; ++band) { +			if (!wiphy->bands[band]) +				continue; + +			qtnf_cmd_band_info_get(vif->mac, wiphy->bands[band]); +		} +	} + +	return ret;  }  int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) @@ -831,55 +847,6 @@ out:  	return ret;  } -static u32 qtnf_cmd_resp_reg_rule_flags_parse(u32 qflags) -{ -	u32 flags = 0; - -	if (qflags & QLINK_RRF_NO_OFDM) -		flags |= NL80211_RRF_NO_OFDM; - -	if (qflags & QLINK_RRF_NO_CCK) -		flags |= NL80211_RRF_NO_CCK; - -	if (qflags & QLINK_RRF_NO_INDOOR) -		flags |= NL80211_RRF_NO_INDOOR; - -	if (qflags & QLINK_RRF_NO_OUTDOOR) -		flags |= NL80211_RRF_NO_OUTDOOR; - -	if (qflags & QLINK_RRF_DFS) -		flags |= NL80211_RRF_DFS; - -	if (qflags & QLINK_RRF_PTP_ONLY) -		flags |= NL80211_RRF_PTP_ONLY; - -	if (qflags & QLINK_RRF_PTMP_ONLY) -		flags |= NL80211_RRF_PTMP_ONLY; - -	if (qflags & QLINK_RRF_NO_IR) -		flags |= NL80211_RRF_NO_IR; - -	if (qflags & QLINK_RRF_AUTO_BW) -		flags |= NL80211_RRF_AUTO_BW; - -	if (qflags & QLINK_RRF_IR_CONCURRENT) -		flags |= NL80211_RRF_IR_CONCURRENT; - -	if (qflags & QLINK_RRF_NO_HT40MINUS) -		flags |= NL80211_RRF_NO_HT40MINUS; - -	if (qflags & QLINK_RRF_NO_HT40PLUS) -		flags |= NL80211_RRF_NO_HT40PLUS; - -	if (qflags & QLINK_RRF_NO_80MHZ) -		flags |= NL80211_RRF_NO_80MHZ; - -	if (qflags & QLINK_RRF_NO_160MHZ) -		flags |= NL80211_RRF_NO_160MHZ; - -	return flags; -} -  static int  qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  			   const struct qlink_resp_get_hw_info *resp, @@ -887,7 +854,6 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  {  	struct qtnf_hw_info *hwinfo = &bus->hw_info;  	const struct qlink_tlv_hdr *tlv; -	const struct qlink_tlv_reg_rule *tlv_rule;  	const char *bld_name = NULL;  	const char *bld_rev = NULL;  	const char *bld_type = NULL; @@ -898,19 +864,8 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  	const char *calibration_ver = NULL;  	const char *uboot_ver = NULL;  	u32 hw_ver = 0; -	struct ieee80211_reg_rule *rule;  	u16 tlv_type;  	u16 tlv_value_len; -	unsigned int rule_idx = 0; - -	if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) -		return -E2BIG; - -	hwinfo->rd = kzalloc(struct_size(hwinfo->rd, reg_rules, -					 resp->n_reg_rules), GFP_KERNEL); - -	if (!hwinfo->rd) -		return -ENOMEM;  	hwinfo->num_mac = resp->num_mac;  	hwinfo->mac_bitmap = resp->mac_bitmap; @@ -919,30 +874,11 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  	hwinfo->total_tx_chain = resp->total_tx_chain;  	hwinfo->total_rx_chain = resp->total_rx_chain;  	hwinfo->hw_capab = le32_to_cpu(resp->hw_capab); -	hwinfo->rd->n_reg_rules = resp->n_reg_rules; -	hwinfo->rd->alpha2[0] = resp->alpha2[0]; -	hwinfo->rd->alpha2[1] = resp->alpha2[1];  	bld_tmstamp = le32_to_cpu(resp->bld_tmstamp);  	plat_id = le32_to_cpu(resp->plat_id);  	hw_ver = le32_to_cpu(resp->hw_ver); -	switch (resp->dfs_region) { -	case QLINK_DFS_FCC: -		hwinfo->rd->dfs_region = NL80211_DFS_FCC; -		break; -	case QLINK_DFS_ETSI: -		hwinfo->rd->dfs_region = NL80211_DFS_ETSI; -		break; -	case QLINK_DFS_JP: -		hwinfo->rd->dfs_region = NL80211_DFS_JP; -		break; -	case QLINK_DFS_UNSET: -	default: -		hwinfo->rd->dfs_region = NL80211_DFS_UNSET; -		break; -	} -  	tlv = (const struct qlink_tlv_hdr *)resp->info;  	while (info_len >= sizeof(*tlv)) { @@ -956,37 +892,6 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  		}  		switch (tlv_type) { -		case QTN_TLV_ID_REG_RULE: -			if (rule_idx >= resp->n_reg_rules) { -				pr_warn("unexpected number of rules: %u\n", -					resp->n_reg_rules); -				return -EINVAL; -			} - -			if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) { -				pr_warn("malformed TLV 0x%.2X; LEN: %u\n", -					tlv_type, tlv_value_len); -				return -EINVAL; -			} - -			tlv_rule = (const struct qlink_tlv_reg_rule *)tlv; -			rule = &hwinfo->rd->reg_rules[rule_idx++]; - -			rule->freq_range.start_freq_khz = -				le32_to_cpu(tlv_rule->start_freq_khz); -			rule->freq_range.end_freq_khz = -				le32_to_cpu(tlv_rule->end_freq_khz); -			rule->freq_range.max_bandwidth_khz = -				le32_to_cpu(tlv_rule->max_bandwidth_khz); -			rule->power_rule.max_antenna_gain = -				le32_to_cpu(tlv_rule->max_antenna_gain); -			rule->power_rule.max_eirp = -				le32_to_cpu(tlv_rule->max_eirp); -			rule->dfs_cac_ms = -				le32_to_cpu(tlv_rule->dfs_cac_ms); -			rule->flags = qtnf_cmd_resp_reg_rule_flags_parse( -					le32_to_cpu(tlv_rule->flags)); -			break;  		case QTN_TLV_ID_BUILD_NAME:  			bld_name = (const void *)tlv->val;  			break; @@ -1019,17 +924,8 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  		tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);  	} -	if (rule_idx != resp->n_reg_rules) { -		pr_warn("unexpected number of rules: expected %u got %u\n", -			resp->n_reg_rules, rule_idx); -		kfree(hwinfo->rd); -		hwinfo->rd = NULL; -		return -EINVAL; -	} - -	pr_info("fw_version=%d, MACs map %#x, alpha2=\"%c%c\", chains Tx=%u Rx=%u, capab=0x%x\n", +	pr_info("fw_version=%d, MACs map %#x, chains Tx=%u Rx=%u, capab=0x%x\n",  		hwinfo->fw_ver, hwinfo->mac_bitmap, -		hwinfo->rd->alpha2[0], hwinfo->rd->alpha2[1],  		hwinfo->total_tx_chain, hwinfo->total_rx_chain,  		hwinfo->hw_capab); @@ -1042,7 +938,7 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,  		"\nHardware ID:           %s"  \  		"\nCalibration version:   %s"  \  		"\nU-Boot version:        %s"  \ -		"\nHardware version:      0x%08x", +		"\nHardware version:      0x%08x\n",  		bld_name, bld_rev, bld_type, bld_label,  		(unsigned long)bld_tmstamp,  		(unsigned long)plat_id, @@ -1085,9 +981,12 @@ qtnf_parse_wowlan_info(struct qtnf_wmac *mac,  	}  } -static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, -					const u8 *tlv_buf, size_t tlv_buf_size) +static int +qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, +			     const struct qlink_resp_get_mac_info *resp, +			     size_t tlv_buf_size)  { +	const u8 *tlv_buf = resp->var_info;  	struct ieee80211_iface_combination *comb = NULL;  	size_t n_comb = 0;  	struct ieee80211_iface_limit *limits; @@ -1105,6 +1004,38 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,  	u8 ext_capa_len = 0;  	u8 ext_capa_mask_len = 0;  	int i = 0; +	struct ieee80211_reg_rule *rule; +	unsigned int rule_idx = 0; +	const struct qlink_tlv_reg_rule *tlv_rule; + +	if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) +		return -E2BIG; + +	mac->rd = kzalloc(sizeof(*mac->rd) + +			  sizeof(struct ieee80211_reg_rule) * +			  resp->n_reg_rules, GFP_KERNEL); +	if (!mac->rd) +		return -ENOMEM; + +	mac->rd->n_reg_rules = resp->n_reg_rules; +	mac->rd->alpha2[0] = resp->alpha2[0]; +	mac->rd->alpha2[1] = resp->alpha2[1]; + +	switch (resp->dfs_region) { +	case QLINK_DFS_FCC: +		mac->rd->dfs_region = NL80211_DFS_FCC; +		break; +	case QLINK_DFS_ETSI: +		mac->rd->dfs_region = NL80211_DFS_ETSI; +		break; +	case QLINK_DFS_JP: +		mac->rd->dfs_region = NL80211_DFS_JP; +		break; +	case QLINK_DFS_UNSET: +	default: +		mac->rd->dfs_region = NL80211_DFS_UNSET; +		break; +	}  	tlv = (const struct qlink_tlv_hdr *)tlv_buf;  	while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) { @@ -1225,6 +1156,23 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,  			mac->macinfo.wowlan = NULL;  			qtnf_parse_wowlan_info(mac, wowlan);  			break; +		case QTN_TLV_ID_REG_RULE: +			if (rule_idx >= resp->n_reg_rules) { +				pr_warn("unexpected number of rules: %u\n", +					resp->n_reg_rules); +				return -EINVAL; +			} + +			if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) { +				pr_warn("malformed TLV 0x%.2X; LEN: %u\n", +					tlv_type, tlv_value_len); +				return -EINVAL; +			} + +			tlv_rule = (const struct qlink_tlv_reg_rule *)tlv; +			rule = &mac->rd->reg_rules[rule_idx++]; +			qlink_utils_regrule_q2nl(rule, tlv_rule); +			break;  		default:  			pr_warn("MAC%u: unknown TLV type %u\n",  				mac->macid, tlv_type); @@ -1253,6 +1201,12 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,  		return -EINVAL;  	} +	if (rule_idx != resp->n_reg_rules) { +		pr_warn("unexpected number of rules: expected %u got %u\n", +			resp->n_reg_rules, rule_idx); +		return -EINVAL; +	} +  	if (ext_capa_len > 0) {  		ext_capa = kmemdup(ext_capa, ext_capa_len, GFP_KERNEL);  		if (!ext_capa) @@ -1663,7 +1617,7 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)  	resp = (const struct qlink_resp_get_mac_info *)resp_skb->data;  	qtnf_cmd_resp_proc_mac_info(mac, resp); -	ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len); +	ret = qtnf_parse_variable_mac_info(mac, resp, var_data_len);  out:  	qtnf_bus_unlock(mac->bus); @@ -1709,21 +1663,7 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,  	struct qlink_resp_band_info_get *resp;  	size_t info_len = 0;  	int ret = 0; -	u8 qband; - -	switch (band->band) { -	case NL80211_BAND_2GHZ: -		qband = QLINK_BAND_2GHZ; -		break; -	case NL80211_BAND_5GHZ: -		qband = QLINK_BAND_5GHZ; -		break; -	case NL80211_BAND_60GHZ: -		qband = QLINK_BAND_60GHZ; -		break; -	default: -		return -EINVAL; -	} +	u8 qband = qlink_utils_band_cfg2q(band->band);  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,  					    QLINK_CMD_BAND_INFO_GET, @@ -2107,22 +2047,23 @@ out:  static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb,  				     const struct ieee80211_channel *sc)  { -	struct qlink_tlv_channel *qchan; -	u32 flags = 0; - -	qchan = skb_put_zero(cmd_skb, sizeof(*qchan)); -	qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); -	qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - sizeof(qchan->hdr)); -	qchan->chan.center_freq = cpu_to_le16(sc->center_freq); -	qchan->chan.hw_value = cpu_to_le16(sc->hw_value); - -	if (sc->flags & IEEE80211_CHAN_NO_IR) -		flags |= QLINK_CHAN_NO_IR; - -	if (sc->flags & IEEE80211_CHAN_RADAR) -		flags |= QLINK_CHAN_RADAR; - -	qchan->chan.flags = cpu_to_le32(flags); +	struct qlink_tlv_channel *tlv; +	struct qlink_channel *qch; + +	tlv = skb_put_zero(cmd_skb, sizeof(*tlv)); +	qch = &tlv->chan; +	tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); +	tlv->hdr.len = cpu_to_le16(sizeof(*qch)); + +	qch->center_freq = cpu_to_le16(sc->center_freq); +	qch->hw_value = cpu_to_le16(sc->hw_value); +	qch->band = qlink_utils_band_cfg2q(sc->band); +	qch->max_power = sc->max_power; +	qch->max_reg_power = sc->max_reg_power; +	qch->max_antenna_gain = sc->max_antenna_gain; +	qch->beacon_found = sc->beacon_found; +	qch->dfs_state = qlink_utils_dfs_state_cfg2q(sc->dfs_state); +	qch->flags = cpu_to_le32(qlink_utils_chflags_cfg2q(sc->flags));  }  static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb, @@ -2141,6 +2082,35 @@ static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb,  	memcpy(randmac->mac_addr_mask, mac_addr_mask, ETH_ALEN);  } +static void qtnf_cmd_scan_set_dwell(struct qtnf_wmac *mac, +				    struct sk_buff *cmd_skb) +{ +	struct cfg80211_scan_request *scan_req = mac->scan_req; +	u16 dwell_active = QTNF_SCAN_DWELL_ACTIVE_DEFAULT; +	u16 dwell_passive = QTNF_SCAN_DWELL_PASSIVE_DEFAULT; +	u16 duration = QTNF_SCAN_SAMPLE_DURATION_DEFAULT; + +	if (scan_req->duration) { +		dwell_active = scan_req->duration; +		dwell_passive = scan_req->duration; +	} + +	pr_debug("MAC%u: %s scan dwell active=%u, passive=%u, duration=%u\n", +		 mac->macid, +		 scan_req->duration_mandatory ? "mandatory" : "max", +		 dwell_active, dwell_passive, duration); + +	qtnf_cmd_skb_put_tlv_u16(cmd_skb, +				 QTN_TLV_ID_SCAN_DWELL_ACTIVE, +				 dwell_active); +	qtnf_cmd_skb_put_tlv_u16(cmd_skb, +				 QTN_TLV_ID_SCAN_DWELL_PASSIVE, +				 dwell_passive); +	qtnf_cmd_skb_put_tlv_u16(cmd_skb, +				 QTN_TLV_ID_SCAN_SAMPLE_DURATION, +				 duration); +} +  int qtnf_cmd_send_scan(struct qtnf_wmac *mac)  {  	struct sk_buff *cmd_skb; @@ -2192,6 +2162,8 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)  		}  	} +	qtnf_cmd_scan_set_dwell(mac, cmd_skb); +  	if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {  		pr_debug("MAC%u: scan with random addr=%pM, mask=%pM\n",  			 mac->macid, @@ -2207,15 +2179,6 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)  		qtnf_cmd_skb_put_tlv_tag(cmd_skb, QTN_TLV_ID_SCAN_FLUSH);  	} -	if (scan_req->duration) { -		pr_debug("MAC%u: %s scan duration %u\n", mac->macid, -			 scan_req->duration_mandatory ? "mandatory" : "max", -			 scan_req->duration); - -		qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_SCAN_DWELL, -					 scan_req->duration); -	} -  	ret = qtnf_cmd_send(mac->bus, cmd_skb);  	if (ret)  		goto out; @@ -2404,13 +2367,18 @@ out:  	return ret;  } -int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req) +int qtnf_cmd_reg_notify(struct qtnf_wmac *mac, struct regulatory_request *req, +			bool slave_radar)  { +	struct wiphy *wiphy = priv_to_wiphy(mac); +	struct qtnf_bus *bus = mac->bus;  	struct sk_buff *cmd_skb;  	int ret;  	struct qlink_cmd_reg_notify *cmd; +	enum nl80211_band band; +	const struct ieee80211_supported_band *cfg_band; -	cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, +	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,  					    QLINK_CMD_REG_NOTIFY,  					    sizeof(*cmd));  	if (!cmd_skb) @@ -2447,12 +2415,41 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req)  		break;  	} +	switch (req->dfs_region) { +	case NL80211_DFS_FCC: +		cmd->dfs_region = QLINK_DFS_FCC; +		break; +	case NL80211_DFS_ETSI: +		cmd->dfs_region = QLINK_DFS_ETSI; +		break; +	case NL80211_DFS_JP: +		cmd->dfs_region = QLINK_DFS_JP; +		break; +	default: +		cmd->dfs_region = QLINK_DFS_UNSET; +		break; +	} + +	cmd->slave_radar = slave_radar; +	cmd->num_channels = 0; + +	for (band = 0; band < NUM_NL80211_BANDS; band++) { +		unsigned int i; + +		cfg_band = wiphy->bands[band]; +		if (!cfg_band) +			continue; + +		cmd->num_channels += cfg_band->n_channels; + +		for (i = 0; i < cfg_band->n_channels; ++i) { +			qtnf_cmd_channel_tlv_add(cmd_skb, +						 &cfg_band->channels[i]); +		} +	} +  	qtnf_bus_lock(bus);  	ret = qtnf_cmd_send(bus, cmd_skb); -	if (ret) -		goto out; - -out:  	qtnf_bus_unlock(bus);  	return ret; @@ -2592,7 +2589,7 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,  	struct qtnf_bus *bus = vif->mac->bus;  	struct sk_buff *cmd_skb;  	struct qlink_tlv_hdr *tlv; -	size_t acl_size = qtnf_cmd_acl_data_size(params); +	size_t acl_size = struct_size(params, mac_addrs, params->n_acl_entries);  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index 64f0b9dc8a14..88d7a3cd90d2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -27,8 +27,8 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,  			   const struct cfg80211_ap_settings *s);  int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif);  int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg); -int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, -			     u16 freq, const u8 *buf, size_t len); +int qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, +			u16 freq, const u8 *buf, size_t len);  int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,  				 const u8 *buf, size_t len);  int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, @@ -57,7 +57,8 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif,  			     u16 reason_code);  int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif,  			      bool up); -int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req); +int qtnf_cmd_reg_notify(struct qtnf_wmac *mac, struct regulatory_request *req, +			bool slave_radar);  int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,  			    struct qtnf_chan_stats *stats);  int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif, diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index ee1b75fda1dd..8d699cc03d26 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -16,6 +16,12 @@  #define QTNF_DMP_MAX_LEN 48  #define QTNF_PRIMARY_VIF_IDX	0 +static bool slave_radar = true; +module_param(slave_radar, bool, 0644); +MODULE_PARM_DESC(slave_radar, "set 0 to disable radar detection in slave mode"); + +static struct dentry *qtnf_debugfs_dir; +  struct qtnf_frame_meta_info {  	u8 magic_s;  	u8 ifidx; @@ -368,6 +374,23 @@ static void qtnf_mac_scan_timeout(struct work_struct *work)  	qtnf_mac_scan_finish(mac, true);  } +static void qtnf_vif_send_data_high_pri(struct work_struct *work) +{ +	struct qtnf_vif *vif = +		container_of(work, struct qtnf_vif, high_pri_tx_work); +	struct sk_buff *skb; + +	if (!vif->netdev || +	    vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) +		return; + +	while ((skb = skb_dequeue(&vif->high_pri_tx_queue))) { +		qtnf_cmd_send_frame(vif, 0, QLINK_FRAME_TX_FLAG_8023, +				    0, skb->data, skb->len); +		dev_kfree_skb_any(skb); +	} +} +  static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,  					     unsigned int macid)  { @@ -395,7 +418,8 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,  		vif->mac = mac;  		vif->vifid = i;  		qtnf_sta_list_init(&vif->sta_list); - +		INIT_WORK(&vif->high_pri_tx_work, qtnf_vif_send_data_high_pri); +		skb_queue_head_init(&vif->high_pri_tx_queue);  		vif->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);  		if (!vif->stats64)  			pr_warn("VIF%u.%u: per cpu stats allocation failed\n", @@ -408,6 +432,11 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,  	return mac;  } +bool qtnf_mac_slave_radar_get(struct wiphy *wiphy) +{ +	return slave_radar; +} +  static const struct ethtool_ops qtnf_ethtool_ops = {  	.get_drvinfo = cfg80211_get_drvinfo,  }; @@ -499,6 +528,8 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)  	qtnf_mac_iface_comb_free(mac);  	qtnf_mac_ext_caps_free(mac);  	kfree(mac->macinfo.wowlan); +	kfree(mac->rd); +	mac->rd = NULL;  	wiphy_free(wiphy);  	bus->mac[macid] = NULL;  } @@ -587,8 +618,6 @@ int qtnf_core_attach(struct qtnf_bus *bus)  	int ret;  	qtnf_trans_init(bus); - -	bus->fw_state = QTNF_FW_STATE_BOOT_DONE;  	qtnf_bus_data_rx_start(bus);  	bus->workqueue = alloc_ordered_workqueue("QTNF_BUS", 0); @@ -598,6 +627,13 @@ int qtnf_core_attach(struct qtnf_bus *bus)  		goto error;  	} +	bus->hprio_workqueue = alloc_workqueue("QTNF_HPRI", WQ_HIGHPRI, 0); +	if (!bus->hprio_workqueue) { +		pr_err("failed to alloc high prio workqueue\n"); +		ret = -ENOMEM; +		goto error; +	} +  	INIT_WORK(&bus->event_work, qtnf_event_work_handler);  	ret = qtnf_cmd_send_init_fw(bus); @@ -607,7 +643,6 @@ int qtnf_core_attach(struct qtnf_bus *bus)  	}  	bus->fw_state = QTNF_FW_STATE_ACTIVE; -  	ret = qtnf_cmd_get_hw_info(bus);  	if (ret) {  		pr_err("failed to get HW info: %d\n", ret); @@ -637,11 +672,11 @@ int qtnf_core_attach(struct qtnf_bus *bus)  		}  	} +	bus->fw_state = QTNF_FW_STATE_RUNNING;  	return 0;  error:  	qtnf_core_detach(bus); -  	return ret;  }  EXPORT_SYMBOL_GPL(qtnf_core_attach); @@ -655,7 +690,7 @@ void qtnf_core_detach(struct qtnf_bus *bus)  	for (macid = 0; macid < QTNF_MAX_MAC; macid++)  		qtnf_core_mac_detach(bus, macid); -	if (bus->fw_state == QTNF_FW_STATE_ACTIVE) +	if (qtnf_fw_is_up(bus))  		qtnf_cmd_send_deinit_fw(bus);  	bus->fw_state = QTNF_FW_STATE_DETACHED; @@ -663,10 +698,14 @@ void qtnf_core_detach(struct qtnf_bus *bus)  	if (bus->workqueue) {  		flush_workqueue(bus->workqueue);  		destroy_workqueue(bus->workqueue); +		bus->workqueue = NULL;  	} -	kfree(bus->hw_info.rd); -	bus->hw_info.rd = NULL; +	if (bus->hprio_workqueue) { +		flush_workqueue(bus->hprio_workqueue); +		destroy_workqueue(bus->hprio_workqueue); +		bus->hprio_workqueue = NULL; +	}  	qtnf_trans_free(bus);  } @@ -684,6 +723,9 @@ struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb)  	struct qtnf_wmac *mac;  	struct qtnf_vif *vif; +	if (unlikely(bus->fw_state != QTNF_FW_STATE_RUNNING)) +		return NULL; +  	meta = (struct qtnf_frame_meta_info *)  		(skb_tail_pointer(skb) - sizeof(*meta)); @@ -799,6 +841,39 @@ void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb)  }  EXPORT_SYMBOL_GPL(qtnf_update_tx_stats); +void qtnf_packet_send_hi_pri(struct sk_buff *skb) +{ +	struct qtnf_vif *vif = qtnf_netdev_get_priv(skb->dev); + +	skb_queue_tail(&vif->high_pri_tx_queue, skb); +	queue_work(vif->mac->bus->hprio_workqueue, &vif->high_pri_tx_work); +} +EXPORT_SYMBOL_GPL(qtnf_packet_send_hi_pri); + +struct dentry *qtnf_get_debugfs_dir(void) +{ +	return qtnf_debugfs_dir; +} +EXPORT_SYMBOL_GPL(qtnf_get_debugfs_dir); + +static int __init qtnf_core_register(void) +{ +	qtnf_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + +	if (IS_ERR(qtnf_debugfs_dir)) +		qtnf_debugfs_dir = NULL; + +	return 0; +} + +static void __exit qtnf_core_exit(void) +{ +	debugfs_remove(qtnf_debugfs_dir); +} + +module_init(qtnf_core_register); +module_exit(qtnf_core_exit); +  MODULE_AUTHOR("Quantenna Communications");  MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");  MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index a31cff46e964..322858df600c 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -63,6 +63,8 @@ struct qtnf_vif {  	struct qtnf_wmac *mac;  	struct work_struct reset_work; +	struct work_struct high_pri_tx_work; +	struct sk_buff_head high_pri_tx_queue;  	struct qtnf_sta_list sta_list;  	unsigned long cons_tx_timeout_cnt;  	int generation; @@ -112,6 +114,7 @@ struct qtnf_wmac {  	struct cfg80211_scan_request *scan_req;  	struct mutex mac_lock;	/* lock during wmac speicific ops */  	struct delayed_work scan_timeout; +	struct ieee80211_regdomain *rd;  };  struct qtnf_hw_info { @@ -120,7 +123,6 @@ struct qtnf_hw_info {  	u8 mac_bitmap;  	u32 fw_ver;  	u32 hw_capab; -	struct ieee80211_regdomain *rd;  	u8 total_tx_chain;  	u8 total_rx_chain;  	char fw_version[ETHTOOL_FWVERS_LEN]; @@ -132,6 +134,7 @@ struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac);  struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac);  void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac);  void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac); +bool qtnf_mac_slave_radar_get(struct wiphy *wiphy);  struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus);  int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv,  			 const char *name, unsigned char name_assign_type); @@ -149,6 +152,8 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev);  void qtnf_netdev_updown(struct net_device *ndev, bool up);  void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted); +void qtnf_packet_send_hi_pri(struct sk_buff *skb); +struct dentry *qtnf_get_debugfs_dir(void);  static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev)  { diff --git a/drivers/net/wireless/quantenna/qtnfmac/debug.c b/drivers/net/wireless/quantenna/qtnfmac/debug.c index 598ece753a4b..2d3574c1f10e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/debug.c +++ b/drivers/net/wireless/quantenna/qtnfmac/debug.c @@ -5,7 +5,9 @@  void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name)  { -	bus->dbg_dir = debugfs_create_dir(name, NULL); +	struct dentry *parent = qtnf_get_debugfs_dir(); + +	bus->dbg_dir = debugfs_create_dir(name, parent);  }  void qtnf_debugfs_remove(struct qtnf_bus *bus) diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 6c1b886339ac..b57c8c18a8d0 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -493,14 +493,20 @@ qtnf_event_handle_freq_change(struct qtnf_wmac *mac,  	for (i = 0; i < QTNF_MAX_INTF; i++) {  		vif = &mac->iflist[i]; +  		if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)  			continue; -		if (vif->netdev) { -			mutex_lock(&vif->wdev.mtx); -			cfg80211_ch_switch_notify(vif->netdev, &chandef); -			mutex_unlock(&vif->wdev.mtx); -		} +		if (vif->wdev.iftype == NL80211_IFTYPE_STATION && +		    !vif->wdev.current_bss) +			continue; + +		if (!vif->netdev) +			continue; + +		mutex_lock(&vif->wdev.mtx); +		cfg80211_ch_switch_notify(vif->netdev, &chandef); +		mutex_unlock(&vif->wdev.mtx);  	}  	return 0; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c index c3a32effa6f0..e4e9344b6982 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -56,7 +56,7 @@ int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb)  	if (ret == -ETIMEDOUT) {  		pr_err("EP firmware is dead\n"); -		bus->fw_state = QTNF_FW_STATE_EP_DEAD; +		bus->fw_state = QTNF_FW_STATE_DEAD;  	}  	return ret; @@ -128,32 +128,22 @@ static int qtnf_dbg_shm_stats(struct seq_file *s, void *data)  	return 0;  } -void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success) +int qtnf_pcie_fw_boot_done(struct qtnf_bus *bus)  { -	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); -	struct pci_dev *pdev = priv->pdev;  	int ret; -	if (boot_success) { -		bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; - -		ret = qtnf_core_attach(bus); -		if (ret) { -			pr_err("failed to attach core\n"); -			boot_success = false; -		} -	} - -	if (boot_success) { +	bus->fw_state = QTNF_FW_STATE_BOOT_DONE; +	ret = qtnf_core_attach(bus); +	if (ret) { +		pr_err("failed to attach core\n"); +	} else {  		qtnf_debugfs_init(bus, DRV_NAME);  		qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show);  		qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show);  		qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); -	} else { -		bus->fw_state = QTNF_FW_STATE_DETACHED;  	} -	put_device(&pdev->dev); +	return ret;  }  static void qtnf_tune_pcie_mps(struct pci_dev *pdev) @@ -344,7 +334,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	pcie_priv = get_bus_priv(bus);  	pci_set_drvdata(pdev, bus);  	bus->dev = &pdev->dev; -	bus->fw_state = QTNF_FW_STATE_RESET; +	bus->fw_state = QTNF_FW_STATE_DETACHED;  	pcie_priv->pdev = pdev;  	pcie_priv->tx_stopped = 0;  	pcie_priv->rx_bd_num = rx_bd_size_param; @@ -364,6 +354,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	pcie_priv->pcie_irq_count = 0;  	pcie_priv->tx_reclaim_done = 0;  	pcie_priv->tx_reclaim_req = 0; +	pcie_priv->tx_eapol = 0;  	pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE");  	if (!pcie_priv->workqueue) { @@ -419,8 +410,7 @@ static void qtnf_pcie_remove(struct pci_dev *dev)  	cancel_work_sync(&bus->fw_work); -	if (bus->fw_state == QTNF_FW_STATE_ACTIVE || -	    bus->fw_state == QTNF_FW_STATE_EP_DEAD) +	if (qtnf_fw_is_attached(bus))  		qtnf_core_detach(bus);  	netif_napi_del(&bus->mux_napi); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h index bbc074e1f34d..5e8b9cb68419 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h @@ -62,6 +62,7 @@ struct qtnf_pcie_bus_priv {  	u32 tx_done_count;  	u32 tx_reclaim_done;  	u32 tx_reclaim_req; +	u32 tx_eapol;  	u8 msi_enabled;  	u8 tx_stopped; @@ -70,7 +71,7 @@ struct qtnf_pcie_bus_priv {  int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb);  int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv); -void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success); +int qtnf_pcie_fw_boot_done(struct qtnf_bus *bus);  void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv,  			    struct qtnf_shm_ipc_region __iomem *ipc_tx_reg,  			    struct qtnf_shm_ipc_region __iomem *ipc_rx_reg, diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 1f5facbb8905..3aa3714d4dfd 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -980,12 +980,11 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work)  {  	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work);  	struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); +	u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; +	const char *fwname = QTN_PCI_PEARL_FW_NAME;  	struct pci_dev *pdev = ps->base.pdev;  	const struct firmware *fw;  	int ret; -	u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; -	const char *fwname = QTN_PCI_PEARL_FW_NAME; -	bool fw_boot_success = false;  	if (ps->base.flashboot) {  		state |= QTN_RC_FW_FLASHBOOT; @@ -1031,23 +1030,23 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work)  		goto fw_load_exit;  	} -	pr_info("firmware is up and running\n"); -  	if (qtnf_poll_state(&ps->bda->bda_ep_state,  			    QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) {  		pr_err("firmware runtime failure\n");  		goto fw_load_exit;  	} -	fw_boot_success = true; +	pr_info("firmware is up and running\n"); -fw_load_exit: -	qtnf_pcie_fw_boot_done(bus, fw_boot_success); +	ret = qtnf_pcie_fw_boot_done(bus); +	if (ret) +		goto fw_load_exit; -	if (fw_boot_success) { -		qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); -		qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); -	} +	qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); +	qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); + +fw_load_exit: +	put_device(&pdev->dev);  }  static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index cbcda57105f3..9a4380ed7f1b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -498,6 +498,13 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)  	int len;  	int i; +	if (unlikely(skb->protocol == htons(ETH_P_PAE))) { +		qtnf_packet_send_hi_pri(skb); +		qtnf_update_tx_stats(skb->dev, skb); +		priv->tx_eapol++; +		return NETDEV_TX_OK; +	} +  	spin_lock_irqsave(&priv->tx_lock, flags);  	if (!qtnf_tx_queue_ready(ts)) { @@ -761,6 +768,7 @@ static int qtnf_dbg_pkt_stats(struct seq_file *s, void *data)  	seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count);  	seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done);  	seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); +	seq_printf(s, "tx_eapol(%u)\n", priv->tx_eapol);  	seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index);  	seq_printf(s, "tx_done_index(%u)\n", tx_done_index); @@ -1023,8 +1031,9 @@ static void qtnf_topaz_fw_work_handler(struct work_struct *work)  {  	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work);  	struct qtnf_pcie_topaz_state *ts = (void *)get_bus_priv(bus); -	int ret;  	int bootloader_needed = readl(&ts->bda->bda_flags) & QTN_BDA_XMIT_UBOOT; +	struct pci_dev *pdev = ts->base.pdev; +	int ret;  	qtnf_set_state(&ts->bda->bda_bootstate, QTN_BDA_FW_TARGET_BOOT); @@ -1073,19 +1082,23 @@ static void qtnf_topaz_fw_work_handler(struct work_struct *work)  		}  	} +	ret = qtnf_post_init_ep(ts); +	if (ret) { +		pr_err("FW runtime failure\n"); +		goto fw_load_exit; +	} +  	pr_info("firmware is up and running\n"); -	ret = qtnf_post_init_ep(ts); +	ret = qtnf_pcie_fw_boot_done(bus);  	if (ret) -		pr_err("FW runtime failure\n"); +		goto fw_load_exit; -fw_load_exit: -	qtnf_pcie_fw_boot_done(bus, ret ? false : true); +	qtnf_debugfs_add_entry(bus, "pkt_stats", qtnf_dbg_pkt_stats); +	qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); -	if (ret == 0) { -		qtnf_debugfs_add_entry(bus, "pkt_stats", qtnf_dbg_pkt_stats); -		qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); -	} +fw_load_exit: +	put_device(&pdev->dev);  }  static void qtnf_reclaim_tasklet_fn(unsigned long data) diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 7798edcf7980..8a3c6344fa8e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -6,7 +6,7 @@  #include <linux/ieee80211.h> -#define QLINK_PROTO_VER		13 +#define QLINK_PROTO_VER		15  #define QLINK_MACID_RSVD		0xFF  #define QLINK_VIFID_RSVD		0xFF @@ -206,6 +206,8 @@ struct qlink_sta_info_state {   * execution status (one of &enum qlink_cmd_result). Reply message   * may also contain data payload specific to the command type.   * + * @QLINK_CMD_SEND_FRAME: send specified frame over the air; firmware will + *	encapsulate 802.3 packet into 802.11 frame automatically.   * @QLINK_CMD_BAND_INFO_GET: for the specified MAC and specified band, get   *	the band's description including number of operational channels and   *	info on each channel, HT/VHT capabilities, supported rates etc. @@ -220,7 +222,7 @@ enum qlink_cmd_type {  	QLINK_CMD_FW_INIT		= 0x0001,  	QLINK_CMD_FW_DEINIT		= 0x0002,  	QLINK_CMD_REGISTER_MGMT		= 0x0003, -	QLINK_CMD_SEND_MGMT_FRAME	= 0x0004, +	QLINK_CMD_SEND_FRAME		= 0x0004,  	QLINK_CMD_MGMT_SET_APPIE	= 0x0005,  	QLINK_CMD_PHY_PARAMS_GET	= 0x0011,  	QLINK_CMD_PHY_PARAMS_SET	= 0x0012, @@ -321,22 +323,26 @@ struct qlink_cmd_mgmt_frame_register {  	u8 do_register;  } __packed; -enum qlink_mgmt_frame_tx_flags { -	QLINK_MGMT_FRAME_TX_FLAG_NONE		= 0, -	QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN	= BIT(0), -	QLINK_MGMT_FRAME_TX_FLAG_NO_CCK		= BIT(1), -	QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT	= BIT(2), +/** + * @QLINK_FRAME_TX_FLAG_8023: frame has a 802.3 header; if not set, frame + *	is a 802.11 encapsulated. + */ +enum qlink_frame_tx_flags { +	QLINK_FRAME_TX_FLAG_OFFCHAN	= BIT(0), +	QLINK_FRAME_TX_FLAG_NO_CCK	= BIT(1), +	QLINK_FRAME_TX_FLAG_ACK_NOWAIT	= BIT(2), +	QLINK_FRAME_TX_FLAG_8023	= BIT(3),  };  /** - * struct qlink_cmd_mgmt_frame_tx - data for QLINK_CMD_SEND_MGMT_FRAME command + * struct qlink_cmd_frame_tx - data for QLINK_CMD_SEND_FRAME command   *   * @cookie: opaque request identifier.   * @freq: Frequency to use for frame transmission. - * @flags: Transmission flags, one of &enum qlink_mgmt_frame_tx_flags. + * @flags: Transmission flags, one of &enum qlink_frame_tx_flags.   * @frame_data: frame to transmit.   */ -struct qlink_cmd_mgmt_frame_tx { +struct qlink_cmd_frame_tx {  	struct qlink_cmd chdr;  	__le32 cookie;  	__le16 freq; @@ -580,12 +586,22 @@ enum qlink_user_reg_hint_type {   * @initiator: which entity sent the request, one of &enum qlink_reg_initiator.   * @user_reg_hint_type: type of hint for QLINK_REGDOM_SET_BY_USER request, one   *	of &enum qlink_user_reg_hint_type. + * @num_channels: number of &struct qlink_tlv_channel in a variable portion of a + *	payload. + * @slave_radar: whether slave device should enable radar detection. + * @dfs_region: one of &enum qlink_dfs_regions. + * @info: variable portion of regulatory notifier callback.   */  struct qlink_cmd_reg_notify {  	struct qlink_cmd chdr;  	u8 alpha2[2];  	u8 initiator;  	u8 user_reg_hint_type; +	u8 num_channels; +	u8 dfs_region; +	u8 slave_radar; +	u8 rsvd[1]; +	u8 info[0];  } __packed;  /** @@ -765,6 +781,18 @@ struct qlink_resp {  } __packed;  /** + * enum qlink_dfs_regions - regulatory DFS regions + * + * Corresponds to &enum nl80211_dfs_regions. + */ +enum qlink_dfs_regions { +	QLINK_DFS_UNSET	= 0, +	QLINK_DFS_FCC	= 1, +	QLINK_DFS_ETSI	= 2, +	QLINK_DFS_JP	= 3, +}; + +/**   * struct qlink_resp_get_mac_info - response for QLINK_CMD_MAC_INFO command   *   * Data describing specific physical device providing wireless MAC @@ -779,6 +807,10 @@ struct qlink_resp {   * @bands_cap: wireless bands WMAC can operate in, bitmap of &enum qlink_band.   * @max_ap_assoc_sta: Maximum number of associations supported by WMAC.   * @radar_detect_widths: bitmask of channels BW for which WMAC can detect radar. + * @alpha2: country code ID firmware is configured to. + * @n_reg_rules: number of regulatory rules TLVs in variable portion of the + *	message. + * @dfs_region: regulatory DFS region, one of &enum qlink_dfs_regions.   * @var_info: variable-length WMAC info data.   */  struct qlink_resp_get_mac_info { @@ -792,23 +824,14 @@ struct qlink_resp_get_mac_info {  	__le16 radar_detect_widths;  	__le32 max_acl_mac_addrs;  	u8 bands_cap; +	u8 alpha2[2]; +	u8 n_reg_rules; +	u8 dfs_region;  	u8 rsvd[1];  	u8 var_info[0];  } __packed;  /** - * enum qlink_dfs_regions - regulatory DFS regions - * - * Corresponds to &enum nl80211_dfs_regions. - */ -enum qlink_dfs_regions { -	QLINK_DFS_UNSET	= 0, -	QLINK_DFS_FCC	= 1, -	QLINK_DFS_ETSI	= 2, -	QLINK_DFS_JP	= 3, -}; - -/**   * struct qlink_resp_get_hw_info - response for QLINK_CMD_GET_HW_INFO command   *   * Description of wireless hardware capabilities and features. @@ -820,11 +843,7 @@ enum qlink_dfs_regions {   * @mac_bitmap: Bitmap of MAC IDs that are active and can be used in firmware.   * @total_tx_chains: total number of transmit chains used by device.   * @total_rx_chains: total number of receive chains. - * @alpha2: country code ID firmware is configured to. - * @n_reg_rules: number of regulatory rules TLVs in variable portion of the - *	message. - * @dfs_region: regulatory DFS region, one of @enum qlink_dfs_region. - * @info: variable-length HW info, can contain QTN_TLV_ID_REG_RULE. + * @info: variable-length HW info.   */  struct qlink_resp_get_hw_info {  	struct qlink_resp rhdr; @@ -838,9 +857,6 @@ struct qlink_resp_get_hw_info {  	u8 mac_bitmap;  	u8 total_tx_chain;  	u8 total_rx_chain; -	u8 alpha2[2]; -	u8 n_reg_rules; -	u8 dfs_region;  	u8 info[0];  } __packed; @@ -1148,6 +1164,13 @@ struct qlink_event_external_auth {   *	carried by QTN_TLV_ID_STA_STATS_MAP.   * @QTN_TLV_ID_MAX_SCAN_SSIDS: maximum number of SSIDs the device can scan   *	for in any given scan. + * @QTN_TLV_ID_SCAN_DWELL_ACTIVE: time spent on a single channel for an active + *	scan. + * @QTN_TLV_ID_SCAN_DWELL_PASSIVE: time spent on a single channel for a passive + *	scan. + * @QTN_TLV_ID_SCAN_SAMPLE_DURATION: total duration of sampling a single channel + *	during a scan including off-channel dwell time and operating channel + *	time.   */  enum qlink_tlv_id {  	QTN_TLV_ID_FRAG_THRESH		= 0x0201, @@ -1180,7 +1203,9 @@ enum qlink_tlv_id {  	QTN_TLV_ID_WOWLAN_CAPAB		= 0x0410,  	QTN_TLV_ID_WOWLAN_PATTERN	= 0x0411,  	QTN_TLV_ID_SCAN_FLUSH		= 0x0412, -	QTN_TLV_ID_SCAN_DWELL		= 0x0413, +	QTN_TLV_ID_SCAN_DWELL_ACTIVE	= 0x0413, +	QTN_TLV_ID_SCAN_DWELL_PASSIVE	= 0x0416, +	QTN_TLV_ID_SCAN_SAMPLE_DURATION	= 0x0417,  };  struct qlink_tlv_hdr { diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c index 72bfd17cb687..1a972bce7b8b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c @@ -182,3 +182,120 @@ void qlink_acl_data_cfg2q(const struct cfg80211_acl_data *acl,  	memcpy(qacl->mac_addrs, acl->mac_addrs,  	       acl->n_acl_entries * sizeof(*qacl->mac_addrs));  } + +enum qlink_band qlink_utils_band_cfg2q(enum nl80211_band band) +{ +	switch (band) { +	case NL80211_BAND_2GHZ: +		return QLINK_BAND_2GHZ; +	case NL80211_BAND_5GHZ: +		return QLINK_BAND_5GHZ; +	case NL80211_BAND_60GHZ: +		return QLINK_BAND_60GHZ; +	default: +		return -EINVAL; +	} +} + +enum qlink_dfs_state qlink_utils_dfs_state_cfg2q(enum nl80211_dfs_state state) +{ +	switch (state) { +	case NL80211_DFS_USABLE: +		return QLINK_DFS_USABLE; +	case NL80211_DFS_AVAILABLE: +		return QLINK_DFS_AVAILABLE; +	case NL80211_DFS_UNAVAILABLE: +	default: +		return QLINK_DFS_UNAVAILABLE; +	} +} + +u32 qlink_utils_chflags_cfg2q(u32 cfgflags) +{ +	u32 flags = 0; + +	if (cfgflags & IEEE80211_CHAN_DISABLED) +		flags |= QLINK_CHAN_DISABLED; + +	if (cfgflags & IEEE80211_CHAN_NO_IR) +		flags |= QLINK_CHAN_NO_IR; + +	if (cfgflags & IEEE80211_CHAN_RADAR) +		flags |= QLINK_CHAN_RADAR; + +	if (cfgflags & IEEE80211_CHAN_NO_HT40PLUS) +		flags |= QLINK_CHAN_NO_HT40PLUS; + +	if (cfgflags & IEEE80211_CHAN_NO_HT40MINUS) +		flags |= QLINK_CHAN_NO_HT40MINUS; + +	if (cfgflags & IEEE80211_CHAN_NO_80MHZ) +		flags |= QLINK_CHAN_NO_80MHZ; + +	if (cfgflags & IEEE80211_CHAN_NO_160MHZ) +		flags |= QLINK_CHAN_NO_160MHZ; + +	return flags; +} + +static u32 qtnf_reg_rule_flags_parse(u32 qflags) +{ +	u32 flags = 0; + +	if (qflags & QLINK_RRF_NO_OFDM) +		flags |= NL80211_RRF_NO_OFDM; + +	if (qflags & QLINK_RRF_NO_CCK) +		flags |= NL80211_RRF_NO_CCK; + +	if (qflags & QLINK_RRF_NO_INDOOR) +		flags |= NL80211_RRF_NO_INDOOR; + +	if (qflags & QLINK_RRF_NO_OUTDOOR) +		flags |= NL80211_RRF_NO_OUTDOOR; + +	if (qflags & QLINK_RRF_DFS) +		flags |= NL80211_RRF_DFS; + +	if (qflags & QLINK_RRF_PTP_ONLY) +		flags |= NL80211_RRF_PTP_ONLY; + +	if (qflags & QLINK_RRF_PTMP_ONLY) +		flags |= NL80211_RRF_PTMP_ONLY; + +	if (qflags & QLINK_RRF_NO_IR) +		flags |= NL80211_RRF_NO_IR; + +	if (qflags & QLINK_RRF_AUTO_BW) +		flags |= NL80211_RRF_AUTO_BW; + +	if (qflags & QLINK_RRF_IR_CONCURRENT) +		flags |= NL80211_RRF_IR_CONCURRENT; + +	if (qflags & QLINK_RRF_NO_HT40MINUS) +		flags |= NL80211_RRF_NO_HT40MINUS; + +	if (qflags & QLINK_RRF_NO_HT40PLUS) +		flags |= NL80211_RRF_NO_HT40PLUS; + +	if (qflags & QLINK_RRF_NO_80MHZ) +		flags |= NL80211_RRF_NO_80MHZ; + +	if (qflags & QLINK_RRF_NO_160MHZ) +		flags |= NL80211_RRF_NO_160MHZ; + +	return flags; +} + +void qlink_utils_regrule_q2nl(struct ieee80211_reg_rule *rule, +			      const struct qlink_tlv_reg_rule *tlv) +{ +	rule->freq_range.start_freq_khz = le32_to_cpu(tlv->start_freq_khz); +	rule->freq_range.end_freq_khz = le32_to_cpu(tlv->end_freq_khz); +	rule->freq_range.max_bandwidth_khz = +		le32_to_cpu(tlv->max_bandwidth_khz); +	rule->power_rule.max_antenna_gain = le32_to_cpu(tlv->max_antenna_gain); +	rule->power_rule.max_eirp = le32_to_cpu(tlv->max_eirp); +	rule->dfs_cac_ms = le32_to_cpu(tlv->dfs_cac_ms); +	rule->flags = qtnf_reg_rule_flags_parse(le32_to_cpu(tlv->flags)); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index 781ea7fe79f2..f873beed2ae7 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -79,5 +79,10 @@ bool qtnf_utils_is_bit_set(const u8 *arr, unsigned int bit,  			   unsigned int arr_max_len);  void qlink_acl_data_cfg2q(const struct cfg80211_acl_data *acl,  			  struct qlink_acl_data *qacl); +enum qlink_band qlink_utils_band_cfg2q(enum nl80211_band band); +enum qlink_dfs_state qlink_utils_dfs_state_cfg2q(enum nl80211_dfs_state state); +u32 qlink_utils_chflags_cfg2q(u32 cfgflags); +void qlink_utils_regrule_q2nl(struct ieee80211_reg_rule *rule, +			      const struct qlink_tlv_reg_rule *tlv_rule);  #endif /* _QTN_FMAC_QLINK_UTIL_H_ */ |