cmd.c 54.8 KB
Newer Older
1 2 3 4 5 6
/**
  * This file contains the handling of command.
  * It prepares command and sends it to firmware when it is ready.
  */

#include <net/iw_handler.h>
7
#include <net/lib80211.h>
8
#include <linux/kfifo.h>
9 10 11 12 13
#include "host.h"
#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
14
#include "assoc.h"
15
#include "wext.h"
16
#include "cmd.h"
17

18
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
19

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
/**
 *  @brief Simple callback that copies response back into command
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param extra  	A pointer to the original command structure for which
 *                      'resp' is a response
 *  @param resp         A pointer to the command response
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
		     struct cmd_header *resp)
{
	struct cmd_header *buf = (void *)extra;
	uint16_t copy_len;

	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
	memcpy(buf, resp, copy_len);
	return 0;
}
EXPORT_SYMBOL_GPL(lbs_cmd_copyback);

/**
 *  @brief Simple callback that ignores the result. Use this if
 *  you just want to send a command to the hardware, but don't
 *  care for the result.
 *
 *  @param priv         ignored
 *  @param extra        ignored
 *  @param resp         ignored
 *
 *  @return 	   	0 for success
 */
static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
		     struct cmd_header *resp)
{
	return 0;
}


60
/**
61
 *  @brief Checks whether a command is allowed in Power Save mode
62 63
 *
 *  @param command the command ID
64
 *  @return 	   1 if allowed, 0 if not allowed
65
 */
66
static u8 is_command_allowed_in_ps(u16 cmd)
67
{
68 69 70 71 72
	switch (cmd) {
	case CMD_802_11_RSSI:
		return 1;
	default:
		break;
73 74 75 76
	}
	return 0;
}

77 78 79 80 81 82 83 84
/**
 *  @brief Updates the hardware details like MAC address and regulatory region
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_update_hw_spec(struct lbs_private *priv)
85
{
86 87 88
	struct cmd_ds_get_hw_spec cmd;
	int ret = -1;
	u32 i;
89

90
	lbs_deb_enter(LBS_DEB_CMD);
91

92 93 94
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
95
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
96 97 98 99 100
	if (ret)
		goto out;

	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);

101 102 103 104 105 106 107 108 109 110
	/* The firmware release is in an interesting format: the patch
	 * level is in the most significant nibble ... so fix that: */
	priv->fwrelease = le32_to_cpu(cmd.fwrelease);
	priv->fwrelease = (priv->fwrelease << 8) |
		(priv->fwrelease >> 24 & 0xff);

	/* Some firmware capabilities:
	 * CF card    firmware 5.0.16p0:   cap 0x00000303
	 * USB dongle firmware 5.110.17p2: cap 0x00000303
	 */
J
Johannes Berg 已提交
111 112
	lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
		cmd.permanentaddr,
113 114 115 116 117
		priv->fwrelease >> 24 & 0xff,
		priv->fwrelease >> 16 & 0xff,
		priv->fwrelease >>  8 & 0xff,
		priv->fwrelease       & 0xff,
		priv->fwcapinfo);
118 119 120
	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
		    cmd.hwifversion, cmd.version);

121 122 123 124 125 126 127 128 129 130 131 132 133
	/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
	/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
	/* 5.110.22 have mesh command with 0xa3 command id */
	/* 10.0.0.p0 FW brings in mesh config command with different id */
	/* Check FW version MSB and initialize mesh_fw_ver */
	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
		priv->mesh_fw_ver = MESH_FW_OLD;
	else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
		priv->mesh_fw_ver = MESH_FW_NEW;
	else
		priv->mesh_fw_ver = MESH_NONE;

134 135 136
	/* Clamp region code to 8-bit since FW spec indicates that it should
	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
	 * returns non-zero high 8 bits here.
137 138 139
	 *
	 * Firmware version 4.0.102 used in CF8381 has region code shifted.  We
	 * need to check for this problem and handle it properly.
140
	 */
141 142 143 144
	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
		priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
	else
		priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
		/* use the region code to search for the index */
		if (priv->regioncode == lbs_region_code_to_index[i])
			break;
	}

	/* if it's unidentified region code, use the default (USA) */
	if (i >= MRVDRV_MAX_REGION_CODE) {
		priv->regioncode = 0x10;
		lbs_pr_info("unidentified region code; using the default (USA)\n");
	}

	if (priv->current_addr[0] == 0xff)
		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
160

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
	memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
	if (priv->mesh_dev)
		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);

	if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
		ret = -1;
		goto out;
	}

	if (lbs_set_universaltable(priv, 0)) {
		ret = -1;
		goto out;
	}

out:
176
	lbs_deb_leave(LBS_DEB_CMD);
177
	return ret;
178 179
}

180 181
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
		struct wol_config *p_wol_config)
182 183 184 185
{
	struct cmd_ds_host_sleep cmd_config;
	int ret;

186
	cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
187
	cmd_config.criteria = cpu_to_le32(criteria);
188 189
	cmd_config.gpio = priv->wol_gpio;
	cmd_config.gap = priv->wol_gap;
190

191 192 193 194 195 196
	if (p_wol_config != NULL)
		memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
				sizeof(struct wol_config));
	else
		cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;

197
	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
198
	if (!ret) {
199 200 201 202 203 204 205
		if (criteria) {
			lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
			priv->wol_criteria = criteria;
		} else
			memcpy((uint8_t *) p_wol_config,
					(uint8_t *)&cmd_config.wol_conf,
					sizeof(struct wol_config));
206
	} else {
207 208
		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
	}
209

210 211 212 213
	return ret;
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);

214
static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
215 216 217 218
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

219
	lbs_deb_enter(LBS_DEB_CMD);
220

221
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
222 223
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
				S_DS_GEN);
224 225
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
226
	switch (cmd_action) {
227
	case CMD_SUBCMD_ENTER_PS:
228
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
229

230
		psm->locallisteninterval = 0;
231
		psm->nullpktinterval = 0;
232
		psm->multipledtim =
233
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
234 235
		break;

236
	case CMD_SUBCMD_EXIT_PS:
237
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
238 239
		break;

240
	case CMD_SUBCMD_SLEEP_CONFIRMED:
241
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
242 243 244 245 246 247
		break;

	default:
		break;
	}

248
	lbs_deb_leave(LBS_DEB_CMD);
249 250 251
	return 0;
}

252 253
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
				      uint16_t cmd_action, uint16_t *timeout)
254
{
255 256
	struct cmd_ds_802_11_inactivity_timeout cmd;
	int ret;
257

258 259
	lbs_deb_enter(LBS_DEB_CMD);

260 261
	cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
262

263
	cmd.action = cpu_to_le16(cmd_action);
264

265 266
	if (cmd_action == CMD_ACT_SET)
		cmd.timeout = cpu_to_le16(*timeout);
267
	else
268
		cmd.timeout = 0;
269

270 271 272 273 274 275
	ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);

	if (!ret)
		*timeout = le16_to_cpu(cmd.timeout);

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
276 277 278
	return 0;
}

279 280
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
				struct sleep_params *sp)
281
{
282 283
	struct cmd_ds_802_11_sleep_params cmd;
	int ret;
284

285
	lbs_deb_enter(LBS_DEB_CMD);
286

287
	if (cmd_action == CMD_ACT_GET) {
288 289 290 291 292 293 294 295
		memset(&cmd, 0, sizeof(cmd));
	} else {
		cmd.error = cpu_to_le16(sp->sp_error);
		cmd.offset = cpu_to_le16(sp->sp_offset);
		cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
		cmd.calcontrol = sp->sp_calcontrol;
		cmd.externalsleepclk = sp->sp_extsleepclk;
		cmd.reserved = cpu_to_le16(sp->sp_reserved);
296
	}
297 298
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
299

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);

	if (!ret) {
		lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
			    "calcontrol 0x%x extsleepclk 0x%x\n",
			    le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
			    le16_to_cpu(cmd.stabletime), cmd.calcontrol,
			    cmd.externalsleepclk);

		sp->sp_error = le16_to_cpu(cmd.error);
		sp->sp_offset = le16_to_cpu(cmd.offset);
		sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
		sp->sp_calcontrol = cmd.calcontrol;
		sp->sp_extsleepclk = cmd.externalsleepclk;
		sp->sp_reserved = le16_to_cpu(cmd.reserved);
	}

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
318 319 320
	return 0;
}

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
static int lbs_wait_for_ds_awake(struct lbs_private *priv)
{
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

	if (priv->is_deep_sleep) {
		if (!wait_event_interruptible_timeout(priv->ds_awake_q,
					!priv->is_deep_sleep, (10 * HZ))) {
			lbs_pr_err("ds_awake_q: timer expired\n");
			ret = -1;
		}
	}

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
{
	int ret =  0;

	lbs_deb_enter(LBS_DEB_CMD);

	if (deep_sleep) {
		if (priv->is_deep_sleep != 1) {
			lbs_deb_cmd("deep sleep: sleep\n");
			BUG_ON(!priv->enter_deep_sleep);
			ret = priv->enter_deep_sleep(priv);
			if (!ret) {
				netif_stop_queue(priv->dev);
				netif_carrier_off(priv->dev);
			}
		} else {
			lbs_pr_err("deep sleep: already enabled\n");
		}
	} else {
		if (priv->is_deep_sleep) {
			lbs_deb_cmd("deep sleep: wakeup\n");
			BUG_ON(!priv->exit_deep_sleep);
			ret = priv->exit_deep_sleep(priv);
			if (!ret) {
				ret = lbs_wait_for_ds_awake(priv);
				if (ret)
					lbs_pr_err("deep sleep: wakeup"
							"failed\n");
			}
		}
	}

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

375 376
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
			   struct assoc_request *assoc)
377
{
378
	struct cmd_ds_802_11_set_wep cmd;
379 380
	int ret = 0;

381
	lbs_deb_enter(LBS_DEB_CMD);
382

383
	memset(&cmd, 0, sizeof(cmd));
384 385
	cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
386

387
	cmd.action = cpu_to_le16(cmd_action);
388

389 390
	if (cmd_action == CMD_ACT_ADD) {
		int i;
391 392

		/* default tx key index */
393 394
		cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
					   CMD_WEP_KEY_INDEX_MASK);
395 396 397

		/* Copy key types and material to host command structure */
		for (i = 0; i < 4; i++) {
398
			struct enc_key *pkey = &assoc->wep_keys[i];
399 400 401

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
402 403
				cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
404
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
405 406
				break;
			case KEY_LEN_WEP_104:
407 408
				cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
409
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
410 411 412 413
				break;
			case 0:
				break;
			default:
414
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
415
					    i, pkey->len);
416 417 418 419 420
				ret = -1;
				goto done;
				break;
			}
		}
421
	} else if (cmd_action == CMD_ACT_REMOVE) {
422 423 424
		/* ACT_REMOVE clears _all_ WEP keys */

		/* default tx key index */
425 426
		cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
					   CMD_WEP_KEY_INDEX_MASK);
427
		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
428 429
	}

430
	ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
431
done:
432
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
433 434 435
	return ret;
}

436 437
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
			      uint16_t *enable)
438
{
439 440
	struct cmd_ds_802_11_enable_rsn cmd;
	int ret;
441 442

	lbs_deb_enter(LBS_DEB_CMD);
443

444 445
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
446

447 448 449
	if (cmd_action == CMD_ACT_GET)
		cmd.enable = 0;
	else {
450
		if (*enable)
451
			cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
452
		else
453
			cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
454
		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
455 456
	}

457 458 459 460 461 462
	ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
	if (!ret && cmd_action == CMD_ACT_GET)
		*enable = le16_to_cpu(cmd.enable);

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
463 464
}

465 466
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
                            struct enc_key *key)
467
{
468 469
	lbs_deb_enter(LBS_DEB_CMD);

470 471 472 473 474 475
	if (key->flags & KEY_INFO_WPA_ENABLED)
		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
	if (key->flags & KEY_INFO_WPA_UNICAST)
		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
	if (key->flags & KEY_INFO_WPA_MCAST)
		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
476

477 478 479 480 481 482 483
	keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
	keyparam->keytypeid = cpu_to_le16(key->type);
	keyparam->keylen = cpu_to_le16(key->len);
	memcpy(keyparam->key, key->key, key->len);

	/* Length field doesn't include the {type,length} header */
	keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
484
	lbs_deb_leave(LBS_DEB_CMD);
485 486
}

487 488
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
				struct assoc_request *assoc)
489
{
490
	struct cmd_ds_802_11_key_material cmd;
491 492 493
	int ret = 0;
	int index = 0;

494
	lbs_deb_enter(LBS_DEB_CMD);
495

496 497
	cmd.action = cpu_to_le16(cmd_action);
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
498

499
	if (cmd_action == CMD_ACT_GET) {
500 501 502
		cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
	} else {
		memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
503

504 505 506 507 508
		if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
			set_one_wpa_key(&cmd.keyParamSet[index],
					&assoc->wpa_unicast_key);
			index++;
		}
509

510 511 512 513 514
		if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
			set_one_wpa_key(&cmd.keyParamSet[index],
					&assoc->wpa_mcast_key);
			index++;
		}
515

516 517 518
		/* The common header and as many keys as we included */
		cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
						    keyParamSet[index]));
519
	}
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
	ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
	/* Copy the returned key to driver private data */
	if (!ret && cmd_action == CMD_ACT_GET) {
		void *buf_ptr = cmd.keyParamSet;
		void *resp_end = &(&cmd)[1];

		while (buf_ptr < resp_end) {
			struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
			struct enc_key *key;
			uint16_t param_set_len = le16_to_cpu(keyparam->length);
			uint16_t key_len = le16_to_cpu(keyparam->keylen);
			uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
			uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
			void *end;

			end = (void *)keyparam + sizeof(keyparam->type)
				+ sizeof(keyparam->length) + param_set_len;

			/* Make sure we don't access past the end of the IEs */
			if (end > resp_end)
				break;
541

542 543 544 545 546 547
			if (key_flags & KEY_INFO_WPA_UNICAST)
				key = &priv->wpa_unicast_key;
			else if (key_flags & KEY_INFO_WPA_MCAST)
				key = &priv->wpa_mcast_key;
			else
				break;
548

549 550 551 552 553 554 555 556 557 558 559 560
			/* Copy returned key into driver */
			memset(key, 0, sizeof(struct enc_key));
			if (key_len > sizeof(key->key))
				break;
			key->type = key_type;
			key->flags = key_flags;
			key->len = key_len;
			memcpy(key->key, keyparam->key, key->len);

			buf_ptr = end + 1;
		}
	}
561

562
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
563 564 565
	return ret;
}

566 567 568 569 570 571 572 573 574 575
/**
 *  @brief Set an SNMP MIB value
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param oid  	The OID to set in the firmware
 *  @param val  	Value to set the OID to
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
576
{
577 578
	struct cmd_ds_802_11_snmp_mib cmd;
	int ret;
579

580
	lbs_deb_enter(LBS_DEB_CMD);
581

582 583 584 585
	memset(&cmd, 0, sizeof (cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);
	cmd.oid = cpu_to_le16((u16) oid);
586

587 588 589 590 591 592 593 594 595 596 597 598
	switch (oid) {
	case SNMP_MIB_OID_BSS_TYPE:
		cmd.bufsize = cpu_to_le16(sizeof(u8));
		cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
		break;
	case SNMP_MIB_OID_11D_ENABLE:
	case SNMP_MIB_OID_FRAG_THRESHOLD:
	case SNMP_MIB_OID_RTS_THRESHOLD:
	case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
	case SNMP_MIB_OID_LONG_RETRY_LIMIT:
		cmd.bufsize = cpu_to_le16(sizeof(u16));
		*((__le16 *)(&cmd.value)) = cpu_to_le16(val);
599
		break;
600 601 602 603
	default:
		lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
		ret = -EINVAL;
		goto out;
604 605
	}

606 607
	lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
		    le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
608

609
	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
610

611 612 613 614
out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}
615

616 617 618 619 620 621 622 623 624 625 626 627 628
/**
 *  @brief Get an SNMP MIB value
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param oid  	The OID to retrieve from the firmware
 *  @param out_val  	Location for the returned value
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
{
	struct cmd_ds_802_11_snmp_mib cmd;
	int ret;
629

630
	lbs_deb_enter(LBS_DEB_CMD);
631

632 633 634 635
	memset(&cmd, 0, sizeof (cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_GET);
	cmd.oid = cpu_to_le16(oid);
636

637 638 639
	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
	if (ret)
		goto out;
640

641 642 643 644 645 646 647 648 649 650 651 652
	switch (le16_to_cpu(cmd.bufsize)) {
	case sizeof(u8):
		if (oid == SNMP_MIB_OID_BSS_TYPE) {
			if (cmd.value[0] == 2)
				*out_val = IW_MODE_ADHOC;
			else
				*out_val = IW_MODE_INFRA;
		} else
			*out_val = cmd.value[0];
		break;
	case sizeof(u16):
		*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
653 654
		break;
	default:
655 656
		lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
		            oid, le16_to_cpu(cmd.bufsize));
657 658 659
		break;
	}

660 661 662
out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
663 664
}

665 666 667 668 669 670 671 672 673 674 675 676
/**
 *  @brief Get the min, max, and current TX power
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param curlevel  	Current power level in dBm
 *  @param minlevel  	Minimum supported power level in dBm (optional)
 *  @param maxlevel  	Maximum supported power level in dBm (optional)
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
		     s16 *maxlevel)
677
{
678 679
	struct cmd_ds_802_11_rf_tx_power cmd;
	int ret;
680

681
	lbs_deb_enter(LBS_DEB_CMD);
682

683 684 685 686 687 688 689 690
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_GET);

	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
	if (ret == 0) {
		*curlevel = le16_to_cpu(cmd.curlevel);
		if (minlevel)
691
			*minlevel = cmd.minlevel;
692
		if (maxlevel)
693
			*maxlevel = cmd.maxlevel;
694
	}
695

696 697 698
	lbs_deb_leave(LBS_DEB_CMD);
	return ret;
}
699

700 701 702 703 704 705 706 707 708 709 710 711
/**
 *  @brief Set the TX power
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param dbm  	The desired power level in dBm
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
{
	struct cmd_ds_802_11_rf_tx_power cmd;
	int ret;
712

713
	lbs_deb_enter(LBS_DEB_CMD);
714

715 716 717 718
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);
	cmd.curlevel = cpu_to_le16(dbm);
719

720 721 722
	lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);

	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
723 724

	lbs_deb_leave(LBS_DEB_CMD);
725
	return ret;
726 727
}

728
static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
				      u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;

	cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
			     S_DS_GEN);

	monitor->action = cpu_to_le16(cmd_action);
	if (cmd_action == CMD_ACT_SET) {
		monitor->mode =
		    cpu_to_le16((u16) (*(u32 *) pdata_buf));
	}

	return 0;
}

747
static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
748
{
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
/*		Bit  	Rate
*		15:13 Reserved
*		12    54 Mbps
*		11    48 Mbps
*		10    36 Mbps
*		9     24 Mbps
*		8     18 Mbps
*		7     12 Mbps
*		6     9 Mbps
*		5     6 Mbps
*		4     Reserved
*		3     11 Mbps
*		2     5.5 Mbps
*		1     2 Mbps
*		0     1 Mbps
**/

	uint16_t ratemask;
	int i = lbs_data_rate_to_fw_index(rate);
	if (lower_rates_ok)
		ratemask = (0x1fef >> (12 - i));
	else
		ratemask = (1 << i);
	return cpu_to_le16(ratemask);
}

int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
				      uint16_t cmd_action)
{
	struct cmd_ds_802_11_rate_adapt_rateset cmd;
	int ret;
780

781
	lbs_deb_enter(LBS_DEB_CMD);
782

783 784
	if (!priv->cur_rate && !priv->enablehwauto)
		return -EINVAL;
785

786 787 788 789 790 791 792 793 794 795 796 797 798
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));

	cmd.action = cpu_to_le16(cmd_action);
	cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
	cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
	ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
	if (!ret && cmd_action == CMD_ACT_GET) {
		priv->ratebitmap = le16_to_cpu(cmd.bitmap);
		priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
	}

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
799
}
800
EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
801

802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
/**
 *  @brief Set the data rate
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param rate  	The desired data rate, or 0 to clear a locked rate
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
{
	struct cmd_ds_802_11_data_rate cmd;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));

	if (rate > 0) {
		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
		cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
		if (cmd.rates[0] == 0) {
			lbs_deb_cmd("DATA_RATE: invalid requested rate of"
			            " 0x%02X\n", rate);
			ret = 0;
			goto out;
		}
		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
	} else {
		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
832
		lbs_deb_cmd("DATA_RATE: setting auto\n");
833 834
	}

835
	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
836 837 838 839 840 841 842 843 844 845 846 847 848 849
	if (ret)
		goto out;

	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));

	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
	priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
850 851
}

852 853 854 855 856 857 858 859
/**
 *  @brief Get the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	The channel on success, error on failure
 */
int lbs_get_channel(struct lbs_private *priv)
860
{
861 862
	struct cmd_ds_802_11_rf_channel cmd;
	int ret = 0;
863

864
	lbs_deb_enter(LBS_DEB_CMD);
865

866
	memset(&cmd, 0, sizeof(cmd));
867 868
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
869

870
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
871 872
	if (ret)
		goto out;
873

874 875
	ret = le16_to_cpu(cmd.channel);
	lbs_deb_cmd("current radio channel is %d\n", ret);
876 877 878 879 880 881

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
int lbs_update_channel(struct lbs_private *priv)
{
	int ret;

	/* the channel in f/w could be out of sync; get the current channel */
	lbs_deb_enter(LBS_DEB_ASSOC);

	ret = lbs_get_channel(priv);
	if (ret > 0) {
		priv->curbssparams.channel = ret;
		ret = 0;
	}
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
	return ret;
}

898 899 900 901 902 903 904 905 906 907 908
/**
 *  @brief Set the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *  @param channel  	The desired channel, or 0 to clear a locked channel
 *
 *  @return 	   	0 on success, error on failure
 */
int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
	struct cmd_ds_802_11_rf_channel cmd;
909
#ifdef DEBUG
910
	u8 old_channel = priv->curbssparams.channel;
911
#endif
912 913 914 915
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

916
	memset(&cmd, 0, sizeof(cmd));
917 918 919 920
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
	cmd.channel = cpu_to_le16(channel);

921
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
922 923 924
	if (ret)
		goto out;

925 926 927
	priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
	lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
		priv->curbssparams.channel);
928 929 930 931

out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
932 933
}

934
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
935 936 937
				struct cmd_ds_command *cmd)
{

938
	lbs_deb_enter(LBS_DEB_CMD);
939
	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
940
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
941
	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
942 943

	/* reset Beacon SNR/NF/RSSI values */
944 945 946 947 948 949
	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
	priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
	priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
950

951
	lbs_deb_leave(LBS_DEB_CMD);
952 953 954
	return 0;
}

955
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
956 957
			       u8 cmd_action, void *pdata_buf)
{
958
	struct lbs_offset_value *offval;
959

960
	lbs_deb_enter(LBS_DEB_CMD);
961

962
	offval = (struct lbs_offset_value *)pdata_buf;
963

H
Holger Schurig 已提交
964
	switch (le16_to_cpu(cmdptr->command)) {
965
	case CMD_MAC_REG_ACCESS:
966 967 968 969
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
970 971
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
972 973 974 975 976 977 978 979 980 981 982
			macreg =
			    (struct cmd_ds_mac_reg_access *)&cmdptr->params.
			    macreg;

			macreg->action = cpu_to_le16(cmd_action);
			macreg->offset = cpu_to_le16((u16) offval->offset);
			macreg->value = cpu_to_le32(offval->value);

			break;
		}

983
	case CMD_BBP_REG_ACCESS:
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
		{
			struct cmd_ds_bbp_reg_access *bbpreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_bbp_reg_access)
					     + S_DS_GEN);
			bbpreg =
			    (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
			    bbpreg;

			bbpreg->action = cpu_to_le16(cmd_action);
			bbpreg->offset = cpu_to_le16((u16) offval->offset);
			bbpreg->value = (u8) offval->value;

			break;
		}

1002
	case CMD_RF_REG_ACCESS:
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
		{
			struct cmd_ds_rf_reg_access *rfreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_rf_reg_access) +
					     S_DS_GEN);
			rfreg =
			    (struct cmd_ds_rf_reg_access *)&cmdptr->params.
			    rfreg;

			rfreg->action = cpu_to_le16(cmd_action);
			rfreg->offset = cpu_to_le16((u16) offval->offset);
			rfreg->value = (u8) offval->value;

			break;
		}

	default:
		break;
	}

1025
	lbs_deb_leave(LBS_DEB_CMD);
1026 1027 1028
	return 0;
}

1029
static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
1030 1031 1032
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
1033
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1034

1035
	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
1036
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
1037 1038 1039 1040
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
1041
	case CMD_ACT_BT_ACCESS_ADD:
1042
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
1043
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
1044
		break;
1045
	case CMD_ACT_BT_ACCESS_DEL:
1046
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
1047
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
1048
		break;
1049
	case CMD_ACT_BT_ACCESS_LIST:
1050 1051
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1052
	case CMD_ACT_BT_ACCESS_RESET:
1053
		break;
1054
	case CMD_ACT_BT_ACCESS_SET_INVERT:
1055 1056
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
1057
	case CMD_ACT_BT_ACCESS_GET_INVERT:
1058
		break;
1059 1060 1061
	default:
		break;
	}
1062
	lbs_deb_leave(LBS_DEB_CMD);
1063 1064 1065
	return 0;
}

1066
static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
1067 1068 1069
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
1070
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1071

1072
	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
1073
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
1074 1075 1076 1077 1078 1079 1080 1081 1082
	cmd->result = 0;

	if (pdata_buf)
		memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
	else
		memset(fwt_access, 0, sizeof(*fwt_access));

	fwt_access->action = cpu_to_le16(cmd_action);

1083
	lbs_deb_leave(LBS_DEB_CMD);
1084 1085 1086
	return 0;
}

1087 1088
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
		    struct cmd_ds_mesh_access *cmd)
1089
{
1090 1091
	int ret;

1092
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
1093

1094
	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
1095
	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
1096
	cmd->hdr.result = 0;
1097

1098
	cmd->action = cpu_to_le16(cmd_action);
1099

1100
	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
1101

1102
	lbs_deb_leave(LBS_DEB_CMD);
1103
	return ret;
1104 1105
}

1106 1107 1108
static int __lbs_mesh_config_send(struct lbs_private *priv,
				  struct cmd_ds_mesh_config *cmd,
				  uint16_t action, uint16_t type)
1109 1110
{
	int ret;
1111
	u16 command = CMD_MESH_CONFIG_OLD;
1112 1113 1114

	lbs_deb_enter(LBS_DEB_CMD);

1115 1116 1117 1118 1119 1120 1121 1122 1123
	/*
	 * Command id is 0xac for v10 FW along with mesh interface
	 * id in bits 14-13-12.
	 */
	if (priv->mesh_fw_ver == MESH_FW_NEW)
		command = CMD_MESH_CONFIG |
			  (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);

	cmd->hdr.command = cpu_to_le16(command);
1124 1125 1126 1127 1128 1129
	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
	cmd->hdr.result = 0;

	cmd->type = cpu_to_le16(type);
	cmd->action = cpu_to_le16(action);

1130
	ret = lbs_cmd_with_response(priv, command, cmd);
1131 1132 1133 1134 1135

	lbs_deb_leave(LBS_DEB_CMD);
	return ret;
}

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
int lbs_mesh_config_send(struct lbs_private *priv,
			 struct cmd_ds_mesh_config *cmd,
			 uint16_t action, uint16_t type)
{
	int ret;

	if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
		return -EOPNOTSUPP;

	ret = __lbs_mesh_config_send(priv, cmd, action, type);
	return ret;
}

1149 1150 1151 1152 1153 1154
/* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
 * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
 * lbs_mesh_config_send.
 */
int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
1155 1156
{
	struct cmd_ds_mesh_config cmd;
1157
	struct mrvl_meshie *ie;
1158
	DECLARE_SSID_BUF(ssid);
1159 1160

	memset(&cmd, 0, sizeof(cmd));
1161
	cmd.channel = cpu_to_le16(chan);
1162 1163 1164 1165
	ie = (struct mrvl_meshie *)cmd.data;

	switch (action) {
	case CMD_ACT_MESH_CONFIG_START:
J
Johannes Berg 已提交
1166
		ie->id = WLAN_EID_GENERIC;
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
		ie->val.oui[0] = 0x00;
		ie->val.oui[1] = 0x50;
		ie->val.oui[2] = 0x43;
		ie->val.type = MARVELL_MESH_IE_TYPE;
		ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
		ie->val.version = MARVELL_MESH_IE_VERSION;
		ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
		ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
		ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
		ie->val.mesh_id_len = priv->mesh_ssid_len;
		memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
J
Johannes Berg 已提交
1178
		ie->len = sizeof(struct mrvl_meshie_val) -
1179 1180 1181 1182 1183 1184 1185
			IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
		cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
		break;
	case CMD_ACT_MESH_CONFIG_STOP:
		break;
	default:
		return -1;
1186
	}
1187 1188
	lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
		    action, priv->mesh_tlv, chan,
1189
		    print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
1190

1191
	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
1192 1193
}

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
				struct cmd_ds_command *cmd,
				u16 cmd_action)
{
	struct cmd_ds_802_11_beacon_control
		*bcn_ctrl = &cmd->params.bcn_ctrl;

	lbs_deb_enter(LBS_DEB_CMD);
	cmd->size =
	    cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
			     + S_DS_GEN);
	cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);

	bcn_ctrl->action = cpu_to_le16(cmd_action);
1208 1209
	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
1210 1211 1212 1213 1214

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

1215 1216
static void lbs_queue_cmd(struct lbs_private *priv,
			  struct cmd_ctrl_node *cmdnode)
1217 1218
{
	unsigned long flags;
1219
	int addtail = 1;
1220

1221
	lbs_deb_enter(LBS_DEB_HOST);
1222

1223 1224
	if (!cmdnode) {
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
1225 1226
		goto done;
	}
1227 1228 1229 1230
	if (!cmdnode->cmdbuf->size) {
		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
		goto done;
	}
1231
	cmdnode->result = 0;
1232 1233

	/* Exit_PS command needs to be queued in the header always. */
1234
	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
1235
		struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
1236

1237
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1238
			if (priv->psstate != PS_STATE_FULL_POWER)
1239 1240 1241 1242
				addtail = 0;
		}
	}

1243
	spin_lock_irqsave(&priv->driver_lock, flags);
1244

1245
	if (addtail)
1246
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
1247
	else
1248
		list_add(&cmdnode->list, &priv->cmdpendingq);
1249

1250
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1251

1252
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
1253
		     le16_to_cpu(cmdnode->cmdbuf->command));
1254 1255

done:
1256
	lbs_deb_leave(LBS_DEB_HOST);
1257 1258
}

1259 1260
static void lbs_submit_command(struct lbs_private *priv,
			       struct cmd_ctrl_node *cmdnode)
1261 1262
{
	unsigned long flags;
1263
	struct cmd_header *cmd;
1264 1265
	uint16_t cmdsize;
	uint16_t command;
1266
	int timeo = 3 * HZ;
1267
	int ret;
1268

1269
	lbs_deb_enter(LBS_DEB_HOST);
1270

1271
	cmd = cmdnode->cmdbuf;
1272

1273 1274 1275 1276
	spin_lock_irqsave(&priv->driver_lock, flags);
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1277

1278 1279
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
1280

1281
	/* These commands take longer */
1282
	if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
1283
		timeo = 5 * HZ;
1284

H
Holger Schurig 已提交
1285 1286
	lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
		     command, le16_to_cpu(cmd->seqnum), cmdsize);
1287
	lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
1288

1289
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
1290

1291 1292
	if (ret) {
		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
1293 1294
		/* Let the timer kick in and retry, and potentially reset
		   the whole thing if the condition persists */
1295
		timeo = HZ/4;
1296
	}
1297

1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
	if (command == CMD_802_11_DEEP_SLEEP) {
		if (priv->is_auto_deep_sleep_enabled) {
			priv->wakeup_dev_required = 1;
			priv->dnld_sent = 0;
		}
		priv->is_deep_sleep = 1;
		lbs_complete_command(priv, cmdnode, 0);
	} else {
		/* Setup the timer after transmit command */
		mod_timer(&priv->command_timer, jiffies + timeo);
	}
1309

1310
	lbs_deb_leave(LBS_DEB_HOST);
1311 1312 1313 1314
}

/**
 *  This function inserts command node to cmdfreeq
1315
 *  after cleans it. Requires priv->driver_lock held.
1316
 */
1317
static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1318
					 struct cmd_ctrl_node *cmdnode)
1319
{
1320 1321 1322 1323 1324 1325 1326
	lbs_deb_enter(LBS_DEB_HOST);

	if (!cmdnode)
		goto out;

	cmdnode->callback = NULL;
	cmdnode->callback_arg = 0;
1327

1328
	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
1329

1330 1331 1332
	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
 out:
	lbs_deb_leave(LBS_DEB_HOST);
1333 1334
}

1335 1336
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
1337 1338 1339
{
	unsigned long flags;

1340
	spin_lock_irqsave(&priv->driver_lock, flags);
1341
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1342
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1343 1344
}

1345 1346 1347 1348 1349
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
			  int result)
{
	if (cmd == priv->cur_cmd)
		priv->cur_cmd_retcode = result;
1350

1351
	cmd->result = result;
1352 1353 1354
	cmd->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmd->cmdwait_q);

1355
	if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
1356
		__lbs_cleanup_and_insert_cmd(priv, cmd);
1357 1358 1359
	priv->cur_cmd = NULL;
}

1360
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
1361
{
1362
	struct cmd_ds_802_11_radio_control cmd;
1363
	int ret = -EINVAL;
1364

1365
	lbs_deb_enter(LBS_DEB_CMD);
1366

1367 1368 1369
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);

1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
	/* Only v8 and below support setting the preamble */
	if (priv->fwrelease < 0x09000000) {
		switch (preamble) {
		case RADIO_PREAMBLE_SHORT:
			if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
				goto out;
			/* Fall through */
		case RADIO_PREAMBLE_AUTO:
		case RADIO_PREAMBLE_LONG:
			cmd.control = cpu_to_le16(preamble);
			break;
		default:
			goto out;
		}
	}
1385

1386 1387 1388 1389 1390
	if (radio_on)
		cmd.control |= cpu_to_le16(0x1);
	else {
		cmd.control &= cpu_to_le16(~0x1);
		priv->txpower_cur = 0;
1391
	}
1392

1393 1394
	lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
		    radio_on ? "ON" : "OFF", preamble);
1395

1396
	priv->radio_on = radio_on;
1397 1398

	ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
1399

1400
out:
1401
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1402 1403 1404
	return ret;
}

1405
void lbs_set_mac_control(struct lbs_private *priv)
1406
{
1407
	struct cmd_ds_mac_control cmd;
1408

1409
	lbs_deb_enter(LBS_DEB_CMD);
1410

1411
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1412
	cmd.action = cpu_to_le16(priv->mac_control);
1413 1414
	cmd.reserved = 0;

1415
	lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
1416

1417
	lbs_deb_leave(LBS_DEB_CMD);
1418 1419 1420 1421 1422
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
1423
 *  @param priv		A pointer to struct lbs_private structure
1424 1425 1426 1427 1428 1429 1430
 *  @param cmd_no	command number
 *  @param cmd_action	command action: GET or SET
 *  @param wait_option	wait option: wait response or not
 *  @param cmd_oid	cmd oid: treated as sub command
 *  @param pdata_buf	A pointer to informaion buffer
 *  @return 		0 or -1
 */
1431
int lbs_prepare_and_send_command(struct lbs_private *priv,
1432 1433 1434 1435 1436 1437 1438 1439 1440
			  u16 cmd_no,
			  u16 cmd_action,
			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
{
	int ret = 0;
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;

1441
	lbs_deb_enter(LBS_DEB_HOST);
1442

1443 1444
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
1445 1446 1447 1448
		ret = -1;
		goto done;
	}

1449
	if (priv->surpriseremoved) {
1450
		lbs_deb_host("PREP_CMD: card removed\n");
1451 1452 1453 1454
		ret = -1;
		goto done;
	}

1455
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1456 1457

	if (cmdnode == NULL) {
1458
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1459 1460

		/* Wake up main thread to execute next command */
1461
		wake_up_interruptible(&priv->waitq);
1462 1463 1464 1465
		ret = -1;
		goto done;
	}

1466 1467
	cmdnode->callback = NULL;
	cmdnode->callback_arg = (unsigned long)pdata_buf;
1468

1469
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1470

1471
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1472 1473

	/* Set sequence number, command and INT option */
1474 1475
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1476

1477
	cmdptr->command = cpu_to_le16(cmd_no);
1478 1479 1480
	cmdptr->result = 0;

	switch (cmd_no) {
1481
	case CMD_802_11_PS_MODE:
1482
		ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
1483 1484
		break;

1485 1486 1487
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1488
		ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
1489 1490
		break;

1491
	case CMD_802_11_MONITOR_MODE:
1492
		ret = lbs_cmd_802_11_monitor_mode(cmdptr,
1493 1494 1495
				          cmd_action, pdata_buf);
		break;

1496
	case CMD_802_11_RSSI:
1497
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1498 1499
		break;

1500 1501
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1502 1503

		cmdptr->command = cpu_to_le16(cmd_no);
1504 1505
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);
1506 1507 1508 1509 1510 1511 1512

		memmove(&cmdptr->params.afc,
			pdata_buf, sizeof(struct cmd_ds_802_11_afc));

		ret = 0;
		goto done;

1513
	case CMD_802_11D_DOMAIN_INFO:
1514
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
1515 1516 1517
						   cmd_no, cmd_action);
		break;

1518 1519
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1520 1521 1522 1523 1524 1525 1526 1527 1528
		cmdptr->size =
		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
				     S_DS_GEN);

		memmove(&cmdptr->params.tpccfg,
			pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));

		ret = 0;
		break;
1529
	case CMD_802_11_LED_GPIO_CTRL:
1530
		{
1531 1532
			struct mrvl_ie_ledgpio *gpio =
			    (struct mrvl_ie_ledgpio*)
1533 1534 1535 1536 1537 1538 1539
			    cmdptr->params.ledgpio.data;

			memmove(&cmdptr->params.ledgpio,
				pdata_buf,
				sizeof(struct cmd_ds_802_11_led_ctrl));

			cmdptr->command =
1540
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
1541 1542 1543

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
H
Holger Schurig 已提交
1544 1545 1546 1547
			    cpu_to_le16(le16_to_cpu(gpio->header.len)
				+ S_DS_GEN
				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = gpio->header.len;
1548 1549 1550 1551

			ret = 0;
			break;
		}
1552

1553
	case CMD_BT_ACCESS:
1554
		ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
1555 1556
		break;

1557
	case CMD_FWT_ACCESS:
1558
		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
1559 1560
		break;

1561 1562
	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
1563 1564
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
1565 1566
		ret = 0;
		break;
1567 1568 1569
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1570 1571 1572 1573
	case CMD_802_11_DEEP_SLEEP:
		cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
		cmdptr->size = cpu_to_le16(S_DS_GEN);
		break;
1574
	default:
1575
		lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1576 1577 1578 1579 1580 1581
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1582
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1583
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1584 1585 1586 1587 1588 1589
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1590
	lbs_queue_cmd(priv, cmdnode);
1591
	wake_up_interruptible(&priv->waitq);
1592

1593
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1594
		lbs_deb_host("PREP_CMD: wait for response\n");
1595 1596 1597 1598 1599
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1600 1601
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1602
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1603 1604
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1605 1606
		ret = -1;
	}
1607
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1608 1609

done:
1610
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1611 1612 1613 1614 1615 1616 1617
	return ret;
}

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1618
 *  @param priv		A pointer to struct lbs_private structure
1619 1620
 *  @return 		0 or -1
 */
1621
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1622 1623
{
	int ret = 0;
1624
	u32 bufsize;
1625
	u32 i;
1626
	struct cmd_ctrl_node *cmdarray;
1627

1628
	lbs_deb_enter(LBS_DEB_HOST);
1629

1630 1631 1632
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1633
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1634 1635 1636
		ret = -1;
		goto done;
	}
1637
	priv->cmd_array = cmdarray;
1638

1639 1640 1641 1642
	/* Allocate and initialize each command buffer in the command array */
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
		if (!cmdarray[i].cmdbuf) {
1643
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1644 1645 1646 1647 1648
			ret = -1;
			goto done;
		}
	}

1649 1650 1651
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1652 1653
	}
	ret = 0;
1654 1655

done:
1656
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1657 1658 1659 1660 1661 1662
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1663
 *  @param priv		A pointer to struct lbs_private structure
1664 1665
 *  @return 		0 or -1
 */
1666
int lbs_free_cmd_buffer(struct lbs_private *priv)
1667
{
1668
	struct cmd_ctrl_node *cmdarray;
1669 1670
	unsigned int i;

1671
	lbs_deb_enter(LBS_DEB_HOST);
1672 1673

	/* need to check if cmd array is allocated or not */
1674
	if (priv->cmd_array == NULL) {
1675
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1676 1677 1678
		goto done;
	}

1679
	cmdarray = priv->cmd_array;
1680 1681

	/* Release shared memory buffers */
1682 1683 1684 1685
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1686 1687 1688 1689
		}
	}

	/* Release cmd_ctrl_node */
1690 1691 1692
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1693 1694 1695
	}

done:
1696
	lbs_deb_leave(LBS_DEB_HOST);
1697 1698 1699 1700 1701 1702 1703
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1704
 *  @param priv		A pointer to struct lbs_private structure
1705 1706
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1707
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1708 1709 1710 1711
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1712 1713
	lbs_deb_enter(LBS_DEB_HOST);

1714
	if (!priv)
1715 1716
		return NULL;

1717
	spin_lock_irqsave(&priv->driver_lock, flags);
1718

1719 1720
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1721 1722
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1723
	} else {
1724
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1725 1726 1727
		tempnode = NULL;
	}

1728
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1729

1730
	lbs_deb_leave(LBS_DEB_HOST);
1731 1732 1733 1734 1735
	return tempnode;
}

/**
 *  @brief This function executes next command in command
1736
 *  pending queue. It will put firmware back to PS mode
1737 1738
 *  if applicable.
 *
1739
 *  @param priv     A pointer to struct lbs_private structure
1740 1741
 *  @return 	   0 or -1
 */
1742
int lbs_execute_next_command(struct lbs_private *priv)
1743 1744
{
	struct cmd_ctrl_node *cmdnode = NULL;
1745
	struct cmd_header *cmd;
1746 1747 1748
	unsigned long flags;
	int ret = 0;

1749 1750 1751
	/* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
	 * only caller to us is lbs_thread() and we get even when a
	 * data packet is received */
1752
	lbs_deb_enter(LBS_DEB_THREAD);
1753

1754
	spin_lock_irqsave(&priv->driver_lock, flags);
1755

1756
	if (priv->cur_cmd) {
1757
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1758
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1759 1760 1761 1762
		ret = -1;
		goto done;
	}

1763 1764
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1765
					   struct cmd_ctrl_node, list);
1766 1767
	}

1768
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1769 1770

	if (cmdnode) {
1771
		cmd = cmdnode->cmdbuf;
1772

1773
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1774 1775
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1776 1777
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1778
				       le16_to_cpu(cmd->command),
1779
				       priv->psstate);
1780 1781 1782
				ret = -1;
				goto done;
			}
1783
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1784 1785
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1786
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1787 1788 1789
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1790
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1791 1792 1793 1794 1795 1796 1797
			 * 2. PS command but not Exit_PS:
			 * Ignore it.
			 * 3. PS command Exit_PS:
			 * Set needtowakeup to TRUE if current state is SLEEP,
			 * otherwise send this command down to firmware
			 * immediately.
			 */
1798
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1799 1800
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1801 1802
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1803 1804 1805
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1806
					priv->needtowakeup = 1;
1807
				} else
1808
					lbs_ps_wakeup(priv, 0);
1809 1810 1811 1812 1813 1814 1815 1816

				ret = 0;
				goto done;
			} else {
				/*
				 * PS command. Ignore it if it is not Exit_PS.
				 * otherwise send it down immediately.
				 */
1817
				struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
1818

1819 1820
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1821 1822
				       psm->action);
				if (psm->action !=
1823
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1824 1825
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1826
					list_del(&cmdnode->list);
1827 1828 1829
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1830 1831 1832 1833 1834

					ret = 0;
					goto done;
				}

1835 1836
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1837 1838
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1839
					list_del(&cmdnode->list);
1840 1841 1842
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1843
					priv->needtowakeup = 1;
1844 1845 1846 1847 1848

					ret = 0;
					goto done;
				}

1849 1850
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1851 1852
			}
		}
1853
		list_del(&cmdnode->list);
1854
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1855
			    le16_to_cpu(cmd->command));
1856
		lbs_submit_command(priv, cmdnode);
1857 1858 1859 1860 1861
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
1862 1863 1864 1865 1866 1867
		if ((priv->psmode != LBS802_11POWERMODECAM) &&
		    (priv->psstate == PS_STATE_FULL_POWER) &&
		    ((priv->connect_status == LBS_CONNECTED) ||
		    (priv->mesh_connect_status == LBS_CONNECTED))) {
			if (priv->secinfo.WPAenabled ||
			    priv->secinfo.WPA2enabled) {
1868
				/* check for valid WPA group keys */
1869 1870
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1871
					lbs_deb_host(
1872 1873
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1874
					lbs_ps_sleep(priv, 0);
1875 1876
				}
			} else {
1877 1878 1879
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1880
				lbs_ps_sleep(priv, 0);
1881 1882 1883 1884 1885 1886
			}
		}
	}

	ret = 0;
done:
1887
	lbs_deb_leave(LBS_DEB_THREAD);
1888 1889 1890
	return ret;
}

1891
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
1892 1893 1894 1895
{
	union iwreq_data iwrq;
	u8 buf[50];

1896
	lbs_deb_enter(LBS_DEB_WEXT);
1897 1898 1899 1900 1901 1902 1903 1904 1905

	memset(&iwrq, 0, sizeof(union iwreq_data));
	memset(buf, 0, sizeof(buf));

	snprintf(buf, sizeof(buf) - 1, "%s", str);

	iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;

	/* Send Event to upper layer */
1906 1907 1908
	lbs_deb_wext("event indication string %s\n", (char *)buf);
	lbs_deb_wext("event indication length %d\n", iwrq.data.length);
	lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
1909

1910
	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
1911

1912
	lbs_deb_leave(LBS_DEB_WEXT);
1913 1914
}

1915
static void lbs_send_confirmsleep(struct lbs_private *priv)
1916 1917
{
	unsigned long flags;
1918
	int ret;
1919

1920
	lbs_deb_enter(LBS_DEB_HOST);
1921 1922
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1923

1924 1925
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1926
	if (ret) {
1927
		lbs_pr_alert("confirm_sleep failed\n");
1928
		goto out;
1929
	}
1930 1931 1932

	spin_lock_irqsave(&priv->driver_lock, flags);

1933 1934 1935
	/* We don't get a response on the sleep-confirmation */
	priv->dnld_sent = DNLD_RES_RECEIVED;

1936 1937 1938 1939 1940 1941 1942
	/* If nothing to do, go back to sleep (?) */
	if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
		priv->psstate = PS_STATE_SLEEP;

	spin_unlock_irqrestore(&priv->driver_lock, flags);

out:
1943
	lbs_deb_leave(LBS_DEB_HOST);
1944 1945
}

1946
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1947
{
1948
	lbs_deb_enter(LBS_DEB_HOST);
1949 1950 1951 1952 1953 1954

	/*
	 * PS is currently supported only in Infrastructure mode
	 * Remove this check if it is to be supported in IBSS mode also
	 */

1955
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1956
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1957

1958
	lbs_deb_leave(LBS_DEB_HOST);
1959 1960 1961
}

/**
1962
 *  @brief This function sends Exit_PS command to firmware.
1963
 *
1964
 *  @param priv    	A pointer to struct lbs_private structure
1965 1966 1967
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
1968
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
1969
{
1970
	__le32 Localpsmode;
1971

1972
	lbs_deb_enter(LBS_DEB_HOST);
1973

1974
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1975

1976
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1977
			      CMD_SUBCMD_EXIT_PS,
1978 1979
			      wait_option, 0, &Localpsmode);

1980
	lbs_deb_leave(LBS_DEB_HOST);
1981 1982 1983 1984 1985 1986
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
1987
 *  @param priv    	A pointer to struct lbs_private structure
1988 1989 1990
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
1991
void lbs_ps_confirm_sleep(struct lbs_private *priv)
1992 1993
{
	unsigned long flags =0;
1994
	int allowed = 1;
1995

1996
	lbs_deb_enter(LBS_DEB_HOST);
1997

1998
	spin_lock_irqsave(&priv->driver_lock, flags);
1999
	if (priv->dnld_sent) {
2000
		allowed = 0;
2001
		lbs_deb_host("dnld_sent was set\n");
2002 2003
	}

2004
	/* In-progress command? */
2005
	if (priv->cur_cmd) {
2006
		allowed = 0;
2007
		lbs_deb_host("cur_cmd was set\n");
2008
	}
2009 2010 2011

	/* Pending events or command responses? */
	if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
2012
		allowed = 0;
2013
		lbs_deb_host("pending events or command responses\n");
2014
	}
2015
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2016 2017

	if (allowed) {
2018
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
2019
		lbs_send_confirmsleep(priv);
2020
	} else {
2021
		lbs_deb_host("sleep confirm has been delayed\n");
2022 2023
	}

2024
	lbs_deb_leave(LBS_DEB_HOST);
2025
}
2026 2027


2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
/**
 * @brief Configures the transmission power control functionality.
 *
 * @param priv		A pointer to struct lbs_private structure
 * @param enable	Transmission power control enable
 * @param p0		Power level when link quality is good (dBm).
 * @param p1		Power level when link quality is fair (dBm).
 * @param p2		Power level when link quality is poor (dBm).
 * @param usesnr	Use Signal to Noise Ratio in TPC
 *
 * @return 0 on success
 */
int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
		int8_t p2, int usesnr)
{
	struct cmd_ds_802_11_tpc_cfg cmd;
	int ret;

	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);
	cmd.enable = !!enable;
2050
	cmd.usesnr = !!usesnr;
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091
	cmd.P0 = p0;
	cmd.P1 = p1;
	cmd.P2 = p2;

	ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);

	return ret;
}

/**
 * @brief Configures the power adaptation settings.
 *
 * @param priv		A pointer to struct lbs_private structure
 * @param enable	Power adaptation enable
 * @param p0		Power level for 1, 2, 5.5 and 11 Mbps (dBm).
 * @param p1		Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
 * @param p2		Power level for 48 and 54 Mbps (dBm).
 *
 * @return 0 on Success
 */

int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
		int8_t p1, int8_t p2)
{
	struct cmd_ds_802_11_pa_cfg cmd;
	int ret;

	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);
	cmd.enable = !!enable;
	cmd.P0 = p0;
	cmd.P1 = p1;
	cmd.P2 = p2;

	ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);

	return ret;
}


2092 2093 2094 2095
static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
	uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
	int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
	unsigned long callback_arg)
2096 2097 2098 2099 2100
{
	struct cmd_ctrl_node *cmdnode;

	lbs_deb_enter(LBS_DEB_HOST);

2101
	if (priv->surpriseremoved) {
2102
		lbs_deb_host("PREP_CMD: card removed\n");
2103
		cmdnode = ERR_PTR(-ENOENT);
2104 2105 2106 2107 2108 2109 2110 2111 2112
		goto done;
	}

	cmdnode = lbs_get_cmd_ctrl_node(priv);
	if (cmdnode == NULL) {
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");

		/* Wake up main thread to execute next command */
		wake_up_interruptible(&priv->waitq);
2113
		cmdnode = ERR_PTR(-ENOBUFS);
2114 2115 2116
		goto done;
	}

2117
	cmdnode->callback = callback;
2118
	cmdnode->callback_arg = callback_arg;
2119

2120
	/* Copy the incoming command to the buffer */
2121
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
2122

2123
	/* Set sequence number, clean result, move to buffer */
2124
	priv->seqnum++;
2125 2126 2127 2128
	cmdnode->cmdbuf->command = cpu_to_le16(command);
	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
	cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
	cmdnode->cmdbuf->result  = 0;
2129 2130 2131 2132

	lbs_deb_host("PREP_CMD: command 0x%04x\n", command);

	cmdnode->cmdwaitqwoken = 0;
2133
	lbs_queue_cmd(priv, cmdnode);
2134 2135
	wake_up_interruptible(&priv->waitq);

2136 2137 2138 2139 2140
 done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
	return cmdnode;
}

2141 2142 2143 2144 2145 2146 2147 2148 2149
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
	struct cmd_header *in_cmd, int in_cmd_size)
{
	lbs_deb_enter(LBS_DEB_CMD);
	__lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
		lbs_cmd_async_callback, 0);
	lbs_deb_leave(LBS_DEB_CMD);
}

2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
int __lbs_cmd(struct lbs_private *priv, uint16_t command,
	      struct cmd_header *in_cmd, int in_cmd_size,
	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
	      unsigned long callback_arg)
{
	struct cmd_ctrl_node *cmdnode;
	unsigned long flags;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

	cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
				  callback, callback_arg);
	if (IS_ERR(cmdnode)) {
		ret = PTR_ERR(cmdnode);
		goto done;
	}

2168 2169 2170
	might_sleep();
	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);

2171
	spin_lock_irqsave(&priv->driver_lock, flags);
2172 2173 2174 2175
	ret = cmdnode->result;
	if (ret)
		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
			    command, ret);
2176

2177
	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
2178
	spin_unlock_irqrestore(&priv->driver_lock, flags);
2179 2180 2181 2182 2183

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
2184
EXPORT_SYMBOL_GPL(__lbs_cmd);
2185 2186