From 421eedff1180ffa8f1780932d0f2561d67a6b44f Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:21 +0530 Subject: rsi: add p2p support parameters to mac80211 This patch adds p2p supported parameters to mac80211 hw and wiphy structures during mac80211 registration. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 37 ++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index fa12c05d9e23..992ac6cf9a34 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -139,6 +139,32 @@ static const u32 rsi_max_ap_stas[16] = { 4, /* 14 - AP + BT Dual */ }; +static const struct ieee80211_iface_limit rsi_iface_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_combination rsi_iface_combinations[] = { + { + .num_different_channels = 1, + .max_interfaces = 3, + .limits = rsi_iface_limits, + .n_limits = ARRAY_SIZE(rsi_iface_limits), + }, +}; + /** * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. * @common: Pointer to the driver private structure. @@ -1581,7 +1607,11 @@ int rsi_mac80211_attach(struct rsi_common *common) ether_addr_copy(hw->wiphy->addr_mask, addr_mask); wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->retry_short = RETRY_SHORT; wiphy->retry_long = RETRY_LONG; @@ -1608,6 +1638,11 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + /* Wi-Fi direct parameters */ + hw->max_listen_interval = 10; + wiphy->iface_combinations = rsi_iface_combinations; + wiphy->n_iface_combinations = ARRAY_SIZE(rsi_iface_combinations); + status = ieee80211_register_hw(hw); if (status) return status; -- cgit v1.2.3-59-g8ed1b From b8bd3a439f3593a5d40e45ce14a17a086a0f6fe2 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:22 +0530 Subject: rsi: add/remove interface enhancements for p2p STA_OPMODE and AP_OPMODE macros are renamed to RSI_OPMODE_STA and RSI_OPMODE_AP. New opmodes are added to this list for P2P support. Mapping of mac80211 interface types to rsi interface types are added. Add and remove interface callbacks are handled for P2P mode. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 117 +++++++++++++++++----------- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 12 +-- drivers/net/wireless/rsi/rsi_main.h | 6 +- drivers/net/wireless/rsi/rsi_mgmt.h | 9 ++- 4 files changed, 89 insertions(+), 55 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 992ac6cf9a34..db69d87bd12e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -355,6 +355,24 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw) mutex_unlock(&common->mutex); } +static int rsi_map_intf_mode(enum nl80211_iftype vif_type) +{ + switch (vif_type) { + case NL80211_IFTYPE_STATION: + return RSI_OPMODE_STA; + case NL80211_IFTYPE_AP: + return RSI_OPMODE_AP; + case NL80211_IFTYPE_P2P_DEVICE: + return RSI_OPMODE_P2P_CLIENT; + case NL80211_IFTYPE_P2P_CLIENT: + return RSI_OPMODE_P2P_CLIENT; + case NL80211_IFTYPE_P2P_GO: + return RSI_OPMODE_P2P_GO; + default: + return RSI_OPMODE_UNSUPPORTED; + } +} + /** * rsi_mac80211_add_interface() - This function is called when a netdevice * attached to the hardware is enabled. @@ -368,54 +386,62 @@ static int rsi_mac80211_add_interface(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; enum opmode intf_mode; - int ret = -EOPNOTSUPP; + enum vap_status vap_status; + int vap_idx = -1, i; vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; mutex_lock(&common->mutex); - if (adapter->sc_nvifs > 1) { - mutex_unlock(&common->mutex); - return -EOPNOTSUPP; - } - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - rsi_dbg(INFO_ZONE, "Station Mode"); - intf_mode = STA_OPMODE; - break; - case NL80211_IFTYPE_AP: - rsi_dbg(INFO_ZONE, "AP Mode"); - intf_mode = AP_OPMODE; - break; - default: + intf_mode = rsi_map_intf_mode(vif->type); + if (intf_mode == RSI_OPMODE_UNSUPPORTED) { rsi_dbg(ERR_ZONE, "%s: Interface type %d not supported\n", __func__, vif->type); - goto out; + mutex_unlock(&common->mutex); + return -EOPNOTSUPP; + } + if ((vif->type == NL80211_IFTYPE_P2P_DEVICE) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT) || + (vif->type == NL80211_IFTYPE_P2P_GO)) + common->p2p_enabled = true; + + /* Get free vap index */ + for (i = 0; i < RSI_MAX_VIFS; i++) { + if (!adapter->vifs[i]) { + vap_idx = i; + break; + } + } + if (vap_idx < 0) { + rsi_dbg(ERR_ZONE, "Reject: Max VAPs reached\n"); + mutex_unlock(&common->mutex); + return -EOPNOTSUPP; } + vif_info->vap_id = vap_idx; + adapter->vifs[vap_idx] = vif; + adapter->sc_nvifs++; + vap_status = VAP_ADD; - adapter->vifs[adapter->sc_nvifs++] = vif; - ret = rsi_set_vap_capabilities(common, intf_mode, common->mac_addr, - 0, VAP_ADD); - if (ret) { + if (rsi_set_vap_capabilities(common, intf_mode, vif->addr, + vif_info->vap_id, vap_status)) { rsi_dbg(ERR_ZONE, "Failed to set VAP capabilities\n"); - goto out; + mutex_unlock(&common->mutex); + return -EINVAL; } - if (vif->type == NL80211_IFTYPE_AP) { - int i; - + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { rsi_send_rx_filter_frame(common, DISALLOW_BEACONS); common->min_rate = RSI_RATE_AUTO; for (i = 0; i < common->max_stations; i++) common->stations[i].sta = NULL; } -out: mutex_unlock(&common->mutex); - return ret; + return 0; } /** @@ -432,6 +458,7 @@ static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; enum opmode opmode; + int i; rsi_dbg(INFO_ZONE, "Remove Interface Called\n"); @@ -442,23 +469,22 @@ static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, return; } - switch (vif->type) { - case NL80211_IFTYPE_STATION: - opmode = STA_OPMODE; - break; - case NL80211_IFTYPE_AP: - opmode = AP_OPMODE; - break; - default: + opmode = rsi_map_intf_mode(vif->type); + if (opmode == RSI_OPMODE_UNSUPPORTED) { + rsi_dbg(ERR_ZONE, "Opmode error : %d\n", opmode); mutex_unlock(&common->mutex); return; } - rsi_set_vap_capabilities(common, opmode, vif->addr, - 0, VAP_DELETE); - adapter->sc_nvifs--; - - if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif))) - adapter->vifs[0] = NULL; + for (i = 0; i < RSI_MAX_VIFS; i++) { + if (!adapter->vifs[i]) + continue; + if (vif == adapter->vifs[i]) { + rsi_set_vap_capabilities(common, opmode, vif->addr, + i, VAP_DELETE); + adapter->sc_nvifs--; + adapter->vifs[i] = NULL; + } + } mutex_unlock(&common->mutex); } @@ -652,7 +678,7 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, rsi_send_rx_filter_frame(common, rx_filter_word); } rsi_inform_bss_status(common, - STA_OPMODE, + RSI_OPMODE_STA, bss_conf->assoc, bss_conf->bssid, bss_conf->qos, @@ -1285,8 +1311,9 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, /* Send peer notify to device */ rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); - rsi_inform_bss_status(common, AP_OPMODE, 1, sta->addr, - sta->wme, sta->aid, sta, sta_idx); + rsi_inform_bss_status(common, RSI_OPMODE_AP, 1, + sta->addr, sta->wme, sta->aid, + sta, sta_idx); if (common->key) { struct ieee80211_key_conf *key = common->key; @@ -1358,7 +1385,7 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, if (!rsta->sta) continue; if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { - rsi_inform_bss_status(common, AP_OPMODE, 0, + rsi_inform_bss_status(common, RSI_OPMODE_AP, 0, sta->addr, sta->wme, sta->aid, sta, sta_idx); rsta->sta = NULL; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index f7b550f900c4..082329d1b42b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -482,9 +482,9 @@ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, memset(skb->data, 0, frame_len); peer_notify = (struct rsi_peer_notify *)skb->data; - if (opmode == STA_OPMODE) + if (opmode == RSI_OPMODE_STA) peer_notify->command = cpu_to_le16(PEER_TYPE_AP << 1); - else if (opmode == AP_OPMODE) + else if (opmode == RSI_OPMODE_AP) peer_notify->command = cpu_to_le16(PEER_TYPE_STA << 1); switch (notify_event) { @@ -1321,7 +1321,7 @@ void rsi_inform_bss_status(struct rsi_common *common, u16 sta_id) { if (status) { - if (opmode == STA_OPMODE) + if (opmode == RSI_OPMODE_STA) common->hw_data_qs_blocked = true; rsi_hal_send_sta_notify_frame(common, opmode, @@ -1331,12 +1331,12 @@ void rsi_inform_bss_status(struct rsi_common *common, aid, sta_id); if (common->min_rate == 0xffff) rsi_send_auto_rate_request(common, sta, sta_id); - if (opmode == STA_OPMODE) { + if (opmode == RSI_OPMODE_STA) { if (!rsi_send_block_unblock_frame(common, false)) common->hw_data_qs_blocked = false; } } else { - if (opmode == STA_OPMODE) + if (opmode == RSI_OPMODE_STA) common->hw_data_qs_blocked = true; rsi_hal_send_sta_notify_frame(common, opmode, @@ -1344,7 +1344,7 @@ void rsi_inform_bss_status(struct rsi_common *common, addr, qos_enable, aid, sta_id); - if (opmode == STA_OPMODE) + if (opmode == RSI_OPMODE_STA) rsi_send_block_unblock_frame(common, true); } } diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 2c18dde633ea..a4837fab1d50 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -60,7 +60,7 @@ enum RSI_FSM_STATES { extern u32 rsi_zone_enabled; extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); -#define RSI_MAX_VIFS 1 +#define RSI_MAX_VIFS 3 #define NUM_EDCA_QUEUES 4 #define IEEE80211_ADDR_LEN 6 #define FRAME_DESC_SZ 16 @@ -157,6 +157,7 @@ struct vif_priv { bool is_ht; bool sgi; u16 seq_start; + int vap_id; }; struct rsi_event { @@ -270,6 +271,9 @@ struct rsi_common { int num_stations; int max_stations; struct ieee80211_key_conf *key; + + /* Wi-Fi direct mode related */ + bool p2p_enabled; }; enum host_intf { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index c6e1fa669a27..8bd7dfacf259 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -200,8 +200,11 @@ #define RSI_DATA_DESC_INSERT_SEQ_NO BIT(2) enum opmode { - AP_OPMODE = 0, - STA_OPMODE, + RSI_OPMODE_UNSUPPORTED = -1, + RSI_OPMODE_AP = 0, + RSI_OPMODE_STA, + RSI_OPMODE_P2P_GO, + RSI_OPMODE_P2P_CLIENT }; enum vap_status { @@ -363,9 +366,9 @@ struct rsi_vap_caps { u8 vif_type; u8 channel_bw; __le16 antenna_info; + __le16 token; u8 radioid_macid; u8 vap_id; - __le16 reserved3; u8 mac_addr[6]; __le16 keep_alive_period; u8 bssid[6]; -- cgit v1.2.3-59-g8ed1b From df771911914ab9f80dd38a2710e50c5a418200ba Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:23 +0530 Subject: rsi: add support for p2p listen Remain-on-channel and cancel-remain-on-channel are implemented to support p2p listen phase. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 15 +++ drivers/net/wireless/rsi/rsi_91x_mac80211.c | 188 +++++++++++++++++++++++++--- drivers/net/wireless/rsi/rsi_91x_main.c | 9 +- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 4 +- drivers/net/wireless/rsi/rsi_common.h | 4 +- drivers/net/wireless/rsi/rsi_main.h | 2 + drivers/net/wireless/rsi/rsi_mgmt.h | 2 +- 7 files changed, 199 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 2b0516d2f63d..d2121965265b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -334,6 +334,21 @@ struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr) return NULL; } +struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac) +{ + struct ieee80211_vif *vif; + int i; + + for (i = 0; i < RSI_MAX_VIFS; i++) { + vif = adapter->vifs[i]; + if (!vif) + continue; + if (!memcmp(vif->addr, mac, ETH_ALEN)) + return vif; + } + return NULL; +} + /** * rsi_core_xmit() - This function transmits the packets received from mac80211 * @common: Pointer to the driver private structure. diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index db69d87bd12e..6780c1cd8c62 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -503,35 +503,44 @@ static int rsi_channel_change(struct ieee80211_hw *hw) int status = -EOPNOTSUPP; struct ieee80211_channel *curchan = hw->conf.chandef.chan; u16 channel = curchan->hw_value; - struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; + struct ieee80211_vif *vif; + struct ieee80211_bss_conf *bss; + bool assoc = false; + int i; rsi_dbg(INFO_ZONE, "%s: Set channel: %d MHz type: %d channel_no %d\n", __func__, curchan->center_freq, curchan->flags, channel); - if (bss->assoc) { + for (i = 0; i < RSI_MAX_VIFS; i++) { + vif = adapter->vifs[i]; + if (!vif) + continue; + if (vif->type == NL80211_IFTYPE_STATION) { + bss = &vif->bss_conf; + if (bss->assoc) { + assoc = true; + break; + } + } + } + if (assoc) { if (!common->hw_data_qs_blocked && - (rsi_get_connected_channel(adapter) != channel)) { + (rsi_get_connected_channel(vif) != channel)) { rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); if (!rsi_send_block_unblock_frame(common, true)) common->hw_data_qs_blocked = true; } } - status = rsi_band_check(common); + status = rsi_band_check(common, curchan); if (!status) status = rsi_set_channel(adapter->priv, curchan); - if (bss->assoc) { + if (assoc) { if (common->hw_data_qs_blocked && - (rsi_get_connected_channel(adapter) == channel)) { - rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); - if (!rsi_send_block_unblock_frame(common, false)) - common->hw_data_qs_blocked = false; - } - } else { - if (common->hw_data_qs_blocked) { + (rsi_get_connected_channel(vif) == channel)) { rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); if (!rsi_send_block_unblock_frame(common, false)) common->hw_data_qs_blocked = false; @@ -632,16 +641,42 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, * * Return: Current connected AP's channel number is returned. */ -u16 rsi_get_connected_channel(struct rsi_hw *adapter) +u16 rsi_get_connected_channel(struct ieee80211_vif *vif) { - struct ieee80211_vif *vif = adapter->vifs[0]; - if (vif) { - struct ieee80211_bss_conf *bss = &vif->bss_conf; - struct ieee80211_channel *channel = bss->chandef.chan; - return channel->hw_value; - } + struct ieee80211_bss_conf *bss; + struct ieee80211_channel *channel; - return 0; + if (!vif) + return 0; + + bss = &vif->bss_conf; + channel = bss->chandef.chan; + + if (!channel) + return 0; + + return channel->hw_value; +} + +static void rsi_switch_channel(struct rsi_hw *adapter, + struct ieee80211_vif *vif) +{ + struct rsi_common *common = adapter->priv; + struct ieee80211_channel *channel; + + if (common->iface_down) + return; + if (!vif) + return; + + channel = vif->bss_conf.chandef.chan; + + if (!channel) + return; + + rsi_band_check(common, channel); + rsi_set_channel(common, channel); + rsi_dbg(INFO_ZONE, "Switched to channel - %d\n", channel->hw_value); } /** @@ -1561,6 +1596,114 @@ static void rsi_mac80211_rfkill_poll(struct ieee80211_hw *hw) mutex_unlock(&common->mutex); } +static void rsi_resume_conn_channel(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_vif *vif; + int cnt; + + for (cnt = 0; cnt < RSI_MAX_VIFS; cnt++) { + vif = adapter->vifs[cnt]; + if (!vif) + continue; + + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { + rsi_switch_channel(adapter, vif); + break; + } + if (((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && + vif->bss_conf.assoc) { + rsi_switch_channel(adapter, vif); + break; + } + } +} + +void rsi_roc_timeout(unsigned long data) +{ + struct rsi_common *common = (struct rsi_common *)data; + + rsi_dbg(INFO_ZONE, "Remain on channel expired\n"); + + mutex_lock(&common->mutex); + ieee80211_remain_on_channel_expired(common->priv->hw); + + if (timer_pending(&common->roc_timer)) + del_timer(&common->roc_timer); + + rsi_resume_conn_channel(common); + mutex_unlock(&common->mutex); +} + +static int rsi_mac80211_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type) +{ + struct rsi_hw *adapter = (struct rsi_hw *)hw->priv; + struct rsi_common *common = (struct rsi_common *)adapter->priv; + int status = 0; + + rsi_dbg(INFO_ZONE, "***** Remain on channel *****\n"); + + mutex_lock(&common->mutex); + rsi_dbg(INFO_ZONE, "%s: channel: %d duration: %dms\n", + __func__, chan->hw_value, duration); + + if (timer_pending(&common->roc_timer)) { + rsi_dbg(INFO_ZONE, "Stop on-going ROC\n"); + del_timer(&common->roc_timer); + } + common->roc_timer.expires = msecs_to_jiffies(duration) + jiffies; + add_timer(&common->roc_timer); + + /* Configure band */ + if (rsi_band_check(common, chan)) { + rsi_dbg(ERR_ZONE, "Failed to set band\n"); + status = -EINVAL; + goto out; + } + + /* Configure channel */ + if (rsi_set_channel(common, chan)) { + rsi_dbg(ERR_ZONE, "Failed to set the channel\n"); + status = -EINVAL; + goto out; + } + + common->roc_vif = vif; + ieee80211_ready_on_channel(hw); + rsi_dbg(INFO_ZONE, "%s: Ready on channel :%d\n", + __func__, chan->hw_value); + +out: + mutex_unlock(&common->mutex); + + return status; +} + +static int rsi_mac80211_cancel_roc(struct ieee80211_hw *hw) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + rsi_dbg(INFO_ZONE, "Cancel remain on channel\n"); + + mutex_lock(&common->mutex); + if (!timer_pending(&common->roc_timer)) { + mutex_unlock(&common->mutex); + return 0; + } + + del_timer(&common->roc_timer); + + rsi_resume_conn_channel(common); + mutex_unlock(&common->mutex); + + return 0; +} + static const struct ieee80211_ops mac80211_ops = { .tx = rsi_mac80211_tx, .start = rsi_mac80211_start, @@ -1580,6 +1723,8 @@ static const struct ieee80211_ops mac80211_ops = { .set_antenna = rsi_mac80211_set_antenna, .get_antenna = rsi_mac80211_get_antenna, .rfkill_poll = rsi_mac80211_rfkill_poll, + .remain_on_channel = rsi_mac80211_roc, + .cancel_remain_on_channel = rsi_mac80211_cancel_roc, }; /** @@ -1666,6 +1811,9 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); /* Wi-Fi direct parameters */ + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX; + wiphy->max_remain_on_channel_duration = 10000; hw->max_listen_interval = 10; wiphy->iface_combinations = rsi_iface_combinations; wiphy->n_iface_combinations = ARRAY_SIZE(rsi_iface_combinations); diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 3e1e80888d98..b57bfdcf3549 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -74,6 +74,8 @@ static struct sk_buff *rsi_prepare_skb(struct rsi_common *common, struct skb_info *rx_params; struct sk_buff *skb = NULL; u8 payload_offset; + struct ieee80211_vif *vif; + struct ieee80211_hdr *wh; if (WARN(!pkt_len, "%s: Dummy pkt received", __func__)) return NULL; @@ -92,11 +94,13 @@ static struct sk_buff *rsi_prepare_skb(struct rsi_common *common, payload_offset = (extended_desc + FRAME_DESC_SZ); skb_put(skb, pkt_len); memcpy((skb->data), (buffer + payload_offset), skb->len); + wh = (struct ieee80211_hdr *)skb->data; + vif = rsi_get_vif(common->priv, wh->addr1); info = IEEE80211_SKB_CB(skb); rx_params = (struct skb_info *)info->driver_data; rx_params->rssi = rsi_get_rssi(buffer); - rx_params->channel = rsi_get_connected_channel(common->priv); + rx_params->channel = rsi_get_connected_channel(vif); return skb; } @@ -233,6 +237,9 @@ struct rsi_hw *rsi_91x_init(void) rsi_default_ps_params(adapter); spin_lock_init(&adapter->ps_lock); + common->roc_timer.data = (unsigned long)common; + common->roc_timer.function = (void *)&rsi_roc_timeout; + init_timer(&common->roc_timer); common->init_done = true; return adapter; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 082329d1b42b..aaf5f32aca54 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -926,13 +926,13 @@ static int rsi_send_reset_mac(struct rsi_common *common) * * Return: 0 on success, corresponding error code on failure. */ -int rsi_band_check(struct rsi_common *common) +int rsi_band_check(struct rsi_common *common, + struct ieee80211_channel *curchan) { struct rsi_hw *adapter = common->priv; struct ieee80211_hw *hw = adapter->hw; u8 prev_bw = common->channel_width; u8 prev_ep = common->endpoint; - struct ieee80211_channel *curchan = hw->conf.chandef.chan; int status = 0; if (common->band != curchan->band) { diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index e579d694d13c..272e18d750ff 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -79,9 +79,11 @@ static inline int rsi_kill_thread(struct rsi_thread *handle) } void rsi_mac80211_detach(struct rsi_hw *hw); -u16 rsi_get_connected_channel(struct rsi_hw *adapter); +u16 rsi_get_connected_channel(struct ieee80211_vif *vif); struct rsi_hw *rsi_91x_init(void); void rsi_91x_deinit(struct rsi_hw *adapter); int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr); +struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac); +void rsi_roc_timeout(unsigned long data); #endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index a4837fab1d50..fd07b377d8c0 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -274,6 +274,8 @@ struct rsi_common { /* Wi-Fi direct mode related */ bool p2p_enabled; + struct timer_list roc_timer; + struct ieee80211_vif *roc_vif; }; enum host_intf { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 8bd7dfacf259..08e3b43b6a10 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -633,7 +633,7 @@ void rsi_core_qos_processor(struct rsi_common *common); void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb); int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb); int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb); -int rsi_band_check(struct rsi_common *common); +int rsi_band_check(struct rsi_common *common, struct ieee80211_channel *chan); int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word); int rsi_send_radio_params_update(struct rsi_common *common); int rsi_set_antenna(struct rsi_common *common, u8 antenna); -- cgit v1.2.3-59-g8ed1b From 4671c209ac461c8826c1241ba423e75f84ae486b Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:24 +0530 Subject: rsi: handle peer connection and disconnection in p2p mode Parameter 'vif' is passed to inform_bss_status function to check the type of vif and to get vap_id. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 9 ++++-- drivers/net/wireless/rsi/rsi_91x_hal.c | 47 +++++++++++++++++------------ drivers/net/wireless/rsi/rsi_91x_mac80211.c | 22 +++++++++----- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 15 +++++---- drivers/net/wireless/rsi/rsi_hal.h | 3 +- drivers/net/wireless/rsi/rsi_main.h | 2 ++ drivers/net/wireless/rsi/rsi_mgmt.h | 5 ++- 7 files changed, 64 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index d2121965265b..432d6ebd14a3 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -361,8 +361,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; struct skb_info *tx_params; - struct ieee80211_hdr *wh; - struct ieee80211_vif *vif = adapter->vifs[0]; + struct ieee80211_hdr *wh = NULL; + struct ieee80211_vif *vif; u8 q_num, tid = 0; struct rsi_sta *rsta = NULL; @@ -381,6 +381,11 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) wh = (struct ieee80211_hdr *)&skb->data[0]; tx_params->sta_id = 0; + vif = rsi_get_vif(adapter, wh->addr2); + if (!vif) + goto xmit_fail; + tx_params->vif = vif; + tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id; if ((ieee80211_is_mgmt(wh->frame_control)) || (ieee80211_is_ctl(wh->frame_control)) || (ieee80211_is_qos_nullfunc(wh->frame_control))) { diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 070dfd68bb83..d0b119e3c6df 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -42,7 +42,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) struct ieee80211_hdr *wh = NULL; struct ieee80211_tx_info *info; struct ieee80211_conf *conf = &adapter->hw->conf; - struct ieee80211_vif *vif = adapter->vifs[0]; + struct ieee80211_vif *vif; struct rsi_mgmt_desc *mgmt_desc; struct skb_info *tx_params; struct ieee80211_bss_conf *bss = NULL; @@ -57,6 +57,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; + vif = tx_params->vif; /* Update header size */ header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); @@ -78,7 +79,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) tx_params->internal_hdr_size = header_size; memset(&skb->data[0], 0, header_size); - bss = &info->control.vif->bss_conf; + bss = &vif->bss_conf; wh = (struct ieee80211_hdr *)&skb->data[header_size]; mgmt_desc = (struct rsi_mgmt_desc *)skb->data; @@ -95,10 +96,10 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) mgmt_desc->seq_ctrl = cpu_to_le16(IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl))); - if (common->band == NL80211_BAND_2GHZ) - mgmt_desc->rate_info = RSI_RATE_1; + if ((common->band == NL80211_BAND_2GHZ) && !common->p2p_enabled) + mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_1); else - mgmt_desc->rate_info = RSI_RATE_6; + mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_6); if (conf_is_ht40(conf)) mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); @@ -121,7 +122,8 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) xtend_desc->retry_cnt = PROBE_RESP_RETRY_CNT; } - if ((vif->type == NL80211_IFTYPE_AP) && + if (((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) && (ieee80211_is_action(wh->frame_control))) { struct rsi_sta *rsta = rsi_find_sta(common, wh->addr1); @@ -130,6 +132,10 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) else return -EINVAL; } + mgmt_desc->rate_info |= + cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) & + RSI_DESC_VAP_ID_MASK); + return 0; } @@ -306,21 +312,11 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct ieee80211_tx_info *info; struct skb_info *tx_params; int status = -E2BIG; - u8 extnd_size; info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; - extnd_size = ((uintptr_t)skb->data & 0x3); if (tx_params->flags & INTERNAL_MGMT_PKT) { - skb->data[1] |= BIT(7); /* Immediate Wakeup bit*/ - if ((extnd_size) > skb_headroom(skb)) { - rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); - dev_kfree_skb(skb); - return -ENOSPC; - } - skb_push(skb, extnd_size); - skb->data[extnd_size + 4] = extnd_size; status = adapter->host_intf_ops->write_pkt(common->priv, (u8 *)skb->data, skb->len); @@ -352,12 +348,23 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) struct rsi_data_desc *bcn_frm; struct ieee80211_hw *hw = common->priv->hw; struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_vif *vif; struct sk_buff *mac_bcn; - u8 vap_id = 0; - u16 tim_offset; - + u8 vap_id = 0, i; + u16 tim_offset = 0; + + for (i = 0; i < RSI_MAX_VIFS; i++) { + vif = adapter->vifs[i]; + if (!vif) + continue; + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) + break; + } + if (!vif) + return -EINVAL; mac_bcn = ieee80211_beacon_get_tim(adapter->hw, - adapter->vifs[adapter->sc_nvifs - 1], + vif, &tim_offset, NULL); if (!mac_bcn) { rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 6780c1cd8c62..ce2f911eace1 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -718,7 +718,7 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->qos, bss_conf->aid, - NULL, 0); + NULL, 0, vif); adapter->ps_info.dtim_interval_duration = bss->dtim_period; adapter->ps_info.listen_interval = conf->listen_interval; @@ -862,7 +862,8 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", __func__, key->cipher, key_type, key->keylen); - if (vif->type == NL80211_IFTYPE_AP) { + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { if (sta) { rsta = rsi_find_sta(adapter->priv, sta->addr); if (rsta) @@ -1297,7 +1298,8 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, mutex_lock(&common->mutex); - if (vif->type == NL80211_IFTYPE_AP) { + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { u8 cnt; int sta_idx = -1; int free_index = -1; @@ -1348,7 +1350,7 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); rsi_inform_bss_status(common, RSI_OPMODE_AP, 1, sta->addr, sta->wme, sta->aid, - sta, sta_idx); + sta, sta_idx, vif); if (common->key) { struct ieee80211_key_conf *key = common->key; @@ -1368,7 +1370,8 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, } } - if (vif->type == NL80211_IFTYPE_STATION) { + if ((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) { rsi_set_min_rate(hw, sta, common); if (sta->ht_cap.ht_supported) { common->vif_info[0].is_ht = true; @@ -1409,7 +1412,8 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, mutex_lock(&common->mutex); - if (vif->type == NL80211_IFTYPE_AP) { + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { u8 sta_idx, cnt; /* Send peer notify to device */ @@ -1422,7 +1426,8 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { rsi_inform_bss_status(common, RSI_OPMODE_AP, 0, sta->addr, sta->wme, - sta->aid, sta, sta_idx); + sta->aid, sta, sta_idx, + vif); rsta->sta = NULL; rsta->sta_id = -1; for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) @@ -1436,7 +1441,8 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, rsi_dbg(ERR_ZONE, "%s: No station found\n", __func__); } - if (vif->type == NL80211_IFTYPE_STATION) { + if ((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) { /* Resetting all the fields to default values */ memcpy((u8 *)bss->bssid, (u8 *)sta->addr, ETH_ALEN); bss->qos = sta->wme; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index aaf5f32aca54..428369bf02f0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -460,12 +460,12 @@ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, const unsigned char *bssid, u8 qos_enable, u16 aid, - u16 sta_id) + u16 sta_id, + struct ieee80211_vif *vif) { - struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb = NULL; struct rsi_peer_notify *peer_notify; - u16 vap_id = 0; + u16 vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id; int status; u16 frame_len = sizeof(struct rsi_peer_notify); @@ -1318,7 +1318,8 @@ void rsi_inform_bss_status(struct rsi_common *common, u8 qos_enable, u16 aid, struct ieee80211_sta *sta, - u16 sta_id) + u16 sta_id, + struct ieee80211_vif *vif) { if (status) { if (opmode == RSI_OPMODE_STA) @@ -1328,7 +1329,8 @@ void rsi_inform_bss_status(struct rsi_common *common, STA_CONNECTED, addr, qos_enable, - aid, sta_id); + aid, sta_id, + vif); if (common->min_rate == 0xffff) rsi_send_auto_rate_request(common, sta, sta_id); if (opmode == RSI_OPMODE_STA) { @@ -1343,7 +1345,8 @@ void rsi_inform_bss_status(struct rsi_common *common, STA_DISCONNECTED, addr, qos_enable, - aid, sta_id); + aid, sta_id, + vif); if (opmode == RSI_OPMODE_STA) rsi_send_block_unblock_frame(common, true); } diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index 7c145053da6d..ad0d6537a678 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -121,8 +121,7 @@ struct rsi_mgmt_desc { u8 xtend_desc_size; u8 header_len; __le16 frame_info; - u8 rate_info; - u8 reserved1; + __le16 rate_info; __le16 bbp_info; __le16 seq_ctrl; u8 reserved2; diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index fd07b377d8c0..34089ab111aa 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -124,6 +124,8 @@ struct skb_info { s8 tid; s8 sta_id; u8 internal_hdr_size; + struct ieee80211_vif *vif; + u8 vap_id; }; enum edca_queue { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 08e3b43b6a10..a82552cfb9d7 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -189,6 +189,8 @@ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) +#define RSI_DESC_VAP_ID_MASK 0xC000 +#define RSI_DESC_VAP_ID_OFST 14 #define RSI_DATA_DESC_MAC_BBP_INFO BIT(0) #define RSI_DATA_DESC_NO_ACK_IND BIT(9) #define RSI_DATA_DESC_QOS_EN BIT(12) @@ -623,7 +625,8 @@ int rsi_send_vap_dynamic_update(struct rsi_common *common); int rsi_send_block_unblock_frame(struct rsi_common *common, bool event); void rsi_inform_bss_status(struct rsi_common *common, enum opmode opmode, u8 status, const u8 *addr, u8 qos_enable, u16 aid, - struct ieee80211_sta *sta, u16 sta_id); + struct ieee80211_sta *sta, u16 sta_id, + struct ieee80211_vif *vif); void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb); int rsi_mac80211_attach(struct rsi_common *common); void rsi_indicate_tx_status(struct rsi_hw *common, struct sk_buff *skb, -- cgit v1.2.3-59-g8ed1b From eac4eed3224b1bc769489ae2e146105cbba3a8ad Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:25 +0530 Subject: rsi: tx and rx path enhancements for p2p mode Data descriptor is updated to include vap_id. TX command frame key config also updated to include vap_id. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 9 +++++++-- drivers/net/wireless/rsi/rsi_91x_hal.c | 26 ++++++++++++++++++-------- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 23 +++++++++++++++++++---- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 4 ++-- drivers/net/wireless/rsi/rsi_mgmt.h | 3 ++- 5 files changed, 48 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 432d6ebd14a3..bc18a191aef9 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -95,6 +95,8 @@ static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) s16 txop = common->tx_qinfo[q_num].txop * 32; __le16 r_txop; struct ieee80211_rate rate; + struct ieee80211_hdr *wh; + struct ieee80211_vif *vif; rate.bitrate = RSI_RATE_MCS0 * 5 * 10; /* Convert to Kbps */ if (q_num == VI_Q) @@ -106,8 +108,10 @@ static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) return 0; do { + wh = (struct ieee80211_hdr *)skb->data; + vif = rsi_get_vif(adapter, wh->addr2); r_txop = ieee80211_generic_frame_duration(adapter->hw, - adapter->vifs[0], + vif, common->band, skb->len, &rate); txop -= le16_to_cpu(r_txop); @@ -403,7 +407,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) q_num = skb->priority; tx_params->tid = tid; - if ((vif->type == NL80211_IFTYPE_AP) && + if (((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) && (!is_broadcast_ether_addr(wh->addr1)) && (!is_multicast_ether_addr(wh->addr1))) { rsta = rsi_find_sta(common, wh->addr1); diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index d0b119e3c6df..7e8e5d4f5f3d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -157,7 +157,8 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) u16 seq_num; info = IEEE80211_SKB_CB(skb); - bss = &info->control.vif->bss_conf; + vif = info->control.vif; + bss = &vif->bss_conf; tx_params = (struct skb_info *)info->driver_data; header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); @@ -181,7 +182,6 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ]; wh = (struct ieee80211_hdr *)&skb->data[header_size]; seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl)); - vif = adapter->vifs[0]; data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; @@ -190,7 +190,8 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) data_desc->mac_flags |= cpu_to_le16(RSI_QOS_ENABLE); } - if ((vif->type == NL80211_IFTYPE_STATION) && + if (((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && (adapter->ps_state == PS_ENABLED)) wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE); @@ -246,17 +247,23 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) data_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); data_desc->sta_id = vap_id; - if (vif->type == NL80211_IFTYPE_AP) { + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { if (common->band == NL80211_BAND_5GHZ) data_desc->rate_info = cpu_to_le16(RSI_RATE_6); else data_desc->rate_info = cpu_to_le16(RSI_RATE_1); } } - if ((vif->type == NL80211_IFTYPE_AP) && + if (((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) && (ieee80211_has_moredata(wh->frame_control))) data_desc->frame_info |= cpu_to_le16(MORE_DATA_PRESENT); + data_desc->rate_info |= + cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) & + RSI_DESC_VAP_ID_MASK); + return 0; } @@ -264,7 +271,7 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; - struct ieee80211_vif *vif = adapter->vifs[0]; + struct ieee80211_vif *vif; struct ieee80211_tx_info *info; struct ieee80211_bss_conf *bss; int status = -EINVAL; @@ -277,9 +284,12 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); if (!info->control.vif) goto err; - bss = &info->control.vif->bss_conf; + vif = info->control.vif; + bss = &vif->bss_conf; - if ((vif->type == NL80211_IFTYPE_STATION) && (!bss->assoc)) + if (((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && + (!bss->assoc)) goto err; status = rsi_prepare_data_desc(common, skb); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index ce2f911eace1..b1550bc243dd 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -879,7 +879,8 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, RSI_PAIRWISE_KEY, key->keyidx, key->cipher, - sta_id); + sta_id, + vif); if (status) return status; } @@ -891,7 +892,8 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, key_type, key->keyidx, key->cipher, - sta_id); + sta_id, + vif); } /** @@ -1165,7 +1167,9 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, struct rsi_common *common, struct ieee80211_rx_status *rxs) { - struct ieee80211_bss_conf *bss = &common->priv->vifs[0]->bss_conf; + struct rsi_hw *adapter = common->priv; + struct ieee80211_vif *vif; + struct ieee80211_bss_conf *bss = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct skb_info *rx_params = (struct skb_info *)info->driver_data; struct ieee80211_hdr *hdr; @@ -1173,6 +1177,7 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, u8 hdrlen = 0; u8 channel = rx_params->channel; s32 freq; + int i; hdr = ((struct ieee80211_hdr *)(skb->data)); hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -1201,6 +1206,15 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, rxs->flag |= RX_FLAG_IV_STRIPPED; } + for (i = 0; i < RSI_MAX_VIFS; i++) { + vif = adapter->vifs[i]; + if (!vif) + continue; + if (vif->type == NL80211_IFTYPE_STATION) + bss = &vif->bss_conf; + } + if (!bss) + return; /* CQM only for connected AP beacons, the RSSI is a weighted avg */ if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { if (ieee80211_is_beacon(hdr->frame_control)) @@ -1363,7 +1377,8 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, RSI_PAIRWISE_KEY, key->keyidx, key->cipher, - sta_idx); + sta_idx, + vif); } common->num_stations++; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 428369bf02f0..4e50cfdc2f47 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -716,9 +716,9 @@ int rsi_hal_load_key(struct rsi_common *common, u8 key_type, u8 key_id, u32 cipher, - s16 sta_id) + s16 sta_id, + struct ieee80211_vif *vif) { - struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb = NULL; struct rsi_set_key *set_key; u16 key_descriptor = 0; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index a82552cfb9d7..331d64b05649 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -618,7 +618,8 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, u16 ssn, u8 buf_size, u8 event, u8 sta_id); int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len, - u8 key_type, u8 key_id, u32 cipher, s16 sta_id); + u8 key_type, u8 key_id, u32 cipher, s16 sta_id, + struct ieee80211_vif *vif); int rsi_set_channel(struct rsi_common *common, struct ieee80211_channel *channel); int rsi_send_vap_dynamic_update(struct rsi_common *common); -- cgit v1.2.3-59-g8ed1b From efe877aa0f40dc1f2be450aba5baf8d90e7d9707 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:26 +0530 Subject: rsi: disallow power save config when AP vap running When AP or P2P GO VAP is running, power save configuration should be disallowed. To check interface type in power save configuration 'vif' parameters is passed. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 33 ++++++++++++++++++++--------- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 5 +++-- drivers/net/wireless/rsi/rsi_91x_ps.c | 15 +++++++------ drivers/net/wireless/rsi/rsi_mgmt.h | 2 ++ drivers/net/wireless/rsi/rsi_ps.h | 7 +++--- 5 files changed, 39 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index b1550bc243dd..09ad909e27ed 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -592,7 +592,6 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; - struct ieee80211_vif *vif = adapter->vifs[0]; struct ieee80211_conf *conf = &hw->conf; int status = -EOPNOTSUPP; @@ -608,16 +607,30 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, } /* Power save parameters */ - if ((changed & IEEE80211_CONF_CHANGE_PS) && - (vif->type == NL80211_IFTYPE_STATION)) { + if (changed & IEEE80211_CONF_CHANGE_PS) { + struct ieee80211_vif *vif; unsigned long flags; + int i, set_ps = 1; - spin_lock_irqsave(&adapter->ps_lock, flags); - if (conf->flags & IEEE80211_CONF_PS) - rsi_enable_ps(adapter); - else - rsi_disable_ps(adapter); - spin_unlock_irqrestore(&adapter->ps_lock, flags); + for (i = 0; i < RSI_MAX_VIFS; i++) { + vif = adapter->vifs[i]; + if (!vif) + continue; + /* Don't go to power save if AP vap exists */ + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { + set_ps = 0; + break; + } + } + if (set_ps) { + spin_lock_irqsave(&adapter->ps_lock, flags); + if (conf->flags & IEEE80211_CONF_PS) + rsi_enable_ps(adapter, vif); + else + rsi_disable_ps(adapter, vif); + spin_unlock_irqrestore(&adapter->ps_lock, flags); + } } /* RTS threshold */ @@ -726,7 +739,7 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, if (bss->assoc) { if (common->uapsd_bitmap) { rsi_dbg(INFO_ZONE, "Configuring UAPSD\n"); - rsi_conf_uapsd(adapter); + rsi_conf_uapsd(adapter, vif); } } else { common->uapsd_bitmap = 0; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 4e50cfdc2f47..383cd432b237 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1474,10 +1474,11 @@ int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word) return rsi_send_internal_mgmt_frame(common, skb); } -int rsi_send_ps_request(struct rsi_hw *adapter, bool enable) +int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, + struct ieee80211_vif *vif) { struct rsi_common *common = adapter->priv; - struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; + struct ieee80211_bss_conf *bss = &vif->bss_conf; struct rsi_request_ps *ps; struct rsi_ps_info *ps_info; struct sk_buff *skb; diff --git a/drivers/net/wireless/rsi/rsi_91x_ps.c b/drivers/net/wireless/rsi/rsi_91x_ps.c index 48c79f035c59..523f5329d2b7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_ps.c +++ b/drivers/net/wireless/rsi/rsi_91x_ps.c @@ -67,7 +67,7 @@ void rsi_default_ps_params(struct rsi_hw *adapter) ps_info->deep_sleep_wakeup_period = RSI_DEF_DS_WAKEUP_PERIOD; } -void rsi_enable_ps(struct rsi_hw *adapter) +void rsi_enable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) { if (adapter->ps_state != PS_NONE) { rsi_dbg(ERR_ZONE, @@ -76,7 +76,7 @@ void rsi_enable_ps(struct rsi_hw *adapter) return; } - if (rsi_send_ps_request(adapter, true)) { + if (rsi_send_ps_request(adapter, true, vif)) { rsi_dbg(ERR_ZONE, "%s: Failed to send PS request to device\n", __func__); @@ -86,7 +86,8 @@ void rsi_enable_ps(struct rsi_hw *adapter) rsi_modify_ps_state(adapter, PS_ENABLE_REQ_SENT); } -void rsi_disable_ps(struct rsi_hw *adapter) +/* This function is used to disable power save */ +void rsi_disable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) { if (adapter->ps_state != PS_ENABLED) { rsi_dbg(ERR_ZONE, @@ -95,7 +96,7 @@ void rsi_disable_ps(struct rsi_hw *adapter) return; } - if (rsi_send_ps_request(adapter, false)) { + if (rsi_send_ps_request(adapter, false, vif)) { rsi_dbg(ERR_ZONE, "%s: Failed to send PS request to device\n", __func__); @@ -105,16 +106,16 @@ void rsi_disable_ps(struct rsi_hw *adapter) rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT); } -void rsi_conf_uapsd(struct rsi_hw *adapter) +void rsi_conf_uapsd(struct rsi_hw *adapter, struct ieee80211_vif *vif) { int ret; if (adapter->ps_state != PS_ENABLED) return; - ret = rsi_send_ps_request(adapter, false); + ret = rsi_send_ps_request(adapter, false, vif); if (!ret) - ret = rsi_send_ps_request(adapter, true); + ret = rsi_send_ps_request(adapter, true, vif); if (ret) rsi_dbg(ERR_ZONE, "%s: Failed to send PS request to device\n", diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 331d64b05649..b9d0802c1b0f 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -641,4 +641,6 @@ int rsi_band_check(struct rsi_common *common, struct ieee80211_channel *chan); int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word); int rsi_send_radio_params_update(struct rsi_common *common); int rsi_set_antenna(struct rsi_common *common, u8 antenna); +int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, + struct ieee80211_vif *vif); #endif diff --git a/drivers/net/wireless/rsi/rsi_ps.h b/drivers/net/wireless/rsi/rsi_ps.h index d8475873df36..98ff6a4ced57 100644 --- a/drivers/net/wireless/rsi/rsi_ps.h +++ b/drivers/net/wireless/rsi/rsi_ps.h @@ -55,10 +55,9 @@ struct rsi_ps_info { } __packed; char *str_psstate(enum ps_state state); -void rsi_enable_ps(struct rsi_hw *adapter); -void rsi_disable_ps(struct rsi_hw *adapter); +void rsi_enable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif); +void rsi_disable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif); int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg); void rsi_default_ps_params(struct rsi_hw *hw); -int rsi_send_ps_request(struct rsi_hw *adapter, bool enable); -void rsi_conf_uapsd(struct rsi_hw *adapter); +void rsi_conf_uapsd(struct rsi_hw *adapter, struct ieee80211_vif *vif); #endif -- cgit v1.2.3-59-g8ed1b From c7245c0975f134cb10f113b0626ebd11799c8931 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:27 +0530 Subject: rsi: aggregation changes for p2p mode P2P Go condition is added wherever AP mode is there in aggregation path. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 09ad909e27ed..79426a2defc4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1005,7 +1005,8 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, if (ssn != NULL) seq_no = *ssn; - if (vif->type == NL80211_IFTYPE_AP) { + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) { rsta = rsi_find_sta(common, sta->addr); if (!rsta) { rsi_dbg(ERR_ZONE, "No station mapped\n"); @@ -1039,9 +1040,11 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_START: - if (vif->type == NL80211_IFTYPE_STATION) + if ((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) common->vif_info[ii].seq_start = seq_no; - else if (vif->type == NL80211_IFTYPE_AP) + else if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) rsta->seq_start[tid] = seq_no; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); status = 0; @@ -1061,9 +1064,11 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_OPERATIONAL: - if (vif->type == NL80211_IFTYPE_STATION) + if ((vif->type == NL80211_IFTYPE_STATION) || + (vif->type == NL80211_IFTYPE_P2P_CLIENT)) seq_start = common->vif_info[ii].seq_start; - else if (vif->type == NL80211_IFTYPE_AP) + else if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO)) seq_start = rsta->seq_start[tid]; status = rsi_send_aggregation_params_frame(common, tid, -- cgit v1.2.3-59-g8ed1b From af75687286bfea63c428591f08e9df6a7e7a9ff2 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 30 Aug 2017 15:08:28 +0530 Subject: rsi: miscellaneous changes for p2p mode Add P2P_GO condition as well when handling BEACON_ENABLE from mac80211. Also passing 'vif' for auto rate request. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 15 +++++++++------ drivers/net/wireless/rsi/rsi_91x_mgmt.c | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 79426a2defc4..b1f5dbbde3cb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -756,7 +756,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, } if ((changed & BSS_CHANGED_BEACON_ENABLED) && - (vif->type == NL80211_IFTYPE_AP)) { + ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_P2P_GO))) { if (bss->enable_beacon) { rsi_dbg(INFO_ZONE, "===> BEACON ENABLED <===\n"); common->beacon_enabled = 1; @@ -1147,9 +1148,9 @@ static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, */ static void rsi_perform_cqm(struct rsi_common *common, u8 *bssid, - s8 rssi) + s8 rssi, + struct ieee80211_vif *vif) { - struct rsi_hw *adapter = common->priv; s8 last_event = common->cqm_info.last_cqm_event_rssi; int thold = common->cqm_info.rssi_thold; u32 hyst = common->cqm_info.rssi_hyst; @@ -1165,7 +1166,7 @@ static void rsi_perform_cqm(struct rsi_common *common, common->cqm_info.last_cqm_event_rssi = rssi; rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event); - ieee80211_cqm_rssi_notify(adapter->vifs[0], event, rssi, GFP_KERNEL); + ieee80211_cqm_rssi_notify(vif, event, rssi, GFP_KERNEL); return; } @@ -1228,15 +1229,17 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, vif = adapter->vifs[i]; if (!vif) continue; - if (vif->type == NL80211_IFTYPE_STATION) + if (vif->type == NL80211_IFTYPE_STATION) { bss = &vif->bss_conf; + break; + } } if (!bss) return; /* CQM only for connected AP beacons, the RSSI is a weighted avg */ if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { if (ieee80211_is_beacon(hdr->frame_control)) - rsi_perform_cqm(common, hdr->addr2, rxs->signal); + rsi_perform_cqm(common, hdr->addr2, rxs->signal, vif); } return; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 383cd432b237..4b94190c9797 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1160,9 +1160,9 @@ static bool rsi_map_rates(u16 rate, int *offset) */ static int rsi_send_auto_rate_request(struct rsi_common *common, struct ieee80211_sta *sta, - u16 sta_id) + u16 sta_id, + struct ieee80211_vif *vif) { - struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb; struct rsi_auto_rate *auto_rate; int ii = 0, jj = 0, kk = 0; @@ -1332,7 +1332,7 @@ void rsi_inform_bss_status(struct rsi_common *common, aid, sta_id, vif); if (common->min_rate == 0xffff) - rsi_send_auto_rate_request(common, sta, sta_id); + rsi_send_auto_rate_request(common, sta, sta_id, vif); if (opmode == RSI_OPMODE_STA) { if (!rsi_send_block_unblock_frame(common, false)) common->hw_data_qs_blocked = false; -- cgit v1.2.3-59-g8ed1b From 6508497cbdc70b92130fbca57402af6a94e05d20 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 8 Sep 2017 16:24:52 +0100 Subject: rsi: fix a dereference on adapter before it has been null checked The assignment of dev is dereferencing adapter before adapter has been null checked, potentially leading to a null pointer dereference. Fix this by simply moving the assignment of dev to a later point after the sanity null check of adapter. Detected by CoverityScan CID#1398383 ("Dereference before null check") Fixes: dad0d04fa7ba ("rsi: Add RS9113 wireless driver") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 81df09dd2636..08730227cd18 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -73,8 +73,7 @@ static int rsi_write_multiple(struct rsi_hw *adapter, u8 *data, u32 count) { - struct rsi_91x_usbdev *dev = - (struct rsi_91x_usbdev *)adapter->rsi_dev; + struct rsi_91x_usbdev *dev; if (!adapter) return -ENODEV; @@ -82,6 +81,7 @@ static int rsi_write_multiple(struct rsi_hw *adapter, if (endpoint == 0) return -EINVAL; + dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; if (dev->write_fail) return -ENETDOWN; -- cgit v1.2.3-59-g8ed1b From 531f3ce953d4c74989eb1ece7ce37a3717532a13 Mon Sep 17 00:00:00 2001 From: Allen Pais Date: Thu, 21 Sep 2017 22:34:32 +0530 Subject: drivers: net: rsi_91x: use setup_timer() helper. Use setup_timer function instead of initializing timer with the function and data fields. Signed-off-by: Allen Pais Signed-off-by: David S. Miller --- drivers/net/wireless/rsi/rsi_91x_hal.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 070dfd68bb83..7ad286d6e9a7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -411,9 +411,8 @@ static void bl_cmd_timeout(unsigned long priv) static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout) { - init_timer(&adapter->bl_cmd_timer); - adapter->bl_cmd_timer.data = (unsigned long)adapter; - adapter->bl_cmd_timer.function = (void *)&bl_cmd_timeout; + setup_timer(&adapter->bl_cmd_timer, (void *)&bl_cmd_timeout, + (unsigned long)adapter); adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies); adapter->blcmd_timer_expired = false; -- cgit v1.2.3-59-g8ed1b From 192524a4992a8e638a05147f02d6e42cb2d485e1 Mon Sep 17 00:00:00 2001 From: Pavani Muthyala Date: Thu, 21 Sep 2017 18:20:34 +0530 Subject: rsi: add version information We will dump information about firmware version, firmware file name and operating mode during initialization. Signed-off-by: Pavani Muthyala Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_debugfs.c | 19 ++++++------------- drivers/net/wireless/rsi/rsi_91x_hal.c | 13 +++++++++++++ drivers/net/wireless/rsi/rsi_91x_main.c | 25 +++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_hal.h | 3 +++ drivers/net/wireless/rsi/rsi_main.h | 14 ++++++++++---- 5 files changed, 57 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index e98eb55c26cc..8c6ca8e689e4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -83,19 +83,12 @@ static int rsi_version_read(struct seq_file *seq, void *data) { struct rsi_common *common = seq->private; - common->driver_ver.major = 0; - common->driver_ver.minor = 1; - common->driver_ver.release_num = 0; - common->driver_ver.patch_num = 0; - seq_printf(seq, "Driver : %x.%d.%d.%d\nLMAC : %d.%d.%d.%d\n", - common->driver_ver.major, - common->driver_ver.minor, - common->driver_ver.release_num, - common->driver_ver.patch_num, - common->fw_ver.major, - common->fw_ver.minor, - common->fw_ver.release_num, - common->fw_ver.patch_num); + seq_printf(seq, "LMAC : %d.%d.%d.%d\n", + common->lmac_ver.major, + common->lmac_ver.minor, + common->lmac_ver.release_num, + common->lmac_ver.patch_num); + return 0; } diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 7e8e5d4f5f3d..71b02add81c8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -769,6 +769,7 @@ static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, static int rsi_load_firmware(struct rsi_hw *adapter) { + struct rsi_common *common = adapter->priv; struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; const struct firmware *fw_entry = NULL; u32 regout_val = 0, content_size; @@ -844,6 +845,18 @@ static int rsi_load_firmware(struct rsi_hw *adapter) content_size = fw_entry->size; rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", content_size); + /* Get the firmware version */ + common->lmac_ver.ver.info.fw_ver[0] = + flash_content[LMAC_VER_OFFSET] & 0xFF; + common->lmac_ver.ver.info.fw_ver[1] = + flash_content[LMAC_VER_OFFSET + 1] & 0xFF; + common->lmac_ver.major = flash_content[LMAC_VER_OFFSET + 2] & 0xFF; + common->lmac_ver.release_num = + flash_content[LMAC_VER_OFFSET + 3] & 0xFF; + common->lmac_ver.minor = flash_content[LMAC_VER_OFFSET + 4] & 0xFF; + common->lmac_ver.patch_num = 0; + rsi_print_version(common); + status = bl_write_header(adapter, flash_content, content_size); if (status) { rsi_dbg(ERR_ZONE, diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index b57bfdcf3549..71b8cfb8252e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -20,6 +20,7 @@ #include #include "rsi_mgmt.h" #include "rsi_common.h" +#include "rsi_hal.h" u32 rsi_zone_enabled = /* INFO_ZONE | INIT_ZONE | @@ -56,6 +57,30 @@ void rsi_dbg(u32 zone, const char *fmt, ...) } EXPORT_SYMBOL_GPL(rsi_dbg); +static char *opmode_str(int oper_mode) +{ + switch (oper_mode) { + case RSI_DEV_OPMODE_WIFI_ALONE: + return "Wi-Fi alone"; + } + + return "Unknown"; +} + +void rsi_print_version(struct rsi_common *common) +{ + rsi_dbg(ERR_ZONE, "================================================\n"); + rsi_dbg(ERR_ZONE, "================ RSI Version Info ==============\n"); + rsi_dbg(ERR_ZONE, "================================================\n"); + rsi_dbg(ERR_ZONE, "FW Version\t: %d.%d.%d\n", + common->lmac_ver.major, common->lmac_ver.minor, + common->lmac_ver.release_num); + rsi_dbg(ERR_ZONE, "Operating mode\t: %d [%s]", + common->oper_mode, opmode_str(common->oper_mode)); + rsi_dbg(ERR_ZONE, "Firmware file\t: %s", common->priv->fw_file_name); + rsi_dbg(ERR_ZONE, "================================================\n"); +} + /** * rsi_prepare_skb() - This function prepares the skb. * @common: Pointer to the driver private structure. diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index ad0d6537a678..a09d36b6b765 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -101,6 +101,9 @@ #define BBP_INFO_40MHZ 0x6 +#define FW_FLASH_OFFSET 0x820 +#define LMAC_VER_OFFSET (FW_FLASH_OFFSET + 0x200) + struct bl_header { __le32 flags; __le32 image_no; diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 34089ab111aa..a118b7aaeca0 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -113,8 +113,13 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); struct version_info { u16 major; u16 minor; - u16 release_num; - u16 patch_num; + u8 release_num; + u8 patch_num; + union { + struct { + u8 fw_ver[8]; + } info; + } ver; } __packed; struct skb_info { @@ -199,8 +204,7 @@ struct rsi_common { struct vif_priv vif_info[RSI_MAX_VIFS]; bool mgmt_q_block; - struct version_info driver_ver; - struct version_info fw_ver; + struct version_info lmac_ver; struct rsi_thread tx_thread; struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 2]; @@ -334,6 +338,8 @@ struct rsi_hw { int (*determine_event_timeout)(struct rsi_hw *adapter); }; +void rsi_print_version(struct rsi_common *common); + struct rsi_host_intf_ops { int (*read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); int (*write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); -- cgit v1.2.3-59-g8ed1b From 20db073327365f41e9b14feacb450df06758b520 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 21 Sep 2017 18:21:28 +0530 Subject: rsi: sdio suspend and resume support SDIO suspend and resume handlers are implemented and verified that device works after suspend/resume cycle. Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 128 +++++++++++++++++++++++++++++++- drivers/net/wireless/rsi/rsi_sdio.h | 2 + 2 files changed, 126 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8d3a4839b6ef..b3f8006c0e9b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1059,16 +1059,136 @@ static void rsi_disconnect(struct sdio_func *pfunction) } #ifdef CONFIG_PM +static int rsi_set_sdio_pm_caps(struct rsi_hw *adapter) +{ + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + struct sdio_func *func = dev->pfunction; + int ret; + + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) + rsi_dbg(ERR_ZONE, "Set sdio keep pwr flag failed: %d\n", ret); + + return ret; +} + +static int rsi_sdio_disable_interrupts(struct sdio_func *pfunc) +{ + struct rsi_hw *adapter = sdio_get_drvdata(pfunc); + u8 isr_status = 0, data = 0; + int ret; + unsigned long t1; + + rsi_dbg(INFO_ZONE, "Waiting for interrupts to be cleared.."); + t1 = jiffies; + do { + rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER, + &isr_status); + rsi_dbg(INFO_ZONE, "."); + } while ((isr_status) && (jiffies_to_msecs(jiffies - t1) < 20)); + rsi_dbg(INFO_ZONE, "Interrupts cleared\n"); + + sdio_claim_host(pfunc); + ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read int enable register\n", + __func__); + goto done; + } + + data &= RSI_INT_ENABLE_MASK; + ret = rsi_cmd52writebyte(pfunc->card, RSI_INT_ENABLE_REGISTER, data); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write to int enable register\n", + __func__); + goto done; + } + ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read int enable register\n", + __func__); + goto done; + } + rsi_dbg(INFO_ZONE, "int enable reg content = %x\n", data); + +done: + sdio_release_host(pfunc); + return ret; +} + +static int rsi_sdio_enable_interrupts(struct sdio_func *pfunc) +{ + u8 data; + int ret; + + sdio_claim_host(pfunc); + ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read int enable register\n", __func__); + goto done; + } + + data |= ~RSI_INT_ENABLE_MASK & 0xff; + + ret = rsi_cmd52writebyte(pfunc->card, RSI_INT_ENABLE_REGISTER, data); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write to int enable register\n", + __func__); + goto done; + } + + ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read int enable register\n", __func__); + goto done; + } + rsi_dbg(INFO_ZONE, "int enable reg content = %x\n", data); + +done: + sdio_release_host(pfunc); + return ret; +} + static int rsi_suspend(struct device *dev) { - /* Not yet implemented */ - return -ENOSYS; + int ret; + struct sdio_func *pfunction = dev_to_sdio_func(dev); + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_common *common; + + if (!adapter) { + rsi_dbg(ERR_ZONE, "Device is not ready\n"); + return -ENODEV; + } + common = adapter->priv; + rsi_sdio_disable_interrupts(pfunction); + + ret = rsi_set_sdio_pm_caps(adapter); + if (ret) + rsi_dbg(INFO_ZONE, + "Setting power management caps failed\n"); + common->fsm_state = FSM_CARD_NOT_READY; + + return 0; } static int rsi_resume(struct device *dev) { - /* Not yet implemented */ - return -ENOSYS; + struct sdio_func *pfunction = dev_to_sdio_func(dev); + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_common *common = adapter->priv; + + common->fsm_state = FSM_MAC_INIT_DONE; + rsi_sdio_enable_interrupts(pfunction); + + return 0; } static const struct dev_pm_ops rsi_pm_ops = { diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 95e4bed57baf..49c549ba6682 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -48,6 +48,8 @@ enum sdio_interrupt_type { #define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3 #define RSI_FN1_INT_REGISTER 0xf9 +#define RSI_INT_ENABLE_REGISTER 0x04 +#define RSI_INT_ENABLE_MASK 0xfc #define RSI_SD_REQUEST_MASTER 0x10000 /* FOR SD CARD ONLY */ -- cgit v1.2.3-59-g8ed1b From a39644b235c1a45f84d6e16603cacb93740ed2d4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Oct 2017 14:05:24 +0200 Subject: rsi: fix integer overflow warning gcc produces a harmless warning about a recently introduced signed integer overflow: drivers/net/wireless/rsi/rsi_91x_hal.c: In function 'rsi_prepare_mgmt_desc': include/uapi/linux/swab.h:13:15: error: integer overflow in expression [-Werror=overflow] (((__u16)(x) & (__u16)0x00ffU) << 8) | \ ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ include/uapi/linux/swab.h:104:2: note: in expansion of macro '___constant_swab16' ___constant_swab16(x) : \ ^~~~~~~~~~~~~~~~~~ include/uapi/linux/byteorder/big_endian.h:34:43: note: in expansion of macro '__swab16' #define __cpu_to_le16(x) ((__force __le16)__swab16((x))) ^~~~~~~~ include/linux/byteorder/generic.h:89:21: note: in expansion of macro '__cpu_to_le16' #define cpu_to_le16 __cpu_to_le16 ^~~~~~~~~~~~~ drivers/net/wireless/rsi/rsi_91x_hal.c:136:3: note: in expansion of macro 'cpu_to_le16' cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) & ^~~~~~~~~~~ The problem is that the 'mask' value is a signed integer that gets turned into a negative number when truncated to 16 bits. Making it an unsigned constant avoids this. Fixes: eac4eed3224b ("rsi: tx and rx path enhancements for p2p mode") Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_mgmt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index b9d0802c1b0f..e21723013f8d 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -189,7 +189,7 @@ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) -#define RSI_DESC_VAP_ID_MASK 0xC000 +#define RSI_DESC_VAP_ID_MASK 0xC000u #define RSI_DESC_VAP_ID_OFST 14 #define RSI_DATA_DESC_MAC_BBP_INFO BIT(0) #define RSI_DATA_DESC_NO_ACK_IND BIT(9) -- cgit v1.2.3-59-g8ed1b From dfefb9f8d082b609197f7ea852333e7a5ecc9563 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 02:29:09 -0700 Subject: drivers/wireless: rsi: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Kalle Valo Cc: Amitkumar Karwar Cc: Prameela Rani Garnepudi Cc: Pavani Muthyala Cc: Karun Eagalapati Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 7 +++---- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 4 ++-- drivers/net/wireless/rsi/rsi_91x_main.c | 4 +--- drivers/net/wireless/rsi/rsi_common.h | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 689527d7007a..1176de646942 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -418,9 +418,9 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) return 0; } -static void bl_cmd_timeout(unsigned long priv) +static void bl_cmd_timeout(struct timer_list *t) { - struct rsi_hw *adapter = (struct rsi_hw *)priv; + struct rsi_hw *adapter = from_timer(adapter, t, bl_cmd_timer); adapter->blcmd_timer_expired = true; del_timer(&adapter->bl_cmd_timer); @@ -428,8 +428,7 @@ static void bl_cmd_timeout(unsigned long priv) static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout) { - setup_timer(&adapter->bl_cmd_timer, (void *)&bl_cmd_timeout, - (unsigned long)adapter); + timer_setup(&adapter->bl_cmd_timer, bl_cmd_timeout, 0); adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies); adapter->blcmd_timer_expired = false; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index b1f5dbbde3cb..9427c9d7c9c7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1663,9 +1663,9 @@ static void rsi_resume_conn_channel(struct rsi_common *common) } } -void rsi_roc_timeout(unsigned long data) +void rsi_roc_timeout(struct timer_list *t) { - struct rsi_common *common = (struct rsi_common *)data; + struct rsi_common *common = from_timer(common, t, roc_timer); rsi_dbg(INFO_ZONE, "Remain on channel expired\n"); diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 71b8cfb8252e..2a1fbb7db6c4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -262,9 +262,7 @@ struct rsi_hw *rsi_91x_init(void) rsi_default_ps_params(adapter); spin_lock_init(&adapter->ps_lock); - common->roc_timer.data = (unsigned long)common; - common->roc_timer.function = (void *)&rsi_roc_timeout; - init_timer(&common->roc_timer); + timer_setup(&common->roc_timer, rsi_roc_timeout, 0); common->init_done = true; return adapter; diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index 272e18d750ff..29acaea3636d 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -85,5 +85,5 @@ void rsi_91x_deinit(struct rsi_hw *adapter); int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr); struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac); -void rsi_roc_timeout(unsigned long data); +void rsi_roc_timeout(struct timer_list *t); #endif -- cgit v1.2.3-59-g8ed1b From f3ac4e7394a1aa89c5ca49f8a5344a98b56df046 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Fri, 27 Oct 2017 16:55:55 +0530 Subject: rsi: sdio: add WOWLAN support for S3 suspend state WoWLAN is supported in RS9113 device through GPIO pin2. wowlan config frame is internally sent to firmware in mac80211 suspend handler. Also beacon miss threshold and keep-alive time values are increased to avoid un-necessary disconnection with AP. Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 6 ++ drivers/net/wireless/rsi/rsi_91x_mac80211.c | 118 ++++++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_91x_mgmt.c | 60 +++++++++++--- drivers/net/wireless/rsi/rsi_91x_sdio.c | 7 ++ drivers/net/wireless/rsi/rsi_common.h | 1 + drivers/net/wireless/rsi/rsi_main.h | 8 +- drivers/net/wireless/rsi/rsi_mgmt.h | 31 +++++++- 7 files changed, 220 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index bc18a191aef9..87e023d601c3 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -379,6 +379,12 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); goto xmit_fail; } + if (common->wow_flags & RSI_WOW_ENABLED) { + rsi_dbg(ERR_ZONE, + "%s: Blocking Tx_packets when WOWLAN is enabled\n", + __func__); + goto xmit_fail; + } info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 9427c9d7c9c7..c3bd3ca9cf83 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1746,6 +1746,119 @@ static int rsi_mac80211_cancel_roc(struct ieee80211_hw *hw) return 0; } +static const struct wiphy_wowlan_support rsi_wowlan_support = { + .flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE, +}; + +static u16 rsi_wow_map_triggers(struct rsi_common *common, + struct cfg80211_wowlan *wowlan) +{ + u16 wow_triggers = 0; + + rsi_dbg(INFO_ZONE, "Mapping wowlan triggers\n"); + + if (wowlan->any) + wow_triggers |= RSI_WOW_ANY; + if (wowlan->magic_pkt) + wow_triggers |= RSI_WOW_MAGIC_PKT; + if (wowlan->disconnect) + wow_triggers |= RSI_WOW_DISCONNECT; + if (wowlan->gtk_rekey_failure || wowlan->eap_identity_req || + wowlan->four_way_handshake) + wow_triggers |= RSI_WOW_GTK_REKEY; + + return wow_triggers; +} + +int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) +{ + struct rsi_common *common = adapter->priv; + u16 triggers = 0; + u16 rx_filter_word = 0; + struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; + + rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n"); + + if (WARN_ON(!wowlan)) { + rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n"); + return -EINVAL; + } + + triggers = rsi_wow_map_triggers(common, wowlan); + if (!triggers) { + rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__); + return -EINVAL; + } + if (!bss->assoc) { + rsi_dbg(ERR_ZONE, + "Cannot configure WoWLAN (Station not connected)\n"); + common->wow_flags |= RSI_WOW_NO_CONNECTION; + return 0; + } + rsi_dbg(INFO_ZONE, "TRIGGERS %x\n", triggers); + rsi_send_wowlan_request(common, triggers, 1); + + /** + * Increase the beacon_miss threshold & keep-alive timers in + * vap_update frame + */ + rsi_send_vap_dynamic_update(common); + + rx_filter_word = (ALLOW_DATA_ASSOC_PEER | DISALLOW_BEACONS); + rsi_send_rx_filter_frame(common, rx_filter_word); + common->wow_flags |= RSI_WOW_ENABLED; + + return 0; +} + +#ifdef CONFIG_PM +static int rsi_mac80211_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + rsi_dbg(INFO_ZONE, "%s: mac80211 suspend\n", __func__); + mutex_lock(&common->mutex); + if (rsi_config_wowlan(adapter, wowlan)) { + rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n"); + mutex_unlock(&common->mutex); + return 1; + } + mutex_unlock(&common->mutex); + + return 0; +} + +static int rsi_mac80211_resume(struct ieee80211_hw *hw) +{ + u16 rx_filter_word = 0; + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + common->wow_flags = 0; + + rsi_dbg(INFO_ZONE, "%s: mac80211 resume\n", __func__); + + mutex_lock(&common->mutex); + rsi_send_wowlan_request(common, 0, 0); + + rx_filter_word = (ALLOW_DATA_ASSOC_PEER | ALLOW_CTRL_ASSOC_PEER | + ALLOW_MGMT_ASSOC_PEER); + rsi_send_rx_filter_frame(common, rx_filter_word); + mutex_unlock(&common->mutex); + + return 0; +} + +#endif + static const struct ieee80211_ops mac80211_ops = { .tx = rsi_mac80211_tx, .start = rsi_mac80211_start, @@ -1767,6 +1880,10 @@ static const struct ieee80211_ops mac80211_ops = { .rfkill_poll = rsi_mac80211_rfkill_poll, .remain_on_channel = rsi_mac80211_roc, .cancel_remain_on_channel = rsi_mac80211_cancel_roc, +#ifdef CONFIG_PM + .suspend = rsi_mac80211_suspend, + .resume = rsi_mac80211_resume, +#endif }; /** @@ -1850,6 +1967,7 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; wiphy->reg_notifier = rsi_reg_notify; + wiphy->wowlan = &rsi_wowlan_support; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); /* Wi-Fi direct parameters */ diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 4b94190c9797..1446ee3581d0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1094,9 +1094,18 @@ int rsi_send_vap_dynamic_update(struct rsi_common *common) dynamic_frame->desc_dword0.frame_type = VAP_DYNAMIC_UPDATE; dynamic_frame->desc_dword2.pkt_info = cpu_to_le32(common->rts_threshold); - /* Beacon miss threshold */ - dynamic_frame->frame_body.keep_alive_period = + + if (common->wow_flags & RSI_WOW_ENABLED) { + /* Beacon miss threshold */ + dynamic_frame->desc_dword3.token = + cpu_to_le16(RSI_BCN_MISS_THRESHOLD); + dynamic_frame->frame_body.keep_alive_period = + cpu_to_le16(RSI_WOW_KEEPALIVE); + } else { + dynamic_frame->frame_body.keep_alive_period = cpu_to_le16(RSI_DEF_KEEPALIVE); + } + dynamic_frame->desc_dword3.sta_id = 0; /* vap id */ skb_put(skb, sizeof(struct rsi_dynamic_s)); @@ -1340,13 +1349,12 @@ void rsi_inform_bss_status(struct rsi_common *common, } else { if (opmode == RSI_OPMODE_STA) common->hw_data_qs_blocked = true; - rsi_hal_send_sta_notify_frame(common, - opmode, - STA_DISCONNECTED, - addr, - qos_enable, - aid, sta_id, - vif); + + if (!(common->wow_flags & RSI_WOW_ENABLED)) + rsi_hal_send_sta_notify_frame(common, opmode, + STA_DISCONNECTED, addr, + qos_enable, aid, sta_id, + vif); if (opmode == RSI_OPMODE_STA) rsi_send_block_unblock_frame(common, true); } @@ -1589,6 +1597,40 @@ static int rsi_send_beacon(struct rsi_common *common) return 0; } +int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, + u16 sleep_status) +{ + struct rsi_wowlan_req *cmd_frame; + struct sk_buff *skb; + u8 length; + + rsi_dbg(ERR_ZONE, "%s: Sending wowlan request frame\n", __func__); + + length = sizeof(*cmd_frame); + skb = dev_alloc_skb(length); + if (!skb) + return -ENOMEM; + memset(skb->data, 0, length); + cmd_frame = (struct rsi_wowlan_req *)skb->data; + + rsi_set_len_qno(&cmd_frame->desc.desc_dword0.len_qno, + (length - FRAME_DESC_SZ), + RSI_WIFI_MGMT_Q); + cmd_frame->desc.desc_dword0.frame_type = WOWLAN_CONFIG_PARAMS; + cmd_frame->host_sleep_status = sleep_status; + if (common->secinfo.security_enable && + common->secinfo.gtk_cipher) + flags |= RSI_WOW_GTK_REKEY; + if (sleep_status) + cmd_frame->wow_flags = flags; + rsi_dbg(INFO_ZONE, "Host_Sleep_Status : %d Flags : %d\n", + cmd_frame->host_sleep_status, cmd_frame->wow_flags); + + skb_put(skb, length); + + return rsi_send_internal_mgmt_frame(common, skb); +} + /** * rsi_handle_ta_confirm_type() - This function handles the confirm frames. * @common: Pointer to the driver private structure. diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index b3f8006c0e9b..fa6af7be61f4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1124,6 +1124,8 @@ static int rsi_sdio_enable_interrupts(struct sdio_func *pfunc) { u8 data; int ret; + struct rsi_hw *adapter = sdio_get_drvdata(pfunc); + struct rsi_common *common = adapter->priv; sdio_claim_host(pfunc); ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data); @@ -1143,6 +1145,11 @@ static int rsi_sdio_enable_interrupts(struct sdio_func *pfunc) goto done; } + if ((common->wow_flags & RSI_WOW_ENABLED) && + (common->wow_flags & RSI_WOW_NO_CONNECTION)) + rsi_dbg(ERR_ZONE, + "##### Device can not wake up through WLAN\n"); + ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data); if (ret < 0) { rsi_dbg(ERR_ZONE, diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index 29acaea3636d..70b8b4b49d04 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -83,6 +83,7 @@ u16 rsi_get_connected_channel(struct ieee80211_vif *vif); struct rsi_hw *rsi_91x_init(void); void rsi_91x_deinit(struct rsi_hw *adapter); int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); +int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan); struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr); struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac); void rsi_roc_timeout(struct timer_list *t); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index a118b7aaeca0..44a199f2116f 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -66,6 +66,8 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define FRAME_DESC_SZ 16 #define MIN_802_11_HDR_LEN 24 #define RSI_DEF_KEEPALIVE 90 +#define RSI_WOW_KEEPALIVE 5 +#define RSI_BCN_MISS_THRESHOLD 24 #define DATA_QUEUE_WATER_MARK 400 #define MIN_DATA_QUEUE_WATER_MARK 300 @@ -108,6 +110,10 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); ((_q) == VI_Q) ? IEEE80211_AC_VI : \ IEEE80211_AC_VO) +/* WoWLAN flags */ +#define RSI_WOW_ENABLED BIT(0) +#define RSI_WOW_NO_CONNECTION BIT(1) + #define RSI_DEV_9113 1 struct version_info { @@ -266,7 +272,7 @@ struct rsi_common { u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; - + u8 wow_flags; u16 beacon_interval; u8 dtim_cnt; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index e21723013f8d..76337ce817e0 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -45,6 +45,17 @@ #define MAGIC_WORD 0x5A #define WLAN_EEPROM_RFTYPE_ADDR 424 +/*WOWLAN RESUME WAKEUP TYPES*/ +#define RSI_UNICAST_MAGIC_PKT BIT(0) +#define RSI_BROADCAST_MAGICPKT BIT(1) +#define RSI_EAPOL_PKT BIT(2) +#define RSI_DISCONNECT_PKT BIT(3) +#define RSI_HW_BMISS_PKT BIT(4) +#define RSI_INSERT_SEQ_IN_FW BIT(2) + +#define WOW_MAX_FILTERS_PER_LIST 16 +#define WOW_PATTERN_SIZE 256 + /* Receive Frame Types */ #define TA_CONFIRM_TYPE 0x01 #define RX_DOT11_MGMT 0x02 @@ -201,6 +212,13 @@ #define RSI_DATA_DESC_INSERT_TSF BIT(15) #define RSI_DATA_DESC_INSERT_SEQ_NO BIT(2) +#ifdef CONFIG_PM +#define RSI_WOW_ANY BIT(1) +#define RSI_WOW_GTK_REKEY BIT(3) +#define RSI_WOW_MAGIC_PKT BIT(4) +#define RSI_WOW_DISCONNECT BIT(5) +#endif + enum opmode { RSI_OPMODE_UNSUPPORTED = -1, RSI_OPMODE_AP = 0, @@ -262,7 +280,9 @@ enum cmd_frame_type { ANT_SEL_FRAME = 0x20, VAP_DYNAMIC_UPDATE = 0x27, COMMON_DEV_CONFIG = 0x28, - RADIO_PARAMS_UPDATE = 0x29 + RADIO_PARAMS_UPDATE = 0x29, + WOWLAN_CONFIG_PARAMS = 0x2B, + WOWLAN_WAKEUP_REASON = 0xc5 }; struct rsi_mac_frame { @@ -581,6 +601,13 @@ struct rsi_request_ps { __le16 ps_num_dtim_intervals; } __packed; +struct rsi_wowlan_req { + struct rsi_cmd_desc desc; + u8 sourceid[ETH_ALEN]; + u16 wow_flags; + u16 host_sleep_status; +} __packed; + static inline u32 rsi_get_queueno(u8 *addr, u16 offset) { return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; @@ -641,6 +668,8 @@ int rsi_band_check(struct rsi_common *common, struct ieee80211_channel *chan); int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word); int rsi_send_radio_params_update(struct rsi_common *common); int rsi_set_antenna(struct rsi_common *common, u8 antenna); +int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, + u16 sleep_status); int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, struct ieee80211_vif *vif); #endif -- cgit v1.2.3-59-g8ed1b From b6c8d06c8a6465c054befd416d8b067ad495fa06 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Fri, 27 Oct 2017 16:55:56 +0530 Subject: rsi: sdio: Add WOWLAN support for S4 hibernate state We are disabling of interrupts from firmware in freeze handler. Also setting power management capability KEEP_MMC_POWER to make device wakeup for WoWLAN trigger. At restore, we observed a device reset on some platforms. Hence reloading of firmware and device initialization is performed. Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 2 + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 9 +++ drivers/net/wireless/rsi/rsi_91x_main.c | 1 + drivers/net/wireless/rsi/rsi_91x_mgmt.c | 7 +- drivers/net/wireless/rsi/rsi_91x_sdio.c | 111 ++++++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_main.h | 4 + drivers/net/wireless/rsi/rsi_sdio.h | 1 + 7 files changed, 134 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 87e023d601c3..d0d2201830e8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -276,6 +276,8 @@ void rsi_core_qos_processor(struct rsi_common *common) rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__); break; } + if (common->hibernate_resume) + break; mutex_lock(&common->tx_lock); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index c3bd3ca9cf83..95eb5e63999f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -17,6 +17,7 @@ #include #include "rsi_debugfs.h" #include "rsi_mgmt.h" +#include "rsi_sdio.h" #include "rsi_common.h" #include "rsi_ps.h" @@ -325,6 +326,11 @@ static int rsi_mac80211_start(struct ieee80211_hw *hw) rsi_dbg(ERR_ZONE, "===> Interface UP <===\n"); mutex_lock(&common->mutex); + if (common->hibernate_resume) { + common->reinit_hw = true; + adapter->host_intf_ops->reinit_device(adapter); + wait_for_completion(&adapter->priv->wlan_init_completion); + } common->iface_down = false; wiphy_rfkill_start_polling(hw->wiphy); rsi_send_rx_filter_frame(common, 0); @@ -1846,6 +1852,9 @@ static int rsi_mac80211_resume(struct ieee80211_hw *hw) rsi_dbg(INFO_ZONE, "%s: mac80211 resume\n", __func__); + if (common->hibernate_resume) + return 0; + mutex_lock(&common->mutex); rsi_send_wowlan_request(common, 0, 0); diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 2a1fbb7db6c4..0cb8e68bab58 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -263,6 +263,7 @@ struct rsi_hw *rsi_91x_init(void) rsi_default_ps_params(adapter); spin_lock_init(&adapter->ps_lock); timer_setup(&common->roc_timer, rsi_roc_timeout, 0); + init_completion(&common->wlan_init_completion); common->init_done = true; return adapter; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 1446ee3581d0..d38a09f15742 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1761,7 +1761,11 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, common->bb_rf_prog_count--; if (!common->bb_rf_prog_count) { common->fsm_state = FSM_MAC_INIT_DONE; - return rsi_mac80211_attach(common); + if (common->reinit_hw) { + complete(&common->wlan_init_completion); + } else { + return rsi_mac80211_attach(common); + } } } else { rsi_dbg(INFO_ZONE, @@ -1839,6 +1843,7 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) case TA_CONFIRM_TYPE: return rsi_handle_ta_confirm_type(common, msg); case CARD_READY_IND: + common->hibernate_resume = false; rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n", __func__); return rsi_handle_card_ready(common, msg); diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index fa6af7be61f4..3f683d873472 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -880,6 +880,7 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = { .master_reg_read = rsi_sdio_master_reg_read, .master_reg_write = rsi_sdio_master_reg_write, .load_data_master_write = rsi_sdio_load_data_master_write, + .reinit_device = rsi_sdio_reinit_device, }; /** @@ -936,6 +937,8 @@ static int rsi_probe(struct sdio_func *pfunction, return -EIO; } + adapter->priv->hibernate_resume = false; + adapter->priv->reinit_hw = false; return 0; fail: rsi_91x_deinit(adapter); @@ -1198,9 +1201,117 @@ static int rsi_resume(struct device *dev) return 0; } +static int rsi_freeze(struct device *dev) +{ + int ret; + struct sdio_func *pfunction = dev_to_sdio_func(dev); + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_common *common; + struct rsi_91x_sdiodev *sdev; + + rsi_dbg(INFO_ZONE, "SDIO Bus freeze ===>\n"); + + if (!adapter) { + rsi_dbg(ERR_ZONE, "Device is not ready\n"); + return -ENODEV; + } + common = adapter->priv; + sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; + +#ifdef CONFIG_RSI_WOW + if ((common->wow_flags & RSI_WOW_ENABLED) && + (common->wow_flags & RSI_WOW_NO_CONNECTION)) + rsi_dbg(ERR_ZONE, + "##### Device can not wake up through WLAN\n"); +#endif + ret = rsi_sdio_disable_interrupts(pfunction); + + if (sdev->write_fail) + rsi_dbg(INFO_ZONE, "###### Device is not ready #######\n"); + + ret = rsi_set_sdio_pm_caps(adapter); + if (ret) + rsi_dbg(INFO_ZONE, "Setting power management caps failed\n"); + + rsi_dbg(INFO_ZONE, "***** RSI module freezed *****\n"); + + return 0; +} + +static int rsi_thaw(struct device *dev) +{ + struct sdio_func *pfunction = dev_to_sdio_func(dev); + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_common *common = adapter->priv; + + rsi_dbg(ERR_ZONE, "SDIO Bus thaw =====>\n"); + + common->hibernate_resume = true; + common->fsm_state = FSM_CARD_NOT_READY; + common->iface_down = true; + + rsi_sdio_enable_interrupts(pfunction); + + rsi_dbg(INFO_ZONE, "***** RSI module thaw done *****\n"); + + return 0; +} + +int rsi_sdio_reinit_device(struct rsi_hw *adapter) +{ + struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; + struct sdio_func *pfunction = sdev->pfunction; + int ii; + + for (ii = 0; ii < NUM_SOFT_QUEUES; ii++) + skb_queue_purge(&adapter->priv->tx_queue[ii]); + + /* Initialize device again */ + sdio_claim_host(pfunction); + + sdio_release_irq(pfunction); + rsi_reset_card(pfunction); + + sdio_enable_func(pfunction); + rsi_setupcard(adapter); + rsi_init_sdio_slave_regs(adapter); + sdio_claim_irq(pfunction, rsi_handle_interrupt); + rsi_hal_device_init(adapter); + + sdio_release_host(pfunction); + + return 0; +} + +static int rsi_restore(struct device *dev) +{ + struct sdio_func *pfunction = dev_to_sdio_func(dev); + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_common *common = adapter->priv; + + rsi_dbg(INFO_ZONE, "SDIO Bus restore ======>\n"); + common->hibernate_resume = true; + common->fsm_state = FSM_FW_NOT_LOADED; + common->iface_down = true; + + adapter->sc_nvifs = 0; + ieee80211_restart_hw(adapter->hw); + +#ifdef CONFIG_RSI_WOW + common->wow_flags = 0; +#endif + common->iface_down = false; + + rsi_dbg(INFO_ZONE, "RSI module restored\n"); + + return 0; +} static const struct dev_pm_ops rsi_pm_ops = { .suspend = rsi_suspend, .resume = rsi_resume, + .freeze = rsi_freeze, + .thaw = rsi_thaw, + .restore = rsi_restore, }; #endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 44a199f2116f..8cab630af4a5 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -214,6 +214,7 @@ struct rsi_common { struct rsi_thread tx_thread; struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 2]; + struct completion wlan_init_completion; /* Mutex declaration */ struct mutex mutex; /* Mutex used for tx thread */ @@ -272,6 +273,8 @@ struct rsi_common { u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; + bool hibernate_resume; + bool reinit_hw; u8 wow_flags; u16 beacon_interval; u8 dtim_cnt; @@ -362,5 +365,6 @@ struct rsi_host_intf_ops { int (*load_data_master_write)(struct rsi_hw *adapter, u32 addr, u32 instructions_size, u16 block_size, u8 *fw); + int (*reinit_device)(struct rsi_hw *adapter); }; #endif diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 49c549ba6682..8fbf90eb7b42 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -131,4 +131,5 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num); +int rsi_sdio_reinit_device(struct rsi_hw *adapter); #endif -- cgit v1.2.3-59-g8ed1b From 063848c3e1558e40879522562aaf905fdcf0d7f1 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Fri, 27 Oct 2017 16:55:57 +0530 Subject: rsi: sdio: Add WOWLAN support for S5 shutdown state Unlike other power states, WoWLAN configuration does not come from mac80211 for shutdown. Hence configuring the WoWLAN from shut down callback it self. Remaining steps of disabling SDIO interrupts, setting 'MMC_PM_KEEP_POWER' flag are same as other power states. Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 1 + drivers/net/wireless/rsi/rsi_91x_sdio.c | 31 +++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 95eb5e63999f..36c63e953f84 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1822,6 +1822,7 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) return 0; } +EXPORT_SYMBOL(rsi_config_wowlan); #ifdef CONFIG_PM static int rsi_mac80211_suspend(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 3f683d873472..3288fb6888b9 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1218,12 +1218,11 @@ static int rsi_freeze(struct device *dev) common = adapter->priv; sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; -#ifdef CONFIG_RSI_WOW if ((common->wow_flags & RSI_WOW_ENABLED) && (common->wow_flags & RSI_WOW_NO_CONNECTION)) rsi_dbg(ERR_ZONE, "##### Device can not wake up through WLAN\n"); -#endif + ret = rsi_sdio_disable_interrupts(pfunction); if (sdev->write_fail) @@ -1257,6 +1256,31 @@ static int rsi_thaw(struct device *dev) return 0; } +static void rsi_shutdown(struct device *dev) +{ + struct sdio_func *pfunction = dev_to_sdio_func(dev); + struct rsi_hw *adapter = sdio_get_drvdata(pfunction); + struct rsi_91x_sdiodev *sdev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; + struct ieee80211_hw *hw = adapter->hw; + struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; + + rsi_dbg(ERR_ZONE, "SDIO Bus shutdown =====>\n"); + + if (rsi_config_wowlan(adapter, wowlan)) + rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n"); + + rsi_sdio_disable_interrupts(sdev->pfunction); + + if (sdev->write_fail) + rsi_dbg(INFO_ZONE, "###### Device is not ready #######\n"); + + if (rsi_set_sdio_pm_caps(adapter)) + rsi_dbg(INFO_ZONE, "Setting power management caps failed\n"); + + rsi_dbg(INFO_ZONE, "***** RSI module shut down *****\n"); +} + int rsi_sdio_reinit_device(struct rsi_hw *adapter) { struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; @@ -1297,9 +1321,7 @@ static int rsi_restore(struct device *dev) adapter->sc_nvifs = 0; ieee80211_restart_hw(adapter->hw); -#ifdef CONFIG_RSI_WOW common->wow_flags = 0; -#endif common->iface_down = false; rsi_dbg(INFO_ZONE, "RSI module restored\n"); @@ -1331,6 +1353,7 @@ static struct sdio_driver rsi_driver = { #ifdef CONFIG_PM .drv = { .pm = &rsi_pm_ops, + .shutdown = rsi_shutdown, } #endif }; -- cgit v1.2.3-59-g8ed1b From 39f1332c526cd9d6de59a72520e8334e54b62cda Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 1 Nov 2017 17:42:44 +0530 Subject: rsi: move rsi_sdio_reinit_device() out of CONFIG_PM This function is generic. It doesn't contain wowlan specific code. It should not be under CONFIG_PM. This patch resolves compilation errors observed when CONFIG_PM flag is disabled. Reported-by: kbuild test robot Fixes: ef71ed0608c ("rsi: sdio: Add WOWLAN support for S5 shutdown state") Fixes: a24e35fcee0 ("rsi: sdio: Add WOWLAN support for S4 hibernate state") Fixes: e1ced6422a3 ("rsi: sdio: add WOWLAN support for S3 suspend state") Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 52 ++++++++++++++++----------------- drivers/net/wireless/rsi/rsi_sdio.h | 1 - 2 files changed, 26 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 3288fb6888b9..b0cf41195051 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -871,6 +871,32 @@ fail: return status; } +static int rsi_sdio_reinit_device(struct rsi_hw *adapter) +{ + struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; + struct sdio_func *pfunction = sdev->pfunction; + int ii; + + for (ii = 0; ii < NUM_SOFT_QUEUES; ii++) + skb_queue_purge(&adapter->priv->tx_queue[ii]); + + /* Initialize device again */ + sdio_claim_host(pfunction); + + sdio_release_irq(pfunction); + rsi_reset_card(pfunction); + + sdio_enable_func(pfunction); + rsi_setupcard(adapter); + rsi_init_sdio_slave_regs(adapter); + sdio_claim_irq(pfunction, rsi_handle_interrupt); + rsi_hal_device_init(adapter); + + sdio_release_host(pfunction); + + return 0; +} + static struct rsi_host_intf_ops sdio_host_intf_ops = { .write_pkt = rsi_sdio_host_intf_write_pkt, .read_pkt = rsi_sdio_host_intf_read_pkt, @@ -1281,32 +1307,6 @@ static void rsi_shutdown(struct device *dev) rsi_dbg(INFO_ZONE, "***** RSI module shut down *****\n"); } -int rsi_sdio_reinit_device(struct rsi_hw *adapter) -{ - struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; - struct sdio_func *pfunction = sdev->pfunction; - int ii; - - for (ii = 0; ii < NUM_SOFT_QUEUES; ii++) - skb_queue_purge(&adapter->priv->tx_queue[ii]); - - /* Initialize device again */ - sdio_claim_host(pfunction); - - sdio_release_irq(pfunction); - rsi_reset_card(pfunction); - - sdio_enable_func(pfunction); - rsi_setupcard(adapter); - rsi_init_sdio_slave_regs(adapter); - sdio_claim_irq(pfunction, rsi_handle_interrupt); - rsi_hal_device_init(adapter); - - sdio_release_host(pfunction); - - return 0; -} - static int rsi_restore(struct device *dev) { struct sdio_func *pfunction = dev_to_sdio_func(dev); diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 8fbf90eb7b42..49c549ba6682 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -131,5 +131,4 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num); -int rsi_sdio_reinit_device(struct rsi_hw *adapter); #endif -- cgit v1.2.3-59-g8ed1b From e6b3b2ed3d270b3c7080c9cf7d28636dc74b0387 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 1 Nov 2017 17:42:45 +0530 Subject: rsi: fix kbuild reported build errors with CONFIG_PM off Some wowlan related code was outside CONFIG_PM flag which caused these build errors. They are fixed by moving that code under CONFIG_PM flag. Reported-by: kbuild test robot Fixes: ef71ed0608c ("rsi: sdio: Add WOWLAN support for S5 shutdown state") Fixes: a24e35fcee0 ("rsi: sdio: Add WOWLAN support for S4 hibernate state") Fixes: e1ced6422a3 ("rsi: sdio: add WOWLAN support for S3 suspend state") Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 5 ++++- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 2 ++ drivers/net/wireless/rsi/rsi_common.h | 2 ++ drivers/net/wireless/rsi/rsi_mgmt.h | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 36c63e953f84..32f5cb46fd4f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1752,6 +1752,7 @@ static int rsi_mac80211_cancel_roc(struct ieee80211_hw *hw) return 0; } +#ifdef CONFIG_PM static const struct wiphy_wowlan_support rsi_wowlan_support = { .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT | @@ -1824,7 +1825,6 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) } EXPORT_SYMBOL(rsi_config_wowlan); -#ifdef CONFIG_PM static int rsi_mac80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -1977,7 +1977,10 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; wiphy->reg_notifier = rsi_reg_notify; +#ifdef CONFIG_PM wiphy->wowlan = &rsi_wowlan_support; +#endif + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); /* Wi-Fi direct parameters */ diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index d38a09f15742..46c9d5470dfb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1597,6 +1597,7 @@ static int rsi_send_beacon(struct rsi_common *common) return 0; } +#ifdef CONFIG_PM int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, u16 sleep_status) { @@ -1630,6 +1631,7 @@ int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, return rsi_send_internal_mgmt_frame(common, skb); } +#endif /** * rsi_handle_ta_confirm_type() - This function handles the confirm frames. diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index 70b8b4b49d04..d07dbba61727 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -83,7 +83,9 @@ u16 rsi_get_connected_channel(struct ieee80211_vif *vif); struct rsi_hw *rsi_91x_init(void); void rsi_91x_deinit(struct rsi_hw *adapter); int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); +#ifdef CONFIG_PM int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan); +#endif struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr); struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac); void rsi_roc_timeout(struct timer_list *t); diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 76337ce817e0..389094a3f91c 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -668,8 +668,10 @@ int rsi_band_check(struct rsi_common *common, struct ieee80211_channel *chan); int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word); int rsi_send_radio_params_update(struct rsi_common *common); int rsi_set_antenna(struct rsi_common *common, u8 antenna); +#ifdef CONFIG_PM int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, u16 sleep_status); +#endif int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, struct ieee80211_vif *vif); #endif -- cgit v1.2.3-59-g8ed1b From 4775ae7afec62e6ae1bc1f99ab57db2a36b8807e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 6 Nov 2017 15:53:21 -0600 Subject: rsi: rsi_91x_ps: remove redundant code in str_psstate "INVALID_STATE" is already being returned in the default case and this code cannot be reached. Addresses-Coverity-ID: 1398384 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_ps.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/rsi') diff --git a/drivers/net/wireless/rsi/rsi_91x_ps.c b/drivers/net/wireless/rsi/rsi_91x_ps.c index 523f5329d2b7..01472fac8b9a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_ps.c +++ b/drivers/net/wireless/rsi/rsi_91x_ps.c @@ -36,7 +36,6 @@ char *str_psstate(enum ps_state state) default: return "INVALID_STATE"; } - return "INVALID_STATE"; } static inline void rsi_modify_ps_state(struct rsi_hw *adapter, -- cgit v1.2.3-59-g8ed1b