-------- Original Message -------- Subject: [PATCH] powertop: wifi Date: Mon, 27 Jul 2009 07:29:40 -0700 From: Johannes Berg <[email protected]> To: Kok, Auke-jan H <[email protected]> CC: Arjan van de Ven <[email protected]>, "Guy, Wey-Yi W" <[email protected]>
The current wifi code in powertop is pretty much broken on current kernels due to various changes in how rfkill is wired up, sysfs changes, etc. On the other hand, the complexity really isn't required on current kernels. Power saving can be enabled via the regular wireless extensions ioctls, and there no longer is a need to touch rfkill to save power, just clearing IFF_UP for an interface is sufficient. This patch adds a new file, wifi-new.c, containing all the new logic for current kernels, which also doesn't depend on iwlwifi or such, it's completely generic now. I've kept the old file for backward compatibility, even though it won't be doing anything on current kernels. Here, 'current' might be the net-next-2.6 of now, or maybe even later versions. However, the wireless.c code has pretty restrictive assumptions anyway that make it somewhat unlikely to work properly on many platforms, like for instance assuming 'rfkill0' is always the right rfkill instance -- this is wrong on almost all laptops. Signed-off-by: Johannes Berg <[email protected]> --- Makefile | 2 powertop.c | 1 powertop.h | 1 wifi-new.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 1 deletion(-) --- powertop-1.11.orig/powertop.c 2009-07-27 14:16:20.000000000 +0200 +++ powertop-1.11/powertop.c 2009-07-27 16:21:41.000000000 +0200 @@ -1134,6 +1134,7 @@ int main(int argc, char **argv) suggest_hpet(); suggest_ac97_powersave(); suggest_wireless_powersave(); + suggest_wifi_new_powersave(); suggest_ondemand_governor(); suggest_noatime(); suggest_sata_alpm(); --- powertop-1.11.orig/powertop.h 2009-07-27 14:16:20.000000000 +0200 +++ powertop-1.11/powertop.h 2009-07-27 14:19:04.000000000 +0200 @@ -51,6 +51,7 @@ void suggest_nmi_watchdog(void); void suggest_hpet(void); void suggest_ac97_powersave(void); void suggest_wireless_powersave(void); +void suggest_wifi_new_powersave(void); void suggest_ondemand_governor(void); void suggest_noatime(void); void suggest_sata_alpm(void); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ powertop-1.11/wifi-new.c 2009-07-27 16:29:13.000000000 +0200 @@ -0,0 +1,203 @@ +/* + * Copyright 2007, Intel Corporation + * Copyright 2009 Johannes Berg <[email protected]> + * + * This file is part of PowerTOP + * + * This program file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + * + * 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 in a file named COPYING; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authors: + * Arjan van de Ven <[email protected]> + * Johannes Berg <[email protected]> + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <dirent.h> +#include <linux/types.h> +#include <linux/sockios.h> +#include <sys/ioctl.h> +/* satisfy weird wireless.h include dependencies */ +#include <sys/socket.h> +#include <linux/if.h> +#include <linux/wireless.h> + +#include "powertop.h" + +static int wext_sock = -1; +static char wireless_nic[IFNAMSIZ + 1] = {0}; +static bool ps_not_working = false; + +static bool check_wireless_unused(void) +{ + struct iwreq wrq; + char ssid[34] = {0}; /* wext sometimes NUL-terminates */ + + memset(&wrq, 0, sizeof(wrq)); + strncpy(wrq.ifr_name, wireless_nic, sizeof(wrq.ifr_name)); + + /* get mode -- PS only available in STA mode */ + if (ioctl(wext_sock, SIOCGIWMODE, &wrq) < 0) + return false; + if (wrq.u.mode != IW_MODE_INFRA) + return false; + + wrq.u.essid.pointer = ssid; + wrq.u.essid.length = sizeof(ssid); + if (ioctl(wext_sock, SIOCGIWESSID, &wrq) < 0) + return false; + + /* no SSID, so can't be connected */ + if (!wrq.u.essid.flags) + return true; + + if (ioctl(wext_sock, SIOCGIWAP, &wrq) < 0) + return false; + + /* no AP -- not connected */ + if (memcmp(wrq.u.ap_addr.sa_data, "\0\0\0\0\0\0", 6) == 0) + return true; + + return false; +} + +static void activate_down_suggestion(void) +{ + struct ifreq ifr; + int ret; + + strncpy(ifr.ifr_name, wireless_nic, sizeof(ifr.ifr_name)); + + /* get flags */ + ret = ioctl(wext_sock, SIOCGIFFLAGS, &ifr); + if (ret < 0) + return; + ifr.ifr_flags &= ~IFF_UP; + + ioctl(wext_sock, SIOCSIFFLAGS, &ifr); +} + +static int check_wireless_powersave(void) +{ + struct iwreq wrq; + + if (ps_not_working) + return false; + + memset(&wrq, 0, sizeof(wrq)); + strncpy(wrq.ifr_name, wireless_nic, sizeof(wrq.ifr_name)); + + /* get powersave -- if supported */ + if (ioctl(wext_sock, SIOCGIWPOWER, &wrq) < 0) + return false; + + return wrq.u.param.disabled; +} + +static void activate_wireless_suggestion(void) +{ + struct iwreq wrq; + + memset(&wrq, 0, sizeof(wrq)); + strncpy(wrq.ifr_name, wireless_nic, sizeof(wrq.ifr_name)); + + wrq.u.param.disabled = false; + wrq.u.param.flags = IW_POWER_ON | IW_POWER_TIMEOUT; + wrq.u.param.value = 500*1000; /* 500 ms */ + again: + /* set powersave -- if supported */ + if (ioctl(wext_sock, SIOCSIWPOWER, &wrq) == 0) + return; + + /* maybe timeout is not supported? */ + if (wrq.u.param.flags & IW_POWER_TIMEOUT) { + wrq.u.param.flags = IW_POWER_ON; + goto again; + } + + ps_not_working = true; +} + +static void find_wireless_nic(void) +{ + DIR *net; + struct dirent *ent; + struct ifreq ifr; + struct iwreq wrq; + int ret; + + memset(&ifr, 0, sizeof(struct ifreq)); + memset(&wrq, 0, sizeof(wrq)); + + net = opendir("/sys/class/net/"); + if (!net) + return; + + while ((ent = readdir(net))) { + strncpy(ifr.ifr_name, ent->d_name, sizeof(ifr.ifr_name)); + strncpy(wrq.ifr_name, ent->d_name, sizeof(wrq.ifr_name)); + + /* Check if the interface is up */ + ret = ioctl(wext_sock, SIOCGIFFLAGS, &ifr); + if (ret < 0) + continue; + if (!(ifr.ifr_flags & (IFF_UP | IFF_RUNNING))) + continue; + + /* and a wireless interface (that we handle) */ + ret = ioctl(wext_sock, SIOCGIWNAME, &wrq); + if (ret < 0) + continue; + + strcpy(wireless_nic, "wlan0"); + break; + } + + closedir(net); +} + +void suggest_wifi_new_powersave(void) +{ + char sug[1024]; + + if (wext_sock == -1) { + wext_sock = socket(AF_INET, SOCK_DGRAM, 0); + if (wext_sock < 0) + return; + } + + if (strlen(wireless_nic) == 0) + find_wireless_nic(); + + if (strlen(wireless_nic) == 0) + return; + + if (check_wireless_unused()) { + sprintf(sug, _("Suggestion: Disable the unused WIFI radio by setting the interface down:\n " + "ifconfig %s down\n"), wireless_nic); + add_suggestion(sug, 60, 'D', _(" D - disable wireless "), activate_down_suggestion); + } else if (check_wireless_powersave()) { + sprintf(sug, _("Suggestion: Enable wireless power saving mode by executing the following command:\n " + " iwconfig %s power timeout 500ms\n" + "This will sacrifice network performance slightly to save power."), wireless_nic); + add_suggestion(sug, 20, 'P', _(" P - Enable wireless power saving "), activate_wireless_suggestion); + } +} --- powertop-1.11.orig/Makefile 2009-07-27 14:18:43.000000000 +0200 +++ powertop-1.11/Makefile 2009-07-27 14:18:48.000000000 +0200 @@ -16,7 +16,7 @@ CC?=gcc # OBJS = powertop.o config.o process.o misctips.o bluetooth.o display.o suggestions.o wireless.o cpufreq.o \ - sata.o xrandr.o ethernet.o cpufreqstats.o usb.o urbnum.o intelcstates.o + sata.o xrandr.o ethernet.o cpufreqstats.o usb.o urbnum.o intelcstates.o wifi-new.o powertop: $(OBJS) Makefile powertop.h _______________________________________________ Power mailing list [email protected] http://www.bughost.org/mailman/listinfo/power
