cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cmd.c (41041B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * This file contains the handling of command.
      4 * It prepares command and sends it to firmware when it is ready.
      5 */
      6
      7#include <linux/hardirq.h>
      8#include <linux/kfifo.h>
      9#include <linux/sched.h>
     10#include <linux/slab.h>
     11#include <linux/if_arp.h>
     12#include <linux/export.h>
     13
     14#include "decl.h"
     15#include "cfg.h"
     16#include "cmd.h"
     17
     18#define CAL_NF(nf)		((s32)(-(s32)(nf)))
     19#define CAL_RSSI(snr, nf)	((s32)((s32)(snr) + CAL_NF(nf)))
     20
     21/**
     22 * lbs_cmd_copyback - Simple callback that copies response back into command
     23 *
     24 * @priv:	A pointer to &struct lbs_private structure
     25 * @extra:	A pointer to the original command structure for which
     26 *		'resp' is a response
     27 * @resp:	A pointer to the command response
     28 *
     29 * returns:	0 on success, error on failure
     30 */
     31int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
     32		     struct cmd_header *resp)
     33{
     34	struct cmd_header *buf = (void *)extra;
     35	uint16_t copy_len;
     36
     37	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
     38	memcpy(buf, resp, copy_len);
     39	return 0;
     40}
     41EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
     42
     43/**
     44 *  lbs_cmd_async_callback - Simple callback that ignores the result.
     45 *  Use this if you just want to send a command to the hardware, but don't
     46 *  care for the result.
     47 *
     48 *  @priv:	ignored
     49 *  @extra:	ignored
     50 *  @resp:	ignored
     51 *
     52 *  returns:	0 for success
     53 */
     54static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
     55		     struct cmd_header *resp)
     56{
     57	return 0;
     58}
     59
     60
     61/**
     62 *  is_command_allowed_in_ps - tests if a command is allowed in Power Save mode
     63 *
     64 *  @cmd:	the command ID
     65 *
     66 *  returns:	1 if allowed, 0 if not allowed
     67 */
     68static u8 is_command_allowed_in_ps(u16 cmd)
     69{
     70	switch (cmd) {
     71	case CMD_802_11_RSSI:
     72		return 1;
     73	case CMD_802_11_HOST_SLEEP_CFG:
     74		return 1;
     75	default:
     76		break;
     77	}
     78	return 0;
     79}
     80
     81/**
     82 *  lbs_update_hw_spec - Updates the hardware details like MAC address
     83 *  and regulatory region
     84 *
     85 *  @priv:	A pointer to &struct lbs_private structure
     86 *
     87 *  returns:	0 on success, error on failure
     88 */
     89int lbs_update_hw_spec(struct lbs_private *priv)
     90{
     91	struct cmd_ds_get_hw_spec cmd;
     92	int ret = -1;
     93	u32 i;
     94
     95	memset(&cmd, 0, sizeof(cmd));
     96	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
     97	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
     98	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
     99	if (ret)
    100		goto out;
    101
    102	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
    103
    104	/* The firmware release is in an interesting format: the patch
    105	 * level is in the most significant nibble ... so fix that: */
    106	priv->fwrelease = le32_to_cpu(cmd.fwrelease);
    107	priv->fwrelease = (priv->fwrelease << 8) |
    108		(priv->fwrelease >> 24 & 0xff);
    109
    110	/* Some firmware capabilities:
    111	 * CF card    firmware 5.0.16p0:   cap 0x00000303
    112	 * USB dongle firmware 5.110.17p2: cap 0x00000303
    113	 */
    114	netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
    115		cmd.permanentaddr,
    116		priv->fwrelease >> 24 & 0xff,
    117		priv->fwrelease >> 16 & 0xff,
    118		priv->fwrelease >>  8 & 0xff,
    119		priv->fwrelease       & 0xff,
    120		priv->fwcapinfo);
    121	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
    122		    cmd.hwifversion, cmd.version);
    123
    124	/* Clamp region code to 8-bit since FW spec indicates that it should
    125	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
    126	 * returns non-zero high 8 bits here.
    127	 *
    128	 * Firmware version 4.0.102 used in CF8381 has region code shifted.  We
    129	 * need to check for this problem and handle it properly.
    130	 */
    131	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
    132		priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
    133	else
    134		priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
    135
    136	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
    137		/* use the region code to search for the index */
    138		if (priv->regioncode == lbs_region_code_to_index[i])
    139			break;
    140	}
    141
    142	/* if it's unidentified region code, use the default (USA) */
    143	if (i >= MRVDRV_MAX_REGION_CODE) {
    144		priv->regioncode = 0x10;
    145		netdev_info(priv->dev,
    146			    "unidentified region code; using the default (USA)\n");
    147	}
    148
    149	if (priv->current_addr[0] == 0xff)
    150		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
    151
    152	if (!priv->copied_hwaddr) {
    153		eth_hw_addr_set(priv->dev, priv->current_addr);
    154		if (priv->mesh_dev)
    155			eth_hw_addr_set(priv->mesh_dev, priv->current_addr);
    156		priv->copied_hwaddr = 1;
    157	}
    158
    159out:
    160	return ret;
    161}
    162
    163static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
    164			struct cmd_header *resp)
    165{
    166	if (priv->is_host_sleep_activated) {
    167		priv->is_host_sleep_configured = 0;
    168		if (priv->psstate == PS_STATE_FULL_POWER) {
    169			priv->is_host_sleep_activated = 0;
    170			wake_up_interruptible(&priv->host_sleep_q);
    171		}
    172	} else {
    173		priv->is_host_sleep_configured = 1;
    174	}
    175
    176	return 0;
    177}
    178
    179int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
    180		struct wol_config *p_wol_config)
    181{
    182	struct cmd_ds_host_sleep cmd_config;
    183	int ret;
    184
    185	/*
    186	 * Certain firmware versions do not support EHS_REMOVE_WAKEUP command
    187	 * and the card will return a failure.  Since we need to be
    188	 * able to reset the mask, in those cases we set a 0 mask instead.
    189	 */
    190	if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)
    191		criteria = 0;
    192
    193	cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
    194	cmd_config.criteria = cpu_to_le32(criteria);
    195	cmd_config.gpio = priv->wol_gpio;
    196	cmd_config.gap = priv->wol_gap;
    197
    198	if (p_wol_config != NULL)
    199		memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
    200				sizeof(struct wol_config));
    201	else
    202		cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
    203
    204	ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
    205			le16_to_cpu(cmd_config.hdr.size),
    206			lbs_ret_host_sleep_cfg, 0);
    207	if (!ret) {
    208		if (p_wol_config)
    209			memcpy((uint8_t *) p_wol_config,
    210					(uint8_t *)&cmd_config.wol_conf,
    211					sizeof(struct wol_config));
    212	} else {
    213		netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
    214	}
    215
    216	return ret;
    217}
    218EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
    219
    220/**
    221 *  lbs_set_ps_mode - Sets the Power Save mode
    222 *
    223 *  @priv:	A pointer to &struct lbs_private structure
    224 *  @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or
    225 *                         PS_MODE_ACTION_EXIT_PS)
    226 *  @block:	Whether to block on a response or not
    227 *
    228 *  returns:	0 on success, error on failure
    229 */
    230int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
    231{
    232	struct cmd_ds_802_11_ps_mode cmd;
    233	int ret = 0;
    234
    235	memset(&cmd, 0, sizeof(cmd));
    236	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    237	cmd.action = cpu_to_le16(cmd_action);
    238
    239	if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
    240		lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
    241		cmd.multipledtim = cpu_to_le16(1);  /* Default DTIM multiple */
    242	} else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
    243		lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
    244	} else {
    245		/* We don't handle CONFIRM_SLEEP here because it needs to
    246		 * be fastpathed to the firmware.
    247		 */
    248		lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
    249		ret = -EOPNOTSUPP;
    250		goto out;
    251	}
    252
    253	if (block)
    254		ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
    255	else
    256		lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
    257
    258out:
    259	return ret;
    260}
    261
    262int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
    263				struct sleep_params *sp)
    264{
    265	struct cmd_ds_802_11_sleep_params cmd;
    266	int ret;
    267
    268	if (cmd_action == CMD_ACT_GET) {
    269		memset(&cmd, 0, sizeof(cmd));
    270	} else {
    271		cmd.error = cpu_to_le16(sp->sp_error);
    272		cmd.offset = cpu_to_le16(sp->sp_offset);
    273		cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
    274		cmd.calcontrol = sp->sp_calcontrol;
    275		cmd.externalsleepclk = sp->sp_extsleepclk;
    276		cmd.reserved = cpu_to_le16(sp->sp_reserved);
    277	}
    278	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    279	cmd.action = cpu_to_le16(cmd_action);
    280
    281	ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
    282
    283	if (!ret) {
    284		lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
    285			    "calcontrol 0x%x extsleepclk 0x%x\n",
    286			    le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
    287			    le16_to_cpu(cmd.stabletime), cmd.calcontrol,
    288			    cmd.externalsleepclk);
    289
    290		sp->sp_error = le16_to_cpu(cmd.error);
    291		sp->sp_offset = le16_to_cpu(cmd.offset);
    292		sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
    293		sp->sp_calcontrol = cmd.calcontrol;
    294		sp->sp_extsleepclk = cmd.externalsleepclk;
    295		sp->sp_reserved = le16_to_cpu(cmd.reserved);
    296	}
    297
    298	return ret;
    299}
    300
    301static int lbs_wait_for_ds_awake(struct lbs_private *priv)
    302{
    303	int ret = 0;
    304
    305	if (priv->is_deep_sleep) {
    306		if (!wait_event_interruptible_timeout(priv->ds_awake_q,
    307					!priv->is_deep_sleep, (10 * HZ))) {
    308			netdev_err(priv->dev, "ds_awake_q: timer expired\n");
    309			ret = -1;
    310		}
    311	}
    312
    313	return ret;
    314}
    315
    316int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
    317{
    318	int ret =  0;
    319
    320	if (deep_sleep) {
    321		if (priv->is_deep_sleep != 1) {
    322			lbs_deb_cmd("deep sleep: sleep\n");
    323			BUG_ON(!priv->enter_deep_sleep);
    324			ret = priv->enter_deep_sleep(priv);
    325			if (!ret) {
    326				netif_stop_queue(priv->dev);
    327				netif_carrier_off(priv->dev);
    328			}
    329		} else {
    330			netdev_err(priv->dev, "deep sleep: already enabled\n");
    331		}
    332	} else {
    333		if (priv->is_deep_sleep) {
    334			lbs_deb_cmd("deep sleep: wakeup\n");
    335			BUG_ON(!priv->exit_deep_sleep);
    336			ret = priv->exit_deep_sleep(priv);
    337			if (!ret) {
    338				ret = lbs_wait_for_ds_awake(priv);
    339				if (ret)
    340					netdev_err(priv->dev,
    341						   "deep sleep: wakeup failed\n");
    342			}
    343		}
    344	}
    345
    346	return ret;
    347}
    348
    349static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
    350		unsigned long dummy,
    351		struct cmd_header *cmd)
    352{
    353	priv->is_host_sleep_activated = 1;
    354	wake_up_interruptible(&priv->host_sleep_q);
    355
    356	return 0;
    357}
    358
    359int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
    360{
    361	struct cmd_header cmd;
    362	int ret = 0;
    363	uint32_t criteria = EHS_REMOVE_WAKEUP;
    364
    365	if (host_sleep) {
    366		if (priv->is_host_sleep_activated != 1) {
    367			memset(&cmd, 0, sizeof(cmd));
    368			ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
    369					(struct wol_config *)NULL);
    370			if (ret) {
    371				netdev_info(priv->dev,
    372					    "Host sleep configuration failed: %d\n",
    373					    ret);
    374				return ret;
    375			}
    376			if (priv->psstate == PS_STATE_FULL_POWER) {
    377				ret = __lbs_cmd(priv,
    378						CMD_802_11_HOST_SLEEP_ACTIVATE,
    379						&cmd,
    380						sizeof(cmd),
    381						lbs_ret_host_sleep_activate, 0);
    382				if (ret)
    383					netdev_info(priv->dev,
    384						    "HOST_SLEEP_ACTIVATE failed: %d\n",
    385						    ret);
    386			}
    387
    388			if (!wait_event_interruptible_timeout(
    389						priv->host_sleep_q,
    390						priv->is_host_sleep_activated,
    391						(10 * HZ))) {
    392				netdev_err(priv->dev,
    393					   "host_sleep_q: timer expired\n");
    394				ret = -1;
    395			}
    396		} else {
    397			netdev_err(priv->dev, "host sleep: already enabled\n");
    398		}
    399	} else {
    400		if (priv->is_host_sleep_activated)
    401			ret = lbs_host_sleep_cfg(priv, criteria,
    402					(struct wol_config *)NULL);
    403	}
    404
    405	return ret;
    406}
    407
    408/**
    409 *  lbs_set_snmp_mib - Set an SNMP MIB value
    410 *
    411 *  @priv:	A pointer to &struct lbs_private structure
    412 *  @oid:	The OID to set in the firmware
    413 *  @val:	Value to set the OID to
    414 *
    415 *  returns: 	   	0 on success, error on failure
    416 */
    417int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
    418{
    419	struct cmd_ds_802_11_snmp_mib cmd;
    420	int ret;
    421
    422	memset(&cmd, 0, sizeof (cmd));
    423	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    424	cmd.action = cpu_to_le16(CMD_ACT_SET);
    425	cmd.oid = cpu_to_le16((u16) oid);
    426
    427	switch (oid) {
    428	case SNMP_MIB_OID_BSS_TYPE:
    429		cmd.bufsize = cpu_to_le16(sizeof(u8));
    430		cmd.value[0] = val;
    431		break;
    432	case SNMP_MIB_OID_11D_ENABLE:
    433	case SNMP_MIB_OID_FRAG_THRESHOLD:
    434	case SNMP_MIB_OID_RTS_THRESHOLD:
    435	case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
    436	case SNMP_MIB_OID_LONG_RETRY_LIMIT:
    437		cmd.bufsize = cpu_to_le16(sizeof(u16));
    438		*((__le16 *)(&cmd.value)) = cpu_to_le16(val);
    439		break;
    440	default:
    441		lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
    442		ret = -EINVAL;
    443		goto out;
    444	}
    445
    446	lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
    447		    le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
    448
    449	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
    450
    451out:
    452	return ret;
    453}
    454
    455/**
    456 *  lbs_get_snmp_mib - Get an SNMP MIB value
    457 *
    458 *  @priv:	A pointer to &struct lbs_private structure
    459 *  @oid:	The OID to retrieve from the firmware
    460 *  @out_val:	Location for the returned value
    461 *
    462 *  returns:	0 on success, error on failure
    463 */
    464int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
    465{
    466	struct cmd_ds_802_11_snmp_mib cmd;
    467	int ret;
    468
    469	memset(&cmd, 0, sizeof (cmd));
    470	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    471	cmd.action = cpu_to_le16(CMD_ACT_GET);
    472	cmd.oid = cpu_to_le16(oid);
    473
    474	ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
    475	if (ret)
    476		goto out;
    477
    478	switch (le16_to_cpu(cmd.bufsize)) {
    479	case sizeof(u8):
    480		*out_val = cmd.value[0];
    481		break;
    482	case sizeof(u16):
    483		*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
    484		break;
    485	default:
    486		lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
    487		            oid, le16_to_cpu(cmd.bufsize));
    488		break;
    489	}
    490
    491out:
    492	return ret;
    493}
    494
    495/**
    496 *  lbs_get_tx_power - Get the min, max, and current TX power
    497 *
    498 *  @priv:	A pointer to &struct lbs_private structure
    499 *  @curlevel:	Current power level in dBm
    500 *  @minlevel:	Minimum supported power level in dBm (optional)
    501 *  @maxlevel:	Maximum supported power level in dBm (optional)
    502 *
    503 *  returns:	0 on success, error on failure
    504 */
    505int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
    506		     s16 *maxlevel)
    507{
    508	struct cmd_ds_802_11_rf_tx_power cmd;
    509	int ret;
    510
    511	memset(&cmd, 0, sizeof(cmd));
    512	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    513	cmd.action = cpu_to_le16(CMD_ACT_GET);
    514
    515	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
    516	if (ret == 0) {
    517		*curlevel = le16_to_cpu(cmd.curlevel);
    518		if (minlevel)
    519			*minlevel = cmd.minlevel;
    520		if (maxlevel)
    521			*maxlevel = cmd.maxlevel;
    522	}
    523
    524	return ret;
    525}
    526
    527/**
    528 *  lbs_set_tx_power - Set the TX power
    529 *
    530 *  @priv:	A pointer to &struct lbs_private structure
    531 *  @dbm:	The desired power level in dBm
    532 *
    533 *  returns: 	   	0 on success, error on failure
    534 */
    535int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
    536{
    537	struct cmd_ds_802_11_rf_tx_power cmd;
    538	int ret;
    539
    540	memset(&cmd, 0, sizeof(cmd));
    541	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    542	cmd.action = cpu_to_le16(CMD_ACT_SET);
    543	cmd.curlevel = cpu_to_le16(dbm);
    544
    545	lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
    546
    547	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
    548
    549	return ret;
    550}
    551
    552/**
    553 *  lbs_set_monitor_mode - Enable or disable monitor mode
    554 *  (only implemented on OLPC usb8388 FW)
    555 *
    556 *  @priv:	A pointer to &struct lbs_private structure
    557 *  @enable:	1 to enable monitor mode, 0 to disable
    558 *
    559 *  returns:	0 on success, error on failure
    560 */
    561int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
    562{
    563	struct cmd_ds_802_11_monitor_mode cmd;
    564	int ret;
    565
    566	memset(&cmd, 0, sizeof(cmd));
    567	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    568	cmd.action = cpu_to_le16(CMD_ACT_SET);
    569	if (enable)
    570		cmd.mode = cpu_to_le16(0x1);
    571
    572	lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
    573
    574	ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
    575	if (ret == 0) {
    576		priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
    577						ARPHRD_ETHER;
    578	}
    579
    580	return ret;
    581}
    582
    583/**
    584 *  lbs_get_channel - Get the radio channel
    585 *
    586 *  @priv:	A pointer to &struct lbs_private structure
    587 *
    588 *  returns:	The channel on success, error on failure
    589 */
    590static int lbs_get_channel(struct lbs_private *priv)
    591{
    592	struct cmd_ds_802_11_rf_channel cmd;
    593	int ret = 0;
    594
    595	memset(&cmd, 0, sizeof(cmd));
    596	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    597	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
    598
    599	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
    600	if (ret)
    601		goto out;
    602
    603	ret = le16_to_cpu(cmd.channel);
    604	lbs_deb_cmd("current radio channel is %d\n", ret);
    605
    606out:
    607	return ret;
    608}
    609
    610int lbs_update_channel(struct lbs_private *priv)
    611{
    612	int ret;
    613
    614	/* the channel in f/w could be out of sync; get the current channel */
    615	ret = lbs_get_channel(priv);
    616	if (ret > 0) {
    617		priv->channel = ret;
    618		ret = 0;
    619	}
    620
    621	return ret;
    622}
    623
    624/**
    625 *  lbs_set_channel - Set the radio channel
    626 *
    627 *  @priv:	A pointer to &struct lbs_private structure
    628 *  @channel:	The desired channel, or 0 to clear a locked channel
    629 *
    630 *  returns:	0 on success, error on failure
    631 */
    632int lbs_set_channel(struct lbs_private *priv, u8 channel)
    633{
    634	struct cmd_ds_802_11_rf_channel cmd;
    635#ifdef DEBUG
    636	u8 old_channel = priv->channel;
    637#endif
    638	int ret = 0;
    639
    640	memset(&cmd, 0, sizeof(cmd));
    641	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    642	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
    643	cmd.channel = cpu_to_le16(channel);
    644
    645	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
    646	if (ret)
    647		goto out;
    648
    649	priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
    650	lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
    651		priv->channel);
    652
    653out:
    654	return ret;
    655}
    656
    657/**
    658 * lbs_get_rssi - Get current RSSI and noise floor
    659 *
    660 * @priv:	A pointer to &struct lbs_private structure
    661 * @rssi:	On successful return, signal level in mBm
    662 * @nf:		On successful return, Noise floor
    663 *
    664 * returns:	The channel on success, error on failure
    665 */
    666int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
    667{
    668	struct cmd_ds_802_11_rssi cmd;
    669	int ret = 0;
    670
    671	BUG_ON(rssi == NULL);
    672	BUG_ON(nf == NULL);
    673
    674	memset(&cmd, 0, sizeof(cmd));
    675	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    676	/* Average SNR over last 8 beacons */
    677	cmd.n_or_snr = cpu_to_le16(8);
    678
    679	ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
    680	if (ret == 0) {
    681		*nf = CAL_NF(le16_to_cpu(cmd.nf));
    682		*rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
    683	}
    684
    685	return ret;
    686}
    687
    688/**
    689 *  lbs_set_11d_domain_info - Send regulatory and 802.11d domain information
    690 *  to the firmware
    691 *
    692 *  @priv:	pointer to &struct lbs_private
    693 *
    694 *  returns:	0 on success, error code on failure
    695*/
    696int lbs_set_11d_domain_info(struct lbs_private *priv)
    697{
    698	struct wiphy *wiphy = priv->wdev->wiphy;
    699	struct ieee80211_supported_band **bands = wiphy->bands;
    700	struct cmd_ds_802_11d_domain_info cmd;
    701	struct mrvl_ie_domain_param_set *domain = &cmd.domain;
    702	struct ieee80211_country_ie_triplet *t;
    703	enum nl80211_band band;
    704	struct ieee80211_channel *ch;
    705	u8 num_triplet = 0;
    706	u8 num_parsed_chan = 0;
    707	u8 first_channel = 0, next_chan = 0, max_pwr = 0;
    708	u8 i, flag = 0;
    709	size_t triplet_size;
    710	int ret = 0;
    711
    712	if (!priv->country_code[0])
    713		goto out;
    714
    715	memset(&cmd, 0, sizeof(cmd));
    716	cmd.action = cpu_to_le16(CMD_ACT_SET);
    717
    718	lbs_deb_11d("Setting country code '%c%c'\n",
    719		    priv->country_code[0], priv->country_code[1]);
    720
    721	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
    722
    723	/* Set country code */
    724	domain->country_code[0] = priv->country_code[0];
    725	domain->country_code[1] = priv->country_code[1];
    726	domain->country_code[2] = ' ';
    727
    728	/* Now set up the channel triplets; firmware is somewhat picky here
    729	 * and doesn't validate channel numbers and spans; hence it would
    730	 * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39.  Since
    731	 * the last 3 aren't valid channels, the driver is responsible for
    732	 * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
    733	 * etc.
    734	 */
    735	for (band = 0;
    736	     (band < NUM_NL80211_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
    737	     band++) {
    738
    739		if (!bands[band])
    740			continue;
    741
    742		for (i = 0;
    743		     (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
    744		     i++) {
    745			ch = &bands[band]->channels[i];
    746			if (ch->flags & IEEE80211_CHAN_DISABLED)
    747				continue;
    748
    749			if (!flag) {
    750				flag = 1;
    751				next_chan = first_channel = (u32) ch->hw_value;
    752				max_pwr = ch->max_power;
    753				num_parsed_chan = 1;
    754				continue;
    755			}
    756
    757			if ((ch->hw_value == next_chan + 1) &&
    758					(ch->max_power == max_pwr)) {
    759				/* Consolidate adjacent channels */
    760				next_chan++;
    761				num_parsed_chan++;
    762			} else {
    763				/* Add this triplet */
    764				lbs_deb_11d("11D triplet (%d, %d, %d)\n",
    765					first_channel, num_parsed_chan,
    766					max_pwr);
    767				t = &domain->triplet[num_triplet];
    768				t->chans.first_channel = first_channel;
    769				t->chans.num_channels = num_parsed_chan;
    770				t->chans.max_power = max_pwr;
    771				num_triplet++;
    772				flag = 0;
    773			}
    774		}
    775
    776		if (flag) {
    777			/* Add last triplet */
    778			lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
    779				num_parsed_chan, max_pwr);
    780			t = &domain->triplet[num_triplet];
    781			t->chans.first_channel = first_channel;
    782			t->chans.num_channels = num_parsed_chan;
    783			t->chans.max_power = max_pwr;
    784			num_triplet++;
    785		}
    786	}
    787
    788	lbs_deb_11d("# triplets %d\n", num_triplet);
    789
    790	/* Set command header sizes */
    791	triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
    792	domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
    793					triplet_size);
    794
    795	lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
    796			(u8 *) &cmd.domain.country_code,
    797			le16_to_cpu(domain->header.len));
    798
    799	cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
    800				   sizeof(cmd.action) +
    801				   sizeof(cmd.domain.header) +
    802				   sizeof(cmd.domain.country_code) +
    803				   triplet_size);
    804
    805	ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
    806
    807out:
    808	return ret;
    809}
    810
    811/**
    812 *  lbs_get_reg - Read a MAC, Baseband, or RF register
    813 *
    814 *  @priv:	pointer to &struct lbs_private
    815 *  @reg:	register command, one of CMD_MAC_REG_ACCESS,
    816 *		CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
    817 *  @offset:	byte offset of the register to get
    818 *  @value:	on success, the value of the register at 'offset'
    819 *
    820 *  returns:	0 on success, error code on failure
    821*/
    822int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
    823{
    824	struct cmd_ds_reg_access cmd;
    825	int ret = 0;
    826
    827	BUG_ON(value == NULL);
    828
    829	memset(&cmd, 0, sizeof(cmd));
    830	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    831	cmd.action = cpu_to_le16(CMD_ACT_GET);
    832	cmd.offset = cpu_to_le16(offset);
    833
    834	if (reg != CMD_MAC_REG_ACCESS &&
    835	    reg != CMD_BBP_REG_ACCESS &&
    836	    reg != CMD_RF_REG_ACCESS) {
    837		ret = -EINVAL;
    838		goto out;
    839	}
    840
    841	ret = lbs_cmd_with_response(priv, reg, &cmd);
    842	if (!ret) {
    843		if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
    844			*value = cmd.value.bbp_rf;
    845		else if (reg == CMD_MAC_REG_ACCESS)
    846			*value = le32_to_cpu(cmd.value.mac);
    847	}
    848
    849out:
    850	return ret;
    851}
    852
    853/**
    854 *  lbs_set_reg - Write a MAC, Baseband, or RF register
    855 *
    856 *  @priv:	pointer to &struct lbs_private
    857 *  @reg:	register command, one of CMD_MAC_REG_ACCESS,
    858 *		CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
    859 *  @offset:	byte offset of the register to set
    860 *  @value:	the value to write to the register at 'offset'
    861 *
    862 *  returns:	0 on success, error code on failure
    863*/
    864int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
    865{
    866	struct cmd_ds_reg_access cmd;
    867	int ret = 0;
    868
    869	memset(&cmd, 0, sizeof(cmd));
    870	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
    871	cmd.action = cpu_to_le16(CMD_ACT_SET);
    872	cmd.offset = cpu_to_le16(offset);
    873
    874	if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
    875		cmd.value.bbp_rf = (u8) (value & 0xFF);
    876	else if (reg == CMD_MAC_REG_ACCESS)
    877		cmd.value.mac = cpu_to_le32(value);
    878	else {
    879		ret = -EINVAL;
    880		goto out;
    881	}
    882
    883	ret = lbs_cmd_with_response(priv, reg, &cmd);
    884
    885out:
    886	return ret;
    887}
    888
    889static void lbs_queue_cmd(struct lbs_private *priv,
    890			  struct cmd_ctrl_node *cmdnode)
    891{
    892	unsigned long flags;
    893	int addtail = 1;
    894
    895	if (!cmdnode) {
    896		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
    897		return;
    898	}
    899	if (!cmdnode->cmdbuf->size) {
    900		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
    901		return;
    902	}
    903	cmdnode->result = 0;
    904
    905	/* Exit_PS command needs to be queued in the header always. */
    906	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
    907		struct cmd_ds_802_11_ps_mode *psm = (void *)cmdnode->cmdbuf;
    908
    909		if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
    910			if (priv->psstate != PS_STATE_FULL_POWER)
    911				addtail = 0;
    912		}
    913	}
    914
    915	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
    916		addtail = 0;
    917
    918	spin_lock_irqsave(&priv->driver_lock, flags);
    919
    920	if (addtail)
    921		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
    922	else
    923		list_add(&cmdnode->list, &priv->cmdpendingq);
    924
    925	spin_unlock_irqrestore(&priv->driver_lock, flags);
    926
    927	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
    928		     le16_to_cpu(cmdnode->cmdbuf->command));
    929}
    930
    931static void lbs_submit_command(struct lbs_private *priv,
    932			       struct cmd_ctrl_node *cmdnode)
    933{
    934	unsigned long flags;
    935	struct cmd_header *cmd;
    936	uint16_t cmdsize;
    937	uint16_t command;
    938	int timeo = 3 * HZ;
    939	int ret;
    940
    941	cmd = cmdnode->cmdbuf;
    942
    943	spin_lock_irqsave(&priv->driver_lock, flags);
    944	priv->seqnum++;
    945	cmd->seqnum = cpu_to_le16(priv->seqnum);
    946	priv->cur_cmd = cmdnode;
    947	spin_unlock_irqrestore(&priv->driver_lock, flags);
    948
    949	cmdsize = le16_to_cpu(cmd->size);
    950	command = le16_to_cpu(cmd->command);
    951
    952	/* These commands take longer */
    953	if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
    954		timeo = 5 * HZ;
    955
    956	lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
    957		     command, le16_to_cpu(cmd->seqnum), cmdsize);
    958	lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
    959
    960	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
    961
    962	if (ret) {
    963		netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
    964			    ret);
    965		/* Reset dnld state machine, report failure */
    966		priv->dnld_sent = DNLD_RES_RECEIVED;
    967		lbs_complete_command(priv, cmdnode, ret);
    968	}
    969
    970	if (command == CMD_802_11_DEEP_SLEEP) {
    971		if (priv->is_auto_deep_sleep_enabled) {
    972			priv->wakeup_dev_required = 1;
    973			priv->dnld_sent = 0;
    974		}
    975		priv->is_deep_sleep = 1;
    976		lbs_complete_command(priv, cmdnode, 0);
    977	} else {
    978		/* Setup the timer after transmit command */
    979		mod_timer(&priv->command_timer, jiffies + timeo);
    980	}
    981}
    982
    983/*
    984 *  This function inserts command node to cmdfreeq
    985 *  after cleans it. Requires priv->driver_lock held.
    986 */
    987static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
    988					 struct cmd_ctrl_node *cmdnode)
    989{
    990	if (!cmdnode)
    991		return;
    992
    993	cmdnode->callback = NULL;
    994	cmdnode->callback_arg = 0;
    995
    996	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
    997
    998	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
    999}
   1000
   1001static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
   1002	struct cmd_ctrl_node *ptempcmd)
   1003{
   1004	unsigned long flags;
   1005
   1006	spin_lock_irqsave(&priv->driver_lock, flags);
   1007	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
   1008	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1009}
   1010
   1011void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
   1012			    int result)
   1013{
   1014	/*
   1015	 * Normally, commands are removed from cmdpendingq before being
   1016	 * submitted. However, we can arrive here on alternative codepaths
   1017	 * where the command is still pending. Make sure the command really
   1018	 * isn't part of a list at this point.
   1019	 */
   1020	list_del_init(&cmd->list);
   1021
   1022	cmd->result = result;
   1023	cmd->cmdwaitqwoken = 1;
   1024	wake_up(&cmd->cmdwait_q);
   1025
   1026	if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
   1027		__lbs_cleanup_and_insert_cmd(priv, cmd);
   1028	priv->cur_cmd = NULL;
   1029	wake_up(&priv->waitq);
   1030}
   1031
   1032void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
   1033			  int result)
   1034{
   1035	unsigned long flags;
   1036	spin_lock_irqsave(&priv->driver_lock, flags);
   1037	__lbs_complete_command(priv, cmd, result);
   1038	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1039}
   1040
   1041int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
   1042{
   1043	struct cmd_ds_802_11_radio_control cmd;
   1044	int ret = -EINVAL;
   1045
   1046	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
   1047	cmd.action = cpu_to_le16(CMD_ACT_SET);
   1048	cmd.control = 0;
   1049
   1050	/* Only v8 and below support setting the preamble */
   1051	if (priv->fwrelease < 0x09000000) {
   1052		switch (preamble) {
   1053		case RADIO_PREAMBLE_SHORT:
   1054		case RADIO_PREAMBLE_AUTO:
   1055		case RADIO_PREAMBLE_LONG:
   1056			cmd.control = cpu_to_le16(preamble);
   1057			break;
   1058		default:
   1059			goto out;
   1060		}
   1061	}
   1062
   1063	if (radio_on)
   1064		cmd.control |= cpu_to_le16(0x1);
   1065	else {
   1066		cmd.control &= cpu_to_le16(~0x1);
   1067		priv->txpower_cur = 0;
   1068	}
   1069
   1070	lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
   1071		    radio_on ? "ON" : "OFF", preamble);
   1072
   1073	priv->radio_on = radio_on;
   1074
   1075	ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
   1076
   1077out:
   1078	return ret;
   1079}
   1080
   1081void lbs_set_mac_control(struct lbs_private *priv)
   1082{
   1083	struct cmd_ds_mac_control cmd;
   1084
   1085	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
   1086	cmd.action = cpu_to_le16(priv->mac_control);
   1087	cmd.reserved = 0;
   1088
   1089	lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
   1090}
   1091
   1092int lbs_set_mac_control_sync(struct lbs_private *priv)
   1093{
   1094	struct cmd_ds_mac_control cmd;
   1095	int ret = 0;
   1096
   1097	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
   1098	cmd.action = cpu_to_le16(priv->mac_control);
   1099	cmd.reserved = 0;
   1100	ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);
   1101
   1102	return ret;
   1103}
   1104
   1105/**
   1106 *  lbs_allocate_cmd_buffer - allocates the command buffer and links
   1107 *  it to command free queue
   1108 *
   1109 *  @priv:	A pointer to &struct lbs_private structure
   1110 *
   1111 *  returns:	0 for success or -1 on error
   1112 */
   1113int lbs_allocate_cmd_buffer(struct lbs_private *priv)
   1114{
   1115	int ret = 0;
   1116	u32 bufsize;
   1117	u32 i;
   1118	struct cmd_ctrl_node *cmdarray;
   1119
   1120	/* Allocate and initialize the command array */
   1121	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
   1122	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
   1123		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
   1124		ret = -1;
   1125		goto done;
   1126	}
   1127	priv->cmd_array = cmdarray;
   1128
   1129	/* Allocate and initialize each command buffer in the command array */
   1130	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
   1131		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
   1132		if (!cmdarray[i].cmdbuf) {
   1133			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
   1134			ret = -1;
   1135			goto done;
   1136		}
   1137	}
   1138
   1139	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
   1140		init_waitqueue_head(&cmdarray[i].cmdwait_q);
   1141		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
   1142	}
   1143	ret = 0;
   1144
   1145done:
   1146	return ret;
   1147}
   1148
   1149/**
   1150 *  lbs_free_cmd_buffer - free the command buffer
   1151 *
   1152 *  @priv:	A pointer to &struct lbs_private structure
   1153 *
   1154 *  returns:	0 for success
   1155 */
   1156int lbs_free_cmd_buffer(struct lbs_private *priv)
   1157{
   1158	struct cmd_ctrl_node *cmdarray;
   1159	unsigned int i;
   1160
   1161	/* need to check if cmd array is allocated or not */
   1162	if (priv->cmd_array == NULL) {
   1163		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
   1164		goto done;
   1165	}
   1166
   1167	cmdarray = priv->cmd_array;
   1168
   1169	/* Release shared memory buffers */
   1170	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
   1171		if (cmdarray[i].cmdbuf) {
   1172			kfree(cmdarray[i].cmdbuf);
   1173			cmdarray[i].cmdbuf = NULL;
   1174		}
   1175	}
   1176
   1177	/* Release cmd_ctrl_node */
   1178	if (priv->cmd_array) {
   1179		kfree(priv->cmd_array);
   1180		priv->cmd_array = NULL;
   1181	}
   1182
   1183done:
   1184	return 0;
   1185}
   1186
   1187/**
   1188 *  lbs_get_free_cmd_node - gets a free command node if available in
   1189 *  command free queue
   1190 *
   1191 *  @priv:	A pointer to &struct lbs_private structure
   1192 *
   1193 *  returns:	A pointer to &cmd_ctrl_node structure on success
   1194 *		or %NULL on error
   1195 */
   1196static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
   1197{
   1198	struct cmd_ctrl_node *tempnode;
   1199	unsigned long flags;
   1200
   1201	if (!priv)
   1202		return NULL;
   1203
   1204	spin_lock_irqsave(&priv->driver_lock, flags);
   1205
   1206	if (!list_empty(&priv->cmdfreeq)) {
   1207		tempnode = list_first_entry(&priv->cmdfreeq,
   1208					    struct cmd_ctrl_node, list);
   1209		list_del_init(&tempnode->list);
   1210	} else {
   1211		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
   1212		tempnode = NULL;
   1213	}
   1214
   1215	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1216
   1217	return tempnode;
   1218}
   1219
   1220/**
   1221 *  lbs_execute_next_command - execute next command in command
   1222 *  pending queue. Will put firmware back to PS mode if applicable.
   1223 *
   1224 *  @priv:	A pointer to &struct lbs_private structure
   1225 *
   1226 *  returns:	0 on success or -1 on error
   1227 */
   1228int lbs_execute_next_command(struct lbs_private *priv)
   1229{
   1230	struct cmd_ctrl_node *cmdnode = NULL;
   1231	struct cmd_header *cmd;
   1232	unsigned long flags;
   1233	int ret = 0;
   1234
   1235	/* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
   1236	 * only caller to us is lbs_thread() and we get even when a
   1237	 * data packet is received */
   1238	spin_lock_irqsave(&priv->driver_lock, flags);
   1239
   1240	if (priv->cur_cmd) {
   1241		netdev_alert(priv->dev,
   1242			     "EXEC_NEXT_CMD: already processing command!\n");
   1243		spin_unlock_irqrestore(&priv->driver_lock, flags);
   1244		ret = -1;
   1245		goto done;
   1246	}
   1247
   1248	if (!list_empty(&priv->cmdpendingq)) {
   1249		cmdnode = list_first_entry(&priv->cmdpendingq,
   1250					   struct cmd_ctrl_node, list);
   1251	}
   1252
   1253	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1254
   1255	if (cmdnode) {
   1256		cmd = cmdnode->cmdbuf;
   1257
   1258		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
   1259			if ((priv->psstate == PS_STATE_SLEEP) ||
   1260			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
   1261				lbs_deb_host(
   1262				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
   1263				       le16_to_cpu(cmd->command),
   1264				       priv->psstate);
   1265				ret = -1;
   1266				goto done;
   1267			}
   1268			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
   1269				     "0x%04x in psstate %d\n",
   1270				     le16_to_cpu(cmd->command), priv->psstate);
   1271		} else if (priv->psstate != PS_STATE_FULL_POWER) {
   1272			/*
   1273			 * 1. Non-PS command:
   1274			 * Queue it. set needtowakeup to TRUE if current state
   1275			 * is SLEEP, otherwise call send EXIT_PS.
   1276			 * 2. PS command but not EXIT_PS:
   1277			 * Ignore it.
   1278			 * 3. PS command EXIT_PS:
   1279			 * Set needtowakeup to TRUE if current state is SLEEP,
   1280			 * otherwise send this command down to firmware
   1281			 * immediately.
   1282			 */
   1283			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
   1284				/*  Prepare to send Exit PS,
   1285				 *  this non PS command will be sent later */
   1286				if ((priv->psstate == PS_STATE_SLEEP)
   1287				    || (priv->psstate == PS_STATE_PRE_SLEEP)
   1288				    ) {
   1289					/* w/ new scheme, it will not reach here.
   1290					   since it is blocked in main_thread. */
   1291					priv->needtowakeup = 1;
   1292				} else {
   1293					lbs_set_ps_mode(priv,
   1294							PS_MODE_ACTION_EXIT_PS,
   1295							false);
   1296				}
   1297
   1298				ret = 0;
   1299				goto done;
   1300			} else {
   1301				/*
   1302				 * PS command. Ignore it if it is not Exit_PS.
   1303				 * otherwise send it down immediately.
   1304				 */
   1305				struct cmd_ds_802_11_ps_mode *psm = (void *)cmd;
   1306
   1307				lbs_deb_host(
   1308				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
   1309				       psm->action);
   1310				if (psm->action !=
   1311				    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
   1312					lbs_deb_host(
   1313					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
   1314					lbs_complete_command(priv, cmdnode, 0);
   1315
   1316					ret = 0;
   1317					goto done;
   1318				}
   1319
   1320				if ((priv->psstate == PS_STATE_SLEEP) ||
   1321				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
   1322					lbs_deb_host(
   1323					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
   1324					lbs_complete_command(priv, cmdnode, 0);
   1325					priv->needtowakeup = 1;
   1326
   1327					ret = 0;
   1328					goto done;
   1329				}
   1330
   1331				lbs_deb_host(
   1332				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
   1333			}
   1334		}
   1335		spin_lock_irqsave(&priv->driver_lock, flags);
   1336		list_del_init(&cmdnode->list);
   1337		spin_unlock_irqrestore(&priv->driver_lock, flags);
   1338		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
   1339			    le16_to_cpu(cmd->command));
   1340		lbs_submit_command(priv, cmdnode);
   1341	} else {
   1342		/*
   1343		 * check if in power save mode, if yes, put the device back
   1344		 * to PS mode
   1345		 */
   1346		if ((priv->psmode != LBS802_11POWERMODECAM) &&
   1347		    (priv->psstate == PS_STATE_FULL_POWER) &&
   1348		    (priv->connect_status == LBS_CONNECTED)) {
   1349			lbs_deb_host(
   1350				"EXEC_NEXT_CMD: cmdpendingq empty, go back to PS_SLEEP");
   1351			lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
   1352					false);
   1353		}
   1354	}
   1355
   1356	ret = 0;
   1357done:
   1358	return ret;
   1359}
   1360
   1361static void lbs_send_confirmsleep(struct lbs_private *priv)
   1362{
   1363	unsigned long flags;
   1364	int ret;
   1365
   1366	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
   1367		sizeof(confirm_sleep));
   1368
   1369	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
   1370		sizeof(confirm_sleep));
   1371	if (ret) {
   1372		netdev_alert(priv->dev, "confirm_sleep failed\n");
   1373		return;
   1374	}
   1375
   1376	spin_lock_irqsave(&priv->driver_lock, flags);
   1377
   1378	/* We don't get a response on the sleep-confirmation */
   1379	priv->dnld_sent = DNLD_RES_RECEIVED;
   1380
   1381	if (priv->is_host_sleep_configured) {
   1382		priv->is_host_sleep_activated = 1;
   1383		wake_up_interruptible(&priv->host_sleep_q);
   1384	}
   1385
   1386	/* If nothing to do, go back to sleep (?) */
   1387	if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
   1388		priv->psstate = PS_STATE_SLEEP;
   1389
   1390	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1391}
   1392
   1393/**
   1394 * lbs_ps_confirm_sleep - checks condition and prepares to
   1395 * send sleep confirm command to firmware if ok
   1396 *
   1397 * @priv:	A pointer to &struct lbs_private structure
   1398 *
   1399 * returns:	n/a
   1400 */
   1401void lbs_ps_confirm_sleep(struct lbs_private *priv)
   1402{
   1403	unsigned long flags =0;
   1404	int allowed = 1;
   1405
   1406	spin_lock_irqsave(&priv->driver_lock, flags);
   1407	if (priv->dnld_sent) {
   1408		allowed = 0;
   1409		lbs_deb_host("dnld_sent was set\n");
   1410	}
   1411
   1412	/* In-progress command? */
   1413	if (priv->cur_cmd) {
   1414		allowed = 0;
   1415		lbs_deb_host("cur_cmd was set\n");
   1416	}
   1417
   1418	/* Pending events or command responses? */
   1419	if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
   1420		allowed = 0;
   1421		lbs_deb_host("pending events or command responses\n");
   1422	}
   1423	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1424
   1425	if (allowed) {
   1426		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
   1427		lbs_send_confirmsleep(priv);
   1428	} else {
   1429		lbs_deb_host("sleep confirm has been delayed\n");
   1430	}
   1431}
   1432
   1433
   1434/**
   1435 * lbs_set_tpc_cfg - Configures the transmission power control functionality
   1436 *
   1437 * @priv:	A pointer to &struct lbs_private structure
   1438 * @enable:	Transmission power control enable
   1439 * @p0:		Power level when link quality is good (dBm).
   1440 * @p1:		Power level when link quality is fair (dBm).
   1441 * @p2:		Power level when link quality is poor (dBm).
   1442 * @usesnr:	Use Signal to Noise Ratio in TPC
   1443 *
   1444 * returns:	0 on success
   1445 */
   1446int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
   1447		int8_t p2, int usesnr)
   1448{
   1449	struct cmd_ds_802_11_tpc_cfg cmd;
   1450	int ret;
   1451
   1452	memset(&cmd, 0, sizeof(cmd));
   1453	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
   1454	cmd.action = cpu_to_le16(CMD_ACT_SET);
   1455	cmd.enable = !!enable;
   1456	cmd.usesnr = !!usesnr;
   1457	cmd.P0 = p0;
   1458	cmd.P1 = p1;
   1459	cmd.P2 = p2;
   1460
   1461	ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
   1462
   1463	return ret;
   1464}
   1465
   1466/**
   1467 * lbs_set_power_adapt_cfg - Configures the power adaptation settings
   1468 *
   1469 * @priv:	A pointer to &struct lbs_private structure
   1470 * @enable:	Power adaptation enable
   1471 * @p0:		Power level for 1, 2, 5.5 and 11 Mbps (dBm).
   1472 * @p1:		Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
   1473 * @p2:		Power level for 48 and 54 Mbps (dBm).
   1474 *
   1475 * returns:	0 on Success
   1476 */
   1477
   1478int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
   1479		int8_t p1, int8_t p2)
   1480{
   1481	struct cmd_ds_802_11_pa_cfg cmd;
   1482	int ret;
   1483
   1484	memset(&cmd, 0, sizeof(cmd));
   1485	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
   1486	cmd.action = cpu_to_le16(CMD_ACT_SET);
   1487	cmd.enable = !!enable;
   1488	cmd.P0 = p0;
   1489	cmd.P1 = p1;
   1490	cmd.P2 = p2;
   1491
   1492	ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
   1493
   1494	return ret;
   1495}
   1496
   1497
   1498struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
   1499	uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
   1500	int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
   1501	unsigned long callback_arg)
   1502{
   1503	struct cmd_ctrl_node *cmdnode;
   1504
   1505	if (priv->surpriseremoved) {
   1506		lbs_deb_host("PREP_CMD: card removed\n");
   1507		cmdnode = ERR_PTR(-ENOENT);
   1508		goto done;
   1509	}
   1510
   1511	/* No commands are allowed in Deep Sleep until we toggle the GPIO
   1512	 * to wake up the card and it has signaled that it's ready.
   1513	 */
   1514	if (!priv->is_auto_deep_sleep_enabled) {
   1515		if (priv->is_deep_sleep) {
   1516			lbs_deb_cmd("command not allowed in deep sleep\n");
   1517			cmdnode = ERR_PTR(-EBUSY);
   1518			goto done;
   1519		}
   1520	}
   1521
   1522	cmdnode = lbs_get_free_cmd_node(priv);
   1523	if (cmdnode == NULL) {
   1524		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
   1525
   1526		/* Wake up main thread to execute next command */
   1527		wake_up(&priv->waitq);
   1528		cmdnode = ERR_PTR(-ENOBUFS);
   1529		goto done;
   1530	}
   1531
   1532	cmdnode->callback = callback;
   1533	cmdnode->callback_arg = callback_arg;
   1534
   1535	/* Copy the incoming command to the buffer */
   1536	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
   1537
   1538	/* Set command, clean result, move to buffer */
   1539	cmdnode->cmdbuf->command = cpu_to_le16(command);
   1540	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
   1541	cmdnode->cmdbuf->result  = 0;
   1542
   1543	lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
   1544
   1545	cmdnode->cmdwaitqwoken = 0;
   1546	lbs_queue_cmd(priv, cmdnode);
   1547	wake_up(&priv->waitq);
   1548
   1549 done:
   1550	return cmdnode;
   1551}
   1552
   1553void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
   1554	struct cmd_header *in_cmd, int in_cmd_size)
   1555{
   1556	__lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
   1557		lbs_cmd_async_callback, 0);
   1558}
   1559
   1560int __lbs_cmd(struct lbs_private *priv, uint16_t command,
   1561	      struct cmd_header *in_cmd, int in_cmd_size,
   1562	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
   1563	      unsigned long callback_arg)
   1564{
   1565	struct cmd_ctrl_node *cmdnode;
   1566	unsigned long flags;
   1567	int ret = 0;
   1568
   1569	cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
   1570				  callback, callback_arg);
   1571	if (IS_ERR(cmdnode)) {
   1572		ret = PTR_ERR(cmdnode);
   1573		goto done;
   1574	}
   1575
   1576	might_sleep();
   1577
   1578	/*
   1579	 * Be careful with signals here. A signal may be received as the system
   1580	 * goes into suspend or resume. We do not want this to interrupt the
   1581	 * command, so we perform an uninterruptible sleep.
   1582	 */
   1583	wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
   1584
   1585	spin_lock_irqsave(&priv->driver_lock, flags);
   1586	ret = cmdnode->result;
   1587	if (ret)
   1588		netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
   1589			    command, ret);
   1590
   1591	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
   1592	spin_unlock_irqrestore(&priv->driver_lock, flags);
   1593
   1594done:
   1595	return ret;
   1596}
   1597EXPORT_SYMBOL_GPL(__lbs_cmd);