Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7919b89c authored by Holger Schurig's avatar Holger Schurig Committed by John W. Linville
Browse files

libertas: convert libertas driver to use an event/cmdresp queue



This patch (co-developed by Dan Williams and Holger Schurig) uses a kfifo
object for events and a swapping buffer scheme for the command response to
preserve the zero-copy semantics of the CF driver and keep memory usage low.
The main thread should only ever touch the buffer indexed by priv->resp_idx,
while the interface code is free to write to the second buffer, then swap
priv->resp_idx under the driver spinlock.  The firmware specs only permit
one in-flight command, so there will only ever be one command response to
process at a time.

Signed-off-by: default avatarHolger Schurig <hs4233@mail.mn-solutions.de>
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 98dd6a57
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
  */

#include <net/iw_handler.h>
#include <linux/kfifo.h>
#include "host.h"
#include "hostcmd.h"
#include "decl.h"
@@ -1829,15 +1830,20 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)

	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
		sizeof(confirm_sleep));

	if (ret) {
		lbs_pr_alert("confirm_sleep failed\n");
	} else {
		goto out;
	}

	spin_lock_irqsave(&priv->driver_lock, flags);
		if (!priv->intcounter)

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

	spin_unlock_irqrestore(&priv->driver_lock, flags);
	}

out:
	lbs_deb_leave(LBS_DEB_HOST);
}

@@ -1899,13 +1905,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
	}

	spin_lock_irqsave(&priv->driver_lock, flags);
	/* In-progress command? */
	if (priv->cur_cmd) {
		allowed = 0;
		lbs_deb_host("cur_cmd was set\n");
	}
	if (priv->intcounter > 0) {

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

+7 −16
Original line number Diff line number Diff line
@@ -384,7 +384,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
	return ret;
}

int lbs_process_rx_command(struct lbs_private *priv)
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
{
	uint16_t respcmd, curcmd;
	struct cmd_header *resp;
@@ -404,14 +404,14 @@ int lbs_process_rx_command(struct lbs_private *priv)
		goto done;
	}

	resp = (void *)priv->upld_buf;
	resp = (void *)data;
	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
	respcmd = le16_to_cpu(resp->command);
	result = le16_to_cpu(resp->result);

	lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
		     respcmd, le16_to_cpu(resp->seqnum), priv->upld_len);
	lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, priv->upld_len);
		     respcmd, le16_to_cpu(resp->seqnum), len);
	lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);

	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
		lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
@@ -569,18 +569,13 @@ static int lbs_send_confirmwake(struct lbs_private *priv)
	return ret;
}

int lbs_process_event(struct lbs_private *priv)
int lbs_process_event(struct lbs_private *priv, u32 event)
{
	int ret = 0;
	u32 eventcause;

	lbs_deb_enter(LBS_DEB_CMD);

	spin_lock_irq(&priv->driver_lock);
	eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
	spin_unlock_irq(&priv->driver_lock);

	switch (eventcause) {
	switch (event) {
	case MACREG_INT_CODE_LINK_SENSED:
		lbs_deb_cmd("EVENT: link sensed\n");
		break;
@@ -696,14 +691,10 @@ int lbs_process_event(struct lbs_private *priv)
		break;

	default:
		lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
		lbs_pr_alert("EVENT: unknown event id %d\n", event);
		break;
	}

	spin_lock_irq(&priv->driver_lock);
	priv->eventcause = 0;
	spin_unlock_irq(&priv->driver_lock);

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}
+0 −1
Original line number Diff line number Diff line
@@ -824,7 +824,6 @@ struct debug_data {
/* To debug any member of struct lbs_private, simply add one line here.
 */
static struct debug_data items[] = {
	{"intcounter", item_size(intcounter), item_addr(intcounter)},
	{"psmode", item_size(psmode), item_addr(psmode)},
	{"psstate", item_size(psstate), item_addr(psstate)},
};
+6 −4
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ struct cmd_ds_command;

void lbs_set_mac_control(struct lbs_private *priv);

void lbs_send_tx_feedback(struct lbs_private *priv);
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);

int lbs_free_cmd_buffer(struct lbs_private *priv);

@@ -30,14 +30,16 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,

int lbs_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv);
void lbs_interrupt(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);

int lbs_set_radio_control(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);

/** The proc fs interface */
int lbs_process_rx_command(struct lbs_private *priv);
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
			  int result);
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+0 −2
Original line number Diff line number Diff line
@@ -177,8 +177,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MRVDRV_CMD_UPLD_RDY		0x0008
#define MRVDRV_CARDEVENT		0x0010

#define SBI_EVENT_CAUSE_SHIFT		3

/** TxPD status */

/*	Station firmware use TxPD status field to report final Tx transmit
Loading