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

6
#include <linux/kfifo.h>
7
#include <linux/sched.h>
8
#include <linux/slab.h>
9

10
#include "decl.h"
K
Kiran Divekar 已提交
11
#include "cfg.h"
12
#include "cmd.h"
13

14

15
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
16

17 18 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
/**
 *  @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;
}


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

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
/**
 *  @brief This function checks if the command is allowed.
 *
 *  @param priv         A pointer to lbs_private structure
 *  @return             allowed or not allowed.
 */

static int lbs_is_cmd_allowed(struct lbs_private *priv)
{
	int ret = 1;

	lbs_deb_enter(LBS_DEB_CMD);

	if (!priv->is_auto_deep_sleep_enabled) {
		if (priv->is_deep_sleep) {
			lbs_deb_cmd("command not allowed in deep sleep\n");
			ret = 0;
		}
	}

	lbs_deb_leave(LBS_DEB_CMD);
	return ret;
}

100 101 102 103 104 105 106 107
/**
 *  @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)
108
{
109 110 111
	struct cmd_ds_get_hw_spec cmd;
	int ret = -1;
	u32 i;
112

113
	lbs_deb_enter(LBS_DEB_CMD);
114

115 116 117
	memset(&cmd, 0, sizeof(cmd));
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
118
	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
119 120 121 122 123
	if (ret)
		goto out;

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

124 125 126 127 128 129 130 131 132 133
	/* 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 已提交
134 135
	lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
		cmd.permanentaddr,
136 137 138 139 140
		priv->fwrelease >> 24 & 0xff,
		priv->fwrelease >> 16 & 0xff,
		priv->fwrelease >>  8 & 0xff,
		priv->fwrelease       & 0xff,
		priv->fwcapinfo);
141 142 143 144 145 146
	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
		    cmd.hwifversion, cmd.version);

	/* 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.
147 148 149
	 *
	 * Firmware version 4.0.102 used in CF8381 has region code shifted.  We
	 * need to check for this problem and handle it properly.
150
	 */
151 152 153 154
	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;
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

	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);
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);

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

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
			struct cmd_header *resp)
{
	lbs_deb_enter(LBS_DEB_CMD);
	if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
		priv->is_host_sleep_configured = 0;
		if (priv->psstate == PS_STATE_FULL_POWER) {
			priv->is_host_sleep_activated = 0;
			wake_up_interruptible(&priv->host_sleep_q);
		}
	} else {
		priv->is_host_sleep_configured = 1;
	}
	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

197 198
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
		struct wol_config *p_wol_config)
199 200 201 202
{
	struct cmd_ds_host_sleep cmd_config;
	int ret;

203
	cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
204
	cmd_config.criteria = cpu_to_le32(criteria);
205 206
	cmd_config.gpio = priv->wol_gpio;
	cmd_config.gap = priv->wol_gap;
207

208 209 210 211 212 213
	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;

214 215 216
	ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
			le16_to_cpu(cmd_config.hdr.size),
			lbs_ret_host_sleep_cfg, 0);
217
	if (!ret) {
218
		if (p_wol_config)
219 220 221
			memcpy((uint8_t *) p_wol_config,
					(uint8_t *)&cmd_config.wol_conf,
					sizeof(struct wol_config));
222
	} else {
223 224
		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
	}
225

226 227 228 229
	return ret;
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);

230
static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
231 232 233 234
				   u16 cmd_action)
{
	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;

235
	lbs_deb_enter(LBS_DEB_CMD);
236

237
	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
238
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
239
				sizeof(struct cmd_header));
240 241
	psm->action = cpu_to_le16(cmd_action);
	psm->multipledtim = 0;
242
	switch (cmd_action) {
243
	case CMD_SUBCMD_ENTER_PS:
244
		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
245

246
		psm->locallisteninterval = 0;
247
		psm->nullpktinterval = 0;
248
		psm->multipledtim =
249
		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
250 251
		break;

252
	case CMD_SUBCMD_EXIT_PS:
253
		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
254 255
		break;

256
	case CMD_SUBCMD_SLEEP_CONFIRMED:
257
		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
258 259 260 261 262 263
		break;

	default:
		break;
	}

264
	lbs_deb_leave(LBS_DEB_CMD);
265 266 267
	return 0;
}

268 269
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
				struct sleep_params *sp)
270
{
271 272
	struct cmd_ds_802_11_sleep_params cmd;
	int ret;
273

274
	lbs_deb_enter(LBS_DEB_CMD);
275

276
	if (cmd_action == CMD_ACT_GET) {
277 278 279 280 281 282 283 284
		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);
285
	}
286 287
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(cmd_action);
288

289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
	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);
307 308 309
	return 0;
}

310 311 312 313 314 315 316 317 318 319 320 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
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;
}

364 365 366 367 368 369 370 371 372 373
/**
 *  @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)
374
{
375 376
	struct cmd_ds_802_11_snmp_mib cmd;
	int ret;
377

378
	lbs_deb_enter(LBS_DEB_CMD);
379

380 381 382 383
	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);
384

385 386 387
	switch (oid) {
	case SNMP_MIB_OID_BSS_TYPE:
		cmd.bufsize = cpu_to_le16(sizeof(u8));
388
		cmd.value[0] = val;
389 390 391 392 393 394 395 396
		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);
397
		break;
398 399 400 401
	default:
		lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
		ret = -EINVAL;
		goto out;
402 403
	}

404 405
	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);
406

407
	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
408

409 410 411 412
out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}
413

414 415 416 417 418 419 420 421 422 423 424 425 426
/**
 *  @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;
427

428
	lbs_deb_enter(LBS_DEB_CMD);
429

430 431 432 433
	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);
434

435 436 437
	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
	if (ret)
		goto out;
438

439 440
	switch (le16_to_cpu(cmd.bufsize)) {
	case sizeof(u8):
441
		*out_val = cmd.value[0];
442 443 444
		break;
	case sizeof(u16):
		*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
445 446
		break;
	default:
447 448
		lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
		            oid, le16_to_cpu(cmd.bufsize));
449 450 451
		break;
	}

452 453 454
out:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
455 456
}

457 458 459 460 461 462 463 464 465 466 467 468
/**
 *  @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)
469
{
470 471
	struct cmd_ds_802_11_rf_tx_power cmd;
	int ret;
472

473
	lbs_deb_enter(LBS_DEB_CMD);
474

475 476 477 478 479 480 481 482
	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)
483
			*minlevel = cmd.minlevel;
484
		if (maxlevel)
485
			*maxlevel = cmd.maxlevel;
486
	}
487

488 489 490
	lbs_deb_leave(LBS_DEB_CMD);
	return ret;
}
491

492 493 494 495 496 497 498 499 500 501 502 503
/**
 *  @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;
504

505
	lbs_deb_enter(LBS_DEB_CMD);
506

507 508 509 510
	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);
511

512 513 514
	lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);

	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
515 516

	lbs_deb_leave(LBS_DEB_CMD);
517
	return ret;
518 519
}

520
static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
521 522 523 524 525 526 527
				      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) +
528
			     sizeof(struct cmd_header));
529 530 531 532 533 534 535 536 537 538

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

	return 0;
}

539 540 541 542 543 544 545
/**
 *  @brief Get the radio channel
 *
 *  @param priv    	A pointer to struct lbs_private structure
 *
 *  @return 	   	The channel on success, error on failure
 */
546
static int lbs_get_channel(struct lbs_private *priv)
547
{
548 549
	struct cmd_ds_802_11_rf_channel cmd;
	int ret = 0;
550

551
	lbs_deb_enter(LBS_DEB_CMD);
552

553
	memset(&cmd, 0, sizeof(cmd));
554 555
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
556

557
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
558 559
	if (ret)
		goto out;
560

561 562
	ret = le16_to_cpu(cmd.channel);
	lbs_deb_cmd("current radio channel is %d\n", ret);
563 564 565 566 567 568

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

569 570 571 572 573 574 575 576 577
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) {
578
		priv->channel = ret;
579 580 581 582 583 584
		ret = 0;
	}
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
	return ret;
}

585 586 587 588 589 590 591 592 593 594 595
/**
 *  @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;
596
#ifdef DEBUG
597
	u8 old_channel = priv->channel;
598
#endif
599 600 601 602
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CMD);

603
	memset(&cmd, 0, sizeof(cmd));
604 605 606 607
	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);

608
	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
609 610 611
	if (ret)
		goto out;

612
	priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
613
	lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
614
		priv->channel);
615 616 617 618

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

621
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
622 623
			       u8 cmd_action, void *pdata_buf)
{
624
	struct lbs_offset_value *offval;
625

626
	lbs_deb_enter(LBS_DEB_CMD);
627

628
	offval = (struct lbs_offset_value *)pdata_buf;
629

H
Holger Schurig 已提交
630
	switch (le16_to_cpu(cmdptr->command)) {
631
	case CMD_MAC_REG_ACCESS:
632 633 634 635
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
636
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
637
					+ sizeof(struct cmd_header));
638 639 640 641 642 643 644 645 646 647 648
			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;
		}

649
	case CMD_BBP_REG_ACCESS:
650 651 652 653 654 655
		{
			struct cmd_ds_bbp_reg_access *bbpreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_bbp_reg_access)
656
					     + sizeof(struct cmd_header));
657 658 659 660 661 662 663 664 665 666 667
			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;
		}

668
	case CMD_RF_REG_ACCESS:
669 670 671 672 673 674
		{
			struct cmd_ds_rf_reg_access *rfreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_rf_reg_access) +
675
					     sizeof(struct cmd_header));
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
			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;
	}

691
	lbs_deb_leave(LBS_DEB_CMD);
692 693 694
	return 0;
}

695 696
static void lbs_queue_cmd(struct lbs_private *priv,
			  struct cmd_ctrl_node *cmdnode)
697 698
{
	unsigned long flags;
699
	int addtail = 1;
700

701
	lbs_deb_enter(LBS_DEB_HOST);
702

703 704
	if (!cmdnode) {
		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
705 706
		goto done;
	}
707 708 709 710
	if (!cmdnode->cmdbuf->size) {
		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
		goto done;
	}
711
	cmdnode->result = 0;
712 713

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

717
		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
718
			if (priv->psstate != PS_STATE_FULL_POWER)
719 720 721 722
				addtail = 0;
		}
	}

723 724 725 726
	if (le16_to_cpu(cmdnode->cmdbuf->command) ==
			CMD_802_11_WAKEUP_CONFIRM)
		addtail = 0;

727
	spin_lock_irqsave(&priv->driver_lock, flags);
728

729
	if (addtail)
730
		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
731
	else
732
		list_add(&cmdnode->list, &priv->cmdpendingq);
733

734
	spin_unlock_irqrestore(&priv->driver_lock, flags);
735

736
	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
737
		     le16_to_cpu(cmdnode->cmdbuf->command));
738 739

done:
740
	lbs_deb_leave(LBS_DEB_HOST);
741 742
}

743 744
static void lbs_submit_command(struct lbs_private *priv,
			       struct cmd_ctrl_node *cmdnode)
745 746
{
	unsigned long flags;
747
	struct cmd_header *cmd;
748 749
	uint16_t cmdsize;
	uint16_t command;
750
	int timeo = 3 * HZ;
751
	int ret;
752

753
	lbs_deb_enter(LBS_DEB_HOST);
754

755
	cmd = cmdnode->cmdbuf;
756

757 758 759 760
	spin_lock_irqsave(&priv->driver_lock, flags);
	priv->cur_cmd = cmdnode;
	priv->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&priv->driver_lock, flags);
761

762 763
	cmdsize = le16_to_cpu(cmd->size);
	command = le16_to_cpu(cmd->command);
764

765
	/* These commands take longer */
766
	if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
767
		timeo = 5 * HZ;
768

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

773
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
774

775 776
	if (ret) {
		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
777 778
		/* Let the timer kick in and retry, and potentially reset
		   the whole thing if the condition persists */
779
		timeo = HZ/4;
780
	}
781

782 783 784 785 786 787 788 789 790 791 792
	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);
	}
793

794
	lbs_deb_leave(LBS_DEB_HOST);
795 796 797 798
}

/**
 *  This function inserts command node to cmdfreeq
799
 *  after cleans it. Requires priv->driver_lock held.
800
 */
801
static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
802
					 struct cmd_ctrl_node *cmdnode)
803
{
804 805 806 807 808 809 810
	lbs_deb_enter(LBS_DEB_HOST);

	if (!cmdnode)
		goto out;

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

812
	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
813

814 815 816
	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
 out:
	lbs_deb_leave(LBS_DEB_HOST);
817 818
}

819 820
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
	struct cmd_ctrl_node *ptempcmd)
821 822 823
{
	unsigned long flags;

824
	spin_lock_irqsave(&priv->driver_lock, flags);
825
	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
826
	spin_unlock_irqrestore(&priv->driver_lock, flags);
827 828
}

829 830 831 832 833
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;
834

835
	cmd->result = result;
836 837 838
	cmd->cmdwaitqwoken = 1;
	wake_up_interruptible(&cmd->cmdwait_q);

839
	if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
840
		__lbs_cleanup_and_insert_cmd(priv, cmd);
841 842 843
	priv->cur_cmd = NULL;
}

844
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
845
{
846
	struct cmd_ds_802_11_radio_control cmd;
847
	int ret = -EINVAL;
848

849
	lbs_deb_enter(LBS_DEB_CMD);
850

851 852 853
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);

854 855 856 857 858 859 860 861 862 863 864 865
	/* Only v8 and below support setting the preamble */
	if (priv->fwrelease < 0x09000000) {
		switch (preamble) {
		case RADIO_PREAMBLE_SHORT:
		case RADIO_PREAMBLE_AUTO:
		case RADIO_PREAMBLE_LONG:
			cmd.control = cpu_to_le16(preamble);
			break;
		default:
			goto out;
		}
	}
866

867 868 869 870 871
	if (radio_on)
		cmd.control |= cpu_to_le16(0x1);
	else {
		cmd.control &= cpu_to_le16(~0x1);
		priv->txpower_cur = 0;
872
	}
873

874 875
	lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
		    radio_on ? "ON" : "OFF", preamble);
876

877
	priv->radio_on = radio_on;
878 879

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

881
out:
882
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
883 884 885
	return ret;
}

886
void lbs_set_mac_control(struct lbs_private *priv)
887
{
888
	struct cmd_ds_mac_control cmd;
889

890
	lbs_deb_enter(LBS_DEB_CMD);
891

892
	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
893
	cmd.action = cpu_to_le16(priv->mac_control);
894 895
	cmd.reserved = 0;

896
	lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
897

898
	lbs_deb_leave(LBS_DEB_CMD);
899 900
}

901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
/**
 *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
 *  @param priv       pointer to struct lbs_private
 *  @param cmd        pointer to cmd buffer
 *  @param cmdno      cmd ID
 *  @param cmdOption  cmd action
 *  @return           0
*/
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
				 struct cmd_ds_command *cmd,
				 u16 cmdoption)
{
	struct cmd_ds_802_11d_domain_info *pdomaininfo =
	    &cmd->params.domaininfo;
	struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
	u8 nr_triplet = priv->domain_reg.no_triplet;

	lbs_deb_enter(LBS_DEB_11D);

	lbs_deb_11d("nr_triplet=%x\n", nr_triplet);

	pdomaininfo->action = cpu_to_le16(cmdoption);
	if (cmdoption == CMD_ACT_GET) {
		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					sizeof(struct cmd_header));
		lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
			le16_to_cpu(cmd->size));
		goto done;
	}

	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
	memcpy(domain->countrycode, priv->domain_reg.country_code,
	       sizeof(domain->countrycode));

	domain->header.len = cpu_to_le16(nr_triplet
				* sizeof(struct ieee80211_country_ie_triplet)
				+ sizeof(domain->countrycode));

	if (nr_triplet) {
		memcpy(domain->triplet, priv->domain_reg.triplet,
				nr_triplet *
				sizeof(struct ieee80211_country_ie_triplet));

		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					     le16_to_cpu(domain->header.len) +
					     sizeof(struct mrvl_ie_header) +
					     sizeof(struct cmd_header));
	} else {
		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					sizeof(struct cmd_header));
	}

	lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
			le16_to_cpu(cmd->size));

done:
	lbs_deb_enter(LBS_DEB_11D);
	return 0;
}

961 962 963
/**
 *  @brief This function prepare the command before send to firmware.
 *
964
 *  @param priv		A pointer to struct lbs_private structure
965 966 967 968 969 970 971
 *  @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
 */
972
int lbs_prepare_and_send_command(struct lbs_private *priv,
973 974 975 976 977 978 979 980 981
			  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;

982
	lbs_deb_enter(LBS_DEB_HOST);
983

984 985
	if (!priv) {
		lbs_deb_host("PREP_CMD: priv is NULL\n");
986 987 988 989
		ret = -1;
		goto done;
	}

990
	if (priv->surpriseremoved) {
991
		lbs_deb_host("PREP_CMD: card removed\n");
992 993 994 995
		ret = -1;
		goto done;
	}

996 997 998 999 1000
	if (!lbs_is_cmd_allowed(priv)) {
		ret = -EBUSY;
		goto done;
	}

1001
	cmdnode = lbs_get_cmd_ctrl_node(priv);
1002 1003

	if (cmdnode == NULL) {
1004
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1005 1006

		/* Wake up main thread to execute next command */
1007
		wake_up_interruptible(&priv->waitq);
1008 1009 1010 1011
		ret = -1;
		goto done;
	}

1012 1013
	cmdnode->callback = NULL;
	cmdnode->callback_arg = (unsigned long)pdata_buf;
1014

1015
	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
1016

1017
	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
1018 1019

	/* Set sequence number, command and INT option */
1020 1021
	priv->seqnum++;
	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
1022

1023
	cmdptr->command = cpu_to_le16(cmd_no);
1024 1025 1026
	cmdptr->result = 0;

	switch (cmd_no) {
1027
	case CMD_802_11_PS_MODE:
1028
		ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
1029 1030
		break;

1031 1032 1033
	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
1034
		ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
1035 1036
		break;

1037
	case CMD_802_11_MONITOR_MODE:
1038
		ret = lbs_cmd_802_11_monitor_mode(cmdptr,
1039 1040 1041
				          cmd_action, pdata_buf);
		break;

1042
	case CMD_802_11_RSSI:
1043
		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
1044 1045
		break;

1046 1047
	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:
1048 1049

		cmdptr->command = cpu_to_le16(cmd_no);
1050
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
1051
					   sizeof(struct cmd_header));
1052 1053 1054 1055 1056 1057 1058

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

		ret = 0;
		goto done;

1059 1060 1061 1062 1063
	case CMD_802_11D_DOMAIN_INFO:
		cmdptr->command = cpu_to_le16(cmd_no);
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
		break;

1064 1065
	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1066 1067
		cmdptr->size =
		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
1068
				     sizeof(struct cmd_header));
1069 1070 1071 1072 1073 1074

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

		ret = 0;
		break;
1075

H
Holger Schurig 已提交
1076 1077
#ifdef CONFIG_LIBERTAS_MESH

1078
	case CMD_BT_ACCESS:
1079
		ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
1080 1081
		break;

1082
	case CMD_FWT_ACCESS:
1083
		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
1084 1085
		break;

H
Holger Schurig 已提交
1086 1087
#endif

1088 1089 1090
	case CMD_802_11_BEACON_CTRL:
		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
		break;
1091 1092
	case CMD_802_11_DEEP_SLEEP:
		cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
1093
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
1094
		break;
1095
	default:
1096
		lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1097 1098 1099 1100 1101 1102
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
1103
		lbs_deb_host("PREP_CMD: command preparation failed\n");
1104
		lbs_cleanup_and_insert_cmd(priv, cmdnode);
1105 1106 1107 1108 1109 1110
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

1111
	lbs_queue_cmd(priv, cmdnode);
1112
	wake_up_interruptible(&priv->waitq);
1113

1114
	if (wait_option & CMD_OPTION_WAITFORRSP) {
1115
		lbs_deb_host("PREP_CMD: wait for response\n");
1116 1117 1118 1119 1120
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

1121 1122
	spin_lock_irqsave(&priv->driver_lock, flags);
	if (priv->cur_cmd_retcode) {
1123
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
1124 1125
		       priv->cur_cmd_retcode);
		priv->cur_cmd_retcode = 0;
1126 1127
		ret = -1;
	}
1128
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1129 1130

done:
1131
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1132 1133 1134 1135 1136 1137 1138
	return ret;
}

/**
 *  @brief This function allocates the command buffer and link
 *  it to command free queue.
 *
1139
 *  @param priv		A pointer to struct lbs_private structure
1140 1141
 *  @return 		0 or -1
 */
1142
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1143 1144
{
	int ret = 0;
1145
	u32 bufsize;
1146
	u32 i;
1147
	struct cmd_ctrl_node *cmdarray;
1148

1149
	lbs_deb_enter(LBS_DEB_HOST);
1150

1151 1152 1153
	/* Allocate and initialize the command array */
	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1154
		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1155 1156 1157
		ret = -1;
		goto done;
	}
1158
	priv->cmd_array = cmdarray;
1159

1160 1161 1162 1163
	/* 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) {
1164
			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1165 1166 1167 1168 1169
			ret = -1;
			goto done;
		}
	}

1170 1171 1172
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		init_waitqueue_head(&cmdarray[i].cmdwait_q);
		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1173 1174
	}
	ret = 0;
1175 1176

done:
1177
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
1178 1179 1180 1181 1182 1183
	return ret;
}

/**
 *  @brief This function frees the command buffer.
 *
1184
 *  @param priv		A pointer to struct lbs_private structure
1185 1186
 *  @return 		0 or -1
 */
1187
int lbs_free_cmd_buffer(struct lbs_private *priv)
1188
{
1189
	struct cmd_ctrl_node *cmdarray;
1190 1191
	unsigned int i;

1192
	lbs_deb_enter(LBS_DEB_HOST);
1193 1194

	/* need to check if cmd array is allocated or not */
1195
	if (priv->cmd_array == NULL) {
1196
		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1197 1198 1199
		goto done;
	}

1200
	cmdarray = priv->cmd_array;
1201 1202

	/* Release shared memory buffers */
1203 1204 1205 1206
	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
		if (cmdarray[i].cmdbuf) {
			kfree(cmdarray[i].cmdbuf);
			cmdarray[i].cmdbuf = NULL;
1207 1208 1209 1210
		}
	}

	/* Release cmd_ctrl_node */
1211 1212 1213
	if (priv->cmd_array) {
		kfree(priv->cmd_array);
		priv->cmd_array = NULL;
1214 1215 1216
	}

done:
1217
	lbs_deb_leave(LBS_DEB_HOST);
1218 1219 1220 1221 1222 1223 1224
	return 0;
}

/**
 *  @brief This function gets a free command node if available in
 *  command free queue.
 *
1225
 *  @param priv		A pointer to struct lbs_private structure
1226 1227
 *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
 */
1228
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
1229 1230 1231 1232
{
	struct cmd_ctrl_node *tempnode;
	unsigned long flags;

1233 1234
	lbs_deb_enter(LBS_DEB_HOST);

1235
	if (!priv)
1236 1237
		return NULL;

1238
	spin_lock_irqsave(&priv->driver_lock, flags);
1239

1240 1241
	if (!list_empty(&priv->cmdfreeq)) {
		tempnode = list_first_entry(&priv->cmdfreeq,
1242 1243
					    struct cmd_ctrl_node, list);
		list_del(&tempnode->list);
1244
	} else {
1245
		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1246 1247 1248
		tempnode = NULL;
	}

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

1251
	lbs_deb_leave(LBS_DEB_HOST);
1252 1253 1254 1255 1256
	return tempnode;
}

/**
 *  @brief This function executes next command in command
1257
 *  pending queue. It will put firmware back to PS mode
1258 1259
 *  if applicable.
 *
1260
 *  @param priv     A pointer to struct lbs_private structure
1261 1262
 *  @return 	   0 or -1
 */
1263
int lbs_execute_next_command(struct lbs_private *priv)
1264 1265
{
	struct cmd_ctrl_node *cmdnode = NULL;
1266
	struct cmd_header *cmd;
1267 1268 1269
	unsigned long flags;
	int ret = 0;

1270 1271 1272
	/* 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 */
1273
	lbs_deb_enter(LBS_DEB_THREAD);
1274

1275
	spin_lock_irqsave(&priv->driver_lock, flags);
1276

1277
	if (priv->cur_cmd) {
1278
		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
1279
		spin_unlock_irqrestore(&priv->driver_lock, flags);
1280 1281 1282 1283
		ret = -1;
		goto done;
	}

1284 1285
	if (!list_empty(&priv->cmdpendingq)) {
		cmdnode = list_first_entry(&priv->cmdpendingq,
1286
					   struct cmd_ctrl_node, list);
1287 1288
	}

1289
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1290 1291

	if (cmdnode) {
1292
		cmd = cmdnode->cmdbuf;
1293

1294
		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1295 1296
			if ((priv->psstate == PS_STATE_SLEEP) ||
			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1297 1298
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1299
				       le16_to_cpu(cmd->command),
1300
				       priv->psstate);
1301 1302 1303
				ret = -1;
				goto done;
			}
1304
			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1305 1306
				     "0x%04x in psstate %d\n",
				     le16_to_cpu(cmd->command), priv->psstate);
1307
		} else if (priv->psstate != PS_STATE_FULL_POWER) {
1308 1309 1310
			/*
			 * 1. Non-PS command:
			 * Queue it. set needtowakeup to TRUE if current state
1311
			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
1312 1313 1314 1315 1316 1317 1318
			 * 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.
			 */
1319
			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1320 1321
				/*  Prepare to send Exit PS,
				 *  this non PS command will be sent later */
1322 1323
				if ((priv->psstate == PS_STATE_SLEEP)
				    || (priv->psstate == PS_STATE_PRE_SLEEP)
1324 1325 1326
				    ) {
					/* w/ new scheme, it will not reach here.
					   since it is blocked in main_thread. */
1327
					priv->needtowakeup = 1;
1328
				} else
1329
					lbs_ps_wakeup(priv, 0);
1330 1331 1332 1333 1334 1335 1336 1337

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

1340 1341
				lbs_deb_host(
				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1342 1343
				       psm->action);
				if (psm->action !=
1344
				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
1345 1346
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1347
					list_del(&cmdnode->list);
1348 1349 1350
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1351 1352 1353 1354 1355

					ret = 0;
					goto done;
				}

1356 1357
				if ((priv->psstate == PS_STATE_SLEEP) ||
				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
1358 1359
					lbs_deb_host(
					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1360
					list_del(&cmdnode->list);
1361 1362 1363
					spin_lock_irqsave(&priv->driver_lock, flags);
					lbs_complete_command(priv, cmdnode, 0);
					spin_unlock_irqrestore(&priv->driver_lock, flags);
1364
					priv->needtowakeup = 1;
1365 1366 1367 1368 1369

					ret = 0;
					goto done;
				}

1370 1371
				lbs_deb_host(
				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
1372 1373
			}
		}
1374
		list_del(&cmdnode->list);
1375
		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1376
			    le16_to_cpu(cmd->command));
1377
		lbs_submit_command(priv, cmdnode);
1378 1379 1380 1381 1382
	} else {
		/*
		 * check if in power save mode, if yes, put the device back
		 * to PS mode
		 */
K
Kiran Divekar 已提交
1383 1384 1385 1386 1387 1388 1389 1390 1391
#ifdef TODO
		/*
		 * This was the old code for libertas+wext. Someone that
		 * understands this beast should re-code it in a sane way.
		 *
		 * I actually don't understand why this is related to WPA
		 * and to connection status, shouldn't powering should be
		 * independ of such things?
		 */
1392 1393 1394
		if ((priv->psmode != LBS802_11POWERMODECAM) &&
		    (priv->psstate == PS_STATE_FULL_POWER) &&
		    ((priv->connect_status == LBS_CONNECTED) ||
1395
		    lbs_mesh_connected(priv))) {
1396 1397
			if (priv->secinfo.WPAenabled ||
			    priv->secinfo.WPA2enabled) {
1398
				/* check for valid WPA group keys */
1399 1400
				if (priv->wpa_mcast_key.len ||
				    priv->wpa_unicast_key.len) {
1401
					lbs_deb_host(
1402 1403
					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
					       " go back to PS_SLEEP");
1404
					lbs_ps_sleep(priv, 0);
1405 1406
				}
			} else {
1407 1408 1409
				lbs_deb_host(
				       "EXEC_NEXT_CMD: cmdpendingq empty, "
				       "go back to PS_SLEEP");
1410
				lbs_ps_sleep(priv, 0);
1411 1412
			}
		}
K
Kiran Divekar 已提交
1413
#endif
1414 1415 1416 1417
	}

	ret = 0;
done:
1418
	lbs_deb_leave(LBS_DEB_THREAD);
1419 1420 1421
	return ret;
}

1422
static void lbs_send_confirmsleep(struct lbs_private *priv)
1423 1424
{
	unsigned long flags;
1425
	int ret;
1426

1427
	lbs_deb_enter(LBS_DEB_HOST);
1428 1429
	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1430

1431 1432
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));
1433
	if (ret) {
1434
		lbs_pr_alert("confirm_sleep failed\n");
1435
		goto out;
1436
	}
1437 1438 1439

	spin_lock_irqsave(&priv->driver_lock, flags);

1440 1441 1442
	/* We don't get a response on the sleep-confirmation */
	priv->dnld_sent = DNLD_RES_RECEIVED;

1443 1444 1445 1446 1447
	if (priv->is_host_sleep_configured) {
		priv->is_host_sleep_activated = 1;
		wake_up_interruptible(&priv->host_sleep_q);
	}

1448
	/* If nothing to do, go back to sleep (?) */
S
Stefani Seibold 已提交
1449
	if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
1450 1451 1452 1453 1454
		priv->psstate = PS_STATE_SLEEP;

	spin_unlock_irqrestore(&priv->driver_lock, flags);

out:
1455
	lbs_deb_leave(LBS_DEB_HOST);
1456 1457
}

1458
void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
1459
{
1460
	lbs_deb_enter(LBS_DEB_HOST);
1461 1462 1463 1464 1465 1466

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

1467
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1468
			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
1469

1470
	lbs_deb_leave(LBS_DEB_HOST);
1471 1472 1473
}

/**
1474
 *  @brief This function sends Exit_PS command to firmware.
1475
 *
1476
 *  @param priv    	A pointer to struct lbs_private structure
1477 1478 1479
 *  @param wait_option	wait response or not
 *  @return 	   	n/a
 */
1480
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
1481
{
1482
	__le32 Localpsmode;
1483

1484
	lbs_deb_enter(LBS_DEB_HOST);
1485

1486
	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1487

1488
	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1489
			      CMD_SUBCMD_EXIT_PS,
1490 1491
			      wait_option, 0, &Localpsmode);

1492
	lbs_deb_leave(LBS_DEB_HOST);
1493 1494 1495 1496 1497 1498
}

/**
 *  @brief This function checks condition and prepares to
 *  send sleep confirm command to firmware if ok.
 *
1499
 *  @param priv    	A pointer to struct lbs_private structure
1500 1501 1502
 *  @param psmode  	Power Saving mode
 *  @return 	   	n/a
 */
1503
void lbs_ps_confirm_sleep(struct lbs_private *priv)
1504 1505
{
	unsigned long flags =0;
1506
	int allowed = 1;
1507

1508
	lbs_deb_enter(LBS_DEB_HOST);
1509

1510
	spin_lock_irqsave(&priv->driver_lock, flags);
1511
	if (priv->dnld_sent) {
1512
		allowed = 0;
1513
		lbs_deb_host("dnld_sent was set\n");
1514 1515
	}

1516
	/* In-progress command? */
1517
	if (priv->cur_cmd) {
1518
		allowed = 0;
1519
		lbs_deb_host("cur_cmd was set\n");
1520
	}
1521 1522

	/* Pending events or command responses? */
S
Stefani Seibold 已提交
1523
	if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
1524
		allowed = 0;
1525
		lbs_deb_host("pending events or command responses\n");
1526
	}
1527
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1528 1529

	if (allowed) {
1530
		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
1531
		lbs_send_confirmsleep(priv);
1532
	} else {
1533
		lbs_deb_host("sleep confirm has been delayed\n");
1534 1535
	}

1536
	lbs_deb_leave(LBS_DEB_HOST);
1537
}
1538 1539


1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
/**
 * @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;
1562
	cmd.usesnr = !!usesnr;
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
	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;
}


1604
struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
1605 1606 1607
	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)
1608 1609 1610 1611 1612
{
	struct cmd_ctrl_node *cmdnode;

	lbs_deb_enter(LBS_DEB_HOST);

1613
	if (priv->surpriseremoved) {
1614
		lbs_deb_host("PREP_CMD: card removed\n");
1615
		cmdnode = ERR_PTR(-ENOENT);
1616 1617 1618
		goto done;
	}

1619 1620 1621 1622 1623
	if (!lbs_is_cmd_allowed(priv)) {
		cmdnode = ERR_PTR(-EBUSY);
		goto done;
	}

1624 1625 1626 1627 1628 1629
	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);
1630
		cmdnode = ERR_PTR(-ENOBUFS);
1631 1632 1633
		goto done;
	}

1634
	cmdnode->callback = callback;
1635
	cmdnode->callback_arg = callback_arg;
1636

1637
	/* Copy the incoming command to the buffer */
1638
	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
1639

1640
	/* Set sequence number, clean result, move to buffer */
1641
	priv->seqnum++;
1642 1643 1644 1645
	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;
1646 1647 1648 1649

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

	cmdnode->cmdwaitqwoken = 0;
1650
	lbs_queue_cmd(priv, cmdnode);
1651 1652
	wake_up_interruptible(&priv->waitq);

1653 1654 1655 1656 1657
 done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
	return cmdnode;
}

1658 1659 1660 1661 1662 1663 1664 1665 1666
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);
}

1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
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;
	}

1685 1686 1687
	might_sleep();
	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);

1688
	spin_lock_irqsave(&priv->driver_lock, flags);
1689 1690 1691 1692
	ret = cmdnode->result;
	if (ret)
		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
			    command, ret);
1693

1694
	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
1695
	spin_unlock_irqrestore(&priv->driver_lock, flags);
1696 1697 1698 1699 1700

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