summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1251_ps.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-14 10:37:28 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-14 10:37:28 -0700
commitd7e9660ad9d5e0845f52848bce31bcf5cdcdea6b (patch)
treec6c67d145771187b194d79d603742b31090a59d6 /drivers/net/wireless/wl12xx/wl1251_ps.c
parentb8cb48aae1b8c50b37dcb7710363aa69a7a0d9ca (diff)
parent13af7a6ea502fcdd4c0e3d7de6e332b102309491 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1623 commits) netxen: update copyright netxen: fix tx timeout recovery netxen: fix file firmware leak netxen: improve pci memory access netxen: change firmware write size tg3: Fix return ring size breakage netxen: build fix for INET=n cdc-phonet: autoconfigure Phonet address Phonet: back-end for autoconfigured addresses Phonet: fix netlink address dump error handling ipv6: Add IFA_F_DADFAILED flag net: Add DEVTYPE support for Ethernet based devices mv643xx_eth.c: remove unused txq_set_wrr() ucc_geth: Fix hangs after switching from full to half duplex ucc_geth: Rearrange some code to avoid forward declarations phy/marvell: Make non-aneg speed/duplex forcing work for 88E1111 PHYs drivers/net/phy: introduce missing kfree drivers/net/wan: introduce missing kfree net: force bridge module(s) to be GPL Subject: [PATCH] appletalk: Fix skb leak when ipddp interface is not loaded ... Fixed up trivial conflicts: - arch/x86/include/asm/socket.h converted to <asm-generic/socket.h> in the x86 tree. The generic header has the same new #define's, so that works out fine. - drivers/net/tun.c fix conflict between 89f56d1e9 ("tun: reuse struct sock fields") that switched over to using 'tun->socket.sk' instead of the redundantly available (and thus removed) 'tun->sk', and 2b980dbd ("lsm: Add hooks to the TUN driver") which added a new 'tun->sk' use. Noted in 'next' by Stephen Rothwell.
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1251_ps.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
new file mode 100644
index 00000000000..c53e28727ed
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -0,0 +1,161 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 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
+ *
+ */
+
+#include "wl1251_reg.h"
+#include "wl1251_ps.h"
+#include "wl1251_cmd.h"
+#include "wl1251_io.h"
+
+#define WL1251_WAKEUP_TIMEOUT 2000
+
+/* Routines to toggle sleep mode while in ELP */
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
+{
+ if (wl->elp || !wl->psm)
+ return;
+
+ wl1251_debug(DEBUG_PSM, "chip to elp");
+
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+
+ wl->elp = true;
+}
+
+int wl1251_ps_elp_wakeup(struct wl1251 *wl)
+{
+ unsigned long timeout;
+ u32 elp_reg;
+
+ if (!wl->elp)
+ return 0;
+
+ wl1251_debug(DEBUG_PSM, "waking up chip from elp");
+
+ timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
+
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+
+ /*
+ * FIXME: we should wait for irq from chip but, as a temporary
+ * solution to simplify locking, let's poll instead
+ */
+ while (!(elp_reg & ELPCTRL_WLAN_READY)) {
+ if (time_after(jiffies, timeout)) {
+ wl1251_error("elp wakeup timeout");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ }
+
+ wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
+ jiffies_to_msecs(jiffies) -
+ (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
+
+ wl->elp = false;
+
+ return 0;
+}
+
+static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
+
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
+ if (ret < 0)
+ return ret;
+
+ wl1251_ps_elp_sleep(wl);
+ } else {
+ wl1251_debug(DEBUG_PSM, "sleep auth cam");
+
+ /*
+ * When the target is in ELP, we can only
+ * access the ELP control register. Thus,
+ * we have to wake the target up before
+ * changing the power authorization.
+ */
+
+ wl1251_ps_elp_wakeup(wl);
+
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
+{
+ int ret;
+
+ switch (mode) {
+ case STATION_POWER_SAVE_MODE:
+ wl1251_debug(DEBUG_PSM, "entering psm");
+
+ ret = wl1251_acx_wake_up_conditions(wl,
+ WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_ps_set_elp(wl, true);
+ if (ret < 0)
+ return ret;
+
+ wl->psm = 1;
+ break;
+ case STATION_ACTIVE_MODE:
+ default:
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+ ret = wl1251_ps_set_elp(wl, false);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_acx_wake_up_conditions(wl,
+ WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ if (ret < 0)
+ return ret;
+
+ wl->psm = 0;
+ break;
+ }
+
+ return ret;
+}
+