From e0d0ae8a4304ce6be488570d085bef278fe941dd Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 6 Jul 2017 20:07:04 +0530 Subject: rsi: use BUILD_BUG_ON check for fsm_state Whenever new fsm_state enum element is added, fsm_state array also needs to be updated. If this change is missed, we may end up doing invalid access in array. BUILD_BUG_ON check will help to avoid this problem. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_main.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index f3985250b593..72675ebcd454 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -40,7 +40,9 @@ enum RSI_FSM_STATES { FSM_RESET_MAC_SENT, FSM_RADIO_CAPS_SENT, FSM_BB_RF_PROG_SENT, - FSM_MAC_INIT_DONE + FSM_MAC_INIT_DONE, + + NUM_FSM_STATES }; extern u32 rsi_zone_enabled; -- cgit v1.2.3 From 09cfb41f35799af91372105a40c0d173e4fef6e5 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 6 Jul 2017 20:07:05 +0530 Subject: rsi: changes in eeprom read frame EEPROM read frame is sent during device initialization to read mac address. The format of the frame is modified in firmware to include eeprom length and offset. This frame does not return firmware version now. Also same frame is sent again to read rf type and band information. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_debugfs.c | 1 + drivers/net/wireless/rsi/rsi_91x_mgmt.c | 90 ++++++++++++++++++++---------- drivers/net/wireless/rsi/rsi_main.h | 16 ++++++ drivers/net/wireless/rsi/rsi_mgmt.h | 19 ++++++- 4 files changed, 96 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index f3b91b656351..e98eb55c26cc 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -130,6 +130,7 @@ static int rsi_stats_read(struct seq_file *seq, void *data) "FSM_COMMON_DEV_PARAMS_SENT", "FSM_BOOT_PARAMS_SENT", "FSM_EEPROM_READ_MAC_ADDR", + "FSM_EEPROM_READ_RF_TYPE", "FSM_RESET_MAC_SENT", "FSM_RADIO_CAPS_SENT", "FSM_BB_RF_PROG_SENT", diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index d4d365b5d2d6..ebd1e5647f03 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1276,7 +1276,8 @@ void rsi_inform_bss_status(struct rsi_common *common, */ static int rsi_eeprom_read(struct rsi_common *common) { - struct rsi_mac_frame *mgmt_frame; + struct rsi_eeprom_read_frame *mgmt_frame; + struct rsi_hw *adapter = common->priv; struct sk_buff *skb; rsi_dbg(MGMT_TX_ZONE, "%s: Sending EEPROM read req frame\n", __func__); @@ -1289,18 +1290,21 @@ static int rsi_eeprom_read(struct rsi_common *common) } memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; + mgmt_frame = (struct rsi_eeprom_read_frame *)skb->data; /* FrameType */ - mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE); - mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + rsi_set_len_qno(&mgmt_frame->len_qno, 0, RSI_WIFI_MGMT_Q); + mgmt_frame->pkt_type = EEPROM_READ; + /* Number of bytes to read */ - mgmt_frame->desc_word[3] = cpu_to_le16(ETH_ALEN + - WLAN_MAC_MAGIC_WORD_LEN + - WLAN_HOST_MODE_LEN + - WLAN_FW_VERSION_LEN); + mgmt_frame->pkt_info = + cpu_to_le32((adapter->eeprom.length << RSI_EEPROM_LEN_OFFSET) & + RSI_EEPROM_LEN_MASK); + mgmt_frame->pkt_info |= cpu_to_le32((3 << RSI_EEPROM_HDR_SIZE_OFFSET) & + RSI_EEPROM_HDR_SIZE_MASK); + /* Address to read */ - mgmt_frame->desc_word[4] = cpu_to_le16(WLAN_MAC_EEPROM_ADDR); + mgmt_frame->eeprom_offset = cpu_to_le32(adapter->eeprom.offset); skb_put(skb, FRAME_DESC_SZ); @@ -1426,19 +1430,25 @@ int rsi_set_antenna(struct rsi_common *common, u8 antenna) static int rsi_handle_ta_confirm_type(struct rsi_common *common, u8 *msg) { + struct rsi_hw *adapter = common->priv; u8 sub_type = (msg[15] & 0xff); + u16 msg_len = ((u16 *)msg)[0] & 0xfff; + u8 offset; switch (sub_type) { case BOOTUP_PARAMS_REQUEST: rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n", __func__); if (common->fsm_state == FSM_BOOT_PARAMS_SENT) { + adapter->eeprom.length = (IEEE80211_ADDR_LEN + + WLAN_MAC_MAGIC_WORD_LEN + + WLAN_HOST_MODE_LEN); + adapter->eeprom.offset = WLAN_MAC_EEPROM_ADDR; if (rsi_eeprom_read(common)) { common->fsm_state = FSM_CARD_NOT_READY; goto out; - } else { - common->fsm_state = FSM_EEPROM_READ_MAC_ADDR; } + common->fsm_state = FSM_EEPROM_READ_MAC_ADDR; } else { rsi_dbg(INFO_ZONE, "%s: Received bootup params cfm in %d state\n", @@ -1447,30 +1457,52 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, } break; - case EEPROM_READ_TYPE: + case EEPROM_READ: + rsi_dbg(FSM_ZONE, "EEPROM READ confirm received\n"); + if (msg_len <= 0) { + rsi_dbg(FSM_ZONE, + "%s: [EEPROM_READ] Invalid len %d\n", + __func__, msg_len); + goto out; + } + if (msg[16] != MAGIC_WORD) { + rsi_dbg(FSM_ZONE, + "%s: [EEPROM_READ] Invalid token\n", __func__); + common->fsm_state = FSM_CARD_NOT_READY; + goto out; + } if (common->fsm_state == FSM_EEPROM_READ_MAC_ADDR) { - if (msg[16] == MAGIC_WORD) { - u8 offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN - + WLAN_MAC_MAGIC_WORD_LEN); - memcpy(common->mac_addr, - &msg[offset], - ETH_ALEN); - memcpy(&common->fw_ver, - &msg[offset + ETH_ALEN], - sizeof(struct version_info)); - - } else { + offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN + + WLAN_MAC_MAGIC_WORD_LEN); + memcpy(common->mac_addr, &msg[offset], ETH_ALEN); + adapter->eeprom.length = + ((WLAN_MAC_MAGIC_WORD_LEN + 3) & (~3)); + adapter->eeprom.offset = WLAN_EEPROM_RFTYPE_ADDR; + if (rsi_eeprom_read(common)) { + rsi_dbg(ERR_ZONE, + "%s: Failed reading RF band\n", + __func__); common->fsm_state = FSM_CARD_NOT_READY; - break; + goto out; + } + common->fsm_state = FSM_EEPROM_READ_RF_TYPE; + } else if (common->fsm_state == FSM_EEPROM_READ_RF_TYPE) { + if ((msg[17] & 0x3) == 0x3) { + rsi_dbg(INIT_ZONE, "Dual band supported\n"); + common->band = NL80211_BAND_5GHZ; + common->num_supp_bands = 2; + } else if ((msg[17] & 0x3) == 0x1) { + rsi_dbg(INIT_ZONE, + "Only 2.4Ghz band supported\n"); + common->band = NL80211_BAND_2GHZ; + common->num_supp_bands = 1; } if (rsi_send_reset_mac(common)) goto out; - else - common->fsm_state = FSM_RESET_MAC_SENT; + common->fsm_state = FSM_RESET_MAC_SENT; } else { - rsi_dbg(ERR_ZONE, - "%s: Received eeprom mac addr in %d state\n", - __func__, common->fsm_state); + rsi_dbg(ERR_ZONE, "%s: Invalid EEPROM read type\n", + __func__); return 0; } break; diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 72675ebcd454..cbf29c36f4f4 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -37,6 +37,7 @@ enum RSI_FSM_STATES { FSM_COMMON_DEV_PARAMS_SENT, FSM_BOOT_PARAMS_SENT, FSM_EEPROM_READ_MAC_ADDR, + FSM_EEPROM_READ_RF_TYPE, FSM_RESET_MAC_SENT, FSM_RADIO_CAPS_SENT, FSM_BB_RF_PROG_SENT, @@ -177,6 +178,7 @@ struct rsi_common { /* Channel/band related */ u8 band; + u8 num_supp_bands; u8 channel_width; u16 rts_threshold; @@ -230,6 +232,19 @@ enum host_intf { RSI_HOST_INTF_USB }; +struct eepromrw_info { + u32 offset; + u32 length; + u8 write; + u16 eeprom_erase; + u8 data[480]; +}; + +struct eeprom_read { + u16 length; + u16 off_set; +}; + struct rsi_hw { struct rsi_common *priv; u8 device_model; @@ -252,6 +267,7 @@ struct rsi_hw { struct timer_list bl_cmd_timer; bool blcmd_timer_expired; u32 flash_capacity; + struct eepromrw_info eeprom; u8 dfs_region; void *rsi_dev; struct rsi_host_intf_ops *host_intf_ops; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index dcb6db728cbd..47926c9f2027 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -43,6 +43,7 @@ #define WLAN_HOST_MODE_LEN 0x04 #define WLAN_FW_VERSION_LEN 0x08 #define MAGIC_WORD 0x5A +#define WLAN_EEPROM_RFTYPE_ADDR 424 /* Receive Frame Types */ #define TA_CONFIRM_TYPE 0x01 @@ -192,7 +193,7 @@ enum cmd_frame_type { AUTO_RATE_IND, BOOTUP_PARAMS_REQUEST, VAP_CAPABILITIES, - EEPROM_READ_TYPE , + EEPROM_READ, EEPROM_WRITE, GPIO_PIN_CONFIG , SET_RX_FILTER, @@ -353,6 +354,22 @@ struct rsi_config_vals { u8 reserved2[16]; } __packed; +/* Packet info flags */ +#define RSI_EEPROM_HDR_SIZE_OFFSET 8 +#define RSI_EEPROM_HDR_SIZE_MASK 0x300 +#define RSI_EEPROM_LEN_OFFSET 20 +#define RSI_EEPROM_LEN_MASK 0xFFF00000 + +struct rsi_eeprom_read_frame { + __le16 len_qno; + u8 pkt_type; + u8 misc_flags; + __le32 pkt_info; + __le32 eeprom_offset; + __le16 delay_ms; + __le16 reserved3; +} __packed; + static inline u32 rsi_get_queueno(u8 *addr, u16 offset) { return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; -- cgit v1.2.3 From 6507de6df9007b24d843287a6feba10c1dafffd6 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 6 Jul 2017 20:07:16 +0530 Subject: rsi: separate function for management packet descriptor Management descriptor preparation is move to a separate function as it will be called from a different context in upcoming patches. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 132 +++++++++++++++++++++------------ drivers/net/wireless/rsi/rsi_hal.h | 10 +-- drivers/net/wireless/rsi/rsi_main.h | 7 ++ drivers/net/wireless/rsi/rsi_mgmt.h | 1 + 4 files changed, 98 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 9eaa0a265c77..f8ccb1cb7c75 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -25,6 +25,89 @@ static struct ta_metadata metadata_flash_content[] = { {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, }; +/*This function prepares descriptor for given management packet*/ + +static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *wh = NULL; + struct ieee80211_tx_info *info; + struct ieee80211_conf *conf = &adapter->hw->conf; + struct ieee80211_vif *vif = NULL; + struct rsi_mgmt_desc *mgmt_desc; + struct skb_info *tx_params; + struct ieee80211_bss_conf *bss = NULL; + struct xtended_desc *xtend_desc = NULL; + u8 header_size; + u32 dword_align_bytes = 0; + + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + + /* Update header size */ + header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); + if (header_size > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to add extended descriptor\n", + __func__); + return -ENOSPC; + } + skb_push(skb, header_size); + dword_align_bytes = ((unsigned long)skb->data & 0x3f); + if (dword_align_bytes > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to add dword align\n", __func__); + return -ENOSPC; + } + skb_push(skb, dword_align_bytes); + header_size += dword_align_bytes; + + tx_params->internal_hdr_size = header_size; + memset(&skb->data[0], 0, header_size); + bss = &info->control.vif->bss_conf; + wh = (struct ieee80211_hdr *)&skb->data[header_size]; + vif = adapter->vifs[0]; + + mgmt_desc = (struct rsi_mgmt_desc *)skb->data; + xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ]; + + if (skb->len > MAX_MGMT_PKT_SIZE) { + rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); + return -EINVAL; + } + rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ), + RSI_WIFI_MGMT_Q); + mgmt_desc->frame_type = TX_DOT11_MGMT; + mgmt_desc->header_len = MIN_802_11_HDR_LEN; + mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; + mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE); + if (is_broadcast_ether_addr(wh->addr1)) + mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); + + 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; + else + mgmt_desc->rate_info = RSI_RATE_6; + + if (conf_is_ht40(conf)) + mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); + + if (ieee80211_is_probe_req(wh->frame_control)) { + if (!bss->assoc) { + rsi_dbg(INFO_ZONE, + "%s: blocking mgmt queue\n", __func__); + mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; + xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM; + common->mgmt_q_block = true; + rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n"); + } + } + + return 0; +} + /** * rsi_send_data_pkt() - This function sends the recieved data packet from * driver to device. @@ -133,16 +216,10 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *wh; struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; - struct ieee80211_hw *hw = adapter->hw; - struct ieee80211_conf *conf = &hw->conf; - struct rsi_mgmt_desc *mgmt_desc; struct skb_info *tx_params; int status = -E2BIG; u8 extnd_size; - u8 vap_id = 0; info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; @@ -168,51 +245,12 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, return status; } - bss = &info->control.vif->bss_conf; - wh = (struct ieee80211_hdr *)&skb->data[0]; - if (FRAME_DESC_SZ > skb_headroom(skb)) goto err; - skb_push(skb, FRAME_DESC_SZ); - memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_desc = (struct rsi_mgmt_desc *)skb->data; - - if (skb->len > MAX_MGMT_PKT_SIZE) { - rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); - goto err; - } - - rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ), - RSI_WIFI_MGMT_Q); - mgmt_desc->frame_type = TX_DOT11_MGMT; - mgmt_desc->header_len = MIN_802_11_HDR_LEN; - mgmt_desc->info_cap |= cpu_to_le16(RATE_INFO_ENABLE); - mgmt_desc->seq_ctrl = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); - - if (wh->addr1[0] & BIT(0)) - mgmt_desc->info_cap |= cpu_to_le16(RSI_BROADCAST_PKT); - - if (common->band == NL80211_BAND_2GHZ) - mgmt_desc->rate_info = RSI_11B_MODE; - else - mgmt_desc->rate_info = (RSI_RATE_6 & 0x0f) | RSI_11G_MODE; - - if (conf_is_ht40(conf)) { - mgmt_desc->rate_info = 0xB | RSI_11G_MODE; - mgmt_desc->bbp_info = BBP_INFO_40MHZ; - } - - /* Indicate to firmware to give cfm */ - if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { - mgmt_desc->misc_flags |= BIT(2); - mgmt_desc->cfm_frame_type = PROBEREQ_CONFIRM; - common->mgmt_q_block = true; - } - mgmt_desc->vap_info = vap_id << 8; - + rsi_prepare_mgmt_desc(common, skb); status = adapter->host_intf_ops->write_pkt(common->priv, - (u8 *)mgmt_desc, skb->len); + (u8 *)skb->data, skb->len); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index da115dd11bdd..adbe54e10007 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -118,14 +118,14 @@ struct rsi_mgmt_desc { __le16 len_qno; u8 frame_type; u8 misc_flags; - u8 reserved1; + u8 xtend_desc_size; u8 header_len; - __le16 info_cap; + __le16 frame_info; u8 rate_info; - u8 reserved2; - u16 bbp_info; + u8 reserved1; + __le16 bbp_info; __le16 seq_ctrl; - u8 cfm_frame_type; + u8 reserved2; u8 vap_info; } __packed; diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index cbf29c36f4f4..699e9da1a87b 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -105,6 +105,7 @@ struct skb_info { u16 channel; s8 tid; s8 sta_id; + u8 internal_hdr_size; }; enum edca_queue { @@ -158,6 +159,12 @@ struct cqm_info { u32 rssi_hyst; }; +struct xtended_desc { + u8 confirm_frame_type; + u8 retry_cnt; + u16 reserved; +}; + struct rsi_hw; struct rsi_common { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 47926c9f2027..8e05e0b222e0 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -63,6 +63,7 @@ #define RF_RESET_ENABLE BIT(3) #define RATE_INFO_ENABLE BIT(0) #define RSI_BROADCAST_PKT BIT(9) +#define RSI_DESC_REQUIRE_CFM_TO_HOST BIT(2) #define UPPER_20_ENABLE (0x2 << 12) #define LOWER_20_ENABLE (0x4 << 12) -- cgit v1.2.3 From ebf084ea0ec749f6ec576a67762f0ec34c514111 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 6 Jul 2017 20:07:22 +0530 Subject: rsi: SDIO Rx packet processing enhancement Newer firmware sends information about number of blocks through interrupt only. We don't need to read extra register for this. This patch adds needed driver changes for this enhancment. The change here is backward compatible Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 34 ++++++++++++++++++++++------- drivers/net/wireless/rsi/rsi_main.h | 1 + drivers/net/wireless/rsi/rsi_sdio.h | 1 + 3 files changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index df2a63b1f15c..b6d0e2ae1412 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -69,20 +69,37 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) static int rsi_process_pkt(struct rsi_common *common) { struct rsi_hw *adapter = common->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; u8 num_blks = 0; u32 rcv_pkt_len = 0; int status = 0; + u8 value = 0; - status = rsi_sdio_read_register(adapter, - SDIO_RX_NUM_BLOCKS_REG, - &num_blks); + num_blks = ((adapter->interrupt_status & 1) | + ((adapter->interrupt_status >> RECV_NUM_BLOCKS) << 1)); - if (status) { - rsi_dbg(ERR_ZONE, - "%s: Failed to read pkt length from the card:\n", - __func__); - return status; + if (!num_blks) { + status = rsi_sdio_read_register(adapter, + SDIO_RX_NUM_BLOCKS_REG, + &value); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read pkt length from the card:\n", + __func__); + return status; + } + num_blks = value & 0x1f; } + + if (dev->write_fail == 2) + rsi_sdio_ack_intr(common->priv, (1 << MSDU_PKT_PENDING)); + + if (unlikely(!num_blks)) { + dev->write_fail = 2; + return -1; + } + rcv_pkt_len = (num_blks * 256); common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL); @@ -224,6 +241,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) mutex_unlock(&common->tx_rxlock); return; } + adapter->interrupt_status = isr_status; if (isr_status == 0) { rsi_set_event(&common->tx_thread.event); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 699e9da1a87b..c2e1c1ce285c 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -275,6 +275,7 @@ struct rsi_hw { bool blcmd_timer_expired; u32 flash_capacity; struct eepromrw_info eeprom; + u32 interrupt_status; u8 dfs_region; void *rsi_dev; struct rsi_host_intf_ops *host_intf_ops; diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index cbbc0448dc40..3cf67565feb1 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -41,6 +41,7 @@ enum sdio_interrupt_type { #define PKT_BUFF_FULL 1 #define PKT_MGMT_BUFF_FULL 2 #define MSDU_PKT_PENDING 3 +#define RECV_NUM_BLOCKS 4 /* Interrupt Bit Related Macros */ #define PKT_BUFF_AVAILABLE 1 #define FW_ASSERT_IND 2 -- cgit v1.2.3 From 6c409cad3d2b66cb4fd184d140fdf48e34890249 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 6 Jul 2017 20:07:23 +0530 Subject: rsi: use separate mutex lock for receive thread Deadlock issue is observed during our stress tests. The root cause for the issue is same lock is used between tx and rx threads. This patch adds a separate mutex lock for rx thread to resolve the problem. Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_main.c | 1 + drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 10 +++++----- drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 6 +++--- drivers/net/wireless/rsi/rsi_main.h | 2 ++ 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index f1cde0ca81f9..939f568dae9b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -221,6 +221,7 @@ struct rsi_hw *rsi_91x_init(void) rsi_init_event(&common->tx_thread.event); mutex_init(&common->mutex); mutex_init(&common->tx_rxlock); + mutex_init(&common->rx_lock); if (rsi_create_kthread(common, &common->tx_thread, diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index b6d0e2ae1412..b3f7adc9d085 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -230,7 +230,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) dev->rx_info.sdio_int_counter++; do { - mutex_lock(&common->tx_rxlock); + mutex_lock(&common->rx_lock); status = rsi_sdio_read_register(common->priv, RSI_FN1_INT_REGISTER, &isr_status); @@ -238,7 +238,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", __func__); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } adapter->interrupt_status = isr_status; @@ -246,7 +246,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) if (isr_status == 0) { rsi_set_event(&common->tx_thread.event); dev->rx_info.sdio_intr_status_zero++; - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } @@ -304,7 +304,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Failed to read pkt\n", __func__); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } break; @@ -319,7 +319,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) } isr_status ^= BIT(isr_type - 1); } while (isr_status); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); } while (1); } diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index d3e0a07604a6..465692b3c351 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -37,14 +37,14 @@ void rsi_usb_rx_thread(struct rsi_common *common) if (atomic_read(&dev->rx_thread.thread_done)) goto out; - mutex_lock(&common->tx_rxlock); + mutex_lock(&common->rx_lock); status = rsi_read_pkt(common, 0); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); rsi_reset_event(&dev->rx_thread.event); if (adapter->rx_urb_submit(adapter)) { rsi_dbg(ERR_ZONE, diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index c2e1c1ce285c..29bccb7079ec 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -181,6 +181,8 @@ struct rsi_common { struct mutex mutex; /* Mutex used between tx/rx threads */ struct mutex tx_rxlock; + /* Mutex used for rx thread */ + struct mutex rx_lock; u8 endpoint; /* Channel/band related */ -- cgit v1.2.3 From cb16453565f8d2d6ee9f098ee575ea030e5d71e9 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 6 Jul 2017 20:07:24 +0530 Subject: rsi: Rename mutex tx_rxlock to the tx_lock. We have now added separate lock for Rx. This lock is used to protect tx path only Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 10 +++++----- drivers/net/wireless/rsi/rsi_91x_main.c | 2 +- drivers/net/wireless/rsi/rsi_main.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 68f04a76769e..88a1a56a20ab 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -268,11 +268,11 @@ void rsi_core_qos_processor(struct rsi_common *common) break; } - mutex_lock(&common->tx_rxlock); + mutex_lock(&common->tx_lock); status = adapter->check_hw_queue_status(adapter, q_num); if ((status <= 0)) { - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); break; } @@ -287,7 +287,7 @@ void rsi_core_qos_processor(struct rsi_common *common) skb = rsi_core_dequeue_pkt(common, q_num); if (skb == NULL) { rsi_dbg(ERR_ZONE, "skb null\n"); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); break; } @@ -297,14 +297,14 @@ void rsi_core_qos_processor(struct rsi_common *common) status = rsi_send_data_pkt(common, skb); if (status) { - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); break; } common->tx_stats.total_tx_pkt_send[q_num]++; tstamp_2 = jiffies; - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) schedule(); diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 939f568dae9b..bb0febb17be0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -220,7 +220,7 @@ struct rsi_hw *rsi_91x_init(void) rsi_init_event(&common->tx_thread.event); mutex_init(&common->mutex); - mutex_init(&common->tx_rxlock); + mutex_init(&common->tx_lock); mutex_init(&common->rx_lock); if (rsi_create_kthread(common, diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 29bccb7079ec..709f767aa34b 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -179,8 +179,8 @@ struct rsi_common { struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 1]; /* Mutex declaration */ struct mutex mutex; - /* Mutex used between tx/rx threads */ - struct mutex tx_rxlock; + /* Mutex used for tx thread */ + struct mutex tx_lock; /* Mutex used for rx thread */ struct mutex rx_lock; u8 endpoint; -- cgit v1.2.3 From 6abdf2c19346b0f98437943215c6763e5f4847c9 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Mon, 10 Jul 2017 18:10:34 +0530 Subject: rsi: Update in tx command frame radio capabilities Radio capabilities frame is updated to use common descriptor structure. Also, few changes to this frame is done like hardware queues are increase to 12 from 8, default channel number is included. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 56 ++++++++++++++++++--------------- drivers/net/wireless/rsi/rsi_main.h | 7 ++++- drivers/net/wireless/rsi/rsi_mgmt.h | 13 +++++++- 3 files changed, 48 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 68771b05797e..65d2dd6b908a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -301,10 +301,11 @@ static int rsi_load_radio_caps(struct rsi_common *common) 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}; struct sk_buff *skb; + u16 frame_len = sizeof(struct rsi_radio_caps); rsi_dbg(INFO_ZONE, "%s: Sending rate symbol req frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_radio_caps)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", @@ -312,37 +313,40 @@ static int rsi_load_radio_caps(struct rsi_common *common) return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_radio_caps)); + memset(skb->data, 0, frame_len); radio_caps = (struct rsi_radio_caps *)skb->data; - radio_caps->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES); - radio_caps->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8); + radio_caps->desc_dword0.frame_type = RADIO_CAPABILITIES; + radio_caps->channel_num = common->channel; + radio_caps->rf_model = RSI_RF_TYPE; if (common->channel_width == BW_40MHZ) { - radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ); - radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ); + radio_caps->radio_cfg_info = RSI_LMAC_CLOCK_80MHZ; + radio_caps->radio_cfg_info |= RSI_ENABLE_40MHZ; if (common->fsm_state == FSM_MAC_INIT_DONE) { struct ieee80211_hw *hw = adapter->hw; struct ieee80211_conf *conf = &hw->conf; + if (conf_is_ht40_plus(conf)) { - radio_caps->desc_word[5] = - cpu_to_le16(LOWER_20_ENABLE); - radio_caps->desc_word[5] |= - cpu_to_le16(LOWER_20_ENABLE >> 12); + radio_caps->radio_cfg_info = + RSI_CMDDESC_LOWER_20_ENABLE; + radio_caps->radio_info = + RSI_CMDDESC_LOWER_20_ENABLE; } else if (conf_is_ht40_minus(conf)) { - radio_caps->desc_word[5] = - cpu_to_le16(UPPER_20_ENABLE); - radio_caps->desc_word[5] |= - cpu_to_le16(UPPER_20_ENABLE >> 12); + radio_caps->radio_cfg_info = + RSI_CMDDESC_UPPER_20_ENABLE; + radio_caps->radio_info = + RSI_CMDDESC_UPPER_20_ENABLE; } else { - radio_caps->desc_word[5] = - cpu_to_le16(BW_40MHZ << 12); - radio_caps->desc_word[5] |= - cpu_to_le16(FULL40M_ENABLE); + radio_caps->radio_cfg_info = + RSI_CMDDESC_40MHZ; + radio_caps->radio_info = + RSI_CMDDESC_FULL_40_ENABLE; } } } + radio_caps->radio_info |= radio_id; radio_caps->sifs_tx_11n = cpu_to_le16(SIFS_TX_11N_VALUE); radio_caps->sifs_tx_11b = cpu_to_le16(SIFS_TX_11B_VALUE); @@ -351,8 +355,6 @@ static int rsi_load_radio_caps(struct rsi_common *common) radio_caps->cck_ack_tout = cpu_to_le16(CCK_ACK_TOUT_VALUE); radio_caps->preamble_type = cpu_to_le16(LONG_PREAMBLE); - radio_caps->desc_word[7] |= cpu_to_le16(radio_id << 8); - for (ii = 0; ii < MAX_HW_QUEUES; ii++) { radio_caps->qos_params[ii].cont_win_min_q = cpu_to_le16(3); radio_caps->qos_params[ii].cont_win_max_q = cpu_to_le16(0x3f); @@ -360,7 +362,7 @@ static int rsi_load_radio_caps(struct rsi_common *common) radio_caps->qos_params[ii].txop_q = 0; } - for (ii = 0; ii < MAX_HW_QUEUES - 4; ii++) { + for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { radio_caps->qos_params[ii].cont_win_min_q = cpu_to_le16(common->edca_params[ii].cw_min); radio_caps->qos_params[ii].cont_win_max_q = @@ -371,17 +373,19 @@ static int rsi_load_radio_caps(struct rsi_common *common) cpu_to_le16(common->edca_params[ii].txop); } + radio_caps->qos_params[BROADCAST_HW_Q].txop_q = cpu_to_le16(0xffff); + radio_caps->qos_params[MGMT_HW_Q].txop_q = 0; + radio_caps->qos_params[BEACON_HW_Q].txop_q = cpu_to_le16(0xffff); + memcpy(&common->rate_pwr[0], &gc[0], 40); for (ii = 0; ii < 20; ii++) radio_caps->gcpd_per_rate[inx++] = cpu_to_le16(common->rate_pwr[ii] & 0x00FF); - radio_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_radio_caps) - - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - + rsi_set_len_qno(&radio_caps->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); - skb_put(skb, (sizeof(struct rsi_radio_caps))); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 709f767aa34b..a567986c5b0b 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -61,11 +61,16 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define MAC_80211_HDR_FRAME_CONTROL 0 #define WME_NUM_AC 4 #define NUM_SOFT_QUEUES 5 -#define MAX_HW_QUEUES 8 +#define MAX_HW_QUEUES 12 #define INVALID_QUEUE 0xff #define MAX_CONTINUOUS_VO_PKTS 8 #define MAX_CONTINUOUS_VI_PKTS 4 +/* Hardware queue info */ +#define BROADCAST_HW_Q 9 +#define MGMT_HW_Q 10 +#define BEACON_HW_Q 11 + /* Queue information */ #define RSI_COEX_Q 0x0 #define RSI_WIFI_MGMT_Q 0x4 diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 6f7f181710f8..3b4bd85e9c4e 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -70,6 +70,10 @@ #define RSI_REKEY_PURPOSE BIT(13) #define RSI_ENCRYPT_PKT BIT(15) +#define RSI_CMDDESC_40MHZ BIT(4) +#define RSI_CMDDESC_UPPER_20_ENABLE BIT(5) +#define RSI_CMDDESC_LOWER_20_ENABLE BIT(6) +#define RSI_CMDDESC_FULL_40_ENABLE (BIT(5) | BIT(6)) #define UPPER_20_ENABLE (0x2 << 12) #define LOWER_20_ENABLE (0x4 << 12) #define FULL40M_ENABLE 0x6 @@ -317,7 +321,14 @@ struct qos_params { } __packed; struct rsi_radio_caps { - __le16 desc_word[8]; + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword0 desc_dword1; + u8 channel_num; + u8 rf_model; + __le16 ppe_ack_rate; + __le16 mode_11j; + u8 radio_cfg_info; + u8 radio_info; struct qos_params qos_params[MAX_HW_QUEUES]; u8 num_11n_rates; u8 num_11ac_rates; -- cgit v1.2.3 From de1d1813a8ca31e8c1229fe0b42eba0574f43e89 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Mon, 10 Jul 2017 18:10:40 +0530 Subject: rsi: update vap capabilities command frame VAP capablities frame configured to device is modified to use common descriptor structure. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 56 ++++++++++++++++++--------------- drivers/net/wireless/rsi/rsi_main.h | 3 ++ drivers/net/wireless/rsi/rsi_mgmt.h | 19 +++++++++-- 3 files changed, 49 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 4bcb84087874..3ce1f71cf537 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -230,6 +230,8 @@ static void rsi_set_default_parameters(struct rsi_common *common) common->rf_power_val = 0; /* Default 1.9V */ common->wlan_rf_power_mode = 0; common->obm_ant_sel_val = 2; + common->beacon_interval = RSI_BEACON_INTERVAL; + common->dtim_cnt = RSI_DTIM_COUNT; } /** @@ -627,59 +629,61 @@ int rsi_set_vap_capabilities(struct rsi_common *common, struct rsi_hw *adapter = common->priv; struct ieee80211_hw *hw = adapter->hw; struct ieee80211_conf *conf = &hw->conf; + u16 frame_len = sizeof(struct rsi_vap_caps); u16 vap_id = 0; rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_vap_caps)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_vap_caps)); + memset(skb->data, 0, frame_len); vap_caps = (struct rsi_vap_caps *)skb->data; - vap_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_vap_caps) - - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - vap_caps->desc_word[1] = cpu_to_le16(VAP_CAPABILITIES); - vap_caps->desc_word[2] = cpu_to_le16(vap_status << 8); - vap_caps->desc_word[4] = cpu_to_le16(mode | - (common->channel_width << 8)); - vap_caps->desc_word[7] = cpu_to_le16((vap_id << 8) | - (common->mac_id << 4) | - common->radio_id); + rsi_set_len_qno(&vap_caps->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); + vap_caps->desc_dword0.frame_type = VAP_CAPABILITIES; + vap_caps->status = vap_status; + vap_caps->vif_type = mode; + vap_caps->channel_bw = common->channel_width; + vap_caps->vap_id = vap_id; + vap_caps->radioid_macid = ((common->mac_id & 0xf) << 4) | + (common->radio_id & 0xf); memcpy(vap_caps->mac_addr, common->mac_addr, IEEE80211_ADDR_LEN); vap_caps->keep_alive_period = cpu_to_le16(90); vap_caps->frag_threshold = cpu_to_le16(IEEE80211_MAX_FRAG_THRESHOLD); vap_caps->rts_threshold = cpu_to_le16(common->rts_threshold); - vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_6); if (common->band == NL80211_BAND_5GHZ) { - vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_6); - if (conf_is_ht40(&common->priv->hw->conf)) { - vap_caps->default_ctrl_rate |= - cpu_to_le32(FULL40M_ENABLE << 16); - } + vap_caps->default_ctrl_rate = cpu_to_le16(RSI_RATE_6); + vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_6); } else { - vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_1); + vap_caps->default_ctrl_rate = cpu_to_le16(RSI_RATE_1); + vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_1); + } + if (conf_is_ht40(conf)) { if (conf_is_ht40_minus(conf)) - vap_caps->default_ctrl_rate |= - cpu_to_le32(UPPER_20_ENABLE << 16); + vap_caps->ctrl_rate_flags = + cpu_to_le16(UPPER_20_ENABLE); else if (conf_is_ht40_plus(conf)) - vap_caps->default_ctrl_rate |= - cpu_to_le32(LOWER_20_ENABLE << 16); + vap_caps->ctrl_rate_flags = + cpu_to_le16(LOWER_20_ENABLE); + else + vap_caps->ctrl_rate_flags = + cpu_to_le16(FULL40M_ENABLE); } vap_caps->default_data_rate = 0; - vap_caps->beacon_interval = cpu_to_le16(200); - vap_caps->dtim_period = cpu_to_le16(4); + vap_caps->beacon_interval = cpu_to_le16(common->beacon_interval); + vap_caps->dtim_period = cpu_to_le16(common->dtim_cnt); - skb_put(skb, sizeof(*vap_caps)); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index a567986c5b0b..485b97ab5779 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -239,6 +239,9 @@ struct rsi_common { u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; + + u16 beacon_interval; + u8 dtim_cnt; }; enum host_intf { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 2f49e55650b0..fcde44e966f1 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -167,6 +167,8 @@ #define RSI_MPDU_DENSITY 0x8 #define RSI_CHAN_RADAR BIT(7) +#define RSI_BEACON_INTERVAL 200 +#define RSI_DTIM_COUNT 2 enum opmode { STA_OPMODE = 1, @@ -320,19 +322,30 @@ struct rsi_chan_config { } __packed; struct rsi_vap_caps { - __le16 desc_word[8]; + struct rsi_cmd_desc_dword0 desc_dword0; + u8 reserved1; + u8 status; + __le16 reserved2; + u8 vif_type; + u8 channel_bw; + __le16 antenna_info; + u8 radioid_macid; + u8 vap_id; + __le16 reserved3; u8 mac_addr[6]; __le16 keep_alive_period; u8 bssid[6]; - __le16 reserved; + __le16 reserved4; __le32 flags; __le16 frag_threshold; __le16 rts_threshold; __le32 default_mgmt_rate; - __le32 default_ctrl_rate; + __le16 default_ctrl_rate; + __le16 ctrl_rate_flags; __le32 default_data_rate; __le16 beacon_interval; __le16 dtim_period; + __le16 beacon_miss_threshold; } __packed; struct rsi_set_key { -- cgit v1.2.3 From d7203a83f065dc78d907c2a2f5d317972ec28d52 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Mon, 10 Jul 2017 18:10:48 +0530 Subject: rsi: regulatory enhancements Below regulatory changes are included this patch * Country code is saved as it will be used in bgscan. * Region codes are mapped according to RSI region codes. * Radar flag settings are moved under the check if 5GHZ band is enabled. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 49 ++++++++++++++++++++++------- drivers/net/wireless/rsi/rsi_main.h | 8 +++++ 2 files changed, 45 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index d094b0ab05ba..c91d6efa7c84 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1163,6 +1163,21 @@ static int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, return 0; } +static int rsi_map_region_code(enum nl80211_dfs_regions region_code) +{ + switch (region_code) { + case NL80211_DFS_FCC: + return RSI_REGION_FCC; + case NL80211_DFS_ETSI: + return RSI_REGION_ETSI; + case NL80211_DFS_JP: + return RSI_REGION_TELEC; + case NL80211_DFS_UNSET: + return RSI_REGION_WORLD; + } + return RSI_REGION_WORLD; +} + static void rsi_reg_notify(struct wiphy *wiphy, struct regulatory_request *request) { @@ -1170,23 +1185,33 @@ static void rsi_reg_notify(struct wiphy *wiphy, struct ieee80211_channel *ch; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct rsi_hw * adapter = hw->priv; + struct rsi_common *common = adapter->priv; int i; - - sband = wiphy->bands[NL80211_BAND_5GHZ]; - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - if (ch->flags & IEEE80211_CHAN_DISABLED) - continue; + mutex_lock(&common->mutex); + + rsi_dbg(INFO_ZONE, "country = %s dfs_region = %d\n", + request->alpha2, request->dfs_region); + + if (common->num_supp_bands > 1) { + sband = wiphy->bands[NL80211_BAND_5GHZ]; - if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IR; + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (ch->flags & IEEE80211_CHAN_RADAR) + ch->flags |= IEEE80211_CHAN_NO_IR; + } } + adapter->dfs_region = rsi_map_region_code(request->dfs_region); + rsi_dbg(INFO_ZONE, "RSI region code = %d\n", adapter->dfs_region); - rsi_dbg(INFO_ZONE, - "country = %s dfs_region = %d\n", - request->alpha2, request->dfs_region); - adapter->dfs_region = request->dfs_region; + adapter->country[0] = request->alpha2[0]; + adapter->country[1] = request->alpha2[1]; + + mutex_unlock(&common->mutex); } static struct ieee80211_ops mac80211_ops = { diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 485b97ab5779..6a8e8e7ed1fb 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -170,6 +170,13 @@ struct xtended_desc { u16 reserved; }; +enum rsi_dfs_regions { + RSI_REGION_FCC = 0, + RSI_REGION_ETSI, + RSI_REGION_TELEC, + RSI_REGION_WORLD +}; + struct rsi_hw; struct rsi_common { @@ -287,6 +294,7 @@ struct rsi_hw { struct eepromrw_info eeprom; u32 interrupt_status; u8 dfs_region; + char country[2]; void *rsi_dev; struct rsi_host_intf_ops *host_intf_ops; int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num); -- cgit v1.2.3 From ce86893fa8d8509d69bef70170ed8c797275c411 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 3 Aug 2017 19:58:59 +0530 Subject: rsi: add support for legacy power save 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 Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- 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 (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile index a475c813674a..ebb89965997a 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 b0a7a1511aee..4addcc0826db 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 193f9227fdb3..16a0fd0f519a 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 bb0febb17be0..3e1e80888d98 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 e00d4edec2ba..f76b34679df8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -17,6 +17,7 @@ #include #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 000000000000..25e8f853837b --- /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 +#include +#include +#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 6a8e8e7ed1fb..9aada0b73108 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -21,6 +21,10 @@ #include #include +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 1060edcb2a96..c5d114d67c83 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 000000000000..d8475873df36 --- /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 -- cgit v1.2.3 From db07971d085fa637816ce029a5411f2ce83ee672 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 3 Aug 2017 19:59:00 +0530 Subject: rsi: add support for U-APSD power save 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 Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- 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(+) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 16a0fd0f519a..6b833c424b18 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 f76b34679df8..e5fe443ddfb6 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 25e8f853837b..48c79f035c59 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 9aada0b73108..d2cc47e98639 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 c5d114d67c83..b22103fd6c81 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 -- cgit v1.2.3 From 80a88ecf3bccb129146e00e429a4b8a90fb89f11 Mon Sep 17 00:00:00 2001 From: Karun Eagalapati Date: Thu, 3 Aug 2017 19:59:04 +0530 Subject: rsi: RTS threshold configuration Provision is added for configuring RTS threshold by sending vap dynamic update frame to firmware. Signed-off-by: Karun Eagalapati Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- 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(+) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 6b833c424b18..210ad79038ed 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 e5fe443ddfb6..f93499d0b8fa 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 d2cc47e98639..d05b5e0847bc 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 b22103fd6c81..201a46572c69 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); -- cgit v1.2.3 From 6da1e00a539d978339d6a6471b4346c6d82797ff Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 16 Aug 2017 18:43:08 +0530 Subject: rsi: advertise ap mode support AP mode support is advertised to cfg80211. Necessary wiphy parameters are initialized. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 28 +++++++++++++++++++++++++++- drivers/net/wireless/rsi/rsi_main.h | 10 ++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 210ad79038ed..2da54932070d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -122,6 +122,23 @@ const u16 rsi_mcsrates[8] = { RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 }; +static const u32 rsi_max_ap_stas[16] = { + 32, /* 1 - Wi-Fi alone */ + 0, /* 2 */ + 0, /* 3 */ + 0, /* 4 - BT EDR alone */ + 4, /* 5 - STA + BT EDR */ + 32, /* 6 - AP + BT EDR */ + 0, /* 7 */ + 0, /* 8 - BT LE alone */ + 4, /* 9 - STA + BE LE */ + 0, /* 10 */ + 0, /* 11 */ + 0, /* 12 */ + 1, /* 13 - STA + BT Dual */ + 4, /* 14 - AP + BT Dual */ +}; + /** * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. * @common: Pointer to the driver private structure. @@ -1348,7 +1365,8 @@ int rsi_mac80211_attach(struct rsi_common *common) SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); ether_addr_copy(hw->wiphy->addr_mask, addr_mask); - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->retry_short = RETRY_SHORT; wiphy->retry_long = RETRY_LONG; @@ -1363,6 +1381,14 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->bands[NL80211_BAND_5GHZ] = &adapter->sbands[NL80211_BAND_5GHZ]; + /* AP Parameters */ + wiphy->max_ap_assoc_sta = rsi_max_ap_stas[common->oper_mode - 1]; + common->max_stations = wiphy->max_ap_assoc_sta; + rsi_dbg(ERR_ZONE, "Max Stations Allowed = %d\n", common->max_stations); + hw->sta_data_size = sizeof(struct rsi_sta); + wiphy->flags = WIPHY_FLAG_REPORTS_OBSS; + wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; wiphy->reg_notifier = rsi_reg_notify; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index d05b5e0847bc..0077888190c3 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -21,6 +21,13 @@ #include #include +struct rsi_sta { + struct ieee80211_sta *sta; + s16 sta_id; + u16 seq_start[IEEE80211_NUM_TIDS]; + bool start_tx_aggr[IEEE80211_NUM_TIDS]; +}; + struct rsi_hw; #include "rsi_ps.h" @@ -253,6 +260,9 @@ struct rsi_common { u16 beacon_interval; u8 dtim_cnt; + + /* AP mode parameters */ + int max_stations; }; enum host_intf { -- cgit v1.2.3 From 03c34c0d73ae872e6e962e02e3c4e98ae364379b Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 16 Aug 2017 18:43:09 +0530 Subject: rsi: add interface changes for ap mode AP mode is handled in add_interface callback of mac80211. Also for AP mode, sending rx filter frame to disallow beacons to host is added. Station structures are initialized to NULL. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 43 +++++++++++++++++++++++------ drivers/net/wireless/rsi/rsi_91x_mgmt.c | 5 ++-- drivers/net/wireless/rsi/rsi_main.h | 3 ++ drivers/net/wireless/rsi/rsi_mgmt.h | 6 ++-- 4 files changed, 44 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 2da54932070d..edcba567bfe8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -342,25 +342,51 @@ static int rsi_mac80211_add_interface(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + enum opmode intf_mode; int ret = -EOPNOTSUPP; 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: - if (!adapter->sc_nvifs) { - ++adapter->sc_nvifs; - adapter->vifs[0] = vif; - ret = rsi_set_vap_capabilities(common, - STA_OPMODE, - VAP_ADD); - } + 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: rsi_dbg(ERR_ZONE, "%s: Interface type %d not supported\n", __func__, vif->type); + goto out; } + + adapter->vifs[adapter->sc_nvifs++] = vif; + ret = rsi_set_vap_capabilities(common, intf_mode, common->mac_addr, + 0, VAP_ADD); + if (ret) { + rsi_dbg(ERR_ZONE, "Failed to set VAP capabilities\n"); + goto out; + } + + if (vif->type == NL80211_IFTYPE_AP) { + int i; + + 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; @@ -383,7 +409,8 @@ static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, mutex_lock(&common->mutex); if (vif->type == NL80211_IFTYPE_STATION) { adapter->sc_nvifs--; - rsi_set_vap_capabilities(common, STA_OPMODE, VAP_DELETE); + rsi_set_vap_capabilities(common, STA_OPMODE, vif->addr, + 0, VAP_DELETE); } if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif))) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index f93499d0b8fa..233a418555bb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -624,6 +624,8 @@ static int rsi_program_bb_rf(struct rsi_common *common) */ int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, + u8 *mac_addr, + u8 vap_id, u8 vap_status) { struct sk_buff *skb = NULL; @@ -632,7 +634,6 @@ int rsi_set_vap_capabilities(struct rsi_common *common, struct ieee80211_hw *hw = adapter->hw; struct ieee80211_conf *conf = &hw->conf; u16 frame_len = sizeof(struct rsi_vap_caps); - u16 vap_id = 0; rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__); @@ -656,7 +657,7 @@ int rsi_set_vap_capabilities(struct rsi_common *common, vap_caps->radioid_macid = ((common->mac_id & 0xf) << 4) | (common->radio_id & 0xf); - memcpy(vap_caps->mac_addr, common->mac_addr, IEEE80211_ADDR_LEN); + memcpy(vap_caps->mac_addr, mac_addr, IEEE80211_ADDR_LEN); vap_caps->keep_alive_period = cpu_to_le16(90); vap_caps->frag_threshold = cpu_to_le16(IEEE80211_MAX_FRAG_THRESHOLD); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 0077888190c3..9f5f33f616b6 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -90,6 +90,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define IEEE80211_MGMT_FRAME 0x00 #define IEEE80211_CTL_FRAME 0x04 +#define RSI_MAX_ASSOC_STAS 32 #define IEEE80211_QOS_TID 0x0f #define IEEE80211_NONQOS_TID 16 @@ -262,6 +263,8 @@ struct rsi_common { u8 dtim_cnt; /* AP mode parameters */ + struct rsi_sta stations[RSI_MAX_ASSOC_STAS + 1]; + int num_stations; int max_stations; }; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 201a46572c69..9093ba685fb0 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -188,8 +188,8 @@ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) enum opmode { - STA_OPMODE = 1, - AP_OPMODE = 2 + AP_OPMODE = 0, + STA_OPMODE, }; enum vap_status { @@ -591,7 +591,7 @@ static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno) int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, - u8 vap_status); + u8 *mac_addr, u8 vap_id, u8 vap_status); int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, u16 ssn, u8 buf_size, u8 event); int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len, -- cgit v1.2.3 From d26a9559403c7c3ec3b430f5825bc22c3d40abdb Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 16 Aug 2017 18:43:11 +0530 Subject: rsi: add beacon changes for AP mode Mac80211 config parameter BEACON_ENABLE is handled. When VAP capabilities frame with AP mode is configured to firmware, beacon events start coming to host at each PreTBTT. At this time, beacon is taken from mac80211, descriptor is prepared and send to firmware. 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_hal.c | 65 ++++++++++++++++++++++++++++- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 12 ++++++ drivers/net/wireless/rsi/rsi_91x_mgmt.c | 48 ++++++++++++++++++--- drivers/net/wireless/rsi/rsi_hal.h | 2 + drivers/net/wireless/rsi/rsi_main.h | 13 +++--- drivers/net/wireless/rsi/rsi_mgmt.h | 11 +++++ 7 files changed, 152 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 88a1a56a20ab..6cfda8626cfe 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -16,6 +16,7 @@ #include "rsi_mgmt.h" #include "rsi_common.h" +#include "rsi_hal.h" /** * rsi_determine_min_weight_queue() - This function determines the queue with @@ -136,6 +137,10 @@ static u8 rsi_core_determine_hal_queue(struct rsi_common *common) u8 q_num = INVALID_QUEUE; u8 ii = 0; + if (skb_queue_len(&common->tx_queue[MGMT_BEACON_Q])) { + q_num = MGMT_BEACON_Q; + return q_num; + } if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { if (!common->mgmt_q_block) q_num = MGMT_SOFT_Q; @@ -291,10 +296,14 @@ void rsi_core_qos_processor(struct rsi_common *common) break; } - if (q_num == MGMT_SOFT_Q) + if (q_num == MGMT_SOFT_Q) { status = rsi_send_mgmt_pkt(common, skb); - else + } else if (q_num == MGMT_BEACON_Q) { + status = rsi_send_pkt_to_bus(common, skb); + dev_kfree_skb(skb); + } else { status = rsi_send_data_pkt(common, skb); + } if (status) { mutex_unlock(&common->tx_lock); @@ -358,7 +367,7 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) tx_params->sta_id = 0; } - if ((q_num != MGMT_SOFT_Q) && + if ((q_num < MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 4addcc0826db..1ed73320e19f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -25,7 +25,15 @@ static struct ta_metadata metadata_flash_content[] = { {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, }; -/*This function prepares descriptor for given management packet*/ +int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + int status; + + status = adapter->host_intf_ops->write_pkt(common->priv, + skb->data, skb->len); + return status; +} static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) { @@ -306,6 +314,61 @@ err: return status; } +int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = (struct rsi_hw *)common->priv; + struct rsi_data_desc *bcn_frm; + struct ieee80211_hw *hw = common->priv->hw; + struct ieee80211_conf *conf = &hw->conf; + struct sk_buff *mac_bcn; + u8 vap_id = 0; + u16 tim_offset; + + mac_bcn = ieee80211_beacon_get_tim(adapter->hw, + adapter->vifs[adapter->sc_nvifs - 1], + &tim_offset, NULL); + if (!mac_bcn) { + rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); + return -EINVAL; + } + + common->beacon_cnt++; + bcn_frm = (struct rsi_data_desc *)skb->data; + rsi_set_len_qno(&bcn_frm->len_qno, mac_bcn->len, RSI_WIFI_DATA_Q); + bcn_frm->header_len = MIN_802_11_HDR_LEN; + bcn_frm->frame_info = cpu_to_le16(RSI_DATA_DESC_MAC_BBP_INFO | + RSI_DATA_DESC_NO_ACK_IND | + RSI_DATA_DESC_BEACON_FRAME | + RSI_DATA_DESC_INSERT_TSF | + RSI_DATA_DESC_INSERT_SEQ_NO | + RATE_INFO_ENABLE); + bcn_frm->rate_info = cpu_to_le16(vap_id << 14); + bcn_frm->qid_tid = BEACON_HW_Q; + + if (conf_is_ht40_plus(conf)) { + bcn_frm->bbp_info = cpu_to_le16(LOWER_20_ENABLE); + bcn_frm->bbp_info |= cpu_to_le16(LOWER_20_ENABLE >> 12); + } else if (conf_is_ht40_minus(conf)) { + bcn_frm->bbp_info = cpu_to_le16(UPPER_20_ENABLE); + bcn_frm->bbp_info |= cpu_to_le16(UPPER_20_ENABLE >> 12); + } + + if (common->band == NL80211_BAND_2GHZ) + bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_1); + else + bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_6); + + if (mac_bcn->data[tim_offset + 2] == 0) + bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON); + + memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len); + skb_put(skb, mac_bcn->len + FRAME_DESC_SZ); + + dev_kfree_skb(mac_bcn); + + return 0; +} + static void bl_cmd_timeout(unsigned long priv) { struct rsi_hw *adapter = (struct rsi_hw *)priv; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 99446bbc0516..6038a2fc9eda 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -652,6 +652,18 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, common->cqm_info.rssi_thold, common->cqm_info.rssi_hyst); } + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && + (vif->type == NL80211_IFTYPE_AP)) { + if (bss->enable_beacon) { + rsi_dbg(INFO_ZONE, "===> BEACON ENABLED <===\n"); + common->beacon_enabled = 1; + } else { + rsi_dbg(INFO_ZONE, "===> BEACON DISABLED <===\n"); + common->beacon_enabled = 0; + } + } + mutex_unlock(&common->mutex); } diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 233a418555bb..e47fc0d96475 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -18,6 +18,7 @@ #include "rsi_mgmt.h" #include "rsi_common.h" #include "rsi_ps.h" +#include "rsi_hal.h" static struct bootup_params boot_params_20 = { .magic_number = cpu_to_le16(0x5aa5), @@ -1518,6 +1519,31 @@ int rsi_set_antenna(struct rsi_common *common, u8 antenna) return rsi_send_internal_mgmt_frame(common, skb); } +static int rsi_send_beacon(struct rsi_common *common) +{ + struct sk_buff *skb = NULL; + u8 dword_align_bytes = 0; + + skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE); + if (!skb) + return -ENOMEM; + + memset(skb->data, 0, MAX_MGMT_PKT_SIZE); + + dword_align_bytes = ((unsigned long)skb->data & 0x3f); + if (dword_align_bytes) + skb_pull(skb, (64 - dword_align_bytes)); + if (rsi_prepare_beacon(common, skb)) { + rsi_dbg(ERR_ZONE, "Failed to prepare beacon\n"); + return -EINVAL; + } + skb_queue_tail(&common->tx_queue[MGMT_BEACON_Q], skb); + rsi_set_event(&common->tx_thread.event); + rsi_dbg(DATA_TX_ZONE, "%s: Added to beacon queue\n", __func__); + + return 0; +} + /** * rsi_handle_ta_confirm_type() - This function handles the confirm frames. * @common: Pointer to the driver private structure. @@ -1722,21 +1748,33 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n", __func__, msg_len, msg_type); - if (msg_type == TA_CONFIRM_TYPE) { + switch (msg_type) { + case TA_CONFIRM_TYPE: return rsi_handle_ta_confirm_type(common, msg); - } else if (msg_type == CARD_READY_IND) { + case CARD_READY_IND: rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n", __func__); return rsi_handle_card_ready(common, msg); - } else if (msg_type == TX_STATUS_IND) { + case TX_STATUS_IND: if (msg[15] == PROBEREQ_CONFIRM) { common->mgmt_q_block = false; rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n", __func__); } - } else if (msg_type == RX_DOT11_MGMT) { + break; + case BEACON_EVENT_IND: + rsi_dbg(INFO_ZONE, "Beacon event\n"); + if (common->fsm_state != FSM_MAC_INIT_DONE) + return -1; + if (common->iface_down) + return -1; + if (!common->beacon_enabled) + return -1; + rsi_send_beacon(common); + break; + case RX_DOT11_MGMT: return rsi_mgmt_pkt_to_core(common, msg, msg_len); - } else { + default: rsi_dbg(INFO_ZONE, "Received packet type: 0x%x\n", msg_type); } return 0; diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index 00c6a0c5a891..297f4ce2c39e 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -144,5 +144,7 @@ struct rsi_data_desc { } __packed; int rsi_hal_device_init(struct rsi_hw *adapter); +int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb); +int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 9f5f33f616b6..169e2f9e3c5e 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -72,7 +72,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define MULTICAST_WATER_MARK 200 #define MAC_80211_HDR_FRAME_CONTROL 0 #define WME_NUM_AC 4 -#define NUM_SOFT_QUEUES 5 +#define NUM_SOFT_QUEUES 6 #define MAX_HW_QUEUES 12 #define INVALID_QUEUE 0xff #define MAX_CONTINUOUS_VO_PKTS 8 @@ -131,7 +131,8 @@ enum edca_queue { BE_Q, VI_Q, VO_Q, - MGMT_SOFT_Q + MGMT_SOFT_Q, + MGMT_BEACON_Q }; struct security_info { @@ -148,8 +149,8 @@ struct wmm_qinfo { }; struct transmit_q_stats { - u32 total_tx_pkt_send[NUM_EDCA_QUEUES + 1]; - u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 1]; + u32 total_tx_pkt_send[NUM_EDCA_QUEUES + 2]; + u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 2]; }; struct vif_priv { @@ -199,7 +200,7 @@ struct rsi_common { struct version_info fw_ver; struct rsi_thread tx_thread; - struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 1]; + struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 2]; /* Mutex declaration */ struct mutex mutex; /* Mutex used for tx thread */ @@ -263,6 +264,8 @@ struct rsi_common { u8 dtim_cnt; /* AP mode parameters */ + u8 beacon_enabled; + u16 beacon_cnt; struct rsi_sta stations[RSI_MAX_ASSOC_STAS + 1]; int num_stations; int max_stations; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 9093ba685fb0..a00aa10b1be5 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -49,6 +49,7 @@ #define TA_CONFIRM_TYPE 0x01 #define RX_DOT11_MGMT 0x02 #define TX_STATUS_IND 0x04 +#define BEACON_EVENT_IND 0x08 #define PROBEREQ_CONFIRM 2 #define CARD_READY_IND 0x00 @@ -187,6 +188,16 @@ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) +#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) +#define RSI_DATA_DESC_NORMAL_FRAME 0x00 +#define RSI_DATA_DESC_DTIM_BEACON_GATED_FRAME BIT(10) +#define RSI_DATA_DESC_BEACON_FRAME BIT(11) +#define RSI_DATA_DESC_DTIM_BEACON (BIT(10) | BIT(11)) +#define RSI_DATA_DESC_INSERT_TSF BIT(15) +#define RSI_DATA_DESC_INSERT_SEQ_NO BIT(2) + enum opmode { AP_OPMODE = 0, STA_OPMODE, -- cgit v1.2.3 From 38ef62353acbaa0eea062a9f047b33aebd7d52ce Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Wed, 16 Aug 2017 18:43:18 +0530 Subject: rsi: security enhancements for AP mode Station id should be set in load key frame configured to device. For WEP mode, key is configured once from mac80211. This key is saved and configured to device every time a station is connected. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 60 +++++++++++++++++++++-------- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 10 ++++- drivers/net/wireless/rsi/rsi_main.h | 1 + drivers/net/wireless/rsi/rsi_mgmt.h | 3 +- 4 files changed, 56 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless/rsi/rsi_main.h') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index f2cb61f2b268..8b983d03f2da 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -758,11 +758,14 @@ static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, */ static int rsi_hal_key_config(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_key_conf *key) + struct ieee80211_key_conf *key, + struct ieee80211_sta *sta) { struct rsi_hw *adapter = hw->priv; + struct rsi_sta *rsta = NULL; int status; u8 key_type; + s16 sta_id = 0; if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) key_type = RSI_PAIRWISE_KEY; @@ -772,23 +775,35 @@ 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 ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || - (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { - status = rsi_hal_load_key(adapter->priv, - key->key, - key->keylen, - RSI_PAIRWISE_KEY, - key->keyidx, - key->cipher); - if (status) - return status; + if (vif->type == NL80211_IFTYPE_AP) { + if (sta) { + rsta = rsi_find_sta(adapter->priv, sta->addr); + if (rsta) + sta_id = rsta->sta_id; + } + adapter->priv->key = key; + } else { + if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || + (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { + status = rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + RSI_PAIRWISE_KEY, + key->keyidx, + key->cipher, + sta_id); + if (status) + return status; + } } + return rsi_hal_load_key(adapter->priv, key->key, key->keylen, key_type, key->keyidx, - key->cipher); + key->cipher, + sta_id); } /** @@ -816,7 +831,7 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, switch (cmd) { case SET_KEY: secinfo->security_enable = true; - status = rsi_hal_key_config(hw, vif, key); + status = rsi_hal_key_config(hw, vif, key, sta); if (status) { mutex_unlock(&common->mutex); return status; @@ -834,10 +849,11 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, break; case DISABLE_KEY: - secinfo->security_enable = false; + if (vif->type == NL80211_IFTYPE_STATION) + secinfo->security_enable = false; rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); memset(key, 0, sizeof(struct ieee80211_key_conf)); - status = rsi_hal_key_config(hw, vif, key); + status = rsi_hal_key_config(hw, vif, key, sta); break; default: @@ -1242,6 +1258,20 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, rsi_inform_bss_status(common, AP_OPMODE, 1, sta->addr, sta->wme, sta->aid, sta, sta_idx); + if (common->key) { + struct ieee80211_key_conf *key = common->key; + + if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || + (key->cipher == WLAN_CIPHER_SUITE_WEP40)) + rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + RSI_PAIRWISE_KEY, + key->keyidx, + key->cipher, + sta_idx); + } + common->num_stations++; } } diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 2d3cae561be2..f7b550f900c4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -715,8 +715,10 @@ int rsi_hal_load_key(struct rsi_common *common, u16 key_len, u8 key_type, u8 key_id, - u32 cipher) + u32 cipher, + s16 sta_id) { + struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb = NULL; struct rsi_set_key *set_key; u16 key_descriptor = 0; @@ -734,8 +736,11 @@ int rsi_hal_load_key(struct rsi_common *common, memset(skb->data, 0, frame_len); set_key = (struct rsi_set_key *)skb->data; - if (key_type == RSI_GROUP_KEY) + if (key_type == RSI_GROUP_KEY) { key_descriptor = RSI_KEY_TYPE_BROADCAST; + if (vif->type == NL80211_IFTYPE_AP) + key_descriptor |= RSI_KEY_MODE_AP; + } if ((cipher == WLAN_CIPHER_SUITE_WEP40) || (cipher == WLAN_CIPHER_SUITE_WEP104)) { key_id = 0; @@ -754,6 +759,7 @@ int rsi_hal_load_key(struct rsi_common *common, (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); set_key->desc_dword0.frame_type = SET_KEY_REQ; set_key->key_desc = cpu_to_le16(key_descriptor); + set_key->sta_id = sta_id; if (data) { if ((cipher == WLAN_CIPHER_SUITE_WEP40) || diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 169e2f9e3c5e..2c18dde633ea 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -269,6 +269,7 @@ struct rsi_common { struct rsi_sta stations[RSI_MAX_ASSOC_STAS + 1]; int num_stations; int max_stations; + struct ieee80211_key_conf *key; }; enum host_intf { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 2d827330130d..c6e1fa669a27 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -409,6 +409,7 @@ struct rsi_dynamic_s { #define RSI_WEP_KEY_104 BIT(3) #define RSI_CIPHER_WPA BIT(4) #define RSI_CIPHER_TKIP BIT(5) +#define RSI_KEY_MODE_AP BIT(7) #define RSI_PROTECT_DATA_FRAMES BIT(13) #define RSI_KEY_ID_MASK 0xC0 #define RSI_KEY_ID_OFFSET 14 @@ -612,7 +613,7 @@ 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); + u8 key_type, u8 key_id, u32 cipher, s16 sta_id); 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 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/rsi_main.h') 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 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/rsi_main.h') 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 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/rsi_main.h') 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 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/rsi_main.h') 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 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/rsi_main.h') 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 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/rsi_main.h') 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