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

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
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <linux/kfifo.h>
#include "host.h" #include "host.h"
#include "hostcmd.h" #include "hostcmd.h"
#include "decl.h" #include "decl.h"
...@@ -1829,15 +1830,20 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) ...@@ -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, ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
sizeof(confirm_sleep)); sizeof(confirm_sleep));
if (ret) { if (ret) {
lbs_pr_alert("confirm_sleep failed\n"); lbs_pr_alert("confirm_sleep failed\n");
} else { goto out;
spin_lock_irqsave(&priv->driver_lock, flags);
if (!priv->intcounter)
priv->psstate = PS_STATE_SLEEP;
spin_unlock_irqrestore(&priv->driver_lock, flags);
} }
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); lbs_deb_leave(LBS_DEB_HOST);
} }
...@@ -1899,13 +1905,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) ...@@ -1899,13 +1905,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
} }
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
/* In-progress command? */
if (priv->cur_cmd) { if (priv->cur_cmd) {
allowed = 0; allowed = 0;
lbs_deb_host("cur_cmd was set\n"); 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; 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); spin_unlock_irqrestore(&priv->driver_lock, flags);
......
...@@ -384,7 +384,7 @@ static inline int handle_cmd_response(struct lbs_private *priv, ...@@ -384,7 +384,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
return ret; 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; uint16_t respcmd, curcmd;
struct cmd_header *resp; struct cmd_header *resp;
...@@ -404,14 +404,14 @@ int lbs_process_rx_command(struct lbs_private *priv) ...@@ -404,14 +404,14 @@ int lbs_process_rx_command(struct lbs_private *priv)
goto done; goto done;
} }
resp = (void *)priv->upld_buf; resp = (void *)data;
curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
respcmd = le16_to_cpu(resp->command); respcmd = le16_to_cpu(resp->command);
result = le16_to_cpu(resp->result); result = le16_to_cpu(resp->result);
lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n", lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
respcmd, le16_to_cpu(resp->seqnum), priv->upld_len); respcmd, le16_to_cpu(resp->seqnum), len);
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, priv->upld_len); lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", 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) ...@@ -569,18 +569,13 @@ static int lbs_send_confirmwake(struct lbs_private *priv)
return ret; return ret;
} }
int lbs_process_event(struct lbs_private *priv) int lbs_process_event(struct lbs_private *priv, u32 event)
{ {
int ret = 0; int ret = 0;
u32 eventcause;
lbs_deb_enter(LBS_DEB_CMD); lbs_deb_enter(LBS_DEB_CMD);
spin_lock_irq(&priv->driver_lock); switch (event) {
eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
spin_unlock_irq(&priv->driver_lock);
switch (eventcause) {
case MACREG_INT_CODE_LINK_SENSED: case MACREG_INT_CODE_LINK_SENSED:
lbs_deb_cmd("EVENT: link sensed\n"); lbs_deb_cmd("EVENT: link sensed\n");
break; break;
...@@ -696,14 +691,10 @@ int lbs_process_event(struct lbs_private *priv) ...@@ -696,14 +691,10 @@ int lbs_process_event(struct lbs_private *priv)
break; break;
default: default:
lbs_pr_alert("EVENT: unknown event id %d\n", eventcause); lbs_pr_alert("EVENT: unknown event id %d\n", event);
break; 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); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret; return ret;
} }
...@@ -824,7 +824,6 @@ struct debug_data { ...@@ -824,7 +824,6 @@ struct debug_data {
/* To debug any member of struct lbs_private, simply add one line here. /* To debug any member of struct lbs_private, simply add one line here.
*/ */
static struct debug_data items[] = { static struct debug_data items[] = {
{"intcounter", item_size(intcounter), item_addr(intcounter)},
{"psmode", item_size(psmode), item_addr(psmode)}, {"psmode", item_size(psmode), item_addr(psmode)},
{"psstate", item_size(psstate), item_addr(psstate)}, {"psstate", item_size(psstate), item_addr(psstate)},
}; };
......
...@@ -19,7 +19,7 @@ struct cmd_ds_command; ...@@ -19,7 +19,7 @@ struct cmd_ds_command;
void lbs_set_mac_control(struct lbs_private *priv); 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); int lbs_free_cmd_buffer(struct lbs_private *priv);
...@@ -30,14 +30,16 @@ int lbs_prepare_and_send_command(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_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv); int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv); int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_interrupt(struct lbs_private *priv); 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); int lbs_set_radio_control(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index); u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate); u8 lbs_data_rate_to_fw_index(u32 rate);
/** The proc fs interface */ /** 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, void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result); int result);
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
......
...@@ -177,8 +177,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in ...@@ -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_CMD_UPLD_RDY 0x0008
#define MRVDRV_CARDEVENT 0x0010 #define MRVDRV_CARDEVENT 0x0010
#define SBI_EVENT_CAUSE_SHIFT 3
/** TxPD status */ /** TxPD status */
/* Station firmware use TxPD status field to report final Tx transmit /* Station firmware use TxPD status field to report final Tx transmit
......
...@@ -129,10 +129,6 @@ struct lbs_private { ...@@ -129,10 +129,6 @@ struct lbs_private {
u32 bbp_offset; u32 bbp_offset;
u32 rf_offset; u32 rf_offset;
/** Upload length */
u32 upld_len;
/* Upload buffer */
u8 upld_buf[LBS_UPLD_SIZE];
/* Download sent: /* Download sent:
bit0 1/0=data_sent/data_tx_done, bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done, bit1 1/0=cmd_sent/cmd_tx_done,
...@@ -155,21 +151,16 @@ struct lbs_private { ...@@ -155,21 +151,16 @@ struct lbs_private {
/** Hardware access */ /** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); 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 */ /* Wake On LAN */
uint32_t wol_criteria; uint32_t wol_criteria;
uint8_t wol_gpio; uint8_t wol_gpio;
uint8_t wol_gap; uint8_t wol_gap;
/* was struct lbs_adapter from here... */
/** Wlan adapter data structure*/ /** Wlan adapter data structure*/
/** STATUS variables */ /** STATUS variables */
u32 fwrelease; u32 fwrelease;
u32 fwcapinfo; u32 fwcapinfo;
/* protected with big lock */
struct mutex lock; struct mutex lock;
...@@ -181,7 +172,6 @@ struct lbs_private { ...@@ -181,7 +172,6 @@ struct lbs_private {
/** command-related variables */ /** command-related variables */
u16 seqnum; u16 seqnum;
/* protected by big lock */
struct cmd_ctrl_node *cmd_array; struct cmd_ctrl_node *cmd_array;
/** Current command */ /** Current command */
...@@ -194,12 +184,17 @@ struct lbs_private { ...@@ -194,12 +184,17 @@ struct lbs_private {
struct list_head cmdpendingq; struct list_head cmdpendingq;
wait_queue_head_t cmd_pending; wait_queue_head_t cmd_pending;
/* command related variables protected by priv->driver_lock */
/** Async and Sync Event variables */ /* Command responses sent from the hardware to the driver */
u32 intcounter; u8 resp_idx;
u32 eventcause; u8 resp_buf[2][LBS_UPLD_SIZE];
u8 nodename[16]; /* nickname */ u32 resp_len[2];
/* Events sent from hardware to driver */
struct kfifo *event_fifo;
/* nickname */
u8 nodename[16];
/** spin locks */ /** spin locks */
spinlock_t driver_lock; spinlock_t driver_lock;
...@@ -209,8 +204,6 @@ struct lbs_private { ...@@ -209,8 +204,6 @@ struct lbs_private {
int nr_retries; int nr_retries;
int cmd_timed_out; int cmd_timed_out;
u8 hisregcpy;
/** current ssid/bssid related parameters*/ /** current ssid/bssid related parameters*/
struct current_bss_params curbssparams; struct current_bss_params curbssparams;
......
This diff is collapsed.
...@@ -91,8 +91,6 @@ struct if_sdio_card { ...@@ -91,8 +91,6 @@ struct if_sdio_card {
const char *firmware; const char *firmware;
u8 buffer[65536]; u8 buffer[65536];
u8 int_cause;
u32 event;
spinlock_t lock; spinlock_t lock;
struct if_sdio_packet *packets; struct if_sdio_packet *packets;
...@@ -129,13 +127,13 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) ...@@ -129,13 +127,13 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
static int if_sdio_handle_cmd(struct if_sdio_card *card, static int if_sdio_handle_cmd(struct if_sdio_card *card,
u8 *buffer, unsigned size) u8 *buffer, unsigned size)
{ {
struct lbs_private *priv = card->priv;
int ret; int ret;
unsigned long flags; unsigned long flags;
u8 i;
lbs_deb_enter(LBS_DEB_SDIO); lbs_deb_enter(LBS_DEB_SDIO);
spin_lock_irqsave(&card->priv->driver_lock, flags);
if (size > LBS_CMD_BUFFER_SIZE) { if (size > LBS_CMD_BUFFER_SIZE) {
lbs_deb_sdio("response packet too large (%d bytes)\n", lbs_deb_sdio("response packet too large (%d bytes)\n",
(int)size); (int)size);
...@@ -143,20 +141,20 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card, ...@@ -143,20 +141,20 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
goto out; goto out;
} }
memcpy(card->priv->upld_buf, buffer, size); spin_lock_irqsave(&priv->driver_lock, flags);
card->priv->upld_len = size;
card->int_cause |= MRVDRV_CMD_UPLD_RDY; i = (priv->resp_idx == 0) ? 1 : 0;
BUG_ON(priv->resp_len[i]);
priv->resp_len[i] = size;
memcpy(priv->resp_buf[i], buffer, size);
lbs_notify_command_response(priv, i);
lbs_interrupt(card->priv); spin_unlock_irqrestore(&card->priv->driver_lock, flags);
ret = 0; ret = 0;
out: out:
spin_unlock_irqrestore(&card->priv->driver_lock, flags);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret; return ret;
} }
...@@ -202,7 +200,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card, ...@@ -202,7 +200,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
u8 *buffer, unsigned size) u8 *buffer, unsigned size)
{ {
int ret; int ret;
unsigned long flags;
u32 event; u32 event;
lbs_deb_enter(LBS_DEB_SDIO); lbs_deb_enter(LBS_DEB_SDIO);
...@@ -222,18 +219,9 @@ static int if_sdio_handle_event(struct if_sdio_card *card, ...@@ -222,18 +219,9 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
event |= buffer[2] << 16; event |= buffer[2] << 16;
event |= buffer[1] << 8; event |= buffer[1] << 8;
event |= buffer[0] << 0; event |= buffer[0] << 0;
event <<= SBI_EVENT_CAUSE_SHIFT;
} }
spin_lock_irqsave(&card->priv->driver_lock, flags); lbs_queue_event(card->priv, event & 0xFF);
card->event = event;
card->int_cause |= MRVDRV_CARDEVENT;
lbs_interrupt(card->priv);
spin_unlock_irqrestore(&card->priv->driver_lock, flags);
ret = 0; ret = 0;
out: out:
...@@ -770,37 +758,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv, ...@@ -770,37 +758,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
return ret; return ret;
} }
static int if_sdio_get_int_status(struct lbs_private *priv, u8 *ireg)
{
struct if_sdio_card *card;
lbs_deb_enter(LBS_DEB_SDIO);
card = priv->card;
*ireg = card->int_cause;
card->int_cause = 0;
lbs_deb_leave(LBS_DEB_SDIO);
return 0;
}
static int if_sdio_read_event_cause(struct lbs_private *priv)
{
struct if_sdio_card *card;
lbs_deb_enter(LBS_DEB_SDIO);
card = priv->card;
priv->eventcause = card->event;
lbs_deb_leave(LBS_DEB_SDIO);
return 0;
}
/*******************************************************************/ /*******************************************************************/
/* SDIO callbacks */ /* SDIO callbacks */
/*******************************************************************/ /*******************************************************************/
...@@ -953,8 +910,6 @@ static int if_sdio_probe(struct sdio_func *func, ...@@ -953,8 +910,6 @@ static int if_sdio_probe(struct sdio_func *func,
priv->card = card; priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card; priv->hw_host_to_card = if_sdio_host_to_card;
priv->hw_get_int_status = if_sdio_get_int_status;
priv->hw_read_event_cause = if_sdio_read_event_cause;
priv->fw_ready = 1; priv->fw_ready = 1;
......
...@@ -38,8 +38,6 @@ static void if_usb_receive_fwload(struct urb *urb); ...@@ -38,8 +38,6 @@ static void if_usb_receive_fwload(struct urb *urb);
static int if_usb_prog_firmware(struct if_usb_card *cardp); static int if_usb_prog_firmware(struct if_usb_card *cardp);
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
uint8_t *payload, uint16_t nb); uint8_t *payload, uint16_t nb);
static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
static int if_usb_read_event_cause(struct lbs_private *);
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
uint16_t nb); uint16_t nb);
static void if_usb_free(struct if_usb_card *cardp); static void if_usb_free(struct if_usb_card *cardp);
...@@ -233,8 +231,6 @@ static int if_usb_probe(struct usb_interface *intf, ...@@ -233,8 +231,6 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1; cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card; priv->hw_host_to_card = if_usb_host_to_card;
priv->hw_get_int_status = if_usb_get_int_status;
priv->hw_read_event_cause = if_usb_read_event_cause;
cardp->boot2_version = udev->descriptor.bcdDevice; cardp->boot2_version = udev->descriptor.bcdDevice;
if_usb_submit_rx_urb(cardp); if_usb_submit_rx_urb(cardp);
...@@ -582,7 +578,6 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, ...@@ -582,7 +578,6 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
skb_pull(skb, MESSAGE_HEADER_LEN); skb_pull(skb, MESSAGE_HEADER_LEN);
lbs_process_rxed_packet(priv, skb); lbs_process_rxed_packet(priv, skb);
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
} }
static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
...@@ -590,6 +585,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, ...@@ -590,6 +585,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
struct if_usb_card *cardp, struct if_usb_card *cardp,
struct lbs_private *priv) struct lbs_private *priv)
{ {
u8 i;
if (recvlength > LBS_CMD_BUFFER_SIZE) { if (recvlength > LBS_CMD_BUFFER_SIZE) {
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
"The receive buffer is too large\n"); "The receive buffer is too large\n");
...@@ -601,12 +598,15 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, ...@@ -601,12 +598,15 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
BUG(); BUG();
spin_lock(&priv->driver_lock); spin_lock(&priv->driver_lock);
cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
i = (priv->resp_idx == 0) ? 1 : 0;
BUG_ON(priv->resp_len[i]);
priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
priv->resp_len[i]);
kfree_skb(skb); kfree_skb(skb);
lbs_interrupt(priv); lbs_notify_command_response(priv, i);
spin_unlock(&priv->driver_lock); spin_unlock(&priv->driver_lock);
lbs_deb_usbd(&cardp->udev->dev, lbs_deb_usbd(&cardp->udev->dev,
...@@ -629,6 +629,7 @@ static void if_usb_receive(struct urb *urb) ...@@ -629,6 +629,7 @@ static void if_usb_receive(struct urb *urb)
uint8_t *recvbuff = NULL; uint8_t *recvbuff = NULL;
uint32_t recvtype = 0; uint32_t recvtype = 0;
__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
uint32_t event;
lbs_deb_enter(LBS_DEB_USB); lbs_deb_enter(LBS_DEB_USB);
...@@ -660,26 +661,20 @@ static void if_usb_receive(struct urb *urb) ...@@ -660,26 +661,20 @@ static void if_usb_receive(struct urb *urb)
break; break;
case CMD_TYPE_INDICATION: case CMD_TYPE_INDICATION:
/* Event cause handling */ /* Event handling */
spin_lock(&priv->driver_lock); event = le32_to_cpu(pkt[1]);
lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
kfree_skb(skb);
cardp->usb_event_cause = le32_to_cpu(pkt[1]); /* Icky undocumented magic special case */
if (event & 0xffff0000) {
u32 trycount = (event & 0xffff0000) >> 16;
lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n", lbs_send_tx_feedback(priv, trycount);
cardp->usb_event_cause); } else
lbs_queue_event(priv, event & 0xFF);
break;
/* Icky undocumented magic special case */
if (cardp->usb_event_cause & 0xffff0000) {
lbs_send_tx_feedback(priv);
spin_unlock(&priv->driver_lock);
break;
}
cardp->usb_event_cause <<= 3;
cardp->usb_int_cause |= MRVDRV_CARDEVENT;
kfree_skb(skb);
lbs_interrupt(priv);
spin_unlock(&priv->driver_lock);
goto rx_exit;
default: default:
lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
recvtype); recvtype);
...@@ -722,30 +717,6 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, ...@@ -722,30 +717,6 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN); return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
} }
/* called with priv->driver_lock held */
static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
{
struct if_usb_card *cardp = priv->card;
*ireg = cardp->usb_int_cause;
cardp->usb_int_cause = 0;
lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
return 0;
}
static int if_usb_read_event_cause(struct lbs_private *priv)
{
struct if_usb_card *cardp = priv->card;
priv->eventcause = cardp->usb_event_cause;
/* Re-submit rx urb here to avoid event lost issue */
if_usb_submit_rx_urb(cardp);
return 0;
}
/** /**
* @brief This function issues Boot command to the Boot2 code * @brief This function issues Boot command to the Boot2 code
* @param ivalue 1:Boot from FW by USB-Download * @param ivalue 1:Boot from FW by USB-Download
......
...@@ -46,8 +46,6 @@ struct if_usb_card { ...@@ -46,8 +46,6 @@ struct if_usb_card {
struct lbs_private *priv; struct lbs_private *priv;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
uint32_t usb_event_cause;
uint8_t usb_int_cause;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_out; uint8_t ep_out;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/kfifo.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <net/ieee80211.h> #include <net/ieee80211.h>
...@@ -480,10 +481,9 @@ static void lbs_tx_timeout(struct net_device *dev) ...@@ -480,10 +481,9 @@ static void lbs_tx_timeout(struct net_device *dev)
dev->trans_start = jiffies; dev->trans_start = jiffies;
if (priv->currenttxskb) { if (priv->currenttxskb)
priv->eventcause = 0x01000000; lbs_send_tx_feedback(priv, 0);
lbs_send_tx_feedback(priv);
}
/* XX: Shouldn't we also call into the hw-specific driver /* XX: Shouldn't we also call into the hw-specific driver
to kick it somehow? */ to kick it somehow? */
lbs_host_to_card_done(priv); lbs_host_to_card_done(priv);
...@@ -659,7 +659,6 @@ static int lbs_thread(void *data) ...@@ -659,7 +659,6 @@ static int lbs_thread(void *data)
struct net_device *dev = data; struct net_device *dev = data;
struct lbs_private *priv = dev->priv; struct lbs_private *priv = dev->priv;
wait_queue_t wait; wait_queue_t wait;
u8 ireg = 0;
lbs_deb_enter(LBS_DEB_THREAD); lbs_deb_enter(LBS_DEB_THREAD);
...@@ -667,9 +666,10 @@ static int lbs_thread(void *data) ...@@ -667,9 +666,10 @@ static int lbs_thread(void *data)
for (;;) { for (;;) {
int shouldsleep; int shouldsleep;
u8 resp_idx;
lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n", lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent); priv->currenttxskb, priv->dnld_sent);
add_wait_queue(&priv->waitq, &wait); add_wait_queue(&priv->waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
...@@ -681,8 +681,6 @@ static int lbs_thread(void *data) ...@@ -681,8 +681,6 @@ static int lbs_thread(void *data)
shouldsleep = 1; /* We need to wait until we're _told_ to die */ shouldsleep = 1; /* We need to wait until we're _told_ to die */
else if (priv->psstate == PS_STATE_SLEEP) else if (priv->psstate == PS_STATE_SLEEP)
shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
else if (priv->intcounter)
shouldsleep = 0; /* Interrupt pending. Deal with it now */
else if (priv->cmd_timed_out) else if (priv->cmd_timed_out)
shouldsleep = 0; /* Command timed out. Recover */ shouldsleep = 0; /* Command timed out. Recover */
else if (!priv->fw_ready) else if (!priv->fw_ready)
...@@ -695,29 +693,34 @@ static int lbs_thread(void *data) ...@@ -695,29 +693,34 @@ static int lbs_thread(void *data)
shouldsleep = 1; /* Can't send a command; one already running */ shouldsleep = 1; /* Can't send a command; one already running */
else if (!list_empty(&priv->cmdpendingq)) else if (!list_empty(&priv->cmdpendingq))
shouldsleep = 0; /* We have a command to send */ shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
else if (priv->resp_len[priv->resp_idx])
shouldsleep = 0; /* We have a command response */
else else
shouldsleep = 1; /* No command */ shouldsleep = 1; /* No command */
if (shouldsleep) { if (shouldsleep) {
lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", lbs_deb_thread("sleeping, connect_status %d, "
priv->connect_status, priv->intcounter, "ps_mode %d, ps_state %d\n",
priv->psmode, priv->psstate); priv->connect_status,
priv->psmode, priv->psstate);
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
schedule(); schedule();
} else } else
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n", lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent); priv->currenttxskb, priv->dnld_sent);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&priv->waitq, &wait); remove_wait_queue(&priv->waitq, &wait);
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n", lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent); priv->currenttxskb, priv->dnld_sent);
if (kthread_should_stop()) { if (kthread_should_stop()) {
lbs_deb_thread("main-thread: break from main thread\n"); lbs_deb_thread("break from main thread\n");
break; break;
} }
...@@ -726,35 +729,23 @@ static int lbs_thread(void *data) ...@@ -726,35 +729,23 @@ static int lbs_thread(void *data)
continue; continue;
} }
spin_lock_irq(&priv->driver_lock); lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
priv->currenttxskb, priv->dnld_sent);
if (priv->intcounter) {
u8 int_status;
priv->intcounter = 0; spin_lock_irq(&priv->driver_lock);
int_status = priv->hw_get_int_status(priv, &ireg); /* Process any pending command response */
resp_idx = priv->resp_idx;
if (int_status) { if (priv->resp_len[resp_idx]) {
lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n");
spin_unlock_irq(&priv->driver_lock);
continue;
}
priv->hisregcpy |= ireg;
}
lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
/* command response? */
if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
lbs_deb_thread("main-thread: cmd response ready\n");
priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
lbs_process_rx_command(priv); lbs_process_command_response(priv,
priv->resp_buf[resp_idx],
priv->resp_len[resp_idx]);
spin_lock_irq(&priv->driver_lock); spin_lock_irq(&priv->driver_lock);
priv->resp_len[resp_idx] = 0;
} }
spin_unlock_irq(&priv->driver_lock);
/* command timeout stuff */
if (priv->cmd_timed_out && priv->cur_cmd) { if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd; struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
...@@ -775,21 +766,18 @@ static int lbs_thread(void *data) ...@@ -775,21 +766,18 @@ static int lbs_thread(void *data)
} }
priv->cmd_timed_out = 0; priv->cmd_timed_out = 0;
/* Any Card Event */ /* Process hardware events, e.g. card removed, link lost */
if (priv->hisregcpy & MRVDRV_CARDEVENT) { spin_lock_irq(&priv->driver_lock);
lbs_deb_thread("main-thread: Card Event Activity\n"); while (__kfifo_len(priv->event_fifo)) {
u32 event;
priv->hisregcpy &= ~MRVDRV_CARDEVENT;
if (priv->hw_read_event_cause(priv)) { __kfifo_get(priv->event_fifo, (unsigned char *) &event,
lbs_pr_alert("main-thread: hw_read_event_cause failed\n"); sizeof(event));
spin_unlock_irq(&priv->driver_lock);
continue;
}
spin_unlock_irq(&priv->driver_lock);
lbs_process_event(priv);
} else
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
lbs_process_event(priv, event);
spin_lock_irq(&priv->driver_lock);
}
spin_unlock_irq(&priv->driver_lock);
if (!priv->fw_ready) if (!priv->fw_ready)
continue; continue;
...@@ -798,8 +786,10 @@ static int lbs_thread(void *data) ...@@ -798,8 +786,10 @@ static int lbs_thread(void *data)
if (priv->psstate == PS_STATE_PRE_SLEEP && if (priv->psstate == PS_STATE_PRE_SLEEP &&
!priv->dnld_sent && !priv->cur_cmd) { !priv->dnld_sent && !priv->cur_cmd) {
if (priv->connect_status == LBS_CONNECTED) { if (priv->connect_status == LBS_CONNECTED) {
lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n", lbs_deb_thread("pre-sleep, currenttxskb %p, "
priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd); "dnld_sent %d, cur_cmd %p\n",
priv->currenttxskb, priv->dnld_sent,
priv->cur_cmd);
lbs_ps_confirm_sleep(priv); lbs_ps_confirm_sleep(priv);
} else { } else {
...@@ -809,7 +799,8 @@ static int lbs_thread(void *data) ...@@ -809,7 +799,8 @@ static int lbs_thread(void *data)
* after firmware fixes it * after firmware fixes it
*/ */
priv->psstate = PS_STATE_AWAKE; priv->psstate = PS_STATE_AWAKE;
lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n"); lbs_pr_alert("ignore PS_SleepConfirm in "
"non-connected state\n");
} }
} }
...@@ -1046,7 +1037,18 @@ static int lbs_init_adapter(struct lbs_private *priv) ...@@ -1046,7 +1037,18 @@ static int lbs_init_adapter(struct lbs_private *priv)
/* Allocate the command buffers */ /* Allocate the command buffers */
if (lbs_allocate_cmd_buffer(priv)) { if (lbs_allocate_cmd_buffer(priv)) {
lbs_pr_err("Out of memory allocating command buffers\n"); lbs_pr_err("Out of memory allocating command buffers\n");
ret = -1; ret = -ENOMEM;
goto out;
}
priv->resp_idx = 0;
priv->resp_len[0] = priv->resp_len[1] = 0;
/* Create the event FIFO */
priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
if (IS_ERR(priv->event_fifo)) {
lbs_pr_err("Out of memory allocating event FIFO buffer\n");
ret = -ENOMEM;
goto out;
} }
out: out:
...@@ -1060,6 +1062,8 @@ static void lbs_free_adapter(struct lbs_private *priv) ...@@ -1060,6 +1062,8 @@ static void lbs_free_adapter(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MAIN); lbs_deb_enter(LBS_DEB_MAIN);
lbs_free_cmd_buffer(priv); lbs_free_cmd_buffer(priv);
if (priv->event_fifo)
kfifo_free(priv->event_fifo);
del_timer(&priv->command_timer); del_timer(&priv->command_timer);
kfree(priv->networks); kfree(priv->networks);
priv->networks = NULL; priv->networks = NULL;
...@@ -1434,27 +1438,41 @@ int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) ...@@ -1434,27 +1438,41 @@ int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
return ret; return ret;
} }
/** void lbs_queue_event(struct lbs_private *priv, u32 event)
* @brief This function handles the interrupt. it will change PS {
* state if applicable. it will wake up main_thread to handle unsigned long flags;
* the interrupt event as well.
* lbs_deb_enter(LBS_DEB_THREAD);
* @param dev A pointer to net_device structure spin_lock_irqsave(&priv->driver_lock, flags);
* @return n/a
*/ if (priv->psstate == PS_STATE_SLEEP)
void lbs_interrupt(struct lbs_private *priv) priv->psstate = PS_STATE_AWAKE;
__kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32));
wake_up_interruptible(&priv->waitq);
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(lbs_queue_event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
{ {
lbs_deb_enter(LBS_DEB_THREAD); lbs_deb_enter(LBS_DEB_THREAD);
lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
priv->intcounter++;
if (priv->psstate == PS_STATE_SLEEP) if (priv->psstate == PS_STATE_SLEEP)
priv->psstate = PS_STATE_AWAKE; priv->psstate = PS_STATE_AWAKE;
/* Swap buffers by flipping the response index */
BUG_ON(resp_idx > 1);
priv->resp_idx = resp_idx;
wake_up_interruptible(&priv->waitq); wake_up_interruptible(&priv->waitq);
lbs_deb_leave(LBS_DEB_THREAD); lbs_deb_leave(LBS_DEB_THREAD);
} }
EXPORT_SYMBOL_GPL(lbs_interrupt); EXPORT_SYMBOL_GPL(lbs_notify_command_response);
static int __init lbs_init_module(void) static int __init lbs_init_module(void)
{ {
......
...@@ -145,14 +145,14 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) ...@@ -145,14 +145,14 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
struct rxpackethdr *p_rx_pkt; struct rxpackethdr *p_rx_pkt;
struct rxpd *p_rx_pd; struct rxpd *p_rx_pd;
int hdrchop; int hdrchop;
struct ethhdr *p_ethhdr; struct ethhdr *p_ethhdr;
const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
lbs_deb_enter(LBS_DEB_RX); lbs_deb_enter(LBS_DEB_RX);
BUG_ON(!skb);
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
if (priv->monitormode) if (priv->monitormode)
......
...@@ -179,31 +179,17 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -179,31 +179,17 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
* *
* @returns void * @returns void
*/ */
void lbs_send_tx_feedback(struct lbs_private *priv) void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
{ {
struct tx_radiotap_hdr *radiotap_hdr; struct tx_radiotap_hdr *radiotap_hdr;
u32 status = priv->eventcause;
int txfail;
int try_count;
if (!priv->monitormode || priv->currenttxskb == NULL) if (!priv->monitormode || priv->currenttxskb == NULL)
return; return;
radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
txfail = (status >> 24); radiotap_hdr->data_retries = try_count ?
(1 + priv->txretrycount - try_count) : 0;
#if 0
/* The version of roofnet that we've tested does not use this yet
* But it may be used in the future.
*/
if (txfail)
radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
#endif
try_count = (status >> 16) & 0xff;
radiotap_hdr->data_retries = (try_count) ?
(1 + priv->txretrycount - try_count) : 0;
priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
priv->rtap_net_dev); priv->rtap_net_dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment