* RE: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
From: Dan Williams @ 2009-10-01 18:00 UTC (permalink / raw)
To: Bing Zhao
Cc: libertas-dev@lists.infradead.org, linux-wireless@vger.kernel.org,
Amitkumar Karwar
In-Reply-To: <477F20668A386D41ADCC57781B1F704306DDA6C1B6@SC-VEXCH1.marvell.com>
On Mon, 2009-09-28 at 15:42 -0700, Bing Zhao wrote:
> Hi Dan,
>
> > -----Original Message-----
> > From: Dan Williams [mailto:dcbw@redhat.com]
> > Sent: Sunday, September 20, 2009 7:58 AM
> > To: Bing Zhao
> > Cc: libertas-dev@lists.infradead.org; linux-wireless@vger.kernel.org; Amitkumar Karwar
> > Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
> >
> > On Tue, 2009-09-15 at 16:45 -0700, Bing Zhao wrote:
> > > From: Amitkumar Karwar <akarwar@marvell.com>
> > >
> > > Add timer based auto deep sleep feature in libertas driver which can be
> > > configured through debugfs interface. 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.
> >
> > So there's always:
> >
> > #define IW_POWER_SAVING 0x4000 /* Value is relative (how aggressive)*/
> >
> > iwconfig wlan0 power saving 10
> >
> > That seems quite a bit better than a new debugfs parameter, until we can
> > conver the driver over cfg80211 and do this properly. If the power
> > saving mode is higher than some number X, the chip gets put into deep
> > sleep mode, or it can be automatically placed in deep sleep mode by the
> > driver when there is no association like you have done with the timer
> > above. I think you should pick reasonable defaults, and perhaps if the
> > 'saving' value is larger, the timer value in the driver gets smaller.
> >
> > Does that sound like an OK approach? We really should be using debugfs
> > only for debugging stuff (obviously), and the real fix for this sort of
> > thing is to switch over to cfg80211 where we can actually extend the
> > configuration API instead of hacking it into debugfs/WEXT/etc.
> >
> > Dan
>
> Thanks for your suggestion.
>
> In latest kernel, IW_POWER_SAVING is not defined in include/linux/wireless.h.
> IW_POWER_PERIOD and IW_POWER_TIMEOUT are defined though.
You're right. wireless-tools apparently had it, but since WEXT is on
life-support, John removed most of the additions before WE-21 got
committed to the kernel. So it's not there.
> We are planning to remove debugfs for configurations and use the following commands instead.
> Please let us know if there is any concern.
>
> iwconfig wlan0 power period 0 -> enable deep sleep (enter deep sleep immediately)
> iwconfig wlan0 power period 5 -> enable auto deep sleep (enter deep sleep automatically after 5s idle time)
> iwconfig wlan0 power period -1 -> disable deep sleep / auto deep sleep
Sure, that seems fine to me.
dan
> By the way, there is a bug in iwconfig tool v29. It doesn’t take any values right after "period" or "timeout". The new version of Wireless Tools v30-pre8 (link below) fixed the bug:
>
> http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/wireless_tools.30.pre8.tar.gz
>
> Thanks,
>
> Bing
>
> >
> > > Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> > > Signed-off-by: Bing Zhao <bzhao@marvell.com>
> > > ---
> > > drivers/net/wireless/libertas/README | 28 +++++-
> > > drivers/net/wireless/libertas/cmd.c | 72 +++++++++++++-
> > > drivers/net/wireless/libertas/cmdresp.c | 12 +++
> > > drivers/net/wireless/libertas/debugfs.c | 160 +++++++++++++++++++++++++++++++
> > > 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 | 138 ++++++++++++++++++++++++++
> > > 15 files changed, 604 insertions(+), 19 deletions(-)
> > >
> > > diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
> > > index ab6a2d5..059ce8c 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,30 @@ 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.
> > >
> > > +deepsleep
> > > +
> > > + This command is used to configure the station in deep sleep mode/auto
> > > + deep sleep mode. Command expects two parameters:
> > > + 'state' 'idle time period'
> > > +
> > > + The timer is implemented to monitor the activities (command, event,
> > > + data, 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 deepsleep mode is entered
> > > + automatically.
> > > +
> > > + Note: this command is for SDIO interface only.
> > > +
> > > + Path: /sys/kernel/debug/libertas_wireless/ethX/
> > > +
> > > + Usage:
> > > + To read the current status of deep sleep do:
> > > + cat deepsleep
> > > + To enable deep sleep mode do:
> > > + echo '1 0' > deepsleep
> > > + To enable auto deep sleep mode with idle time period 5 seconds do:
> > > + echo '1 5000' > deepsleep
> > > + To disable deep sleep/auto deep sleep mode do:
> > > + echo '0 0' > deepsleep
> > > +
> > > ==============================================================================
> > > 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..624a438 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;
> > > @@ -173,6 +183,118 @@ out_unlock:
> > > return ret;
> > > }
> > >
> > > +static ssize_t lbs_deepsleep_read(struct file *file, char __user *userbuf,
> > > + size_t count, loff_t *ppos)
> > > +{
> > > + struct lbs_private *priv = file->private_data;
> > > + ssize_t pos = 0;
> > > + int ret;
> > > + unsigned long addr = get_zeroed_page(GFP_KERNEL);
> > > + char *buf = (char *)addr;
> > > +
> > > + if (!buf)
> > > + return -ENOMEM;
> > > +
> > > + if (!priv->enter_deep_sleep) {
> > > + lbs_pr_err("deep sleep feature is not implemented "
> > > + "for this interface driver\n");
> > > + ret = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + if (priv->is_auto_deep_sleep_enabled)
> > > + pos += snprintf(buf, len, "%d %d\n",
> > > + priv->is_auto_deep_sleep_enabled,
> > > + priv->auto_deep_sleep_timeout);
> > > + else if (priv->is_deep_sleep)
> > > + pos += snprintf(buf, len, "%d %d\n",
> > > + priv->is_deep_sleep,
> > > + priv->auto_deep_sleep_timeout);
> > > + else
> > > + pos += snprintf(buf, len, "%d %d\n",
> > > + priv->is_deep_sleep,
> > > + priv->auto_deep_sleep_timeout);
> > > +
> > > + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> > > +
> > > +out_ds:
> > > + free_page(addr);
> > > + return ret;
> > > +}
> > > +
> > > +static ssize_t lbs_deepsleep_write(struct file *file,
> > > + const char __user *userbuf,
> > > + size_t count, loff_t *ppos)
> > > +{
> > > + struct lbs_private *priv = file->private_data;
> > > + ssize_t res, buf_size;
> > > + int is_deep_sleep, auto_deep_sleep_timeout;
> > > + unsigned long addr = get_zeroed_page(GFP_KERNEL);
> > > + char *buf = (char *)addr;
> > > +
> > > + if (!buf)
> > > + return -ENOMEM;
> > > +
> > > + if (!priv->enter_deep_sleep) {
> > > + lbs_pr_err("deep sleep feature is not implemented "
> > > + "for this interface driver\n");
> > > + res = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + if (priv->connect_status == LBS_CONNECTED) {
> > > + lbs_pr_err("can't use deep sleep cmd in connected "
> > > + "state\n");
> > > + res = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + buf_size = min(count, len - 1);
> > > + if (copy_from_user(buf, userbuf, buf_size)) {
> > > + res = -EFAULT;
> > > + goto out_ds;
> > > + }
> > > +
> > > + res = sscanf(buf, "%d %d", &is_deep_sleep, &auto_deep_sleep_timeout);
> > > + if ((res != 2) || (!is_deep_sleep && auto_deep_sleep_timeout) ||
> > > + !((is_deep_sleep == 1) ||
> > > + (is_deep_sleep == 0))) {
> > > + lbs_pr_err("unknown option\n");
> > > + res = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + if (auto_deep_sleep_timeout) {
> > > + if (!priv->is_auto_deep_sleep_enabled) {
> > > + priv->is_activity_detected = 0;
> > > + priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
> > > + lbs_enter_auto_deep_sleep(priv);
> > > + } else {
> > > + priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
> > > + lbs_deb_debugfs("auto deep sleep: already enabled\n");
> > > + }
> > > + } else {
> > > + if (priv->is_auto_deep_sleep_enabled) {
> > > + lbs_exit_auto_deep_sleep(priv);
> > > + /* Try to exit deep sleep if auto deep sleep disabled */
> > > + res = lbs_set_deep_sleep(priv, 0);
> > > + if (res)
> > > + goto out_ds;
> > > + }
> > > + if ((is_deep_sleep == 0) || (is_deep_sleep == 1)) {
> > > + res = lbs_set_deep_sleep(priv, is_deep_sleep);
> > > + if (res)
> > > + goto out_ds;
> > > + }
> > > + }
> > > +
> > > + res = count;
> > > +
> > > +out_ds:
> > > + free_page(addr);
> > > + return res;
> > > +}
> > > +
> > > /*
> > > * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
> > > * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
> > > @@ -223,6 +345,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 +400,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 +572,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 +629,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 +670,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 +728,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 +769,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 +827,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;
> > > @@ -717,6 +875,8 @@ static const struct lbs_debugfs_files debugfs_files[] = {
> > > write_file_dummy), },
> > > { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
> > > lbs_sleepparams_write), },
> > > + { "deepsleep", 0644, FOPS(lbs_deepsleep_read,
> > > + lbs_deepsleep_write), },
> > > };
> > >
> > > static const struct lbs_debugfs_files debugfs_events_files[] = {
> > > 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..ef2b986 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) {
> > > @@ -712,6 +779,11 @@ static int lbs_set_power(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->fwcapinfo & FW_CAPINFO_PS)) {
> > > if (vwrq->disabled)
> > > return 0;
> > > @@ -792,6 +864,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 +967,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 +1081,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 +1145,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 +1176,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 +1422,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 +1611,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 +1829,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 +1937,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 +1985,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 +2109,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 +2242,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;
> > >
>
^ permalink raw reply
* Re: [PATCH 0/2] cfg80211: firmware and hardware version
From: John W. Linville @ 2009-10-01 17:07 UTC (permalink / raw)
To: Kalle Valo; +Cc: Luis R. Rodriguez, linux-wireless, netdev
In-Reply-To: <873a63qe6e.fsf@purkki.valot.fi>
On Thu, Oct 01, 2009 at 07:20:09PM +0300, Kalle Valo wrote:
> "John W. Linville" <linville@tuxdriver.com> writes:
>
> > On Thu, Oct 01, 2009 at 05:18:33PM +0300, Kalle Valo wrote:
> > Anyway, adding a couple of ioctl calls isn't a big deal.
>
> Sure, but we need to support this forever. If, say after two years, we
> decide that ethtool is not the way to go, it's very difficult to
> remove it. The less interfaces we have, the easier it is to maintain
> them.
Just to be clear, I was taling about adding ioctl calls to a
userland application (if you didn't want to use the ethtool utility).
The required ioctls are already defined for ethtool in the kernel.
> >> ethtool -r|--negotiate DEVNAME Restart N-WAY negotation
> >
> > Ethernet-specific...might could be overloaded for wireless to trigger
> > reassoc...?
>
> Please no, I don't want to see any reassociation or anything else
> 802.11 state related in ethtool, nl80211 was created for this. This is
> something I would object loudly :)
Well, it was just a thought... :-)
> > Anyway, between the link detection and making distro scripts work
> > plus enabling a familiar tool for basic driver info I think this is
> > a win. So much the better if some drivers move to ethtool for register
> > dumping, setting message verbosity, querying/changing eeprom values,
> > etc, etc...
>
> Sounds good enough. As I said in my earlier email, I'm not going argue
> about this for too long. You know this better than I do. So let's go
> forward with ethtool.
>
> Thanks for listening to my concerns.
Sure, np. And FWIW, I don't predict a huge problem if there are
valid extensions required for use by wireless drivers in the future.
But for now, I'd like to see us make use of some of the debugging
facilities available in the ethtool API -- hopefully the iwlwifi guys
are listening... ;-)
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: [PATCH 0/2] cfg80211: firmware and hardware version
From: John W. Linville @ 2009-10-01 16:56 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Kalle Valo, Luis R. Rodriguez, linux-wireless, netdev
In-Reply-To: <1254411199.2735.4.camel@achroite>
On Thu, Oct 01, 2009 at 04:33:19PM +0100, Ben Hutchings wrote:
> On Thu, 2009-10-01 at 11:18 -0400, John W. Linville wrote:
> [...]
> > > But here are the features which I doubt we will ever use:
> > >
> > > ethtool -s|--change DEVNAME Change generic options
> > > [ speed %%d ]
> > > [ duplex half|full ]
> > > [ port tp|aui|bnc|mii|fibre ]
> > > [ autoneg on|off ]
> > > [ advertise %%x ]
> > > [ phyad %%d ]
> > > [ xcvr internal|external ]
> > > [ wol p|u|m|b|a|g|s|d... ]
> > > [ sopass %%x:%%x:%%x:%%x:%%x:%%x ]
> > > [ msglvl %%d ]
> > > ethtool -a|--show-pause DEVNAME Show pause options
> > > ethtool -A|--pause DEVNAME Set pause options
> > > [ autoneg on|off ]
> > > [ rx on|off ]
> > > [ tx on|off ]
> >
> > I agree that the above are ethernet-specific.
> [...]
>
> Message level isn't and WoL arguably isn't. It's a shame that these
> original ethtool settings are still bundled together...
Oh, yes! Missed those in the noise...
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: [PATCH 0/2] cfg80211: firmware and hardware version
From: Kalle Valo @ 2009-10-01 16:20 UTC (permalink / raw)
To: John W. Linville; +Cc: Luis R. Rodriguez, linux-wireless, netdev
In-Reply-To: <20091001151820.GA2895@tuxdriver.com>
"John W. Linville" <linville@tuxdriver.com> writes:
> On Thu, Oct 01, 2009 at 05:18:33PM +0300, Kalle Valo wrote:
>>
>> I'm not worried about the implementation complexity, and as your
>> patches show it was easy. My concern is the overall design for
>> wireless devices. Instead of using nl80211 for everything, with some
>> features we would use nl80211/iw and with some ethtool. That's just
>> confusing and I don't like that. I would prefer that nl80211 provides
>> everything, it makes things so much easier.
>
> Well, if the hw/fw version numbers were the only thing then I'd
> probably say it's not a big deal. But having ethtool support is nice
> in that it makes a familiar tool work for us. Among other things,
> this probably helps with some distro scripts that don't work quite
> right without it. Plus, there is lots of debugging stuff that could
> be turned-on without having to write new tools.
Agreed, maybe expect the distro scripts part. To me that just sounds
as a bug in the scripts.
> I suppose I understand the 'one API' idea, but why duplicate
> functionality?
Just because the common functionality in this case isn't high enough.
I'm worried that we will use 10% of the functionality in nl80211 and
the rest 90% will be something we can't use and have to reimplement in
nl80211.
> Anyway, adding a couple of ioctl calls isn't a big deal.
Sure, but we need to support this forever. If, say after two years, we
decide that ethtool is not the way to go, it's very difficult to
remove it. The less interfaces we have, the easier it is to maintain
them.
> And don't forget, we are still network drivers too...
I hope ethtool isn't a strict requirement for a network driver, at
least I haven't heard about that.
>> One example is the hw version, ethtool only provides u32 to userspace
>> and moves the burden of translating hw id to the user. For us a string
>> is much better choise because when debuggin we need to often (or
>> always?) know the chip version.
>
> Look at the way most drivers set the version (using each byte as a
> field).
Yes, that's how it is also with wl1251. A number like '0x7030101' is
just not that user friendly.
> If you want prettier output, adding a parser to the userland ethtool
> is fairly trivial. It looks something like the patch below...
Oh wow, that's cool and a truly useful feature. One complaint less
from me :)
>> ethtool -c|--show-coalesce DEVNAME Show coalesce options
>> ethtool -C|--coalesce DEVNAME Set coalesce options
>> [adaptive-rx on|off]
>> [adaptive-tx on|off]
>> [rx-usecs N]
>> [rx-frames N]
>> [rx-usecs-irq N]
>> [rx-frames-irq N]
>> [tx-usecs N]
>> [tx-frames N]
>> [tx-usecs-irq N]
>> [tx-frames-irq N]
>> [stats-block-usecs N]
>> [pkt-rate-low N]
>> [rx-usecs-low N]
>> [rx-frames-low N]
>> [tx-usecs-low N]
>> [tx-frames-low N]
>> [pkt-rate-high N]
>> [rx-usecs-high N]
>> [rx-frames-high N]
>> [tx-usecs-high N]
>> [tx-frames-high N]
>> [sample-interval N]
>
> These _could_ be useful if wireless becomes more
> performance-oriented...
Maybe, or maybe not. We will only find out within the next few years.
And what will we do if the parameters are actually a bit different? Is
it ok to extend ethtool for supporting wireless or do we later on have
to add separate support to nl80211? The latter would suck big time.
>> ethtool -g|--show-ring DEVNAME Query RX/TX ring parameters
>> ethtool -G|--set-ring DEVNAME Set RX/TX ring parameters
>> [ rx N ]
>> [ rx-mini N ]
>> [ rx-jumbo N ]
>> [ tx N ]
>
> Wireless devices have ring buffers, no?
Yes, there is hardware which have them but again the question is this
relevant for wireless devices. In ethernet the hardware is the
bottleneck but in 802.11 the wireless medium is the bottleneck, so the
parameters we need to configure are usually different.
>> ethtool -r|--negotiate DEVNAME Restart N-WAY negotation
>
> Ethernet-specific...might could be overloaded for wireless to trigger
> reassoc...?
Please no, I don't want to see any reassociation or anything else
802.11 state related in ethtool, nl80211 was created for this. This is
something I would object loudly :)
> Anyway, it doesn't really matter if we don't use the whole API -- many
> older ethernet devices don't support all these features. The point
> is that the API exists and has some overlap with our needs. It is a
> driver-oriented API, with nitty-gritty stuff that need not clutter a
> configuraiton API like cfg80211. There is even the potential of us
> adding our own extensions (e.g. WoW) that are also device-oriented.
>
> Anyway, between the link detection and making distro scripts work
> plus enabling a familiar tool for basic driver info I think this is
> a win. So much the better if some drivers move to ethtool for register
> dumping, setting message verbosity, querying/changing eeprom values,
> etc, etc...
Sounds good enough. As I said in my earlier email, I'm not going argue
about this for too long. You know this better than I do. So let's go
forward with ethtool.
Thanks for listening to my concerns.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH 0/2] cfg80211: firmware and hardware version
From: Ben Hutchings @ 2009-10-01 15:33 UTC (permalink / raw)
To: John W. Linville; +Cc: Kalle Valo, Luis R. Rodriguez, linux-wireless, netdev
In-Reply-To: <20091001151820.GA2895@tuxdriver.com>
On Thu, 2009-10-01 at 11:18 -0400, John W. Linville wrote:
[...]
> > But here are the features which I doubt we will ever use:
> >
> > ethtool -s|--change DEVNAME Change generic options
> > [ speed %%d ]
> > [ duplex half|full ]
> > [ port tp|aui|bnc|mii|fibre ]
> > [ autoneg on|off ]
> > [ advertise %%x ]
> > [ phyad %%d ]
> > [ xcvr internal|external ]
> > [ wol p|u|m|b|a|g|s|d... ]
> > [ sopass %%x:%%x:%%x:%%x:%%x:%%x ]
> > [ msglvl %%d ]
> > ethtool -a|--show-pause DEVNAME Show pause options
> > ethtool -A|--pause DEVNAME Set pause options
> > [ autoneg on|off ]
> > [ rx on|off ]
> > [ tx on|off ]
>
> I agree that the above are ethernet-specific.
[...]
Message level isn't and WoL arguably isn't. It's a shame that these
original ethtool settings are still bundled together...
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 0/2] cfg80211: firmware and hardware version
From: John W. Linville @ 2009-10-01 15:18 UTC (permalink / raw)
To: Kalle Valo; +Cc: Luis R. Rodriguez, linux-wireless, netdev
In-Reply-To: <87fxa3qjt2.fsf@purkki.valot.fi>
On Thu, Oct 01, 2009 at 05:18:33PM +0300, Kalle Valo wrote:
> "John W. Linville" <linville@tuxdriver.com> writes:
>
> > On Fri, Sep 25, 2009 at 09:53:35AM -0700, Luis R. Rodriguez wrote:
> >
> >> 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.
>
> I'm not worried about the implementation complexity, and as your
> patches show it was easy. My concern is the overall design for
> wireless devices. Instead of using nl80211 for everything, with some
> features we would use nl80211/iw and with some ethtool. That's just
> confusing and I don't like that. I would prefer that nl80211 provides
> everything, it makes things so much easier.
Well, if the hw/fw version numbers were the only thing then I'd
probably say it's not a big deal. But having ethtool support is nice
in that it makes a familiar tool work for us. Among other things,
this probably helps with some distro scripts that don't work quite
right without it. Plus, there is lots of debugging stuff that could
be turned-on without having to write new tools.
I suppose I understand the 'one API' idea, but why duplicate
functionality? Anyway, adding a couple of ioctl calls isn't a
big deal. And don't forget, we are still network drivers too...
> > 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... :-)
>
> I don't have a problem with the name :) But ethernet is still so much
> different from 802.11 that there isn't that much to share and we in
> wireless will need different features.
>
> One example is the hw version, ethtool only provides u32 to userspace
> and moves the burden of translating hw id to the user. For us a string
> is much better choise because when debuggin we need to often (or
> always?) know the chip version.
Look at the way most drivers set the version (using each byte as a
field). If you want prettier output, adding a parser to the userland
ethtool is fairly trivial. It looks something like the patch below...
> But this is not something I will start fighting about. If you still
> think that ethtool is the way to go, I'm perfectly fine with it.
>
> >> 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 took a look at ethtool help output from debian unstable and I think
> this is the set of features we can use in wireless:
>
> ethtool -i|--driver DEVNAME Show driver information
> ethtool -d|--register-dump DEVNAME Do a register dump
> [ raw on|off ]
> [ file FILENAME ]
> ethtool -e|--eeprom-dump DEVNAME Do a EEPROM dump
> [ raw on|off ]
> [ offset N ]
> [ length N ]
> ethtool -E|--change-eeprom DEVNAME Change bytes in device
> EEPROM
> [ magic N ]
> [ offset N ]
> [ value N ]
> ethtool -p|--identify DEVNAME Show visible port
> identification (e.g. blinking)
> [ TIME-IN-SECONDS ]
> ethtool -t|--test DEVNAME Execute adapter self test
> [ online | offline ]
I agree with the above.
> But here are the features which I doubt we will ever use:
>
> ethtool -s|--change DEVNAME Change generic options
> [ speed %%d ]
> [ duplex half|full ]
> [ port tp|aui|bnc|mii|fibre ]
> [ autoneg on|off ]
> [ advertise %%x ]
> [ phyad %%d ]
> [ xcvr internal|external ]
> [ wol p|u|m|b|a|g|s|d... ]
> [ sopass %%x:%%x:%%x:%%x:%%x:%%x ]
> [ msglvl %%d ]
> ethtool -a|--show-pause DEVNAME Show pause options
> ethtool -A|--pause DEVNAME Set pause options
> [ autoneg on|off ]
> [ rx on|off ]
> [ tx on|off ]
I agree that the above are ethernet-specific.
> ethtool -c|--show-coalesce DEVNAME Show coalesce options
> ethtool -C|--coalesce DEVNAME Set coalesce options
> [adaptive-rx on|off]
> [adaptive-tx on|off]
> [rx-usecs N]
> [rx-frames N]
> [rx-usecs-irq N]
> [rx-frames-irq N]
> [tx-usecs N]
> [tx-frames N]
> [tx-usecs-irq N]
> [tx-frames-irq N]
> [stats-block-usecs N]
> [pkt-rate-low N]
> [rx-usecs-low N]
> [rx-frames-low N]
> [tx-usecs-low N]
> [tx-frames-low N]
> [pkt-rate-high N]
> [rx-usecs-high N]
> [rx-frames-high N]
> [tx-usecs-high N]
> [tx-frames-high N]
> [sample-interval N]
These _could_ be useful if wireless becomes more
performance-oriented...
> ethtool -g|--show-ring DEVNAME Query RX/TX ring parameters
> ethtool -G|--set-ring DEVNAME Set RX/TX ring parameters
> [ rx N ]
> [ rx-mini N ]
> [ rx-jumbo N ]
> [ tx N ]
Wireless devices have ring buffers, no?
> ethtool -k|--show-offload DEVNAME Get protocol offload
> information
> ethtool -K|--offload DEVNAME Set protocol offload
> [ rx on|off ]
> [ tx on|off ]
> [ sg on|off ]
> [ tso on|off ]
> [ ufo on|off ]
> [ gso on|off ]
> [ gro on|off ]
> [ lro on|off ]
Again, if wireless devices become performance-oriented...
> ethtool -r|--negotiate DEVNAME Restart N-WAY negotation
Ethernet-specific...might could be overloaded for wireless to trigger
reassoc...?
> ethtool -n|--show-nfc DEVNAME Show Rx network flow
> classificationoptions
> [ rx-flow-hash
> tcp4|udp4|ah4|sctp4|tcp6|udp6|ah6|sctp6 ]
> ethtool -N|--config-nfc DEVNAME Configure Rx network flow
> classification options
> [ rx-flow-hash tcp4|udp4|ah4|sctp4|tcp6|udp6|ah6|sctp6
> m|v|t|s|d|f|n|r... ]
Long-shot, but no reason it couldn't be used in wireless... :-)
Anyway, it doesn't really matter if we don't use the whole API -- many
older ethernet devices don't support all these features. The point
is that the API exists and has some overlap with our needs. It is a
driver-oriented API, with nitty-gritty stuff that need not clutter a
configuraiton API like cfg80211. There is even the potential of us
adding our own extensions (e.g. WoW) that are also device-oriented.
Anyway, between the link detection and making distro scripts work
plus enabling a familiar tool for basic driver info I think this is
a win. So much the better if some drivers move to ethtool for register
dumping, setting message verbosity, querying/changing eeprom values,
etc, etc...
John
P.S. The aforementioned path for userland ethtool...(theorhetical,
not even compiled...)
>From aa92d32ac1cca57bdd3439013b0c7777bdf1217c Mon Sep 17 00:00:00 2001
From: John W. Linville <linville@tuxdriver.com>
Date: Thu, 1 Oct 2009 11:01:32 -0400
Subject: [PATCH] add support for at76c50x-usb driver.
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
Makefile.am | 2 +-
at76c50x-usb.c | 32 ++++++++++++++++++++++++++++++++
ethtool.c | 1 +
3 files changed, 34 insertions(+), 1 deletions(-)
create mode 100644 at76c50x-usb.c
diff --git a/Makefile.am b/Makefile.am
index eac65fe..a384949 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@ ethtool_SOURCES = ethtool.c ethtool-copy.h ethtool-util.h \
amd8111e.c de2104x.c e100.c e1000.c igb.c \
fec_8xx.c ibm_emac.c ixgb.c ixgbe.c natsemi.c \
pcnet32.c realtek.c tg3.c marvell.c vioc.c \
- smsc911x.c
+ smsc911x.c at76c50x-usb.c
dist-hook:
cp $(top_srcdir)/ethtool.spec $(distdir)
diff --git a/at76c50x-usb.c b/at76c50x-usb.c
new file mode 100644
index 0000000..295d1cb
--- /dev/null
+++ b/at76c50x-usb.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include "ethtool-util.h"
+
+static char hw_versions[] = {
+ "503_ISL3861",
+ "503_ISL3863",
+ " 503",
+ " 503_ACC",
+ " 505",
+ " 505_2958",
+ " 505A",
+ " 505AMX",
+};
+
+int
+at76c50x_usb_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+ u8 version = (u8)(regs->version >> 24);
+ u8 rev_id = (u8)(regs->version);
+ char *ver_string;
+
+ if(version != 0)
+ return -1;
+
+ ver_string = hw_versions[rev_id];
+ fprintf(stdout,
+ "Hardware Version %s\n",
+ ver_string);
+
+ return 0;
+}
+
diff --git a/ethtool.c b/ethtool.c
index 0110682..7608750 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1189,6 +1189,7 @@ static struct {
{ "sky2", sky2_dump_regs },
{ "vioc", vioc_dump_regs },
{ "smsc911x", smsc911x_dump_regs },
+ { "at76c50x-usb", at76c50x_usb_dump_regs },
};
static int dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
--
1.6.2.5
--
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: [PATCH] ar9170usb: LEDs are confused
From: Christian Lamparter @ 2009-10-01 14:54 UTC (permalink / raw)
To: Malte Gell; +Cc: linux-wireless, Luis R. Rodriguez, linville
On 2009-10-01 06:32 AM, Malte Gell wrote:
>I first noticed the LEDs are confused,
no, the LED colors is not _confused_ at all.
This is simply different on.... well, you know: on a per-device base!
For example: The Netgear uses a single bi-color LED for their WNDA3100 stick.
It glows blue or/and orange depending on the selected band and current
operation mode and state...
No idea why they didn't stick to the usual red/green mix.
Maybe because someone told the hw-devs about the existence of
red/green colorblind people??!
The original vendor driver (located: drivers/staging/otus/80211core/ledmgr.c)
goes to great lengths to describe what's behind the variety of
blinking signals. Which is nice, if you like expensive light shows...
>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.
FYI: you can assign the LEDs under "/sys/class/leds/" with a different tigger
without messing with the kernel source... An up-to-date README can be found in
the kernel's documentation directory: Documentation/leds-class.txt ,
or you can look it up online as well:
http://www.mjmwired.net/kernel/Documentation/leds-class.txt (from 2.6.31)
but back to the patch and the problem with the wide diversity of
over-customized solutions for a direct feedback mechanism to the
mindful human operator...
what about the (inline) _attached_ approach?
Sure, this idea needs some more code... but, it covers all/most
possible scenarios from beloved "no, no, no" vendors.
---
From: Christian Lamparter <chunkeey@googlemail.com>
Subject: [PATCH] ar9170usb: flexible LED mapping
This patch adds two more quirk flags which are useful to:
- reduce the number of virtual/ghost LEDs
( for low-budget devices: Netgear WN111 v2 )
- select an alternative LED mapping.
( for AVM FRITZ!WLAN USB Stick N )
Reported-by: Malte Gell <malte.gell@gmx.de>
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index ec034af..a451bb1 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -155,6 +155,12 @@ struct ar9170_sta_tid {
#define AR9170_NUM_TX_STATUS 128
#define AR9170_NUM_TX_AGG_MAX 30
+enum ar9170_quirks {
+ AR9170_REQ_FW1_ONLY = BIT(0),
+ AR9170_ONLY_ONE_LED = BIT(1),
+ AR9170_SWAPPED_LEDS = BIT(2),
+};
+
struct ar9170 {
struct ieee80211_hw *hw;
struct ath_common common;
@@ -241,6 +247,9 @@ struct ar9170 {
/* (cached) HW A-MPDU settings */
u8 global_ampdu_density;
u8 global_ampdu_factor;
+
+ /* device quirks */
+ unsigned long quirks;
};
struct ar9170_sta_info {
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 86c4e79..36ab738 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -155,18 +155,30 @@ void ar9170_unregister_leds(struct ar9170 *ar)
cancel_delayed_work_sync(&ar->led_work);
}
+const static int std_led_map[AR9170_NUM_LEDS] = { 0, 1 };
+const static int avm_led_map[AR9170_NUM_LEDS] = { 1, 0 };
+
int ar9170_register_leds(struct ar9170 *ar)
{
+ const int *led_map;
int err;
+ if (ar->quirks & AR9170_SWAPPED_LEDS)
+ led_map = avm_led_map;
+ else
+ led_map = std_led_map;
+
INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds);
- err = ar9170_register_led(ar, 0, "tx",
+ err = ar9170_register_led(ar, led_map[0], "tx",
ieee80211_get_tx_led_name(ar->hw));
if (err)
goto fail;
- err = ar9170_register_led(ar, 1, "assoc",
+ if (ar->quirks & AR9170_ONLY_ONE_LED)
+ return 0;
+
+ err = ar9170_register_led(ar, led_map[1], "assoc",
ieee80211_get_assoc_led_name(ar->hw));
if (err)
goto fail;
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index e974e58..3be19e4 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -55,10 +55,6 @@ MODULE_FIRMWARE("ar9170.fw");
MODULE_FIRMWARE("ar9170-1.fw");
MODULE_FIRMWARE("ar9170-2.fw");
-enum ar9170_requirements {
- AR9170_REQ_FW1_ONLY = 1,
-};
-
static struct usb_device_id ar9170_usb_ids[] = {
/* Atheros 9170 */
{ USB_DEVICE(0x0cf3, 0x9170) },
@@ -73,7 +69,7 @@ static struct usb_device_id ar9170_usb_ids[] = {
/* Netgear WNDA3100 */
{ USB_DEVICE(0x0846, 0x9010) },
/* Netgear WN111 v2 */
- { USB_DEVICE(0x0846, 0x9001) },
+ { USB_DEVICE(0x0846, 0x9001), .driver_info = AR9170_ONLY_ONE_LED },
/* Zydas ZD1221 */
{ USB_DEVICE(0x0ace, 0x1221) },
/* ZyXEL NWD271N */
@@ -89,7 +85,7 @@ static struct usb_device_id ar9170_usb_ids[] = {
/* IO-Data WNGDNUS2 */
{ USB_DEVICE(0x04bb, 0x093f) },
/* AVM FRITZ!WLAN USB Stick N */
- { USB_DEVICE(0x057C, 0x8401) },
+ { USB_DEVICE(0x057C, 0x8401), .driver_info = AR9170_SWAPPED_LEDS },
/* AVM FRITZ!WLAN USB Stick N 2.4 */
{ USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
@@ -589,7 +585,7 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
return 0;
}
- if (aru->req_one_stage_fw) {
+ if (aru->common.quirks & AR9170_REQ_FW1_ONLY) {
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
"not found and is required for this device\n");
return -EINVAL;
@@ -753,15 +749,6 @@ err_out:
return err;
}
-static bool ar9170_requires_one_stage(const struct usb_device_id *id)
-{
- if (!id->driver_info)
- return false;
- if (id->driver_info == AR9170_REQ_FW1_ONLY)
- return true;
- return false;
-}
-
static int ar9170_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -781,8 +768,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->udev = udev;
aru->intf = intf;
ar = &aru->common;
-
- aru->req_one_stage_fw = ar9170_requires_one_stage(id);
+ ar->quirks = id->driver_info;
usb_set_intfdata(intf, aru);
SET_IEEE80211_DEV(ar->hw, &intf->dev);
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index d098f4d..714436d 100644
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -64,8 +64,6 @@ struct ar9170_usb {
struct usb_anchor tx_pending;
struct usb_anchor tx_submitted;
- bool req_one_stage_fw;
-
spinlock_t tx_urb_lock;
unsigned int tx_submitted_urbs;
unsigned int tx_pending_urbs;
^ permalink raw reply related
* Re: VLAN traffic appearing on the wrong iface
From: Blaž Bačnik @ 2009-10-01 14:40 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <57b62e7d0910010732m38ab57k916662f9047fcc91@mail.gmail.com>
Meh, I messed up the patch. Take two, hopefully better. Sorry.
Regards, Blaz
--- a/net/mac80211/sta_info.c 2009-10-01 16:24:34.000000000 +0200
+++ b/net/mac80211/sta_info.c 2009-10-01 16:27:31.000000000 +0200
@@ -498,7 +498,7 @@ static void __sta_info_unlink(struct sta
&(*sta)->sta);
}
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ if (ieee80211_vif_is_mesh(&(*sta)->sdata->vif)) {
mesh_accept_plinks_update(sdata);
#ifdef CONFIG_MAC80211_MESH
del_timer(&(*sta)->plink_timer);
On Thu, Oct 1, 2009 at 4:32 PM, Blaž Bačnik <bacnik@gmail.com> wrote:
> On Wed, Sep 30, 2009 at 10:16 PM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
>> I can't reproduce that oops, but we have a fix to the issue which I'll
>> send separately.
>
> Thanks for patches. However, I've investigated that oops and I don't really
> understand it. Problem seems to be in __sta_info_unlink where code checks
> if vif is a mesh. Since this is a vlan iface, sdata used actually belongs to ap
> iface due to previous if but that really shouldn't be a problem since ap's
> sdata should have vif->type as well, right?
>
> While testing I've found out that sdata_of_ap->vif points to funny addresses
> like 248 and such. So I've changed the code and that seems to have fixed
> oops. I think this is now the right behaviour, anyway.
>
> --- a/net/mac80211/sta_info.c 2009-10-01 16:27:31.000000000 +0200
> +++ b/net/mac80211/sta_info.c 2009-10-01 16:24:34.000000000 +0200
> @@ -498,7 +498,7 @@ static void __sta_info_unlink(struct sta
> &(*sta)->sta);
> }
>
> - if (ieee80211_vif_is_mesh(&(*sta)->sdata->vif)) {
> + if (ieee80211_vif_is_mesh(&sdata->vif)) {
> mesh_accept_plinks_update(sdata);
> #ifdef CONFIG_MAC80211_MESH
> del_timer(&(*sta)->plink_timer);
>
^ permalink raw reply
* Re: VLAN traffic appearing on the wrong iface
From: Blaž Bačnik @ 2009-10-01 14:32 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1254341787.3959.11.camel@johannes.local>
On Wed, Sep 30, 2009 at 10:16 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> I can't reproduce that oops, but we have a fix to the issue which I'll
> send separately.
Thanks for patches. However, I've investigated that oops and I don't really
understand it. Problem seems to be in __sta_info_unlink where code checks
if vif is a mesh. Since this is a vlan iface, sdata used actually belongs to ap
iface due to previous if but that really shouldn't be a problem since ap's
sdata should have vif->type as well, right?
While testing I've found out that sdata_of_ap->vif points to funny addresses
like 248 and such. So I've changed the code and that seems to have fixed
oops. I think this is now the right behaviour, anyway.
--- a/net/mac80211/sta_info.c 2009-10-01 16:27:31.000000000 +0200
+++ b/net/mac80211/sta_info.c 2009-10-01 16:24:34.000000000 +0200
@@ -498,7 +498,7 @@ static void __sta_info_unlink(struct sta
&(*sta)->sta);
}
- if (ieee80211_vif_is_mesh(&(*sta)->sdata->vif)) {
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
mesh_accept_plinks_update(sdata);
#ifdef CONFIG_MAC80211_MESH
del_timer(&(*sta)->plink_timer);
^ permalink raw reply
* Re: [PATCH 3/3] at76c50x-usb: set firmware and hardware version in wiphy
From: Kalle Valo @ 2009-10-01 14:27 UTC (permalink / raw)
To: Ben Hutchings; +Cc: John W. Linville, linux-wireless, netdev, Luis R. Rodriguez
In-Reply-To: <1254360747.23350.2.camel@localhost>
Ben Hutchings <bhutchings@solarflare.com> writes:
> 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).
Yes, the extra null termination is unnecessary. This was my mistake in
the first patchset I sent.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH] net: fix NOHZ: local_softirq_pending 08
From: Kalle Valo @ 2009-10-01 14:24 UTC (permalink / raw)
To: Michael Buesch
Cc: David Miller, oliver, johannes, linville, linux-wireless, netdev
In-Reply-To: <200910011604.42916.mb@bu3sch.de>
Michael Buesch <mb@bu3sch.de> writes:
> On Thursday 01 October 2009 01:33:33 David Miller wrote:
>
>> I'm not applying this until all of these details are sorted out
>
> John, please apply my fix to wireless-testing to get rid of the
> regression. You can revert it later, if there's a better fix
> available.
I agree, please take Michael's patch. It's trivial to change mac80211
part whenever there's better support available.
But I don't think this is a regression because I see the bug also with
2.6.28, most probably it has been in mac80211 forever. But it's still
a bug which needs to be fixed.
--
Kalle Valo
^ permalink raw reply
* Re: BUG: "wext: refactor" broke compilation
From: Johannes Berg @ 2009-10-01 14:23 UTC (permalink / raw)
To: Holger Schurig; +Cc: linux-wireless
In-Reply-To: <200910011139.30914.hs4233@mail.mn-solutions.de>
[-- Attachment #1: Type: text/plain, Size: 1211 bytes --]
On Thu, 2009-10-01 at 11:39 +0200, Holger Schurig wrote:
> LD net/wireless/built-in.o
> CC [M] net/wireless/core.o
> net/wireless/core.c: In function 'cfg80211_netdev_notifier_call':
> net/wireless/core.c:673: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:674: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:675: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:676: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:677: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:680: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:681: error: 'struct wireless_dev' has no member named 'wext'
> net/wireless/core.c:683: error: 'struct wireless_dev' has no member named 'wext'
>
> The reason is that currently two different Kconfig
> defines are used:
>
>
> in net/wireless/core.c:
>
> #ifdef CONFIG_WIRELESS_EXT
> wdev->wext.default_key = -1;
> ...
> #endif
Oops, yes, that one needs to be fixed. I thought I just used sed but I
guess somehow I managed to miss this one.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 0/2] cfg80211: firmware and hardware version
From: Kalle Valo @ 2009-10-01 14:18 UTC (permalink / raw)
To: John W. Linville; +Cc: Luis R. Rodriguez, linux-wireless, netdev
In-Reply-To: <20091001011340.GA3123@tuxdriver.com>
"John W. Linville" <linville@tuxdriver.com> writes:
> On Fri, Sep 25, 2009 at 09:53:35AM -0700, Luis R. Rodriguez wrote:
>
>> 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.
I'm not worried about the implementation complexity, and as your
patches show it was easy. My concern is the overall design for
wireless devices. Instead of using nl80211 for everything, with some
features we would use nl80211/iw and with some ethtool. That's just
confusing and I don't like that. I would prefer that nl80211 provides
everything, it makes things so much easier.
> 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... :-)
I don't have a problem with the name :) But ethernet is still so much
different from 802.11 that there isn't that much to share and we in
wireless will need different features.
One example is the hw version, ethtool only provides u32 to userspace
and moves the burden of translating hw id to the user. For us a string
is much better choise because when debuggin we need to often (or
always?) know the chip version.
But this is not something I will start fighting about. If you still
think that ethtool is the way to go, I'm perfectly fine with it.
>> 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 took a look at ethtool help output from debian unstable and I think
this is the set of features we can use in wireless:
ethtool -i|--driver DEVNAME Show driver information
ethtool -d|--register-dump DEVNAME Do a register dump
[ raw on|off ]
[ file FILENAME ]
ethtool -e|--eeprom-dump DEVNAME Do a EEPROM dump
[ raw on|off ]
[ offset N ]
[ length N ]
ethtool -E|--change-eeprom DEVNAME Change bytes in device
EEPROM
[ magic N ]
[ offset N ]
[ value N ]
ethtool -p|--identify DEVNAME Show visible port
identification (e.g. blinking)
[ TIME-IN-SECONDS ]
ethtool -t|--test DEVNAME Execute adapter self test
[ online | offline ]
But here are the features which I doubt we will ever use:
ethtool -s|--change DEVNAME Change generic options
[ speed %%d ]
[ duplex half|full ]
[ port tp|aui|bnc|mii|fibre ]
[ autoneg on|off ]
[ advertise %%x ]
[ phyad %%d ]
[ xcvr internal|external ]
[ wol p|u|m|b|a|g|s|d... ]
[ sopass %%x:%%x:%%x:%%x:%%x:%%x ]
[ msglvl %%d ]
ethtool -a|--show-pause DEVNAME Show pause options
ethtool -A|--pause DEVNAME Set pause options
[ autoneg on|off ]
[ rx on|off ]
[ tx on|off ]
ethtool -c|--show-coalesce DEVNAME Show coalesce options
ethtool -C|--coalesce DEVNAME Set coalesce options
[adaptive-rx on|off]
[adaptive-tx on|off]
[rx-usecs N]
[rx-frames N]
[rx-usecs-irq N]
[rx-frames-irq N]
[tx-usecs N]
[tx-frames N]
[tx-usecs-irq N]
[tx-frames-irq N]
[stats-block-usecs N]
[pkt-rate-low N]
[rx-usecs-low N]
[rx-frames-low N]
[tx-usecs-low N]
[tx-frames-low N]
[pkt-rate-high N]
[rx-usecs-high N]
[rx-frames-high N]
[tx-usecs-high N]
[tx-frames-high N]
[sample-interval N]
ethtool -g|--show-ring DEVNAME Query RX/TX ring parameters
ethtool -G|--set-ring DEVNAME Set RX/TX ring parameters
[ rx N ]
[ rx-mini N ]
[ rx-jumbo N ]
[ tx N ]
ethtool -k|--show-offload DEVNAME Get protocol offload
information
ethtool -K|--offload DEVNAME Set protocol offload
[ rx on|off ]
[ tx on|off ]
[ sg on|off ]
[ tso on|off ]
[ ufo on|off ]
[ gso on|off ]
[ gro on|off ]
[ lro on|off ]
ethtool -r|--negotiate DEVNAME Restart N-WAY negotation
ethtool -n|--show-nfc DEVNAME Show Rx network flow
classificationoptions
[ rx-flow-hash
tcp4|udp4|ah4|sctp4|tcp6|udp6|ah6|sctp6 ]
ethtool -N|--config-nfc DEVNAME Configure Rx network flow
classification options
[ rx-flow-hash tcp4|udp4|ah4|sctp4|tcp6|udp6|ah6|sctp6
m|v|t|s|d|f|n|r... ]
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH] net: fix NOHZ: local_softirq_pending 08
From: Michael Buesch @ 2009-10-01 14:04 UTC (permalink / raw)
To: David Miller
Cc: oliver, johannes, kalle.valo, linville, linux-wireless, netdev
In-Reply-To: <20090930.163333.234658158.davem@davemloft.net>
On Thursday 01 October 2009 01:33:33 David Miller wrote:
> I'm not applying this until all of these details are sorted out
John, please apply my fix to wireless-testing to get rid of the regression.
You can revert it later, if there's a better fix available.
--
Greetings, Michael.
^ permalink raw reply
* [PATCH] b43: Don't use struct wldev after detach.
From: Michael Buesch @ 2009-10-01 13:54 UTC (permalink / raw)
To: linville; +Cc: bcm43xx-dev, linux-wireless
Don't use struct wldev after detach. This fixes an oops on access.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
---
drivers/net/wireless/b43/leds.c | 4 ++--
drivers/net/wireless/b43/leds.h | 4 ++--
drivers/net/wireless/b43/main.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/b43/leds.c
+++ wireless-testing/drivers/net/wireless/b43/leds.c
@@ -348,9 +348,9 @@ void b43_leds_register(struct b43_wldev
}
}
-void b43_leds_unregister(struct b43_wldev *dev)
+void b43_leds_unregister(struct b43_wl *wl)
{
- struct b43_leds *leds = &dev->wl->leds;
+ struct b43_leds *leds = &wl->leds;
b43_unregister_led(&leds->led_tx);
b43_unregister_led(&leds->led_rx);
--- wireless-testing.orig/drivers/net/wireless/b43/leds.h
+++ wireless-testing/drivers/net/wireless/b43/leds.h
@@ -60,7 +60,7 @@ enum b43_led_behaviour {
};
void b43_leds_register(struct b43_wldev *dev);
-void b43_leds_unregister(struct b43_wldev *dev);
+void b43_leds_unregister(struct b43_wl *wl);
void b43_leds_init(struct b43_wldev *dev);
void b43_leds_exit(struct b43_wldev *dev);
void b43_leds_stop(struct b43_wldev *dev);
@@ -76,7 +76,7 @@ struct b43_leds {
static inline void b43_leds_register(struct b43_wldev *dev)
{
}
-static inline void b43_leds_unregister(struct b43_wldev *dev)
+static inline void b43_leds_unregister(struct b43_wl *wl)
{
}
static inline void b43_leds_init(struct b43_wldev *dev)
--- wireless-testing.orig/drivers/net/wireless/b43/main.c
+++ wireless-testing/drivers/net/wireless/b43/main.c
@@ -4997,7 +4997,7 @@ static void b43_remove(struct ssb_device
if (list_empty(&wl->devlist)) {
b43_rng_exit(wl);
- b43_leds_unregister(wldev);
+ b43_leds_unregister(wl);
/* Last core on the chip unregistered.
* We can destroy common struct b43_wl.
*/
--
Greetings, Michael.
^ permalink raw reply
* Re: [PATCH]: nl80211: report age of scan results
From: Jouni Malinen @ 2009-10-01 12:40 UTC (permalink / raw)
To: Holger Schurig; +Cc: John Linville, linux-wireless, Johannes Berg
In-Reply-To: <200910010957.31558.hs4233@mail.mn-solutions.de>
On Thu, Oct 01, 2009 at 09:57:31AM +0200, Holger Schurig wrote:
> Hmm, what would a scan-sequence help in the case when mac80211 updates
> a BSS because of a received beacon?
I have been most interested in knowing whether the result was after the
scan request or not; not necessarily receiving during the scan request
itself.
> 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?
seq 6 based on the earlier discussion. However, there would be an option
to increment the sequence number whenever a scan is terminated, i.e.,
the move to normal operation would move to seq 7 and 'YYY' would
actually show up with seq 7 here. The scan trigger command would return
the sequence number for that particular scan (6 for the second one), so
it would be possible to notice the difference between ZZZ and YYY.
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply
* Re: Linux-2.6.32-rc1/2] wext refactor needs wpasupplicant 0.7.0+?
From: Sedat Dilek @ 2009-10-01 10:15 UTC (permalink / raw)
To: wireless; +Cc: Johannes Berg
In-Reply-To: <2d0a357f0910010247jfda1199h5a9b873233b186ca@mail.gmail.com>
For the sake of completeness:
Herre the WEXT config parameters in kernel dot-config:
# grep -i wext /boot/config-$(uname -r)
CONFIG_WEXT_CORE=y
CONFIG_WEXT_PROC=y
CONFIG_WEXT_SPY=y
CONFIG_WEXT_PRIV=y
CONFIG_CFG80211_WEXT=y
- Sedat -
On Thu, Oct 1, 2009 at 11:47 AM, Sedat Dilek <sedat.dilek@googlemail.com> wrote:
> Hi,
>
> a few hours ago I compiled a new kernel from upstream and put
> wireless-testing master-2009-09-30 on top of it.
>
> Last commit a1bec0ecfc76281d5e1ebd33435c67da7dd0fe71
> wext: refactor
>
> linux-2.6/master:
> 84d88d5: Merge branch 'sched-fixes-for-linus' of
> git://git./linux/kernel/git/tip/linux-2.6-tip
>
> After installation of the above described kernel, I could not connect
> to my AP using wext driver and wpasupplicant (0.6.9-3) from Debian/sid
> [1].
> With ath5k I could not establish a network connection neither via DHCP
> nor via static-IP to my AP (iwl3945 on a second machine works with
> self-debianized wpasupplicant 0.7.0+ and static-IP, same kernel).
>
> Just for clarification:
> Does wext refactor need a wpasupplicant >= 0.7.0 from hostap GIT repository [2]?
>
> Below you will find some needful informations of my configuration and system.
>
> Kind Regards,
> - Sedat -
>
> P.S.:
> I can offer a debianized wpasupplicant package for 32bit, if you like.
>
> [1] http://packages.debian.org/sid/wpasupplicant
> [2] http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=summary
>
> ---- NEEDFUL INFORMATIONS ----
>
> # lspci -nnvv | grep -i ath
> 02:02.0 Ethernet controller [0200]: Atheros Communications Inc. AR5212
> 802.11abg NIC [168c:1014] (rev 01)
> Kernel driver in use: ath5k
>
> # ps axu | grep -v grep | grep wpa
> root 1411 0.0 0.1 4916 1124 ? Ss 10:59 0:00
> /sbin/wpa_supplicant -B -P /var/run/wpa_supplicant.wlan0.pid -i wlan0
> -D wext -C /var/run/wpa_supplicant
>
> # wpa_cli -iwlan0 status
> bssid=00:04:0e:e4:00:3d
> ssid=$mySSID
> id=0
> pairwise_cipher=CCMP
> group_cipher=CCMP
> key_mgmt=WPA2-PSK
> wpa_state=COMPLETED
> ip_address=$myIPADDR
>
> # cat /proc/version
> Linux version 2.6.32-rc1-iniza-686-kms (Debian 2.6.32~rc1-5)
> (sedat.dilek@gmail.com) (gcc version 4.4.1 (Debian 4.4.1-4) ) #1 SMP
> PREEMPT Thu Oct 1 04:57:49 CEST 2009
>
^ permalink raw reply
* [PATCH] wl1251: remove wl1251_netlink.h
From: Kalle Valo @ 2009-10-01 9:51 UTC (permalink / raw)
To: linux-wireless
From: Kalle Valo <kalle.valo@nokia.com>
The file was accidentally added in commit ef2f8d4577 ("wl1251: add
wl1251 prefix to all 1251 files"). This happened when I rebased the
patches from a private tree.
Reported-by: Robert P. J. Day <rpjday@crashcourse.ca>
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
---
drivers/net/wireless/wl12xx/wl1251_netlink.h | 30 --------------------------
1 files changed, 0 insertions(+), 30 deletions(-)
delete mode 100644 drivers/net/wireless/wl12xx/wl1251_netlink.h
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
deleted file mode 100644
index ee36695..0000000
--- a/drivers/net/wireless/wl12xx/wl1251_netlink.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This file is part of wl1251
- *
- * Copyright (C) 2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __WL1251_NETLINK_H__
-#define __WL1251_NETLINK_H__
-
-int wl1251_nl_register(void);
-void wl1251_nl_unregister(void);
-
-#endif /* __WL1251_NETLINK_H__ */
^ permalink raw reply related
* Linux-2.6.32-rc1/2] wext refactor needs wpasupplicant 0.7.0+?
From: Sedat Dilek @ 2009-10-01 9:47 UTC (permalink / raw)
To: wireless; +Cc: Johannes Berg
Hi,
a few hours ago I compiled a new kernel from upstream and put
wireless-testing master-2009-09-30 on top of it.
Last commit a1bec0ecfc76281d5e1ebd33435c67da7dd0fe71
wext: refactor
linux-2.6/master:
84d88d5: Merge branch 'sched-fixes-for-linus' of
git://git./linux/kernel/git/tip/linux-2.6-tip
After installation of the above described kernel, I could not connect
to my AP using wext driver and wpasupplicant (0.6.9-3) from Debian/sid
[1].
With ath5k I could not establish a network connection neither via DHCP
nor via static-IP to my AP (iwl3945 on a second machine works with
self-debianized wpasupplicant 0.7.0+ and static-IP, same kernel).
Just for clarification:
Does wext refactor need a wpasupplicant >= 0.7.0 from hostap GIT repository [2]?
Below you will find some needful informations of my configuration and system.
Kind Regards,
- Sedat -
P.S.:
I can offer a debianized wpasupplicant package for 32bit, if you like.
[1] http://packages.debian.org/sid/wpasupplicant
[2] http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=summary
---- NEEDFUL INFORMATIONS ----
# lspci -nnvv | grep -i ath
02:02.0 Ethernet controller [0200]: Atheros Communications Inc. AR5212
802.11abg NIC [168c:1014] (rev 01)
Kernel driver in use: ath5k
# ps axu | grep -v grep | grep wpa
root 1411 0.0 0.1 4916 1124 ? Ss 10:59 0:00
/sbin/wpa_supplicant -B -P /var/run/wpa_supplicant.wlan0.pid -i wlan0
-D wext -C /var/run/wpa_supplicant
# wpa_cli -iwlan0 status
bssid=00:04:0e:e4:00:3d
ssid=$mySSID
id=0
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=$myIPADDR
# cat /proc/version
Linux version 2.6.32-rc1-iniza-686-kms (Debian 2.6.32~rc1-5)
(sedat.dilek@gmail.com) (gcc version 4.4.1 (Debian 4.4.1-4) ) #1 SMP
PREEMPT Thu Oct 1 04:57:49 CEST 2009
^ permalink raw reply
* BUG: "wext: refactor" broke compilation
From: Holger Schurig @ 2009-10-01 9:39 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
LD net/wireless/built-in.o
CC [M] net/wireless/core.o
net/wireless/core.c: In function 'cfg80211_netdev_notifier_call':
net/wireless/core.c:673: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:674: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:675: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:676: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:677: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:680: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:681: error: 'struct wireless_dev' has no member named 'wext'
net/wireless/core.c:683: error: 'struct wireless_dev' has no member named 'wext'
The reason is that currently two different Kconfig
defines are used:
in net/wireless/core.c:
#ifdef CONFIG_WIRELESS_EXT
wdev->wext.default_key = -1;
...
#endif
in include/net/cfg80211.h:
#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
...
} wext;
#endif
But I configure my kernel this way:
$ grep WIRELESS .config
CONFIG_WIRELESS=y
CONFIG_WIRELESS_EXT=y
...
$ grep WEXT .config
CONFIG_WEXT_CORE=y
CONFIG_WEXT_PROC=y
CONFIG_WEXT_SPY=y
CONFIG_WEXT_PRIV=y
# CONFIG_CFG80211_WEXT is not set
--
http://www.holgerschurig.de
^ permalink raw reply
* b43: fix wldev use after free
From: Dave Young @ 2009-10-01 8:49 UTC (permalink / raw)
To: mb, linville; +Cc: bcm43xx-dev, linux-wireless, linux-kernel
when rmmod b43, I got following bug message
[ 100.121798] BUG: unable to handle kernel paging request at 2f4066fa
[ 100.123338] IP: [<f9e9dd57>] b43_unregister_led+0x6/0x1c [b43]
[ 100.123338] *pde = 00000000
[ 100.123338] Oops: 0000 [#1] SMP
[ 100.123338] last sysfs file: /sys/devices/pci0000:00/0000:00:1c.1/0000:0c:00.0/ssb0:0/firmware/ssb0:0/loading
[ 100.123338] Modules linked in: reiserfs kvm_intel kvm snd_hda_codec_intelhdmi firewire_ohci snd_hda_codec_idt firewire_core b43(-) snd_hda_intel mac80211 snd_hda_codec crc_itu_t cfg80211 snd_hwdep ohci1394 snd_pcm dell_laptop wmi ieee1394 rfkill snd_timer snd_page_alloc
[ 100.123338]
[ 100.123338] Pid: 1931, comm: rmmod Not tainted (2.6.31-mm1 #2) Latitude E5400
[ 100.123338] EIP: 0060:[<f9e9dd57>] EFLAGS: 00010246 CPU: 0
[ 100.123338] EIP is at b43_unregister_led+0x6/0x1c [b43]
[ 100.123338] EAX: 2f4066fa EBX: 2f4066fa ECX: 00000006 EDX: 00000246
[ 100.123338] ESI: f6a59000 EDI: f72030a8 EBP: f6373ec8 ESP: f6373ec4
[ 100.123338] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[ 100.123338] Process rmmod (pid: 1931, ti=f6372000 task=f66e0000 task.ti=f6372000)
[ 100.123338] Stack:
[ 100.123338] 2f406576 f6373ed4 f9e9dd7f f674cda0 f6373ee8 f9e8816e f72030a8 f9ea4b18
[ 100.123338] <0> f9ea4b18 f6373ef4 c04bbd57 f7297000 f6373f04 c03f2563 f7297000 f7297034
[ 100.123338] <0> f6373f18 c03f2609 f9ea4b18 00000000 c07742fc f6373f2c c03f1aac 00000000
[ 100.123338] Call Trace:
[ 100.123338] [<f9e9dd7f>] ? b43_leds_unregister+0x12/0x36 [b43]
[ 100.123338] [<f9e8816e>] ? b43_remove+0x79/0x87 [b43]
[ 100.123338] [<c04bbd57>] ? ssb_device_remove+0x1d/0x29
[ 100.123338] [<c03f2563>] ? __device_release_driver+0x59/0x98
[ 100.123338] [<c03f2609>] ? driver_detach+0x67/0x85
[ 100.123338] [<c03f1aac>] ? bus_remove_driver+0x63/0x7f
[ 100.123338] [<c03f2a04>] ? driver_unregister+0x4d/0x54
[ 100.123338] [<c04bb828>] ? ssb_driver_unregister+0xb/0xd
[ 100.123338] [<f9e9f876>] ? b43_exit+0xd/0x19 [b43]
[ 100.123338] [<c025124b>] ? sys_delete_module+0x17c/0x1e0
[ 100.123338] [<c054c654>] ? do_page_fault+0x29d/0x2a5
[ 100.123338] [<c02032d6>] ? restore_all_notrace+0x0/0x18
[ 100.123338] [<c054c3b7>] ? do_page_fault+0x0/0x2a5
[ 100.123338] [<c020329d>] ? syscall_call+0x7/0xb
[ 100.123338] Code: 0f b6 93 d8 03 00 00 e8 16 ff ff ff 0f b6 8b 39 03 00 00 89 f0 0f b6 93 38 03 00 00 e8 01 ff ff ff 5b 5e 5d c3 55 89 e5 53 89 c3 <83> 38 00 74 0e 8d 40 04 e8 de cc 60 c6 c7 03 00 00 00 00 5b 5d
[ 100.123338] EIP: [<f9e9dd57>] b43_unregister_led+0x6/0x1c [b43] SS:ESP 0068:f6373ec4
[ 100.123338] CR2: 000000002f4066fa
[ 100.953375] ---[ end trace d100c06b1451fbd8 ]---
in b43_remove, b43_one_core_detach free the wldev,
thus following callback which reference wldev will oops.
fix it by call b43_leds_unregister before b43_one_core_detach
if it is the last one in wl->devlist
Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
---
drivers/net/wireless/b43/main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- linux-2.6.31.orig/drivers/net/wireless/b43/main.c 2009-10-01 16:17:00.000000000 +0800
+++ linux-2.6.31/drivers/net/wireless/b43/main.c 2009-10-01 16:37:41.000000000 +0800
@@ -4993,11 +4993,13 @@ static void b43_remove(struct ssb_device
ieee80211_unregister_hw(wl->hw);
}
+ if (list_is_last(&wldev->list, &wl->devlist))
+ b43_leds_unregister(wldev);
+
b43_one_core_detach(dev);
if (list_empty(&wl->devlist)) {
b43_rng_exit(wl);
- b43_leds_unregister(wldev);
/* Last core on the chip unregistered.
* We can destroy common struct b43_wl.
*/
^ permalink raw reply
* Re: [SOLVED][.32-rc1/2] ath5k: has become unreliable with .32-rc1
From: Johannes Berg @ 2009-10-01 8:52 UTC (permalink / raw)
To: Frans Pop; +Cc: linux-wireless, linux-kernel, Bob Copeland, Rafael J. Wysocki
In-Reply-To: <200910010235.28904.elendil@planet.nl>
[-- Attachment #1: Type: text/plain, Size: 291 bytes --]
On Thu, 2009-10-01 at 02:35 +0200, Frans Pop wrote:
> 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').
Nah, it's going to be the "add back wireless/ dir" patch.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] wireless: implement basic ethtool support for cfg80211 devices
From: Johannes Berg @ 2009-10-01 8:51 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>
[-- Attachment #1: Type: text/plain, Size: 609 bytes --]
On Wed, 2009-09-30 at 21:19 -0400, John W. Linville wrote:
> + if (!dev->ethtool_ops)
> + dev->ethtool_ops = &cfg80211_ethtool_ops;
> break;
I might go so far and do it unconditionally so we get consistent
functionality across things. OTOH, full-mac drivers might be able to
support more.
> +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)
if you change the order, you can make the latter static
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: driver_nl80211 broken again
From: Johannes Berg @ 2009-10-01 8:46 UTC (permalink / raw)
To: Jouni Malinen; +Cc: Maxim Levitsky, hostap@lists.shmoo.com, linux-wireless
In-Reply-To: <20090930221353.GB11052@jm.kir.nu>
[-- Attachment #1: Type: text/plain, Size: 1593 bytes --]
On Thu, 2009-10-01 at 01:13 +0300, Jouni Malinen wrote:
> > @@ -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.
cfg80211/mac80211 _do_ handle that. If you ask for disassociation, it
stays authenticated, and later expects you to still remember that and
refuses authentication since you're already authenticated.
> 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.
I still don't see how it makes sense to authenticate while still being
authenticated.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* 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
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