xref: /linux/drivers/net/wireless/marvell/libertas_tf/cmd.c (revision 744972b2c4d2f62e5a1dde28404ec0f359726771)
1dd3f92deSKalle Valo /*
2dd3f92deSKalle Valo  *  Copyright (C) 2008, cozybit Inc.
3dd3f92deSKalle Valo  *  Copyright (C) 2003-2006, Marvell International Ltd.
4dd3f92deSKalle Valo  *
5dd3f92deSKalle Valo  *  This program is free software; you can redistribute it and/or modify
6dd3f92deSKalle Valo  *  it under the terms of the GNU General Public License as published by
7dd3f92deSKalle Valo  *  the Free Software Foundation; either version 2 of the License, or (at
8dd3f92deSKalle Valo  *  your option) any later version.
9dd3f92deSKalle Valo  */
10dd3f92deSKalle Valo #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11dd3f92deSKalle Valo 
12dd3f92deSKalle Valo #include <linux/hardirq.h>
13dd3f92deSKalle Valo #include <linux/slab.h>
14dd3f92deSKalle Valo #include <linux/export.h>
15dd3f92deSKalle Valo 
16dd3f92deSKalle Valo #include "libertas_tf.h"
17dd3f92deSKalle Valo 
18dd3f92deSKalle Valo static const struct channel_range channel_ranges[] = {
19dd3f92deSKalle Valo 	{ LBTF_REGDOMAIN_US,		1, 12 },
20dd3f92deSKalle Valo 	{ LBTF_REGDOMAIN_CA,		1, 12 },
21dd3f92deSKalle Valo 	{ LBTF_REGDOMAIN_EU,		1, 14 },
22dd3f92deSKalle Valo 	{ LBTF_REGDOMAIN_JP,		1, 14 },
23dd3f92deSKalle Valo 	{ LBTF_REGDOMAIN_SP,		1, 14 },
24dd3f92deSKalle Valo 	{ LBTF_REGDOMAIN_FR,		1, 14 },
25dd3f92deSKalle Valo };
26dd3f92deSKalle Valo 
27dd3f92deSKalle Valo static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
28dd3f92deSKalle Valo {
29dd3f92deSKalle Valo 	LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU,
30dd3f92deSKalle Valo 	LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP,
31dd3f92deSKalle Valo };
32dd3f92deSKalle Valo 
33dd3f92deSKalle Valo static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv);
34dd3f92deSKalle Valo 
35dd3f92deSKalle Valo 
36dd3f92deSKalle Valo /**
37dd3f92deSKalle Valo  *  lbtf_cmd_copyback - Simple callback that copies response back into command
38dd3f92deSKalle Valo  *
39dd3f92deSKalle Valo  *  @priv	A pointer to struct lbtf_private structure
40dd3f92deSKalle Valo  *  @extra	A pointer to the original command structure for which
41dd3f92deSKalle Valo  *		'resp' is a response
42dd3f92deSKalle Valo  *  @resp	A pointer to the command response
43dd3f92deSKalle Valo  *
44dd3f92deSKalle Valo  *  Returns: 0 on success, error on failure
45dd3f92deSKalle Valo  */
46dd3f92deSKalle Valo int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
47dd3f92deSKalle Valo 		     struct cmd_header *resp)
48dd3f92deSKalle Valo {
49dd3f92deSKalle Valo 	struct cmd_header *buf = (void *)extra;
50dd3f92deSKalle Valo 	uint16_t copy_len;
51dd3f92deSKalle Valo 
52dd3f92deSKalle Valo 	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
53dd3f92deSKalle Valo 	memcpy(buf, resp, copy_len);
54dd3f92deSKalle Valo 	return 0;
55dd3f92deSKalle Valo }
56dd3f92deSKalle Valo EXPORT_SYMBOL_GPL(lbtf_cmd_copyback);
57dd3f92deSKalle Valo 
58dd3f92deSKalle Valo #define CHAN_TO_IDX(chan) ((chan) - 1)
59dd3f92deSKalle Valo 
60dd3f92deSKalle Valo static void lbtf_geo_init(struct lbtf_private *priv)
61dd3f92deSKalle Valo {
62dd3f92deSKalle Valo 	const struct channel_range *range = channel_ranges;
63dd3f92deSKalle Valo 	u8 ch;
64dd3f92deSKalle Valo 	int i;
65dd3f92deSKalle Valo 
66dd3f92deSKalle Valo 	for (i = 0; i < ARRAY_SIZE(channel_ranges); i++)
67dd3f92deSKalle Valo 		if (channel_ranges[i].regdomain == priv->regioncode) {
68dd3f92deSKalle Valo 			range = &channel_ranges[i];
69dd3f92deSKalle Valo 			break;
70dd3f92deSKalle Valo 		}
71dd3f92deSKalle Valo 
72dd3f92deSKalle Valo 	for (ch = priv->range.start; ch < priv->range.end; ch++)
73dd3f92deSKalle Valo 		priv->channels[CHAN_TO_IDX(ch)].flags = 0;
74dd3f92deSKalle Valo }
75dd3f92deSKalle Valo 
76dd3f92deSKalle Valo /**
77dd3f92deSKalle Valo  *  lbtf_update_hw_spec: Updates the hardware details.
78dd3f92deSKalle Valo  *
79dd3f92deSKalle Valo  *  @priv    	A pointer to struct lbtf_private structure
80dd3f92deSKalle Valo  *
81dd3f92deSKalle Valo  *  Returns: 0 on success, error on failure
82dd3f92deSKalle Valo  */
83dd3f92deSKalle Valo int lbtf_update_hw_spec(struct lbtf_private *priv)
84dd3f92deSKalle Valo {
85dd3f92deSKalle Valo 	struct cmd_ds_get_hw_spec cmd;
86dd3f92deSKalle Valo 	int ret = -1;
87dd3f92deSKalle Valo 	u32 i;
88dd3f92deSKalle Valo 
89dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
90dd3f92deSKalle Valo 
91dd3f92deSKalle Valo 	memset(&cmd, 0, sizeof(cmd));
92dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
93dd3f92deSKalle Valo 	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
94dd3f92deSKalle Valo 	ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
95dd3f92deSKalle Valo 	if (ret)
96dd3f92deSKalle Valo 		goto out;
97dd3f92deSKalle Valo 
98dd3f92deSKalle Valo 	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
99dd3f92deSKalle Valo 
100dd3f92deSKalle Valo 	/* The firmware release is in an interesting format: the patch
101dd3f92deSKalle Valo 	 * level is in the most significant nibble ... so fix that: */
102dd3f92deSKalle Valo 	priv->fwrelease = le32_to_cpu(cmd.fwrelease);
103dd3f92deSKalle Valo 	priv->fwrelease = (priv->fwrelease << 8) |
104dd3f92deSKalle Valo 		(priv->fwrelease >> 24 & 0xff);
105dd3f92deSKalle Valo 
106dd3f92deSKalle Valo 	printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
107dd3f92deSKalle Valo 		cmd.permanentaddr,
108dd3f92deSKalle Valo 		priv->fwrelease >> 24 & 0xff,
109dd3f92deSKalle Valo 		priv->fwrelease >> 16 & 0xff,
110dd3f92deSKalle Valo 		priv->fwrelease >>  8 & 0xff,
111dd3f92deSKalle Valo 		priv->fwrelease       & 0xff,
112dd3f92deSKalle Valo 		priv->fwcapinfo);
113dd3f92deSKalle Valo 	lbtf_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
114dd3f92deSKalle Valo 		    cmd.hwifversion, cmd.version);
115dd3f92deSKalle Valo 
116dd3f92deSKalle Valo 	/* Clamp region code to 8-bit since FW spec indicates that it should
117dd3f92deSKalle Valo 	 * only ever be 8-bit, even though the field size is 16-bit.  Some
118dd3f92deSKalle Valo 	 * firmware returns non-zero high 8 bits here.
119dd3f92deSKalle Valo 	 */
120dd3f92deSKalle Valo 	priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
121dd3f92deSKalle Valo 
122dd3f92deSKalle Valo 	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
123dd3f92deSKalle Valo 		/* use the region code to search for the index */
124dd3f92deSKalle Valo 		if (priv->regioncode == lbtf_region_code_to_index[i])
125dd3f92deSKalle Valo 			break;
126dd3f92deSKalle Valo 	}
127dd3f92deSKalle Valo 
128dd3f92deSKalle Valo 	/* if it's unidentified region code, use the default (USA) */
129dd3f92deSKalle Valo 	if (i >= MRVDRV_MAX_REGION_CODE) {
130dd3f92deSKalle Valo 		priv->regioncode = 0x10;
131dd3f92deSKalle Valo 		pr_info("unidentified region code; using the default (USA)\n");
132dd3f92deSKalle Valo 	}
133dd3f92deSKalle Valo 
134dd3f92deSKalle Valo 	if (priv->current_addr[0] == 0xff)
135dd3f92deSKalle Valo 		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
136dd3f92deSKalle Valo 
137dd3f92deSKalle Valo 	SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr);
138dd3f92deSKalle Valo 
139dd3f92deSKalle Valo 	lbtf_geo_init(priv);
140dd3f92deSKalle Valo out:
141dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
142dd3f92deSKalle Valo 	return ret;
143dd3f92deSKalle Valo }
144dd3f92deSKalle Valo 
145dd3f92deSKalle Valo /**
146dd3f92deSKalle Valo  *  lbtf_set_channel: Set the radio channel
147dd3f92deSKalle Valo  *
148dd3f92deSKalle Valo  *  @priv	A pointer to struct lbtf_private structure
149dd3f92deSKalle Valo  *  @channel	The desired channel, or 0 to clear a locked channel
150dd3f92deSKalle Valo  *
151dd3f92deSKalle Valo  *  Returns: 0 on success, error on failure
152dd3f92deSKalle Valo  */
153dd3f92deSKalle Valo int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
154dd3f92deSKalle Valo {
155dd3f92deSKalle Valo 	int ret = 0;
156dd3f92deSKalle Valo 	struct cmd_ds_802_11_rf_channel cmd;
157dd3f92deSKalle Valo 
158dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
159dd3f92deSKalle Valo 
160dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
161dd3f92deSKalle Valo 	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
162dd3f92deSKalle Valo 	cmd.channel = cpu_to_le16(channel);
163dd3f92deSKalle Valo 
164dd3f92deSKalle Valo 	ret = lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
165dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
166dd3f92deSKalle Valo 	return ret;
167dd3f92deSKalle Valo }
168dd3f92deSKalle Valo 
169dd3f92deSKalle Valo int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
170dd3f92deSKalle Valo {
171dd3f92deSKalle Valo 	struct cmd_ds_802_11_beacon_set cmd;
172dd3f92deSKalle Valo 	int size;
173dd3f92deSKalle Valo 
174dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
175dd3f92deSKalle Valo 
176dd3f92deSKalle Valo 	if (beacon->len > MRVL_MAX_BCN_SIZE) {
177dd3f92deSKalle Valo 		lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", -1);
178dd3f92deSKalle Valo 		return -1;
179dd3f92deSKalle Valo 	}
180dd3f92deSKalle Valo 	size =  sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
181dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(size);
182dd3f92deSKalle Valo 	cmd.len = cpu_to_le16(beacon->len);
183dd3f92deSKalle Valo 	memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
184dd3f92deSKalle Valo 
185dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
186dd3f92deSKalle Valo 
187dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", 0);
188dd3f92deSKalle Valo 	return 0;
189dd3f92deSKalle Valo }
190dd3f92deSKalle Valo 
191dd3f92deSKalle Valo int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
192dd3f92deSKalle Valo 		     int beacon_int)
193dd3f92deSKalle Valo {
194dd3f92deSKalle Valo 	struct cmd_ds_802_11_beacon_control cmd;
195dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
196dd3f92deSKalle Valo 
197dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
198dd3f92deSKalle Valo 	cmd.action = cpu_to_le16(CMD_ACT_SET);
199dd3f92deSKalle Valo 	cmd.beacon_enable = cpu_to_le16(beacon_enable);
200dd3f92deSKalle Valo 	cmd.beacon_period = cpu_to_le16(beacon_int);
201dd3f92deSKalle Valo 
202dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
203dd3f92deSKalle Valo 
204dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
205dd3f92deSKalle Valo 	return 0;
206dd3f92deSKalle Valo }
207dd3f92deSKalle Valo 
208dd3f92deSKalle Valo static void lbtf_queue_cmd(struct lbtf_private *priv,
209dd3f92deSKalle Valo 			  struct cmd_ctrl_node *cmdnode)
210dd3f92deSKalle Valo {
211dd3f92deSKalle Valo 	unsigned long flags;
212dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
213dd3f92deSKalle Valo 
214dd3f92deSKalle Valo 	if (!cmdnode) {
215dd3f92deSKalle Valo 		lbtf_deb_host("QUEUE_CMD: cmdnode is NULL\n");
216dd3f92deSKalle Valo 		goto qcmd_done;
217dd3f92deSKalle Valo 	}
218dd3f92deSKalle Valo 
219dd3f92deSKalle Valo 	if (!cmdnode->cmdbuf->size) {
220dd3f92deSKalle Valo 		lbtf_deb_host("DNLD_CMD: cmd size is zero\n");
221dd3f92deSKalle Valo 		goto qcmd_done;
222dd3f92deSKalle Valo 	}
223dd3f92deSKalle Valo 
224dd3f92deSKalle Valo 	cmdnode->result = 0;
225dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
226dd3f92deSKalle Valo 	list_add_tail(&cmdnode->list, &priv->cmdpendingq);
227dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
228dd3f92deSKalle Valo 
229dd3f92deSKalle Valo 	lbtf_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
230dd3f92deSKalle Valo 		     le16_to_cpu(cmdnode->cmdbuf->command));
231dd3f92deSKalle Valo 
232dd3f92deSKalle Valo qcmd_done:
233dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_HOST);
234dd3f92deSKalle Valo }
235dd3f92deSKalle Valo 
236dd3f92deSKalle Valo static void lbtf_submit_command(struct lbtf_private *priv,
237dd3f92deSKalle Valo 			       struct cmd_ctrl_node *cmdnode)
238dd3f92deSKalle Valo {
239dd3f92deSKalle Valo 	unsigned long flags;
240dd3f92deSKalle Valo 	struct cmd_header *cmd;
241dd3f92deSKalle Valo 	uint16_t cmdsize;
242dd3f92deSKalle Valo 	uint16_t command;
243dd3f92deSKalle Valo 	int timeo = 5 * HZ;
244dd3f92deSKalle Valo 	int ret;
245dd3f92deSKalle Valo 
246dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
247dd3f92deSKalle Valo 
248dd3f92deSKalle Valo 	cmd = cmdnode->cmdbuf;
249dd3f92deSKalle Valo 
250dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
251dd3f92deSKalle Valo 	priv->cur_cmd = cmdnode;
252dd3f92deSKalle Valo 	cmdsize = le16_to_cpu(cmd->size);
253dd3f92deSKalle Valo 	command = le16_to_cpu(cmd->command);
254dd3f92deSKalle Valo 
255dd3f92deSKalle Valo 	lbtf_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
256dd3f92deSKalle Valo 		     command, le16_to_cpu(cmd->seqnum), cmdsize);
257dd3f92deSKalle Valo 	lbtf_deb_hex(LBTF_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
258dd3f92deSKalle Valo 
259dd3f92deSKalle Valo 	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
260dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
261dd3f92deSKalle Valo 
262dd3f92deSKalle Valo 	if (ret) {
263dd3f92deSKalle Valo 		pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
264dd3f92deSKalle Valo 		/* Let the timer kick in and retry, and potentially reset
265dd3f92deSKalle Valo 		   the whole thing if the condition persists */
266dd3f92deSKalle Valo 		timeo = HZ;
267dd3f92deSKalle Valo 	}
268dd3f92deSKalle Valo 
269dd3f92deSKalle Valo 	/* Setup the timer after transmit command */
270dd3f92deSKalle Valo 	mod_timer(&priv->command_timer, jiffies + timeo);
271dd3f92deSKalle Valo 
272dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_HOST);
273dd3f92deSKalle Valo }
274dd3f92deSKalle Valo 
275dd3f92deSKalle Valo /**
276dd3f92deSKalle Valo  *  This function inserts command node to cmdfreeq
277dd3f92deSKalle Valo  *  after cleans it. Requires priv->driver_lock held.
278dd3f92deSKalle Valo  */
279dd3f92deSKalle Valo static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
280dd3f92deSKalle Valo 					 struct cmd_ctrl_node *cmdnode)
281dd3f92deSKalle Valo {
282dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
283dd3f92deSKalle Valo 
284dd3f92deSKalle Valo 	if (!cmdnode)
285dd3f92deSKalle Valo 		goto cl_ins_out;
286dd3f92deSKalle Valo 
287dd3f92deSKalle Valo 	cmdnode->callback = NULL;
288dd3f92deSKalle Valo 	cmdnode->callback_arg = 0;
289dd3f92deSKalle Valo 
290dd3f92deSKalle Valo 	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
291dd3f92deSKalle Valo 
292dd3f92deSKalle Valo 	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
293dd3f92deSKalle Valo 
294dd3f92deSKalle Valo cl_ins_out:
295dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_HOST);
296dd3f92deSKalle Valo }
297dd3f92deSKalle Valo 
298dd3f92deSKalle Valo static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
299dd3f92deSKalle Valo 	struct cmd_ctrl_node *ptempcmd)
300dd3f92deSKalle Valo {
301dd3f92deSKalle Valo 	unsigned long flags;
302dd3f92deSKalle Valo 
303dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
304dd3f92deSKalle Valo 	__lbtf_cleanup_and_insert_cmd(priv, ptempcmd);
305dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
306dd3f92deSKalle Valo }
307dd3f92deSKalle Valo 
308dd3f92deSKalle Valo void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
309dd3f92deSKalle Valo 			  int result)
310dd3f92deSKalle Valo {
311dd3f92deSKalle Valo 	cmd->result = result;
312dd3f92deSKalle Valo 	cmd->cmdwaitqwoken = 1;
313dd3f92deSKalle Valo 	wake_up_interruptible(&cmd->cmdwait_q);
314dd3f92deSKalle Valo 
315dd3f92deSKalle Valo 	if (!cmd->callback)
316dd3f92deSKalle Valo 		__lbtf_cleanup_and_insert_cmd(priv, cmd);
317dd3f92deSKalle Valo 	priv->cur_cmd = NULL;
318dd3f92deSKalle Valo }
319dd3f92deSKalle Valo 
320dd3f92deSKalle Valo int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
321dd3f92deSKalle Valo {
322dd3f92deSKalle Valo 	struct cmd_ds_mac_multicast_addr cmd;
323dd3f92deSKalle Valo 
324dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
325dd3f92deSKalle Valo 
326dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
327dd3f92deSKalle Valo 	cmd.action = cpu_to_le16(CMD_ACT_SET);
328dd3f92deSKalle Valo 
329dd3f92deSKalle Valo 	cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
330dd3f92deSKalle Valo 
331dd3f92deSKalle Valo 	lbtf_deb_cmd("MULTICAST_ADR: setting %d addresses\n", cmd.nr_of_adrs);
332dd3f92deSKalle Valo 
333dd3f92deSKalle Valo 	memcpy(cmd.maclist, priv->multicastlist,
334dd3f92deSKalle Valo 	       priv->nr_of_multicastmacaddr * ETH_ALEN);
335dd3f92deSKalle Valo 
336dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
337dd3f92deSKalle Valo 
338dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
339dd3f92deSKalle Valo 	return 0;
340dd3f92deSKalle Valo }
341dd3f92deSKalle Valo 
342dd3f92deSKalle Valo void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
343dd3f92deSKalle Valo {
344dd3f92deSKalle Valo 	struct cmd_ds_set_mode cmd;
345dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_WEXT);
346dd3f92deSKalle Valo 
347dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
348dd3f92deSKalle Valo 	cmd.mode = cpu_to_le16(mode);
349dd3f92deSKalle Valo 	lbtf_deb_wext("Switching to mode: 0x%x\n", mode);
350dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
351dd3f92deSKalle Valo 
352dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_WEXT);
353dd3f92deSKalle Valo }
354dd3f92deSKalle Valo 
355dd3f92deSKalle Valo void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
356dd3f92deSKalle Valo {
357dd3f92deSKalle Valo 	struct cmd_ds_set_bssid cmd;
358dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
359dd3f92deSKalle Valo 
360dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
361dd3f92deSKalle Valo 	cmd.activate = activate ? 1 : 0;
362dd3f92deSKalle Valo 	if (activate)
363dd3f92deSKalle Valo 		memcpy(cmd.bssid, bssid, ETH_ALEN);
364dd3f92deSKalle Valo 
365dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
366dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
367dd3f92deSKalle Valo }
368dd3f92deSKalle Valo 
369dd3f92deSKalle Valo int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
370dd3f92deSKalle Valo {
371dd3f92deSKalle Valo 	struct cmd_ds_802_11_mac_address cmd;
372dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
373dd3f92deSKalle Valo 
374dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
375dd3f92deSKalle Valo 	cmd.action = cpu_to_le16(CMD_ACT_SET);
376dd3f92deSKalle Valo 
377dd3f92deSKalle Valo 	memcpy(cmd.macadd, mac_addr, ETH_ALEN);
378dd3f92deSKalle Valo 
379dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
380dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
381dd3f92deSKalle Valo 	return 0;
382dd3f92deSKalle Valo }
383dd3f92deSKalle Valo 
384dd3f92deSKalle Valo int lbtf_set_radio_control(struct lbtf_private *priv)
385dd3f92deSKalle Valo {
386dd3f92deSKalle Valo 	int ret = 0;
387dd3f92deSKalle Valo 	struct cmd_ds_802_11_radio_control cmd;
388dd3f92deSKalle Valo 
389dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
390dd3f92deSKalle Valo 
391dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
392dd3f92deSKalle Valo 	cmd.action = cpu_to_le16(CMD_ACT_SET);
393dd3f92deSKalle Valo 
394dd3f92deSKalle Valo 	switch (priv->preamble) {
395dd3f92deSKalle Valo 	case CMD_TYPE_SHORT_PREAMBLE:
396dd3f92deSKalle Valo 		cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
397dd3f92deSKalle Valo 		break;
398dd3f92deSKalle Valo 
399dd3f92deSKalle Valo 	case CMD_TYPE_LONG_PREAMBLE:
400dd3f92deSKalle Valo 		cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
401dd3f92deSKalle Valo 		break;
402dd3f92deSKalle Valo 
403dd3f92deSKalle Valo 	case CMD_TYPE_AUTO_PREAMBLE:
404dd3f92deSKalle Valo 	default:
405dd3f92deSKalle Valo 		cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
406dd3f92deSKalle Valo 		break;
407dd3f92deSKalle Valo 	}
408dd3f92deSKalle Valo 
409dd3f92deSKalle Valo 	if (priv->radioon)
410dd3f92deSKalle Valo 		cmd.control |= cpu_to_le16(TURN_ON_RF);
411dd3f92deSKalle Valo 	else
412dd3f92deSKalle Valo 		cmd.control &= cpu_to_le16(~TURN_ON_RF);
413dd3f92deSKalle Valo 
414dd3f92deSKalle Valo 	lbtf_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
415dd3f92deSKalle Valo 		    priv->preamble);
416dd3f92deSKalle Valo 
417dd3f92deSKalle Valo 	ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
418dd3f92deSKalle Valo 
419dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
420dd3f92deSKalle Valo 	return ret;
421dd3f92deSKalle Valo }
422dd3f92deSKalle Valo 
423dd3f92deSKalle Valo void lbtf_set_mac_control(struct lbtf_private *priv)
424dd3f92deSKalle Valo {
425dd3f92deSKalle Valo 	struct cmd_ds_mac_control cmd;
426dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
427dd3f92deSKalle Valo 
428dd3f92deSKalle Valo 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
429dd3f92deSKalle Valo 	cmd.action = cpu_to_le16(priv->mac_control);
430dd3f92deSKalle Valo 	cmd.reserved = 0;
431dd3f92deSKalle Valo 
432dd3f92deSKalle Valo 	lbtf_cmd_async(priv, CMD_MAC_CONTROL,
433dd3f92deSKalle Valo 		&cmd.hdr, sizeof(cmd));
434dd3f92deSKalle Valo 
435dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
436dd3f92deSKalle Valo }
437dd3f92deSKalle Valo 
438dd3f92deSKalle Valo /**
439dd3f92deSKalle Valo  *  lbtf_allocate_cmd_buffer - Allocates cmd buffer, links it to free cmd queue
440dd3f92deSKalle Valo  *
441dd3f92deSKalle Valo  *  @priv	A pointer to struct lbtf_private structure
442dd3f92deSKalle Valo  *
443dd3f92deSKalle Valo  *  Returns: 0 on success.
444dd3f92deSKalle Valo  */
445dd3f92deSKalle Valo int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
446dd3f92deSKalle Valo {
447dd3f92deSKalle Valo 	int ret = 0;
448dd3f92deSKalle Valo 	u32 bufsize;
449dd3f92deSKalle Valo 	u32 i;
450dd3f92deSKalle Valo 	struct cmd_ctrl_node *cmdarray;
451dd3f92deSKalle Valo 
452dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
453dd3f92deSKalle Valo 
454dd3f92deSKalle Valo 	/* Allocate and initialize the command array */
455dd3f92deSKalle Valo 	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
456dd3f92deSKalle Valo 	cmdarray = kzalloc(bufsize, GFP_KERNEL);
457dd3f92deSKalle Valo 	if (!cmdarray) {
458dd3f92deSKalle Valo 		lbtf_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
459dd3f92deSKalle Valo 		ret = -1;
460dd3f92deSKalle Valo 		goto done;
461dd3f92deSKalle Valo 	}
462dd3f92deSKalle Valo 	priv->cmd_array = cmdarray;
463dd3f92deSKalle Valo 
464dd3f92deSKalle Valo 	/* Allocate and initialize each command buffer in the command array */
465dd3f92deSKalle Valo 	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
466dd3f92deSKalle Valo 		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
467dd3f92deSKalle Valo 		if (!cmdarray[i].cmdbuf) {
468dd3f92deSKalle Valo 			lbtf_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
469dd3f92deSKalle Valo 			ret = -1;
470dd3f92deSKalle Valo 			goto done;
471dd3f92deSKalle Valo 		}
472dd3f92deSKalle Valo 	}
473dd3f92deSKalle Valo 
474dd3f92deSKalle Valo 	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
475dd3f92deSKalle Valo 		init_waitqueue_head(&cmdarray[i].cmdwait_q);
476dd3f92deSKalle Valo 		lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
477dd3f92deSKalle Valo 	}
478dd3f92deSKalle Valo 
479dd3f92deSKalle Valo 	ret = 0;
480dd3f92deSKalle Valo 
481dd3f92deSKalle Valo done:
482dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
483dd3f92deSKalle Valo 	return ret;
484dd3f92deSKalle Valo }
485dd3f92deSKalle Valo 
486dd3f92deSKalle Valo /**
487dd3f92deSKalle Valo  *  lbtf_free_cmd_buffer - Frees the cmd buffer.
488dd3f92deSKalle Valo  *
489dd3f92deSKalle Valo  *  @priv	A pointer to struct lbtf_private structure
490dd3f92deSKalle Valo  *
491dd3f92deSKalle Valo  *  Returns: 0
492dd3f92deSKalle Valo  */
493dd3f92deSKalle Valo int lbtf_free_cmd_buffer(struct lbtf_private *priv)
494dd3f92deSKalle Valo {
495dd3f92deSKalle Valo 	struct cmd_ctrl_node *cmdarray;
496dd3f92deSKalle Valo 	unsigned int i;
497dd3f92deSKalle Valo 
498dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
499dd3f92deSKalle Valo 
500dd3f92deSKalle Valo 	/* need to check if cmd array is allocated or not */
501dd3f92deSKalle Valo 	if (priv->cmd_array == NULL) {
502dd3f92deSKalle Valo 		lbtf_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
503dd3f92deSKalle Valo 		goto done;
504dd3f92deSKalle Valo 	}
505dd3f92deSKalle Valo 
506dd3f92deSKalle Valo 	cmdarray = priv->cmd_array;
507dd3f92deSKalle Valo 
508dd3f92deSKalle Valo 	/* Release shared memory buffers */
509dd3f92deSKalle Valo 	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
510dd3f92deSKalle Valo 		kfree(cmdarray[i].cmdbuf);
511dd3f92deSKalle Valo 		cmdarray[i].cmdbuf = NULL;
512dd3f92deSKalle Valo 	}
513dd3f92deSKalle Valo 
514dd3f92deSKalle Valo 	/* Release cmd_ctrl_node */
515dd3f92deSKalle Valo 	kfree(priv->cmd_array);
516dd3f92deSKalle Valo 	priv->cmd_array = NULL;
517dd3f92deSKalle Valo 
518dd3f92deSKalle Valo done:
519dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_HOST);
520dd3f92deSKalle Valo 	return 0;
521dd3f92deSKalle Valo }
522dd3f92deSKalle Valo 
523dd3f92deSKalle Valo /**
524dd3f92deSKalle Valo  *  lbtf_get_cmd_ctrl_node - Gets free cmd node from free cmd queue.
525dd3f92deSKalle Valo  *
526dd3f92deSKalle Valo  *  @priv		A pointer to struct lbtf_private structure
527dd3f92deSKalle Valo  *
528dd3f92deSKalle Valo  *  Returns: pointer to a struct cmd_ctrl_node or NULL if none available.
529dd3f92deSKalle Valo  */
530dd3f92deSKalle Valo static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
531dd3f92deSKalle Valo {
532dd3f92deSKalle Valo 	struct cmd_ctrl_node *tempnode;
533dd3f92deSKalle Valo 	unsigned long flags;
534dd3f92deSKalle Valo 
535dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
536dd3f92deSKalle Valo 
537dd3f92deSKalle Valo 	if (!priv)
538dd3f92deSKalle Valo 		return NULL;
539dd3f92deSKalle Valo 
540dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
541dd3f92deSKalle Valo 
542dd3f92deSKalle Valo 	if (!list_empty(&priv->cmdfreeq)) {
543dd3f92deSKalle Valo 		tempnode = list_first_entry(&priv->cmdfreeq,
544dd3f92deSKalle Valo 					    struct cmd_ctrl_node, list);
545dd3f92deSKalle Valo 		list_del(&tempnode->list);
546dd3f92deSKalle Valo 	} else {
547dd3f92deSKalle Valo 		lbtf_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
548dd3f92deSKalle Valo 		tempnode = NULL;
549dd3f92deSKalle Valo 	}
550dd3f92deSKalle Valo 
551dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
552dd3f92deSKalle Valo 
553dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_HOST);
554dd3f92deSKalle Valo 	return tempnode;
555dd3f92deSKalle Valo }
556dd3f92deSKalle Valo 
557dd3f92deSKalle Valo /**
558dd3f92deSKalle Valo  *  lbtf_execute_next_command: execute next command in cmd pending queue.
559dd3f92deSKalle Valo  *
560dd3f92deSKalle Valo  *  @priv     A pointer to struct lbtf_private structure
561dd3f92deSKalle Valo  *
562dd3f92deSKalle Valo  *  Returns: 0 on success.
563dd3f92deSKalle Valo  */
564dd3f92deSKalle Valo int lbtf_execute_next_command(struct lbtf_private *priv)
565dd3f92deSKalle Valo {
566dd3f92deSKalle Valo 	struct cmd_ctrl_node *cmdnode = NULL;
567dd3f92deSKalle Valo 	struct cmd_header *cmd;
568dd3f92deSKalle Valo 	unsigned long flags;
569dd3f92deSKalle Valo 	int ret = 0;
570dd3f92deSKalle Valo 
571dd3f92deSKalle Valo 	/* Debug group is lbtf_deb_THREAD and not lbtf_deb_HOST, because the
572dd3f92deSKalle Valo 	 * only caller to us is lbtf_thread() and we get even when a
573dd3f92deSKalle Valo 	 * data packet is received */
574dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_THREAD);
575dd3f92deSKalle Valo 
576dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
577dd3f92deSKalle Valo 
578dd3f92deSKalle Valo 	if (priv->cur_cmd) {
579dd3f92deSKalle Valo 		pr_alert("EXEC_NEXT_CMD: already processing command!\n");
580dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
581dd3f92deSKalle Valo 		ret = -1;
582dd3f92deSKalle Valo 		goto done;
583dd3f92deSKalle Valo 	}
584dd3f92deSKalle Valo 
585dd3f92deSKalle Valo 	if (!list_empty(&priv->cmdpendingq)) {
586dd3f92deSKalle Valo 		cmdnode = list_first_entry(&priv->cmdpendingq,
587dd3f92deSKalle Valo 					   struct cmd_ctrl_node, list);
588dd3f92deSKalle Valo 	}
589dd3f92deSKalle Valo 
590dd3f92deSKalle Valo 	if (cmdnode) {
591dd3f92deSKalle Valo 		cmd = cmdnode->cmdbuf;
592dd3f92deSKalle Valo 
593dd3f92deSKalle Valo 		list_del(&cmdnode->list);
594dd3f92deSKalle Valo 		lbtf_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
595dd3f92deSKalle Valo 			    le16_to_cpu(cmd->command));
596dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
597dd3f92deSKalle Valo 		lbtf_submit_command(priv, cmdnode);
598dd3f92deSKalle Valo 	} else
599dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
600dd3f92deSKalle Valo 
601dd3f92deSKalle Valo 	ret = 0;
602dd3f92deSKalle Valo done:
603dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_THREAD);
604dd3f92deSKalle Valo 	return ret;
605dd3f92deSKalle Valo }
606dd3f92deSKalle Valo 
607dd3f92deSKalle Valo static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
608dd3f92deSKalle Valo 	uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
609dd3f92deSKalle Valo 	int (*callback)(struct lbtf_private *, unsigned long,
610dd3f92deSKalle Valo 			struct cmd_header *),
611dd3f92deSKalle Valo 	unsigned long callback_arg)
612dd3f92deSKalle Valo {
613dd3f92deSKalle Valo 	struct cmd_ctrl_node *cmdnode;
614dd3f92deSKalle Valo 
615dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
616dd3f92deSKalle Valo 
617dd3f92deSKalle Valo 	if (priv->surpriseremoved) {
618dd3f92deSKalle Valo 		lbtf_deb_host("PREP_CMD: card removed\n");
619dd3f92deSKalle Valo 		cmdnode = ERR_PTR(-ENOENT);
620dd3f92deSKalle Valo 		goto done;
621dd3f92deSKalle Valo 	}
622dd3f92deSKalle Valo 
623dd3f92deSKalle Valo 	cmdnode = lbtf_get_cmd_ctrl_node(priv);
624dd3f92deSKalle Valo 	if (cmdnode == NULL) {
625dd3f92deSKalle Valo 		lbtf_deb_host("PREP_CMD: cmdnode is NULL\n");
626dd3f92deSKalle Valo 
627dd3f92deSKalle Valo 		/* Wake up main thread to execute next command */
628dd3f92deSKalle Valo 		queue_work(lbtf_wq, &priv->cmd_work);
629dd3f92deSKalle Valo 		cmdnode = ERR_PTR(-ENOBUFS);
630dd3f92deSKalle Valo 		goto done;
631dd3f92deSKalle Valo 	}
632dd3f92deSKalle Valo 
633dd3f92deSKalle Valo 	cmdnode->callback = callback;
634dd3f92deSKalle Valo 	cmdnode->callback_arg = callback_arg;
635dd3f92deSKalle Valo 
636dd3f92deSKalle Valo 	/* Copy the incoming command to the buffer */
637dd3f92deSKalle Valo 	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
638dd3f92deSKalle Valo 
639dd3f92deSKalle Valo 	/* Set sequence number, clean result, move to buffer */
640dd3f92deSKalle Valo 	priv->seqnum++;
641dd3f92deSKalle Valo 	cmdnode->cmdbuf->command = cpu_to_le16(command);
642dd3f92deSKalle Valo 	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
643dd3f92deSKalle Valo 	cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
644dd3f92deSKalle Valo 	cmdnode->cmdbuf->result  = 0;
645dd3f92deSKalle Valo 
646dd3f92deSKalle Valo 	lbtf_deb_host("PREP_CMD: command 0x%04x\n", command);
647dd3f92deSKalle Valo 
648dd3f92deSKalle Valo 	cmdnode->cmdwaitqwoken = 0;
649dd3f92deSKalle Valo 	lbtf_queue_cmd(priv, cmdnode);
650dd3f92deSKalle Valo 	queue_work(lbtf_wq, &priv->cmd_work);
651dd3f92deSKalle Valo 
652dd3f92deSKalle Valo  done:
653dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %p", cmdnode);
654dd3f92deSKalle Valo 	return cmdnode;
655dd3f92deSKalle Valo }
656dd3f92deSKalle Valo 
657dd3f92deSKalle Valo void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
658dd3f92deSKalle Valo 	struct cmd_header *in_cmd, int in_cmd_size)
659dd3f92deSKalle Valo {
660dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
661dd3f92deSKalle Valo 	__lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
662dd3f92deSKalle Valo 	lbtf_deb_leave(LBTF_DEB_CMD);
663dd3f92deSKalle Valo }
664dd3f92deSKalle Valo 
665dd3f92deSKalle Valo int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
666dd3f92deSKalle Valo 	      struct cmd_header *in_cmd, int in_cmd_size,
667dd3f92deSKalle Valo 	      int (*callback)(struct lbtf_private *,
668dd3f92deSKalle Valo 			      unsigned long, struct cmd_header *),
669dd3f92deSKalle Valo 	      unsigned long callback_arg)
670dd3f92deSKalle Valo {
671dd3f92deSKalle Valo 	struct cmd_ctrl_node *cmdnode;
672dd3f92deSKalle Valo 	unsigned long flags;
673dd3f92deSKalle Valo 	int ret = 0;
674dd3f92deSKalle Valo 
675dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_HOST);
676dd3f92deSKalle Valo 
677dd3f92deSKalle Valo 	cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
678dd3f92deSKalle Valo 				  callback, callback_arg);
679dd3f92deSKalle Valo 	if (IS_ERR(cmdnode)) {
680dd3f92deSKalle Valo 		ret = PTR_ERR(cmdnode);
681dd3f92deSKalle Valo 		goto done;
682dd3f92deSKalle Valo 	}
683dd3f92deSKalle Valo 
684dd3f92deSKalle Valo 	might_sleep();
685dd3f92deSKalle Valo 	ret = wait_event_interruptible(cmdnode->cmdwait_q,
686dd3f92deSKalle Valo 				       cmdnode->cmdwaitqwoken);
687dd3f92deSKalle Valo 	if (ret) {
688dd3f92deSKalle Valo 		pr_info("PREP_CMD: command 0x%04x interrupted by signal: %d\n",
689dd3f92deSKalle Valo 			    command, ret);
690dd3f92deSKalle Valo 		goto done;
691dd3f92deSKalle Valo 	}
692dd3f92deSKalle Valo 
693dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
694dd3f92deSKalle Valo 	ret = cmdnode->result;
695dd3f92deSKalle Valo 	if (ret)
696dd3f92deSKalle Valo 		pr_info("PREP_CMD: command 0x%04x failed: %d\n",
697dd3f92deSKalle Valo 			    command, ret);
698dd3f92deSKalle Valo 
699dd3f92deSKalle Valo 	__lbtf_cleanup_and_insert_cmd(priv, cmdnode);
700dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
701dd3f92deSKalle Valo 
702dd3f92deSKalle Valo done:
703dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
704dd3f92deSKalle Valo 	return ret;
705dd3f92deSKalle Valo }
706dd3f92deSKalle Valo EXPORT_SYMBOL_GPL(__lbtf_cmd);
707dd3f92deSKalle Valo 
708dd3f92deSKalle Valo /* Call holding driver_lock */
709dd3f92deSKalle Valo void lbtf_cmd_response_rx(struct lbtf_private *priv)
710dd3f92deSKalle Valo {
711dd3f92deSKalle Valo 	priv->cmd_response_rxed = 1;
712dd3f92deSKalle Valo 	queue_work(lbtf_wq, &priv->cmd_work);
713dd3f92deSKalle Valo }
714dd3f92deSKalle Valo EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx);
715dd3f92deSKalle Valo 
716dd3f92deSKalle Valo int lbtf_process_rx_command(struct lbtf_private *priv)
717dd3f92deSKalle Valo {
718dd3f92deSKalle Valo 	uint16_t respcmd, curcmd;
719dd3f92deSKalle Valo 	struct cmd_header *resp;
720dd3f92deSKalle Valo 	int ret = 0;
721dd3f92deSKalle Valo 	unsigned long flags;
722dd3f92deSKalle Valo 	uint16_t result;
723dd3f92deSKalle Valo 
724dd3f92deSKalle Valo 	lbtf_deb_enter(LBTF_DEB_CMD);
725dd3f92deSKalle Valo 
726dd3f92deSKalle Valo 	mutex_lock(&priv->lock);
727dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
728dd3f92deSKalle Valo 
729dd3f92deSKalle Valo 	if (!priv->cur_cmd) {
730dd3f92deSKalle Valo 		ret = -1;
731dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
732dd3f92deSKalle Valo 		goto done;
733dd3f92deSKalle Valo 	}
734dd3f92deSKalle Valo 
735dd3f92deSKalle Valo 	resp = (void *)priv->cmd_resp_buff;
736dd3f92deSKalle Valo 	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
737dd3f92deSKalle Valo 	respcmd = le16_to_cpu(resp->command);
738dd3f92deSKalle Valo 	result = le16_to_cpu(resp->result);
739dd3f92deSKalle Valo 
740*744972b2SLubomir Rintel 	lbtf_deb_cmd("libertastf: cmd response 0x%04x, seq %d, size %d\n",
741dd3f92deSKalle Valo 		     respcmd, le16_to_cpu(resp->seqnum),
742dd3f92deSKalle Valo 		     le16_to_cpu(resp->size));
743dd3f92deSKalle Valo 
744dd3f92deSKalle Valo 	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
745dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
746dd3f92deSKalle Valo 		ret = -1;
747dd3f92deSKalle Valo 		goto done;
748dd3f92deSKalle Valo 	}
749dd3f92deSKalle Valo 	if (respcmd != CMD_RET(curcmd)) {
750dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
751dd3f92deSKalle Valo 		ret = -1;
752dd3f92deSKalle Valo 		goto done;
753dd3f92deSKalle Valo 	}
754dd3f92deSKalle Valo 
755dd3f92deSKalle Valo 	if (resp->result == cpu_to_le16(0x0004)) {
756dd3f92deSKalle Valo 		/* 0x0004 means -EAGAIN. Drop the response, let it time out
757dd3f92deSKalle Valo 		   and be resubmitted */
758dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
759dd3f92deSKalle Valo 		ret = -1;
760dd3f92deSKalle Valo 		goto done;
761dd3f92deSKalle Valo 	}
762dd3f92deSKalle Valo 
763dd3f92deSKalle Valo 	/* Now we got response from FW, cancel the command timer */
764dd3f92deSKalle Valo 	del_timer(&priv->command_timer);
765dd3f92deSKalle Valo 	priv->cmd_timed_out = 0;
766dd3f92deSKalle Valo 	if (priv->nr_retries)
767dd3f92deSKalle Valo 		priv->nr_retries = 0;
768dd3f92deSKalle Valo 
769dd3f92deSKalle Valo 	/* If the command is not successful, cleanup and return failure */
770dd3f92deSKalle Valo 	if ((result != 0 || !(respcmd & 0x8000))) {
771dd3f92deSKalle Valo 		/*
772dd3f92deSKalle Valo 		 * Handling errors here
773dd3f92deSKalle Valo 		 */
774dd3f92deSKalle Valo 		switch (respcmd) {
775dd3f92deSKalle Valo 		case CMD_RET(CMD_GET_HW_SPEC):
776dd3f92deSKalle Valo 		case CMD_RET(CMD_802_11_RESET):
777dd3f92deSKalle Valo 			pr_info("libertastf: reset failed\n");
778dd3f92deSKalle Valo 			break;
779dd3f92deSKalle Valo 
780dd3f92deSKalle Valo 		}
781dd3f92deSKalle Valo 		lbtf_complete_command(priv, priv->cur_cmd, result);
782dd3f92deSKalle Valo 		spin_unlock_irqrestore(&priv->driver_lock, flags);
783dd3f92deSKalle Valo 
784dd3f92deSKalle Valo 		ret = -1;
785dd3f92deSKalle Valo 		goto done;
786dd3f92deSKalle Valo 	}
787dd3f92deSKalle Valo 
788dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
789dd3f92deSKalle Valo 
790dd3f92deSKalle Valo 	if (priv->cur_cmd && priv->cur_cmd->callback) {
791dd3f92deSKalle Valo 		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
792dd3f92deSKalle Valo 				resp);
793dd3f92deSKalle Valo 	}
794dd3f92deSKalle Valo 	spin_lock_irqsave(&priv->driver_lock, flags);
795dd3f92deSKalle Valo 
796dd3f92deSKalle Valo 	if (priv->cur_cmd) {
797dd3f92deSKalle Valo 		/* Clean up and Put current command back to cmdfreeq */
798dd3f92deSKalle Valo 		lbtf_complete_command(priv, priv->cur_cmd, result);
799dd3f92deSKalle Valo 	}
800dd3f92deSKalle Valo 	spin_unlock_irqrestore(&priv->driver_lock, flags);
801dd3f92deSKalle Valo 
802dd3f92deSKalle Valo done:
803dd3f92deSKalle Valo 	mutex_unlock(&priv->lock);
804dd3f92deSKalle Valo 	lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
805dd3f92deSKalle Valo 	return ret;
806dd3f92deSKalle Valo }
807