mwifiex: add usb multi channel event process support
authorZhaoyang Liu <liuzy@marvell.com>
Fri, 18 Sep 2015 13:32:15 +0000 (06:32 -0700)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 29 Sep 2015 07:47:44 +0000 (10:47 +0300)
This patch add multi channel event process for USB multi tx data endpoints.
Driver receives firmware multi channel event only in case that new
connection is setup or interface is disconnect. Different BSS interface
need update used usb endpoint.

Signed-off-by: Zhaoyang Liu <liuzy@marvell.com>
Signed-off-by: Cathy Luo <cluo@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/usb.c

index 3ec2ac82e394a158e6c346d75e73a29715e7ec29..0e6f029458d531142f0ad29a31b23132547f5a86 100644 (file)
@@ -104,6 +104,7 @@ enum KEY_TYPE_ID {
 enum mwifiex_usb_ep {
        MWIFIEX_USB_EP_CMD_EVENT = 1,
        MWIFIEX_USB_EP_DATA = 2,
+       MWIFIEX_USB_EP_DATA_CH2 = 3,
 };
 
 enum MWIFIEX_802_11_PRIVACY_FILTER {
@@ -173,6 +174,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
 #define TLV_TYPE_MULTI_CHAN_INFO    (PROPRIETARY_TLV_BASE_ID + 183)
+#define TLV_TYPE_MC_GROUP_INFO      (PROPRIETARY_TLV_BASE_ID + 184)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
 #define TLV_TYPE_SCAN_CHANNEL_GAP   (PROPRIETARY_TLV_BASE_ID + 197)
 #define TLV_TYPE_API_REV            (PROPRIETARY_TLV_BASE_ID + 199)
@@ -1984,6 +1986,22 @@ struct mwifiex_ie_types_multi_chan_info {
        u8 tlv_buffer[0];
 } __packed;
 
+struct mwifiex_ie_types_mc_group_info {
+       struct mwifiex_ie_types_header header;
+       u8 chan_group_id;
+       u8 chan_buf_weight;
+       u8 band_config;
+       u8 chan_num;
+       u32 chan_time;
+       u32 reserved;
+       union {
+               u8 sdio_func_num;
+               u8 usb_ep_num;
+       } hid_num;
+       u8 intf_num;
+       u8 bss_type_numlist[0];
+} __packed;
+
 struct meas_rpt_map {
        u8 rssi:3;
        u8 unmeasured:1;
index 5d3ae63baea4c1950203563f712bda2f83c04988..de74a7773fb6b22db78bafb8fb7f547753d939b7 100644 (file)
@@ -78,6 +78,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
        priv->media_connected = false;
        eth_broadcast_addr(priv->curr_addr);
        priv->port_open = false;
+       priv->usb_port = MWIFIEX_USB_EP_DATA;
        priv->pkt_tx_ctrl = 0;
        priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
        priv->data_rate = 0;    /* Initially indicate the rate as auto */
index 2c2004e991e0edb06c5e79dedfa9ed7ffb314695..9772a186f480d19955610032a201cb40d11a28d0 100644 (file)
@@ -519,6 +519,7 @@ struct mwifiex_private {
        u8 curr_addr[ETH_ALEN];
        u8 media_connected;
        u8 port_open;
+       u8 usb_port;
        u32 num_tx_timeout;
        /* track consecutive timeout */
        u8 tx_timeout_cnt;
@@ -989,6 +990,7 @@ struct mwifiex_adapter {
        u8 coex_rx_win_size;
        bool drcs_enabled;
        u8 active_scan_triggered;
+       bool usb_mc_status;
 };
 
 void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
index 3d18c585e5436769061a3de767e17c22674206c7..67920899afebc584e83320f168429538fed02118 100644 (file)
@@ -313,25 +313,74 @@ void mwifiex_process_multi_chan_event(struct mwifiex_private *priv,
                                      struct sk_buff *event_skb)
 {
        struct mwifiex_ie_types_multi_chan_info *chan_info;
-       u16 status;
+       struct mwifiex_ie_types_mc_group_info *grp_info;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct mwifiex_ie_types_header *tlv;
+       u16 tlv_buf_left, tlv_type, tlv_len;
+       int intf_num, bss_type, bss_num, i;
+       struct mwifiex_private *intf_priv;
 
+       tlv_buf_left = event_skb->len - sizeof(u32);
        chan_info = (void *)event_skb->data + sizeof(u32);
 
-       if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) {
-               mwifiex_dbg(priv->adapter, ERROR,
+       if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO ||
+           tlv_buf_left < sizeof(struct mwifiex_ie_types_multi_chan_info)) {
+               mwifiex_dbg(adapter, ERROR,
                            "unknown TLV in chan_info event\n");
                return;
        }
 
-       status = le16_to_cpu(chan_info->status);
+       adapter->usb_mc_status = le16_to_cpu(chan_info->status);
+       mwifiex_dbg(adapter, EVENT, "multi chan operation %s\n",
+                   adapter->usb_mc_status ? "started" : "over");
 
-       if (status) {
-               mwifiex_dbg(priv->adapter, EVENT,
-                           "multi-channel operation started\n");
-       } else {
-               mwifiex_dbg(priv->adapter, EVENT,
-                           "multi-channel operation over\n");
+       tlv_buf_left -= sizeof(struct mwifiex_ie_types_multi_chan_info);
+       tlv = (struct mwifiex_ie_types_header *)chan_info->tlv_buffer;
+
+       while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) {
+               tlv_type = le16_to_cpu(tlv->type);
+               tlv_len  = le16_to_cpu(tlv->len);
+               if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) >
+                   tlv_buf_left) {
+                       mwifiex_dbg(adapter, ERROR, "wrong tlv: tlvLen=%d,\t"
+                                   "tlvBufLeft=%d\n", tlv_len, tlv_buf_left);
+                       break;
+               }
+               if (tlv_type != TLV_TYPE_MC_GROUP_INFO) {
+                       mwifiex_dbg(adapter, ERROR, "wrong tlv type: 0x%x\n",
+                                   tlv_type);
+                       break;
+               }
+
+               grp_info = (struct mwifiex_ie_types_mc_group_info *)tlv;
+               intf_num = grp_info->intf_num;
+               for (i = 0; i < intf_num; i++) {
+                       bss_type = grp_info->bss_type_numlist[i] >> 4;
+                       bss_num = grp_info->bss_type_numlist[i] & BSS_NUM_MASK;
+                       intf_priv = mwifiex_get_priv_by_id(adapter, bss_num,
+                                                          bss_type);
+                       if (!intf_priv) {
+                               mwifiex_dbg(adapter, ERROR,
+                                           "Invalid bss_type bss_num\t"
+                                           "in multi channel event\n");
+                               continue;
+                       }
+                       if (adapter->iface_type == MWIFIEX_USB) {
+                               u8 ep;
+
+                               ep = grp_info->hid_num.usb_ep_num;
+                               if (ep == MWIFIEX_USB_EP_DATA ||
+                                   ep == MWIFIEX_USB_EP_DATA_CH2)
+                                       intf_priv->usb_port = ep;
+                       }
+               }
+
+               tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) +
+                               tlv_len;
+               tlv = (void *)((u8 *)tlv + tlv_len +
+                              sizeof(struct mwifiex_ie_types_header));
        }
+
 }
 
 void mwifiex_process_tx_pause_event(struct mwifiex_private *priv,
index 01438a4e1732c7b9fd54b583da30da37706e9f7e..54c9b4517700a3bbf3506a388c4ef3f3d1e59917 100644 (file)
@@ -858,6 +858,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
                break;
        }
 
+       adapter->usb_mc_status = false;
+
        return 0;
 }