* Re: [PATCH]: nl80211: report age of scan results
From: Holger Schurig @ 2009-10-01 7:57 UTC (permalink / raw)
To: Jouni Malinen; +Cc: John Linville, linux-wireless, Johannes Berg
In-Reply-To: <20090930212123.GA8616@jm.kir.nu>
> If anyone gets interested enough in trying to figure out whether
> scan results are from the time after the last scan (more exactly than
> just guessing based on age), he/she can add that later and probably
> using something like a sequence number for scan requests, etc.
Hmm, what would a scan-sequence help in the case when mac80211 updates
a BSS because of a received beacon?
E.g.:
scan trigger, seq 5:
find AP 'XXX', signal -50
find AP 'YYY', signal -60
scan trigger, seq 6:
find AP 'ZZZ', signal -55
normal operation:
beacon for 'YYY' comes in, signal -45
scan-dump:
get 'XXX', signal -50, seq 5
get 'ZZZ', signal -55, seq 6
get 'YYY', signal -45, but with which seq?
--
http://www.holgerschurig.de
^ permalink raw reply
* Re: unused header file drivers/net/wireless/wl12xx/wl1251_netlink.h?
From: Kalle Valo @ 2009-10-01 7:49 UTC (permalink / raw)
To: Robert P. J. Day; +Cc: linux-wireless
In-Reply-To: <alpine.LFD.2.00.0909301554001.21753@localhost>
"Robert P. J. Day" <rpjday@crashcourse.ca> writes:
> as best i can tell, that header file is entirely unreferenced by
> anything in the tree. just an observation.
Yes, it's unused. I added it accidentally a long time ago when I
rebased a big pile of patches. I'll send a patch to remove it.
Thanks for reporting this.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH v2] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
From: Holger Schurig @ 2009-10-01 7:42 UTC (permalink / raw)
To: Bing Zhao; +Cc: libertas-dev, linux-wireless, Amitkumar Karwar
In-Reply-To: <1254366278-15483-1-git-send-email-bzhao@marvell.com>
> Tests have been done for USB/CS cards to make sure that the patch
> won't break USB/CS code.
Side question: which firmware are you using on CS cards?
--
http://www.holgerschurig.de
^ permalink raw reply
* Re: [PATCH] net: fix NOHZ: local_softirq_pending 08
From: Oliver Hartkopp @ 2009-10-01 7:08 UTC (permalink / raw)
To: David Miller; +Cc: johannes, mb, kalle.valo, linville, linux-wireless, netdev
In-Reply-To: <20090930.163333.234658158.davem@davemloft.net>
David Miller wrote:
> From: Oliver Hartkopp <oliver@hartkopp.net>
> Date: Wed, 30 Sep 2009 20:18:25 +0200
>
>> Socket buffers that are generated and received inside softirqs or from process
>> context must not use netif_rx() that's intended to be used from irq context only.
>>
>> This patch introduces a new helper function netif_rx_ti(skb) that tests for
>> in_interrupt() before invoking netif_rx() or netif_rx_ni().
>>
>> It fixes the ratelimited kernel warning
>>
>> NOHZ: local_softirq_pending 08
>>
>> in the mac80211 and can subsystems.
>>
>> Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net>
>
> I bet all of these code paths can use netif_receive_skb() or
> don't need this conditional blob at all.
>
> Looking at some specific cases in this patch:
>
> 1) VCAN: This RX routine is only invoked from the drivers
> ->ndo_start_xmit() handler, and therefore like the loopback
> driver we know that BH's are already disabled and therefore
> it can always use netif_rx() safely.
>
> Why did you convert this case?
>
> And if this needs to be converted, why doesn't loopback need
> to be?
>
> 2) af_can.c: In what situation will netif_rx_ni() not be appropriate
> here? It should always execute in softirq or user context, now
> hardirq context.
>
> And the list goes on and on, I don't really like this new conditional
> testing of interrupt state.
Hello Dave,
i'm confused about in_interrupt(), in_softirq() and in_irq() as pointed out by
Johannes here:
http://marc.info/?l=linux-wireless&m=125432410405562&w=2
Indeed in the two cases for the CAN stuff (in vcan.c and af_can.c) the skb's
are received in process-context and softirq-context only.
Therefore i used netif_rx_ni() in my last change of this code.
Now i was reading from Johannes that in_interrupt() is used for
hardirq-context /and/ softirq-context, so i was just *unsure* and used the
newly introduced netif_rx_ti() for that, which tests for in_interrupt().
Indeed i'm not really happy with that, as it is always better to check each
receive case in which context it can be used and used exactly the right
function for that.
So when netif_rx_ni() or netif_receive_skb() is the best i can use when in
process-context or in softirq-context, i'll do it with pleasure.
And if it is like this the problematic netif_rx() calls in mac80211 need to be
sorted out in detail also ...
Regards,
Oliver
^ permalink raw reply
* PATCH ar9170usb LEDs are confused
From: Malte Gell @ 2009-10-01 4:32 UTC (permalink / raw)
To: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 281 bytes --]
Hello,
I first noticed the LEDs are confused, when I ran my AVM Fritz USBN N under
Windows, where the LEDs had the right order. I made a little patch that put
the assoc and the tx LEDs in the right order.
That patch was built against compat-wireless-2009-09-29.
Regards
Malte
[-- Attachment #2: ar9170-led.patch --]
[-- Type: text/x-patch, Size: 643 bytes --]
--- drivers/net/wireless/ath/ar9170/led_c_orig 2009-10-01 05:55:55.000000000 +0200
+++ drivers/net/wireless/ath/ar9170/led.c 2009-10-01 06:02:26.000000000 +0200
@@ -161,13 +161,13 @@
INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds);
- err = ar9170_register_led(ar, 0, "tx",
- ieee80211_get_tx_led_name(ar->hw));
+ err = ar9170_register_led(ar, 0, "assoc",
+ ieee80211_get_assoc_led_name(ar->hw));
if (err)
goto fail;
- err = ar9170_register_led(ar, 1, "assoc",
- ieee80211_get_assoc_led_name(ar->hw));
+ err = ar9170_register_led(ar, 1, "tx",
+ ieee80211_get_tx_led_name(ar->hw));
if (err)
goto fail;
^ permalink raw reply
* [PATCH v2] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
From: Bing Zhao @ 2009-10-01 3:04 UTC (permalink / raw)
To: libertas-dev; +Cc: linux-wireless, Bing Zhao, Amitkumar Karwar
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 32842 bytes --]
From: Amitkumar Karwar <akarwar@marvell.com>
Add timer based auto deep sleep feature in libertas driver which can be
configured using iwconfig command. This is tested on SD8688, SD8686 cards
with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit
platforms. Tests have been done for USB/CS cards to make sure that the patch
won't break USB/CS code. We didn't test the if_spi driver.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
drivers/net/wireless/libertas/README | 26 ++++-
drivers/net/wireless/libertas/cmd.c | 72 ++++++++++++-
drivers/net/wireless/libertas/cmdresp.c | 12 ++
drivers/net/wireless/libertas/debugfs.c | 46 ++++++++
drivers/net/wireless/libertas/decl.h | 4 +
drivers/net/wireless/libertas/dev.h | 18 +++
drivers/net/wireless/libertas/host.h | 1 +
drivers/net/wireless/libertas/if_cs.c | 3 +
drivers/net/wireless/libertas/if_sdio.c | 56 +++++++++
drivers/net/wireless/libertas/if_sdio.h | 3 +-
drivers/net/wireless/libertas/if_spi.c | 3 +
drivers/net/wireless/libertas/if_usb.c | 3 +
drivers/net/wireless/libertas/main.c | 111 ++++++++++++++++---
drivers/net/wireless/libertas/scan.c | 11 ++
drivers/net/wireless/libertas/wext.c | 185 ++++++++++++++++++++++++++++++-
15 files changed, 533 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d5..635002d 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -1,5 +1,5 @@
================================================================================
- README for USB8388
+ README for Libertas
(c) Copyright © 2003-2006, Marvell International Ltd.
All Rights Reserved
@@ -226,4 +226,28 @@ setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.
+========================
+IWCONFIG COMMANDS
+========================
+power period
+
+ This command is used to configure the station in deep sleep mode /
+ auto deep sleep mode.
+
+ The timer is implemented to monitor the activities (command, event,
+ etc.). When an activity is detected station will exit from deep
+ sleep mode automatically and restart the timer. At timer expiry
+ (no activity for defined time period) the deep sleep mode is entered
+ automatically.
+
+ Note: this command is for SDIO interface only.
+
+ Usage:
+ To enable deep sleep mode do:
+ iwconfig wlan0 power period 0
+ To enable auto deep sleep mode with idle time period 5 seconds do:
+ iwconfig wlan0 power period 5
+ To disable deep sleep/auto deep sleep mode do:
+ iwconfig wlan0 power period -1
+
==============================================================================
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 6850981..3a3e894 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -17,7 +17,6 @@
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
-
/**
* @brief Simple callback that copies response back into command
*
@@ -319,6 +318,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
return 0;
}
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_deep_sleep) {
+ if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+ !priv->is_deep_sleep, (10 * HZ))) {
+ lbs_pr_err("ds_awake_q: timer expired\n");
+ ret = -1;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (deep_sleep) {
+ if (priv->is_deep_sleep != 1) {
+ lbs_deb_cmd("deep sleep: sleep\n");
+ BUG_ON(!priv->enter_deep_sleep);
+ ret = priv->enter_deep_sleep(priv);
+ if (!ret) {
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ }
+ } else {
+ lbs_pr_err("deep sleep: already enabled\n");
+ }
+ } else {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("deep sleep: wakeup\n");
+ BUG_ON(!priv->exit_deep_sleep);
+ ret = priv->exit_deep_sleep(priv);
+ if (!ret) {
+ ret = lbs_wait_for_ds_awake(priv);
+ if (ret)
+ lbs_pr_err("deep sleep: wakeup"
+ "failed\n");
+ }
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
@@ -1242,8 +1295,17 @@ static void lbs_submit_command(struct lbs_private *priv,
timeo = HZ/4;
}
- /* Setup the timer after transmit command */
- mod_timer(&priv->command_timer, jiffies + timeo);
+ if (command == CMD_802_11_DEEP_SLEEP) {
+ if (priv->is_auto_deep_sleep_enabled) {
+ priv->wakeup_dev_required = 1;
+ priv->dnld_sent = 0;
+ }
+ priv->is_deep_sleep = 1;
+ lbs_complete_command(priv, cmdnode, 0);
+ } else {
+ /* Setup the timer after transmit command */
+ mod_timer(&priv->command_timer, jiffies + timeo);
+ }
lbs_deb_leave(LBS_DEB_HOST);
}
@@ -1505,6 +1567,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
+ case CMD_802_11_DEEP_SLEEP:
+ cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+ cmdptr->size = cpu_to_le16(S_DS_GEN);
+ break;
default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index c42d3fa..47d2b19 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -504,9 +504,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_HOST_AWAKE:
lbs_deb_cmd("EVENT: host awake\n");
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ priv->is_deep_sleep = 0;
lbs_send_confirmwake(priv);
break;
+ case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ lbs_deb_cmd("EVENT: ds awake\n");
+ priv->is_deep_sleep = 0;
+ priv->wakeup_dev_required = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ break;
+
case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: ps awake\n");
/* handle unexpected PS AWAKE event */
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 893a55c..8a7e931 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -117,6 +117,11 @@ static ssize_t lbs_sleepparams_write(struct file *file,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
ret = -EFAULT;
@@ -157,6 +162,11 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
if (ret)
goto out_unlock;
@@ -223,6 +233,9 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
u8 freq;
int events = 0;
+ if (!lbs_is_cmd_allowed(priv))
+ return -EBUSY;
+
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -275,6 +288,9 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
char *buf;
int ret;
+ if (!lbs_is_cmd_allowed(priv))
+ return -EBUSY;
+
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -444,6 +460,11 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ free_page(addr);
+ return -EBUSY;
+ }
+
offval.offset = priv->mac_offset;
offval.value = 0;
@@ -496,6 +517,11 @@ static ssize_t lbs_wrmac_write(struct file *file,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ res = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
@@ -532,6 +558,11 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ free_page(addr);
+ return -EBUSY;
+ }
+
offval.offset = priv->bbp_offset;
offval.value = 0;
@@ -585,6 +616,11 @@ static ssize_t lbs_wrbbp_write(struct file *file,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ res = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
@@ -621,6 +657,11 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ free_page(addr);
+ return -EBUSY;
+ }
+
offval.offset = priv->rf_offset;
offval.value = 0;
@@ -674,6 +715,11 @@ static ssize_t lbs_wrrf_write(struct file *file,
if (!buf)
return -ENOMEM;
+ if (!lbs_is_cmd_allowed(priv)) {
+ res = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 0b84bdc..34b475f 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -33,6 +33,10 @@ int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+int lbs_is_cmd_allowed(struct lbs_private *priv);
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 578c697..e2b4ef2 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -129,6 +129,20 @@ struct lbs_private {
u32 bbp_offset;
u32 rf_offset;
+ /** Deep sleep flag */
+ int is_deep_sleep;
+ /** Auto deep sleep enabled flag */
+ int is_auto_deep_sleep_enabled;
+ /** Device wakeup required flag */
+ int wakeup_dev_required;
+ /** Auto deep sleep flag*/
+ int is_activity_detected;
+ /** Auto deep sleep timeout (in miliseconds) */
+ int auto_deep_sleep_timeout;
+
+ /** Deep sleep wait queue */
+ wait_queue_head_t ds_awake_q;
+
/* Download sent:
bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done,
@@ -154,6 +168,9 @@ struct lbs_private {
/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*enter_deep_sleep) (struct lbs_private *priv);
+ int (*exit_deep_sleep) (struct lbs_private *priv);
+ int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
/* Wake On LAN */
uint32_t wol_criteria;
@@ -204,6 +221,7 @@ struct lbs_private {
/** Timers */
struct timer_list command_timer;
+ struct timer_list auto_deepsleep_timer;
int nr_retries;
int cmd_timed_out;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb..c055daa 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -57,6 +57,7 @@
#define CMD_802_11_ENABLE_RSN 0x002f
#define CMD_802_11_SET_AFC 0x003c
#define CMD_802_11_GET_AFC 0x003d
+#define CMD_802_11_DEEP_SLEEP 0x003e
#define CMD_802_11_AD_HOC_STOP 0x0040
#define CMD_802_11_HOST_SLEEP_CFG 0x0043
#define CMD_802_11_WAKEUP_CONFIRM 0x0044
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 6238176..465742f 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Now actually get the IRQ */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 485a8d4..9716728 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -831,6 +831,58 @@ out:
return ret;
}
+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+ int ret = -1;
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send DEEP_SLEEP command\n");
+ ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd);
+ if (ret)
+ lbs_pr_err("DEEP_SLEEP cmd failed\n");
+
+ mdelay(200);
+ return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+
+}
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
* Ignore the define name, this really means the card has
* successfully received the command.
*/
+ card->priv->is_activity_detected = 1;
if (cause & IF_SDIO_H_INT_DNLD)
lbs_host_to_card_done(card->priv);
@@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,
priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+ priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+ priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
priv->fw_ready = 1;
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 60c9b2f..12179c1 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -51,5 +51,6 @@
#define IF_SDIO_EVENT 0x80fc
#define IF_SDIO_BLOCK_SIZE 256
-
+#define CONFIGURATION_REG 0x03
+#define HOST_POWER_UP (0x1U << 1)
#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 446e327..e2fa657 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Initialize interrupt handling stuff. */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 92bc8c5..a8262de 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
#ifdef CONFIG_OLPC
if (machine_is_olpc())
priv->reset_card = if_usb_reset_olpc_card;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 8df1cfd..3b14fcc 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
- if (!priv->cur_cmd || priv->tx_pending_len > 0)
- wake_up_interruptible(&priv->waitq);
+ if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+ if (!priv->wakeup_dev_required)
+ wake_up_interruptible(&priv->waitq);
+ }
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -770,7 +772,8 @@ static int lbs_thread(void *data)
shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */
- else if (!list_empty(&priv->cmdpendingq))
+ else if (!list_empty(&priv->cmdpendingq) &&
+ !(priv->wakeup_dev_required))
shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
@@ -822,6 +825,26 @@ static int lbs_thread(void *data)
}
spin_unlock_irq(&priv->driver_lock);
+ /* Process hardware events, e.g. card removed, link lost */
+ spin_lock_irq(&priv->driver_lock);
+ while (__kfifo_len(priv->event_fifo)) {
+ u32 event;
+ __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+ sizeof(event));
+ spin_unlock_irq(&priv->driver_lock);
+ lbs_process_event(priv, event);
+ spin_lock_irq(&priv->driver_lock);
+ }
+ spin_unlock_irq(&priv->driver_lock);
+
+ if (priv->wakeup_dev_required) {
+ lbs_deb_thread("Waking up device...\n");
+ /* Wake up device */
+ if (priv->exit_deep_sleep(priv))
+ lbs_deb_thread("Wakeup device failed\n");
+ continue;
+ }
+
/* command timeout stuff */
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +872,7 @@ static int lbs_thread(void *data)
}
priv->cmd_timed_out = 0;
- /* Process hardware events, e.g. card removed, link lost */
- spin_lock_irq(&priv->driver_lock);
- while (__kfifo_len(priv->event_fifo)) {
- u32 event;
- __kfifo_get(priv->event_fifo, (unsigned char *) &event,
- sizeof(event));
- spin_unlock_irq(&priv->driver_lock);
- lbs_process_event(priv, event);
- spin_lock_irq(&priv->driver_lock);
- }
- spin_unlock_irq(&priv->driver_lock);
if (!priv->fw_ready)
continue;
@@ -894,6 +906,9 @@ static int lbs_thread(void *data)
(priv->psstate == PS_STATE_PRE_SLEEP))
continue;
+ if (priv->is_deep_sleep)
+ continue;
+
/* Execute the next command */
if (!priv->dnld_sent && !priv->cur_cmd)
lbs_execute_next_command(priv);
@@ -928,6 +943,7 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
wake_up_all(&priv->cmd_pending);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +1066,60 @@ out:
lbs_deb_leave(LBS_DEB_CMD);
}
+/**
+ * This function put the device back to deep sleep mode when timer expires
+ * and no activity (command, event, data etc.) is detected.
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+ struct lbs_private *priv = (struct lbs_private *)data;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_activity_detected) {
+ priv->is_activity_detected = 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled &&
+ (!priv->wakeup_dev_required) &&
+ (priv->connect_status != LBS_CONNECTED)) {
+ lbs_deb_main("Entering auto deep sleep mode...\n");
+ ret = lbs_prepare_and_send_command(priv,
+ CMD_802_11_DEEP_SLEEP, 0,
+ 0, 0, NULL);
+ }
+ }
+ mod_timer(&priv->auto_deepsleep_timer , jiffies +
+ (priv->auto_deep_sleep_timeout * HZ)/1000);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 1;
+ if (priv->is_deep_sleep)
+ priv->wakeup_dev_required = 1;
+ mod_timer(&priv->auto_deepsleep_timer ,
+ jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->auto_deep_sleep_timeout = 0;
+ del_timer(&priv->auto_deepsleep_timer);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
static void lbs_sync_channel_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
+ priv->is_deep_sleep = 0;
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->wakeup_dev_required = 0;
+ init_waitqueue_head(&priv->ds_awake_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, command_timer_fn,
(unsigned long)priv);
+ setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+ (unsigned long)priv);
INIT_LIST_HEAD(&priv->cmdfreeq);
INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
if (priv->event_fifo)
kfifo_free(priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
kfree(priv->networks);
priv->networks = NULL;
@@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv)
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ if (priv->is_deep_sleep) {
+ priv->is_deep_sleep = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ }
+
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
@@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv)
/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
+ del_timer_sync(&priv->auto_deepsleep_timer);
/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3..e468e15 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -950,6 +950,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
@@ -1017,6 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ err = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
+ return err;
+ }
+
/* iwlist should wait until the current scan is finished */
if (priv->scan_channel)
return -EAGAIN;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0..38a451e 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -45,6 +45,31 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL;
}
+/**
+ * @brief This function checks if the command is allowed.
+ *
+ * @param priv A pointer to lbs_private structure
+ * @return allowed or not allowed.
+ */
+
+int lbs_is_cmd_allowed(struct lbs_private *priv)
+{
+ int ret = 1;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_wext("IOCTLS called when station"
+ "is in deep sleep\n");
+ ret = 0;
+ }
+ }
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return ret;
+}
+
/**
* @brief Find the channel frequency power info with specific channel
@@ -168,6 +193,11 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return -EBUSY;
+ }
+
cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
priv->curbssparams.channel);
@@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (vwrq->disabled)
val = MRVDRV_RTS_MAX_VALUE;
@@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
if (ret)
goto out;
@@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (vwrq->disabled)
val = MRVDRV_FRAG_MAX_VALUE;
@@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
if (ret)
goto out;
@@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if (!priv->radio_on) {
lbs_deb_wext("tx power off\n");
vwrq->value = 0;
@@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
return -EOPNOTSUPP;
@@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
vwrq->disabled = 0;
if (vwrq->flags & IW_RETRY_LONG) {
@@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
"setting power timeout is not supported\n");
return -EINVAL;
} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- lbs_deb_wext("setting power period not supported\n");
- return -EINVAL;
+ vwrq->value = vwrq->value / 1000;
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ return -EINVAL;
+ }
+
+ if (priv->connect_status == LBS_CONNECTED) {
+ if ((priv->is_auto_deep_sleep_enabled) &&
+ (vwrq->value == -1000)) {
+ lbs_exit_auto_deep_sleep(priv);
+ return 0;
+ } else {
+ lbs_pr_err("can't use deep sleep cmd in "
+ "connected state\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((vwrq->value < 0) && (vwrq->value != -1000)) {
+ lbs_pr_err("unknown option\n");
+ return -EINVAL;
+ }
+
+ if (vwrq->value > 0) {
+ if (!priv->is_auto_deep_sleep_enabled) {
+ priv->is_activity_detected = 0;
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_enter_auto_deep_sleep(priv);
+ } else {
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_deb_debugfs("auto deep sleep: "
+ "already enabled\n");
+ }
+ return 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled) {
+ lbs_exit_auto_deep_sleep(priv);
+ /* Try to exit deep sleep if auto */
+ /*deep sleep disabled */
+ ret = lbs_set_deep_sleep(priv, 0);
+ }
+ if (vwrq->value == 0)
+ ret = lbs_set_deep_sleep(priv, 1);
+ else if (vwrq->value == -1000)
+ ret = lbs_set_deep_sleep(priv, 0);
+ return ret;
+ }
}
if (priv->psmode != LBS802_11POWERMODECAM) {
@@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
}
lbs_deb_leave(LBS_DEB_WEXT);
+
return 0;
}
@@ -792,6 +907,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv))
+ return NULL;
+
priv->wstats.status = priv->mode;
/* If we're not associated, all quality values are meaningless */
@@ -892,6 +1010,12 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1000,6 +1124,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
u8 rates[MAX_RATES + 1];
lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
@@ -1058,6 +1188,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return -EBUSY;
+ }
+
if (priv->connect_status == LBS_CONNECTED) {
vwrq->value = priv->cur_rate * 500000;
@@ -1084,6 +1219,11 @@ static int lbs_set_mode(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if ( (*uwrq != IW_MODE_ADHOC)
&& (*uwrq != IW_MODE_INFRA)
&& (*uwrq != IW_MODE_AUTO)) {
@@ -1325,6 +1465,12 @@ static int lbs_set_encode(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1508,6 +1654,12 @@ static int lbs_set_encodeext(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1720,6 +1872,12 @@ static int lbs_set_auth(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1822,6 +1980,12 @@ static int lbs_get_auth(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
switch (dwrq->flags & IW_AUTH_INDEX) {
case IW_AUTH_KEY_MGMT:
dwrq->value = priv->secinfo.key_mgmt;
@@ -1864,6 +2028,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if (vwrq->disabled) {
lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
goto out;
@@ -1983,6 +2152,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
@@ -2110,6 +2285,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (!priv->radio_on)
return -EINVAL;
--
1.5.4.3
^ permalink raw reply related
* Re: [PATCH 1/3] wireless: implement basic ethtool support for cfg80211 devices
From: Ben Hutchings @ 2009-10-01 1:30 UTC (permalink / raw)
To: John W. Linville
Cc: linux-wireless, netdev, Kalle Valo, Kalle Valo, Luis R. Rodriguez
In-Reply-To: <1254359942-3483-1-git-send-email-linville@tuxdriver.com>
On Wed, 2009-09-30 at 21:19 -0400, John W. Linville wrote:
[...]
> +void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
> +{
> + struct wireless_dev *wdev = dev->ieee80211_ptr;
> +
> + strncpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name,
> + sizeof(info->driver));
> + info->driver[sizeof(info->driver) - 1] = '\0';
[...]
Use strlcpy() instead of these two statements.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH 3/3] at76c50x-usb: set firmware and hardware version in wiphy
From: Ben Hutchings @ 2009-10-01 1:32 UTC (permalink / raw)
To: John W. Linville
Cc: linux-wireless, netdev, Kalle Valo, Kalle Valo, Luis R. Rodriguez
In-Reply-To: <1254359942-3483-3-git-send-email-linville@tuxdriver.com>
On Wed, 2009-09-30 at 21:19 -0400, John W. Linville wrote:
[...]
> + len = sizeof(wiphy->fw_version);
> + snprintf(wiphy->fw_version, len, "%d.%d.%d-%d",
> + priv->fw_version.major, priv->fw_version.minor,
> + priv->fw_version.patch, priv->fw_version.build);
> + /* null terminate the strings in case they were truncated */
> + wiphy->fw_version[len - 1] = '\0';
[...]
This last statement is unnecessary; snprintf() always null-terminates
(unless the length is zero).
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* [PATCH 2/3] cfg80211: add firmware and hardware version to wiphy
From: John W. Linville @ 2009-10-01 1:19 UTC (permalink / raw)
To: linux-wireless
Cc: netdev, Kalle Valo, Kalle Valo, Luis R. Rodriguez,
John W. Linville
In-Reply-To: <1254359942-3483-1-git-send-email-linville@tuxdriver.com>
From: Kalle Valo <kalle.valo@nokia.com>
It's useful to provide firmware and hardware version to user space and have a
generic interface to retrieve them. Users can provide the version information
in bug reports etc.
Add fields for firmware and hardware version to struct wiphy.
(Dropped nl80211 bits for now and modified remaining bits in favor of
ethtool. -- JWL)
Cc: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
include/net/cfg80211.h | 3 +++
net/wireless/ethtool.c | 23 ++++++++++++++++++++++-
net/wireless/ethtool.h | 3 +++
3 files changed, 28 insertions(+), 1 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 241ea14..6f4862b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1142,6 +1142,9 @@ struct wiphy {
u32 frag_threshold;
u32 rts_threshold;
+ char fw_version[ETHTOOL_BUSINFO_LEN];
+ u32 hw_version;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c
index 94ca377..3c59549 100644
--- a/net/wireless/ethtool.c
+++ b/net/wireless/ethtool.c
@@ -4,6 +4,8 @@
const struct ethtool_ops cfg80211_ethtool_ops = {
.get_drvinfo = cfg80211_get_drvinfo,
+ .get_regs_len = cfg80211_get_regs_len,
+ .get_regs = cfg80211_get_regs,
.get_link = ethtool_op_get_link,
};
@@ -18,10 +20,29 @@ void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strncpy(info->version, UTS_RELEASE, sizeof(info->version));
info->version[sizeof(info->version) - 1] = '\0';
- strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ if (wdev->wiphy->fw_version[0])
+ strncpy(info->fw_version, wdev->wiphy->fw_version,
+ sizeof(info->fw_version));
+ else
+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
info->fw_version[sizeof(info->fw_version) - 1] = '\0';
strncpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
sizeof(info->bus_info));
info->bus_info[sizeof(info->bus_info) - 1] = '\0';
}
+
+int cfg80211_get_regs_len(struct net_device *dev)
+{
+ /* For now, return 0... */
+ return 0;
+}
+
+void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *data)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ regs->version = wdev->wiphy->hw_version;
+ regs->len = 0;
+}
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h
index a51b470..2d4602a 100644
--- a/net/wireless/ethtool.h
+++ b/net/wireless/ethtool.h
@@ -4,6 +4,9 @@
#include <linux/ethtool.h>
extern void cfg80211_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+extern int cfg80211_get_regs_len(struct net_device *);
+extern void cfg80211_get_regs(struct net_device *, struct ethtool_regs *,
+ void *);
extern const struct ethtool_ops cfg80211_ethtool_ops;
--
1.6.2.5
^ permalink raw reply related
* [PATCH 3/3] at76c50x-usb: set firmware and hardware version in wiphy
From: John W. Linville @ 2009-10-01 1:19 UTC (permalink / raw)
To: linux-wireless
Cc: netdev, Kalle Valo, Kalle Valo, Luis R. Rodriguez,
John W. Linville
In-Reply-To: <1254359942-3483-2-git-send-email-linville@tuxdriver.com>
From: Kalle Valo <kalle.valo@iki.fi>
Set firmware and hardware version in wiphy so that user space can access
it.
(Modification from original in favor of cfg80211 ethtool support. -- JWL)
Cc: Kalle Valo <kalle.valo@iki.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
drivers/net/wireless/at76c50x-usb.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 8e1a55d..533954d 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2217,6 +2217,8 @@ static struct ieee80211_supported_band at76_supported_band = {
static int at76_init_new_device(struct at76_priv *priv,
struct usb_interface *interface)
{
+ struct wiphy *wiphy;
+ size_t len;
int ret;
/* set up the endpoint information */
@@ -2254,6 +2256,7 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->device_unplugged = 0;
/* mac80211 initialisation */
+ wiphy = priv->hw->wiphy;
priv->hw->wiphy->max_scan_ssids = 1;
priv->hw->wiphy->max_scan_ie_len = 0;
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
@@ -2265,6 +2268,15 @@ static int at76_init_new_device(struct at76_priv *priv,
SET_IEEE80211_DEV(priv->hw, &interface->dev);
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ len = sizeof(wiphy->fw_version);
+ snprintf(wiphy->fw_version, len, "%d.%d.%d-%d",
+ priv->fw_version.major, priv->fw_version.minor,
+ priv->fw_version.patch, priv->fw_version.build);
+ /* null terminate the strings in case they were truncated */
+ wiphy->fw_version[len - 1] = '\0';
+
+ wiphy->hw_version = priv->board_type;
+
ret = ieee80211_register_hw(priv->hw);
if (ret) {
printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
--
1.6.2.5
^ permalink raw reply related
* [PATCH 1/3] wireless: implement basic ethtool support for cfg80211 devices
From: John W. Linville @ 2009-10-01 1:19 UTC (permalink / raw)
To: linux-wireless
Cc: netdev, Kalle Valo, Kalle Valo, Luis R. Rodriguez,
John W. Linville
In-Reply-To: <20091001011340.GA3123@tuxdriver.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
net/wireless/Makefile | 2 +-
net/wireless/core.c | 3 +++
net/wireless/ethtool.c | 27 +++++++++++++++++++++++++++
net/wireless/ethtool.h | 10 ++++++++++
4 files changed, 41 insertions(+), 1 deletions(-)
create mode 100644 net/wireless/ethtool.c
create mode 100644 net/wireless/ethtool.h
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index c814150..f07c8dc 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c761532..faada5c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -21,6 +21,7 @@
#include "sysfs.h"
#include "debugfs.h"
#include "wext-compat.h"
+#include "ethtool.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -683,6 +684,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->wext.ps = false;
}
#endif
+ if (!dev->ethtool_ops)
+ dev->ethtool_ops = &cfg80211_ethtool_ops;
break;
case NETDEV_GOING_DOWN:
switch (wdev->iftype) {
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c
new file mode 100644
index 0000000..94ca377
--- /dev/null
+++ b/net/wireless/ethtool.c
@@ -0,0 +1,27 @@
+#include <linux/utsrelease.h>
+#include <net/cfg80211.h>
+#include "ethtool.h"
+
+const struct ethtool_ops cfg80211_ethtool_ops = {
+ .get_drvinfo = cfg80211_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
+
+void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ strncpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name,
+ sizeof(info->driver));
+ info->driver[sizeof(info->driver) - 1] = '\0';
+
+ strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+ info->version[sizeof(info->version) - 1] = '\0';
+
+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ info->fw_version[sizeof(info->fw_version) - 1] = '\0';
+
+ strncpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
+ sizeof(info->bus_info));
+ info->bus_info[sizeof(info->bus_info) - 1] = '\0';
+}
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h
new file mode 100644
index 0000000..a51b470
--- /dev/null
+++ b/net/wireless/ethtool.h
@@ -0,0 +1,10 @@
+#ifndef __CFG80211_ETHTOOL__
+#define __CFG80211_ETHTOOL__
+
+#include <linux/ethtool.h>
+
+extern void cfg80211_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+
+extern const struct ethtool_ops cfg80211_ethtool_ops;
+
+#endif /* __CFG80211_ETHTOOL__ */
--
1.6.2.5
^ permalink raw reply related
* Re: [PATCH 0/2] cfg80211: firmware and hardware version
From: John W. Linville @ 2009-10-01 1:13 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: Kalle Valo, linux-wireless, netdev
In-Reply-To: <43e72e890909250953r1714c79bsa679b96ca6f5797@mail.gmail.com>
On Fri, Sep 25, 2009 at 09:53:35AM -0700, Luis R. Rodriguez wrote:
> On Fri, Sep 25, 2009 at 9:47 AM, Kalle Valo <kalle.valo@iki.fi> wrote:
> > But we want to export two strings to user space (at least for now), is
> > it really worth the effort to add ethtool support for such a minor
> > feature? Also I have understood that ethtool is implemented only for
> > ethernet drivers, I don't feel comfortable that we use ethernet driver
> > interfaces with 802.11 device drivers. They are so much different that
> > there isn't that much common functionality. That's why I prefer
> > nl80211 over ethtool.
> >
> > What do people think?
>
> So for Wake-on-Wireless I ran into the same, ethtool just did not
> offer the same wake up events needed for wireless. I could have
> technically used ethtool and expanded it to support wireless but it
> just seemed dirty.
>
> I agree that using ethtool seems overkill compared to the patches you posted.
I think you either overestimate the amount of trouble for implementing
(minimal) ethtool support or you underestimate the amount of
functionality available through that interface. That, or you just
don't like using something named "eth"tool for wireless -- but hey,
let's be honest about the frames we send/receive to/from the kernel...
:-)
The ethtool interface provides functionality for viewing and modifying
eeprom contents, dumping registers, trigger self-tests, basic driver
info, getting and setting message reporting levels, external card
identification (hey, _could_ be useful!), and some other bits like
checksum offload that might(?) be useful in the future. I understand
regarding the WoW vs. WoL issue but probably the answer is just to
add a new method for WoW...?
I'll post a patch series based on what Kalle sent but using ethtool
instead of nl80211...
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
* Re: [SOLVED][.32-rc1/2] ath5k: has become unreliable with .32-rc1
From: Frans Pop @ 2009-10-01 0:35 UTC (permalink / raw)
To: linux-wireless; +Cc: linux-kernel, Bob Copeland, Rafael J. Wysocki
In-Reply-To: <200909300952.29106.elendil@planet.nl>
On Wednesday 30 September 2009, Frans Pop wrote:
> The first time I booted .32-rc1 (reboot from .31-rc5), wireless came up
> without problems, but failed to come back after suspend to RAM. I could
> only get wireless back by ejecting and re-inserting the PCMCIA card.
>
> The second and third time I booted .32-rc1 (to write this report; a cold
> boot and a ".32 to .32" reboot), wireless did not come up at all.
> See attached dmesg. The last part is after 'ifup ath0'. It seems to
> associate, but then for some reason immediately deauthenticates again.
Both issues are solved with current mainline. Probably the resume issue by
Rafael's PCMCIA patch (the "late" config restore messages for ath5k are
back too), the boot issue by one of Johannes' patches (I'd guess either
4be3bd8c 'cfg80211: don't set privacy w/o key' or maybe 8bb89485
'cfg80211: always get BSS').
Still strange that iwlagn continued to work. Although, come to think of it,
I have not cold booted that laptop recently.
Cheers,
FJP
^ permalink raw reply
* Re: [PATCH] net: fix NOHZ: local_softirq_pending 08
From: David Miller @ 2009-09-30 23:33 UTC (permalink / raw)
To: oliver; +Cc: johannes, mb, kalle.valo, linville, linux-wireless, netdev
In-Reply-To: <4AC3A0F1.3060306@hartkopp.net>
From: Oliver Hartkopp <oliver@hartkopp.net>
Date: Wed, 30 Sep 2009 20:18:25 +0200
> Socket buffers that are generated and received inside softirqs or from process
> context must not use netif_rx() that's intended to be used from irq context only.
>
> This patch introduces a new helper function netif_rx_ti(skb) that tests for
> in_interrupt() before invoking netif_rx() or netif_rx_ni().
>
> It fixes the ratelimited kernel warning
>
> NOHZ: local_softirq_pending 08
>
> in the mac80211 and can subsystems.
>
> Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net>
I bet all of these code paths can use netif_receive_skb() or
don't need this conditional blob at all.
Looking at some specific cases in this patch:
1) VCAN: This RX routine is only invoked from the drivers
->ndo_start_xmit() handler, and therefore like the loopback
driver we know that BH's are already disabled and therefore
it can always use netif_rx() safely.
Why did you convert this case?
And if this needs to be converted, why doesn't loopback need
to be?
2) af_can.c: In what situation will netif_rx_ni() not be appropriate
here? It should always execute in softirq or user context, now
hardirq context.
And the list goes on and on, I don't really like this new conditional
testing of interrupt state. As always, that's usually a red flag and
as far as I can see these spots where you're changing things are only
trying to receive packets in one of the two possible cases not both.
I'm not applying this until all of these details are sorted out and
you add some verbosity to the commit message explaining each and every
case you are changing, what contexts those cases can be called
from, and from where.
Thanks.
^ permalink raw reply
* Re: SME warning on 2.6.32-rc<bleh>
From: Luis R. Rodriguez @ 2009-09-30 23:19 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <43e72e890909301612v5079c9bco9ac8529f77a7c67a@mail.gmail.com>
On Wed, Sep 30, 2009 at 4:12 PM, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
> On Tue, Sep 29, 2009 at 12:24 PM, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
>> I believe the problem comes from the assumption from cfg80211 that
>> previous deauthentications would have gone through before we run
>> __cfg80211_disconnected() and are using wext or nl80211
>> connec/disconnectt. Under certain conditions (clearly not known yet)
>> this is not true and we'll end up asking mac80211 to deauthenticate us
>> from a BSS we already deauthenticated to end end up with an -ENOLINK
>> on our mac80211 cfg80211 deauth ops. It seems this race was expected
>> all along on mac80211 ieee80211_mgd_deauth():
>>
>> /*
>> * cfg80211 should catch this ... but it's racy since
>> * we can receive a deauth frame, process it, hand it
>> * to cfg80211 while that's in a locked section already
>> * trying to tell us that the user wants to disconnect.
>> */
>> if (!bssid) {
>> mutex_unlock(&ifmgd->mtx);
>> return -ENOLINK;
>> }
>>
>> So it seems we do need to address that race but I'm not yet sure how.
>>
>> Here is a warning from the latest wireless-testing. Unfortunately I
>> cannot reproduce in a systematic way, I've tried even different boot
>> configuration (mem=300M) and CPU pegged at 800 MHz thinking the race
>> occurs when mac80211 takes its sweet time deathenticating but that
>> wasn't the case.
>
> OK so I just got this again today with a cardbus card. The curious
> thing to see was that it happened when I rmmod'd ath9k right after
> these messages:
>
> [ 234.481226] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
> AR_DIAG_SW=0x40000020
> [ 234.928823] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
> AR_DIAG_SW=0x40000020
> [ 237.064792] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
> AR_DIAG_SW=0x40000020
> [ 310.676842] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
> AR_DIAG_SW=0x40000020
Mind you I am not sure if its the Cardbus card, it could be busted,
I've seen some strange issues with it before.
Luis
^ permalink raw reply
* Re: SME warning on 2.6.32-rc<bleh>
From: Luis R. Rodriguez @ 2009-09-30 23:12 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <43e72e890909291224t26b7e6cbmc78976165bd1bb88@mail.gmail.com>
On Tue, Sep 29, 2009 at 12:24 PM, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
> I believe the problem comes from the assumption from cfg80211 that
> previous deauthentications would have gone through before we run
> __cfg80211_disconnected() and are using wext or nl80211
> connec/disconnectt. Under certain conditions (clearly not known yet)
> this is not true and we'll end up asking mac80211 to deauthenticate us
> from a BSS we already deauthenticated to end end up with an -ENOLINK
> on our mac80211 cfg80211 deauth ops. It seems this race was expected
> all along on mac80211 ieee80211_mgd_deauth():
>
> /*
> * cfg80211 should catch this ... but it's racy since
> * we can receive a deauth frame, process it, hand it
> * to cfg80211 while that's in a locked section already
> * trying to tell us that the user wants to disconnect.
> */
> if (!bssid) {
> mutex_unlock(&ifmgd->mtx);
> return -ENOLINK;
> }
>
> So it seems we do need to address that race but I'm not yet sure how.
>
> Here is a warning from the latest wireless-testing. Unfortunately I
> cannot reproduce in a systematic way, I've tried even different boot
> configuration (mem=300M) and CPU pegged at 800 MHz thinking the race
> occurs when mac80211 takes its sweet time deathenticating but that
> wasn't the case.
OK so I just got this again today with a cardbus card. The curious
thing to see was that it happened when I rmmod'd ath9k right after
these messages:
[ 234.481226] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
AR_DIAG_SW=0x40000020
[ 234.928823] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
AR_DIAG_SW=0x40000020
[ 237.064792] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
AR_DIAG_SW=0x40000020
[ 310.676842] ath: DMA failed to stop in 10 ms AR_CR=0x00000024
AR_DIAG_SW=0x40000020
There were quite a lot of these. I was then thinking perhaps it has to
do with mac80211 assuming a hardware state which we obviously are not
in yet but then again -- I believe I've seen these with ath5k as well.
Here's the new shiny warning as of today's wireless testing (john just updated)
[ 701.025450] phy1: device now idle
[ 701.025503] phy1: Removed STA <myh-ap>
[ 701.036691] phy1: Destroyed STA <my-ap>
[ 701.036725] wlan3: deauthenticating from <my-ap> by local choice (reason=3)
[ 701.036848] ------------[ cut here ]------------
[ 701.036862] WARNING: at net/wireless/sme.c:620
__cfg80211_disconnected+0x209/0x260 [cfg80211]()
[ 701.036866] Hardware name: 7660A14
[ 701.036868] deauth failed: -67 (editorial note: -ENOLINK)
[ 701.036870] Modules linked in: ath9k(-) ath9k_hw (shiny new
module!) ath <etc>
[ 701.036944] Pid: 4432, comm: rmmod Not tainted 2.6.32-rc2-wl #47
[ 701.036947] Call Trace:
[ 701.036956] [<ffffffff8105be78>] warn_slowpath_common+0x78/0xb0
[ 701.036960] [<ffffffff8105bf0c>] warn_slowpath_fmt+0x3c/0x40
[ 701.036970] [<ffffffffa00df439>]
__cfg80211_disconnected+0x209/0x260 [cfg80211]
[ 701.036980] [<ffffffffa00dd158>]
__cfg80211_send_deauth+0x228/0x2a0 [cfg80211]
[ 701.036989] [<ffffffffa00dd211>] cfg80211_send_deauth+0x41/0x80 [cfg80211]
[ 701.037003] [<ffffffffa01d4c1f>]
ieee80211_send_deauth_disassoc+0x14f/0x170 [mac80211]
[ 701.037014] [<ffffffffa01d7945>] ieee80211_mgd_deauth+0xf5/0x120 [mac80211]
[ 701.037025] [<ffffffffa01dbfa9>] ieee80211_deauth+0x19/0x20 [mac80211]
[ 701.037034] [<ffffffffa00dbb5e>] __cfg80211_mlme_deauth+0xee/0x130
[cfg80211]
[ 701.037042] [<ffffffffa00cb22c>] ?
cfg80211_netdev_notifier_call+0xdc/0x400 [cfg80211]
[ 701.037048] [<ffffffff8108f1bc>] ? mark_held_locks+0x6c/0xa0
[ 701.037057] [<ffffffffa00df9a9>] __cfg80211_disconnect+0x159/0x1d0
[cfg80211]
[ 701.037065] [<ffffffffa00cb261>]
cfg80211_netdev_notifier_call+0x111/0x400 [cfg80211]
[ 701.037072] [<ffffffff81538ea7>] notifier_call_chain+0x47/0x90
[ 701.037078] [<ffffffff8107fc51>] raw_notifier_call_chain+0x11/0x20
[ 701.037084] [<ffffffff8144cb46>] call_netdevice_notifiers+0x16/0x20
[ 701.037088] [<ffffffff8144d335>] dev_close+0x55/0xb0
[ 701.037092] [<ffffffff8144d6f8>] rollback_registered+0x48/0x120
[ 701.037097] [<ffffffff8144d7ed>] unregister_netdevice+0x1d/0x70
[ 701.037107] [<ffffffffa01d8d36>]
ieee80211_remove_interfaces+0x86/0xc0 [mac80211]
[ 701.037115] [<ffffffffa01cc0a2>] ieee80211_unregister_hw+0x42/0xf0
[mac80211]
[ 701.037123] [<ffffffffa04879b6>] ath_detach+0x86/0x170 [ath9k]
[ 701.037129] [<ffffffffa0487ac0>] ath_cleanup+0x20/0x60 [ath9k]
[ 701.037136] [<ffffffffa04912e9>] ath_pci_remove+0x19/0x20 [ath9k]
[ 701.037141] [<ffffffff812aeb2f>] pci_device_remove+0x2f/0x60
[ 701.037147] [<ffffffff81343850>] __device_release_driver+0x70/0xe0
[ 701.037151] [<ffffffff81343980>] driver_detach+0xc0/0xd0
[ 701.037155] [<ffffffff813428a8>] bus_remove_driver+0x98/0xc0
[ 701.037159] [<ffffffff81343f8a>] driver_unregister+0x5a/0x90
[ 701.037164] [<ffffffff812aee3f>] pci_unregister_driver+0x3f/0xb0
[ 701.037170] [<ffffffffa0491190>] ath_pci_exit+0x10/0x20 [ath9k]
[ 701.037176] [<ffffffffa04935e5>] ath9k_exit+0x9/0x2a [ath9k]
[ 701.037180] [<ffffffff8109c17a>] sys_delete_module+0x1aa/0x270
[ 701.037186] [<ffffffff81012975>] ? retint_swapgs+0x13/0x1b
[ 701.037191] [<ffffffff8153579f>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[ 701.037196] [<ffffffff81011ec2>] system_call_fastpath+0x16/0x1b
[ 701.037199] ---[ end trace 6c7b2b3bef84cccc ]---
[ 702.431558] ath9k 0000:16:00.0: PCI INT A disabled
[ 702.433718] ath9k: Driver unloaded
Luis
^ permalink raw reply
* Re: [stable] Making Intel WiFi Link 1000 usable in 2.6.31
From: reinette chatre @ 2009-09-30 22:36 UTC (permalink / raw)
To: Greg KH; +Cc: stable@kernel.org, linux-wireless@vger.kernel.org
In-Reply-To: <20090930212447.GB30093@kroah.com>
[-- Attachment #1: Type: text/plain, Size: 2193 bytes --]
On Wed, 2009-09-30 at 14:24 -0700, Greg KH wrote:
> On Wed, Sep 30, 2009 at 12:34:19PM -0700, reinette chatre wrote:
> > commit cc0f555d511a5fe9d4519334c8f674a1dbab9e3a
> > Author: Jay Sternberg <jay.e.sternberg@intel.com>
> > Date: Fri Jul 17 09:30:16 2009 -0700
> >
> > iwlwifi: Handle new firmware file with ucode build number in header
> >
> > commit cce53aa347c1e023d967b1cb1aa393c725aedba5
> > Author: Jay Sternberg <jay.e.sternberg@intel.com>
> > Date: Fri Jul 17 09:30:22 2009 -0700
> >
> > iwlwifi: update 1000 series API version to match firmware
> >
> > commit 02c06e4abc0680afd31bf481a803541556757fb6
> > Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > Date: Fri Jul 17 09:30:14 2009 -0700
> >
> > iwlagn: modify digital SVR for 1000
> >
> > commit 415e49936b4b29b34c2fb561eeab867d41fc43a6
> > Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > Date: Thu Aug 13 13:30:54 2009 -0700
> >
> > iwlwifi: traverse linklist to find the valid OTP block
> >
> > commit f7ea097d9b4e61a816c041c92548aad7c7ed7915
> > Author: Reinette Chatre <reinette.chatre@intel.com>
> > Date: Fri Jul 24 11:13:12 2009 -0700
> >
> > iwlagn: fix null pointer access during ucode load on 1000
> >
> > Thank you very much
>
> Is this the order in which they should be applied?
The first three patches from this list can be applied directly from
linux-2.6 in the order they appear here. That is:
commit cc0f555d511a5fe9d4519334c8f674a1dbab9e3a
Author: Jay Sternberg <jay.e.sternberg@intel.com>
Date: Fri Jul 17 09:30:16 2009 -0700
iwlwifi: Handle new firmware file with ucode build number in header
commit cce53aa347c1e023d967b1cb1aa393c725aedba5
Author: Jay Sternberg <jay.e.sternberg@intel.com>
Date: Fri Jul 17 09:30:22 2009 -0700
iwlwifi: update 1000 series API version to match firmware
commit 02c06e4abc0680afd31bf481a803541556757fb6
Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Date: Fri Jul 17 09:30:14 2009 -0700
iwlagn: modify digital SVR for 1000
The fourth patch needed backporting and is attached.
After doing the backporting I determined that the fifth patch is not
needed.
Thank you very much for taking these patches
Reinette
[-- Attachment #2: 0001-iwlwifi-traverse-linklist-to-find-the-valid-OTP-blo.patch --]
[-- Type: text/x-patch, Size: 14696 bytes --]
>From 07c88863a94534f36668ed543555e020c949990e Mon Sep 17 00:00:00 2001
From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Date: Thu, 13 Aug 2009 13:30:54 -0700
Subject: [PATCH] iwlwifi: traverse linklist to find the valid OTP block
For devices using OTP memory, EEPROM image can start from
any one of the OTP blocks. If shadow RAM is disabled, we need to
traverse link list to find the last valid block, then start the EEPROM
image reading.
If OTP is not full, the valid block is the block _before_ the last block
on the link list; the last block on the link list is the empty block
ready for next OTP refresh/update.
If OTP is full, then the last block is the valid block to be used for
configure the device.
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
drivers/net/wireless/iwlwifi/iwl-1000.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-6000.c | 20 +++-
drivers/net/wireless/iwlwifi/iwl-core.h | 4 +
drivers/net/wireless/iwlwifi/iwl-dev.h | 12 ++
drivers/net/wireless/iwlwifi/iwl-eeprom.c | 185 +++++++++++++++++++++++------
drivers/net/wireless/iwlwifi/iwl-eeprom.h | 10 ++-
6 files changed, 192 insertions(+), 43 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index a899be9..d83d430 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -62,12 +62,14 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.ucode_api_min = IWL1000_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+ .shadow_ram_support = false,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 26c5d4a..e4a405f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -82,13 +82,15 @@ struct iwl_cfg iwl6000_2ag_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
};
struct iwl_cfg iwl6000_2agn_cfg = {
@@ -98,13 +100,15 @@ struct iwl_cfg iwl6000_2agn_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -114,13 +118,15 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -130,13 +136,15 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -146,13 +154,15 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index e460eb6..1e51891 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -207,6 +207,8 @@ struct iwl_mod_params {
* filename is constructed as fw_name_pre<api>.ucode.
* @ucode_api_max: Highest version of uCode API supported by driver.
* @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @max_ll_items: max number of OTP blocks
+ * @shadow_ram_support: shadow support for OTP memory
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -243,6 +245,8 @@ struct iwl_cfg {
u8 valid_rx_ant;
bool need_pll_cfg;
bool use_isr_legacy;
+ const u16 max_ll_items;
+ const bool shadow_ram_support;
};
/***************************
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 5491041..e8c8607 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -835,6 +835,18 @@ enum iwl_nvm_type {
NVM_DEVICE_TYPE_OTP,
};
+/*
+ * Two types of OTP memory access modes
+ * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
+ * based on physical memory addressing
+ * IWL_OTP_ACCESS_RELATIVE - relative address mode,
+ * based on logical memory addressing
+ */
+enum iwl_access_mode {
+ IWL_OTP_ACCESS_ABSOLUTE,
+ IWL_OTP_ACCESS_RELATIVE,
+};
+
/* interrupt statistics */
struct isr_statistics {
u32 hw;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 7d7554a..e8c0e82 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
+static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+{
+ u32 otpgp;
+
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ if (mode == IWL_OTP_ACCESS_ABSOLUTE)
+ iwl_clear_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+ else
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+}
+
static int iwlcore_get_nvm_type(struct iwl_priv *priv)
{
u32 otpgp;
@@ -249,6 +262,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
return ret;
}
+static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
+{
+ int ret = 0;
+ u32 r;
+ u32 otpgp;
+
+ _iwl_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+ ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ IWL_EEPROM_ACCESS_TIMEOUT);
+ if (ret < 0) {
+ IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+ return ret;
+ }
+ r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+ /* check for ECC errors: */
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+ /* stop in this case */
+ /* set the uncorrectable OTP ECC bit for acknowledgement */
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+ IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+ return -EINVAL;
+ }
+ if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+ /* continue in this case */
+ /* set the correctable OTP ECC bit for acknowledgement */
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+ IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+ }
+ *eeprom_data = le16_to_cpu((__force __le16)(r >> 16));
+ return 0;
+}
+
+/*
+ * iwl_is_otp_empty: check for empty OTP
+ */
+static bool iwl_is_otp_empty(struct iwl_priv *priv)
+{
+ u16 next_link_addr = 0, link_value;
+ bool is_empty = false;
+
+ /* locate the beginning of OTP link list */
+ if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+ if (!link_value) {
+ IWL_ERR(priv, "OTP is empty\n");
+ is_empty = true;
+ }
+ } else {
+ IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+ is_empty = true;
+ }
+
+ return is_empty;
+}
+
+
+/*
+ * iwl_find_otp_image: find EEPROM image in OTP
+ * finding the OTP block that contains the EEPROM image.
+ * the last valid block on the link list (the block _before_ the last block)
+ * is the block we should read and used to configure the device.
+ * If all the available OTP blocks are full, the last block will be the block
+ * we should read and used to configure the device.
+ * only perform this operation if shadow RAM is disabled
+ */
+static int iwl_find_otp_image(struct iwl_priv *priv,
+ u16 *validblockaddr)
+{
+ u16 next_link_addr = 0, link_value = 0, valid_addr;
+ int ret = 0;
+ int usedblocks = 0;
+
+ /* set addressing mode to absolute to traverse the link list */
+ iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+
+ /* checking for empty OTP or error */
+ if (iwl_is_otp_empty(priv))
+ return -EINVAL;
+
+ /*
+ * start traverse link list
+ * until reach the max number of OTP blocks
+ * different devices have different number of OTP blocks
+ */
+ do {
+ /* save current valid block address
+ * check for more block on the link list
+ */
+ valid_addr = next_link_addr;
+ next_link_addr = link_value;
+ IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
+ usedblocks, next_link_addr);
+ if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+ return -EINVAL;
+ if (!link_value) {
+ /*
+ * reach the end of link list,
+ * set address point to the starting address
+ * of the image
+ */
+ goto done;
+ }
+ /* more in the link list, continue */
+ usedblocks++;
+ } while (usedblocks < priv->cfg->max_ll_items);
+ /* OTP full, use last block */
+ IWL_DEBUG_INFO(priv, "OTP is full, use last block\n");
+done:
+ *validblockaddr = valid_addr;
+ /* skip first 2 bytes (link list pointer) */
+ *validblockaddr += 2;
+ return ret;
+}
+
/**
* iwl_eeprom_init - read EEPROM contents
*
@@ -263,14 +394,13 @@ int iwl_eeprom_init(struct iwl_priv *priv)
int sz;
int ret;
u16 addr;
- u32 otpgp;
+ u16 validblockaddr = 0;
+ u16 cache_addr = 0;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
/* allocate eeprom */
- if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- priv->cfg->eeprom_size =
- OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
+ IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
sz = priv->cfg->eeprom_size;
priv->eeprom = kzalloc(sz, GFP_KERNEL);
if (!priv->eeprom) {
@@ -298,46 +428,31 @@ int iwl_eeprom_init(struct iwl_priv *priv)
if (ret) {
IWL_ERR(priv, "Failed to initialize OTP access.\n");
ret = -ENOENT;
- goto err;
+ goto done;
}
_iwl_write32(priv, CSR_EEPROM_GP,
iwl_read32(priv, CSR_EEPROM_GP) &
~CSR_EEPROM_GP_IF_OWNER_MSK);
- /* clear */
- _iwl_write32(priv, CSR_OTP_GP_REG,
- iwl_read32(priv, CSR_OTP_GP_REG) |
+
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-
- for (addr = 0; addr < sz; addr += sizeof(u16)) {
- u32 r;
-
- _iwl_write32(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_READ_VALID_MSK,
- IWL_EEPROM_ACCESS_TIMEOUT);
- if (ret < 0) {
- IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+ /* traversing the linked list if no shadow ram supported */
+ if (!priv->cfg->shadow_ram_support) {
+ if (iwl_find_otp_image(priv, &validblockaddr)) {
+ ret = -ENOENT;
goto done;
}
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
- /* check for ECC errors: */
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
- if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
- /* stop in this case */
- IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
+ }
+ for (addr = validblockaddr; addr < validblockaddr + sz;
+ addr += sizeof(u16)) {
+ u16 eeprom_data;
+
+ ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+ if (ret)
goto done;
- }
- if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
- /* continue in this case */
- _iwl_write32(priv, CSR_OTP_GP_REG,
- iwl_read32(priv, CSR_OTP_GP_REG) |
- CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
- IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
- }
- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+ e[cache_addr / 2] = eeprom_data;
+ cache_addr += sizeof(u16);
}
} else {
/* eeprom is an array of 16bit values */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 195b4ef..7899885 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -180,8 +180,14 @@ struct iwl_eeprom_channel {
#define EEPROM_5050_EEPROM_VERSION (0x21E)
/* OTP */
-#define OTP_LOWER_BLOCKS_TOTAL (3)
-#define OTP_BLOCK_SIZE (0x400)
+/* lower blocks contain EEPROM image and calibration data */
+#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
+/* high blocks contain PAPD data */
+#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */
+#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */
+#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */
+#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */
+#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
--
1.5.6.3
^ permalink raw reply related
* Re: [.32-rc1/2] ath5k: has become unreliable with .32-rc1
From: Rafael J. Wysocki @ 2009-09-30 22:27 UTC (permalink / raw)
To: Frans Pop; +Cc: Bob Copeland, linux-wireless, linux-kernel
In-Reply-To: <200909302349.05614.elendil@planet.nl>
On Wednesday 30 September 2009, Frans Pop wrote:
> On Wednesday 30 September 2009, Bob Copeland wrote:
> > On Wed, Sep 30, 2009 at 09:52:27AM +0200, Frans Pop wrote:
> > > This is on a laptop I don't use much, but with .31 wireless has always
> > > been (and still is) reliable (.31-rc5 is the last kernel I built for
> > > it). On my other laptop wireless (iwlagn) works fine with .32-rc1.
> >
> > Although iwlagn works, I would think this kind of thing:
> > > ath0: authenticated
> > > ath0: associate with AP 00:14:c1:38:e5:15 (try 1)
> > > ath0: RX ReassocResp from 00:14:c1:38:e5:15 (capab=0x411 status=0 aid=2)
> > > ath0: associated
> > > ath0: deauthenticating by local choice (reason=3)
> >
> > ...is some kind of issue with userspace or wext rather than the driver.
> > Ath5k only had a dozen or so patches this time around, so it should be
> > easy to bisect if it's a problem in the driver. One possibility is
> > hardware CCMP support but I've been using it here for some time.
>
> I doubt it's a userspace issue, but it does look like the regression was
> not triggered by the ath5k driver itself. In the mean time I did a bisect
> on the drivers/net/wireless/ath directory without any results.
>
> > By the way, name it what you will, but the standard is wlan0 these days
> > :)
>
> Yep. A leftover from the days I used madwifi :-) I kind of like it though
> given its similarity to eth0.
>
> > > So the difference looks to be how I boot: if I do a *cold* boot
> > > directly into .32, wireless fails; if I *reboot* from .31 into .32,
> > > wireless comes up correctly. Reboot from .32 to .32 fails too.
> >
> > Is that repeatable?
>
> Yes, 100%. Weird heh? That's what made me think it must be an ath5k
> driver issue as it looks like a hardware initialization problem. Could
> be PCI or PCMCIA though, although I don't see anything suspicious in
> dmesg.
>
> > Rafael J. Wysocki has a patch floating around to fix PCMCIA resume,
> > linked here: http://bugzilla.kernel.org/show_bug.cgi?id=13092
Already in the Linus' tree.
Thanks,
Rafael
^ permalink raw reply
* Re: driver_nl80211 broken again
From: Jouni Malinen @ 2009-09-30 22:13 UTC (permalink / raw)
To: Maxim Levitsky; +Cc: Johannes Berg, hostap@lists.shmoo.com, linux-wireless
In-Reply-To: <1254273569.4499.8.camel@maxim-laptop>
On Wed, Sep 30, 2009 at 03:19:28AM +0200, Maxim Levitsky wrote:
> So I didn't do the testing that soon...
> Got swamped by many bugs present in ubuntu 9.10.
>
> Now I have attempted same patch on top of wpa_supplicant, and it works.
Depends on your definition of working, I'd guess.. ;-)
> @@ -1302,8 +1302,10 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
> wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
> + wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
To me, this looks broken. When wpa_supplicant requests a
disassociastion, it is _only_ asking for disassociation, not
deauthentication. cfg80211/mac80211 may not currently handle that, but
as far as I can tell, it sounds like an issue there and not in
wpa_supplicant. Johannes may disagree with this, though.
> Would that be enough, or this is too hacky, and we need to audit each callsite of wpa_supplicant_disassociate
> and see if we need to send deauth frame too?
I don't think either of those options would be acceptable for
wpa_supplicant and the correct fix is to make cfg80211/mac80211 be able
to handle authentication to a STA that is already authenticated. If
that is not acceptable, this hack needs to be hidden in driver_nl80211.c
instead of polluting core wpa_supplicant code which is supposed to be
driver independent. In other words, make driver_nl80211.c deauth if auth
fails and then try auth again. I don't really like that much, but if
this needs to be worked around in wpa_supplicant, that is the most
likely place where such a change could be considered.
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply
* Re: [stable] Making Intel WiFi Link 1000 usable in 2.6.31
From: reinette chatre @ 2009-09-30 21:53 UTC (permalink / raw)
To: Greg KH; +Cc: stable@kernel.org, linux-wireless@vger.kernel.org
In-Reply-To: <20090930212447.GB30093@kroah.com>
On Wed, 2009-09-30 at 14:24 -0700, Greg KH wrote:
> On Wed, Sep 30, 2009 at 12:34:19PM -0700, reinette chatre wrote:
> >
> > commit cc0f555d511a5fe9d4519334c8f674a1dbab9e3a
> > Author: Jay Sternberg <jay.e.sternberg@intel.com>
> > Date: Fri Jul 17 09:30:16 2009 -0700
> >
> > iwlwifi: Handle new firmware file with ucode build number in header
> >
> > commit cce53aa347c1e023d967b1cb1aa393c725aedba5
> > Author: Jay Sternberg <jay.e.sternberg@intel.com>
> > Date: Fri Jul 17 09:30:22 2009 -0700
> >
> > iwlwifi: update 1000 series API version to match firmware
> >
> > commit 02c06e4abc0680afd31bf481a803541556757fb6
> > Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > Date: Fri Jul 17 09:30:14 2009 -0700
> >
> > iwlagn: modify digital SVR for 1000
> >
> > commit 415e49936b4b29b34c2fb561eeab867d41fc43a6
> > Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > Date: Thu Aug 13 13:30:54 2009 -0700
> >
> > iwlwifi: traverse linklist to find the valid OTP block
> >
> > commit f7ea097d9b4e61a816c041c92548aad7c7ed7915
> > Author: Reinette Chatre <reinette.chatre@intel.com>
> > Date: Fri Jul 24 11:13:12 2009 -0700
> >
> > iwlagn: fix null pointer access during ucode load on 1000
> >
> > Thank you very much
>
> Is this the order in which they should be applied?
This is the correct order, but the last two patches need to be ported to
2.6.31. I will send out new versions.
Reinette
^ permalink raw reply
* Re: [.32-rc1/2] ath5k: has become unreliable with .32-rc1
From: Frans Pop @ 2009-09-30 21:49 UTC (permalink / raw)
To: Bob Copeland; +Cc: linux-wireless, linux-kernel
In-Reply-To: <20090930122451.GA17280@hash.localnet>
On Wednesday 30 September 2009, Bob Copeland wrote:
> On Wed, Sep 30, 2009 at 09:52:27AM +0200, Frans Pop wrote:
> > This is on a laptop I don't use much, but with .31 wireless has always
> > been (and still is) reliable (.31-rc5 is the last kernel I built for
> > it). On my other laptop wireless (iwlagn) works fine with .32-rc1.
>
> Although iwlagn works, I would think this kind of thing:
> > ath0: authenticated
> > ath0: associate with AP 00:14:c1:38:e5:15 (try 1)
> > ath0: RX ReassocResp from 00:14:c1:38:e5:15 (capab=0x411 status=0 aid=2)
> > ath0: associated
> > ath0: deauthenticating by local choice (reason=3)
>
> ...is some kind of issue with userspace or wext rather than the driver.
> Ath5k only had a dozen or so patches this time around, so it should be
> easy to bisect if it's a problem in the driver. One possibility is
> hardware CCMP support but I've been using it here for some time.
I doubt it's a userspace issue, but it does look like the regression was
not triggered by the ath5k driver itself. In the mean time I did a bisect
on the drivers/net/wireless/ath directory without any results.
> By the way, name it what you will, but the standard is wlan0 these days
> :)
Yep. A leftover from the days I used madwifi :-) I kind of like it though
given its similarity to eth0.
> > So the difference looks to be how I boot: if I do a *cold* boot
> > directly into .32, wireless fails; if I *reboot* from .31 into .32,
> > wireless comes up correctly. Reboot from .32 to .32 fails too.
>
> Is that repeatable?
Yes, 100%. Weird heh? That's what made me think it must be an ath5k
driver issue as it looks like a hardware initialization problem. Could
be PCI or PCMCIA though, although I don't see anything suspicious in
dmesg.
> Rafael J. Wysocki has a patch floating around to fix PCMCIA resume,
> linked here: http://bugzilla.kernel.org/show_bug.cgi?id=13092
Ack.
I'll probably wait and see how -rc2 (or 2a or 3 or whatever) behaves
before doing a full bisect, but I will come back to this.
Thanks,
FJP
^ permalink raw reply
* Re: [stable] Making Intel WiFi Link 1000 usable in 2.6.31
From: Greg KH @ 2009-09-30 21:24 UTC (permalink / raw)
To: reinette chatre; +Cc: stable, linux-wireless
In-Reply-To: <1254339259.26521.1645.camel@rc-desk>
On Wed, Sep 30, 2009 at 12:34:19PM -0700, reinette chatre wrote:
> Hi,
>
> A few distributions would like to enable the new 1000 series Intel
> wireless hardware (Intel WiFi Link 1000BGN) in their next releases that
> are based on 2.6.31. This hardware is not usable in 2.6.31, but it can
> be enabled in this kernel with the addition of five patches.
>
> Until now we have been providing the distributions with this list of
> patches to do their own backporting.
>
> Since this seems to be a general problem for distributions and users
> alike, is it possible to consider these enabling patches for inclusion
> into 2.6.31?
>
> Here is the list:
>
> commit cc0f555d511a5fe9d4519334c8f674a1dbab9e3a
> Author: Jay Sternberg <jay.e.sternberg@intel.com>
> Date: Fri Jul 17 09:30:16 2009 -0700
>
> iwlwifi: Handle new firmware file with ucode build number in header
>
> commit cce53aa347c1e023d967b1cb1aa393c725aedba5
> Author: Jay Sternberg <jay.e.sternberg@intel.com>
> Date: Fri Jul 17 09:30:22 2009 -0700
>
> iwlwifi: update 1000 series API version to match firmware
>
> commit 02c06e4abc0680afd31bf481a803541556757fb6
> Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> Date: Fri Jul 17 09:30:14 2009 -0700
>
> iwlagn: modify digital SVR for 1000
>
> commit 415e49936b4b29b34c2fb561eeab867d41fc43a6
> Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> Date: Thu Aug 13 13:30:54 2009 -0700
>
> iwlwifi: traverse linklist to find the valid OTP block
>
> commit f7ea097d9b4e61a816c041c92548aad7c7ed7915
> Author: Reinette Chatre <reinette.chatre@intel.com>
> Date: Fri Jul 24 11:13:12 2009 -0700
>
> iwlagn: fix null pointer access during ucode load on 1000
>
> Thank you very much
Is this the order in which they should be applied?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH]: nl80211: report age of scan results
From: Jouni Malinen @ 2009-09-30 21:21 UTC (permalink / raw)
To: Holger Schurig; +Cc: John Linville, linux-wireless, Johannes Berg
In-Reply-To: <200909280914.48847.hs4233@mail.mn-solutions.de>
On Mon, Sep 28, 2009 at 09:14:48AM +0200, Holger Schurig wrote:
> Oh, we can still easily change that to an absolute time, if you
> prefer. It's not yet upstream, AFAIK.
I have had hard time trying to figure out which option I would really
prefer.. ;-) Since the patch is actually in wireless-testing.git now and
I do not have that strong opinion either way, it's fine to leave it in
as-is. If anyone gets interested enough in trying to figure out whether
scan results are from the time after the last scan (more exactly than
just guessing based on age), he/she can add that later and probably
using something like a sequence number for scan requests, etc.
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply
* Re: Problems with "cfg80211: fix SME connect" commit
From: Johannes Berg @ 2009-09-30 21:20 UTC (permalink / raw)
To: Hin-Tak Leung; +Cc: Albert Herranz, Holger Schurig, linville, linux-wireless
In-Reply-To: <3ace41890909301417j5966336dn197a45cf66c2cd1e@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1097 bytes --]
On Wed, 2009-09-30 at 22:17 +0100, Hin-Tak Leung wrote:
> On Sat, Sep 26, 2009 at 12:39 PM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
>
> > The extra deauth is because cfg80211 already starts the auth with the
> > BSS before wpa_supplicant set the BSSID, and then when setting the BSSID
> > it asks for deauth, but before we ever actually did anything... I think
> > we'll just have to live with that, since it's hard to fix in the layered
> > design we have now.
>
> Hmm, I looked at the AP log, and the deauth is there...
Yeah. I've thought of doing a fix in mac80211, but haven't gotten around
to it yet -- should be fairly easy tho.
> also I think
> due to recent changes, association takes longer now. Is there
> something that can be done in userland, for example?
You can use -Dnl80211 with wpa_supplicant, but other than that we may or
may not scan a few times more or less, which is somewhat unfortunate.
Though it shouldn't be taking longer due to these specific recent
changes, in fact this should make it faster, if anything, I think.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: Problems with "cfg80211: fix SME connect" commit
From: Hin-Tak Leung @ 2009-09-30 21:17 UTC (permalink / raw)
To: Johannes Berg; +Cc: Albert Herranz, Holger Schurig, linville, linux-wireless
In-Reply-To: <1253965154.5122.7.camel@johannes.local>
On Sat, Sep 26, 2009 at 12:39 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> The extra deauth is because cfg80211 already starts the auth with the
> BSS before wpa_supplicant set the BSSID, and then when setting the BSSID
> it asks for deauth, but before we ever actually did anything... I think
> we'll just have to live with that, since it's hard to fix in the layered
> design we have now.
Hmm, I looked at the AP log, and the deauth is there... also I think
due to recent changes, association takes longer now. Is there
something that can be done in userland, for example?
Hin-Tak
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox