2017-08-03 14:32:59

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 0/8] rsi driver enhancements

From: Amitkumar Karwar <[email protected]>

This patch series brings in few enhancements in rsi driver
like rfkill support, U-APSD and Legacy power save support,
antenna and RTS threshold configuration, improvements in
reading SDIO buffer status.

Changes in v2:
1/8: Pavani's name was in incorrect format. Fixed this(Kalle)
3/8: Used the same licence information for newly added files.
Removed redundant comments for functions (Kalle)

Karun Eagalapati (6):
rsi: add support for legacy power save
rsi: add support for U-APSD power save
rsi: rename sdio_read_buffer_status_register
rsi: buffer full check optimization
rsi: buffer available interrupt handling
rsi: RTS threshold configuration

Pavani Muthyala (2):
rsi: add support for rf-kill functionality
rsi: update set_antenna command frame

drivers/net/wireless/rsi/Makefile | 1 +
drivers/net/wireless/rsi/rsi_91x_hal.c | 7 ++
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 71 +++++++++++++-
drivers/net/wireless/rsi/rsi_91x_main.c | 2 +
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 104 ++++++++++++++++++--
drivers/net/wireless/rsi/rsi_91x_ps.c | 146 ++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 +-
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 40 +++++---
drivers/net/wireless/rsi/rsi_main.h | 11 ++-
drivers/net/wireless/rsi/rsi_mgmt.h | 52 ++++++++++
drivers/net/wireless/rsi/rsi_ps.h | 64 ++++++++++++
drivers/net/wireless/rsi/rsi_sdio.h | 3 +-
12 files changed, 474 insertions(+), 29 deletions(-)
create mode 100644 drivers/net/wireless/rsi/rsi_91x_ps.c
create mode 100644 drivers/net/wireless/rsi/rsi_ps.h

--
2.7.4


2017-08-03 14:33:52

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 8/8] rsi: RTS threshold configuration

From: Karun Eagalapati <[email protected]>

Provision is added for configuring RTS threshold by sending
vap dynamic update frame to firmware.

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 9 +++++++++
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 31 +++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_main.h | 1 +
drivers/net/wireless/rsi/rsi_mgmt.h | 14 +++++++++++++
4 files changed, 55 insertions(+)

diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 6b833c4..210ad79 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -497,6 +497,15 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw,
spin_unlock_irqrestore(&adapter->ps_lock, flags);
}

+ /* RTS threshold */
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ rsi_dbg(INFO_ZONE, "RTS threshold\n");
+ if ((common->rts_threshold) <= IEEE80211_MAX_RTS_THRESHOLD) {
+ rsi_dbg(INFO_ZONE,
+ "%s: Sending vap updates....\n", __func__);
+ status = rsi_send_vap_dynamic_update(common);
+ }
+ }
mutex_unlock(&common->mutex);

return status;
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index e5fe443..f93499d0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1058,6 +1058,37 @@ int rsi_send_radio_params_update(struct rsi_common *common)
return rsi_send_internal_mgmt_frame(common, skb);
}

+/* This function programs the threshold. */
+int rsi_send_vap_dynamic_update(struct rsi_common *common)
+{
+ struct sk_buff *skb;
+ struct rsi_dynamic_s *dynamic_frame;
+
+ rsi_dbg(MGMT_TX_ZONE,
+ "%s: Sending vap update indication frame\n", __func__);
+
+ skb = dev_alloc_skb(sizeof(struct rsi_dynamic_s));
+ if (!skb)
+ return -ENOMEM;
+
+ memset(skb->data, 0, sizeof(struct rsi_dynamic_s));
+ dynamic_frame = (struct rsi_dynamic_s *)skb->data;
+ rsi_set_len_qno(&dynamic_frame->desc_dword0.len_qno,
+ sizeof(dynamic_frame->frame_body), RSI_WIFI_MGMT_Q);
+
+ 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 =
+ cpu_to_le16(RSI_DEF_KEEPALIVE);
+ dynamic_frame->desc_dword3.sta_id = 0; /* vap id */
+
+ skb_put(skb, sizeof(struct rsi_dynamic_s));
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
/**
* rsi_compare() - This function is used to compare two integers
* @a: pointer to the first integer
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index d2cc47e..d05b5e0 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -58,6 +58,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define IEEE80211_ADDR_LEN 6
#define FRAME_DESC_SZ 16
#define MIN_802_11_HDR_LEN 24
+#define RSI_DEF_KEEPALIVE 90

#define DATA_QUEUE_WATER_MARK 400
#define MIN_DATA_QUEUE_WATER_MARK 300
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index b22103f..201a465 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -239,6 +239,7 @@ enum cmd_frame_type {
CW_MODE_REQ,
PER_CMD_PKT,
ANT_SEL_FRAME = 0x20,
+ VAP_DYNAMIC_UPDATE = 0x27,
COMMON_DEV_CONFIG = 0x28,
RADIO_PARAMS_UPDATE = 0x29
};
@@ -374,6 +375,18 @@ struct rsi_ant_sel_frame {
__le32 reserved2;
} __packed;

+struct rsi_dynamic_s {
+ struct rsi_cmd_desc_dword0 desc_dword0;
+ struct rsi_cmd_desc_dword1 desc_dword1;
+ struct rsi_cmd_desc_dword2 desc_dword2;
+ struct rsi_cmd_desc_dword3 desc_dword3;
+ struct framebody {
+ __le16 data_rate;
+ __le16 mgmt_rate;
+ __le16 keep_alive_period;
+ } frame_body;
+} __packed;
+
/* Key descriptor flags */
#define RSI_KEY_TYPE_BROADCAST BIT(1)
#define RSI_WEP_KEY BIT(2)
@@ -585,6 +598,7 @@ int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len,
u8 key_type, u8 key_id, u32 cipher);
int rsi_set_channel(struct rsi_common *common,
struct ieee80211_channel *channel);
+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, u8 status,
const u8 *bssid, u8 qos_enable, u16 aid);
--
2.7.4

2017-08-03 14:33:34

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 5/8] rsi: rename sdio_read_buffer_status_register

From: Karun Eagalapati <[email protected]>

rsi_sdio_check_buffer_status would be the appropriate name
for this function as we are checking hardware buffers
availability status.

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 +-
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 13 +++----------
drivers/net/wireless/rsi/rsi_sdio.h | 2 +-
3 files changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 42d558b..742f6cd 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -860,7 +860,7 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter,
sdio_release_host(pfunction);

adapter->determine_event_timeout = rsi_sdio_determine_event_timeout;
- adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register;
+ adapter->check_hw_queue_status = rsi_sdio_check_buffer_status;

#ifdef CONFIG_RSI_DEBUGFS
adapter->num_debugfs_entries = MAX_DEBUGFS_ENTRIES;
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index b3f7adc..9b94ba7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -323,17 +323,10 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)
} while (1);
}

-/**
- * rsi_sdio_read_buffer_status_register() - This function is used to the read
- * buffer status register and set
- * relevant fields in
- * rsi_91x_sdiodev struct.
- * @adapter: Pointer to the driver hw structure.
- * @q_num: The Q number whose status is to be found.
- *
- * Return: status: -1 on failure or else queue full/stop is indicated.
+/* This function is used to read buffer status register and
+ * set relevant fields in rsi_91x_sdiodev struct.
*/
-int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num)
+int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num)
{
struct rsi_common *common = adapter->priv;
struct rsi_91x_sdiodev *dev =
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index 3cf6756..9239fbe 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -127,5 +127,5 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr,
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_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num);
+int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num);
#endif
--
2.7.4

2017-08-03 14:33:25

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 4/8] rsi: add support for U-APSD power save

From: Karun Eagalapati <[email protected]>

This patch adds support for U-APSD power save. Configuration
frame is downloaded to firmware with default settings and
support is advertised to mac80211

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 19 +++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 3 +++
drivers/net/wireless/rsi/rsi_91x_ps.c | 17 +++++++++++++++++
drivers/net/wireless/rsi/rsi_main.h | 1 +
drivers/net/wireless/rsi/rsi_mgmt.h | 6 ++++++
5 files changed, 46 insertions(+)

diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 16a0fd0..6b833c4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -327,6 +327,7 @@ static int rsi_mac80211_add_interface(struct ieee80211_hw *hw,
struct rsi_common *common = adapter->priv;
int ret = -EOPNOTSUPP;

+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
mutex_lock(&common->mutex);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
@@ -560,6 +561,16 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->aid);
adapter->ps_info.dtim_interval_duration = bss->dtim_period;
adapter->ps_info.listen_interval = conf->listen_interval;
+
+ /* If U-APSD is updated, send ps parameters to firmware */
+ if (bss->assoc) {
+ if (common->uapsd_bitmap) {
+ rsi_dbg(INFO_ZONE, "Configuring UAPSD\n");
+ rsi_conf_uapsd(adapter);
+ }
+ } else {
+ common->uapsd_bitmap = 0;
+ }
}

if (changed & BSS_CHANGED_CQM) {
@@ -641,6 +652,12 @@ static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw,
memcpy(&common->edca_params[idx],
params,
sizeof(struct ieee80211_tx_queue_params));
+
+ if (params->uapsd)
+ common->uapsd_bitmap |= idx;
+ else
+ common->uapsd_bitmap &= (~idx);
+
mutex_unlock(&common->mutex);

return 0;
@@ -1311,6 +1328,8 @@ int rsi_mac80211_attach(struct rsi_common *common)

hw->max_rates = 1;
hw->max_rate_tries = MAX_RETRIES;
+ hw->uapsd_queues = RSI_IEEE80211_UAPSD_QUEUES;
+ hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;

hw->max_tx_aggregation_subframes = 6;
rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index f76b346..e5fe443 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1425,6 +1425,9 @@ int rsi_send_ps_request(struct rsi_hw *adapter, bool enable)
ps->desc.desc_dword0.len_qno |= cpu_to_le16(RSI_PS_DISABLE_IND);
ps->desc.desc_dword3.token = cpu_to_le16(RSI_WAKEUP_REQUEST);
}
+
+ ps->ps_uapsd_acs = common->uapsd_bitmap;
+
ps->ps_sleep.sleep_type = ps_info->sleep_type;
ps->ps_sleep.num_bcns_per_lis_int =
cpu_to_le16(ps_info->num_bcns_per_lis_int);
diff --git a/drivers/net/wireless/rsi/rsi_91x_ps.c b/drivers/net/wireless/rsi/rsi_91x_ps.c
index 25e8f85..48c79f0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_ps.c
+++ b/drivers/net/wireless/rsi/rsi_91x_ps.c
@@ -105,6 +105,22 @@ 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)
+{
+ int ret;
+
+ if (adapter->ps_state != PS_ENABLED)
+ return;
+
+ ret = rsi_send_ps_request(adapter, false);
+ if (!ret)
+ ret = rsi_send_ps_request(adapter, true);
+ if (ret)
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to send PS request to device\n",
+ __func__);
+}
+
int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg)
{
u16 cfm_type = get_unaligned_le16(msg + PS_CONFIRM_INDEX);
@@ -127,3 +143,4 @@ int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg)

return 0;
}
+
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 9aada0b..d2cc47e 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -243,6 +243,7 @@ struct rsi_common {
u16 oper_mode;
u8 lp_ps_handshake_mode;
u8 ulp_ps_handshake_mode;
+ u8 uapsd_bitmap;
u8 rf_power_val;
u8 wlan_rf_power_mode;
u8 obm_ant_sel_val;
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index c5d114d..b22103f 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -181,6 +181,12 @@
#define RSI_SLEEP_REQUEST 1
#define RSI_WAKEUP_REQUEST 2

+#define RSI_IEEE80211_UAPSD_QUEUES \
+ (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO | \
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+
enum opmode {
STA_OPMODE = 1,
AP_OPMODE = 2
--
2.7.4

2017-08-03 14:33:10

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 2/8] rsi: update set_antenna command frame

From: Pavani Muthyala <[email protected]>

TX command frame set_antenna is modified to use common
descriptor structure. Also it's subframe type is set.

Signed-off-by: Pavani Muthyala <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 13 +++++++------
drivers/net/wireless/rsi/rsi_mgmt.h | 11 +++++++++++
2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index c488f4b..e00d4ed 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1407,7 +1407,7 @@ int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word)
*/
int rsi_set_antenna(struct rsi_common *common, u8 antenna)
{
- struct rsi_mac_frame *cmd_frame;
+ struct rsi_ant_sel_frame *ant_sel_frame;
struct sk_buff *skb;

skb = dev_alloc_skb(FRAME_DESC_SZ);
@@ -1418,12 +1418,13 @@ int rsi_set_antenna(struct rsi_common *common, u8 antenna)
}

memset(skb->data, 0, FRAME_DESC_SZ);
- cmd_frame = (struct rsi_mac_frame *)skb->data;
-
- cmd_frame->desc_word[1] = cpu_to_le16(ANT_SEL_FRAME);
- cmd_frame->desc_word[3] = cpu_to_le16(antenna & 0x00ff);
- cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);

+ ant_sel_frame = (struct rsi_ant_sel_frame *)skb->data;
+ ant_sel_frame->desc_dword0.frame_type = ANT_SEL_FRAME;
+ ant_sel_frame->sub_frame_type = ANTENNA_SEL_TYPE;
+ ant_sel_frame->ant_value = cpu_to_le16(antenna & ANTENNA_MASK_VALUE);
+ rsi_set_len_qno(&ant_sel_frame->desc_dword0.len_qno,
+ 0, RSI_WIFI_MGMT_Q);
skb_put(skb, FRAME_DESC_SZ);

return rsi_send_internal_mgmt_frame(common, skb);
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index cb0b17e..1060edc 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -155,6 +155,8 @@

#define ANTENNA_SEL_INT 0x02 /* RF_OUT_2 / Integerated */
#define ANTENNA_SEL_UFL 0x03 /* RF_OUT_1 / U.FL */
+#define ANTENNA_MASK_VALUE 0x00ff
+#define ANTENNA_SEL_TYPE 1

/* Rx filter word definitions */
#define PROMISCOUS_MODE BIT(0)
@@ -348,6 +350,15 @@ struct rsi_vap_caps {
__le16 beacon_miss_threshold;
} __packed;

+struct rsi_ant_sel_frame {
+ struct rsi_cmd_desc_dword0 desc_dword0;
+ u8 reserved;
+ u8 sub_frame_type;
+ __le16 ant_value;
+ __le32 reserved1;
+ __le32 reserved2;
+} __packed;
+
/* Key descriptor flags */
#define RSI_KEY_TYPE_BROADCAST BIT(1)
#define RSI_WEP_KEY BIT(2)
--
2.7.4

2017-08-03 14:33:41

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 6/8] rsi: buffer full check optimization

From: Karun Eagalapati <[email protected]>

We get buffer full event from firmware whenever Tx queue is full
Host should stop writing packets after this and resume after
buffer free event.
Buffer status checking is optimized for once in 4 times if
BUFF_FULL condition is not set, otherwise once for every
packet.

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 16 +++++++++++++++-
drivers/net/wireless/rsi/rsi_sdio.h | 1 +
2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 9b94ba7..94a9fcd 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -271,6 +271,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)
"%s: ==> BUFFER_AVAILABLE <==\n",
__func__);
dev->rx_info.buf_available_counter++;
+ dev->buff_status_updated = true;
break;

case FIRMWARE_ASSERT_IND:
@@ -333,7 +334,14 @@ int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num)
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
u8 buf_status = 0;
int status = 0;
+ static int counter = 4;

+ if (!dev->buff_status_updated && counter) {
+ counter--;
+ goto out;
+ }
+
+ dev->buff_status_updated = false;
status = rsi_sdio_read_register(common->priv,
RSI_DEVICE_BUFFER_STATUS_REGISTER,
&buf_status);
@@ -368,10 +376,16 @@ int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num)
dev->rx_info.semi_buffer_full = false;
}

+ if (dev->rx_info.mgmt_buffer_full || dev->rx_info.buf_full_counter)
+ counter = 1;
+ else
+ counter = 4;
+
+out:
if ((q_num == MGMT_SOFT_Q) && (dev->rx_info.mgmt_buffer_full))
return QUEUE_FULL;

- if (dev->rx_info.buffer_full)
+ if ((q_num < MGMT_SOFT_Q) && (dev->rx_info.buffer_full))
return QUEUE_FULL;

return QUEUE_NOT_FULL;
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index 9239fbe..95e4bed 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -114,6 +114,7 @@ struct rsi_91x_sdiodev {
u8 prev_desc[16];
u16 tx_blk_size;
u8 write_fail;
+ bool buff_status_updated;
};

void rsi_interrupt_handler(struct rsi_hw *adapter);
--
2.7.4

2017-08-03 14:33:03

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 1/8] rsi: add support for rf-kill functionality

From: Pavani Muthyala <[email protected]>

This patch implements rfkill_poll handler. Also, necessary changes
are done in interface up and down handler to support rfkill
functionality.

Signed-off-by: Pavani Muthyala <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index c91d6ef..193f922 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -279,11 +279,12 @@ static int rsi_mac80211_start(struct ieee80211_hw *hw)
struct rsi_hw *adapter = hw->priv;
struct rsi_common *common = adapter->priv;

+ rsi_dbg(ERR_ZONE, "===> Interface UP <===\n");
mutex_lock(&common->mutex);
common->iface_down = false;
- mutex_unlock(&common->mutex);
-
+ wiphy_rfkill_start_polling(hw->wiphy);
rsi_send_rx_filter_frame(common, 0);
+ mutex_unlock(&common->mutex);

return 0;
}
@@ -299,8 +300,10 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw)
struct rsi_hw *adapter = hw->priv;
struct rsi_common *common = adapter->priv;

+ rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n");
mutex_lock(&common->mutex);
common->iface_down = true;
+ wiphy_rfkill_stop_polling(hw->wiphy);

/* Block all rx frames */
rsi_send_rx_filter_frame(common, 0xffff);
@@ -1214,6 +1217,19 @@ static void rsi_reg_notify(struct wiphy *wiphy,
mutex_unlock(&common->mutex);
}

+static void rsi_mac80211_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+ if (common->fsm_state != FSM_MAC_INIT_DONE)
+ wiphy_rfkill_set_hw_state(hw->wiphy, true);
+ else
+ wiphy_rfkill_set_hw_state(hw->wiphy, false);
+ mutex_unlock(&common->mutex);
+}
+
static struct ieee80211_ops mac80211_ops = {
.tx = rsi_mac80211_tx,
.start = rsi_mac80211_start,
@@ -1232,6 +1248,7 @@ static struct ieee80211_ops mac80211_ops = {
.sta_remove = rsi_mac80211_sta_remove,
.set_antenna = rsi_mac80211_set_antenna,
.get_antenna = rsi_mac80211_get_antenna,
+ .rfkill_poll = rsi_mac80211_rfkill_poll,
};

/**
--
2.7.4

2017-08-03 14:33:47

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 7/8] rsi: buffer available interrupt handling

From: Karun Eagalapati <[email protected]>

BUFFER_AVAILABLE interrupt is sent by firmware to indicate
change in buffer status. We should check buffer status while
handling this interrupt. Currently buffer status is checked
only while dequeueing packets. This patch fixes a data
traffic stuck problem observed occasionally.

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 94a9fcd..8e2a95c 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -259,10 +259,12 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)

switch (isr_type) {
case BUFFER_AVAILABLE:
- dev->rx_info.watch_bufferfull_count = 0;
- dev->rx_info.buffer_full = false;
- dev->rx_info.semi_buffer_full = false;
- dev->rx_info.mgmt_buffer_full = false;
+ status = rsi_sdio_check_buffer_status(adapter,
+ 0);
+ if (status < 0)
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to check buffer status\n",
+ __func__);
rsi_sdio_ack_intr(common->priv,
(1 << PKT_BUFF_AVAILABLE));
rsi_set_event(&common->tx_thread.event);
@@ -270,7 +272,6 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)
rsi_dbg(ISR_ZONE,
"%s: ==> BUFFER_AVAILABLE <==\n",
__func__);
- dev->rx_info.buf_available_counter++;
dev->buff_status_updated = true;
break;

--
2.7.4

2017-08-08 11:46:26

by Kalle Valo

[permalink] [raw]
Subject: Re: [v2,1/8] rsi: add support for rf-kill functionality

Amitkumar Karwar <[email protected]> wrote:

> From: Pavani Muthyala <[email protected]>
>
> This patch implements rfkill_poll handler. Also, necessary changes
> are done in interface up and down handler to support rfkill
> functionality.
>
> Signed-off-by: Pavani Muthyala <[email protected]>
> Signed-off-by: Amitkumar Karwar <[email protected]>

8 patches applied to wireless-drivers-next.git, thanks.

edba3532c652 rsi: add support for rf-kill functionality
588349a1fe3b rsi: update set_antenna command frame
ce86893fa8d8 rsi: add support for legacy power save
db07971d085f rsi: add support for U-APSD power save
23e414cca1f7 rsi: rename sdio_read_buffer_status_register
d64dd2a172d8 rsi: buffer full check optimization
67c52a4dafce rsi: buffer available interrupt handling
80a88ecf3bcc rsi: RTS threshold configuration

--
https://patchwork.kernel.org/patch/9879251/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2017-08-03 14:33:20

by Amitkumar Karwar

[permalink] [raw]
Subject: [v2 3/8] rsi: add support for legacy power save

From: Karun Eagalapati <[email protected]>

This patch adds support for legacy power save. Necessary
configuration frames are downloaded to firmware when power save
is enabled/disabled

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/Makefile | 1 +
drivers/net/wireless/rsi/rsi_91x_hal.c | 7 ++
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 22 +++++
drivers/net/wireless/rsi/rsi_91x_main.c | 2 +
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 57 +++++++++++-
drivers/net/wireless/rsi/rsi_91x_ps.c | 129 ++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_main.h | 9 +-
drivers/net/wireless/rsi/rsi_mgmt.h | 21 +++++
drivers/net/wireless/rsi/rsi_ps.h | 64 ++++++++++++++
9 files changed, 309 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/wireless/rsi/rsi_91x_ps.c
create mode 100644 drivers/net/wireless/rsi/rsi_ps.h

diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile
index a475c81..ebb8996 100644
--- a/drivers/net/wireless/rsi/Makefile
+++ b/drivers/net/wireless/rsi/Makefile
@@ -3,6 +3,7 @@ rsi_91x-y += rsi_91x_core.o
rsi_91x-y += rsi_91x_mac80211.o
rsi_91x-y += rsi_91x_mgmt.o
rsi_91x-y += rsi_91x_hal.o
+rsi_91x-y += rsi_91x_ps.o
rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o

rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index b0a7a15..4addcc0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -111,6 +111,8 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
/* This function prepares descriptor for given data packet */
static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_vif *vif;
struct ieee80211_hdr *wh = NULL;
struct ieee80211_tx_info *info;
struct skb_info *tx_params;
@@ -148,6 +150,7 @@ 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 = (le16_to_cpu(wh->seq_ctrl) >> 4);
+ vif = adapter->vifs[0];

data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ;

@@ -156,6 +159,10 @@ 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) &&
+ (adapter->ps_state == PS_ENABLED))
+ wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE);
+
if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
(common->secinfo.security_enable)) {
if (rsi_is_cipher_wep(common))
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 193f922..16a0fd0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -18,6 +18,7 @@
#include "rsi_debugfs.h"
#include "rsi_mgmt.h"
#include "rsi_common.h"
+#include "rsi_ps.h"

static const struct ieee80211_channel rsi_2ghz_channels[] = {
{ .band = NL80211_BAND_2GHZ, .center_freq = 2412,
@@ -467,6 +468,8 @@ 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;

mutex_lock(&common->mutex);
@@ -480,6 +483,19 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw,
status = rsi_config_power(hw);
}

+ /* Power save parameters */
+ if ((changed & IEEE80211_CONF_CHANGE_PS) &&
+ (vif->type == NL80211_IFTYPE_STATION)) {
+ unsigned long flags;
+
+ 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);
+ }
+
mutex_unlock(&common->mutex);

return status;
@@ -522,6 +538,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw,
{
struct rsi_hw *adapter = hw->priv;
struct rsi_common *common = adapter->priv;
+ struct ieee80211_bss_conf *bss = &vif->bss_conf;
+ struct ieee80211_conf *conf = &hw->conf;
u16 rx_filter_word = 0;

mutex_lock(&common->mutex);
@@ -540,6 +558,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid,
bss_conf->qos,
bss_conf->aid);
+ adapter->ps_info.dtim_interval_duration = bss->dtim_period;
+ adapter->ps_info.listen_interval = conf->listen_interval;
}

if (changed & BSS_CHANGED_CQM) {
@@ -1283,6 +1303,8 @@ int rsi_mac80211_attach(struct rsi_common *common)
ieee80211_hw_set(hw, SIGNAL_DBM);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);

hw->queues = MAX_HW_QUEUES;
hw->extra_tx_headroom = RSI_NEEDED_HEADROOM;
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index bb0febb..3e1e808 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -231,6 +231,8 @@ struct rsi_hw *rsi_91x_init(void)
goto err;
}

+ rsi_default_ps_params(adapter);
+ spin_lock_init(&adapter->ps_lock);
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 e00d4ed..f76b346 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -17,6 +17,7 @@
#include <linux/etherdevice.h>
#include "rsi_mgmt.h"
#include "rsi_common.h"
+#include "rsi_ps.h"

static struct bootup_params boot_params_20 = {
.magic_number = cpu_to_le16(0x5aa5),
@@ -1396,6 +1397,58 @@ 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)
+{
+ struct rsi_common *common = adapter->priv;
+ struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf;
+ struct rsi_request_ps *ps;
+ struct rsi_ps_info *ps_info;
+ struct sk_buff *skb;
+ int frame_len = sizeof(*ps);
+
+ skb = dev_alloc_skb(frame_len);
+ if (!skb)
+ return -ENOMEM;
+ memset(skb->data, 0, frame_len);
+
+ ps = (struct rsi_request_ps *)skb->data;
+ ps_info = &adapter->ps_info;
+
+ rsi_set_len_qno(&ps->desc.desc_dword0.len_qno,
+ (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q);
+ ps->desc.desc_dword0.frame_type = WAKEUP_SLEEP_REQUEST;
+ if (enable) {
+ ps->ps_sleep.enable = RSI_PS_ENABLE;
+ ps->desc.desc_dword3.token = cpu_to_le16(RSI_SLEEP_REQUEST);
+ } else {
+ ps->ps_sleep.enable = RSI_PS_DISABLE;
+ ps->desc.desc_dword0.len_qno |= cpu_to_le16(RSI_PS_DISABLE_IND);
+ ps->desc.desc_dword3.token = cpu_to_le16(RSI_WAKEUP_REQUEST);
+ }
+ ps->ps_sleep.sleep_type = ps_info->sleep_type;
+ ps->ps_sleep.num_bcns_per_lis_int =
+ cpu_to_le16(ps_info->num_bcns_per_lis_int);
+ ps->ps_sleep.sleep_duration =
+ cpu_to_le32(ps_info->deep_sleep_wakeup_period);
+
+ if (bss->assoc)
+ ps->ps_sleep.connected_sleep = RSI_CONNECTED_SLEEP;
+ else
+ ps->ps_sleep.connected_sleep = RSI_DEEP_SLEEP;
+
+ ps->ps_listen_interval = cpu_to_le32(ps_info->listen_interval);
+ ps->ps_dtim_interval_duration =
+ cpu_to_le32(ps_info->dtim_interval_duration);
+
+ if (ps_info->listen_interval > ps_info->dtim_interval_duration)
+ ps->ps_listen_interval = cpu_to_le32(RSI_PS_DISABLE);
+
+ ps->ps_num_dtim_intervals = cpu_to_le16(ps_info->num_dtims_per_sleep);
+ skb_put(skb, frame_len);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
/**
* rsi_set_antenna() - This fuction send antenna configuration request
* to device
@@ -1569,7 +1622,9 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
return 0;
}
break;
-
+ case WAKEUP_SLEEP_REQUEST:
+ rsi_dbg(INFO_ZONE, "Wakeup/Sleep confirmation.\n");
+ return rsi_handle_ps_confirm(adapter, msg);
default:
rsi_dbg(INFO_ZONE, "%s: Invalid TA confirm pkt received\n",
__func__);
diff --git a/drivers/net/wireless/rsi/rsi_91x_ps.c b/drivers/net/wireless/rsi/rsi_91x_ps.c
new file mode 100644
index 0000000..25e8f85
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_ps.c
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if.h>
+#include <linux/version.h>
+#include "rsi_debugfs.h"
+#include "rsi_mgmt.h"
+#include "rsi_common.h"
+#include "rsi_ps.h"
+
+char *str_psstate(enum ps_state state)
+{
+ switch (state) {
+ case PS_NONE:
+ return "PS_NONE";
+ case PS_DISABLE_REQ_SENT:
+ return "PS_DISABLE_REQ_SENT";
+ case PS_ENABLE_REQ_SENT:
+ return "PS_ENABLE_REQ_SENT";
+ case PS_ENABLED:
+ return "PS_ENABLED";
+ default:
+ return "INVALID_STATE";
+ }
+ return "INVALID_STATE";
+}
+
+static inline void rsi_modify_ps_state(struct rsi_hw *adapter,
+ enum ps_state nstate)
+{
+ rsi_dbg(INFO_ZONE, "PS state changed %s => %s\n",
+ str_psstate(adapter->ps_state),
+ str_psstate(nstate));
+
+ adapter->ps_state = nstate;
+}
+
+void rsi_default_ps_params(struct rsi_hw *adapter)
+{
+ struct rsi_ps_info *ps_info = &adapter->ps_info;
+
+ ps_info->enabled = true;
+ ps_info->sleep_type = RSI_SLEEP_TYPE_LP;
+ ps_info->tx_threshold = 0;
+ ps_info->rx_threshold = 0;
+ ps_info->tx_hysterisis = 0;
+ ps_info->rx_hysterisis = 0;
+ ps_info->monitor_interval = 0;
+ ps_info->listen_interval = RSI_DEF_LISTEN_INTERVAL;
+ ps_info->num_bcns_per_lis_int = 0;
+ ps_info->dtim_interval_duration = 0;
+ ps_info->num_dtims_per_sleep = 0;
+ ps_info->deep_sleep_wakeup_period = RSI_DEF_DS_WAKEUP_PERIOD;
+}
+
+void rsi_enable_ps(struct rsi_hw *adapter)
+{
+ if (adapter->ps_state != PS_NONE) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Cannot accept enable PS in %s state\n",
+ __func__, str_psstate(adapter->ps_state));
+ return;
+ }
+
+ if (rsi_send_ps_request(adapter, true)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to send PS request to device\n",
+ __func__);
+ return;
+ }
+
+ rsi_modify_ps_state(adapter, PS_ENABLE_REQ_SENT);
+}
+
+void rsi_disable_ps(struct rsi_hw *adapter)
+{
+ if (adapter->ps_state != PS_ENABLED) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Cannot accept disable PS in %s state\n",
+ __func__, str_psstate(adapter->ps_state));
+ return;
+ }
+
+ if (rsi_send_ps_request(adapter, false)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to send PS request to device\n",
+ __func__);
+ return;
+ }
+
+ rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT);
+}
+
+int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg)
+{
+ u16 cfm_type = get_unaligned_le16(msg + PS_CONFIRM_INDEX);
+
+ switch (cfm_type) {
+ case RSI_SLEEP_REQUEST:
+ if (adapter->ps_state == PS_ENABLE_REQ_SENT)
+ rsi_modify_ps_state(adapter, PS_ENABLED);
+ break;
+ case RSI_WAKEUP_REQUEST:
+ if (adapter->ps_state == PS_DISABLE_REQ_SENT)
+ rsi_modify_ps_state(adapter, PS_NONE);
+ break;
+ default:
+ rsi_dbg(ERR_ZONE,
+ "Invalid PS confirm type %x in state %s\n",
+ cfm_type, str_psstate(adapter->ps_state));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 6a8e8e7..9aada0b 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -21,6 +21,10 @@
#include <linux/skbuff.h>
#include <net/mac80211.h>

+struct rsi_hw;
+
+#include "rsi_ps.h"
+
#define ERR_ZONE BIT(0) /* For Error Msgs */
#define INFO_ZONE BIT(1) /* For General Status Msgs */
#define INIT_ZONE BIT(2) /* For Driver Init Seq Msgs */
@@ -177,8 +181,6 @@ enum rsi_dfs_regions {
RSI_REGION_WORLD
};

-struct rsi_hw;
-
struct rsi_common {
struct rsi_hw *priv;
struct vif_priv vif_info[RSI_MAX_VIFS];
@@ -282,6 +284,9 @@ struct rsi_hw {

enum host_intf rsi_host_intf;
u16 block_size;
+ enum ps_state ps_state;
+ struct rsi_ps_info ps_info;
+ spinlock_t ps_lock; /*To protect power save config*/
u32 usb_buffer_status_reg;
#ifdef CONFIG_RSI_DEBUGFS
struct rsi_debugfs *dfsentry;
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index 1060edc..c5d114d 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -69,6 +69,7 @@
#define RSI_QOS_ENABLE BIT(12)
#define RSI_REKEY_PURPOSE BIT(13)
#define RSI_ENCRYPT_PKT BIT(15)
+#define RSI_SET_PS_ENABLE BIT(12)

#define RSI_CMDDESC_40MHZ BIT(4)
#define RSI_CMDDESC_UPPER_20_ENABLE BIT(5)
@@ -172,6 +173,14 @@
#define RSI_BEACON_INTERVAL 200
#define RSI_DTIM_COUNT 2

+#define RSI_PS_DISABLE_IND BIT(15)
+#define RSI_PS_ENABLE 1
+#define RSI_PS_DISABLE 0
+#define RSI_DEEP_SLEEP 1
+#define RSI_CONNECTED_SLEEP 2
+#define RSI_SLEEP_REQUEST 1
+#define RSI_WAKEUP_REQUEST 2
+
enum opmode {
STA_OPMODE = 1,
AP_OPMODE = 2
@@ -519,6 +528,18 @@ struct rsi_eeprom_read_frame {
__le16 reserved3;
} __packed;

+struct rsi_request_ps {
+ struct rsi_cmd_desc desc;
+ struct ps_sleep_params ps_sleep;
+ u8 ps_mimic_support;
+ u8 ps_uapsd_acs;
+ u8 ps_uapsd_wakeup_period;
+ u8 reserved;
+ __le32 ps_listen_interval;
+ __le32 ps_dtim_interval_duration;
+ __le16 ps_num_dtim_intervals;
+} __packed;
+
static inline u32 rsi_get_queueno(u8 *addr, u16 offset)
{
return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12;
diff --git a/drivers/net/wireless/rsi/rsi_ps.h b/drivers/net/wireless/rsi/rsi_ps.h
new file mode 100644
index 0000000..d847587
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_ps.h
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_PS_H__
+#define __RSI_PS_H__
+
+#define PS_CONFIRM_INDEX 12
+#define RSI_DEF_DS_WAKEUP_PERIOD 200
+#define RSI_DEF_LISTEN_INTERVAL 200
+#define RSI_SLEEP_TYPE_LP 1
+
+enum ps_state {
+ PS_NONE = 0,
+ PS_ENABLE_REQ_SENT = 1,
+ PS_DISABLE_REQ_SENT = 2,
+ PS_ENABLED = 3
+};
+
+struct ps_sleep_params {
+ u8 enable;
+ u8 sleep_type;
+ u8 connected_sleep;
+ u8 reserved1;
+ __le16 num_bcns_per_lis_int;
+ __le16 wakeup_type;
+ __le32 sleep_duration;
+} __packed;
+
+struct rsi_ps_info {
+ u8 enabled;
+ u8 sleep_type;
+ u8 tx_threshold;
+ u8 rx_threshold;
+ u8 tx_hysterisis;
+ u8 rx_hysterisis;
+ u16 monitor_interval;
+ u32 listen_interval;
+ u16 num_bcns_per_lis_int;
+ u32 dtim_interval_duration;
+ u16 num_dtims_per_sleep;
+ u32 deep_sleep_wakeup_period;
+} __packed;
+
+char *str_psstate(enum ps_state state);
+void rsi_enable_ps(struct rsi_hw *adapter);
+void rsi_disable_ps(struct rsi_hw *adapter);
+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);
+#endif
--
2.7.4