Search Linux Wireless

Re: [RFC] libertas: convert libertas driver to use an event/cmdresp queue

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2008-04-01 at 14:50 +0200, Holger Schurig wrote:
> [RFC] 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: Holger Schurig <hs4233@xxxxxxxxxxxxxxxxxxxx>

Signed-off-by: Dan Williams <dcbw@xxxxxxxxxx>

> ---
> 
> Dan, I hope it's OK to do ping-ponging of the signed-off-by line. Actually,
> we'd need a
> 
> Signed-off-by: Holger Schurig <hs4233@xxxxxxxxxxxxxxxxxxxx>, Dan Williams <dcbw@xxxxxxxxxx>
> 
> but I doubt that this is allowed :-)
> 
> 
> 
> The patch has been made (almost) checkpatch.pl clean, just one
> silly 80 lines violation which doesn't make sense to convert.
> I've also checked with
> 
>    make modules SUBDIRS=drivers/net/wireless/libertas C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
> 
> the ISR in if_cs.c has been changed again to be more like the old
> if_cs_get_int_status().
> 
> 
> Index: wireless-testing/drivers/net/wireless/libertas/cmd.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/cmd.c	2008-04-01 10:44:49.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/cmd.c	2008-04-01 12:37:04.000000000 +0200
> @@ -4,6 +4,7 @@
>    */
>  
>  #include <net/iw_handler.h>
> +#include <linux/kfifo.h>
>  #include "host.h"
>  #include "hostcmd.h"
>  #include "decl.h"
> @@ -1826,15 +1827,20 @@ static void lbs_send_confirmsleep(struct
>  
>  	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);
>  }
>  
> @@ -1896,13 +1902,16 @@ void lbs_ps_confirm_sleep(struct lbs_pri
>  	}
>  
>  	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);
>  
> Index: wireless-testing/drivers/net/wireless/libertas/cmdresp.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/cmdresp.c	2008-04-01 10:44:49.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/cmdresp.c	2008-04-01 10:44:49.000000000 +0200
> @@ -341,7 +341,7 @@ static inline int handle_cmd_response(st
>  	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;
> @@ -361,14 +361,14 @@ int lbs_process_rx_command(struct lbs_pr
>  		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",
> @@ -526,18 +526,13 @@ static int lbs_send_confirmwake(struct l
>  	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;
> @@ -653,14 +648,10 @@ int lbs_process_event(struct lbs_private
>  		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;
>  }
> Index: wireless-testing/drivers/net/wireless/libertas/debugfs.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/debugfs.c	2008-04-01 10:43:11.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/debugfs.c	2008-04-01 10:44:49.000000000 +0200
> @@ -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)},
>  };
> Index: wireless-testing/drivers/net/wireless/libertas/decl.h
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/decl.h	2008-04-01 10:44:49.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/decl.h	2008-04-01 10:44:49.000000000 +0200
> @@ -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,8 +30,10 @@ int lbs_prepare_and_send_command(struct 
>  
>  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);
> @@ -40,7 +42,7 @@ void lbs_get_fwversion(struct lbs_privat
>  	int maxlen);
>  
>  /** 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);
> Index: wireless-testing/drivers/net/wireless/libertas/defs.h
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/defs.h	2008-04-01 10:43:11.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/defs.h	2008-04-01 10:44:49.000000000 +0200
> @@ -177,8 +177,6 @@ static inline void lbs_deb_hex(unsigned 
>  #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
> Index: wireless-testing/drivers/net/wireless/libertas/dev.h
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/dev.h	2008-04-01 10:44:49.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/dev.h	2008-04-01 10:44:49.000000000 +0200
> @@ -128,10 +128,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,
> @@ -154,21 +150,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;
>  
> @@ -180,7 +171,6 @@ struct lbs_private {
>  
>  	/** command-related variables */
>  	u16 seqnum;
> -	/* protected by big lock */
>  
>  	struct cmd_ctrl_node *cmd_array;
>  	/** Current command */
> @@ -193,12 +183,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;
> @@ -208,8 +203,6 @@ struct lbs_private {
>  	int nr_retries;
>  	int cmd_timed_out;
>  
> -	u8 hisregcpy;
> -
>  	/** current ssid/bssid related parameters*/
>  	struct current_bss_params curbssparams;
>  
> Index: wireless-testing/drivers/net/wireless/libertas/if_cs.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/if_cs.c	2008-04-01 10:43:11.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/if_cs.c	2008-04-01 12:37:30.000000000 +0200
> @@ -83,14 +83,14 @@ static inline unsigned int if_cs_read8(s
>  {
>  	unsigned int val = ioread8(card->iobase + reg);
>  	if (debug_output)
> -		printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
> +		printk(KERN_INFO "inb %08x<%02x\n", reg, val);
>  	return val;
>  }
>  static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
>  {
>  	unsigned int val = ioread16(card->iobase + reg);
>  	if (debug_output)
> -		printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
> +		printk(KERN_INFO "inw %08x<%04x\n", reg, val);
>  	return val;
>  }
>  static inline void if_cs_read16_rep(
> @@ -100,7 +100,7 @@ static inline void if_cs_read16_rep(
>  	unsigned long count)
>  {
>  	if (debug_output)
> -		printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
> +		printk(KERN_INFO "insw %08x<(0x%lx words)\n",
>  			reg, count);
>  	ioread16_rep(card->iobase + reg, buf, count);
>  }
> @@ -108,14 +108,14 @@ static inline void if_cs_read16_rep(
>  static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
>  {
>  	if (debug_output)
> -		printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
> +		printk(KERN_INFO "outb %08x>%02x\n", reg, val);
>  	iowrite8(val, card->iobase + reg);
>  }
>  
>  static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
>  {
>  	if (debug_output)
> -		printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
> +		printk(KERN_INFO "outw %08x>%04x\n", reg, val);
>  	iowrite16(val, card->iobase + reg);
>  }
>  
> @@ -126,7 +126,7 @@ static inline void if_cs_write16_rep(
>  	unsigned long count)
>  {
>  	if (debug_output)
> -		printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
> +		printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
>  			reg, count);
>  	iowrite16_rep(card->iobase + reg, buf, count);
>  }
> @@ -199,17 +199,6 @@ static int if_cs_poll_while_fw_download(
>  #define IF_CS_C_S_CARDEVENT		0x0010
>  #define IF_CS_C_S_MASK			0x001f
>  #define IF_CS_C_S_STATUS_MASK		0x7f00
> -/* The following definitions should be the same as the MRVDRV_ ones */
> -
> -#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
> -#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
> -#endif
> -#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
> -#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
> -#endif
> -#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
> -#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
> -#endif
>  
>  #define IF_CS_C_INT_CAUSE		0x00000022
>  #define	IF_CS_C_IC_MASK			0x001f
> @@ -226,55 +215,6 @@ static int if_cs_poll_while_fw_download(
>  
> 
>  /********************************************************************/
> -/* Interrupts                                                       */
> -/********************************************************************/
> -
> -static inline void if_cs_enable_ints(struct if_cs_card *card)
> -{
> -	lbs_deb_enter(LBS_DEB_CS);
> -	if_cs_write16(card, IF_CS_H_INT_MASK, 0);
> -}
> -
> -static inline void if_cs_disable_ints(struct if_cs_card *card)
> -{
> -	lbs_deb_enter(LBS_DEB_CS);
> -	if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
> -}
> -
> -static irqreturn_t if_cs_interrupt(int irq, void *data)
> -{
> -	struct if_cs_card *card = data;
> -	u16 int_cause;
> -
> -	lbs_deb_enter(LBS_DEB_CS);
> -
> -	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
> -	if (int_cause == 0x0) {
> -		/* Not for us */
> -		return IRQ_NONE;
> -
> -	} else if (int_cause == 0xffff) {
> -		/* Read in junk, the card has probably been removed */
> -		card->priv->surpriseremoved = 1;
> -		return IRQ_HANDLED;
> -	} else {
> -		if (int_cause & IF_CS_H_IC_TX_OVER)
> -			lbs_host_to_card_done(card->priv);
> -
> -		/* clear interrupt */
> -		if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
> -	}
> -	spin_lock(&card->priv->driver_lock);
> -	lbs_interrupt(card->priv);
> -	spin_unlock(&card->priv->driver_lock);
> -
> -	return IRQ_HANDLED;
> -}
> -
> -
> -
> -
> -/********************************************************************/
>  /* I/O                                                              */
>  /********************************************************************/
>  
> @@ -351,6 +291,7 @@ static void if_cs_send_data(struct lbs_p
>   */
>  static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
>  {
> +	unsigned long flags;
>  	int ret = -1;
>  	u16 val;
>  
> @@ -378,6 +319,12 @@ static int if_cs_receive_cmdres(struct l
>  	 * bytes */
>  	*len -= 8;
>  	ret = 0;
> +
> +	/* Clear this flag again */
> +	spin_lock_irqsave(&priv->driver_lock, flags);
> +	priv->dnld_sent = DNLD_RES_RECEIVED;
> +	spin_unlock_irqrestore(&priv->driver_lock, flags);
> +
>  out:
>  	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
>  	return ret;
> @@ -396,11 +343,9 @@ static struct sk_buff *if_cs_receive_dat
>  	if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
>  		lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
>  		priv->stats.rx_dropped++;
> -		printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
>  		goto dat_err;
>  	}
>  
> -	//TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
>  	skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
>  	if (!skb)
>  		goto out;
> @@ -425,6 +370,96 @@ out:
>  
> 
>  /********************************************************************/
> +/* Interrupts                                                       */
> +/********************************************************************/
> +
> +static inline void if_cs_enable_ints(struct if_cs_card *card)
> +{
> +	lbs_deb_enter(LBS_DEB_CS);
> +	if_cs_write16(card, IF_CS_H_INT_MASK, 0);
> +}
> +
> +static inline void if_cs_disable_ints(struct if_cs_card *card)
> +{
> +	lbs_deb_enter(LBS_DEB_CS);
> +	if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
> +}
> +
> +
> +static irqreturn_t if_cs_interrupt(int irq, void *data)
> +{
> +	struct if_cs_card *card = data;
> +	struct lbs_private *priv = card->priv;
> +	u16 cause;
> +
> +	lbs_deb_enter(LBS_DEB_CS);
> +
> +	cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
> +	if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
> +
> +	lbs_deb_cs("cause 0x%04x\n", cause);
> +	if (cause == 0) {
> +		/* Not for us */
> +		return IRQ_NONE;
> +	}
> +
> +	if (cause == 0xffff) {
> +		/* Read in junk, the card has probably been removed */
> +		card->priv->surpriseremoved = 1;
> +		return IRQ_HANDLED;
> +	}
> +
> +	/* TODO: I'm not sure what the best ordering is */
> +
> +	cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
> +
> +	if (cause & IF_CS_C_S_RX_UPLD_RDY) {
> +		struct sk_buff *skb;
> +		lbs_deb_cs("rx packet\n");
> +		skb = if_cs_receive_data(priv);
> +		if (skb)
> +			lbs_process_rxed_packet(priv, skb);
> +	}
> +
> +	if (cause & IF_CS_H_IC_TX_OVER) {
> +		lbs_deb_cs("tx over\n");
> +		lbs_host_to_card_done(priv);
> +	}
> +
> +	if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
> +		unsigned long flags;
> +		u8 i;
> +
> +		lbs_deb_cs("cmd upload ready\n");
> +		spin_lock_irqsave(&priv->driver_lock, flags);
> +		i = (priv->resp_idx == 0) ? 1 : 0;
> +		spin_unlock_irqrestore(&priv->driver_lock, flags);
> +
> +		BUG_ON(priv->resp_len[i]);
> +		if_cs_receive_cmdres(priv, priv->resp_buf[i],
> +			&priv->resp_len[i]);
> +
> +		spin_lock_irqsave(&priv->driver_lock, flags);
> +		lbs_notify_command_response(priv, i);
> +		spin_unlock_irqrestore(&priv->driver_lock, flags);
> +	}
> +
> +	if (cause & IF_CS_H_IC_HOST_EVENT) {
> +		u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
> +			& IF_CS_C_S_STATUS_MASK;
> +		if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
> +			IF_CS_H_IC_HOST_EVENT);
> +		lbs_deb_cs("eventcause 0x%04x\n", event);
> +		lbs_queue_event(priv, event >> 8 & 0xff);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +
> +
> +
> +/********************************************************************/
>  /* Firmware                                                         */
>  /********************************************************************/
>  
> @@ -476,8 +511,6 @@ static int if_cs_prog_helper(struct if_c
>  
>  		if (remain < count)
>  			count = remain;
> -		/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
> -			__LINE__, sent, fw->size); */
>  
>  		/* "write the number of bytes to be sent to the I/O Command
>  		 * write length register" */
> @@ -544,18 +577,12 @@ static int if_cs_prog_real(struct if_cs_
>  
>  	ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
>  	if (ret < 0) {
> -		int i;
>  		lbs_pr_err("helper firmware doesn't answer\n");
> -		for (i = 0; i < 0x50; i += 2)
> -			printk(KERN_INFO "## HS %02x: %04x\n",
> -				i, if_cs_read16(card, i));
>  		goto err_release;
>  	}
>  
>  	for (sent = 0; sent < fw->size; sent += len) {
>  		len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
> -		/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
> -			__LINE__, sent, fw->size); */
>  		if (len & 1) {
>  			retry++;
>  			lbs_pr_info("odd, need to retry this firmware block\n");
> @@ -642,64 +669,6 @@ static int if_cs_host_to_card(struct lbs
>  }
>  
> 
> -static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
> -{
> -	struct if_cs_card *card = (struct if_cs_card *)priv->card;
> -	int ret = 0;
> -	u16 int_cause;
> -	*ireg = 0;
> -
> -	lbs_deb_enter(LBS_DEB_CS);
> -
> -	if (priv->surpriseremoved)
> -		goto out;
> -
> -	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
> -	if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
> -
> -	*ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
> -
> -	if (!*ireg)
> -		goto sbi_get_int_status_exit;
> -
> -sbi_get_int_status_exit:
> -
> -	/* is there a data packet for us? */
> -	if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
> -		struct sk_buff *skb = if_cs_receive_data(priv);
> -		lbs_process_rxed_packet(priv, skb);
> -		*ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
> -	}
> -
> -	if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
> -		priv->dnld_sent = DNLD_RES_RECEIVED;
> -	}
> -
> -	/* Card has a command result for us */
> -	if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
> -		ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
> -		if (ret < 0)
> -			lbs_pr_err("could not receive cmd from card\n");
> -	}
> -
> -out:
> -	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
> -	return ret;
> -}
> -
> -
> -static int if_cs_read_event_cause(struct lbs_private *priv)
> -{
> -	lbs_deb_enter(LBS_DEB_CS);
> -
> -	priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
> -	if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
> -
> -	return 0;
> -}
> -
> -
> -
>  /********************************************************************/
>  /* Card Services                                                    */
>  /********************************************************************/
> @@ -852,13 +821,10 @@ static int if_cs_probe(struct pcmcia_dev
>  		goto out2;
>  	}
>  
> -	/* Store pointers to our call-back functions */
> +	/* Finish setting up fields in lbs_private */
>  	card->priv = priv;
>  	priv->card = card;
> -	priv->hw_host_to_card     = if_cs_host_to_card;
> -	priv->hw_get_int_status   = if_cs_get_int_status;
> -	priv->hw_read_event_cause = if_cs_read_event_cause;
> -
> +	priv->hw_host_to_card = if_cs_host_to_card;
>  	priv->fw_ready = 1;
>  
>  	/* Now actually get the IRQ */
> Index: wireless-testing/drivers/net/wireless/libertas/if_sdio.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/if_sdio.c	2008-02-26 15:24:34.000000000 +0100
> +++ wireless-testing/drivers/net/wireless/libertas/if_sdio.c	2008-04-01 10:44:49.000000000 +0200
> @@ -91,8 +91,6 @@ struct if_sdio_card {
>  	const char		*firmware;
>  
>  	u8			buffer[65536];
> -	u8			int_cause;
> -	u32			event;
>  
>  	spinlock_t		lock;
>  	struct if_sdio_packet	*packets;
> @@ -129,13 +127,13 @@ static u16 if_sdio_read_scratch(struct i
>  static int if_sdio_handle_cmd(struct if_sdio_card *card,
>  		u8 *buffer, unsigned size)
>  {
> +	struct lbs_private *priv = card->priv;
>  	int ret;
>  	unsigned long flags;
> +	u8 i;
>  
>  	lbs_deb_enter(LBS_DEB_SDIO);
>  
> -	spin_lock_irqsave(&card->priv->driver_lock, flags);
> -
>  	if (size > LBS_CMD_BUFFER_SIZE) {
>  		lbs_deb_sdio("response packet too large (%d bytes)\n",
>  			(int)size);
> @@ -143,20 +141,20 @@ static int if_sdio_handle_cmd(struct if_
>  		goto out;
>  	}
>  
> -	memcpy(card->priv->upld_buf, buffer, size);
> -	card->priv->upld_len = size;
> +	spin_lock_irqsave(&priv->driver_lock, flags);
>  
> -	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;
>  
>  out:
> -	spin_unlock_irqrestore(&card->priv->driver_lock, flags);
> -
>  	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> -
>  	return ret;
>  }
>  
> @@ -202,7 +200,6 @@ static int if_sdio_handle_event(struct i
>  		u8 *buffer, unsigned size)
>  {
>  	int ret;
> -	unsigned long flags;
>  	u32 event;
>  
>  	lbs_deb_enter(LBS_DEB_SDIO);
> @@ -222,18 +219,9 @@ static int if_sdio_handle_event(struct i
>  		event |= buffer[2] << 16;
>  		event |= buffer[1] << 8;
>  		event |= buffer[0] << 0;
> -		event <<= SBI_EVENT_CAUSE_SHIFT;
>  	}
>  
> -	spin_lock_irqsave(&card->priv->driver_lock, flags);
> -
> -	card->event = event;
> -	card->int_cause |= MRVDRV_CARDEVENT;
> -
> -	lbs_interrupt(card->priv);
> -
> -	spin_unlock_irqrestore(&card->priv->driver_lock, flags);
> -
> +	lbs_queue_event(card->priv, event & 0xFF);
>  	ret = 0;
>  
>  out:
> @@ -770,37 +758,6 @@ out:
>  	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                                                  */
>  /*******************************************************************/
> @@ -953,8 +910,6 @@ static int if_sdio_probe(struct sdio_fun
>  
>  	priv->card = 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;
>  
> Index: wireless-testing/drivers/net/wireless/libertas/if_usb.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/if_usb.c	2008-03-19 13:16:52.000000000 +0100
> +++ wireless-testing/drivers/net/wireless/libertas/if_usb.c	2008-04-01 12:36:37.000000000 +0200
> @@ -38,8 +38,6 @@ static void if_usb_receive_fwload(struct
>  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,
>  			       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,
>  			uint16_t nb);
>  static void if_usb_free(struct if_usb_card *cardp);
> @@ -233,8 +231,6 @@ static int if_usb_probe(struct usb_inter
>  	cardp->priv->fw_ready = 1;
>  
>  	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;
>  
>  	if_usb_submit_rx_urb(cardp);
> @@ -582,7 +578,6 @@ static inline void process_cmdtypedata(i
>  	skb_pull(skb, MESSAGE_HEADER_LEN);
>  
>  	lbs_process_rxed_packet(priv, skb);
> -	priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
>  }
>  
>  static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
> @@ -590,6 +585,8 @@ static inline void process_cmdrequest(in
>  				      struct if_usb_card *cardp,
>  				      struct lbs_private *priv)
>  {
> +	u8 i;
> +
>  	if (recvlength > LBS_CMD_BUFFER_SIZE) {
>  		lbs_deb_usbd(&cardp->udev->dev,
>  			     "The receive buffer is too large\n");
> @@ -601,12 +598,15 @@ static inline void process_cmdrequest(in
>  		BUG();
>  
>  	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);
> -	lbs_interrupt(priv);
> +	lbs_notify_command_response(priv, i);
> +
>  	spin_unlock(&priv->driver_lock);
>  
>  	lbs_deb_usbd(&cardp->udev->dev,
> @@ -629,6 +629,7 @@ static void if_usb_receive(struct urb *u
>  	uint8_t *recvbuff = NULL;
>  	uint32_t recvtype = 0;
>  	__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
> +	uint32_t event;
>  
>  	lbs_deb_enter(LBS_DEB_USB);
>  
> @@ -660,26 +661,20 @@ static void if_usb_receive(struct urb *u
>  		break;
>  
>  	case CMD_TYPE_INDICATION:
> -		/* Event cause handling */
> -		spin_lock(&priv->driver_lock);
> +		/* Event handling */
> +		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",
> -			     cardp->usb_event_cause);
> +			lbs_send_tx_feedback(priv, trycount);
> +		} 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:
>  		lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
>  			     recvtype);
> @@ -722,30 +717,6 @@ static int if_usb_host_to_card(struct lb
>  	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
>   *  @param ivalue   1:Boot from FW by USB-Download
> Index: wireless-testing/drivers/net/wireless/libertas/if_usb.h
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/if_usb.h	2008-02-26 14:39:43.000000000 +0100
> +++ wireless-testing/drivers/net/wireless/libertas/if_usb.h	2008-04-01 10:44:49.000000000 +0200
> @@ -46,8 +46,6 @@ struct if_usb_card {
>  	struct lbs_private *priv;
>  
>  	struct sk_buff *rx_skb;
> -	uint32_t usb_event_cause;
> -	uint8_t usb_int_cause;
>  
>  	uint8_t ep_in;
>  	uint8_t ep_out;
> Index: wireless-testing/drivers/net/wireless/libertas/main.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/main.c	2008-04-01 10:44:49.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/main.c	2008-04-01 12:36:10.000000000 +0200
> @@ -10,6 +10,7 @@
>  #include <linux/netdevice.h>
>  #include <linux/if_arp.h>
>  #include <linux/kthread.h>
> +#include <linux/kfifo.h>
>  
>  #include <net/iw_handler.h>
>  #include <net/ieee80211.h>
> @@ -480,10 +481,9 @@ static void lbs_tx_timeout(struct net_de
>  
>  	dev->trans_start = jiffies;
>  
> -	if (priv->currenttxskb) {
> -		priv->eventcause = 0x01000000;
> -		lbs_send_tx_feedback(priv);
> -	}
> +	if (priv->currenttxskb)
> +		lbs_send_tx_feedback(priv, 0);
> +
>  	/* XX: Shouldn't we also call into the hw-specific driver
>  	   to kick it somehow? */
>  	lbs_host_to_card_done(priv);
> @@ -658,7 +658,6 @@ static int lbs_thread(void *data)
>  	struct net_device *dev = data;
>  	struct lbs_private *priv = dev->priv;
>  	wait_queue_t wait;
> -	u8 ireg = 0;
>  
>  	lbs_deb_enter(LBS_DEB_THREAD);
>  
> @@ -666,9 +665,10 @@ static int lbs_thread(void *data)
>  
>  	for (;;) {
>  		int shouldsleep;
> +		u8 resp_idx;
>  
> -		lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
> -				priv->intcounter, priv->currenttxskb, priv->dnld_sent);
> +		lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
> +				priv->currenttxskb, priv->dnld_sent);
>  
>  		add_wait_queue(&priv->waitq, &wait);
>  		set_current_state(TASK_INTERRUPTIBLE);
> @@ -680,8 +680,6 @@ static int lbs_thread(void *data)
>  			shouldsleep = 1;	/* We need to wait until we're _told_ to die */
>  		else if (priv->psstate == PS_STATE_SLEEP)
>  			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)
>  			shouldsleep = 0;	/* Command timed out. Recover */
>  		else if (!priv->fw_ready)
> @@ -694,29 +692,34 @@ static int lbs_thread(void *data)
>  			shouldsleep = 1;	/* Can't send a command; one already running */
>  		else if (!list_empty(&priv->cmdpendingq))
>  			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
>  			shouldsleep = 1;	/* No command */
>  
>  		if (shouldsleep) {
> -			lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
> -				       priv->connect_status, priv->intcounter,
> -				       priv->psmode, priv->psstate);
> +			lbs_deb_thread("sleeping, connect_status %d, "
> +				"ps_mode %d, ps_state %d\n",
> +				priv->connect_status,
> +				priv->psmode, priv->psstate);
>  			spin_unlock_irq(&priv->driver_lock);
>  			schedule();
>  		} else
>  			spin_unlock_irq(&priv->driver_lock);
>  
> -		lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n",
> -			       priv->intcounter, priv->currenttxskb, priv->dnld_sent);
> +		lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
> +			       priv->currenttxskb, priv->dnld_sent);
>  
>  		set_current_state(TASK_RUNNING);
>  		remove_wait_queue(&priv->waitq, &wait);
>  
> -		lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
> -			       priv->intcounter, priv->currenttxskb, priv->dnld_sent);
> +		lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
> +			       priv->currenttxskb, priv->dnld_sent);
>  
>  		if (kthread_should_stop()) {
> -			lbs_deb_thread("main-thread: break from main thread\n");
> +			lbs_deb_thread("break from main thread\n");
>  			break;
>  		}
>  
> @@ -725,35 +728,23 @@ static int lbs_thread(void *data)
>  			continue;
>  		}
>  
> -		spin_lock_irq(&priv->driver_lock);
> -
> -		if (priv->intcounter) {
> -			u8 int_status;
> -
> -			priv->intcounter = 0;
> -			int_status = priv->hw_get_int_status(priv, &ireg);
> -
> -			if (int_status) {
> -				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");
> +		lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
> +		       priv->currenttxskb, priv->dnld_sent);
>  
> -			priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
> +		spin_lock_irq(&priv->driver_lock);
> +		/* Process any pending command response */
> +		resp_idx = priv->resp_idx;
> +		if (priv->resp_len[resp_idx]) {
>  			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);
> +			priv->resp_len[resp_idx] = 0;
>  		}
> +		spin_unlock_irq(&priv->driver_lock);
>  
> +		/* command timeout stuff */
>  		if (priv->cmd_timed_out && priv->cur_cmd) {
>  			struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
>  
> @@ -774,21 +765,18 @@ static int lbs_thread(void *data)
>  		}
>  		priv->cmd_timed_out = 0;
>  
> -		/* Any Card Event */
> -		if (priv->hisregcpy & MRVDRV_CARDEVENT) {
> -			lbs_deb_thread("main-thread: Card Event Activity\n");
> -
> -			priv->hisregcpy &= ~MRVDRV_CARDEVENT;
> +		/* Process hardware events, e.g. card removed, link lost */
> +		spin_lock_irq(&priv->driver_lock);
> +		while (__kfifo_len(priv->event_fifo)) {
> +			u32 event;
>  
> -			if (priv->hw_read_event_cause(priv)) {
> -				lbs_pr_alert("main-thread: hw_read_event_cause failed\n");
> -				spin_unlock_irq(&priv->driver_lock);
> -				continue;
> -			}
> -			spin_unlock_irq(&priv->driver_lock);
> -			lbs_process_event(priv);
> -		} else
> +			__kfifo_get(priv->event_fifo, (unsigned char *) &event,
> +				sizeof(event));
>  			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)
>  			continue;
> @@ -797,8 +785,10 @@ static int lbs_thread(void *data)
>  		if (priv->psstate == PS_STATE_PRE_SLEEP &&
>  		    !priv->dnld_sent && !priv->cur_cmd) {
>  			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",
> -					       priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd);
> +				lbs_deb_thread("pre-sleep, currenttxskb %p, "
> +					"dnld_sent %d, cur_cmd %p\n",
> +					priv->currenttxskb, priv->dnld_sent,
> +					priv->cur_cmd);
>  
>  				lbs_ps_confirm_sleep(priv);
>  			} else {
> @@ -808,7 +798,8 @@ static int lbs_thread(void *data)
>  				 * after firmware fixes it
>  				 */
>  				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");
>  			}
>  		}
>  
> @@ -1044,7 +1035,18 @@ static int lbs_init_adapter(struct lbs_p
>  	/* Allocate the command buffers */
>  	if (lbs_allocate_cmd_buffer(priv)) {
>  		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:
> @@ -1058,6 +1060,8 @@ static void lbs_free_adapter(struct lbs_
>  	lbs_deb_enter(LBS_DEB_MAIN);
>  
>  	lbs_free_cmd_buffer(priv);
> +	if (priv->event_fifo)
> +		kfifo_free(priv->event_fifo);
>  	del_timer(&priv->command_timer);
>  	kfree(priv->networks);
>  	priv->networks = NULL;
> @@ -1432,27 +1436,41 @@ out:
>  	return ret;
>  }
>  
> -/**
> - *  @brief This function handles the interrupt. it will change PS
> - *  state if applicable. it will wake up main_thread to handle
> - *  the interrupt event as well.
> - *
> - *  @param dev     A pointer to net_device structure
> - *  @return 	   n/a
> - */
> -void lbs_interrupt(struct lbs_private *priv)
> +void lbs_queue_event(struct lbs_private *priv, u32 event)
>  {
> +	unsigned long flags;
> +
>  	lbs_deb_enter(LBS_DEB_THREAD);
> +	spin_lock_irqsave(&priv->driver_lock, flags);
>  
> -	lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
> -	priv->intcounter++;
>  	if (priv->psstate == PS_STATE_SLEEP)
>  		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_interrupt);
> +EXPORT_SYMBOL_GPL(lbs_queue_event);
> +
> +void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
> +{
> +	lbs_deb_enter(LBS_DEB_THREAD);
> +
> +	if (priv->psstate == PS_STATE_SLEEP)
> +		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);
> +
> +	lbs_deb_leave(LBS_DEB_THREAD);
> +}
> +EXPORT_SYMBOL_GPL(lbs_notify_command_response);
>  
>  static int __init lbs_init_module(void)
>  {
> Index: wireless-testing/drivers/net/wireless/libertas/rx.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/rx.c	2008-04-01 10:44:49.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/rx.c	2008-04-01 12:33:26.000000000 +0200
> @@ -52,14 +52,14 @@ int lbs_process_rxed_packet(struct lbs_p
>  	struct net_device *dev = priv->dev;
>  	struct rxpackethdr *p_rx_pkt;
>  	struct rxpd *p_rx_pd;
> -
>  	int hdrchop;
>  	struct ethhdr *p_ethhdr;
> -
>  	const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
>  
>  	lbs_deb_enter(LBS_DEB_RX);
>  
> +	BUG_ON(!skb);
> +
>  	skb->ip_summed = CHECKSUM_NONE;
>  
>  	if (priv->monitormode)
> Index: wireless-testing/drivers/net/wireless/libertas/tx.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/libertas/tx.c	2008-04-01 10:43:11.000000000 +0200
> +++ wireless-testing/drivers/net/wireless/libertas/tx.c	2008-04-01 10:44:49.000000000 +0200
> @@ -179,31 +179,17 @@ int lbs_hard_start_xmit(struct sk_buff *
>   *
>   *  @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;
> -	u32 status = priv->eventcause;
> -	int txfail;
> -	int try_count;
>  
>  	if (!priv->monitormode || priv->currenttxskb == NULL)
>  		return;
>  
>  	radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
>  
> -	txfail = (status >> 24);
> -
> -#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;
> -
> +	radiotap_hdr->data_retries = try_count ?
> +		(1 + priv->txretrycount - try_count) : 0;
>  
>  	priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
>  						      priv->rtap_net_dev);

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux