brintos

brintos / linux-shallow public Read only

0
0
Text · 16.7 KiB · aa7b2e7 Raw
643 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2015-2017 Qualcomm Atheros, Inc.4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.5 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.6 */7 8#include "mac.h"9 10#include <net/mac80211.h>11#include "hif.h"12#include "core.h"13#include "debug.h"14#include "wmi.h"15#include "wmi-ops.h"16 17static const struct wiphy_wowlan_support ath10k_wowlan_support = {18	.flags = WIPHY_WOWLAN_DISCONNECT |19		 WIPHY_WOWLAN_MAGIC_PKT,20	.pattern_min_len = WOW_MIN_PATTERN_SIZE,21	.pattern_max_len = WOW_MAX_PATTERN_SIZE,22	.max_pkt_offset = WOW_MAX_PKT_OFFSET,23};24 25static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif)26{27	struct ath10k *ar = arvif->ar;28	int i, ret;29 30	for (i = 0; i < WOW_EVENT_MAX; i++) {31		ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);32		if (ret) {33			ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n",34				    wow_wakeup_event(i), arvif->vdev_id, ret);35			return ret;36		}37	}38 39	for (i = 0; i < ar->wow.max_num_patterns; i++) {40		ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);41		if (ret) {42			ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n",43				    i, arvif->vdev_id, ret);44			return ret;45		}46	}47 48	return 0;49}50 51static int ath10k_wow_cleanup(struct ath10k *ar)52{53	struct ath10k_vif *arvif;54	int ret;55 56	lockdep_assert_held(&ar->conf_mutex);57 58	list_for_each_entry(arvif, &ar->arvifs, list) {59		ret = ath10k_wow_vif_cleanup(arvif);60		if (ret) {61			ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n",62				    arvif->vdev_id, ret);63			return ret;64		}65	}66 67	return 0;68}69 70/*71 * Convert a 802.3 format to a 802.11 format.72 *         +------------+-----------+--------+----------------+73 * 802.3:  |dest mac(6B)|src mac(6B)|type(2B)|     body...    |74 *         +------------+-----------+--------+----------------+75 *                |__         |_______    |____________  |________76 *                   |                |                |          |77 *         +--+------------+----+-----------+---------------+-----------+78 * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)|  8B  |type(2B)|  body...  |79 *         +--+------------+----+-----------+---------------+-----------+80 */81static void ath10k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,82					     const struct cfg80211_pkt_pattern *old)83{84	u8 hdr_8023_pattern[ETH_HLEN] = {};85	u8 hdr_8023_bit_mask[ETH_HLEN] = {};86	u8 hdr_80211_pattern[WOW_HDR_LEN] = {};87	u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {};88 89	int total_len = old->pkt_offset + old->pattern_len;90	int hdr_80211_end_offset;91 92	struct ieee80211_hdr_3addr *new_hdr_pattern =93		(struct ieee80211_hdr_3addr *)hdr_80211_pattern;94	struct ieee80211_hdr_3addr *new_hdr_mask =95		(struct ieee80211_hdr_3addr *)hdr_80211_bit_mask;96	struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern;97	struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask;98	int hdr_len = sizeof(*new_hdr_pattern);99 100	struct rfc1042_hdr *new_rfc_pattern =101		(struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len);102	struct rfc1042_hdr *new_rfc_mask =103		(struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len);104	int rfc_len = sizeof(*new_rfc_pattern);105 106	memcpy(hdr_8023_pattern + old->pkt_offset,107	       old->pattern, ETH_HLEN - old->pkt_offset);108	memcpy(hdr_8023_bit_mask + old->pkt_offset,109	       old->mask, ETH_HLEN - old->pkt_offset);110 111	/* Copy destination address */112	memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN);113	memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN);114 115	/* Copy source address */116	memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN);117	memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN);118 119	/* Copy logic link type */120	memcpy(&new_rfc_pattern->snap_type,121	       &old_hdr_pattern->h_proto,122	       sizeof(old_hdr_pattern->h_proto));123	memcpy(&new_rfc_mask->snap_type,124	       &old_hdr_mask->h_proto,125	       sizeof(old_hdr_mask->h_proto));126 127	/* Calculate new pkt_offset */128	if (old->pkt_offset < ETH_ALEN)129		new->pkt_offset = old->pkt_offset +130			offsetof(struct ieee80211_hdr_3addr, addr1);131	else if (old->pkt_offset < offsetof(struct ethhdr, h_proto))132		new->pkt_offset = old->pkt_offset +133			offsetof(struct ieee80211_hdr_3addr, addr3) -134			offsetof(struct ethhdr, h_source);135	else136		new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN;137 138	/* Calculate new hdr end offset */139	if (total_len > ETH_HLEN)140		hdr_80211_end_offset = hdr_len + rfc_len;141	else if (total_len > offsetof(struct ethhdr, h_proto))142		hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN;143	else if (total_len > ETH_ALEN)144		hdr_80211_end_offset = total_len - ETH_ALEN +145			offsetof(struct ieee80211_hdr_3addr, addr3);146	else147		hdr_80211_end_offset = total_len +148			offsetof(struct ieee80211_hdr_3addr, addr1);149 150	new->pattern_len = hdr_80211_end_offset - new->pkt_offset;151 152	memcpy((u8 *)new->pattern,153	       hdr_80211_pattern + new->pkt_offset,154	       new->pattern_len);155	memcpy((u8 *)new->mask,156	       hdr_80211_bit_mask + new->pkt_offset,157	       new->pattern_len);158 159	if (total_len > ETH_HLEN) {160		/* Copy frame body */161		memcpy((u8 *)new->pattern + new->pattern_len,162		       (void *)old->pattern + ETH_HLEN - old->pkt_offset,163		       total_len - ETH_HLEN);164		memcpy((u8 *)new->mask + new->pattern_len,165		       (void *)old->mask + ETH_HLEN - old->pkt_offset,166		       total_len - ETH_HLEN);167 168		new->pattern_len += total_len - ETH_HLEN;169	}170}171 172static int ath10k_wmi_pno_check(struct ath10k *ar, u32 vdev_id,173				struct cfg80211_sched_scan_request *nd_config,174				struct wmi_pno_scan_req *pno)175{176	int i, j, ret = 0;177	u8 ssid_len;178 179	pno->enable = 1;180	pno->vdev_id = vdev_id;181	pno->uc_networks_count = nd_config->n_match_sets;182 183	if (!pno->uc_networks_count ||184	    pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS)185		return -EINVAL;186 187	if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX)188		return -EINVAL;189 190	/* Filling per profile  params */191	for (i = 0; i < pno->uc_networks_count; i++) {192		ssid_len = nd_config->match_sets[i].ssid.ssid_len;193 194		if (ssid_len == 0 || ssid_len > 32)195			return -EINVAL;196 197		pno->a_networks[i].ssid.ssid_len = __cpu_to_le32(ssid_len);198 199		memcpy(pno->a_networks[i].ssid.ssid,200		       nd_config->match_sets[i].ssid.ssid,201		       nd_config->match_sets[i].ssid.ssid_len);202		pno->a_networks[i].authentication = 0;203		pno->a_networks[i].encryption     = 0;204		pno->a_networks[i].bcast_nw_type  = 0;205 206		/*Copying list of valid channel into request */207		pno->a_networks[i].channel_count = nd_config->n_channels;208		pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold;209 210		for (j = 0; j < nd_config->n_channels; j++) {211			pno->a_networks[i].channels[j] =212					nd_config->channels[j]->center_freq;213		}214	}215 216	/* set scan to passive if no SSIDs are specified in the request */217	if (nd_config->n_ssids == 0)218		pno->do_passive_scan = true;219	else220		pno->do_passive_scan = false;221 222	for (i = 0; i < nd_config->n_ssids; i++) {223		j = 0;224		while (j < pno->uc_networks_count) {225			if (__le32_to_cpu(pno->a_networks[j].ssid.ssid_len) ==226				nd_config->ssids[i].ssid_len &&227			(memcmp(pno->a_networks[j].ssid.ssid,228				nd_config->ssids[i].ssid,229				__le32_to_cpu(pno->a_networks[j].ssid.ssid_len)) == 0)) {230				pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN;231				break;232			}233			j++;234		}235	}236 237	if (nd_config->n_scan_plans == 2) {238		pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;239		pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations;240		pno->slow_scan_period =241			nd_config->scan_plans[1].interval * MSEC_PER_SEC;242	} else if (nd_config->n_scan_plans == 1) {243		pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;244		pno->fast_scan_max_cycles = 1;245		pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;246	} else {247		ath10k_warn(ar, "Invalid number of scan plans %d !!",248			    nd_config->n_scan_plans);249	}250 251	if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {252		/* enable mac randomization */253		pno->enable_pno_scan_randomization = 1;254		memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN);255		memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN);256	}257 258	pno->delay_start_time = nd_config->delay;259 260	/* Current FW does not support min-max range for dwell time */261	pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME;262	pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME;263	return ret;264}265 266static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,267				      struct cfg80211_wowlan *wowlan)268{269	int ret, i;270	unsigned long wow_mask = 0;271	struct ath10k *ar = arvif->ar;272	const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;273	int pattern_id = 0;274 275	/* Setup requested WOW features */276	switch (arvif->vdev_type) {277	case WMI_VDEV_TYPE_IBSS:278		__set_bit(WOW_BEACON_EVENT, &wow_mask);279		fallthrough;280	case WMI_VDEV_TYPE_AP:281		__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);282		__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);283		__set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);284		__set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);285		__set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);286		__set_bit(WOW_HTT_EVENT, &wow_mask);287		__set_bit(WOW_RA_MATCH_EVENT, &wow_mask);288		break;289	case WMI_VDEV_TYPE_STA:290		if (wowlan->disconnect) {291			__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);292			__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);293			__set_bit(WOW_BMISS_EVENT, &wow_mask);294			__set_bit(WOW_CSA_IE_EVENT, &wow_mask);295		}296 297		if (wowlan->magic_pkt)298			__set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);299 300		if (wowlan->nd_config) {301			struct wmi_pno_scan_req *pno;302			int ret;303 304			pno = kzalloc(sizeof(*pno), GFP_KERNEL);305			if (!pno)306				return -ENOMEM;307 308			ar->nlo_enabled = true;309 310			ret = ath10k_wmi_pno_check(ar, arvif->vdev_id,311						   wowlan->nd_config, pno);312			if (!ret) {313				ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);314				__set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask);315			}316 317			kfree(pno);318		}319		break;320	default:321		break;322	}323 324	for (i = 0; i < wowlan->n_patterns; i++) {325		u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};326		u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {};327		u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {};328		struct cfg80211_pkt_pattern new_pattern = {};329		struct cfg80211_pkt_pattern old_pattern = patterns[i];330		int j;331 332		new_pattern.pattern = ath_pattern;333		new_pattern.mask = ath_bitmask;334		if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)335			continue;336		/* convert bytemask to bitmask */337		for (j = 0; j < patterns[i].pattern_len; j++)338			if (patterns[i].mask[j / 8] & BIT(j % 8))339				bitmask[j] = 0xff;340		old_pattern.mask = bitmask;341 342		if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {343			if (patterns[i].pkt_offset < ETH_HLEN) {344				ath10k_wow_convert_8023_to_80211(&new_pattern,345								 &old_pattern);346			} else {347				new_pattern = old_pattern;348				new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;349			}350		}351 352		if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE))353			return -EINVAL;354 355		ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id,356						 pattern_id,357						 new_pattern.pattern,358						 new_pattern.mask,359						 new_pattern.pattern_len,360						 new_pattern.pkt_offset);361		if (ret) {362			ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n",363				    pattern_id,364				    arvif->vdev_id, ret);365			return ret;366		}367 368		pattern_id++;369		__set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);370	}371 372	for (i = 0; i < WOW_EVENT_MAX; i++) {373		if (!test_bit(i, &wow_mask))374			continue;375		ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);376		if (ret) {377			ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n",378				    wow_wakeup_event(i), arvif->vdev_id, ret);379			return ret;380		}381	}382 383	return 0;384}385 386static int ath10k_wow_set_wakeups(struct ath10k *ar,387				  struct cfg80211_wowlan *wowlan)388{389	struct ath10k_vif *arvif;390	int ret;391 392	lockdep_assert_held(&ar->conf_mutex);393 394	list_for_each_entry(arvif, &ar->arvifs, list) {395		ret = ath10k_vif_wow_set_wakeups(arvif, wowlan);396		if (ret) {397			ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n",398				    arvif->vdev_id, ret);399			return ret;400		}401	}402 403	return 0;404}405 406static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif)407{408	int ret = 0;409	struct ath10k *ar = arvif->ar;410 411	switch (arvif->vdev_type) {412	case WMI_VDEV_TYPE_STA:413		if (ar->nlo_enabled) {414			struct wmi_pno_scan_req *pno;415 416			pno = kzalloc(sizeof(*pno), GFP_KERNEL);417			if (!pno)418				return -ENOMEM;419 420			pno->enable = 0;421			ar->nlo_enabled = false;422			ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);423			kfree(pno);424		}425		break;426	default:427		break;428	}429	return ret;430}431 432static int ath10k_wow_nlo_cleanup(struct ath10k *ar)433{434	struct ath10k_vif *arvif;435	int ret = 0;436 437	lockdep_assert_held(&ar->conf_mutex);438 439	list_for_each_entry(arvif, &ar->arvifs, list) {440		ret = ath10k_vif_wow_clean_nlo(arvif);441		if (ret) {442			ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n",443				    arvif->vdev_id, ret);444			return ret;445		}446	}447 448	return 0;449}450 451static int ath10k_wow_enable(struct ath10k *ar)452{453	int ret;454 455	lockdep_assert_held(&ar->conf_mutex);456 457	reinit_completion(&ar->target_suspend);458 459	ret = ath10k_wmi_wow_enable(ar);460	if (ret) {461		ath10k_warn(ar, "failed to issue wow enable: %d\n", ret);462		return ret;463	}464 465	ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);466	if (ret == 0) {467		ath10k_warn(ar, "timed out while waiting for suspend completion\n");468		return -ETIMEDOUT;469	}470 471	return 0;472}473 474static int ath10k_wow_wakeup(struct ath10k *ar)475{476	int ret;477 478	lockdep_assert_held(&ar->conf_mutex);479 480	reinit_completion(&ar->wow.wakeup_completed);481 482	ret = ath10k_wmi_wow_host_wakeup_ind(ar);483	if (ret) {484		ath10k_warn(ar, "failed to send wow wakeup indication: %d\n",485			    ret);486		return ret;487	}488 489	ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ);490	if (ret == 0) {491		ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n");492		return -ETIMEDOUT;493	}494 495	return 0;496}497 498int ath10k_wow_op_suspend(struct ieee80211_hw *hw,499			  struct cfg80211_wowlan *wowlan)500{501	struct ath10k *ar = hw->priv;502	int ret;503 504	mutex_lock(&ar->conf_mutex);505 506	if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,507			      ar->running_fw->fw_file.fw_features))) {508		ret = 1;509		goto exit;510	}511 512	ret =  ath10k_wow_cleanup(ar);513	if (ret) {514		ath10k_warn(ar, "failed to clear wow wakeup events: %d\n",515			    ret);516		goto exit;517	}518 519	ret = ath10k_wow_set_wakeups(ar, wowlan);520	if (ret) {521		ath10k_warn(ar, "failed to set wow wakeup events: %d\n",522			    ret);523		goto cleanup;524	}525 526	ath10k_mac_wait_tx_complete(ar);527 528	ret = ath10k_wow_enable(ar);529	if (ret) {530		ath10k_warn(ar, "failed to start wow: %d\n", ret);531		goto cleanup;532	}533 534	ret = ath10k_hif_suspend(ar);535	if (ret) {536		ath10k_warn(ar, "failed to suspend hif: %d\n", ret);537		goto wakeup;538	}539 540	goto exit;541 542wakeup:543	ath10k_wow_wakeup(ar);544 545cleanup:546	ath10k_wow_cleanup(ar);547 548exit:549	mutex_unlock(&ar->conf_mutex);550	return ret ? 1 : 0;551}552 553void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)554{555	struct ath10k *ar = hw->priv;556 557	mutex_lock(&ar->conf_mutex);558	if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,559		     ar->running_fw->fw_file.fw_features)) {560		device_set_wakeup_enable(ar->dev, enabled);561	}562	mutex_unlock(&ar->conf_mutex);563}564 565int ath10k_wow_op_resume(struct ieee80211_hw *hw)566{567	struct ath10k *ar = hw->priv;568	int ret;569 570	mutex_lock(&ar->conf_mutex);571 572	if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,573			      ar->running_fw->fw_file.fw_features))) {574		ret = 1;575		goto exit;576	}577 578	ret = ath10k_hif_resume(ar);579	if (ret) {580		ath10k_warn(ar, "failed to resume hif: %d\n", ret);581		goto exit;582	}583 584	ret = ath10k_wow_wakeup(ar);585	if (ret)586		ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);587 588	ret = ath10k_wow_nlo_cleanup(ar);589	if (ret)590		ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret);591 592exit:593	if (ret) {594		switch (ar->state) {595		case ATH10K_STATE_ON:596			ar->state = ATH10K_STATE_RESTARTING;597			ret = 1;598			break;599		case ATH10K_STATE_OFF:600		case ATH10K_STATE_RESTARTING:601		case ATH10K_STATE_RESTARTED:602		case ATH10K_STATE_UTF:603		case ATH10K_STATE_WEDGED:604			ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n",605				    ar->state);606			ret = -EIO;607			break;608		}609	}610 611	mutex_unlock(&ar->conf_mutex);612	return ret;613}614 615int ath10k_wow_init(struct ath10k *ar)616{617	if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,618		      ar->running_fw->fw_file.fw_features))619		return 0;620 621	if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))622		return -EINVAL;623 624	ar->wow.wowlan_support = ath10k_wowlan_support;625 626	if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {627		ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE;628		ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE;629	}630 631	if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {632		ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;633		ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;634	}635 636	ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;637	ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;638 639	device_set_wakeup_capable(ar->dev, true);640 641	return 0;642}643