PageRenderTime 121ms CodeModel.GetById 20ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 1ms

/drivers/net/wireless/ath/ath6kl/wmi.c

http://github.com/mirrors/linux
C | 4173 lines | 3177 code | 764 blank | 232 comment | 489 complexity | 5cecb7efd1534bb7667e9e3a2b41f31d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Copyright (c) 2004-2011 Atheros Communications Inc.
   3 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18#include <linux/ip.h>
  19#include <linux/in.h>
  20#include "core.h"
  21#include "debug.h"
  22#include "testmode.h"
  23#include "trace.h"
  24#include "../regd.h"
  25#include "../regd_common.h"
  26
  27static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx);
  28
  29static const s32 wmi_rate_tbl[][2] = {
  30	/* {W/O SGI, with SGI} */
  31	{1000, 1000},
  32	{2000, 2000},
  33	{5500, 5500},
  34	{11000, 11000},
  35	{6000, 6000},
  36	{9000, 9000},
  37	{12000, 12000},
  38	{18000, 18000},
  39	{24000, 24000},
  40	{36000, 36000},
  41	{48000, 48000},
  42	{54000, 54000},
  43	{6500, 7200},
  44	{13000, 14400},
  45	{19500, 21700},
  46	{26000, 28900},
  47	{39000, 43300},
  48	{52000, 57800},
  49	{58500, 65000},
  50	{65000, 72200},
  51	{13500, 15000},
  52	{27000, 30000},
  53	{40500, 45000},
  54	{54000, 60000},
  55	{81000, 90000},
  56	{108000, 120000},
  57	{121500, 135000},
  58	{135000, 150000},
  59	{0, 0}
  60};
  61
  62static const s32 wmi_rate_tbl_mcs15[][2] = {
  63	/* {W/O SGI, with SGI} */
  64	{1000, 1000},
  65	{2000, 2000},
  66	{5500, 5500},
  67	{11000, 11000},
  68	{6000, 6000},
  69	{9000, 9000},
  70	{12000, 12000},
  71	{18000, 18000},
  72	{24000, 24000},
  73	{36000, 36000},
  74	{48000, 48000},
  75	{54000, 54000},
  76	{6500, 7200},     /* HT 20, MCS 0 */
  77	{13000, 14400},
  78	{19500, 21700},
  79	{26000, 28900},
  80	{39000, 43300},
  81	{52000, 57800},
  82	{58500, 65000},
  83	{65000, 72200},
  84	{13000, 14400},   /* HT 20, MCS 8 */
  85	{26000, 28900},
  86	{39000, 43300},
  87	{52000, 57800},
  88	{78000, 86700},
  89	{104000, 115600},
  90	{117000, 130000},
  91	{130000, 144400}, /* HT 20, MCS 15 */
  92	{13500, 15000},   /*HT 40, MCS 0 */
  93	{27000, 30000},
  94	{40500, 45000},
  95	{54000, 60000},
  96	{81000, 90000},
  97	{108000, 120000},
  98	{121500, 135000},
  99	{135000, 150000},
 100	{27000, 30000},   /*HT 40, MCS 8 */
 101	{54000, 60000},
 102	{81000, 90000},
 103	{108000, 120000},
 104	{162000, 180000},
 105	{216000, 240000},
 106	{243000, 270000},
 107	{270000, 300000}, /*HT 40, MCS 15 */
 108	{0, 0}
 109};
 110
 111/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
 112static const u8 up_to_ac[] = {
 113	WMM_AC_BE,
 114	WMM_AC_BK,
 115	WMM_AC_BK,
 116	WMM_AC_BE,
 117	WMM_AC_VI,
 118	WMM_AC_VI,
 119	WMM_AC_VO,
 120	WMM_AC_VO,
 121};
 122
 123void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)
 124{
 125	if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))
 126		return;
 127
 128	wmi->ep_id = ep_id;
 129}
 130
 131enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
 132{
 133	return wmi->ep_id;
 134}
 135
 136struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
 137{
 138	struct ath6kl_vif *vif, *found = NULL;
 139
 140	if (WARN_ON(if_idx > (ar->vif_max - 1)))
 141		return NULL;
 142
 143	/* FIXME: Locking */
 144	spin_lock_bh(&ar->list_lock);
 145	list_for_each_entry(vif, &ar->vif_list, list) {
 146		if (vif->fw_vif_idx == if_idx) {
 147			found = vif;
 148			break;
 149		}
 150	}
 151	spin_unlock_bh(&ar->list_lock);
 152
 153	return found;
 154}
 155
 156/*  Performs DIX to 802.3 encapsulation for transmit packets.
 157 *  Assumes the entire DIX header is contiguous and that there is
 158 *  enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
 159 */
 160int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
 161{
 162	struct ath6kl_llc_snap_hdr *llc_hdr;
 163	struct ethhdr *eth_hdr;
 164	size_t new_len;
 165	__be16 type;
 166	u8 *datap;
 167	u16 size;
 168
 169	if (WARN_ON(skb == NULL))
 170		return -EINVAL;
 171
 172	size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);
 173	if (skb_headroom(skb) < size)
 174		return -ENOMEM;
 175
 176	eth_hdr = (struct ethhdr *) skb->data;
 177	type = eth_hdr->h_proto;
 178
 179	if (!is_ethertype(be16_to_cpu(type))) {
 180		ath6kl_dbg(ATH6KL_DBG_WMI,
 181			   "%s: pkt is already in 802.3 format\n", __func__);
 182		return 0;
 183	}
 184
 185	new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);
 186
 187	skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));
 188	datap = skb->data;
 189
 190	eth_hdr->h_proto = cpu_to_be16(new_len);
 191
 192	memcpy(datap, eth_hdr, sizeof(*eth_hdr));
 193
 194	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));
 195	llc_hdr->dsap = 0xAA;
 196	llc_hdr->ssap = 0xAA;
 197	llc_hdr->cntl = 0x03;
 198	llc_hdr->org_code[0] = 0x0;
 199	llc_hdr->org_code[1] = 0x0;
 200	llc_hdr->org_code[2] = 0x0;
 201	llc_hdr->eth_type = type;
 202
 203	return 0;
 204}
 205
 206static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
 207			       u8 *version, void *tx_meta_info)
 208{
 209	struct wmi_tx_meta_v1 *v1;
 210	struct wmi_tx_meta_v2 *v2;
 211
 212	if (WARN_ON(skb == NULL || version == NULL))
 213		return -EINVAL;
 214
 215	switch (*version) {
 216	case WMI_META_VERSION_1:
 217		skb_push(skb, WMI_MAX_TX_META_SZ);
 218		v1 = (struct wmi_tx_meta_v1 *) skb->data;
 219		v1->pkt_id = 0;
 220		v1->rate_plcy_id = 0;
 221		*version = WMI_META_VERSION_1;
 222		break;
 223	case WMI_META_VERSION_2:
 224		skb_push(skb, WMI_MAX_TX_META_SZ);
 225		v2 = (struct wmi_tx_meta_v2 *) skb->data;
 226		memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,
 227		       sizeof(struct wmi_tx_meta_v2));
 228		break;
 229	}
 230
 231	return 0;
 232}
 233
 234int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
 235			    u8 msg_type, u32 flags,
 236			    enum wmi_data_hdr_data_type data_type,
 237			    u8 meta_ver, void *tx_meta_info, u8 if_idx)
 238{
 239	struct wmi_data_hdr *data_hdr;
 240	int ret;
 241
 242	if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
 243		return -EINVAL;
 244
 245	if (tx_meta_info) {
 246		ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);
 247		if (ret)
 248			return ret;
 249	}
 250
 251	skb_push(skb, sizeof(struct wmi_data_hdr));
 252
 253	data_hdr = (struct wmi_data_hdr *)skb->data;
 254	memset(data_hdr, 0, sizeof(struct wmi_data_hdr));
 255
 256	data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
 257	data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
 258
 259	if (flags & WMI_DATA_HDR_FLAGS_MORE)
 260		data_hdr->info |= WMI_DATA_HDR_MORE;
 261
 262	if (flags & WMI_DATA_HDR_FLAGS_EOSP)
 263		data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);
 264
 265	data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
 266	data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
 267
 268	return 0;
 269}
 270
 271u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
 272{
 273	struct iphdr *ip_hdr = (struct iphdr *) pkt;
 274	u8 ip_pri;
 275
 276	/*
 277	 * Determine IPTOS priority
 278	 *
 279	 * IP-TOS - 8bits
 280	 *          : DSCP(6-bits) ECN(2-bits)
 281	 *          : DSCP - P2 P1 P0 X X X
 282	 * where (P2 P1 P0) form 802.1D
 283	 */
 284	ip_pri = ip_hdr->tos >> 5;
 285	ip_pri &= 0x7;
 286
 287	if ((layer2_pri & 0x7) > ip_pri)
 288		return (u8) layer2_pri & 0x7;
 289	else
 290		return ip_pri;
 291}
 292
 293u8 ath6kl_wmi_get_traffic_class(u8 user_priority)
 294{
 295	return  up_to_ac[user_priority & 0x7];
 296}
 297
 298int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
 299				       struct sk_buff *skb,
 300				       u32 layer2_priority, bool wmm_enabled,
 301				       u8 *ac)
 302{
 303	struct wmi_data_hdr *data_hdr;
 304	struct ath6kl_llc_snap_hdr *llc_hdr;
 305	struct wmi_create_pstream_cmd cmd;
 306	u32 meta_size, hdr_size;
 307	u16 ip_type = IP_ETHERTYPE;
 308	u8 stream_exist, usr_pri;
 309	u8 traffic_class = WMM_AC_BE;
 310	u8 *datap;
 311
 312	if (WARN_ON(skb == NULL))
 313		return -EINVAL;
 314
 315	datap = skb->data;
 316	data_hdr = (struct wmi_data_hdr *) datap;
 317
 318	meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
 319		     WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;
 320
 321	if (!wmm_enabled) {
 322		/* If WMM is disabled all traffic goes as BE traffic */
 323		usr_pri = 0;
 324	} else {
 325		hdr_size = sizeof(struct ethhdr);
 326
 327		llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +
 328							 sizeof(struct
 329								wmi_data_hdr) +
 330							 meta_size + hdr_size);
 331
 332		if (llc_hdr->eth_type == htons(ip_type)) {
 333			/*
 334			 * Extract the endpoint info from the TOS field
 335			 * in the IP header.
 336			 */
 337			usr_pri =
 338			   ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
 339					sizeof(struct ath6kl_llc_snap_hdr),
 340					layer2_priority);
 341		} else {
 342			usr_pri = layer2_priority & 0x7;
 343		}
 344
 345		/*
 346		 * Queue the EAPOL frames in the same WMM_AC_VO queue
 347		 * as that of management frames.
 348		 */
 349		if (skb->protocol == cpu_to_be16(ETH_P_PAE))
 350			usr_pri = WMI_VOICE_USER_PRIORITY;
 351	}
 352
 353	/*
 354	 * workaround for WMM S5
 355	 *
 356	 * FIXME: wmi->traffic_class is always 100 so this test doesn't
 357	 * make sense
 358	 */
 359	if ((wmi->traffic_class == WMM_AC_VI) &&
 360	    ((usr_pri == 5) || (usr_pri == 4)))
 361		usr_pri = 1;
 362
 363	/* Convert user priority to traffic class */
 364	traffic_class = up_to_ac[usr_pri & 0x7];
 365
 366	wmi_data_hdr_set_up(data_hdr, usr_pri);
 367
 368	spin_lock_bh(&wmi->lock);
 369	stream_exist = wmi->fat_pipe_exist;
 370	spin_unlock_bh(&wmi->lock);
 371
 372	if (!(stream_exist & (1 << traffic_class))) {
 373		memset(&cmd, 0, sizeof(cmd));
 374		cmd.traffic_class = traffic_class;
 375		cmd.user_pri = usr_pri;
 376		cmd.inactivity_int =
 377			cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);
 378		/* Implicit streams are created with TSID 0xFF */
 379		cmd.tsid = WMI_IMPLICIT_PSTREAM;
 380		ath6kl_wmi_create_pstream_cmd(wmi, if_idx, &cmd);
 381	}
 382
 383	*ac = traffic_class;
 384
 385	return 0;
 386}
 387
 388int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
 389{
 390	struct ieee80211_hdr_3addr *pwh, wh;
 391	struct ath6kl_llc_snap_hdr *llc_hdr;
 392	struct ethhdr eth_hdr;
 393	u32 hdr_size;
 394	u8 *datap;
 395	__le16 sub_type;
 396
 397	if (WARN_ON(skb == NULL))
 398		return -EINVAL;
 399
 400	datap = skb->data;
 401	pwh = (struct ieee80211_hdr_3addr *) datap;
 402
 403	sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
 404
 405	memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));
 406
 407	/* Strip off the 802.11 header */
 408	if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
 409		hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
 410				   sizeof(u32));
 411		skb_pull(skb, hdr_size);
 412	} else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) {
 413		skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
 414	}
 415
 416	datap = skb->data;
 417	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
 418
 419	memset(&eth_hdr, 0, sizeof(eth_hdr));
 420	eth_hdr.h_proto = llc_hdr->eth_type;
 421
 422	switch ((le16_to_cpu(wh.frame_control)) &
 423		(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
 424	case IEEE80211_FCTL_TODS:
 425		memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);
 426		memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
 427		break;
 428	case IEEE80211_FCTL_FROMDS:
 429		memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
 430		memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);
 431		break;
 432	case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
 433		break;
 434	default:
 435		memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
 436		memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
 437		break;
 438	}
 439
 440	skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
 441	skb_push(skb, sizeof(eth_hdr));
 442
 443	datap = skb->data;
 444
 445	memcpy(datap, &eth_hdr, sizeof(eth_hdr));
 446
 447	return 0;
 448}
 449
 450/*
 451 * Performs 802.3 to DIX encapsulation for received packets.
 452 * Assumes the entire 802.3 header is contiguous.
 453 */
 454int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
 455{
 456	struct ath6kl_llc_snap_hdr *llc_hdr;
 457	struct ethhdr eth_hdr;
 458	u8 *datap;
 459
 460	if (WARN_ON(skb == NULL))
 461		return -EINVAL;
 462
 463	datap = skb->data;
 464
 465	memcpy(&eth_hdr, datap, sizeof(eth_hdr));
 466
 467	llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));
 468	eth_hdr.h_proto = llc_hdr->eth_type;
 469
 470	skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
 471	datap = skb->data;
 472
 473	memcpy(datap, &eth_hdr, sizeof(eth_hdr));
 474
 475	return 0;
 476}
 477
 478static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
 479{
 480	struct tx_complete_msg_v1 *msg_v1;
 481	struct wmi_tx_complete_event *evt;
 482	int index;
 483	u16 size;
 484
 485	evt = (struct wmi_tx_complete_event *) datap;
 486
 487	ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
 488		   evt->num_msg, evt->msg_len, evt->msg_type);
 489
 490	for (index = 0; index < evt->num_msg; index++) {
 491		size = sizeof(struct wmi_tx_complete_event) +
 492		    (index * sizeof(struct tx_complete_msg_v1));
 493		msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);
 494
 495		ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",
 496			   msg_v1->status, msg_v1->pkt_id,
 497			   msg_v1->rate_idx, msg_v1->ack_failures);
 498	}
 499
 500	return 0;
 501}
 502
 503static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
 504					      int len, struct ath6kl_vif *vif)
 505{
 506	struct wmi_remain_on_chnl_event *ev;
 507	u32 freq;
 508	u32 dur;
 509	struct ieee80211_channel *chan;
 510	struct ath6kl *ar = wmi->parent_dev;
 511	u32 id;
 512
 513	if (len < sizeof(*ev))
 514		return -EINVAL;
 515
 516	ev = (struct wmi_remain_on_chnl_event *) datap;
 517	freq = le32_to_cpu(ev->freq);
 518	dur = le32_to_cpu(ev->duration);
 519	ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",
 520		   freq, dur);
 521	chan = ieee80211_get_channel(ar->wiphy, freq);
 522	if (!chan) {
 523		ath6kl_dbg(ATH6KL_DBG_WMI,
 524			   "remain_on_chnl: Unknown channel (freq=%u)\n",
 525			   freq);
 526		return -EINVAL;
 527	}
 528	id = vif->last_roc_id;
 529	cfg80211_ready_on_channel(&vif->wdev, id, chan,
 530				  dur, GFP_ATOMIC);
 531
 532	return 0;
 533}
 534
 535static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
 536						     u8 *datap, int len,
 537						     struct ath6kl_vif *vif)
 538{
 539	struct wmi_cancel_remain_on_chnl_event *ev;
 540	u32 freq;
 541	u32 dur;
 542	struct ieee80211_channel *chan;
 543	struct ath6kl *ar = wmi->parent_dev;
 544	u32 id;
 545
 546	if (len < sizeof(*ev))
 547		return -EINVAL;
 548
 549	ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
 550	freq = le32_to_cpu(ev->freq);
 551	dur = le32_to_cpu(ev->duration);
 552	ath6kl_dbg(ATH6KL_DBG_WMI,
 553		   "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",
 554		   freq, dur, ev->status);
 555	chan = ieee80211_get_channel(ar->wiphy, freq);
 556	if (!chan) {
 557		ath6kl_dbg(ATH6KL_DBG_WMI,
 558			   "cancel_remain_on_chnl: Unknown channel (freq=%u)\n",
 559			   freq);
 560		return -EINVAL;
 561	}
 562	if (vif->last_cancel_roc_id &&
 563	    vif->last_cancel_roc_id + 1 == vif->last_roc_id)
 564		id = vif->last_cancel_roc_id; /* event for cancel command */
 565	else
 566		id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
 567	vif->last_cancel_roc_id = 0;
 568	cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);
 569
 570	return 0;
 571}
 572
 573static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len,
 574					 struct ath6kl_vif *vif)
 575{
 576	struct wmi_tx_status_event *ev;
 577	u32 id;
 578
 579	if (len < sizeof(*ev))
 580		return -EINVAL;
 581
 582	ev = (struct wmi_tx_status_event *) datap;
 583	id = le32_to_cpu(ev->id);
 584	ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
 585		   id, ev->ack_status);
 586	if (wmi->last_mgmt_tx_frame) {
 587		cfg80211_mgmt_tx_status(&vif->wdev, id,
 588					wmi->last_mgmt_tx_frame,
 589					wmi->last_mgmt_tx_frame_len,
 590					!!ev->ack_status, GFP_ATOMIC);
 591		kfree(wmi->last_mgmt_tx_frame);
 592		wmi->last_mgmt_tx_frame = NULL;
 593		wmi->last_mgmt_tx_frame_len = 0;
 594	}
 595
 596	return 0;
 597}
 598
 599static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
 600					    struct ath6kl_vif *vif)
 601{
 602	struct wmi_p2p_rx_probe_req_event *ev;
 603	u32 freq;
 604	u16 dlen;
 605
 606	if (len < sizeof(*ev))
 607		return -EINVAL;
 608
 609	ev = (struct wmi_p2p_rx_probe_req_event *) datap;
 610	freq = le32_to_cpu(ev->freq);
 611	dlen = le16_to_cpu(ev->len);
 612	if (datap + len < ev->data + dlen) {
 613		ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",
 614			   len, dlen);
 615		return -EINVAL;
 616	}
 617	ath6kl_dbg(ATH6KL_DBG_WMI,
 618		   "rx_probe_req: len=%u freq=%u probe_req_report=%d\n",
 619		   dlen, freq, vif->probe_req_report);
 620
 621	if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
 622		cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
 623
 624	return 0;
 625}
 626
 627static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
 628{
 629	struct wmi_p2p_capabilities_event *ev;
 630	u16 dlen;
 631
 632	if (len < sizeof(*ev))
 633		return -EINVAL;
 634
 635	ev = (struct wmi_p2p_capabilities_event *) datap;
 636	dlen = le16_to_cpu(ev->len);
 637	ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen);
 638
 639	return 0;
 640}
 641
 642static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
 643					 struct ath6kl_vif *vif)
 644{
 645	struct wmi_rx_action_event *ev;
 646	u32 freq;
 647	u16 dlen;
 648
 649	if (len < sizeof(*ev))
 650		return -EINVAL;
 651
 652	ev = (struct wmi_rx_action_event *) datap;
 653	freq = le32_to_cpu(ev->freq);
 654	dlen = le16_to_cpu(ev->len);
 655	if (datap + len < ev->data + dlen) {
 656		ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",
 657			   len, dlen);
 658		return -EINVAL;
 659	}
 660	ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
 661	cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
 662
 663	return 0;
 664}
 665
 666static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len)
 667{
 668	struct wmi_p2p_info_event *ev;
 669	u32 flags;
 670	u16 dlen;
 671
 672	if (len < sizeof(*ev))
 673		return -EINVAL;
 674
 675	ev = (struct wmi_p2p_info_event *) datap;
 676	flags = le32_to_cpu(ev->info_req_flags);
 677	dlen = le16_to_cpu(ev->len);
 678	ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen);
 679
 680	if (flags & P2P_FLAG_CAPABILITIES_REQ) {
 681		struct wmi_p2p_capabilities *cap;
 682		if (dlen < sizeof(*cap))
 683			return -EINVAL;
 684		cap = (struct wmi_p2p_capabilities *) ev->data;
 685		ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n",
 686			   cap->go_power_save);
 687	}
 688
 689	if (flags & P2P_FLAG_MACADDR_REQ) {
 690		struct wmi_p2p_macaddr *mac;
 691		if (dlen < sizeof(*mac))
 692			return -EINVAL;
 693		mac = (struct wmi_p2p_macaddr *) ev->data;
 694		ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n",
 695			   mac->mac_addr);
 696	}
 697
 698	if (flags & P2P_FLAG_HMODEL_REQ) {
 699		struct wmi_p2p_hmodel *mod;
 700		if (dlen < sizeof(*mod))
 701			return -EINVAL;
 702		mod = (struct wmi_p2p_hmodel *) ev->data;
 703		ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n",
 704			   mod->p2p_model,
 705			   mod->p2p_model ? "host" : "firmware");
 706	}
 707	return 0;
 708}
 709
 710static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
 711{
 712	struct sk_buff *skb;
 713
 714	skb = ath6kl_buf_alloc(size);
 715	if (!skb)
 716		return NULL;
 717
 718	skb_put(skb, size);
 719	if (size)
 720		memset(skb->data, 0, size);
 721
 722	return skb;
 723}
 724
 725/* Send a "simple" wmi command -- one with no arguments */
 726static int ath6kl_wmi_simple_cmd(struct wmi *wmi, u8 if_idx,
 727				 enum wmi_cmd_id cmd_id)
 728{
 729	struct sk_buff *skb;
 730	int ret;
 731
 732	skb = ath6kl_wmi_get_new_buf(0);
 733	if (!skb)
 734		return -ENOMEM;
 735
 736	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, cmd_id, NO_SYNC_WMIFLAG);
 737
 738	return ret;
 739}
 740
 741static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
 742{
 743	struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;
 744
 745	if (len < sizeof(struct wmi_ready_event_2))
 746		return -EINVAL;
 747
 748	ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
 749			   le32_to_cpu(ev->sw_version),
 750			   le32_to_cpu(ev->abi_version), ev->phy_cap);
 751
 752	return 0;
 753}
 754
 755/*
 756 * Mechanism to modify the roaming behavior in the firmware. The lower rssi
 757 * at which the station has to roam can be passed with
 758 * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level
 759 * in dBm.
 760 */
 761int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi)
 762{
 763	struct sk_buff *skb;
 764	struct roam_ctrl_cmd *cmd;
 765
 766	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 767	if (!skb)
 768		return -ENOMEM;
 769
 770	cmd = (struct roam_ctrl_cmd *) skb->data;
 771
 772	cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD);
 773	cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi +
 774						       DEF_SCAN_FOR_ROAM_INTVL);
 775	cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi);
 776	cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR;
 777	cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS;
 778
 779	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
 780			    NO_SYNC_WMIFLAG);
 781}
 782
 783int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
 784{
 785	struct sk_buff *skb;
 786	struct roam_ctrl_cmd *cmd;
 787
 788	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 789	if (!skb)
 790		return -ENOMEM;
 791
 792	cmd = (struct roam_ctrl_cmd *) skb->data;
 793
 794	memcpy(cmd->info.bssid, bssid, ETH_ALEN);
 795	cmd->roam_ctrl = WMI_FORCE_ROAM;
 796
 797	ath6kl_dbg(ATH6KL_DBG_WMI, "force roam to %pM\n", bssid);
 798	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
 799				   NO_SYNC_WMIFLAG);
 800}
 801
 802int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
 803				       u32 beacon_intvl)
 804{
 805	struct sk_buff *skb;
 806	struct set_beacon_int_cmd *cmd;
 807
 808	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 809	if (!skb)
 810		return -ENOMEM;
 811
 812	cmd = (struct set_beacon_int_cmd *) skb->data;
 813
 814	cmd->beacon_intvl = cpu_to_le32(beacon_intvl);
 815	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
 816				   WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);
 817}
 818
 819int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
 820{
 821	struct sk_buff *skb;
 822	struct set_dtim_cmd *cmd;
 823
 824	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 825	if (!skb)
 826		return -ENOMEM;
 827
 828	cmd = (struct set_dtim_cmd *) skb->data;
 829
 830	cmd->dtim_period = cpu_to_le32(dtim_period);
 831	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
 832				   WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
 833}
 834
 835int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 836{
 837	struct sk_buff *skb;
 838	struct roam_ctrl_cmd *cmd;
 839
 840	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
 841	if (!skb)
 842		return -ENOMEM;
 843
 844	cmd = (struct roam_ctrl_cmd *) skb->data;
 845
 846	cmd->info.roam_mode = mode;
 847	cmd->roam_ctrl = WMI_SET_ROAM_MODE;
 848
 849	ath6kl_dbg(ATH6KL_DBG_WMI, "set roam mode %d\n", mode);
 850	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
 851				   NO_SYNC_WMIFLAG);
 852}
 853
 854static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
 855				       struct ath6kl_vif *vif)
 856{
 857	struct wmi_connect_event *ev;
 858	u8 *pie, *peie;
 859
 860	if (len < sizeof(struct wmi_connect_event))
 861		return -EINVAL;
 862
 863	ev = (struct wmi_connect_event *) datap;
 864
 865	if (vif->nw_type == AP_NETWORK) {
 866		/* AP mode start/STA connected event */
 867		struct net_device *dev = vif->ndev;
 868		if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
 869			ath6kl_dbg(ATH6KL_DBG_WMI,
 870				   "%s: freq %d bssid %pM (AP started)\n",
 871				   __func__, le16_to_cpu(ev->u.ap_bss.ch),
 872				   ev->u.ap_bss.bssid);
 873			ath6kl_connect_ap_mode_bss(
 874				vif, le16_to_cpu(ev->u.ap_bss.ch));
 875		} else {
 876			ath6kl_dbg(ATH6KL_DBG_WMI,
 877				   "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",
 878				   __func__, ev->u.ap_sta.aid,
 879				   ev->u.ap_sta.mac_addr,
 880				   ev->u.ap_sta.auth,
 881				   ev->u.ap_sta.keymgmt,
 882				   le16_to_cpu(ev->u.ap_sta.cipher),
 883				   ev->u.ap_sta.apsd_info);
 884
 885			ath6kl_connect_ap_mode_sta(
 886				vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
 887				ev->u.ap_sta.keymgmt,
 888				le16_to_cpu(ev->u.ap_sta.cipher),
 889				ev->u.ap_sta.auth, ev->assoc_req_len,
 890				ev->assoc_info + ev->beacon_ie_len,
 891				ev->u.ap_sta.apsd_info);
 892		}
 893		return 0;
 894	}
 895
 896	/* STA/IBSS mode connection event */
 897
 898	ath6kl_dbg(ATH6KL_DBG_WMI,
 899		   "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n",
 900		   le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid,
 901		   le16_to_cpu(ev->u.sta.listen_intvl),
 902		   le16_to_cpu(ev->u.sta.beacon_intvl),
 903		   le32_to_cpu(ev->u.sta.nw_type));
 904
 905	/* Start of assoc rsp IEs */
 906	pie = ev->assoc_info + ev->beacon_ie_len +
 907	      ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */
 908
 909	/* End of assoc rsp IEs */
 910	peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +
 911	    ev->assoc_resp_len;
 912
 913	while (pie < peie) {
 914		switch (*pie) {
 915		case WLAN_EID_VENDOR_SPECIFIC:
 916			if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
 917			    pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
 918				/* WMM OUT (00:50:F2) */
 919				if (pie[1] > 5 &&
 920				    pie[6] == WMM_PARAM_OUI_SUBTYPE)
 921					wmi->is_wmm_enabled = true;
 922			}
 923			break;
 924		}
 925
 926		if (wmi->is_wmm_enabled)
 927			break;
 928
 929		pie += pie[1] + 2;
 930	}
 931
 932	ath6kl_connect_event(vif, le16_to_cpu(ev->u.sta.ch),
 933			     ev->u.sta.bssid,
 934			     le16_to_cpu(ev->u.sta.listen_intvl),
 935			     le16_to_cpu(ev->u.sta.beacon_intvl),
 936			     le32_to_cpu(ev->u.sta.nw_type),
 937			     ev->beacon_ie_len, ev->assoc_req_len,
 938			     ev->assoc_resp_len, ev->assoc_info);
 939
 940	return 0;
 941}
 942
 943static struct country_code_to_enum_rd *
 944ath6kl_regd_find_country(u16 countryCode)
 945{
 946	int i;
 947
 948	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
 949		if (allCountries[i].countryCode == countryCode)
 950			return &allCountries[i];
 951	}
 952
 953	return NULL;
 954}
 955
 956static struct reg_dmn_pair_mapping *
 957ath6kl_get_regpair(u16 regdmn)
 958{
 959	int i;
 960
 961	if (regdmn == NO_ENUMRD)
 962		return NULL;
 963
 964	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
 965		if (regDomainPairs[i].reg_domain == regdmn)
 966			return &regDomainPairs[i];
 967	}
 968
 969	return NULL;
 970}
 971
 972static struct country_code_to_enum_rd *
 973ath6kl_regd_find_country_by_rd(u16 regdmn)
 974{
 975	int i;
 976
 977	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
 978		if (allCountries[i].regDmnEnum == regdmn)
 979			return &allCountries[i];
 980	}
 981
 982	return NULL;
 983}
 984
 985static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
 986{
 987	struct ath6kl_wmi_regdomain *ev;
 988	struct country_code_to_enum_rd *country = NULL;
 989	struct reg_dmn_pair_mapping *regpair = NULL;
 990	char alpha2[2];
 991	u32 reg_code;
 992
 993	ev = (struct ath6kl_wmi_regdomain *) datap;
 994	reg_code = le32_to_cpu(ev->reg_code);
 995
 996	if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) {
 997		country = ath6kl_regd_find_country((u16) reg_code);
 998	} else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {
 999		regpair = ath6kl_get_regpair((u16) reg_code);
1000		country = ath6kl_regd_find_country_by_rd((u16) reg_code);
1001		if (regpair)
1002			ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
1003				   regpair->reg_domain);
1004		else
1005			ath6kl_warn("Regpair not found reg_code 0x%0x\n",
1006				    reg_code);
1007	}
1008
1009	if (country && wmi->parent_dev->wiphy_registered) {
1010		alpha2[0] = country->isoName[0];
1011		alpha2[1] = country->isoName[1];
1012
1013		regulatory_hint(wmi->parent_dev->wiphy, alpha2);
1014
1015		ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
1016			   alpha2[0], alpha2[1]);
1017	}
1018}
1019
1020static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len,
1021					  struct ath6kl_vif *vif)
1022{
1023	struct wmi_disconnect_event *ev;
1024	wmi->traffic_class = 100;
1025
1026	if (len < sizeof(struct wmi_disconnect_event))
1027		return -EINVAL;
1028
1029	ev = (struct wmi_disconnect_event *) datap;
1030
1031	ath6kl_dbg(ATH6KL_DBG_WMI,
1032		   "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n",
1033		   le16_to_cpu(ev->proto_reason_status), ev->bssid,
1034		   ev->disconn_reason, ev->assoc_resp_len);
1035
1036	wmi->is_wmm_enabled = false;
1037
1038	ath6kl_disconnect_event(vif, ev->disconn_reason,
1039				ev->bssid, ev->assoc_resp_len, ev->assoc_info,
1040				le16_to_cpu(ev->proto_reason_status));
1041
1042	return 0;
1043}
1044
1045static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
1046{
1047	struct wmi_peer_node_event *ev;
1048
1049	if (len < sizeof(struct wmi_peer_node_event))
1050		return -EINVAL;
1051
1052	ev = (struct wmi_peer_node_event *) datap;
1053
1054	if (ev->event_code == PEER_NODE_JOIN_EVENT)
1055		ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",
1056			   ev->peer_mac_addr);
1057	else if (ev->event_code == PEER_NODE_LEAVE_EVENT)
1058		ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",
1059			   ev->peer_mac_addr);
1060
1061	return 0;
1062}
1063
1064static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
1065					   struct ath6kl_vif *vif)
1066{
1067	struct wmi_tkip_micerr_event *ev;
1068
1069	if (len < sizeof(struct wmi_tkip_micerr_event))
1070		return -EINVAL;
1071
1072	ev = (struct wmi_tkip_micerr_event *) datap;
1073
1074	ath6kl_tkip_micerr_event(vif, ev->key_id, ev->is_mcast);
1075
1076	return 0;
1077}
1078
1079void ath6kl_wmi_sscan_timer(struct timer_list *t)
1080{
1081	struct ath6kl_vif *vif = from_timer(vif, t, sched_scan_timer);
1082
1083	cfg80211_sched_scan_results(vif->ar->wiphy, 0);
1084}
1085
1086static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
1087				       struct ath6kl_vif *vif)
1088{
1089	struct wmi_bss_info_hdr2 *bih;
1090	u8 *buf;
1091	struct ieee80211_channel *channel;
1092	struct ath6kl *ar = wmi->parent_dev;
1093	struct cfg80211_bss *bss;
1094
1095	if (len <= sizeof(struct wmi_bss_info_hdr2))
1096		return -EINVAL;
1097
1098	bih = (struct wmi_bss_info_hdr2 *) datap;
1099	buf = datap + sizeof(struct wmi_bss_info_hdr2);
1100	len -= sizeof(struct wmi_bss_info_hdr2);
1101
1102	ath6kl_dbg(ATH6KL_DBG_WMI,
1103		   "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "
1104		   "frame_type=%d\n",
1105		   bih->ch, bih->snr, bih->snr - 95, bih->bssid,
1106		   bih->frame_type);
1107
1108	if (bih->frame_type != BEACON_FTYPE &&
1109	    bih->frame_type != PROBERESP_FTYPE)
1110		return 0; /* Only update BSS table for now */
1111
1112	if (bih->frame_type == BEACON_FTYPE &&
1113	    test_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags)) {
1114		clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
1115		ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
1116					 NONE_BSS_FILTER, 0);
1117	}
1118
1119	channel = ieee80211_get_channel(ar->wiphy, le16_to_cpu(bih->ch));
1120	if (channel == NULL)
1121		return -EINVAL;
1122
1123	if (len < 8 + 2 + 2)
1124		return -EINVAL;
1125
1126	if (bih->frame_type == BEACON_FTYPE &&
1127	    test_bit(CONNECTED, &vif->flags) &&
1128	    memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
1129		const u8 *tim;
1130		tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
1131				       len - 8 - 2 - 2);
1132		if (tim && tim[1] >= 2) {
1133			vif->assoc_bss_dtim_period = tim[3];
1134			set_bit(DTIM_PERIOD_AVAIL, &vif->flags);
1135		}
1136	}
1137
1138	bss = cfg80211_inform_bss(ar->wiphy, channel,
1139				  bih->frame_type == BEACON_FTYPE ?
1140					CFG80211_BSS_FTYPE_BEACON :
1141					CFG80211_BSS_FTYPE_PRESP,
1142				  bih->bssid, get_unaligned_le64((__le64 *)buf),
1143				  get_unaligned_le16(((__le16 *)buf) + 5),
1144				  get_unaligned_le16(((__le16 *)buf) + 4),
1145				  buf + 8 + 2 + 2, len - 8 - 2 - 2,
1146				  (bih->snr - 95) * 100, GFP_ATOMIC);
1147	if (bss == NULL)
1148		return -ENOMEM;
1149	cfg80211_put_bss(ar->wiphy, bss);
1150
1151	/*
1152	 * Firmware doesn't return any event when scheduled scan has
1153	 * finished, so we need to use a timer to find out when there are
1154	 * no more results.
1155	 *
1156	 * The timer is started from the first bss info received, otherwise
1157	 * the timer would not ever fire if the scan interval is short
1158	 * enough.
1159	 */
1160	if (test_bit(SCHED_SCANNING, &vif->flags) &&
1161	    !timer_pending(&vif->sched_scan_timer)) {
1162		mod_timer(&vif->sched_scan_timer, jiffies +
1163			  msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
1164	}
1165
1166	return 0;
1167}
1168
1169/* Inactivity timeout of a fatpipe(pstream) at the target */
1170static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
1171					       int len)
1172{
1173	struct wmi_pstream_timeout_event *ev;
1174
1175	if (len < sizeof(struct wmi_pstream_timeout_event))
1176		return -EINVAL;
1177
1178	ev = (struct wmi_pstream_timeout_event *) datap;
1179	if (ev->traffic_class >= WMM_NUM_AC) {
1180		ath6kl_err("invalid traffic class: %d\n", ev->traffic_class);
1181		return -EINVAL;
1182	}
1183
1184	/*
1185	 * When the pstream (fat pipe == AC) timesout, it means there were
1186	 * no thinStreams within this pstream & it got implicitly created
1187	 * due to data flow on this AC. We start the inactivity timer only
1188	 * for implicitly created pstream. Just reset the host state.
1189	 */
1190	spin_lock_bh(&wmi->lock);
1191	wmi->stream_exist_for_ac[ev->traffic_class] = 0;
1192	wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);
1193	spin_unlock_bh(&wmi->lock);
1194
1195	/* Indicate inactivity to driver layer for this fatpipe (pstream) */
1196	ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);
1197
1198	return 0;
1199}
1200
1201static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
1202{
1203	struct wmi_bit_rate_reply *reply;
1204	s32 rate;
1205	u32 sgi, index;
1206
1207	if (len < sizeof(struct wmi_bit_rate_reply))
1208		return -EINVAL;
1209
1210	reply = (struct wmi_bit_rate_reply *) datap;
1211
1212	ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);
1213
1214	if (reply->rate_index == (s8) RATE_AUTO) {
1215		rate = RATE_AUTO;
1216	} else {
1217		index = reply->rate_index & 0x7f;
1218		if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))
1219			return -EINVAL;
1220
1221		sgi = (reply->rate_index & 0x80) ? 1 : 0;
1222		rate = wmi_rate_tbl[index][sgi];
1223	}
1224
1225	ath6kl_wakeup_event(wmi->parent_dev);
1226
1227	return 0;
1228}
1229
1230static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len)
1231{
1232	ath6kl_tm_rx_event(wmi->parent_dev, datap, len);
1233
1234	return 0;
1235}
1236
1237static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)
1238{
1239	if (len < sizeof(struct wmi_fix_rates_reply))
1240		return -EINVAL;
1241
1242	ath6kl_wakeup_event(wmi->parent_dev);
1243
1244	return 0;
1245}
1246
1247static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)
1248{
1249	if (len < sizeof(struct wmi_channel_list_reply))
1250		return -EINVAL;
1251
1252	ath6kl_wakeup_event(wmi->parent_dev);
1253
1254	return 0;
1255}
1256
1257static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)
1258{
1259	struct wmi_tx_pwr_reply *reply;
1260
1261	if (len < sizeof(struct wmi_tx_pwr_reply))
1262		return -EINVAL;
1263
1264	reply = (struct wmi_tx_pwr_reply *) datap;
1265	ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);
1266
1267	return 0;
1268}
1269
1270static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
1271{
1272	if (len < sizeof(struct wmi_get_keepalive_cmd))
1273		return -EINVAL;
1274
1275	ath6kl_wakeup_event(wmi->parent_dev);
1276
1277	return 0;
1278}
1279
1280static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len,
1281				       struct ath6kl_vif *vif)
1282{
1283	struct wmi_scan_complete_event *ev;
1284
1285	ev = (struct wmi_scan_complete_event *) datap;
1286
1287	ath6kl_scan_complete_evt(vif, a_sle32_to_cpu(ev->status));
1288	wmi->is_probe_ssid = false;
1289
1290	return 0;
1291}
1292
1293static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
1294					       int len, struct ath6kl_vif *vif)
1295{
1296	struct wmi_neighbor_report_event *ev;
1297	u8 i;
1298
1299	if (len < sizeof(*ev))
1300		return -EINVAL;
1301	ev = (struct wmi_neighbor_report_event *) datap;
1302	if (struct_size(ev, neighbor, ev->num_neighbors) > len) {
1303		ath6kl_dbg(ATH6KL_DBG_WMI,
1304			   "truncated neighbor event (num=%d len=%d)\n",
1305			   ev->num_neighbors, len);
1306		return -EINVAL;
1307	}
1308	for (i = 0; i < ev->num_neighbors; i++) {
1309		ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n",
1310			   i + 1, ev->num_neighbors, ev->neighbor[i].bssid,
1311			   ev->neighbor[i].bss_flags);
1312		cfg80211_pmksa_candidate_notify(vif->ndev, i,
1313						ev->neighbor[i].bssid,
1314						!!(ev->neighbor[i].bss_flags &
1315						   WMI_PREAUTH_CAPABLE_BSS),
1316						GFP_ATOMIC);
1317	}
1318
1319	return 0;
1320}
1321
1322/*
1323 * Target is reporting a programming error.  This is for
1324 * developer aid only.  Target only checks a few common violations
1325 * and it is responsibility of host to do all error checking.
1326 * Behavior of target after wmi error event is undefined.
1327 * A reset is recommended.
1328 */
1329static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
1330{
1331	const char *type = "unknown error";
1332	struct wmi_cmd_error_event *ev;
1333	ev = (struct wmi_cmd_error_event *) datap;
1334
1335	switch (ev->err_code) {
1336	case INVALID_PARAM:
1337		type = "invalid parameter";
1338		break;
1339	case ILLEGAL_STATE:
1340		type = "invalid state";
1341		break;
1342	case INTERNAL_ERROR:
1343		type = "internal error";
1344		break;
1345	}
1346
1347	ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",
1348		   ev->cmd_id, type);
1349
1350	return 0;
1351}
1352
1353static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len,
1354				     struct ath6kl_vif *vif)
1355{
1356	ath6kl_tgt_stats_event(vif, datap, len);
1357
1358	return 0;
1359}
1360
1361static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
1362					 struct sq_threshold_params *sq_thresh,
1363					 u32 size)
1364{
1365	u32 index;
1366	u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];
1367
1368	/* The list is already in sorted order. Get the next lower value */
1369	for (index = 0; index < size; index++) {
1370		if (rssi < sq_thresh->upper_threshold[index]) {
1371			threshold = (u8) sq_thresh->upper_threshold[index];
1372			break;
1373		}
1374	}
1375
1376	return threshold;
1377}
1378
1379static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,
1380					 struct sq_threshold_params *sq_thresh,
1381					 u32 size)
1382{
1383	u32 index;
1384	u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];
1385
1386	/* The list is already in sorted order. Get the next lower value */
1387	for (index = 0; index < size; index++) {
1388		if (rssi > sq_thresh->lower_threshold[index]) {
1389			threshold = (u8) sq_thresh->lower_threshold[index];
1390			break;
1391		}
1392	}
1393
1394	return threshold;
1395}
1396
1397static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
1398			struct wmi_rssi_threshold_params_cmd *rssi_cmd)
1399{
1400	struct sk_buff *skb;
1401	struct wmi_rssi_threshold_params_cmd *cmd;
1402
1403	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1404	if (!skb)
1405		return -ENOMEM;
1406
1407	cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;
1408	memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));
1409
1410	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
1411				   NO_SYNC_WMIFLAG);
1412}
1413
1414static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
1415					      int len)
1416{
1417	struct wmi_rssi_threshold_event *reply;
1418	struct wmi_rssi_threshold_params_cmd cmd;
1419	struct sq_threshold_params *sq_thresh;
1420	enum wmi_rssi_threshold_val new_threshold;
1421	u8 upper_rssi_threshold, lower_rssi_threshold;
1422	s16 rssi;
1423	int ret;
1424
1425	if (len < sizeof(struct wmi_rssi_threshold_event))
1426		return -EINVAL;
1427
1428	reply = (struct wmi_rssi_threshold_event *) datap;
1429	new_threshold = (enum wmi_rssi_threshold_val) reply->range;
1430	rssi = a_sle16_to_cpu(reply->rssi);
1431
1432	sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];
1433
1434	/*
1435	 * Identify the threshold breached and communicate that to the app.
1436	 * After that install a new set of thresholds based on the signal
1437	 * quality reported by the target
1438	 */
1439	if (new_threshold) {
1440		/* Upper threshold breached */
1441		if (rssi < sq_thresh->upper_threshold[0]) {
1442			ath6kl_dbg(ATH6KL_DBG_WMI,
1443				   "spurious upper rssi threshold event: %d\n",
1444				   rssi);
1445		} else if ((rssi < sq_thresh->upper_threshold[1]) &&
1446			   (rssi >= sq_thresh->upper_threshold[0])) {
1447			new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
1448		} else if ((rssi < sq_thresh->upper_threshold[2]) &&
1449			   (rssi >= sq_thresh->upper_threshold[1])) {
1450			new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;
1451		} else if ((rssi < sq_thresh->upper_threshold[3]) &&
1452			   (rssi >= sq_thresh->upper_threshold[2])) {
1453			new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;
1454		} else if ((rssi < sq_thresh->upper_threshold[4]) &&
1455			   (rssi >= sq_thresh->upper_threshold[3])) {
1456			new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;
1457		} else if ((rssi < sq_thresh->upper_threshold[5]) &&
1458			   (rssi >= sq_thresh->upper_threshold[4])) {
1459			new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;
1460		} else if (rssi >= sq_thresh->upper_threshold[5]) {
1461			new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;
1462		}
1463	} else {
1464		/* Lower threshold breached */
1465		if (rssi > sq_thresh->lower_threshold[0]) {
1466			ath6kl_dbg(ATH6KL_DBG_WMI,
1467				   "spurious lower rssi threshold event: %d %d\n",
1468				rssi, sq_thresh->lower_threshold[0]);
1469		} else if ((rssi > sq_thresh->lower_threshold[1]) &&
1470			   (rssi <= sq_thresh->lower_threshold[0])) {
1471			new_threshold = WMI_RSSI_THRESHOLD6_BELOW;
1472		} else if ((rssi > sq_thresh->lower_threshold[2]) &&
1473			   (rssi <= sq_thresh->lower_threshold[1])) {
1474			new_threshold = WMI_RSSI_THRESHOLD5_BELOW;
1475		} else if ((rssi > sq_thresh->lower_threshold[3]) &&
1476			   (rssi <= sq_thresh->lower_threshold[2])) {
1477			new_threshold = WMI_RSSI_THRESHOLD4_BELOW;
1478		} else if ((rssi > sq_thresh->lower_threshold[4]) &&
1479			   (rssi <= sq_thresh->lower_threshold[3])) {
1480			new_threshold = WMI_RSSI_THRESHOLD3_BELOW;
1481		} else if ((rssi > sq_thresh->lower_threshold[5]) &&
1482			   (rssi <= sq_thresh->lower_threshold[4])) {
1483			new_threshold = WMI_RSSI_THRESHOLD2_BELOW;
1484		} else if (rssi <= sq_thresh->lower_threshold[5]) {
1485			new_threshold = WMI_RSSI_THRESHOLD1_BELOW;
1486		}
1487	}
1488
1489	/* Calculate and install the next set of thresholds */
1490	lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,
1491				       sq_thresh->lower_threshold_valid_count);
1492	upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,
1493				       sq_thresh->upper_threshold_valid_count);
1494
1495	/* Issue a wmi command to install the thresholds */
1496	cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);
1497	cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);
1498	cmd.weight = sq_thresh->weight;
1499	cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1500
1501	ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);
1502	if (ret) {
1503		ath6kl_err("unable to configure rssi thresholds\n");
1504		return -EIO;
1505	}
1506
1507	return 0;
1508}
1509
1510static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
1511				   struct ath6kl_vif *vif)
1512{
1513	struct wmi_cac_event *reply;
1514	struct ieee80211_tspec_ie *ts;
1515	u16 active_tsids, tsinfo;
1516	u8 tsid, index;
1517	u8 ts_id;
1518
1519	if (len < sizeof(struct wmi_cac_event))
1520		return -EINVAL;
1521
1522	reply = (struct wmi_cac_event *) datap;
1523	if (reply->ac >= WMM_NUM_AC) {
1524		ath6kl_err("invalid AC: %d\n", reply->ac);
1525		return -EINVAL;
1526	}
1527
1528	if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
1529	    (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
1530		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1531		tsinfo = le16_to_cpu(ts->tsinfo);
1532		tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1533			IEEE80211_WMM_IE_TSPEC_TID_MASK;
1534
1535		ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,
1536					      reply->ac, tsid);
1537	} else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
1538		/*
1539		 * Following assumes that there is only one outstanding
1540		 * ADDTS request when this event is received
1541		 */
1542		spin_lock_bh(&wmi->lock);
1543		active_tsids = wmi->stream_exist_for_ac[reply->ac];
1544		spin_unlock_bh(&wmi->lock);
1545
1546		for (index = 0; index < sizeof(active_tsids) * 8; index++) {
1547			if ((active_tsids >> index) & 1)
1548				break;
1549		}
1550		if (index < (sizeof(active_tsids) * 8))
1551			ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,
1552						      reply->ac, index);
1553	}
1554
1555	/*
1556	 * Clear active tsids and Add missing handling
1557	 * for delete qos stream from AP
1558	 */
1559	else if (reply->cac_indication == CAC_INDICATION_DELETE) {
1560		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1561		tsinfo = le16_to_cpu(ts->tsinfo);
1562		ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1563			 IEEE80211_WMM_IE_TSPEC_TID_MASK);
1564
1565		spin_lock_bh(&wmi->lock);
1566		wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);
1567		active_tsids = wmi->stream_exist_for_ac[reply->ac];
1568		spin_unlock_bh(&wmi->lock);
1569
1570		/* Indicate stream inactivity to driver layer only if all tsids
1571		 * within this AC are deleted.
1572		 */
1573		if (!active_tsids) {
1574			ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,
1575						    false);
1576			wmi->fat_pipe_exist &= ~(1 << reply->ac);
1577		}
1578	}
1579
1580	return 0;
1581}
1582
1583static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
1584					  struct ath6kl_vif *vif)
1585{
1586	struct wmi_txe_notify_event *ev;
1587	u32 rate, pkts;
1588
1589	if (len < sizeof(*ev))
1590		return -EINVAL;
1591
1592	if (vif->nw_type != INFRA_NETWORK ||
1593	    !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
1594		      vif->ar->fw_capabilities))
1595		return -EOPNOTSUPP;
1596
1597	if (vif->sme_state != SME_CONNECTED)
1598		return -ENOTCONN;
1599
1600	ev = (struct wmi_txe_notify_event *) datap;
1601	rate = le32_to_cpu(ev->rate);
1602	pkts = le32_to_cpu(ev->pkts);
1603
1604	ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d%% pkts %d intvl %ds\n",
1605		   vif->bssid, rate, pkts, vif->txe_intvl);
1606
1607	cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,
1608				rate, vif->txe_intvl, GFP_KERNEL);
1609
1610	return 0;
1611}
1612
1613int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
1614			      u32 rate, u32 pkts, u32 intvl)
1615{
1616	struct sk_buff *skb;
1617	struct wmi_txe_notify_cmd *cmd;
1618
1619	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1620	if (!skb)
1621		return -ENOMEM;
1622
1623	cmd = (struct wmi_txe_notify_cmd *) skb->data;
1624	cmd->rate = cpu_to_le32(rate);
1625	cmd->pkts = cpu_to_le32(pkts);
1626	cmd->intvl = cpu_to_le32(intvl);
1627
1628	return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,
1629				   NO_SYNC_WMIFLAG);
1630}
1631
1632int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)
1633{
1634	struct sk_buff *skb;
1635	struct wmi_set_rssi_filter_cmd *cmd;
1636	int ret;
1637
1638	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1639	if (!skb)
1640		return -ENOMEM;
1641
1642	cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;
1643	cmd->rssi = rssi;
1644
1645	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,
1646				  NO_SYNC_WMIFLAG);
1647	return ret;
1648}
1649
1650static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
1651			struct wmi_snr_threshold_params_cmd *snr_cmd)
1652{
1653	struct sk_buff *skb;
1654	struct wmi_snr_threshold_params_cmd *cmd;
1655
1656	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1657	if (!skb)
1658		return -ENOMEM;
1659
1660	cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;
1661	memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));
1662
1663	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,
1664				   NO_SYNC_WMIFLAG);
1665}
1666
1667static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
1668					     int len)
1669{
1670	struct wmi_snr_threshold_event *reply;
1671	struct sq_threshold_params *sq_thresh;
1672	struct wmi_snr_threshold_params_cmd cmd;
1673	enum wmi_snr_threshold_val new_threshold;
1674	u8 upper_snr_threshold, lower_snr_threshold;
1675	s16 snr;
1676	int ret;
1677
1678	if (len < sizeof(struct wmi_snr_threshold_event))
1679		return -EINVAL;
1680
1681	reply = (struct wmi_snr_threshold_event *) datap;
1682
1683	new_threshold = (enum wmi_snr_threshold_val) reply->range;
1684	snr = reply->snr;
1685
1686	sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];
1687
1688	/*
1689	 * Identify the threshold breached and communicate that to the app.
1690	 * After that install a new set of thresholds based on the signal
1691	 * quality reported by the target.
1692	 */
1693	if (new_threshold) {
1694		/* Upper threshold breached */
1695		if (snr < sq_thresh->upper_threshold[0]) {
1696			ath6kl_dbg(ATH6KL_DBG_WMI,
1697				   "spurious upper snr threshold event: %d\n",
1698				   snr);
1699		} else if ((snr < sq_thresh->upper_threshold[1]) &&
1700			   (snr >= sq_thresh->upper_threshold[0])) {
1701			new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
1702		} else if ((snr < sq_thresh->upper_threshold[2]) &&
1703			   (snr >= sq_thresh->upper_threshold[1])) {
1704			new_threshold = WMI_SNR_THRESHOLD2_ABOVE;
1705		} else if ((snr < sq_thresh->upper_threshold[3]) &&
1706			   (snr >= sq_thresh->upper_threshold[2])) {
1707			new_threshold = WMI_SNR_THRESHOLD3_ABOVE;
1708		} else if (snr >= sq_thresh->upper_threshold[3]) {
1709			new_threshold = WMI_SNR_THRESHOLD4_ABOVE;
1710		}
1711	} else {
1712		/* Lower threshold breached */
1713		if (snr > sq_thresh->lower_threshold[0]) {
1714			ath6kl_dbg(ATH6KL_DBG_WMI,
1715				   "spurious lower snr threshold event: %d\n",
1716				   sq_thresh->lower_threshold[0]);
1717		} else if ((snr > sq_thresh->lower_threshold[1]) &&
1718			   (snr <= sq_thresh->lower_threshold[0])) {
1719			new_threshold = WMI_SNR_THRESHOLD4_BELOW;
1720		} else if ((snr > sq_thresh->lower_threshold[2]) &&
1721			   (snr <= sq_thresh->lower_threshold[1])) {
1722			new_threshold = WMI_SNR_THRESHOLD3_BELOW;
1723		} else if ((snr > sq_thresh->lower_threshold[3]) &&
1724			   (snr <= sq_thresh->lower_threshold[2])) {
1725			new_threshold = WMI_SNR_THRESHOLD2_BELOW;
1726		} else if (snr <= sq_thresh->lower_threshold[3]) {
1727			new_threshold = WMI_SNR_THRESHOLD1_BELOW;
1728		}
1729	}
1730
1731	/* Calculate and install the next set of thresholds */
1732	lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,
1733				       sq_thresh->lower_threshold_valid_count);
1734	upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,
1735				       sq_thresh->upper_threshold_valid_count);
1736
1737	/* Issue a wmi command to install the thresholds */
1738	cmd.thresh_above1_val = upper_snr_threshold;
1739	cmd.thresh_below1_val = lower_snr_threshold;
1740	cmd.weight = sq_thresh->weight;
1741	cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1742
1743	ath6kl_dbg(ATH6KL_DBG_WMI,
1744		   "snr: %d, threshold: %d, lower: %d, upper: %d\n",
1745		   snr, new_threshold,
1746		   lower_snr_threshold, upper_snr_threshold);
1747
1748	ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);
1749	if (ret) {
1750		ath6kl_err("unable to configure snr threshold\n");
1751		return -EIO;
1752	}
1753
1754	return 0;
1755}
1756
1757static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
1758{
1759	u16 ap_info_entry_size;
1760	struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;
1761	struct wmi_ap_info_v1 *ap_info_v1;
1762	u8 index;
1763
1764	if (len < sizeof(struct wmi_aplist_event) ||
1765	    ev->ap_list_ver != APLIST_VER1)
1766		return -EINVAL;
1767
1768	ap_info_entry_size = sizeof(struct wmi_ap_info_v1);
1769	ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;
1770
1771	ath6kl_dbg(ATH6KL_DBG_WMI,
1772		   "number of APs in aplist event: %d\n", ev->num_ap);
1773
1774	if (len < (int) (sizeof(struct wmi_aplist_event) +
1775			 (ev->num_ap - 1) * ap_info_entry_size))
1776		return -EINVAL;
1777
1778	/* AP list version 1 contents */
1779	for (index = 0; index < ev->num_ap; index++) {
1780		ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",
1781			   index, ap_info_v1->bssid, ap_info_v1->channel);
1782		ap_info_v1++;
1783	}
1784
1785	return 0;
1786}
1787
1788int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
1789			enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)
1790{
1791	struct wmi_cmd_hdr *cmd_hdr;
1792	enum htc_endpoint_id ep_id = wmi->ep_id;
1793	int ret;
1794	u16 info1;
1795
1796	if (WARN_ON(skb == NULL ||
1797		    (if_idx > (wmi->parent_dev->vif_max - 1)))) {
1798		dev_kfree_skb(skb);
1799		return -EINVAL;
1800	}
1801
1802	ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
1803		   cmd_id, skb->len, sync_flag);
1804	ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ",
1805			skb->data, skb->len);
1806
1807	if (sync_flag >= END_WMIFLAG) {
1808		dev_kfree_skb(skb);
1809		return -EINVAL;
1810	}
1811
1812	if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||
1813	    (sync_flag == SYNC_BOTH_WMIFLAG)) {
1814		/*
1815		 * Make sure all data currently queued is transmitted before
1816		 * the cmd execution.  Establish a new sync point.
1817		 */
1818		ath6kl_wmi_sync_point(wmi, if_idx);
1819	}
1820
1821	skb_push(skb, sizeof(struct wmi_cmd_hdr));
1822
1823	cmd_hdr = (struct wmi_cmd_hdr *) skb->data;
1824	cmd_hdr->cmd_id = cpu_to_le16(cmd_id);
1825	info1 = if_idx & WMI_CMD_HDR_IF_ID_MASK;
1826	cmd_hdr->info1 = cpu_to_le16(info1);
1827
1828	/* Only for OPT_TX_CMD, use BE endpoint. */
1829	if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {
1830		ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE,
1831					      false, false, 0, NULL, if_idx);
1832		if (ret) {
1833			dev_kfree_skb(skb);
1834			return ret;
1835		}
1836		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);
1837	}
1838
1839	ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
1840
1841	if ((sync_flag == SYNC_AFTER_WMIFLAG) ||
1842	    (sync_flag == SYNC_BOTH_WMIFLAG)) {
1843		/*
1844		 * Make sure all new data queued waits for the command to
1845		 * execute. Establish a new sync point.
1846		 */
1847		ath6kl_wmi_sync_point(wmi, if_idx);
1848	}
1849
1850	return 0;
1851}
1852
1853int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
1854			   enum network_type nw_type,
1855			   enum dot11_auth_mode dot11_auth_mode,
1856			   enum auth_mode auth_mode,
1857			   enum ath6kl_crypto_type pairwise_crypto,
1858			   u8 pairwise_crypto_len,
1859			   enum ath6kl_crypto_type group_crypto,
1860			   u8 group_crypto_len, int ssid_len, u8 *ssid,
1861			   u8 *bssid, u16 channel, u32 ctrl_flags,
1862			   u8 nw_subtype)
1863{
1864	struct sk_buff *skb;
1865	struct wmi_connect_cmd *cc;
1866	int ret;
1867
1868	ath6kl_dbg(ATH6KL_DBG_WMI,
1869		   "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d "
1870		   "type %d dot11_auth %d auth %d pairwise %d group %d\n",
1871		   bssid, channel, ctrl_

Large files files are truncated, but you can click here to view the full file