cfg80211: implement iwpower
Just on/off and timeout, and with a hacky cfg80211 method until we figure out what we want, though this is probably sufficient as we want to use pm_qos for wifi everywhere. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
f21293549f
commit
bc92afd920
10 changed files with 151 additions and 135 deletions
|
@ -522,6 +522,27 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
bool enabled, int timeout)
|
||||
{
|
||||
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
|
||||
u32 power_index;
|
||||
|
||||
if (enabled)
|
||||
power_index = IWM_POWER_INDEX_DEFAULT;
|
||||
else
|
||||
power_index = IWM_POWER_INDEX_MIN;
|
||||
|
||||
if (power_index == iwm->conf.power_index)
|
||||
return 0;
|
||||
|
||||
iwm->conf.power_index = power_index;
|
||||
|
||||
return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
|
||||
CFG_POWER_INDEX, iwm->conf.power_index);
|
||||
}
|
||||
|
||||
static struct cfg80211_ops iwm_cfg80211_ops = {
|
||||
.change_virtual_intf = iwm_cfg80211_change_iface,
|
||||
.add_key = iwm_cfg80211_add_key,
|
||||
|
@ -534,6 +555,7 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
|
|||
.leave_ibss = iwm_cfg80211_leave_ibss,
|
||||
.set_tx_power = iwm_cfg80211_set_txpower,
|
||||
.get_tx_power = iwm_cfg80211_get_txpower,
|
||||
.set_power_mgmt = iwm_cfg80211_set_power_mgmt,
|
||||
};
|
||||
|
||||
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
|
||||
|
|
|
@ -238,49 +238,6 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iwm_wext_siwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq, char *extra)
|
||||
{
|
||||
struct iwm_priv *iwm = ndev_to_iwm(dev);
|
||||
u32 power_index;
|
||||
|
||||
if (wrq->disabled) {
|
||||
power_index = IWM_POWER_INDEX_MIN;
|
||||
goto set;
|
||||
} else
|
||||
power_index = IWM_POWER_INDEX_DEFAULT;
|
||||
|
||||
switch (wrq->flags & IW_POWER_MODE) {
|
||||
case IW_POWER_ON:
|
||||
case IW_POWER_MODE:
|
||||
case IW_POWER_ALL_R:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set:
|
||||
if (power_index == iwm->conf.power_index)
|
||||
return 0;
|
||||
|
||||
iwm->conf.power_index = power_index;
|
||||
|
||||
return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
|
||||
CFG_POWER_INDEX, iwm->conf.power_index);
|
||||
}
|
||||
|
||||
static int iwm_wext_giwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu, char *extra)
|
||||
{
|
||||
struct iwm_priv *iwm = ndev_to_iwm(dev);
|
||||
|
||||
wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
|
||||
{
|
||||
u8 *auth_type = &iwm->umac_profile->sec.auth_type;
|
||||
|
@ -458,8 +415,8 @@ static const iw_handler iwm_handlers[] =
|
|||
(iw_handler) NULL, /* SIOCGIWRETRY */
|
||||
(iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
|
||||
(iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
|
||||
(iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
|
||||
(iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
|
||||
(iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
|
||||
(iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
|
||||
(iw_handler) NULL, /* -- hole -- */
|
||||
(iw_handler) NULL, /* -- hole -- */
|
||||
(iw_handler) NULL, /* SIOCSIWGENIE */
|
||||
|
|
|
@ -1023,6 +1023,10 @@ struct cfg80211_ops {
|
|||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
|
||||
#endif
|
||||
|
||||
/* some temporary stuff to finish wext */
|
||||
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
|
||||
bool enabled, int timeout);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1262,6 +1266,8 @@ struct wireless_dev {
|
|||
u8 bssid[ETH_ALEN];
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
s8 default_key, default_mgmt_key;
|
||||
bool ps;
|
||||
int ps_timeout;
|
||||
} wext;
|
||||
#endif
|
||||
};
|
||||
|
@ -1606,6 +1612,13 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
|
|||
struct iw_request_info *info,
|
||||
union iwreq_data *data, char *keybuf);
|
||||
|
||||
int cfg80211_wext_siwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq, char *extra);
|
||||
int cfg80211_wext_giwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq, char *extra);
|
||||
|
||||
/*
|
||||
* callbacks for asynchronous cfg80211 methods, notification
|
||||
* functions and BSS handling helpers
|
||||
|
|
|
@ -14,22 +14,6 @@ config MAC80211
|
|||
comment "CFG80211 needs to be enabled for MAC80211"
|
||||
depends on CFG80211=n
|
||||
|
||||
config MAC80211_DEFAULT_PS
|
||||
bool "enable powersave by default"
|
||||
depends on MAC80211
|
||||
default y
|
||||
help
|
||||
This option enables powersave mode by default.
|
||||
|
||||
If this causes your applications to misbehave you should fix your
|
||||
applications instead -- they need to register their network
|
||||
latency requirement, see Documentation/power/pm_qos_interface.txt.
|
||||
|
||||
config MAC80211_DEFAULT_PS_VALUE
|
||||
int
|
||||
default 1 if MAC80211_DEFAULT_PS
|
||||
default 0
|
||||
|
||||
menu "Rate control algorithm selection"
|
||||
depends on MAC80211 != n
|
||||
|
||||
|
|
|
@ -1388,6 +1388,31 @@ int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
||||
bool enabled, int timeout)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (enabled == sdata->u.mgd.powersave &&
|
||||
timeout == conf->dynamic_ps_timeout)
|
||||
return 0;
|
||||
|
||||
sdata->u.mgd.powersave = enabled;
|
||||
conf->dynamic_ps_timeout = timeout;
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
|
@ -1431,4 +1456,5 @@ struct cfg80211_ops mac80211_config_ops = {
|
|||
.get_tx_power = ieee80211_get_tx_power,
|
||||
.rfkill_poll = ieee80211_rfkill_poll,
|
||||
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
||||
.set_power_mgmt = ieee80211_set_power_mgmt,
|
||||
};
|
||||
|
|
|
@ -2360,11 +2360,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
|||
ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
|
||||
|
||||
hw_flags = sdata->local->hw.flags;
|
||||
|
||||
if (hw_flags & IEEE80211_HW_SUPPORTS_PS) {
|
||||
ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE;
|
||||
sdata->local->hw.conf.dynamic_ps_timeout = 500;
|
||||
}
|
||||
}
|
||||
|
||||
/* configuration hooks */
|
||||
|
|
|
@ -255,72 +255,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_ioctl_siwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq,
|
||||
char *extra)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
int timeout = 0;
|
||||
bool ps;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return -EINVAL;
|
||||
|
||||
if (wrq->disabled) {
|
||||
ps = false;
|
||||
timeout = 0;
|
||||
goto set;
|
||||
}
|
||||
|
||||
switch (wrq->flags & IW_POWER_MODE) {
|
||||
case IW_POWER_ON: /* If not specified */
|
||||
case IW_POWER_MODE: /* If set all mask */
|
||||
case IW_POWER_ALL_R: /* If explicitely state all */
|
||||
ps = true;
|
||||
break;
|
||||
default: /* Otherwise we ignore */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
|
||||
return -EINVAL;
|
||||
|
||||
if (wrq->flags & IW_POWER_TIMEOUT)
|
||||
timeout = wrq->value / 1000;
|
||||
|
||||
set:
|
||||
if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout)
|
||||
return 0;
|
||||
|
||||
sdata->u.mgd.powersave = ps;
|
||||
conf->dynamic_ps_timeout = timeout;
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_ioctl_giwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu,
|
||||
char *extra)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
wrqu->power.disabled = !sdata->u.mgd.powersave;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
|
||||
static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
|
||||
{
|
||||
|
@ -436,8 +370,8 @@ static const iw_handler ieee80211_handler[] =
|
|||
(iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
|
||||
(iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
|
||||
(iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
|
||||
(iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
|
||||
(iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
|
||||
(iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
|
||||
(iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
|
||||
(iw_handler) NULL, /* -- hole -- */
|
||||
(iw_handler) NULL, /* -- hole -- */
|
||||
(iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
|
||||
|
|
|
@ -26,6 +26,22 @@ config CFG80211_REG_DEBUG
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config CFG80211_DEFAULT_PS
|
||||
bool "enable powersave by default"
|
||||
depends on CFG80211
|
||||
default y
|
||||
help
|
||||
This option enables powersave mode by default.
|
||||
|
||||
If this causes your applications to misbehave you should fix your
|
||||
applications instead -- they need to register their network
|
||||
latency requirement, see Documentation/power/pm_qos_interface.txt.
|
||||
|
||||
config CFG80211_DEFAULT_PS_VALUE
|
||||
int
|
||||
default 1 if CFG80211_DEFAULT_PS
|
||||
default 0
|
||||
|
||||
config CFG80211_DEBUGFS
|
||||
bool "cfg80211 DebugFS entries"
|
||||
depends on CFG80211 && DEBUG_FS
|
||||
|
|
|
@ -550,12 +550,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
|
|||
}
|
||||
wdev->netdev = dev;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
#ifdef CONFIG_WIRELESS_EXT
|
||||
wdev->wext.default_key = -1;
|
||||
wdev->wext.default_mgmt_key = -1;
|
||||
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
|
||||
wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE;
|
||||
wdev->wext.ps_timeout = 500;
|
||||
if (rdev->ops->set_power_mgmt)
|
||||
if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
|
||||
wdev->wext.ps,
|
||||
wdev->wext.ps_timeout)) {
|
||||
/* assume this means it's off */
|
||||
wdev->wext.ps = false;
|
||||
}
|
||||
#endif
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
break;
|
||||
case NETDEV_GOING_DOWN:
|
||||
if (!wdev->ssid_len)
|
||||
|
|
|
@ -987,3 +987,63 @@ int cfg80211_wext_giwauth(struct net_device *dev,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth);
|
||||
|
||||
int cfg80211_wext_siwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq, char *extra)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
bool ps = wdev->wext.ps;
|
||||
int timeout = wdev->wext.ps_timeout;
|
||||
int err;
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_STATION)
|
||||
return -EINVAL;
|
||||
|
||||
if (!rdev->ops->set_power_mgmt)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (wrq->disabled) {
|
||||
ps = false;
|
||||
} else {
|
||||
switch (wrq->flags & IW_POWER_MODE) {
|
||||
case IW_POWER_ON: /* If not specified */
|
||||
case IW_POWER_MODE: /* If set all mask */
|
||||
case IW_POWER_ALL_R: /* If explicitely state all */
|
||||
ps = true;
|
||||
break;
|
||||
default: /* Otherwise we ignore */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
|
||||
return -EINVAL;
|
||||
|
||||
if (wrq->flags & IW_POWER_TIMEOUT)
|
||||
timeout = wrq->value / 1000;
|
||||
}
|
||||
|
||||
err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
wdev->wext.ps = ps;
|
||||
wdev->wext.ps_timeout = timeout;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower);
|
||||
|
||||
int cfg80211_wext_giwpower(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_param *wrq, char *extra)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
|
||||
wrq->disabled = !wdev->wext.ps;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
|
||||
|
|
Loading…
Reference in a new issue