Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH 2/4] compat: move va_format to compat-2.6.36.h
From: Johannes Berg @ 2010-08-07 15:50 UTC (permalink / raw)
  To: Hauke Mehrtens; +Cc: lrodriguez, linux-wireless, mcgrof
In-Reply-To: <1281187941-7168-3-git-send-email-hauke@hauke-m.de>

On Sat, 2010-08-07 at 15:32 +0200, Hauke Mehrtens wrote:
> This struct was introduced in kernel 2.6.36 and not 2.6.35.

I'm confused now:

$ git describe 7db6f5fb
v2.6.35-rc1-928-g7db6f5f

johannes


^ permalink raw reply

* Re: [RFC] minstrel_ht: fill out more than 3 rates
From: Felix Fietkau @ 2010-08-07 14:28 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless
In-Reply-To: <201008070007.53294.chunkeey@googlemail.com>

On 2010-08-07 12:07 AM, Christian Lamparter wrote:
> Hello Felix,
> 
> I've stumbled into this conundrum a while ago...
> then as usual: forgot that it existed, until yesterday:
> 
> As you know minstrel (our non ht fallback) enables mrr-mode
> only if the driver sets hw->max_rates to 4 or more. 
> minstrel_ht - on the other hand - just prepares a set
> of 3 rates, so at least one additional retry with
> different tx-vectors remains unused...
> 
> How the last tries should be used is up for debate,
> I've opted out for lowest possible MCS.
> (although, some devices may also use a legacy
>  rate for the final tries...)
> 
> And the reason why I think it's worth to do an additional
> round: The reordering penalty for lost MPDUs on the receiver-
> side can be as high as 100ms, which is quite expensive compared
> to some extra airtime...
The problem here is that we have very different forms of retransmission
that receive the same kind of tx rate information, even though they
should be treated in a different way.

With drivers like ath9k, we don't need many retransmission steps. The
hardware-level retransmission stops as soon as it receives a Block Ack,
even if that may only ACK one of many frames (or maybe even none at
all). Software retransmission is then used to ensure that we don't
usually see lost MPDUs (under sane conditions, software-level excessive
retries should be pretty rare).

With this form of aggregation, the processing of the MRR chain is always
restarted for the next transmission attempt.
Since the table is for hw-level retransmission only, we do need to
ensure that we don't put unnecessarily low rates into the MRR array, as
this will limit aggregation size based on the 4-ms limit.

When using hardware aggregation, the behaviour kind of depends on how
the hardware interprets the retransmission information and how many
times it retransmits failed subframes of an A-MPDU transmission that
received a Block Ack.

I think in the long run we need to split this up. In my software
aggregation rewrite, I plan to add rate control lookups per A-MPDU, so
that the rate control algorithm can make a decision based on the number
of failed subframes (or the delta between first frame seqno and last
frame seqno, to better utilize the block ack window). In this case, the
rate control can be (and should be) much more optimistic about rates,
whereas with hardware aggregation we should probably put more emphasis
on reliability to reduce the latency.

- Felix

^ permalink raw reply

* [PATCH 2/2] compat-wireless: activate more bluetooth drivers
From: Hauke Mehrtens @ 2010-08-07 13:34 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens
In-Reply-To: <1281188084-7232-1-git-send-email-hauke@hauke-m.de>

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 config.mk |   34 ++++++++++++++++++++++++++++++++--
 1 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/config.mk b/config.mk
index 733ea33..777ebd3 100644
--- a/config.mk
+++ b/config.mk
@@ -154,14 +154,33 @@ CONFIG_BT=m
 CONFIG_BT_L2CAP=m
 CONFIG_BT_SCO=m
 CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
-CONFIG_BT_ATH3K=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
 # CONFIG_BT_CMTP depends on ISDN_CAPI
-ifneq ($(CONFIG_BT_CMTP),)
+ifneq ($(CONFIG_ISDN_CAPI),)
 CONFIG_BT_CMTP=m
 endif
 CONFIG_BT_HIDP=m
 
+CONFIG_BT_HCIUART=M
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+
+ifneq ($(CONFIG_PCMCIA),)
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+endif
+
+
 # CONFIG_CFG80211_WEXT will be resepected for
 # future kernels but for older kenrels we need
 # to enable it against the the old CONFIG_WIRELESS_EXT.
@@ -192,6 +211,7 @@ CONFIG_ATH9K=m
 # as you could then have ath9k disabled but ath9k_htc enabled.
 CONFIG_ATH9K_COMMON=m
 # CONFIG_ATH9K_DEBUGFS=y
+# CONFIG_ATH9K_PKTLOG=y
 
 
 CONFIG_IWLWIFI=m
@@ -377,6 +397,7 @@ CONFIG_AR9170_LEDS=y
 endif
 
 CONFIG_ATH9K_HTC=m
+# CONFIG_ATH9K_HTC_DEBUGFS=y
 
 # RT2500USB does not require firmware
 CONFIG_RT2500USB=m
@@ -406,6 +427,12 @@ endif
 
 CONFIG_ORINOCO_USB=m
 
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_ATH3K=m
+
 endif # end of USB driver list
 
 ifneq ($(CONFIG_SPI_MASTER),)
@@ -448,6 +475,9 @@ endif
 CONFIG_IWM=m
 # CONFIG_IWM_DEBUG=y
 
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_MRVL_SDIO=m
+
 endif # end of SDIO driver list
 
 # Common rt2x00 requirements
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/2] compat-wireless: backport pcmcia api changes
From: Hauke Mehrtens @ 2010-08-07 13:34 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 patches/24-pcmcia.patch |  483 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 469 insertions(+), 14 deletions(-)

diff --git a/patches/24-pcmcia.patch b/patches/24-pcmcia.patch
index b1d65bf..5beda46 100644
--- a/patches/24-pcmcia.patch
+++ b/patches/24-pcmcia.patch
@@ -1,6 +1,115 @@
 --- a/drivers/bluetooth/bluecard_cs.c
 +++ b/drivers/bluetooth/bluecard_cs.c
-@@ -865,6 +865,12 @@ static int bluecard_probe(struct pcmcia_
+@@ -159,7 +159,12 @@ static void bluecard_detach(struct pcmci
+ static void bluecard_activity_led_timeout(u_long arg)
+ {
+ 	bluecard_info_t *info = (bluecard_info_t *)arg;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
++
+ 
+ 	if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
+ 		return;
+@@ -176,7 +181,11 @@ static void bluecard_activity_led_timeou
+ 
+ static void bluecard_enable_activity_led(bluecard_info_t *info)
+ {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
+ 		return;
+@@ -232,7 +241,11 @@ static void bluecard_write_wakeup(blueca
+ 	}
+ 
+ 	do {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		register unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++		register unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 		register unsigned int offset;
+ 		register unsigned char command;
+ 		register unsigned long ready_bit;
+@@ -379,7 +392,11 @@ static void bluecard_receive(bluecard_in
+ 		return;
+ 	}
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
+ 		bluecard_enable_activity_led(info);
+@@ -508,7 +525,11 @@ static irqreturn_t bluecard_interrupt(in
+ 	if (!test_bit(CARD_READY, &(info->hw_state)))
+ 		return IRQ_HANDLED;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	spin_lock(&(info->lock));
+ 
+@@ -622,7 +643,11 @@ static int bluecard_hci_flush(struct hci
+ static int bluecard_hci_open(struct hci_dev *hdev)
+ {
+ 	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
+ 		bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
+@@ -642,7 +667,11 @@ static int bluecard_hci_open(struct hci_
+ static int bluecard_hci_close(struct hci_dev *hdev)
+ {
+ 	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+ 		return 0;
+@@ -709,7 +738,11 @@ static int bluecard_hci_ioctl(struct hci
+ 
+ static int bluecard_open(bluecard_info_t *info)
+ {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 	struct hci_dev *hdev;
+ 	unsigned char id;
+ 
+@@ -828,7 +861,11 @@ static int bluecard_open(bluecard_info_t
+ 
+ static int bluecard_close(bluecard_info_t *info)
+ {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 	struct hci_dev *hdev = info->hdev;
+ 
+ 	if (!hdev)
+@@ -865,6 +902,12 @@ static int bluecard_probe(struct pcmcia_
  	info->p_dev = link;
  	link->priv = info;
  
@@ -13,7 +122,32 @@
  	link->conf.Attributes = CONF_ENABLE_IRQ;
  	link->conf.IntType = INT_MEMORY_AND_IO;
  
-@@ -902,9 +908,15 @@ static int bluecard_config(struct pcmcia
+@@ -888,13 +931,24 @@ static int bluecard_config(struct pcmcia
+ 
+ 	link->conf.ConfigIndex = 0x20;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ 	link->resource[0]->end = 64;
+ 	link->io_lines = 6;
++#else
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 64;
++	link->io.IOAddrLines = 6;;
++#endif
+ 
+ 	for (n = 0; n < 0x400; n += 0x40) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		link->resource[0]->start = n ^ 0x300;
+ 		i = pcmcia_request_io(link);
++#else
++		link->io.BasePort1 = n ^ 0x300;
++		i = pcmcia_request_io(link, &link->io);
++#endif
+ 		if (i == 0)
+ 			break;
+ 	}
+@@ -902,9 +956,15 @@ static int bluecard_config(struct pcmcia
  	if (i != 0)
  		goto failed;
  
@@ -31,20 +165,115 @@
  	if (i != 0)
 --- a/drivers/bluetooth/bt3c_cs.c
 +++ b/drivers/bluetooth/bt3c_cs.c
-@@ -660,6 +660,12 @@ static int bt3c_probe(struct pcmcia_devi
+@@ -188,7 +188,11 @@ static void bt3c_write_wakeup(bt3c_info_
+ 		return;
+ 
+ 	do {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		register unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++		register unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 		register struct sk_buff *skb;
+ 		register int len;
+ 
+@@ -226,7 +230,11 @@ static void bt3c_receive(bt3c_info_t *in
+ 		return;
+ 	}
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	avail = bt3c_read(iobase, 0x7006);
+ 	//printk("bt3c_cs: receiving %d bytes\n", avail);
+@@ -347,7 +355,11 @@ static irqreturn_t bt3c_interrupt(int ir
+ 		/* our irq handler is shared */
+ 		return IRQ_NONE;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	spin_lock(&(info->lock));
+ 
+@@ -480,7 +492,11 @@ static int bt3c_load_firmware(bt3c_info_
+ 	unsigned int iobase, size, addr, fcs, tmp;
+ 	int i, err = 0;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	/* Reset */
+ 	bt3c_io_write(iobase, 0x8040, 0x0404);
+@@ -657,8 +673,19 @@ static int bt3c_probe(struct pcmcia_devi
+ 	info->p_dev = link;
+ 	link->priv = info;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
  	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
  	link->resource[0]->end = 8;
- 
++#else
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1= 8;
++#endif
++
 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
 +	link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 +
 +	link->irq.Handler = bt3c_interrupt;
 +#endif
-+
+ 
  	link->conf.Attributes = CONF_ENABLE_IRQ;
  	link->conf.IntType = INT_MEMORY_AND_IO;
+@@ -683,14 +710,23 @@ static int bt3c_check_config(struct pcmc
+ {
+ 	unsigned long try = (unsigned long) priv_data;
  
-@@ -738,9 +744,15 @@ static int bt3c_config(struct pcmcia_dev
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++#endif
+ 
+ 	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ 		p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ 	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+ 	    (cf->io.win[0].base != 0)) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		p_dev->resource[0]->start = cf->io.win[0].base;
+ 		if (!pcmcia_request_io(p_dev))
++#else
++		p_dev->io.BasePort1 = cf->io.win[0].base;
++		p_dev->io.IOAddrLines = (try == 0) ? 16 :
++			cf->io.flags & CISTPL_IO_LINES_MASK;
++		if (!pcmcia_request_io(p_dev, &p_dev->io))
++#endif
+ 			return 0;
+ 	}
+ 	return -ENODEV;
+@@ -707,9 +743,15 @@ static int bt3c_check_config_notpicky(st
+ 
+ 	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+ 		for (j = 0; j < 5; j++) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 			p_dev->resource[0]->start = base[j];
+ 			p_dev->io_lines = base[j] ? 16 : 3;
+ 			if (!pcmcia_request_io(p_dev))
++#else
++			p_dev->io.BasePort1 = base[j];
++			p_dev->io.IOAddrLines = base[j] ? 16 : 3;
++			if (!pcmcia_request_io(p_dev, &p_dev->io))
++#endif
+ 				return 0;
+ 		}
+ 	}
+@@ -738,9 +780,15 @@ static int bt3c_config(struct pcmcia_dev
  	goto failed;
  
  found_port:
@@ -62,20 +291,139 @@
  	if (i != 0)
 --- a/drivers/bluetooth/btuart_cs.c
 +++ b/drivers/bluetooth/btuart_cs.c
-@@ -589,6 +589,12 @@ static int btuart_probe(struct pcmcia_de
+@@ -142,7 +142,11 @@ static void btuart_write_wakeup(btuart_i
+ 	}
+ 
+ 	do {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		register unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++		register unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 		register struct sk_buff *skb;
+ 		register int len;
+ 
+@@ -183,7 +187,11 @@ static void btuart_receive(btuart_info_t
+ 		return;
+ 	}
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	do {
+ 		info->hdev->stat.byte_rx++;
+@@ -297,7 +305,11 @@ static irqreturn_t btuart_interrupt(int 
+ 		/* our irq handler is shared */
+ 		return IRQ_NONE;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	spin_lock(&(info->lock));
+ 
+@@ -354,7 +366,11 @@ static void btuart_change_speed(btuart_i
+ 		return;
+ 	}
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	spin_lock_irqsave(&(info->lock), flags);
+ 
+@@ -478,7 +494,11 @@ static int btuart_hci_ioctl(struct hci_d
+ static int btuart_open(btuart_info_t *info)
+ {
+ 	unsigned long flags;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 	struct hci_dev *hdev;
+ 
+ 	spin_lock_init(&(info->lock));
+@@ -548,7 +568,11 @@ static int btuart_open(btuart_info_t *in
+ static int btuart_close(btuart_info_t *info)
+ {
+ 	unsigned long flags;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 	struct hci_dev *hdev = info->hdev;
+ 
+ 	if (!hdev)
+@@ -586,8 +610,19 @@ static int btuart_probe(struct pcmcia_de
+ 	info->p_dev = link;
+ 	link->priv = info;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
  	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
  	link->resource[0]->end = 8;
- 
++#else
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1= 8;
++#endif
++
 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
 +	link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 +
 +	link->irq.Handler = btuart_interrupt;
 +#endif
-+
+ 
  	link->conf.Attributes = CONF_ENABLE_IRQ;
  	link->conf.IntType = INT_MEMORY_AND_IO;
+@@ -612,14 +647,23 @@ static int btuart_check_config(struct pc
+ {
+ 	int *try = priv_data;
  
-@@ -667,9 +673,15 @@ static int btuart_config(struct pcmcia_d
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++#endif
+ 
+ 	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ 		p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ 	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+ 	    (cf->io.win[0].base != 0)) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		p_dev->resource[0]->start = cf->io.win[0].base;
+ 		if (!pcmcia_request_io(p_dev))
++#else
++		p_dev->io.BasePort1 = cf->io.win[0].base;
++		p_dev->io.IOAddrLines = (*try == 0) ? 16 :
++			cf->io.flags & CISTPL_IO_LINES_MASK;
++		if (!pcmcia_request_io(p_dev, &p_dev->io))
++#endif
+ 			return 0;
+ 	}
+ 	return -ENODEV;
+@@ -636,9 +680,15 @@ static int btuart_check_config_notpicky(
+ 
+ 	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+ 		for (j = 0; j < 5; j++) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 			p_dev->resource[0]->start = base[j];
+ 			p_dev->io_lines = base[j] ? 16 : 3;
+ 			if (!pcmcia_request_io(p_dev))
++#else
++			p_dev->io.BasePort1 = base[j];
++			p_dev->io.IOAddrLines = base[j] ? 16 : 3;
++			if (!pcmcia_request_io(p_dev, &p_dev->io))
++#endif
+ 				return 0;
+ 		}
+ 	}
+@@ -667,9 +717,15 @@ static int btuart_config(struct pcmcia_d
  	goto failed;
  
  found_port:
@@ -93,10 +441,91 @@
  	if (i != 0)
 --- a/drivers/bluetooth/dtl1_cs.c
 +++ b/drivers/bluetooth/dtl1_cs.c
-@@ -574,6 +574,10 @@ static int dtl1_probe(struct pcmcia_devi
+@@ -149,7 +149,11 @@ static void dtl1_write_wakeup(dtl1_info_
+ 	}
+ 
+ 	do {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 		register unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++		register unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 		register struct sk_buff *skb;
+ 		register int len;
+ 
+@@ -214,7 +218,11 @@ static void dtl1_receive(dtl1_info_t *in
+ 		return;
+ 	}
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	do {
+ 		info->hdev->stat.byte_rx++;
+@@ -301,7 +309,11 @@ static irqreturn_t dtl1_interrupt(int ir
+ 		/* our irq handler is shared */
+ 		return IRQ_NONE;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	iobase = info->p_dev->resource[0]->start;
++#else
++	iobase = info->p_dev->io.BasePort1;
++#endif
+ 
+ 	spin_lock(&(info->lock));
+ 
+@@ -461,7 +473,11 @@ static int dtl1_hci_ioctl(struct hci_dev
+ static int dtl1_open(dtl1_info_t *info)
+ {
+ 	unsigned long flags;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 	struct hci_dev *hdev;
+ 
+ 	spin_lock_init(&(info->lock));
+@@ -508,8 +524,13 @@ static int dtl1_open(dtl1_info_t *info)
+ 	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
+ 	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	info->ri_latch = inb(info->p_dev->resource[0]->start + UART_MSR)
+ 				& UART_MSR_RI;
++#else
++	info->ri_latch = inb(info->p_dev->io.BasePort1 + UART_MSR)
++				& UART_MSR_RI;
++#endif
+ 
+ 	/* Turn on interrupts */
+ 	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+@@ -534,7 +555,11 @@ static int dtl1_open(dtl1_info_t *info)
+ static int dtl1_close(dtl1_info_t *info)
+ {
+ 	unsigned long flags;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	unsigned int iobase = info->p_dev->resource[0]->start;
++#else
++	unsigned int iobase = info->p_dev->io.BasePort1;
++#endif
+ 	struct hci_dev *hdev = info->hdev;
+ 
+ 	if (!hdev)
+@@ -572,8 +597,17 @@ static int dtl1_probe(struct pcmcia_devi
+ 	info->p_dev = link;
+ 	link->priv = info;
  
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
  	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
  	link->resource[0]->end = 8;
++#else
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1= 8;
++#endif
 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
 +	link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 +	link->irq.Handler = dtl1_interrupt;
@@ -104,7 +533,33 @@
  
  	link->conf.Attributes = CONF_ENABLE_IRQ;
  	link->conf.IntType = INT_MEMORY_AND_IO;
-@@ -616,9 +620,15 @@ static int dtl1_config(struct pcmcia_dev
+@@ -600,10 +634,17 @@ static int dtl1_confcheck(struct pcmcia_
+ 	if ((cf->io.nwin != 1) || (cf->io.win[0].len <= 8))
+ 		return -ENODEV;
+ 
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	p_dev->resource[0]->start = cf->io.win[0].base;
+ 	p_dev->resource[0]->end = cf->io.win[0].len;	/*yo */
+ 	p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+ 	return pcmcia_request_io(p_dev);
++#else
++	p_dev->io.BasePort1 = cf->io.win[0].base;
++	p_dev->io.NumPorts1 = cf->io.win[0].len;	/*yo */
++	p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
++	return pcmcia_request_io(p_dev, &p_dev->io);
++#endif
+ }
+ 
+ static int dtl1_config(struct pcmcia_device *link)
+@@ -612,13 +653,23 @@ static int dtl1_config(struct pcmcia_dev
+ 	int i;
+ 
+ 	/* Look for a generic full-sized window */
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ 	link->resource[0]->end = 8;
++#else
++	link->io.NumPorts1 = 8;
++#endif
  	if (pcmcia_loop_config(link, dtl1_confcheck, NULL) < 0)
  		goto failed;
  
@@ -429,7 +884,7 @@
  			goto next_entry;
  	}
  	return 0;
-@@ -310,15 +341,23 @@ spectrum_cs_config(struct pcmcia_device
+@@ -310,15 +341,23 @@ spectrum_cs_config(struct pcmcia_device 
  		goto failed;
  	}
  
@@ -453,7 +908,7 @@
  	if (!mem)
  		goto failed;
  
-@@ -345,8 +384,16 @@ spectrum_cs_config(struct pcmcia_device
+@@ -345,8 +384,16 @@ spectrum_cs_config(struct pcmcia_device 
  	}
  
  	/* Register an interface with the stack */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 4/4] compat: update compat_firmware_class.c
From: Hauke Mehrtens @ 2010-08-07 13:32 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens
In-Reply-To: <1281187941-7168-1-git-send-email-hauke@hauke-m.de>

Refresh code based on recent version in linux-next.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 compat/compat_firmware_class.c |  290 ++++++++++++++++++++-------------------
 1 files changed, 149 insertions(+), 141 deletions(-)

diff --git a/compat/compat_firmware_class.c b/compat/compat_firmware_class.c
index 02f38a2..70ab25c 100644
--- a/compat/compat_firmware_class.c
+++ b/compat/compat_firmware_class.c
@@ -88,27 +88,31 @@ static DEFINE_MUTEX(fw_lock);
 
 struct firmware_priv {
 	struct completion completion;
-	struct bin_attribute attr_data;
 	struct firmware *fw;
 	unsigned long status;
 	struct page **pages;
 	int nr_pages;
 	int page_array_size;
 	struct timer_list timeout;
+	struct device dev;
 	bool nowait;
 	char fw_id[];
 };
 
-static void
-fw_load_abort(struct firmware_priv *fw_priv)
+static struct firmware_priv *to_firmware_priv(struct device *dev)
+{
+	return container_of(dev, struct firmware_priv, dev);
+}
+
+static void fw_load_abort(struct firmware_priv *fw_priv)
 {
 	set_bit(FW_STATUS_ABORT, &fw_priv->status);
 	wmb();
 	complete(&fw_priv->completion);
 }
 
-static ssize_t
-firmware_timeout_show(struct class *class, char *buf)
+static ssize_t firmware_timeout_show(struct class *class,
+				     char *buf)
 {
 	return sprintf(buf, "%d\n", loading_timeout);
 }
@@ -125,12 +129,13 @@ firmware_timeout_show(struct class *class, char *buf)
  *
  *	Note: zero means 'wait forever'.
  **/
-static ssize_t
-firmware_timeout_store(struct class *class, const char *buf, size_t count)
+static ssize_t firmware_timeout_store(struct class *class,
+				      const char *buf, size_t count)
 {
 	loading_timeout = simple_strtol(buf, NULL, 10);
 	if (loading_timeout < 0)
 		loading_timeout = 0;
+
 	return count;
 }
 
@@ -142,14 +147,13 @@ static struct class_attribute firmware_class_attrs[] = {
 
 static void fw_dev_release(struct device *dev)
 {
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	int i;
 
 	for (i = 0; i < fw_priv->nr_pages; i++)
 		__free_page(fw_priv->pages[i]);
 	kfree(fw_priv->pages);
 	kfree(fw_priv);
-	kfree(dev);
 
 	module_put(THIS_MODULE);
 }
@@ -157,7 +161,7 @@ static void fw_dev_release(struct device *dev)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
 static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 
 	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
@@ -172,7 +176,7 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
 static int firmware_uevent(struct device *dev, char **envp,
 			   int num_envp, char *buf, int size)
 {
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	int error, len = 0, i = 0;
 
 	error = add_uevent_var(envp, num_envp, &i,
@@ -209,11 +213,27 @@ static struct class firmware_class = {
 static ssize_t firmware_loading_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
+
 	return sprintf(buf, "%d\n", loading);
 }
 
+static void firmware_free_data(const struct firmware *fw)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+	int i;
+	vunmap(fw->data);
+	if (fw->pages) {
+		for (i = 0; i < PFN_UP(fw->size); i++)
+			__free_page(fw->pages[i]);
+		kfree(fw->pages);
+	}
+#else
+	vunmap(fw->data);
+#endif
+}
+
 /* Some architectures don't have PAGE_KERNEL_RO */
 #ifndef PAGE_KERNEL_RO
 #define PAGE_KERNEL_RO PAGE_KERNEL
@@ -221,7 +241,6 @@ static ssize_t firmware_loading_show(struct device *dev,
 /**
  * firmware_loading_store - set value in the 'loading' control file
  * @dev: device pointer
- * @attr: device attribute pointer
  * @buf: buffer to scan for loading control value
  * @count: number of bytes in @buf
  *
@@ -235,7 +254,7 @@ static ssize_t firmware_loading_store(struct device *dev,
 				      struct device_attribute *attr,
 				      const char *buf, size_t count)
 {
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	int loading = simple_strtol(buf, NULL, 10);
 	int i;
 
@@ -246,21 +265,21 @@ static ssize_t firmware_loading_store(struct device *dev,
 			mutex_unlock(&fw_lock);
 			break;
 		}
-		vfree(fw_priv->fw->data);
-		fw_priv->fw->data = NULL;
+		firmware_free_data(fw_priv->fw);
+		memset(fw_priv->fw, 0, sizeof(struct firmware));
+		/* If the pages are not owned by 'struct firmware' */
 		for (i = 0; i < fw_priv->nr_pages; i++)
 			__free_page(fw_priv->pages[i]);
 		kfree(fw_priv->pages);
 		fw_priv->pages = NULL;
 		fw_priv->page_array_size = 0;
 		fw_priv->nr_pages = 0;
-		fw_priv->fw->size = 0;
 		set_bit(FW_STATUS_LOADING, &fw_priv->status);
 		mutex_unlock(&fw_lock);
 		break;
 	case 0:
 		if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
-			vfree(fw_priv->fw->data);
+			vunmap(fw_priv->fw->data);
 			fw_priv->fw->data = vmap(fw_priv->pages,
 						 fw_priv->nr_pages,
 						 0, PAGE_KERNEL_RO);
@@ -268,7 +287,12 @@ static ssize_t firmware_loading_store(struct device *dev,
 				dev_err(dev, "%s: vmap() failed\n", __func__);
 				goto err;
 			}
-			/* Pages will be freed by vfree() */
+			/* Pages are now owned by 'struct firmware' */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+			fw_priv->fw->pages = fw_priv->pages;
+			fw_priv->pages = NULL;
+#endif
+
 			fw_priv->page_array_size = 0;
 			fw_priv->nr_pages = 0;
 			complete(&fw_priv->completion);
@@ -290,12 +314,12 @@ static ssize_t firmware_loading_store(struct device *dev,
 
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
 
-static ssize_t
-firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
-		   char *buffer, loff_t offset, size_t count)
+static ssize_t firmware_data_read(struct kobject *kobj,
+				  struct bin_attribute *bin_attr,
+				  char *buffer, loff_t offset, size_t count)
 {
 	struct device *dev = to_dev(kobj);
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	struct firmware *fw;
 	ssize_t ret_count;
 
@@ -334,8 +358,7 @@ out:
 	return ret_count;
 }
 
-static int
-fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
+static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
 	int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
 
@@ -384,12 +407,12 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
  *	Data written to the 'data' attribute will be later handed to
  *	the driver as a firmware image.
  **/
-static ssize_t
-firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr,
-		    char *buffer, loff_t offset, size_t count)
+static ssize_t firmware_data_write(struct kobject *kobj,
+				   struct bin_attribute *bin_attr,
+				   char *buffer, loff_t offset, size_t count)
 {
 	struct device *dev = to_dev(kobj);
-	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	struct firmware *fw;
 	ssize_t retval;
 
@@ -430,116 +453,103 @@ out:
 	return retval;
 }
 
-static struct bin_attribute firmware_attr_data_tmpl = {
-	.attr = {.name = "data", .mode = 0644},
+static struct bin_attribute firmware_attr_data = {
+	.attr = { .name = "data", .mode = 0644 },
 	.size = 0,
 	.read = firmware_data_read,
 	.write = firmware_data_write,
 };
 
-static void
-firmware_class_timeout(u_long data)
+static void firmware_class_timeout(u_long data)
 {
 	struct firmware_priv *fw_priv = (struct firmware_priv *) data;
+
 	fw_load_abort(fw_priv);
 }
 
-static int fw_register_device(struct device **dev_p, const char *fw_name,
-			      struct device *device)
+static struct firmware_priv *
+fw_create_instance(struct firmware *firmware, const char *fw_name,
+		   struct device *device, bool uevent, bool nowait)
 {
-	int retval;
-	struct firmware_priv *fw_priv =
-		kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
-	struct device *f_dev = kzalloc(sizeof(*f_dev), GFP_KERNEL);
-
-	*dev_p = NULL;
+	struct firmware_priv *fw_priv;
+	struct device *f_dev;
+	int error;
 
-	if (!fw_priv || !f_dev) {
+	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
+	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		retval = -ENOMEM;
-		goto error_kfree;
+		error = -ENOMEM;
+		goto err_out;
 	}
 
+	fw_priv->fw = firmware;
+	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
-	fw_priv->attr_data = firmware_attr_data_tmpl;
-	fw_priv->timeout.function = firmware_class_timeout;
-	fw_priv->timeout.data = (u_long) fw_priv;
-	init_timer(&fw_priv->timeout);
+	setup_timer(&fw_priv->timeout,
+		    firmware_class_timeout, (u_long) fw_priv);
 
+	f_dev = &fw_priv->dev;
+
+	device_initialize(f_dev);
 	dev_set_name(f_dev, "%s", dev_name(device));
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
-	dev_set_drvdata(f_dev, fw_priv);
-	dev_set_uevent_suppress(f_dev, 1);
-	retval = device_register(f_dev);
-	if (retval) {
-		dev_err(device, "%s: device_register failed\n", __func__);
-		put_device(f_dev);
-		return retval;
-	}
-	*dev_p = f_dev;
-	return 0;
-
-error_kfree:
-	kfree(f_dev);
-	kfree(fw_priv);
-	return retval;
-}
 
-static int fw_setup_device(struct firmware *fw, struct device **dev_p,
-			   const char *fw_name, struct device *device,
-			   int uevent, bool nowait)
-{
-	struct device *f_dev;
-	struct firmware_priv *fw_priv;
-	int retval;
-
-	*dev_p = NULL;
-	retval = fw_register_device(&f_dev, fw_name, device);
-	if (retval)
-		goto out;
+	dev_set_uevent_suppress(f_dev, true);
 
 	/* Need to pin this module until class device is destroyed */
 	__module_get(THIS_MODULE);
 
-	fw_priv = dev_get_drvdata(f_dev);
-
-	fw_priv->nowait = nowait;
+	error = device_add(f_dev);
+	if (error) {
+		dev_err(device, "%s: device_register failed\n", __func__);
+		goto err_put_dev;
+	}
 
-	fw_priv->fw = fw;
-	sysfs_bin_attr_init(&fw_priv->attr_data);
-	retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
-	if (retval) {
+	error = device_create_bin_file(f_dev, &firmware_attr_data);
+	if (error) {
 		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
-		goto error_unreg;
+		goto err_del_dev;
 	}
 
-	retval = device_create_file(f_dev, &dev_attr_loading);
-	if (retval) {
+	error = device_create_file(f_dev, &dev_attr_loading);
+	if (error) {
 		dev_err(device, "%s: device_create_file failed\n", __func__);
-		goto error_unreg;
+		goto err_del_bin_attr;
 	}
 
 	if (uevent)
-		dev_set_uevent_suppress(f_dev, 0);
-	*dev_p = f_dev;
-	goto out;
+		dev_set_uevent_suppress(f_dev, false);
+
+	return fw_priv;
+
+err_del_bin_attr:
+	device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+	device_del(f_dev);
+err_put_dev:
+	put_device(f_dev);
+err_out:
+	return ERR_PTR(error);
+}
+
+static void fw_destroy_instance(struct firmware_priv *fw_priv)
+{
+	struct device *f_dev = &fw_priv->dev;
 
-error_unreg:
+	device_remove_file(f_dev, &dev_attr_loading);
+	device_remove_bin_file(f_dev, &firmware_attr_data);
 	device_unregister(f_dev);
-out:
-	return retval;
 }
 
-static int
-_request_firmware(const struct firmware **firmware_p, const char *name,
-		 struct device *device, int uevent, bool nowait)
+static int _request_firmware(const struct firmware **firmware_p,
+			     const char *name, struct device *device,
+			     bool uevent, bool nowait)
 {
-	struct device *f_dev;
 	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval;
+	int retval = 0;
 
 	if (!firmware_p)
 		return -EINVAL;
@@ -560,41 +570,40 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 	if (uevent)
 		dev_dbg(device, "firmware: requesting %s\n", name);
 
-	retval = fw_setup_device(firmware, &f_dev, name, device,
-				 uevent, nowait);
-	if (retval)
-		goto error_kfree_fw;
-
-	fw_priv = dev_get_drvdata(f_dev);
+	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+	if (IS_ERR(fw_priv)) {
+		retval = PTR_ERR(fw_priv);
+		goto out;
+	}
 
 	if (uevent) {
-		if (loading_timeout > 0) {
-			fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
-			add_timer(&fw_priv->timeout);
-		}
+		if (loading_timeout > 0)
+			mod_timer(&fw_priv->timeout,
+				  round_jiffies_up(jiffies +
+						   loading_timeout * HZ));
+
+		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+	}
+
+	wait_for_completion(&fw_priv->completion);
 
-		kobject_uevent(&f_dev->kobj, KOBJ_ADD);
-		wait_for_completion(&fw_priv->completion);
-		set_bit(FW_STATUS_DONE, &fw_priv->status);
-		del_timer_sync(&fw_priv->timeout);
-	} else
-		wait_for_completion(&fw_priv->completion);
+	set_bit(FW_STATUS_DONE, &fw_priv->status);
+	del_timer_sync(&fw_priv->timeout);
 
 	mutex_lock(&fw_lock);
-	if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
+	if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
 		retval = -ENOENT;
-		release_firmware(fw_priv->fw);
-		*firmware_p = NULL;
-	}
 	fw_priv->fw = NULL;
 	mutex_unlock(&fw_lock);
-	device_unregister(f_dev);
-	goto out;
 
-error_kfree_fw:
-	kfree(firmware);
-	*firmware_p = NULL;
+	fw_destroy_instance(fw_priv);
+
 out:
+	if (retval) {
+		release_firmware(firmware);
+		firmware_p = NULL;
+	}
+
 	return retval;
 }
 
@@ -629,8 +638,7 @@ void release_firmware(const struct firmware *fw)
 {
 	if (fw) {
 		if (!fw_is_builtin_firmware(fw))
-			vfree(fw->data);
-
+			firmware_free_data(fw);
 		kfree(fw);
 	}
 }
@@ -646,23 +654,24 @@ struct firmware_work {
 	int uevent;
 };
 
-static int
-request_firmware_work_func(void *arg)
+static int request_firmware_work_func(void *arg)
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
 	int ret;
+
 	if (!arg) {
 		WARN_ON(1);
 		return 0;
 	}
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
-		fw_work->uevent, true);
 
+	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+				fw_work->uevent, true);
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);
 	kfree(fw_work);
+
 	return ret;
 }
 
@@ -690,34 +699,33 @@ request_firmware_nowait(
 	void (*cont)(const struct firmware *fw, void *context))
 {
 	struct task_struct *task;
-	struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
-						gfp);
+	struct firmware_work *fw_work;
 
+	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
 	if (!fw_work)
 		return -ENOMEM;
+
+	fw_work->module = module;
+	fw_work->name = name;
+	fw_work->device = device;
+	fw_work->context = context;
+	fw_work->cont = cont;
+	fw_work->uevent = uevent;
+
 	if (!try_module_get(module)) {
 		kfree(fw_work);
 		return -EFAULT;
 	}
 
-	*fw_work = (struct firmware_work) {
-		.module = module,
-		.name = name,
-		.device = device,
-		.context = context,
-		.cont = cont,
-		.uevent = uevent,
-	};
-
 	task = kthread_run(request_firmware_work_func, fw_work,
 			    "firmware/%s", name);
-
 	if (IS_ERR(task)) {
 		fw_work->cont(NULL, fw_work->context);
 		module_put(fw_work->module);
 		kfree(fw_work);
 		return PTR_ERR(task);
 	}
+
 	return 0;
 }
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 3/4] compat: fix compiler warning
From: Hauke Mehrtens @ 2010-08-07 13:32 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens
In-Reply-To: <1281187941-7168-1-git-send-email-hauke@hauke-m.de>


Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 include/linux/compat-2.6.27.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/linux/compat-2.6.27.h b/include/linux/compat-2.6.27.h
index d667222..b9d7029 100644
--- a/include/linux/compat-2.6.27.h
+++ b/include/linux/compat-2.6.27.h
@@ -236,6 +236,8 @@ static inline void debugfs_remove_recursive(struct dentry *dentry)
 	_dev;								\
 })
 
+#define dev_name(dev) dev_name((struct device *)dev)
+
 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)) */
 
 #endif /* LINUX_26_27_COMPAT_H */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 2/4] compat: move va_format to compat-2.6.36.h
From: Hauke Mehrtens @ 2010-08-07 13:32 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens
In-Reply-To: <1281187941-7168-1-git-send-email-hauke@hauke-m.de>

This struct was introduced in kernel 2.6.36 and not 2.6.35.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 include/linux/compat-2.6.35.h |    5 -----
 include/linux/compat-2.6.36.h |    5 +++++
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/linux/compat-2.6.35.h b/include/linux/compat-2.6.35.h
index d2e82cc..f0562cd 100644
--- a/include/linux/compat-2.6.35.h
+++ b/include/linux/compat-2.6.35.h
@@ -8,11 +8,6 @@
 #include <net/sock.h>
 #include <linux/types.h>
 
-struct va_format {
-	const char *fmt;
-	va_list *va;
-};
-
 /* added on linux/kernel.h */
 #define USHRT_MAX      ((u16)(~0U))
 #define SHRT_MAX       ((s16)(USHRT_MAX>>1))
diff --git a/include/linux/compat-2.6.36.h b/include/linux/compat-2.6.36.h
index 0307108..b14c772 100644
--- a/include/linux/compat-2.6.36.h
+++ b/include/linux/compat-2.6.36.h
@@ -8,6 +8,11 @@
 #define kparam_block_sysfs_write(a)
 #define kparam_unblock_sysfs_write(a)
 
+struct va_format {
+	const char *fmt;
+	va_list *va;
+};
+
 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) */
 
 #endif /* LINUX_26_36_COMPAT_H */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/4] compat: backport n_tty_ioctl_helper
From: Hauke Mehrtens @ 2010-08-07 13:32 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens
In-Reply-To: <1281187941-7168-1-git-send-email-hauke@hauke-m.de>

This function is needed by some bluetooth drivers

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 compat/compat-2.6.28.c        |  128 +++++++++++++++++++++++++++++++++++++++++
 include/linux/compat-2.6.28.h |    6 ++
 2 files changed, 134 insertions(+), 0 deletions(-)

diff --git a/compat/compat-2.6.28.c b/compat/compat-2.6.28.c
index 115bd23..bfb645a 100644
--- a/compat/compat-2.6.28.c
+++ b/compat/compat-2.6.28.c
@@ -13,6 +13,8 @@
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28))
 
 #include <linux/usb.h>
+#include <linux/tty.h>
+#include <asm/poll.h>
 
 /* 2.6.28 compat code goes here */
 
@@ -370,4 +372,130 @@ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
 }
 EXPORT_SYMBOL(skb_add_rx_frag);
 
+void tty_write_unlock(struct tty_struct *tty)
+{
+	mutex_unlock(&tty->atomic_write_lock);
+	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+	if (!mutex_trylock(&tty->atomic_write_lock)) {
+		if (ndelay)
+			return -EAGAIN;
+		if (mutex_lock_interruptible(&tty->atomic_write_lock))
+			return -ERESTARTSYS;
+	}
+	return 0;
+}
+
+/**
+ *	send_prio_char		-	send priority character
+ *
+ *	Send a high priority character to the tty even if stopped
+ *
+ *	Locking: none for xchar method, write ordering for write method.
+ */
+
+static int send_prio_char(struct tty_struct *tty, char ch)
+{
+	int	was_stopped = tty->stopped;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+	if (tty->ops->send_xchar) {
+		tty->ops->send_xchar(tty, ch);
+#else
+	if (tty->driver->send_xchar) {
+		tty->driver->send_xchar(tty, ch);
+#endif
+		return 0;
+	}
+
+	if (tty_write_lock(tty, 0) < 0)
+		return -ERESTARTSYS;
+
+	if (was_stopped)
+		start_tty(tty);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+	tty->ops->write(tty, &ch, 1);
+#else
+	tty->driver->write(tty, &ch, 1);
+#endif
+	if (was_stopped)
+		stop_tty(tty);
+	tty_write_unlock(tty);
+	return 0;
+}
+
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+	unsigned long flags;
+#endif
+	int retval;
+
+	switch (cmd) {
+	case TCXONC:
+		retval = tty_check_change(tty);
+		if (retval)
+			return retval;
+		switch (arg) {
+		case TCOOFF:
+			if (!tty->flow_stopped) {
+				tty->flow_stopped = 1;
+				stop_tty(tty);
+			}
+			break;
+		case TCOON:
+			if (tty->flow_stopped) {
+				tty->flow_stopped = 0;
+				start_tty(tty);
+			}
+			break;
+		case TCIOFF:
+			if (STOP_CHAR(tty) != __DISABLED_CHAR)
+				return send_prio_char(tty, STOP_CHAR(tty));
+			break;
+		case TCION:
+			if (START_CHAR(tty) != __DISABLED_CHAR)
+				return send_prio_char(tty, START_CHAR(tty));
+			break;
+		default:
+			return -EINVAL;
+		}
+		return 0;
+	case TCFLSH:
+		return tty_perform_flush(tty, arg);
+	case TIOCPKT:
+	{
+		int pktmode;
+
+		if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
+		    tty->driver->subtype != PTY_TYPE_MASTER)
+			return -ENOTTY;
+		if (get_user(pktmode, (int __user *) arg))
+			return -EFAULT;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+		spin_lock_irqsave(&tty->ctrl_lock, flags);
+#endif
+		if (pktmode) {
+			if (!tty->packet) {
+				tty->packet = 1;
+				tty->link->ctrl_status = 0;
+			}
+		} else
+			tty->packet = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+#endif
+		return 0;
+	}
+	default:
+		/* Try the mode commands */
+		return tty_mode_ioctl(tty, file, cmd, arg);
+	}
+}
+EXPORT_SYMBOL(n_tty_ioctl_helper);
+
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) */
diff --git a/include/linux/compat-2.6.28.h b/include/linux/compat-2.6.28.h
index 7160548..649fbbc 100644
--- a/include/linux/compat-2.6.28.h
+++ b/include/linux/compat-2.6.28.h
@@ -230,6 +230,12 @@ unsigned long round_jiffies_up(unsigned long j);
 extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
 			    int off, int size);
 
+#define wake_up_interruptible_poll(x, m)			\
+	__wake_up(x, TASK_INTERRUPTIBLE, 1, (void *) (m))
+
+extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
+		       unsigned int cmd, unsigned long arg);
+
 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) */
 
 #endif /* LINUX_26_28_COMPAT_H */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 0/4] compat: miscellaneous updates for compat
From: Hauke Mehrtens @ 2010-08-07 13:32 UTC (permalink / raw)
  To: lrodriguez; +Cc: linux-wireless, mcgrof, Hauke Mehrtens

This series contains miscellaneous updates for compat. They are compile
tested with kernel 2.6.26 to 2.6.35. ath9k and b43 were tested with
kernel 2.6.32.

Hauke Mehrtens (4):
  compat: backport n_tty_ioctl_helper
  compat: move va_format to compat-2.6.36.h
  compat: fix compiler warning
  compat: update compat_firmware_class.c

 compat/compat-2.6.28.c         |  128 ++++++++++++++++++
 compat/compat_firmware_class.c |  290 ++++++++++++++++++++-------------------
 include/linux/compat-2.6.27.h  |    2 +
 include/linux/compat-2.6.28.h  |    6 +
 include/linux/compat-2.6.35.h  |    5 -
 include/linux/compat-2.6.36.h  |    5 +
 6 files changed, 290 insertions(+), 146 deletions(-)


^ permalink raw reply

* Re: [stable] ssb: 2.6.34.1 -> 2.6.34.2 regression
From: Michael Büsch @ 2010-08-07 10:44 UTC (permalink / raw)
  To: Greg KH; +Cc: stable, Christoph Fritz, Larry Finger, wireless, b43-dev
In-Reply-To: <20100806235631.GA21827@kroah.com>

On 08/07/2010 01:56 AM, Greg KH wrote:
> On Sat, Aug 07, 2010 at 12:53:06AM +0200, Michael Büsch wrote:
>> Hi,
>>
>> The SPROM changes applied to SSB in 2.6.34.2 completely broke SPROM
>> extraction. This leads to broken wireless for my BCM4306 card.
>> All other BCM43xx and BCM44xx most likely are affected, too.
>> Symptoms should be wrong MAC addresses and broken transmission (for 43xx).
>>
>> The patch changed the SPEX() macro and removed the offset subtraction,
>> but did not remove the actual 0x1000 offset from the SPROM defines.
>> This results in random memory poking rather than proper SPROM data
>> extraction.
>>
>> I applied the following to my kernel to get it working again. However
>> this is not a proper fix. I suggest that the -stable SSB patch
>> is dropped and mainline patches being applied. They seem to
>> be correct (However I did not test mainline, yet).
>
> That's already done, can you please test the 2.6.34.3-rc1 kernel that
> was announced a few hours ago?  I should have fixed all of the issues
> there, if not, please let me know.

That one works. Thanks.

-- 
Greetings Michael.

^ permalink raw reply

* Re: ssb: 2.6.34.1 -> 2.6.34.2 regression
From: Rafał Miłecki @ 2010-08-07  6:29 UTC (permalink / raw)
  To: Michael Büsch
  Cc: stable, Christoph Fritz, Larry Finger, wireless, b43-dev
In-Reply-To: <4C5C9252.7040007@bu3sch.de>

2010/8/7 Michael Büsch <mb@bu3sch.de>:
> The SPROM changes applied to SSB in 2.6.34.2 completely broke SPROM
> extraction. This leads to broken wireless for my BCM4306 card.
> All other BCM43xx and BCM44xx most likely are affected, too.
> Symptoms should be wrong MAC addresses and broken transmission (for 43xx).
>
> The patch changed the SPEX() macro and removed the offset subtraction,
> but did not remove the actual 0x1000 offset from the SPROM defines.
> This results in random memory poking rather than proper SPROM data
> extraction.
>
> I applied the following to my kernel to get it working again. However
> this is not a proper fix. I suggest that the -stable SSB patch
> is dropped and mainline patches being applied. They seem to
> be correct (However I did not test mainline, yet).

The original patch didn't simply drop subtraction of offset, it also
modified defines in .h:
http://marc.info/?l=linux-wireless&m=127006884129062&w=4

It's Larry combined patch that you see in .34.2 and it indeed lacks
changes in defines. We already explained that situation, Greg will
revert it and apply correct patches instead.

-- 
Rafał

^ permalink raw reply

* Re: virtual access poitns (ath5k/mac80211)
From: Ryszard @ 2010-08-07  5:23 UTC (permalink / raw)
  To: Ben Greear; +Cc: Florian Fainelli, Patrick McHardy, linux-wireless
In-Reply-To: <AANLkTim8i245P0nGcnpsf63_O8xXeby9re=pX53WfOwV@mail.gmail.com>

hey ben,

i've spend a day attempting to get the kernel installed but am not
having much luck.. the box i'm installing on is an alix
(http://www.pcengines.ch/alix2d13.htm, amd geode) which has an ubuntu
lucid kernel on it.

the error message i'm getting (before it drops to an initramfs) is:
==========================================
Gave up waiting for root device.  Common problems:
 - Boot args (cat /proc/cmdline)
   - Check rootdelay= (did the system wait long enough?)
   - Check root= (did the system wait for the right device?)
 - Missing modules (cat /proc/modules; ls /dev)
chvt: can't open console
ALERT! /dev/disk/by-uuid/371f6b1f-0267-41c1-94d6-4068567af74f does not
exist. Dropping to a shell!



BusyBox v1.13.3 (Ubuntu 1:1.13.3-1ubuntu11) built-in shell (ash)
Enter 'help' for a list of built-in commands.


(initramfs)
==========================================

while the error message may seem obvious (that it cant find the disk)
i'm unsure how to proceed.. are you able to give any tips at all?
(i'll keep plugging away in the meantime)
regs
R

On 2 August 2010 21:16, Ryszard <ryszard99@gmail.com> wrote:
> Hi Ben,
> i'll get to this in the next day or so.
> regs
> R.
>
> On 2 August 2010 15:00, Ben Greear <greearb@candelatech.com> wrote:
>>
>> On 08/01/2010 06:51 PM, Ryszard wrote:
>>>
>>> Hey ben,
>>>
>>> thanks for the reply on this.
>>>

^ permalink raw reply

* [RFC] minstrel_ht: fill out more than 3 rates
From: Christian Lamparter @ 2010-08-06 22:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: Felix Fietkau

Hello Felix,

I've stumbled into this conundrum a while ago...
then as usual: forgot that it existed, until yesterday:

As you know minstrel (our non ht fallback) enables mrr-mode
only if the driver sets hw->max_rates to 4 or more. 
minstrel_ht - on the other hand - just prepares a set
of 3 rates, so at least one additional retry with
different tx-vectors remains unused...

How the last tries should be used is up for debate,
I've opted out for lowest possible MCS.
(although, some devices may also use a legacy
 rate for the final tries...)

And the reason why I think it's worth to do an additional
round: The reordering penalty for lost MPDUs on the receiver-
side can be as high as 100ms, which is quite expensive compared
to some extra airtime...
---
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index c5b4659..5f44c0b 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -584,7 +584,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	struct minstrel_ht_sta_priv *msp = priv_sta;
 	struct minstrel_ht_sta *mi = &msp->ht;
 	struct minstrel_priv *mp = priv;
-	int sample_idx;
+	int sample_idx, i = 0;
 
 	if (rate_control_send_low(sta, priv_sta, txrc))
 		return;
@@ -595,21 +595,29 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	info->flags |= mi->tx_flags;
 	sample_idx = minstrel_get_sample_rate(mp, mi);
 	if (sample_idx >= 0) {
-		minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
+		minstrel_ht_set_rate(mp, mi, &ar[i++], sample_idx,
 			txrc, true, false);
-		minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
+		minstrel_ht_set_rate(mp, mi, &ar[i++], mi->max_tp_rate,
 			txrc, false, true);
 		info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
 	} else {
-		minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
+		minstrel_ht_set_rate(mp, mi, &ar[i++], mi->max_tp_rate,
 			txrc, false, false);
-		minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
+		minstrel_ht_set_rate(mp, mi, &ar[i++], mi->max_tp_rate2,
 			txrc, false, true);
 	}
-	minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true);
+	minstrel_ht_set_rate(mp, mi, &ar[i++], mi->max_prob_rate,
+			     txrc, false, true);
 
-	ar[3].count = 0;
-	ar[3].idx = -1;
+	for (;i < mp->hw->max_rates; i++) {
+		minstrel_ht_set_rate(mp, mi, &ar[i++], 0,
+				     txrc, false, true);
+	}
+
+	for (; i < IEEE80211_TX_MAX_RATES; i++) {
+		ar[i].count = 0;
+		ar[i].idx = -1;
+	}
 
 	mi->total_packets++;
 

^ permalink raw reply related

* Re: [stable] ssb: 2.6.34.1 -> 2.6.34.2 regression
From: Greg KH @ 2010-08-06 23:56 UTC (permalink / raw)
  To: Michael Büsch
  Cc: stable, Christoph Fritz, Larry Finger, wireless, b43-dev
In-Reply-To: <4C5C9252.7040007@bu3sch.de>

On Sat, Aug 07, 2010 at 12:53:06AM +0200, Michael Büsch wrote:
> Hi,
> 
> The SPROM changes applied to SSB in 2.6.34.2 completely broke SPROM
> extraction. This leads to broken wireless for my BCM4306 card.
> All other BCM43xx and BCM44xx most likely are affected, too.
> Symptoms should be wrong MAC addresses and broken transmission (for 43xx).
> 
> The patch changed the SPEX() macro and removed the offset subtraction,
> but did not remove the actual 0x1000 offset from the SPROM defines.
> This results in random memory poking rather than proper SPROM data
> extraction.
> 
> I applied the following to my kernel to get it working again. However
> this is not a proper fix. I suggest that the -stable SSB patch
> is dropped and mainline patches being applied. They seem to
> be correct (However I did not test mainline, yet).

That's already done, can you please test the 2.6.34.3-rc1 kernel that
was announced a few hours ago?  I should have fixed all of the issues
there, if not, please let me know.

thanks,
greg k-h

^ permalink raw reply

* ssb: 2.6.34.1 -> 2.6.34.2 regression
From: Michael Büsch @ 2010-08-06 22:53 UTC (permalink / raw)
  To: stable, Christoph Fritz, Larry Finger; +Cc: b43-dev, wireless

Hi,

The SPROM changes applied to SSB in 2.6.34.2 completely broke SPROM
extraction. This leads to broken wireless for my BCM4306 card.
All other BCM43xx and BCM44xx most likely are affected, too.
Symptoms should be wrong MAC addresses and broken transmission (for 43xx).

The patch changed the SPEX() macro and removed the offset subtraction,
but did not remove the actual 0x1000 offset from the SPROM defines.
This results in random memory poking rather than proper SPROM data
extraction.

I applied the following to my kernel to get it working again. However
this is not a proper fix. I suggest that the -stable SSB patch
is dropped and mainline patches being applied. They seem to
be correct (However I did not test mainline, yet).


Index: linux-2.6.34/drivers/ssb/pci.c
===================================================================
--- linux-2.6.34.orig/drivers/ssb/pci.c	2010-08-05 23:26:07.000000000 +0200
+++ linux-2.6.34/drivers/ssb/pci.c	2010-08-07 00:17:26.000000000 +0200
@@ -169,7 +169,7 @@ err_pci:
  }

  /* Get the word-offset for a SSB_SPROM_XXX define. */
-#define SPOFF(offset)	((offset) / sizeof(u16))
+#define SPOFF(offset)	(((offset) - SSB_SPROM_BASE1) / sizeof(u16))
  /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX 
defines. */
  #define SPEX16(_outvar, _offset, _mask, _shift)	\
  	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
-- 
Greetings Michael.

^ permalink raw reply

* Re: [PATCH 3/8] iwlwifi: separate thermal throttling function
From: Guy, Wey-Yi @ 2010-08-06 21:56 UTC (permalink / raw)
  To: linville@tuxdriver.com
  Cc: Johannes Berg, linux-wireless@vger.kernel.org,
	ipw3945-devel@lists.sourceforge.net
In-Reply-To: <1281100480.3853.424.camel@jlt3.sipsolutions.net>

[-- Attachment #1: Type: text/plain, Size: 1618 bytes --]

Hi John,

Based on ours previous conversation, I understand the thermal throttling
patch is not being merge it, since it has a stupid bug I create and
being identify by Johannes, is it ok for you to merge the attached patch
with the original patch work while you ready to push?

Thanks

On Fri, 2010-08-06 at 06:14 -0700, Johannes Berg wrote:
> > @@ -325,9 +283,15 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
> >  	else if (priv->cfg->supports_idle &&
> >  		 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
> >  		iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
> > -	else if (tt->state >= IWL_TI_1)
> > -		iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
> > -	else if (!enabled)
> > +	else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
> > +		 priv->cfg->ops->lib->tt_ops.tt_power_mode) {
> > +		if (priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
> > +			/* in thermal throttling low power state */
> > +			iwl_static_sleep_cmd(priv, &cmd,
> > +			    priv->cfg->ops->lib->tt_ops.tt_power_mode(priv),
> > +			    dtimper);
> > +		}
> > +	} else if (!enabled)
> >  		iwl_power_sleep_cam_cmd(priv, &cmd);
> >  	else if (priv->power_data.debug_sleep_level_override >= 0)
> >  		iwl_static_sleep_cmd(priv, &cmd,
> 
> This is very very broken because it adds an often-used code path that
> will not initialise "cmd" at all. It needs to be
> 
> ...
> else if (priv->...lower_power_detection &&
>          priv->...tt_power_mode &&
>          priv->...lower_power_detection(priv))
>         iwl_static_sleep_cmd(...)
> else if (!enabled)
> ...
> 
> johannes
> 

[-- Attachment #2: 0001-iwlwifi-fix-thermal-throttling-related-power-manage.patch --]
[-- Type: text/x-patch, Size: 1783 bytes --]

>From 98ec32fb40c92ce0175a3246660f4ae7969308d7 Mon Sep 17 00:00:00 2001
From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Date: Fri, 6 Aug 2010 12:39:14 -0700
Subject: [PATCH 1/1] iwlwifi: fix thermal throttling related power manageent operation

The current approach is very broken because it adds an
often-used code path that will not initialise "cmd" at all.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Shanyu Zhao <shanyu.zhao.intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-power.c |   12 +++++-------
 1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index da1f2ae..63c0ab4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -284,13 +284,11 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 		 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
 		iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
 	else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
-		 priv->cfg->ops->lib->tt_ops.tt_power_mode) {
-		if (priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
-			/* in thermal throttling low power state */
-			iwl_static_sleep_cmd(priv, &cmd,
-			    priv->cfg->ops->lib->tt_ops.tt_power_mode(priv),
-			    dtimper);
-		}
+		 priv->cfg->ops->lib->tt_ops.tt_power_mode &&
+		 priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
+		/* in thermal throttling low power state */
+		iwl_static_sleep_cmd(priv, &cmd,
+		    priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
 	} else if (!enabled)
 		iwl_power_sleep_cam_cmd(priv, &cmd);
 	else if (priv->power_data.debug_sleep_level_override >= 0)
-- 
1.5.6.3


^ permalink raw reply related

* Re: wireless-testing won't build
From: Ben Greear @ 2010-08-06 21:14 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <20100806201956.GD2753@tuxdriver.com>

On 08/06/2010 01:19 PM, John W. Linville wrote:
> On Fri, Aug 06, 2010 at 12:58:02PM -0700, Ben Greear wrote:
>> [greearb@grok2 wireless-testing.p4s]$ make bzImage modules
>> make -C /home/greearb/git/wireless-testing O=/home/greearb/kernel/2.6/wireless-testing.p4s/. bzImage modules
>>    Using /home/greearb/git/wireless-testing as source for kernel
>>    GEN     /home/greearb/kernel/2.6/wireless-testing.p4s/Makefile
>>    CHK     include/linux/version.h
>>    CHK     include/generated/utsrelease.h
>>    CALL    /home/greearb/git/wireless-testing/scripts/checksyscalls.sh
>>    CHK     include/generated/compile.h
>>    CC [M]  drivers/net/wireless/libertas/cfg.o
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c: In function ‘lbs_scan_worker’:
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: ‘TASK_NORMAL’ undeclared (first use in this function)
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: (Each undeclared identifier is reported only once
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: for each function it appears in.)
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c: In function ‘lbs_cfg_connect’:
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: implicit declaration of function ‘signal_pending’
>> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: implicit declaration of function ‘schedule_timeout’
>> make[6]: *** [drivers/net/wireless/libertas/cfg.o] Error 1
>> make[5]: *** [drivers/net/wireless/libertas] Error 2
>> make[4]: *** [drivers/net/wireless] Error 2
>> make[3]: *** [drivers/net] Error 2
>> make[2]: *** [drivers] Error 2
>> make[1]: *** [sub-make] Error 2
>> make: *** [all] Error 2
>
> It builds here...does adding "#include<linux/sched.h>" at the top
> of drivers/net/wireless/libertas/cfg.c correct this for you?

That seems to do the trick.  Compile is continuing now...

Ben

>
> John


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: pull request: wireless-2.6 2010-08-06
From: David Miller @ 2010-08-06 20:46 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20100806191443.GB2753@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Fri, 6 Aug 2010 15:14:43 -0400

> Here is the first round of fixes intended for 2.6.36.  It is bigger than
> I would prefer, but I hope you will still find it acceptable, especially
> as we are still so early in the cycle.

Pulled, thanks John.

As you know I'd prefer if things settle down from this point
forward, thanks :-)

^ permalink raw reply

* [PATCH] b43: move hwrng registration driver to wireless core initialization
From: John W. Linville @ 2010-08-06 20:26 UTC (permalink / raw)
  To: linux-wireless; +Cc: Michael Buesch, Larry Finger, John W. Linville

...and unregistration to core shutdown.  Previously, the driver
remained registered even when the hardware was shutdown.  That
causes the driver to return -ENODEV if the b43 device is IFF_DOWN.
This change causes the driver to disappear in that case, allowing
/dev/hwrng to still function if another hwrng device is available.

Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 drivers/net/wireless/b43/main.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 20631ae..4062c07 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -4250,6 +4250,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
 	B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
 	if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
 		return;
+
+	/* Unregister HW RNG driver */
+	b43_rng_exit(dev->wl);
+
 	b43_set_status(dev, B43_STAT_UNINIT);
 
 	/* Stop the microcode PSM. */
@@ -4379,6 +4383,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 
 	b43_set_status(dev, B43_STAT_INITIALIZED);
 
+	/* Register HW RNG driver */
+	b43_rng_init(dev->wl);
+
 out:
 	return err;
 
@@ -4984,7 +4991,6 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
 		if (err)
 			goto err_one_core_detach;
 		b43_leds_register(wl->current_dev);
-		b43_rng_init(wl);
 	}
 
       out:
@@ -5020,7 +5026,6 @@ static void b43_remove(struct ssb_device *dev)
 	b43_one_core_detach(dev);
 
 	if (list_empty(&wl->devlist)) {
-		b43_rng_exit(wl);
 		b43_leds_unregister(wl);
 		/* Last core on the chip unregistered.
 		 * We can destroy common struct b43_wl.
-- 
1.7.2


^ permalink raw reply related

* Re: wireless-testing won't build
From: John W. Linville @ 2010-08-06 20:19 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <4C5C694A.7060500@candelatech.com>

On Fri, Aug 06, 2010 at 12:58:02PM -0700, Ben Greear wrote:
> [greearb@grok2 wireless-testing.p4s]$ make bzImage modules
> make -C /home/greearb/git/wireless-testing O=/home/greearb/kernel/2.6/wireless-testing.p4s/. bzImage modules
>   Using /home/greearb/git/wireless-testing as source for kernel
>   GEN     /home/greearb/kernel/2.6/wireless-testing.p4s/Makefile
>   CHK     include/linux/version.h
>   CHK     include/generated/utsrelease.h
>   CALL    /home/greearb/git/wireless-testing/scripts/checksyscalls.sh
>   CHK     include/generated/compile.h
>   CC [M]  drivers/net/wireless/libertas/cfg.o
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c: In function ‘lbs_scan_worker’:
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: ‘TASK_NORMAL’ undeclared (first use in this function)
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: (Each undeclared identifier is reported only once
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: for each function it appears in.)
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c: In function ‘lbs_cfg_connect’:
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: implicit declaration of function ‘signal_pending’
> /home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: implicit declaration of function ‘schedule_timeout’
> make[6]: *** [drivers/net/wireless/libertas/cfg.o] Error 1
> make[5]: *** [drivers/net/wireless/libertas] Error 2
> make[4]: *** [drivers/net/wireless] Error 2
> make[3]: *** [drivers/net] Error 2
> make[2]: *** [drivers] Error 2
> make[1]: *** [sub-make] Error 2
> make: *** [all] Error 2

It builds here...does adding "#include <linux/sched.h>" at the top
of drivers/net/wireless/libertas/cfg.c correct this for you?

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* wireless-testing won't build
From: Ben Greear @ 2010-08-06 19:58 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

[greearb@grok2 wireless-testing.p4s]$ make bzImage modules
make -C /home/greearb/git/wireless-testing O=/home/greearb/kernel/2.6/wireless-testing.p4s/. bzImage modules
   Using /home/greearb/git/wireless-testing as source for kernel
   GEN     /home/greearb/kernel/2.6/wireless-testing.p4s/Makefile
   CHK     include/linux/version.h
   CHK     include/generated/utsrelease.h
   CALL    /home/greearb/git/wireless-testing/scripts/checksyscalls.sh
   CHK     include/generated/compile.h
   CC [M]  drivers/net/wireless/libertas/cfg.o
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c: In function ‘lbs_scan_worker’:
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: ‘TASK_NORMAL’ undeclared (first use in this function)
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: (Each undeclared identifier is reported only once
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:722: error: for each function it appears in.)
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c: In function ‘lbs_cfg_connect’:
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: implicit declaration of function ‘signal_pending’
/home/greearb/git/wireless-testing/drivers/net/wireless/libertas/cfg.c:1267: error: implicit declaration of function ‘schedule_timeout’
make[6]: *** [drivers/net/wireless/libertas/cfg.o] Error 1
make[5]: *** [drivers/net/wireless/libertas] Error 2
make[4]: *** [drivers/net/wireless] Error 2
make[3]: *** [drivers/net] Error 2
make[2]: *** [drivers] Error 2
make[1]: *** [sub-make] Error 2
make: *** [all] Error 2

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: A mailing list for regulatory wireless-regdb changes
From: Luis R. Rodriguez @ 2010-08-06 19:32 UTC (permalink / raw)
  To: John W. Linville, Johannes Berg
  Cc: David Woodhouse, linux-wireless, Michael Green, David Quan,
	Emmanuel Grumbach
In-Reply-To: <AANLkTinQLcc9iwu9YSV64_JcmDLdg9bkkG7PHA17oSRW@mail.gmail.com>

On Thu, May 27, 2010 at 9:44 AM, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
> On Thu, May 27, 2010 at 8:43 AM, John W. Linville
> <linville@tuxdriver.com> wrote:
>> On Thu, May 27, 2010 at 04:34:12PM +0100, David Woodhouse wrote:
>>> On Thu, 2010-05-27 at 11:05 -0400, John W. Linville wrote:
>>> > On Thu, May 27, 2010 at 01:15:50AM -0700, Luis R. Rodriguez wrote:
>>> > > David, can I trouble you for a mailman wireless-regdb mailing list on
>>> > > infradead.org? This would be used by those who are not developers and
>>> > > do not need to be subscribed to linux-wireless. An example are
>>> > > regulatory guys at different companies and generally interested
>>> > > people/developers on the topic. This should hopefully accelerate the
>>> > > turn around time for reviewing of patches and also a good placeholder
>>> > > for us to go back and check the discussions that went on about this.
>>> >
>>> > Is this really necessary?
>>>
>>> Feel free not to use it :)
>>
>> Just hoping to avoid unnecessary confusion -- I suppose it is fine
>> if that is what people want...
>
> I do not know how else to help speed up review without having to wait
> for a intermediary delay of someone at a company forwarding some
> regulatory changes e-mail to a person who is supposed to review them.
> With the list we would have a direct way for people to communicate
> with the folks who do care about regulatory and who may have roles who
> do that.
>
> If people do not mind the constant "please give us a few days" e-mails
> then things work without the list but then we (at least Atheros) just
> need to make sure regulatory change e-mails do get to the proper folks
> for review because we (Atheros) is committed to reviewing these
> changes.

BTW I found a use for this list now, to archive some initial e-mails
from Michael / others regarding reguatory changes. This information
would need to be parsed and then submitted in patch form but it should
also provide us with a URL reference on a regulatory related mailing
list for some details for commits on wireless-regdb.

I'll try it out next and you guys tell me if its OK.

PS. I'll be subscribing a few of you guys to this list now :)

  Luis

^ permalink raw reply

* Re: Patches not make into wireless-next
From: John W. Linville @ 2010-08-06 19:17 UTC (permalink / raw)
  To: Guy, Wey-Yi
  Cc: linux-wireless@vger.kernel.org,
	ipw3945-devel@lists.sourceforge.net
In-Reply-To: <1281121153.4294.2.camel@wwguy-huron>

On Fri, Aug 06, 2010 at 11:59:13AM -0700, Guy, Wey-Yi wrote:
> Hi John,
> 
> Number of patches not make into wireless-next-2.6 last week
> 
> iwlwifi: make iwl_set_hw_params static to _agn
> iwlwifi: separate thermal throttling function
> iwlagn: log pci revision id
> iwlwifi: make iwl_hw_detect static to _agn
> 
> 
> I need to re-work "thermal-throttling" patch to include Johanne's fix,
> how about other patches, any recommendation?
> 
> Thanks
> Wey

I'm not merging any non-fix patches at the moment.  That activity
will resume at or about the time that 2.6.36-rc1 is released.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* pull request: wireless-2.6 2010-08-06
From: John W. Linville @ 2010-08-06 19:14 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev, linux-kernel

Dave,

Here is the first round of fixes intended for 2.6.36.  It is bigger than
I would prefer, but I hope you will still find it acceptable, especially
as we are still so early in the cycle.

The largest batch of fixes are from the ath9k team.  These are primarily
calibration fixes that they assure me fix some real connectivity
problems.  The patch from Luis fixes a potential regulatory compliance
issue as well.

The next largest batch is from the libertas guys.  This is necessary to
correct some association problems introduced by some of the patches
already sent for 2.6.36.

Also included are a couple of fixes for recently introduced build
warnings, a MAINTAINERS update, a PCI ID, and some minor adjustments to
some user-visible log SPAM.

The remainder are a variety of small fixes of varying significance.
This also includes a few Bluetooth fixes by way of Marcel Holtmann.
I think all of these are worthwhile to have merged at or before -rc1.

Please let me know if there are problems!

Thanks,

John

---

The following changes since commit 4b030d4288a569d6bdeca884d7f102d951f097f2:

  isdn: fix information leak (2010-08-05 13:21:25 -0700)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master

Andy Lutomirski (1):
      iwlagn: Improve aggregation failure error messages

Christoph Fritz (1):
      wireless: ipw2100: check result of kzalloc()

Dan Williams (3):
      libertas: get the right # of scanned BSSes
      libertas: fix association with some APs by using extended rates
      libertas: scan before assocation if no BSSID was given

David Miller (1):
      Bluetooth: Use list_head for HCI blacklist head

Felix Fietkau (7):
      ath9k_hw: clean up and fix initial noise floor calibration
      ath9k_hw: fix periodic noise floor calibration on AR9003
      ath9k: fix a crash in the PA predistortion apply function
      ath9k_hw: fix analog shift register writes on AR9003
      ath9k: prevent calibration during off-channel activity
      ath9k_hw: clean up per-channel calibration data
      ath9k_hw: fix a noise floor calibration related race condition

Gustavo F. Padovan (2):
      Bluetooth: Remove __exit from rfcomm_cleanup_ttys()
      Bluetooth: Don't send RFC for Basic Mode if only it is supported

Jan Friedrich (1):
      ath9k: fix erased ieee80211_rx_status.mactime

Johannes Berg (5):
      iwlwifi: fix possible recursive locking deadlock
      mac80211: fix scan locking wrt. hw scan
      iwlwifi: fix compile warning
      iwlwifi: fix TX tracer
      iwlwifi: fix locking assertions

John W. Linville (2):
      Merge branch 'master' of git://git.kernel.org/.../holtmann/bluetooth-next-2.6
      rtl8180: avoid potential NULL deref in rtl8180_beacon_work

Juuso Oikarinen (1):
      mac80211: Fix compilation warning when CONFIG_INET is not set

Kulikov Vasiliy (2):
      net: wl12xx: do not use kfree'd memory
      rt2x00: do not use PCI resources before pci_enable_device()

Larry Finger (1):
      p54pci: Add PCI ID for SMC2802W

Lorenzo Bianconi (1):
      ath9k: fix an issue in ath_atx_tid paused flag management

Luis R. Rodriguez (1):
      ath9k_hw: Fix regulatory CTL index usage for AR9003

Sujith (1):
      ath9k: Remove myself from the MAINTAINERS list

Ville Tervo (1):
      Bluetooth: Check result code of L2CAP information response

Wey-Yi Guy (2):
      iwlwifi: BA scd_flow not match condition detected
      iwlagn: fix typo in ucode_bt_stats_read debugfs

 MAINTAINERS                                    |    1 -
 drivers/net/wireless/ath/ath9k/ar9002_calib.c  |   43 ++-
 drivers/net/wireless/ath/ath9k/ar9003_calib.c  |   18 +-
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c |  388 +++++++++++++++++++++++-
 drivers/net/wireless/ath/ath9k/ar9003_paprd.c  |   17 +-
 drivers/net/wireless/ath/ath9k/ar9003_phy.c    |    6 +-
 drivers/net/wireless/ath/ath9k/ath9k.h         |    3 +-
 drivers/net/wireless/ath/ath9k/calib.c         |  118 ++++----
 drivers/net/wireless/ath/ath9k/calib.h         |    8 +-
 drivers/net/wireless/ath/ath9k/htc.h           |    2 +
 drivers/net/wireless/ath/ath9k/htc_drv_main.c  |   10 +-
 drivers/net/wireless/ath/ath9k/hw.c            |   25 +-
 drivers/net/wireless/ath/ath9k/hw.h            |   25 +-
 drivers/net/wireless/ath/ath9k/main.c          |  104 ++++---
 drivers/net/wireless/ath/ath9k/recv.c          |   10 +-
 drivers/net/wireless/ath/ath9k/xmit.c          |   36 +--
 drivers/net/wireless/ipw2x00/ipw2100.c         |    4 +
 drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c |    2 +-
 drivers/net/wireless/iwlwifi/iwl-agn-lib.c     |    2 +-
 drivers/net/wireless/iwlwifi/iwl-agn-rs.c      |   11 +-
 drivers/net/wireless/iwlwifi/iwl-agn-tx.c      |   11 +-
 drivers/net/wireless/iwlwifi/iwl-core.c        |    6 +-
 drivers/net/wireless/iwlwifi/iwl-debug.h       |    2 +-
 drivers/net/wireless/iwlwifi/iwl-devtrace.h    |    2 +-
 drivers/net/wireless/iwlwifi/iwl-scan.c        |    2 +-
 drivers/net/wireless/iwlwifi/iwl-sta.c         |    6 +-
 drivers/net/wireless/libertas/cfg.c            |  214 ++++++++++---
 drivers/net/wireless/libertas/dev.h            |    5 +
 drivers/net/wireless/libertas/main.c           |    1 +
 drivers/net/wireless/p54/p54pci.c              |    2 +
 drivers/net/wireless/rt2x00/rt2x00pci.c        |   21 +-
 drivers/net/wireless/rtl818x/rtl8180_dev.c     |    2 +
 drivers/net/wireless/wl12xx/wl1271_spi.c       |    3 +-
 include/net/bluetooth/hci_core.h               |    2 +-
 net/bluetooth/hci_core.c                       |    2 +-
 net/bluetooth/hci_sock.c                       |    8 +-
 net/bluetooth/hci_sysfs.c                      |    3 +-
 net/bluetooth/l2cap.c                          |   24 ++-
 net/bluetooth/rfcomm/tty.c                     |    2 +-
 net/mac80211/main.c                            |    2 +
 net/mac80211/scan.c                            |   14 -
 41 files changed, 866 insertions(+), 301 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index b04b97f..1dcedaa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1085,7 +1085,6 @@ F:	drivers/net/wireless/ath/ath5k/
 ATHEROS ATH9K WIRELESS DRIVER
 M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
 M:	Jouni Malinen <jmalinen@atheros.com>
-M:	Sujith Manoharan <Sujith.Manoharan@atheros.com>
 M:	Vasanthakumar Thiagarajan <vasanth@atheros.com>
 M:	Senthil Balasubramanian <senthilkumar@atheros.com>
 L:	linux-wireless@vger.kernel.org
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index dabafb8..fe7418a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -63,6 +63,7 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
 				      u8 rxchainmask,
 				      struct ath9k_cal_list *currCal)
 {
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	bool iscaldone = false;
 
 	if (currCal->calState == CAL_RUNNING) {
@@ -81,14 +82,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
 				}
 
 				currCal->calData->calPostProc(ah, numChains);
-				ichan->CalValid |= currCal->calData->calType;
+				caldata->CalValid |= currCal->calData->calType;
 				currCal->calState = CAL_DONE;
 				iscaldone = true;
 			} else {
 				ar9002_hw_setup_calibration(ah, currCal);
 			}
 		}
-	} else if (!(ichan->CalValid & currCal->calData->calType)) {
+	} else if (!(caldata->CalValid & currCal->calData->calType)) {
 		ath9k_hw_reset_calibration(ah, currCal);
 	}
 
@@ -686,8 +687,13 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 {
 	bool iscaldone = true;
 	struct ath9k_cal_list *currCal = ah->cal_list_curr;
+	bool nfcal, nfcal_pending = false;
 
-	if (currCal &&
+	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
+	if (ah->caldata)
+		nfcal_pending = ah->caldata->nfcal_pending;
+
+	if (currCal && !nfcal &&
 	    (currCal->calState == CAL_RUNNING ||
 	     currCal->calState == CAL_WAITING)) {
 		iscaldone = ar9002_hw_per_calibration(ah, chan,
@@ -703,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 	}
 
 	/* Do NF cal only at longer intervals */
-	if (longcal) {
+	if (longcal || nfcal_pending) {
 		/* Do periodic PAOffset Cal */
 		ar9002_hw_pa_cal(ah, false);
 		ar9002_hw_olc_temp_compensation(ah);
@@ -712,16 +718,18 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 		 * Get the value from the previous NF cal and update
 		 * history buffer.
 		 */
-		ath9k_hw_getnf(ah, chan);
-
-		/*
-		 * Load the NF from history buffer of the current channel.
-		 * NF is slow time-variant, so it is OK to use a historical
-		 * value.
-		 */
-		ath9k_hw_loadnf(ah, ah->curchan);
+		if (ath9k_hw_getnf(ah, chan)) {
+			/*
+			 * Load the NF from history buffer of the current
+			 * channel.
+			 * NF is slow time-variant, so it is OK to use a
+			 * historical value.
+			 */
+			ath9k_hw_loadnf(ah, ah->curchan);
+		}
 
-		ath9k_hw_start_nfcal(ah);
+		if (longcal)
+			ath9k_hw_start_nfcal(ah, false);
 	}
 
 	return iscaldone;
@@ -869,8 +877,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 	ar9002_hw_pa_cal(ah, true);
 
 	/* Do NF Calibration after DC offset and other calibrations */
-	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
+	ath9k_hw_start_nfcal(ah, true);
+
+	if (ah->caldata)
+		ah->caldata->nfcal_pending = true;
 
 	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
@@ -901,7 +911,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 	}
 
-	chan->CalValid = 0;
+	if (ah->caldata)
+		ah->caldata->CalValid = 0;
 
 	return true;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 5a06503..4674ea8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -68,6 +68,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
 				      u8 rxchainmask,
 				      struct ath9k_cal_list *currCal)
 {
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	/* Cal is assumed not done until explicitly set below */
 	bool iscaldone = false;
 
@@ -95,7 +96,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
 				currCal->calData->calPostProc(ah, numChains);
 
 				/* Calibration has finished. */
-				ichan->CalValid |= currCal->calData->calType;
+				caldata->CalValid |= currCal->calData->calType;
 				currCal->calState = CAL_DONE;
 				iscaldone = true;
 			} else {
@@ -106,7 +107,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
 			ar9003_hw_setup_calibration(ah, currCal);
 			}
 		}
-	} else if (!(ichan->CalValid & currCal->calData->calType)) {
+	} else if (!(caldata->CalValid & currCal->calData->calType)) {
 		/* If current cal is marked invalid in channel, kick it off */
 		ath9k_hw_reset_calibration(ah, currCal);
 	}
@@ -149,6 +150,12 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
 	/* Do NF cal only at longer intervals */
 	if (longcal) {
 		/*
+		 * Get the value from the previous NF cal and update
+		 * history buffer.
+		 */
+		ath9k_hw_getnf(ah, chan);
+
+		/*
 		 * Load the NF from history buffer of the current channel.
 		 * NF is slow time-variant, so it is OK to use a historical
 		 * value.
@@ -156,7 +163,7 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
 		ath9k_hw_loadnf(ah, ah->curchan);
 
 		/* start NF calibration, without updating BB NF register */
-		ath9k_hw_start_nfcal(ah);
+		ath9k_hw_start_nfcal(ah, false);
 	}
 
 	return iscaldone;
@@ -762,6 +769,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	/* Revert chainmasks to their original values before NF cal */
 	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
 
+	ath9k_hw_start_nfcal(ah, true);
+
 	/* Initialize list pointers */
 	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
@@ -785,7 +794,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	if (ah->cal_list_curr)
 		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 
-	chan->CalValid = 0;
+	if (ah->caldata)
+		ah->caldata->CalValid = 0;
 
 	return true;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index ace8d26..b883b17 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -41,6 +41,20 @@
 #define LE16(x) __constant_cpu_to_le16(x)
 #define LE32(x) __constant_cpu_to_le32(x)
 
+/* Local defines to distinguish between extension and control CTL's */
+#define EXT_ADDITIVE (0x8000)
+#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
+#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
+#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   9  /* 10*log10(3)*2 */
+#define PWRINCR_3_TO_1_CHAIN      9             /* 10*log(3)*2 */
+#define PWRINCR_3_TO_2_CHAIN      3             /* floor(10*log(3/2)*2) */
+#define PWRINCR_2_TO_1_CHAIN      6             /* 10*log(2)*2 */
+
+#define SUB_NUM_CTL_MODES_AT_5G_40 2    /* excluding HT40, EXT-OFDM */
+#define SUB_NUM_CTL_MODES_AT_2G_40 3    /* excluding HT40, EXT-OFDM, EXT-CCK */
+
 static const struct ar9300_eeprom ar9300_default = {
 	.eepromVersion = 2,
 	.templateVersion = 2,
@@ -609,6 +623,14 @@ static const struct ar9300_eeprom ar9300_default = {
 	 }
 };
 
+static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
+{
+	if (fbin == AR9300_BCHAN_UNUSED)
+		return fbin;
+
+	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
 static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah)
 {
 	return 0;
@@ -1417,9 +1439,9 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
 #undef POW_SM
 }
 
-static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq)
+static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
+					      u8 *targetPowerValT2)
 {
-	u8 targetPowerValT2[ar9300RateSize];
 	/* XXX: hard code for now, need to get from eeprom struct */
 	u8 ht40PowerIncForPdadc = 0;
 	bool is2GHz = false;
@@ -1553,9 +1575,6 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq)
 			  "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
 		i++;
 	}
-
-	/* Write target power array to registers */
-	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
 }
 
 static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
@@ -1799,14 +1818,369 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
 	return 0;
 }
 
+static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep,
+					   int idx,
+					   int edge,
+					   bool is2GHz)
+{
+	struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G;
+	struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
+
+	if (is2GHz)
+		return ctl_2g[idx].ctlEdges[edge].tPower;
+	else
+		return ctl_5g[idx].ctlEdges[edge].tPower;
+}
+
+static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
+					     int idx,
+					     unsigned int edge,
+					     u16 freq,
+					     bool is2GHz)
+{
+	struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G;
+	struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
+
+	u8 *ctl_freqbin = is2GHz ?
+		&eep->ctl_freqbin_2G[idx][0] :
+		&eep->ctl_freqbin_5G[idx][0];
+
+	if (is2GHz) {
+		if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
+		    ctl_2g[idx].ctlEdges[edge - 1].flag)
+			return ctl_2g[idx].ctlEdges[edge - 1].tPower;
+	} else {
+		if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
+		    ctl_5g[idx].ctlEdges[edge - 1].flag)
+			return ctl_5g[idx].ctlEdges[edge - 1].tPower;
+	}
+
+	return AR9300_MAX_RATE_POWER;
+}
+
+/*
+ * Find the maximum conformance test limit for the given channel and CTL info
+ */
+static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
+					u16 freq, int idx, bool is2GHz)
+{
+	u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER;
+	u8 *ctl_freqbin = is2GHz ?
+		&eep->ctl_freqbin_2G[idx][0] :
+		&eep->ctl_freqbin_5G[idx][0];
+	u16 num_edges = is2GHz ?
+		AR9300_NUM_BAND_EDGES_2G : AR9300_NUM_BAND_EDGES_5G;
+	unsigned int edge;
+
+	/* Get the edge power */
+	for (edge = 0;
+	     (edge < num_edges) && (ctl_freqbin[edge] != AR9300_BCHAN_UNUSED);
+	     edge++) {
+		/*
+		 * If there's an exact channel match or an inband flag set
+		 * on the lower channel use the given rdEdgePower
+		 */
+		if (freq == ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz)) {
+			twiceMaxEdgePower =
+				ar9003_hw_get_direct_edge_power(eep, idx,
+								edge, is2GHz);
+			break;
+		} else if ((edge > 0) &&
+			   (freq < ath9k_hw_fbin2freq(ctl_freqbin[edge],
+						      is2GHz))) {
+			twiceMaxEdgePower =
+				ar9003_hw_get_indirect_edge_power(eep, idx,
+								  edge, freq,
+								  is2GHz);
+			/*
+			 * Leave loop - no more affecting edges possible in
+			 * this monotonic increasing list
+			 */
+			break;
+		}
+	}
+	return twiceMaxEdgePower;
+}
+
+static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
+					       struct ath9k_channel *chan,
+					       u8 *pPwrArray, u16 cfgCtl,
+					       u8 twiceAntennaReduction,
+					       u8 twiceMaxRegulatoryPower,
+					       u16 powerLimit)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
+	u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] = {
+		0, 3, 6, 9, AR9300_MAX_RATE_POWER
+	};
+	int i;
+	int16_t  twiceLargestAntenna;
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	u16 ctlModesFor11a[] = {
+		CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
+	};
+	u16 ctlModesFor11g[] = {
+		CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT,
+		CTL_11G_EXT, CTL_2GHT40
+	};
+	u16 numCtlModes, *pCtlMode, ctlMode, freq;
+	struct chan_centers centers;
+	u8 *ctlIndex;
+	u8 ctlNum;
+	u16 twiceMinEdgePower;
+	bool is2ghz = IS_CHAN_2GHZ(chan);
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	/* Compute TxPower reduction due to Antenna Gain */
+	if (is2ghz)
+		twiceLargestAntenna = pEepData->modalHeader2G.antennaGain;
+	else
+		twiceLargestAntenna = pEepData->modalHeader5G.antennaGain;
+
+	twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) -
+				twiceLargestAntenna, 0);
+
+	/*
+	 * scaledPower is the minimum of the user input power level
+	 * and the regulatory allowed power level
+	 */
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	/*
+	 * Reduce scaled Power by number of chains active to get
+	 * to per chain tx power level
+	 */
+	switch (ar5416_get_ntxchains(ah->txchainmask)) {
+	case 1:
+		break;
+	case 2:
+		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+		break;
+	case 3:
+		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+		break;
+	}
+
+	scaledPower = max((u16)0, scaledPower);
+
+	/*
+	 * Get target powers from EEPROM - our baseline for TX Power
+	 */
+	if (is2ghz) {
+		/* Setup for CTL modes */
+		/* CTL_11B, CTL_11G, CTL_2GHT20 */
+		numCtlModes =
+			ARRAY_SIZE(ctlModesFor11g) -
+				   SUB_NUM_CTL_MODES_AT_2G_40;
+		pCtlMode = ctlModesFor11g;
+		if (IS_CHAN_HT40(chan))
+			/* All 2G CTL's */
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+	} else {
+		/* Setup for CTL modes */
+		/* CTL_11A, CTL_5GHT20 */
+		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+					 SUB_NUM_CTL_MODES_AT_5G_40;
+		pCtlMode = ctlModesFor11a;
+		if (IS_CHAN_HT40(chan))
+			/* All 5G CTL's */
+			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+	}
+
+	/*
+	 * For MIMO, need to apply regulatory caps individually across
+	 * dynamically running modes: CCK, OFDM, HT20, HT40
+	 *
+	 * The outer loop walks through each possible applicable runtime mode.
+	 * The inner loop walks through each ctlIndex entry in EEPROM.
+	 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode.
+	 */
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		ath_print(common, ATH_DBG_REGULATORY,
+			  "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+			  "EXT_ADDITIVE %d\n",
+			  ctlMode, numCtlModes, isHt40CtlMode,
+			  (pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+		/* walk through each CTL index stored in EEPROM */
+		if (is2ghz) {
+			ctlIndex = pEepData->ctlIndex_2G;
+			ctlNum = AR9300_NUM_CTLS_2G;
+		} else {
+			ctlIndex = pEepData->ctlIndex_5G;
+			ctlNum = AR9300_NUM_CTLS_5G;
+		}
+
+		for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) {
+			ath_print(common, ATH_DBG_REGULATORY,
+				  "LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+				  "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+				  "chan %dn",
+				  i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
+				  chan->channel);
+
+				/*
+				 * compare test group from regulatory
+				 * channel list with test mode from pCtlMode
+				 * list
+				 */
+				if ((((cfgCtl & ~CTL_MODE_M) |
+				       (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+					ctlIndex[i]) ||
+				    (((cfgCtl & ~CTL_MODE_M) |
+				       (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+				     ((ctlIndex[i] & CTL_MODE_M) |
+				       SD_NO_CTL))) {
+					twiceMinEdgePower =
+					  ar9003_hw_get_max_edge_power(pEepData,
+								       freq, i,
+								       is2ghz);
+
+					if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
+						/*
+						 * Find the minimum of all CTL
+						 * edge powers that apply to
+						 * this channel
+						 */
+						twiceMaxEdgePower =
+							min(twiceMaxEdgePower,
+							    twiceMinEdgePower);
+						else {
+							/* specific */
+							twiceMaxEdgePower =
+							  twiceMinEdgePower;
+							break;
+						}
+				}
+			}
+
+			minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+			ath_print(common, ATH_DBG_REGULATORY,
+				  "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d "
+				  "sP %d minCtlPwr %d\n",
+				  ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+				  scaledPower, minCtlPower);
+
+			/* Apply ctl mode to correct target power set */
+			switch (pCtlMode[ctlMode]) {
+			case CTL_11B:
+				for (i = ALL_TARGET_LEGACY_1L_5L;
+				     i <= ALL_TARGET_LEGACY_11S; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				break;
+			case CTL_11A:
+			case CTL_11G:
+				for (i = ALL_TARGET_LEGACY_6_24;
+				     i <= ALL_TARGET_LEGACY_54; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				break;
+			case CTL_5GHT20:
+			case CTL_2GHT20:
+				for (i = ALL_TARGET_HT20_0_8_16;
+				     i <= ALL_TARGET_HT20_21; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				pPwrArray[ALL_TARGET_HT20_22] =
+				  (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22],
+					  minCtlPower);
+				pPwrArray[ALL_TARGET_HT20_23] =
+				  (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23],
+					   minCtlPower);
+				break;
+			case CTL_5GHT40:
+			case CTL_2GHT40:
+				for (i = ALL_TARGET_HT40_0_8_16;
+				     i <= ALL_TARGET_HT40_23; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				break;
+			default:
+			    break;
+			}
+	} /* end ctl mode checking */
+}
+
 static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
 					struct ath9k_channel *chan, u16 cfgCtl,
 					u8 twiceAntennaReduction,
 					u8 twiceMaxRegulatoryPower,
 					u8 powerLimit)
 {
-	ah->txpower_limit = powerLimit;
-	ar9003_hw_set_target_power_eeprom(ah, chan->channel);
+	struct ath_common *common = ath9k_hw_common(ah);
+	u8 targetPowerValT2[ar9300RateSize];
+	unsigned int i = 0;
+
+	ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2);
+	ar9003_hw_set_power_per_rate_table(ah, chan,
+					   targetPowerValT2, cfgCtl,
+					   twiceAntennaReduction,
+					   twiceMaxRegulatoryPower,
+					   powerLimit);
+
+	while (i < ar9300RateSize) {
+		ath_print(common, ATH_DBG_EEPROM,
+			  "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
+		i++;
+		ath_print(common, ATH_DBG_EEPROM,
+			  "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
+		i++;
+		ath_print(common, ATH_DBG_EEPROM,
+			  "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
+		i++;
+		ath_print(common, ATH_DBG_EEPROM,
+			  "TPC[%02d] 0x%08x\n\n", i, targetPowerValT2[i]);
+		i++;
+	}
+
+	/* Write target power array to registers */
+	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
+
+	/*
+	 * This is the TX power we send back to driver core,
+	 * and it can use to pass to userspace to display our
+	 * currently configured TX power setting.
+	 *
+	 * Since power is rate dependent, use one of the indices
+	 * from the AR9300_Rates enum to select an entry from
+	 * targetPowerValT2[] to report. Currently returns the
+	 * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
+	 * as CCK power is less interesting (?).
+	 */
+	i = ALL_TARGET_LEGACY_6_24; /* legacy */
+	if (IS_CHAN_HT40(chan))
+		i = ALL_TARGET_HT40_0_8_16; /* ht40 */
+	else if (IS_CHAN_HT20(chan))
+		i = ALL_TARGET_HT20_0_8_16; /* ht20 */
+
+	ah->txpower_limit = targetPowerValT2[i];
+
 	ar9003_hw_calibration_apply(ah, chan->channel);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 49e0c86..7c38229 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -577,10 +577,11 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
 }
 
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
-					struct ath9k_channel *chan, int chain)
+					struct ath9k_hw_cal_data *caldata,
+					int chain)
 {
-	u32 *paprd_table_val = chan->pa_table[chain];
-	u32 small_signal_gain = chan->small_signal_gain[chain];
+	u32 *paprd_table_val = caldata->pa_table[chain];
+	u32 small_signal_gain = caldata->small_signal_gain[chain];
 	u32 training_power;
 	u32 reg = 0;
 	int i;
@@ -654,17 +655,17 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
 }
 EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
 
-int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
-			      int chain)
+int ar9003_paprd_create_curve(struct ath_hw *ah,
+			      struct ath9k_hw_cal_data *caldata, int chain)
 {
-	u16 *small_signal_gain = &chan->small_signal_gain[chain];
-	u32 *pa_table = chan->pa_table[chain];
+	u16 *small_signal_gain = &caldata->small_signal_gain[chain];
+	u32 *pa_table = caldata->pa_table[chain];
 	u32 *data_L, *data_U;
 	int i, status = 0;
 	u32 *buf;
 	u32 reg;
 
-	memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain]));
+	memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));
 
 	buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
 	if (!buf)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index a753a43..a491854 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -542,7 +542,11 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah,
 		u32 reg = INI_RA(iniArr, i, 0);
 		u32 val = INI_RA(iniArr, i, column);
 
-		REG_WRITE(ah, reg, val);
+		if (reg >= 0x16000 && reg < 0x17000)
+			ath9k_hw_analog_shift_regwrite(ah, reg, val);
+		else
+			REG_WRITE(ah, reg, val);
+
 		DO_DELAY(regWrites);
 	}
 }
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 998ae2c..07f26ee 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -510,7 +510,7 @@ void ath_deinit_leds(struct ath_softc *sc);
 #define SC_OP_BEACONS                BIT(1)
 #define SC_OP_RXAGGR                 BIT(2)
 #define SC_OP_TXAGGR                 BIT(3)
-#define SC_OP_FULL_RESET             BIT(4)
+#define SC_OP_OFFCHANNEL             BIT(4)
 #define SC_OP_PREAMBLE_SHORT         BIT(5)
 #define SC_OP_PROTECT_ENABLE         BIT(6)
 #define SC_OP_RXFLUSH                BIT(7)
@@ -609,6 +609,7 @@ struct ath_softc {
 struct ath_wiphy {
 	struct ath_softc *sc; /* shared for all virtual wiphys */
 	struct ieee80211_hw *hw;
+	struct ath9k_hw_cal_data caldata;
 	enum ath_wiphy_state {
 		ATH_WIPHY_INACTIVE,
 		ATH_WIPHY_ACTIVE,
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 139289e..4520869 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -22,23 +22,6 @@
 /* We can tune this as we go by monitoring really low values */
 #define ATH9K_NF_TOO_LOW	-60
 
-/* AR5416 may return very high value (like -31 dBm), in those cases the nf
- * is incorrect and we should use the static NF value. Later we can try to
- * find out why they are reporting these values */
-
-static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
-{
-	if (nf > ATH9K_NF_TOO_LOW) {
-		ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-			  "noise floor value detected (%d) is "
-			  "lower than what we think is a "
-			  "reasonable value (%d)\n",
-			  nf, ATH9K_NF_TOO_LOW);
-		return false;
-	}
-	return true;
-}
-
 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
 {
 	int16_t nfval;
@@ -121,6 +104,19 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
 	ah->cal_samples = 0;
 }
 
+static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
+				   struct ath9k_channel *chan)
+{
+	struct ath_nf_limits *limit;
+
+	if (!chan || IS_CHAN_2GHZ(chan))
+		limit = &ah->nf_2g;
+	else
+		limit = &ah->nf_5g;
+
+	return limit->nominal;
+}
+
 /* This is done for the currently configured channel */
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
@@ -128,7 +124,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 	struct ieee80211_conf *conf = &common->hw->conf;
 	struct ath9k_cal_list *currCal = ah->cal_list_curr;
 
-	if (!ah->curchan)
+	if (!ah->caldata)
 		return true;
 
 	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
@@ -151,37 +147,55 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 		  "Resetting Cal %d state for channel %u\n",
 		  currCal->calData->calType, conf->channel->center_freq);
 
-	ah->curchan->CalValid &= ~currCal->calData->calType;
+	ah->caldata->CalValid &= ~currCal->calData->calType;
 	currCal->calState = CAL_WAITING;
 
 	return false;
 }
 EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
 
-void ath9k_hw_start_nfcal(struct ath_hw *ah)
+void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
 {
+	if (ah->caldata)
+		ah->caldata->nfcal_pending = true;
+
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 		    AR_PHY_AGC_CONTROL_ENABLE_NF);
-	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+
+	if (update)
+		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	else
+		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 }
 
 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-	struct ath9k_nfcal_hist *h;
+	struct ath9k_nfcal_hist *h = NULL;
 	unsigned i, j;
 	int32_t val;
 	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
 	struct ath_common *common = ath9k_hw_common(ah);
+	s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
 
-	h = ah->nfCalHist;
+	if (ah->caldata)
+		h = ah->caldata->nfCalHist;
 
 	for (i = 0; i < NUM_NF_READINGS; i++) {
 		if (chainmask & (1 << i)) {
+			s16 nfval;
+
+			if (h)
+				nfval = h[i].privNF;
+			else
+				nfval = default_nf;
+
 			val = REG_READ(ah, ah->nf_regs[i]);
 			val &= 0xFFFFFE00;
-			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+			val |= (((u32) nfval << 1) & 0x1ff);
 			REG_WRITE(ah, ah->nf_regs[i], val);
 		}
 	}
@@ -277,22 +291,25 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
 	}
 }
 
-int16_t ath9k_hw_getnf(struct ath_hw *ah,
-		       struct ath9k_channel *chan)
+bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	int16_t nf, nfThresh;
 	int16_t nfarray[NUM_NF_READINGS] = { 0 };
 	struct ath9k_nfcal_hist *h;
 	struct ieee80211_channel *c = chan->chan;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+	if (!caldata)
+		return false;
 
 	chan->channelFlags &= (~CHANNEL_CW_INT);
 	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
 		ath_print(common, ATH_DBG_CALIBRATE,
 			  "NF did not complete in calibration window\n");
 		nf = 0;
-		chan->rawNoiseFloor = nf;
-		return chan->rawNoiseFloor;
+		caldata->rawNoiseFloor = nf;
+		return false;
 	} else {
 		ath9k_hw_do_getnf(ah, nfarray);
 		ath9k_hw_nf_sanitize(ah, nfarray);
@@ -307,47 +324,40 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 		}
 	}
 
-	h = ah->nfCalHist;
-
+	h = caldata->nfCalHist;
+	caldata->nfcal_pending = false;
 	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
-	chan->rawNoiseFloor = h[0].privNF;
-
-	return chan->rawNoiseFloor;
+	caldata->rawNoiseFloor = h[0].privNF;
+	return true;
 }
 
-void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+				  struct ath9k_channel *chan)
 {
-	struct ath_nf_limits *limit;
+	struct ath9k_nfcal_hist *h;
+	s16 default_nf;
 	int i, j;
 
-	if (!ah->curchan || IS_CHAN_2GHZ(ah->curchan))
-		limit = &ah->nf_2g;
-	else
-		limit = &ah->nf_5g;
+	if (!ah->caldata)
+		return;
 
+	h = ah->caldata->nfCalHist;
+	default_nf = ath9k_hw_get_default_nf(ah, chan);
 	for (i = 0; i < NUM_NF_READINGS; i++) {
-		ah->nfCalHist[i].currIndex = 0;
-		ah->nfCalHist[i].privNF = limit->nominal;
-		ah->nfCalHist[i].invalidNFcount =
-			AR_PHY_CCA_FILTERWINDOW_LENGTH;
+		h[i].currIndex = 0;
+		h[i].privNF = default_nf;
+		h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
 		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-			ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
+			h[i].nfCalBuffer[j] = default_nf;
 		}
 	}
 }
 
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-	s16 nf;
-
-	if (chan->rawNoiseFloor == 0)
-		nf = -96;
-	else
-		nf = chan->rawNoiseFloor;
-
-	if (!ath9k_hw_nf_in_range(ah, nf))
-		nf = ATH_DEFAULT_NOISE_FLOOR;
+	if (!ah->caldata || !ah->caldata->rawNoiseFloor)
+		return ath9k_hw_get_default_nf(ah, chan);
 
-	return nf;
+	return ah->caldata->rawNoiseFloor;
 }
 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index cd60d09..0a304b3 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -108,11 +108,11 @@ struct ath9k_pacal_info{
 };
 
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
-void ath9k_hw_start_nfcal(struct ath_hw *ah);
+void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
-int16_t ath9k_hw_getnf(struct ath_hw *ah,
-		       struct ath9k_channel *chan);
-void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
+bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+				  struct ath9k_channel *chan);
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_hw_reset_calibration(struct ath_hw *ah,
 				struct ath9k_cal_list *currCal);
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 3756400..43b9e21 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -353,6 +353,8 @@ struct ath9k_htc_priv {
 	u16 seq_no;
 	u32 bmiss_cnt;
 
+	struct ath9k_hw_cal_data caldata[38];
+
 	spinlock_t beacon_lock;
 
 	bool tx_queues_stop;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index cf9bcc6..ebed9d1 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -125,6 +125,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 	struct ieee80211_conf *conf = &common->hw->conf;
 	bool fastcc = true;
 	struct ieee80211_channel *channel = hw->conf.channel;
+	struct ath9k_hw_cal_data *caldata;
 	enum htc_phymode mode;
 	__be16 htc_mode;
 	u8 cmd_rsp;
@@ -149,7 +150,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 		  priv->ah->curchan->channel,
 		  channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
 
-	ret = ath9k_hw_reset(ah, hchan, fastcc);
+	caldata = &priv->caldata[channel->hw_value];
+	ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u Mhz) "
@@ -1028,7 +1030,7 @@ static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
 		ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
 	/* Reset the HW */
-	ret = ath9k_hw_reset(ah, ah->curchan, false);
+	ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
@@ -1091,7 +1093,7 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
 		ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
 	/* Reset the HW */
-	ret = ath9k_hw_reset(ah, ah->curchan, false);
+	ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
@@ -1179,7 +1181,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 	ath9k_hw_configpcipowersave(ah, 0, 0);
 
 	ath9k_hw_htc_resetinit(ah);
-	ret = ath9k_hw_reset(ah, init_channel, false);
+	ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8d291cc..3384ca1 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -610,7 +610,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	else
 		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 
-	ath9k_init_nfcal_hist_buffer(ah);
 	ah->bb_watchdog_timeout_ms = 25;
 
 	common->state = ATH_HW_INITIALIZED;
@@ -1183,9 +1182,6 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 
 	ath9k_hw_spur_mitigate_freq(ah, chan);
 
-	if (!chan->oneTimeCalsDone)
-		chan->oneTimeCalsDone = true;
-
 	return true;
 }
 
@@ -1218,7 +1214,7 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
 EXPORT_SYMBOL(ath9k_hw_check_alive);
 
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
-		    bool bChannelChange)
+		   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 saveLedState;
@@ -1243,9 +1239,19 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return -EIO;
 
-	if (curchan && !ah->chip_fullsleep)
+	if (curchan && !ah->chip_fullsleep && ah->caldata)
 		ath9k_hw_getnf(ah, curchan);
 
+	ah->caldata = caldata;
+	if (caldata &&
+	    (chan->channel != caldata->channel ||
+	     (chan->channelFlags & ~CHANNEL_CW_INT) !=
+	     (caldata->channelFlags & ~CHANNEL_CW_INT))) {
+		/* Operating channel changed, reset channel calibration data */
+		memset(caldata, 0, sizeof(*caldata));
+		ath9k_init_nfcal_hist_buffer(ah, chan);
+	}
+
 	if (bChannelChange &&
 	    (ah->chip_fullsleep != true) &&
 	    (ah->curchan != NULL) &&
@@ -1256,7 +1262,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
 		if (ath9k_hw_channel_change(ah, chan)) {
 			ath9k_hw_loadnf(ah, ah->curchan);
-			ath9k_hw_start_nfcal(ah);
+			ath9k_hw_start_nfcal(ah, true);
 			return 0;
 		}
 	}
@@ -1461,11 +1467,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (ah->btcoex_hw.enabled)
 		ath9k_hw_btcoex_enable(ah);
 
-	if (AR_SREV_9300_20_OR_LATER(ah)) {
-		ath9k_hw_loadnf(ah, curchan);
-		ath9k_hw_start_nfcal(ah);
+	if (AR_SREV_9300_20_OR_LATER(ah))
 		ar9003_hw_bb_watchdog_config(ah);
-	}
 
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 2d30efc..399f7c1 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -346,19 +346,25 @@ enum ath9k_int {
 	 CHANNEL_HT40PLUS |			\
 	 CHANNEL_HT40MINUS)
 
-struct ath9k_channel {
-	struct ieee80211_channel *chan;
+struct ath9k_hw_cal_data {
 	u16 channel;
 	u32 channelFlags;
-	u32 chanmode;
 	int32_t CalValid;
-	bool oneTimeCalsDone;
 	int8_t iCoff;
 	int8_t qCoff;
 	int16_t rawNoiseFloor;
 	bool paprd_done;
+	bool nfcal_pending;
 	u16 small_signal_gain[AR9300_MAX_CHAINS];
 	u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
+	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+};
+
+struct ath9k_channel {
+	struct ieee80211_channel *chan;
+	u16 channel;
+	u32 channelFlags;
+	u32 chanmode;
 };
 
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -669,7 +675,7 @@ struct ath_hw {
 	enum nl80211_iftype opmode;
 	enum ath9k_power_mode power_mode;
 
-	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+	struct ath9k_hw_cal_data *caldata;
 	struct ath9k_pacal_info pacal_info;
 	struct ar5416Stats stats;
 	struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
@@ -863,7 +869,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 void ath9k_hw_deinit(struct ath_hw *ah);
 int ath9k_hw_init(struct ath_hw *ah);
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
-		   bool bChannelChange);
+		   struct ath9k_hw_cal_data *caldata, bool bChannelChange);
 int ath9k_hw_fill_cap_info(struct ath_hw *ah);
 u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
 
@@ -958,9 +964,10 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
 void ar9003_paprd_enable(struct ath_hw *ah, bool val);
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
-					struct ath9k_channel *chan, int chain);
-int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
-			      int chain);
+					struct ath9k_hw_cal_data *caldata,
+					int chain);
+int ar9003_paprd_create_curve(struct ath_hw *ah,
+			      struct ath9k_hw_cal_data *caldata, int chain);
 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
 int ar9003_paprd_init_table(struct ath_hw *ah);
 bool ar9003_paprd_is_done(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 0429dda..3caa323 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
 	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 }
 
+static void ath_start_ani(struct ath_common *common)
+{
+	struct ath_hw *ah = common->ah;
+	unsigned long timestamp = jiffies_to_msecs(jiffies);
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+	if (!(sc->sc_flags & SC_OP_ANI_RUN))
+		return;
+
+	if (sc->sc_flags & SC_OP_OFFCHANNEL)
+		return;
+
+	common->ani.longcal_timer = timestamp;
+	common->ani.shortcal_timer = timestamp;
+	common->ani.checkani_timer = timestamp;
+
+	mod_timer(&common->ani.timer,
+		  jiffies +
+			msecs_to_jiffies((u32)ah->config.ani_poll_interval));
+}
+
 /*
  * Set/change channels.  If the channel is really being changed, it's done
  * by reseting the chip.  To accomplish this we must first cleanup any pending
@@ -162,16 +183,23 @@ void ath9k_ps_restore(struct ath_softc *sc)
 int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 		    struct ath9k_channel *hchan)
 {
+	struct ath_wiphy *aphy = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ieee80211_conf *conf = &common->hw->conf;
 	bool fastcc = true, stopped;
 	struct ieee80211_channel *channel = hw->conf.channel;
+	struct ath9k_hw_cal_data *caldata = NULL;
 	int r;
 
 	if (sc->sc_flags & SC_OP_INVALID)
 		return -EIO;
 
+	del_timer_sync(&common->ani.timer);
+	cancel_work_sync(&sc->paprd_work);
+	cancel_work_sync(&sc->hw_check_work);
+	cancel_delayed_work_sync(&sc->tx_complete_work);
+
 	ath9k_ps_wakeup(sc);
 
 	/*
@@ -191,9 +219,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	 * to flush data frames already in queue because of
 	 * changing channel. */
 
-	if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
+	if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
 		fastcc = false;
 
+	if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
+		caldata = &aphy->caldata;
+
 	ath_print(common, ATH_DBG_CONFIG,
 		  "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
 		  sc->sc_ah->curchan->channel,
@@ -201,7 +232,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
 	spin_lock_bh(&sc->sc_resetlock);
 
-	r = ath9k_hw_reset(ah, hchan, fastcc);
+	r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
@@ -212,8 +243,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
 
-	sc->sc_flags &= ~SC_OP_FULL_RESET;
-
 	if (ath_startrecv(sc) != 0) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to restart recv logic\n");
@@ -225,6 +254,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	ath_update_txpow(sc);
 	ath9k_hw_set_interrupts(ah, ah->imask);
 
+	if (!(sc->sc_flags & (SC_OP_OFFCHANNEL | SC_OP_SCANNING))) {
+		ath_start_ani(common);
+		ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+		ath_beacon_config(sc, NULL);
+	}
+
  ps_restore:
 	ath9k_ps_restore(sc);
 	return r;
@@ -233,17 +268,19 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 static void ath_paprd_activate(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	int chain;
 
-	if (!ah->curchan->paprd_done)
+	if (!caldata || !caldata->paprd_done)
 		return;
 
 	ath9k_ps_wakeup(sc);
+	ar9003_paprd_enable(ah, false);
 	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
 		if (!(ah->caps.tx_chainmask & BIT(chain)))
 			continue;
 
-		ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
+		ar9003_paprd_populate_single_table(ah, caldata, chain);
 	}
 
 	ar9003_paprd_enable(ah, true);
@@ -261,6 +298,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 	int band = hw->conf.channel->band;
 	struct ieee80211_supported_band *sband = &sc->sbands[band];
 	struct ath_tx_control txctl;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	int qnum, ftype;
 	int chain_ok = 0;
 	int chain;
@@ -268,6 +306,9 @@ void ath_paprd_calibrate(struct work_struct *work)
 	int time_left;
 	int i;
 
+	if (!caldata)
+		return;
+
 	skb = alloc_skb(len, GFP_KERNEL);
 	if (!skb)
 		return;
@@ -322,7 +363,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 		if (!ar9003_paprd_is_done(ah))
 			break;
 
-		if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
+		if (ar9003_paprd_create_curve(ah, caldata, chain) != 0)
 			break;
 
 		chain_ok = 1;
@@ -330,7 +371,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 	kfree_skb(skb);
 
 	if (chain_ok) {
-		ah->curchan->paprd_done = true;
+		caldata->paprd_done = true;
 		ath_paprd_activate(sc);
 	}
 
@@ -439,33 +480,14 @@ set_timer:
 		cal_interval = min(cal_interval, (u32)short_cal_interval);
 
 	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) &&
-	    !(sc->sc_flags & SC_OP_SCANNING)) {
-		if (!sc->sc_ah->curchan->paprd_done)
+	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
+		if (!ah->caldata->paprd_done)
 			ieee80211_queue_work(sc->hw, &sc->paprd_work);
 		else
 			ath_paprd_activate(sc);
 	}
 }
 
-static void ath_start_ani(struct ath_common *common)
-{
-	struct ath_hw *ah = common->ah;
-	unsigned long timestamp = jiffies_to_msecs(jiffies);
-	struct ath_softc *sc = (struct ath_softc *) common->priv;
-
-	if (!(sc->sc_flags & SC_OP_ANI_RUN))
-		return;
-
-	common->ani.longcal_timer = timestamp;
-	common->ani.shortcal_timer = timestamp;
-	common->ani.checkani_timer = timestamp;
-
-	mod_timer(&common->ani.timer,
-		  jiffies +
-			msecs_to_jiffies((u32)ah->config.ani_poll_interval));
-}
-
 /*
  * Update tx/rx chainmask. For legacy association,
  * hard code chainmask to 1x1, for 11n association, use
@@ -477,7 +499,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht)
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 
-	if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
+	if ((sc->sc_flags & SC_OP_OFFCHANNEL) || is_ht ||
 	    (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) {
 		common->tx_chainmask = ah->caps.tx_chainmask;
 		common->rx_chainmask = ah->caps.rx_chainmask;
@@ -817,7 +839,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 		ah->curchan = ath_get_curchannel(sc, sc->hw);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, ah->curchan, false);
+	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
@@ -877,7 +899,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 		ah->curchan = ath_get_curchannel(sc, hw);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, ah->curchan, false);
+	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
@@ -910,7 +932,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	ath_flushrecv(sc);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
+	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
 	if (r)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d\n", r);
@@ -1085,7 +1107,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	 * and then setup of the interrupt mask.
 	 */
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, init_channel, false);
+	r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
@@ -1579,6 +1601,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 
 		aphy->chan_idx = pos;
 		aphy->chan_is_ht = conf_is_ht(conf);
+		if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+			sc->sc_flags |= SC_OP_OFFCHANNEL;
+		else
+			sc->sc_flags &= ~SC_OP_OFFCHANNEL;
 
 		if (aphy->state == ATH_WIPHY_SCAN ||
 		    aphy->state == ATH_WIPHY_ACTIVE)
@@ -1990,7 +2016,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
 	mutex_lock(&sc->mutex);
 	if (ath9k_wiphy_scanning(sc)) {
@@ -2008,10 +2033,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 	aphy->state = ATH_WIPHY_SCAN;
 	ath9k_wiphy_pause_all_forced(sc, aphy);
 	sc->sc_flags |= SC_OP_SCANNING;
-	del_timer_sync(&common->ani.timer);
-	cancel_work_sync(&sc->paprd_work);
-	cancel_work_sync(&sc->hw_check_work);
-	cancel_delayed_work_sync(&sc->tx_complete_work);
 	mutex_unlock(&sc->mutex);
 }
 
@@ -2023,15 +2044,10 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
 	mutex_lock(&sc->mutex);
 	aphy->state = ATH_WIPHY_ACTIVE;
 	sc->sc_flags &= ~SC_OP_SCANNING;
-	sc->sc_flags |= SC_OP_FULL_RESET;
-	ath_start_ani(common);
-	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
-	ath_beacon_config(sc, NULL);
 	mutex_unlock(&sc->mutex);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index da0cfe9..a3fc987 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1140,6 +1140,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		if (flush)
 			goto requeue;
 
+		retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
+						 rxs, &decrypt_error);
+		if (retval)
+			goto requeue;
+
 		rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
 		if (rs.rs_tstamp > tsf_lower &&
 		    unlikely(rs.rs_tstamp - tsf_lower > 0x10000000))
@@ -1149,11 +1154,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
 			rxs->mactime += 0x100000000ULL;
 
-		retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
-						 rxs, &decrypt_error);
-		if (retval)
-			goto requeue;
-
 		/* Ensure we always have an skb to requeue once we are done
 		 * processing the current buffer's skb */
 		requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 501b728..4dda14e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -120,26 +120,14 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
 	list_add_tail(&ac->list, &txq->axq_acq);
 }
 
-static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
-	struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
-
-	spin_lock_bh(&txq->axq_lock);
-	tid->paused++;
-	spin_unlock_bh(&txq->axq_lock);
-}
-
 static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
 	struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
 
-	BUG_ON(tid->paused <= 0);
-	spin_lock_bh(&txq->axq_lock);
-
-	tid->paused--;
+	WARN_ON(!tid->paused);
 
-	if (tid->paused > 0)
-		goto unlock;
+	spin_lock_bh(&txq->axq_lock);
+	tid->paused = false;
 
 	if (list_empty(&tid->buf_q))
 		goto unlock;
@@ -157,15 +145,10 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 	struct list_head bf_head;
 	INIT_LIST_HEAD(&bf_head);
 
-	BUG_ON(tid->paused <= 0);
-	spin_lock_bh(&txq->axq_lock);
+	WARN_ON(!tid->paused);
 
-	tid->paused--;
-
-	if (tid->paused > 0) {
-		spin_unlock_bh(&txq->axq_lock);
-		return;
-	}
+	spin_lock_bh(&txq->axq_lock);
+	tid->paused = false;
 
 	while (!list_empty(&tid->buf_q)) {
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
@@ -811,7 +794,7 @@ void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 	an = (struct ath_node *)sta->drv_priv;
 	txtid = ATH_AN_2_TID(an, tid);
 	txtid->state |= AGGR_ADDBA_PROGRESS;
-	ath_tx_pause_tid(sc, txtid);
+	txtid->paused = true;
 	*ssn = txtid->seq_start;
 }
 
@@ -835,10 +818,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 		return;
 	}
 
-	ath_tx_pause_tid(sc, txtid);
-
 	/* drop all software retried frames and mark this TID */
 	spin_lock_bh(&txq->axq_lock);
+	txtid->paused = true;
 	while (!list_empty(&txtid->buf_q)) {
 		bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
 		if (!bf_isretried(bf)) {
@@ -1181,7 +1163,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 			  "Failed to stop TX DMA. Resetting hardware!\n");
 
 		spin_lock_bh(&sc->sc_resetlock);
-		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
+		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
 		if (r)
 			ath_print(common, ATH_DBG_FATAL,
 				  "Unable to reset hardware; reset status %d\n",
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 5bbff4c..a146240 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -1924,6 +1924,10 @@ static int ipw2100_net_init(struct net_device *dev)
 		bg_band->channels =
 			kzalloc(geo->bg_channels *
 				sizeof(struct ieee80211_channel), GFP_KERNEL);
+		if (!bg_band->channels) {
+			ipw2100_down(priv);
+			return -ENOMEM;
+		}
 		/* translate geo->bg to bg_band.channels */
 		for (i = 0; i < geo->bg_channels; i++) {
 			bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index f052c6d..d706b8a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -980,7 +980,7 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file,
 			 le32_to_cpu(bt->lo_priority_tx_req_cnt),
 			 accum_bt->lo_priority_tx_req_cnt);
 	pos += scnprintf(buf + pos, bufsz - pos,
-			 "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+			 "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
 			 le32_to_cpu(bt->lo_priority_tx_denied_cnt),
 			 accum_bt->lo_priority_tx_denied_cnt);
 	pos += scnprintf(buf + pos, bufsz - pos,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index a1b6d20..9dd9e64 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1429,7 +1429,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
 void iwl_free_tfds_in_queue(struct iwl_priv *priv,
 			    int sta_id, int tid, int freed)
 {
-	WARN_ON(!spin_is_locked(&priv->sta_lock));
+	lockdep_assert_held(&priv->sta_lock);
 
 	if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
 		priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 35c86d2..23e5c42 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -300,8 +300,9 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
 				      struct ieee80211_sta *sta)
 {
 	int ret = -EAGAIN;
+	u32 load = rs_tl_get_load(lq_data, tid);
 
-	if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
+	if (load > IWL_AGG_LOAD_THRESHOLD) {
 		IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
 				sta->addr, tid);
 		ret = ieee80211_start_tx_ba_session(sta, tid);
@@ -311,12 +312,14 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
 			 * this might be cause by reloading firmware
 			 * stop the tx ba session here
 			 */
-			IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
+			IWL_ERR(priv, "Fail start Tx agg on tid: %d\n",
 				tid);
 			ieee80211_stop_tx_ba_session(sta, tid);
 		}
-	} else
-		IWL_ERR(priv, "Fail finding valid aggregation tid: %d\n", tid);
+	} else {
+		IWL_ERR(priv, "Aggregation not enabled for tid %d "
+			"because load = %u\n", tid, load);
+	}
 	return ret;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 55a1b31..d04502d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -1117,7 +1117,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
 	u8 *addr = priv->stations[sta_id].sta.sta.addr;
 	struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
 
-	WARN_ON(!spin_is_locked(&priv->sta_lock));
+	lockdep_assert_held(&priv->sta_lock);
 
 	switch (priv->stations[sta_id].tid[tid].agg.state) {
 	case IWL_EMPTYING_HW_QUEUE_DELBA:
@@ -1331,7 +1331,14 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
 	tid = ba_resp->tid;
 	agg = &priv->stations[sta_id].tid[tid].agg;
 	if (unlikely(agg->txq_id != scd_flow)) {
-		IWL_ERR(priv, "BA scd_flow %d does not match txq_id %d\n",
+		/*
+		 * FIXME: this is a uCode bug which need to be addressed,
+		 * log the information and return for now!
+		 * since it is possible happen very often and in order
+		 * not to fill the syslog, don't enable the logging by default
+		 */
+		IWL_DEBUG_TX_REPLY(priv,
+			"BA scd_flow %d does not match txq_id %d\n",
 			scd_flow, agg->txq_id);
 		return;
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 8024d44..8ccb6d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2000,6 +2000,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 			      struct ieee80211_vif *vif)
 {
 	struct iwl_priv *priv = hw->priv;
+	bool scan_completed = false;
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -2013,7 +2014,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 	if (priv->vif == vif) {
 		priv->vif = NULL;
 		if (priv->scan_vif == vif) {
-			ieee80211_scan_completed(priv->hw, true);
+			scan_completed = true;
 			priv->scan_vif = NULL;
 			priv->scan_request = NULL;
 		}
@@ -2021,6 +2022,9 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 	}
 	mutex_unlock(&priv->mutex);
 
+	if (scan_completed)
+		ieee80211_scan_completed(priv->hw, true);
+
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 5c2bcef..0b961a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -71,7 +71,7 @@ do {                                            			\
 #define IWL_DEBUG(__priv, level, fmt, args...)
 #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
 static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
-				      void *p, u32 len)
+				      const void *p, u32 len)
 {}
 #endif				/* CONFIG_IWLWIFI_DEBUG */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index ae7319b..4cf864c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -193,7 +193,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
 		__entry->framelen = buf0_len + buf1_len;
 		memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
 		memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
-		memcpy(__get_dynamic_array(buf1), buf1, buf0_len);
+		memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
 	),
 	TP_printk("[%p] TX %.2x (%zu bytes)",
 		  __entry->priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index b0c6b04..a4b3663 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -298,7 +298,7 @@ EXPORT_SYMBOL(iwl_init_scan_params);
 
 static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
-	WARN_ON(!mutex_is_locked(&priv->mutex));
+	lockdep_assert_held(&priv->mutex);
 
 	IWL_DEBUG_INFO(priv, "Starting scan...\n");
 	set_bit(STATUS_SCANNING, &priv->status);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 9511f03..7e0829b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -773,7 +773,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 
 int iwl_restore_default_wep_keys(struct iwl_priv *priv)
 {
-	WARN_ON(!mutex_is_locked(&priv->mutex));
+	lockdep_assert_held(&priv->mutex);
 
 	return iwl_send_static_wepkey_cmd(priv, 0);
 }
@@ -784,7 +784,7 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
 {
 	int ret;
 
-	WARN_ON(!mutex_is_locked(&priv->mutex));
+	lockdep_assert_held(&priv->mutex);
 
 	IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
 		      keyconf->keyidx);
@@ -808,7 +808,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 {
 	int ret;
 
-	WARN_ON(!mutex_is_locked(&priv->mutex));
+	lockdep_assert_held(&priv->mutex);
 
 	if (keyconf->keylen != WEP_KEY_LEN_128 &&
 	    keyconf->keylen != WEP_KEY_LEN_64) {
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 25f9027..8e9fbfd 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -257,6 +257,29 @@ static int lbs_add_supported_rates_tlv(u8 *tlv)
 	return sizeof(rate_tlv->header) + i;
 }
 
+/* Add common rates from a TLV and return the new end of the TLV */
+static u8 *
+add_ie_rates(u8 *tlv, const u8 *ie, int *nrates)
+{
+	int hw, ap, ap_max = ie[1];
+	u8 hw_rate;
+
+	/* Advance past IE header */
+	ie += 2;
+
+	lbs_deb_hex(LBS_DEB_ASSOC, "AP IE Rates", (u8 *) ie, ap_max);
+
+	for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+		hw_rate = lbs_rates[hw].bitrate / 5;
+		for (ap = 0; ap < ap_max; ap++) {
+			if (hw_rate == (ie[ap] & 0x7f)) {
+				*tlv++ = ie[ap];
+				*nrates = *nrates + 1;
+			}
+		}
+	}
+	return tlv;
+}
 
 /*
  * Adds a TLV with all rates the hardware *and* BSS supports.
@@ -264,8 +287,11 @@ static int lbs_add_supported_rates_tlv(u8 *tlv)
 static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
 {
 	struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
-	const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
-	int n;
+	const u8 *rates_eid, *ext_rates_eid;
+	int n = 0;
+
+	rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
 
 	/*
 	 * 01 00                   TLV_TYPE_RATES
@@ -275,26 +301,21 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
 	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
 	tlv += sizeof(rate_tlv->header);
 
-	if (!rates_eid) {
+	/* Add basic rates */
+	if (rates_eid) {
+		tlv = add_ie_rates(tlv, rates_eid, &n);
+
+		/* Add extended rates, if any */
+		if (ext_rates_eid)
+			tlv = add_ie_rates(tlv, ext_rates_eid, &n);
+	} else {
+		lbs_deb_assoc("assoc: bss had no basic rate IE\n");
 		/* Fallback: add basic 802.11b rates */
 		*tlv++ = 0x82;
 		*tlv++ = 0x84;
 		*tlv++ = 0x8b;
 		*tlv++ = 0x96;
 		n = 4;
-	} else {
-		int hw, ap;
-		u8 ap_max = rates_eid[1];
-		n = 0;
-		for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
-			u8 hw_rate = lbs_rates[hw].bitrate / 5;
-			for (ap = 0; ap < ap_max; ap++) {
-				if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
-					*tlv++ = rates_eid[ap+2];
-					n++;
-				}
-			}
-		}
 	}
 
 	rate_tlv->header.len = cpu_to_le16(n);
@@ -465,7 +486,15 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
-	nr_sets = le16_to_cpu(resp->size);
+	nr_sets = le16_to_cpu(scanresp->nr_sets);
+
+	lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n",
+			nr_sets, bsssize, le16_to_cpu(resp->size));
+
+	if (nr_sets == 0) {
+		ret = 0;
+		goto done;
+	}
 
 	/*
 	 * The general layout of the scan response is described in chapter
@@ -670,8 +699,13 @@ static void lbs_scan_worker(struct work_struct *work)
 
 	if (priv->scan_channel >= priv->scan_req->n_channels) {
 		/* Mark scan done */
-		cfg80211_scan_done(priv->scan_req, false);
+		if (priv->internal_scan)
+			kfree(priv->scan_req);
+		else
+			cfg80211_scan_done(priv->scan_req, false);
+
 		priv->scan_req = NULL;
+		priv->last_scan = jiffies;
 	}
 
 	/* Restart network */
@@ -682,10 +716,33 @@ static void lbs_scan_worker(struct work_struct *work)
 
 	kfree(scan_cmd);
 
+	/* Wake up anything waiting on scan completion */
+	if (priv->scan_req == NULL) {
+		lbs_deb_scan("scan: waking up waiters\n");
+		wake_up_all(&priv->scan_q);
+	}
+
  out_no_scan_cmd:
 	lbs_deb_leave(LBS_DEB_SCAN);
 }
 
+static void _internal_start_scan(struct lbs_private *priv, bool internal,
+	struct cfg80211_scan_request *request)
+{
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
+		request->n_ssids, request->n_channels, request->ie_len);
+
+	priv->scan_channel = 0;
+	queue_delayed_work(priv->work_thread, &priv->scan_work,
+		msecs_to_jiffies(50));
+
+	priv->scan_req = request;
+	priv->internal_scan = internal;
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+}
 
 static int lbs_cfg_scan(struct wiphy *wiphy,
 	struct net_device *dev,
@@ -702,18 +759,11 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
 		goto out;
 	}
 
-	lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
-		request->n_ssids, request->n_channels, request->ie_len);
-
-	priv->scan_channel = 0;
-	queue_delayed_work(priv->work_thread, &priv->scan_work,
-		msecs_to_jiffies(50));
+	_internal_start_scan(priv, false, request);
 
 	if (priv->surpriseremoved)
 		ret = -EIO;
 
-	priv->scan_req = request;
-
  out:
 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
 	return ret;
@@ -1000,6 +1050,7 @@ static int lbs_associate(struct lbs_private *priv,
 	int status;
 	int ret;
 	u8 *pos = &(cmd->iebuf[0]);
+	u8 *tmp;
 
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
@@ -1044,7 +1095,9 @@ static int lbs_associate(struct lbs_private *priv,
 	pos += lbs_add_cf_param_tlv(pos);
 
 	/* add rates TLV */
+	tmp = pos + 4; /* skip Marvell IE header */
 	pos += lbs_add_common_rates_tlv(pos, bss);
+	lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
 
 	/* add auth type TLV */
 	if (priv->fwrelease >= 0x09000000)
@@ -1124,7 +1177,62 @@ done:
 	return ret;
 }
 
+static struct cfg80211_scan_request *
+_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
+{
+	struct cfg80211_scan_request *creq = NULL;
+	int i, n_channels = 0;
+	enum ieee80211_band band;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		if (wiphy->bands[band])
+			n_channels += wiphy->bands[band]->n_channels;
+	}
+
+	creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
+		       n_channels * sizeof(void *),
+		       GFP_ATOMIC);
+	if (!creq)
+		return NULL;
+
+	/* SSIDs come after channels */
+	creq->ssids = (void *)&creq->channels[n_channels];
+	creq->n_channels = n_channels;
+	creq->n_ssids = 1;
+
+	/* Scan all available channels */
+	i = 0;
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		int j;
+
+		if (!wiphy->bands[band])
+			continue;
+
+		for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+			/* ignore disabled channels */
+			if (wiphy->bands[band]->channels[j].flags &
+						IEEE80211_CHAN_DISABLED)
+				continue;
+
+			creq->channels[i] = &wiphy->bands[band]->channels[j];
+			i++;
+		}
+	}
+	if (i) {
+		/* Set real number of channels specified in creq->channels[] */
+		creq->n_channels = i;
+
+		/* Scan for the SSID we're going to connect to */
+		memcpy(creq->ssids[0].ssid, sme->ssid, sme->ssid_len);
+		creq->ssids[0].ssid_len = sme->ssid_len;
+	} else {
+		/* No channels found... */
+		kfree(creq);
+		creq = NULL;
+	}
 
+	return creq;
+}
 
 static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
 			   struct cfg80211_connect_params *sme)
@@ -1136,37 +1244,43 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
 
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
-	if (sme->bssid) {
-		bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
-			sme->ssid, sme->ssid_len,
-			WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
-	} else {
-		/*
-		 * Here we have an impedance mismatch. The firmware command
-		 * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot
-		 * connect otherwise. However, for the connect-API of
-		 * cfg80211 the bssid is purely optional. We don't get one,
-		 * except the user specifies one on the "iw" command line.
-		 *
-		 * If we don't got one, we could initiate a scan and look
-		 * for the best matching cfg80211_bss entry.
-		 *
-		 * Or, better yet, net/wireless/sme.c get's rewritten into
-		 * something more generally useful.
+	if (!sme->bssid) {
+		/* Run a scan if one isn't in-progress already and if the last
+		 * scan was done more than 2 seconds ago.
 		 */
-		lbs_pr_err("TODO: no BSS specified\n");
-		ret = -ENOTSUPP;
-		goto done;
-	}
+		if (priv->scan_req == NULL &&
+		    time_after(jiffies, priv->last_scan + (2 * HZ))) {
+			struct cfg80211_scan_request *creq;
 
+			creq = _new_connect_scan_req(wiphy, sme);
+			if (!creq) {
+				ret = -EINVAL;
+				goto done;
+			}
+
+			lbs_deb_assoc("assoc: scanning for compatible AP\n");
+			_internal_start_scan(priv, true, creq);
+		}
+
+		/* Wait for any in-progress scan to complete */
+		lbs_deb_assoc("assoc: waiting for scan to complete\n");
+		wait_event_interruptible_timeout(priv->scan_q,
+						 (priv->scan_req == NULL),
+						 (15 * HZ));
+		lbs_deb_assoc("assoc: scanning competed\n");
+	}
 
+	/* Find the BSS we want using available scan results */
+	bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
+		sme->ssid, sme->ssid_len,
+		WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
 	if (!bss) {
-		lbs_pr_err("assicate: bss %pM not in scan results\n",
+		lbs_pr_err("assoc: bss %pM not in scan results\n",
 			   sme->bssid);
 		ret = -ENOENT;
 		goto done;
 	}
-	lbs_deb_assoc("trying %pM", sme->bssid);
+	lbs_deb_assoc("trying %pM\n", bss->bssid);
 	lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
 		      sme->crypto.cipher_group,
 		      sme->key_idx, sme->key_len);
@@ -1229,7 +1343,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
 	lbs_set_radio(priv, preamble, 1);
 
 	/* Do the actual association */
-	lbs_associate(priv, bss, sme);
+	ret = lbs_associate(priv, bss, sme);
 
  done:
 	if (bss)
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 3c7e255..f062ed5 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -161,6 +161,11 @@ struct lbs_private {
 	/** Scanning */
 	struct delayed_work scan_work;
 	int scan_channel;
+	/* Queue of things waiting for scan completion */
+	wait_queue_head_t scan_q;
+	/* Whether the scan was initiated internally and not by cfg80211 */
+	bool internal_scan;
+	unsigned long last_scan;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 2589671..24958a8 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -719,6 +719,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
 	priv->deep_sleep_required = 0;
 	priv->wakeup_dev_required = 0;
 	init_waitqueue_head(&priv->ds_awake_q);
+	init_waitqueue_head(&priv->scan_q);
 	priv->authtype_auto = 1;
 	priv->is_host_sleep_configured = 0;
 	priv->is_host_sleep_activated = 0;
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 822f8dc..71a101f 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -43,6 +43,8 @@ static DEFINE_PCI_DEVICE_TABLE(p54p_table) = {
 	{ PCI_DEVICE(0x1260, 0x3886) },
 	/* Intersil PRISM Xbow Wireless LAN adapter (Symbol AP-300) */
 	{ PCI_DEVICE(0x1260, 0xffff) },
+	/* Standard Microsystems Corp SMC2802W Wireless PCI */
+	{ PCI_DEVICE(0x10b8, 0x2802) },
 	{ },
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 19b262e..63c2cc4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -240,16 +240,16 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 	struct rt2x00_dev *rt2x00dev;
 	int retval;
 
-	retval = pci_request_regions(pci_dev, pci_name(pci_dev));
+	retval = pci_enable_device(pci_dev);
 	if (retval) {
-		ERROR_PROBE("PCI request regions failed.\n");
+		ERROR_PROBE("Enable device failed.\n");
 		return retval;
 	}
 
-	retval = pci_enable_device(pci_dev);
+	retval = pci_request_regions(pci_dev, pci_name(pci_dev));
 	if (retval) {
-		ERROR_PROBE("Enable device failed.\n");
-		goto exit_release_regions;
+		ERROR_PROBE("PCI request regions failed.\n");
+		goto exit_disable_device;
 	}
 
 	pci_set_master(pci_dev);
@@ -260,14 +260,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 	if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
 		ERROR_PROBE("PCI DMA not supported.\n");
 		retval = -EIO;
-		goto exit_disable_device;
+		goto exit_release_regions;
 	}
 
 	hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
 	if (!hw) {
 		ERROR_PROBE("Failed to allocate hardware.\n");
 		retval = -ENOMEM;
-		goto exit_disable_device;
+		goto exit_release_regions;
 	}
 
 	pci_set_drvdata(pci_dev, hw);
@@ -300,13 +300,12 @@ exit_free_reg:
 exit_free_device:
 	ieee80211_free_hw(hw);
 
-exit_disable_device:
-	if (retval != -EBUSY)
-		pci_disable_device(pci_dev);
-
 exit_release_regions:
 	pci_release_regions(pci_dev);
 
+exit_disable_device:
+	pci_disable_device(pci_dev);
+
 	pci_set_drvdata(pci_dev, NULL);
 
 	return retval;
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 1d81785..b50c39a 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -695,6 +695,8 @@ static void rtl8180_beacon_work(struct work_struct *work)
 
 	/* grab a fresh beacon */
 	skb = ieee80211_beacon_get(dev, vif);
+	if (!skb)
+		goto resched;
 
 	/*
 	 * update beacon timestamp w/ TSF value
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 96d25fb..4cb99c5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -160,9 +160,8 @@ static void wl1271_spi_init(struct wl1271 *wl)
 	spi_message_add_tail(&t, &m);
 
 	spi_sync(wl_to_spi(wl), &m);
-	kfree(cmd);
-
 	wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+	kfree(cmd);
 }
 
 #define WL1271_BUSY_WORD_TIMEOUT 1000
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8b28962..4568b93 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -132,7 +132,7 @@ struct hci_dev {
 
 	struct inquiry_cache	inq_cache;
 	struct hci_conn_hash	conn_hash;
-	struct bdaddr_list	blacklist;
+	struct list_head	blacklist;
 
 	struct hci_dev_stats	stat;
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 8303f1c..c52f091 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -924,7 +924,7 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	hci_conn_hash_init(hdev);
 
-	INIT_LIST_HEAD(&hdev->blacklist.list);
+	INIT_LIST_HEAD(&hdev->blacklist);
 
 	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 4f170a5..83acd16 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -168,9 +168,8 @@ static int hci_sock_release(struct socket *sock)
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
 	struct list_head *p;
-	struct bdaddr_list *blacklist = &hdev->blacklist;
 
-	list_for_each(p, &blacklist->list) {
+	list_for_each(p, &hdev->blacklist) {
 		struct bdaddr_list *b;
 
 		b = list_entry(p, struct bdaddr_list, list);
@@ -202,7 +201,7 @@ static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
 
 	bacpy(&entry->bdaddr, &bdaddr);
 
-	list_add(&entry->list, &hdev->blacklist.list);
+	list_add(&entry->list, &hdev->blacklist);
 
 	return 0;
 }
@@ -210,9 +209,8 @@ static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
 int hci_blacklist_clear(struct hci_dev *hdev)
 {
 	struct list_head *p, *n;
-	struct bdaddr_list *blacklist = &hdev->blacklist;
 
-	list_for_each_safe(p, n, &blacklist->list) {
+	list_for_each_safe(p, n, &hdev->blacklist) {
 		struct bdaddr_list *b;
 
 		b = list_entry(p, struct bdaddr_list, list);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index ce44c47..8fb967b 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -439,12 +439,11 @@ static const struct file_operations inquiry_cache_fops = {
 static int blacklist_show(struct seq_file *f, void *p)
 {
 	struct hci_dev *hdev = f->private;
-	struct bdaddr_list *blacklist = &hdev->blacklist;
 	struct list_head *l;
 
 	hci_dev_lock_bh(hdev);
 
-	list_for_each(l, &blacklist->list) {
+	list_for_each(l, &hdev->blacklist) {
 		struct bdaddr_list *b;
 		bdaddr_t bdaddr;
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 9ba1e8e..3e3cd9d 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2527,6 +2527,10 @@ done:
 		if (pi->imtu != L2CAP_DEFAULT_MTU)
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
 
+		if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) &&
+				!(pi->conn->feat_mask & L2CAP_FEAT_STREAMING))
+			break;
+
 		rfc.mode            = L2CAP_MODE_BASIC;
 		rfc.txwin_size      = 0;
 		rfc.max_transmit    = 0;
@@ -2534,6 +2538,8 @@ done:
 		rfc.monitor_timeout = 0;
 		rfc.max_pdu_size    = 0;
 
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+							(unsigned long) &rfc);
 		break;
 
 	case L2CAP_MODE_ERTM:
@@ -2546,6 +2552,9 @@ done:
 		if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
 			rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+							(unsigned long) &rfc);
+
 		if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
 			break;
 
@@ -2566,6 +2575,9 @@ done:
 		if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
 			rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+							(unsigned long) &rfc);
+
 		if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
 			break;
 
@@ -2577,9 +2589,6 @@ done:
 		break;
 	}
 
-	l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-						(unsigned long) &rfc);
-
 	/* FIXME: Need actual value of the flush timeout */
 	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
 	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
@@ -3339,6 +3348,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
 	del_timer(&conn->info_timer);
 
+	if (result != L2CAP_IR_SUCCESS) {
+		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+		conn->info_ident = 0;
+
+		l2cap_conn_start(conn);
+
+		return 0;
+	}
+
 	if (type == L2CAP_IT_FEAT_MASK) {
 		conn->feat_mask = get_unaligned_le32(rsp->data);
 
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 026205c..befc3a5 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -1183,7 +1183,7 @@ int __init rfcomm_init_ttys(void)
 	return 0;
 }
 
-void __exit rfcomm_cleanup_ttys(void)
+void rfcomm_cleanup_ttys(void)
 {
 	tty_unregister_driver(rfcomm_tty_driver);
 	put_tty_driver(rfcomm_tty_driver);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 7cc4f91..798a91b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -685,10 +685,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
 	return 0;
 
+#ifdef CONFIG_INET
  fail_ifa:
 	pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
 			       &local->network_latency_notifier);
 	rtnl_lock();
+#endif
  fail_pm_qos:
 	ieee80211_led_exit(local);
 	ieee80211_remove_interfaces(local);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 41f20fb..872d7b6 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -400,19 +400,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	else
 		__set_bit(SCAN_SW_SCANNING, &local->scanning);
 
-	/*
-	 * Kicking off the scan need not be protected,
-	 * only the scan variable stuff, since now
-	 * local->scan_req is assigned and other callers
-	 * will abort their scan attempts.
-	 *
-	 * This avoids too many locking dependencies
-	 * so that the scan completed calls have more
-	 * locking freedom.
-	 */
-
 	ieee80211_recalc_idle(local);
-	mutex_unlock(&local->scan_mtx);
 
 	if (local->ops->hw_scan) {
 		WARN_ON(!ieee80211_prep_hw_scan(local));
@@ -420,8 +408,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	} else
 		rc = ieee80211_start_sw_scan(local);
 
-	mutex_lock(&local->scan_mtx);
-
 	if (rc) {
 		kfree(local->hw_scan_req);
 		local->hw_scan_req = NULL;
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply related

* Re: Odd BUG on wireless-testing master-2010-08-05
From: Luis R. Rodriguez @ 2010-08-06 19:05 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless
In-Reply-To: <20100806135057.GA2753@tuxdriver.com>

On Fri, Aug 6, 2010 at 6:50 AM, John W. Linville <linville@tuxdriver.com> wrote:
> On Thu, Aug 05, 2010 at 03:31:06PM -0700, Luis R. Rodriguez wrote:
>> I just ran into this. My first load of master-2010-08-05 was fine but
>> I started getting a lot of disconnects on AR9003 hardware after a
>> period of RX'ing data over an encrypted legacy network. Instead of
>> checking dmesg I just rebooted though. After that I connected to the
>> same AP again, started Rx'ing for a while and then shortly got this:
>>
>>
>> [  818.749585] BUG: unable to handle kernel paging request at 00003f3f00000000
>> [  818.749594] IP: [<ffffffff814ee0d8>] unix_stream_recvmsg+0x3f8/0x790
>
>> After a reboot I got a hard hang which I could not capture any logs
>> for. I rebooted and am up now but not seeing these issues yet. John,
>> does this smell like what you were seeing or is this different?
>
> Yeah, I'm seeing that too.  There is some netdev stuff in
> wireless-testing at the moment that I suspect was undercooked...
>
> Sorry for the inconvenience while this gets sorted-out!

Ah no problem, just wanted to see if I should dig into ath9k or not,
sounds like I don't. FWIW I had a hang overnight as well.

  Luis

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox