brintos

brintos / linux-shallow public Read only

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