Skip to content

Commit

Permalink
libertas: convert libertas driver to use an event/cmdresp queue
Browse files Browse the repository at this point in the history
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: Holger Schurig <hs4233@mail.mn-solutions.de>
Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Holger Schurig authored and John W. Linville committed Apr 16, 2008
1 parent 98dd6a5 commit 7919b89
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 383 deletions.
25 changes: 17 additions & 8 deletions drivers/net/wireless/libertas/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include <net/iw_handler.h>
#include <linux/kfifo.h>
#include "host.h"
#include "hostcmd.h"
#include "decl.h"
Expand Down Expand Up @@ -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 {
spin_lock_irqsave(&priv->driver_lock, flags);
if (!priv->intcounter)
priv->psstate = PS_STATE_SLEEP;
spin_unlock_irqrestore(&priv->driver_lock, flags);
goto out;
}

spin_lock_irqsave(&priv->driver_lock, flags);

/* 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);
}

Expand Down Expand Up @@ -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);

Expand Down
23 changes: 7 additions & 16 deletions drivers/net/wireless/libertas/cmdresp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
1 change: 0 additions & 1 deletion drivers/net/wireless/libertas/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
};
Expand Down
10 changes: 6 additions & 4 deletions drivers/net/wireless/libertas/decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions drivers/net/wireless/libertas/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 10 additions & 17 deletions drivers/net/wireless/libertas/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,6 @@ struct lbs_private {
u32 bbp_offset;
u32 rf_offset;

/** Upload length */
u32 upld_len;
/* Upload buffer */
u8 upld_buf[LBS_UPLD_SIZE];
/* Download sent:
bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done,
Expand All @@ -155,21 +151,16 @@ struct lbs_private {

/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
int (*hw_read_event_cause) (struct lbs_private *);

/* Wake On LAN */
uint32_t wol_criteria;
uint8_t wol_gpio;
uint8_t wol_gap;

/* was struct lbs_adapter from here... */

/** Wlan adapter data structure*/
/** STATUS variables */
u32 fwrelease;
u32 fwcapinfo;
/* protected with big lock */

struct mutex lock;

Expand All @@ -181,7 +172,6 @@ struct lbs_private {

/** command-related variables */
u16 seqnum;
/* protected by big lock */

struct cmd_ctrl_node *cmd_array;
/** Current command */
Expand All @@ -194,12 +184,17 @@ struct lbs_private {
struct list_head cmdpendingq;

wait_queue_head_t cmd_pending;
/* command related variables protected by priv->driver_lock */

/** Async and Sync Event variables */
u32 intcounter;
u32 eventcause;
u8 nodename[16]; /* nickname */
/* Command responses sent from the hardware to the driver */
u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2];

/* Events sent from hardware to driver */
struct kfifo *event_fifo;

/* nickname */
u8 nodename[16];

/** spin locks */
spinlock_t driver_lock;
Expand All @@ -209,8 +204,6 @@ struct lbs_private {
int nr_retries;
int cmd_timed_out;

u8 hisregcpy;

/** current ssid/bssid related parameters*/
struct current_bss_params curbssparams;

Expand Down
Loading

0 comments on commit 7919b89

Please sign in to comment.