OSDN Git Service

wil6210: Add EDMG channel support
authorAlexei Avshalom Lazar <ailizaro@codeaurora.org>
Sun, 18 Aug 2019 14:35:18 +0000 (17:35 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 4 Sep 2019 06:06:26 +0000 (09:06 +0300)
Add support for Enhanced Directional Multi-Gigabit (EDMG) channels 9-11.
wil6210 reports it's EDMG capabilities (that are also based on FW
capability) to cfg80211 by filling
wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.
wil6210 handles edmg.channels and edmg.bw_config requested in connect
and start_ap operations.

Signed-off-by: Alexei Avshalom Lazar <ailizaro@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/txrx_edma.c
drivers/net/wireless/ath/wil6210/txrx_edma.h
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/ath/wil6210/wmi.h

index 2414f57..1883690 100644 (file)
 
 #define WIL_MAX_ROC_DURATION_MS 5000
 
+#define WIL_EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1))
+#define WIL_EDMG_CHANNEL_10_SUBCHANNELS        (BIT(1) | BIT(2))
+#define WIL_EDMG_CHANNEL_11_SUBCHANNELS        (BIT(2) | BIT(3))
+
+/* WIL_EDMG_BW_CONFIGURATION define the allowed channel bandwidth
+ * configurations as defined by IEEE 802.11 section 9.4.2.251, Table 13.
+ * The value 5 allowing CB1 and CB2 of adjacent channels.
+ */
+#define WIL_EDMG_BW_CONFIGURATION 5
+
+/* WIL_EDMG_CHANNELS is a bitmap that indicates the 2.16 GHz channel(s) that
+ * are allowed to be used for EDMG transmissions in the BSS as defined by
+ * IEEE 802.11 section 9.4.2.251.
+ */
+#define WIL_EDMG_CHANNELS (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
 bool disable_ap_sme;
 module_param(disable_ap_sme, bool, 0444);
 MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
@@ -51,6 +67,39 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
        CHAN60G(4, 0),
 };
 
+/* Rx channel bonding mode */
+enum wil_rx_cb_mode {
+       WIL_RX_CB_MODE_DMG,
+       WIL_RX_CB_MODE_EDMG,
+       WIL_RX_CB_MODE_WIDE,
+};
+
+static int wil_rx_cb_mode_to_n_bonded(u8 cb_mode)
+{
+       switch (cb_mode) {
+       case WIL_RX_CB_MODE_DMG:
+       case WIL_RX_CB_MODE_EDMG:
+               return 1;
+       case WIL_RX_CB_MODE_WIDE:
+               return 2;
+       default:
+               return 1;
+       }
+}
+
+static int wil_tx_cb_mode_to_n_bonded(u8 cb_mode)
+{
+       switch (cb_mode) {
+       case WMI_TX_MODE_DMG:
+       case WMI_TX_MODE_EDMG_CB1:
+               return 1;
+       case WMI_TX_MODE_EDMG_CB2:
+               return 2;
+       default:
+               return 1;
+       }
+}
+
 static void
 wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len)
 {
@@ -82,6 +131,13 @@ void update_supported_bands(struct wil6210_priv *wil)
 
        wiphy->bands[NL80211_BAND_60GHZ]->n_channels =
                                                wil_num_supported_channels(wil);
+
+       if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) {
+               wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.channels =
+                                                       WIL_EDMG_CHANNELS;
+               wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.bw_config =
+                                                     WIL_EDMG_BW_CONFIGURATION;
+       }
 }
 
 /* Vendor id to be used in vendor specific command and events
@@ -300,6 +356,86 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
        return -EOPNOTSUPP;
 }
 
+int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch)
+{
+       switch (spec_ch) {
+       case 1:
+               *wmi_ch = WMI_CHANNEL_1;
+               break;
+       case 2:
+               *wmi_ch = WMI_CHANNEL_2;
+               break;
+       case 3:
+               *wmi_ch = WMI_CHANNEL_3;
+               break;
+       case 4:
+               *wmi_ch = WMI_CHANNEL_4;
+               break;
+       case 5:
+               *wmi_ch = WMI_CHANNEL_5;
+               break;
+       case 6:
+               *wmi_ch = WMI_CHANNEL_6;
+               break;
+       case 9:
+               *wmi_ch = WMI_CHANNEL_9;
+               break;
+       case 10:
+               *wmi_ch = WMI_CHANNEL_10;
+               break;
+       case 11:
+               *wmi_ch = WMI_CHANNEL_11;
+               break;
+       case 12:
+               *wmi_ch = WMI_CHANNEL_12;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch)
+{
+       switch (wmi_ch) {
+       case WMI_CHANNEL_1:
+               *spec_ch = 1;
+               break;
+       case WMI_CHANNEL_2:
+               *spec_ch = 2;
+               break;
+       case WMI_CHANNEL_3:
+               *spec_ch = 3;
+               break;
+       case WMI_CHANNEL_4:
+               *spec_ch = 4;
+               break;
+       case WMI_CHANNEL_5:
+               *spec_ch = 5;
+               break;
+       case WMI_CHANNEL_6:
+               *spec_ch = 6;
+               break;
+       case WMI_CHANNEL_9:
+               *spec_ch = 9;
+               break;
+       case WMI_CHANNEL_10:
+               *spec_ch = 10;
+               break;
+       case WMI_CHANNEL_11:
+               *spec_ch = 11;
+               break;
+       case WMI_CHANNEL_12:
+               *spec_ch = 12;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
                       struct station_info *sinfo)
 {
@@ -314,6 +450,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
        } __packed reply;
        struct wil_net_stats *stats = &wil->sta[cid].stats;
        int rc;
+       u8 txflag = RATE_INFO_FLAGS_DMG;
 
        memset(&reply, 0, sizeof(reply));
 
@@ -327,7 +464,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
                    "  MCS %d TSF 0x%016llx\n"
                    "  BF status 0x%08x RSSI %d SQI %d%%\n"
                    "  Tx Tpt %d goodput %d Rx goodput %d\n"
-                   "  Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
+                   "  Sectors(rx:tx) my %d:%d peer %d:%d\n"
+                   "  Tx mode %d}\n",
                    cid, vif->mid, le16_to_cpu(reply.evt.bf_mcs),
                    le64_to_cpu(reply.evt.tsf), reply.evt.status,
                    reply.evt.rssi,
@@ -338,7 +476,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
                    le16_to_cpu(reply.evt.my_rx_sector),
                    le16_to_cpu(reply.evt.my_tx_sector),
                    le16_to_cpu(reply.evt.other_rx_sector),
-                   le16_to_cpu(reply.evt.other_tx_sector));
+                   le16_to_cpu(reply.evt.other_tx_sector),
+                   reply.evt.tx_mode);
 
        sinfo->generation = wil->sinfo_gen;
 
@@ -351,9 +490,16 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
                        BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) |
                        BIT_ULL(NL80211_STA_INFO_TX_FAILED);
 
-       sinfo->txrate.flags = RATE_INFO_FLAGS_DMG;
+       if (wil->use_enhanced_dma_hw && reply.evt.tx_mode != WMI_TX_MODE_DMG)
+               txflag = RATE_INFO_FLAGS_EDMG;
+
+       sinfo->txrate.flags = txflag;
        sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
        sinfo->rxrate.mcs = stats->last_mcs_rx;
+       sinfo->txrate.n_bonded_ch =
+                                 wil_tx_cb_mode_to_n_bonded(reply.evt.tx_mode);
+       sinfo->rxrate.n_bonded_ch =
+                            wil_rx_cb_mode_to_n_bonded(stats->last_cb_mode_rx);
        sinfo->rx_bytes = stats->rx_bytes;
        sinfo->rx_packets = stats->rx_packets;
        sinfo->rx_dropped_misc = stats->rx_dropped;
@@ -1022,6 +1168,33 @@ static int wil_ft_connect(struct wiphy *wiphy,
        return rc;
 }
 
+static int wil_get_wmi_edmg_channel(struct wil6210_priv *wil, u8 edmg_bw_config,
+                                   u8 edmg_channels, u8 *wmi_ch)
+{
+       if (!edmg_bw_config) {
+               *wmi_ch = 0;
+               return 0;
+       } else if (edmg_bw_config == WIL_EDMG_BW_CONFIGURATION) {
+               /* convert from edmg channel bitmap into edmg channel number */
+               switch (edmg_channels) {
+               case WIL_EDMG_CHANNEL_9_SUBCHANNELS:
+                       return wil_spec2wmi_ch(9, wmi_ch);
+               case WIL_EDMG_CHANNEL_10_SUBCHANNELS:
+                       return wil_spec2wmi_ch(10, wmi_ch);
+               case WIL_EDMG_CHANNEL_11_SUBCHANNELS:
+                       return wil_spec2wmi_ch(11, wmi_ch);
+               default:
+                       wil_err(wil, "Unsupported edmg channel bitmap 0x%x\n",
+                               edmg_channels);
+                       return -EINVAL;
+               }
+       } else {
+               wil_err(wil, "Unsupported EDMG BW configuration %d\n",
+                       edmg_bw_config);
+               return -EINVAL;
+       }
+}
+
 static int wil_cfg80211_connect(struct wiphy *wiphy,
                                struct net_device *ndev,
                                struct cfg80211_connect_params *sme)
@@ -1167,6 +1340,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
        memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
        conn.channel = ch - 1;
 
+       rc = wil_get_wmi_edmg_channel(wil, sme->edmg.bw_config,
+                                     sme->edmg.channels, &conn.edmg_channel);
+       if (rc < 0)
+               return rc;
+
        ether_addr_copy(conn.bssid, bss->bssid);
        ether_addr_copy(conn.dst_mac, bss->bssid);
 
@@ -1728,7 +1906,7 @@ out:
 static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
                                  struct net_device *ndev,
                                  const u8 *ssid, size_t ssid_len, u32 privacy,
-                                 int bi, u8 chan,
+                                 int bi, u8 chan, u8 wmi_edmg_channel,
                                  struct cfg80211_beacon_data *bcon,
                                  u8 hidden_ssid, u32 pbss)
 {
@@ -1791,6 +1969,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
 
        vif->privacy = privacy;
        vif->channel = chan;
+       vif->wmi_edmg_channel = wmi_edmg_channel;
        vif->hidden_ssid = hidden_ssid;
        vif->pbss = pbss;
        vif->bi = bi;
@@ -1801,7 +1980,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
        if (!wil_has_other_active_ifaces(wil, ndev, false, true))
                wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
 
-       rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go);
+       rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, wmi_edmg_channel,
+                          hidden_ssid, is_go);
        if (rc)
                goto err_pcp_start;
 
@@ -1853,7 +2033,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
                rc = _wil_cfg80211_start_ap(wiphy, ndev,
                                            vif->ssid, vif->ssid_len,
                                            vif->privacy, vif->bi,
-                                           vif->channel, &bcon,
+                                           vif->channel,
+                                           vif->wmi_edmg_channel, &bcon,
                                            vif->hidden_ssid, vif->pbss);
                if (rc) {
                        wil_err(wil, "vif %d recovery failed (%d)\n", i, rc);
@@ -1903,7 +2084,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
                rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid,
                                            vif->ssid_len, privacy,
                                            wdev->beacon_interval,
-                                           vif->channel, bcon,
+                                           vif->channel,
+                                           vif->wmi_edmg_channel, bcon,
                                            vif->hidden_ssid,
                                            vif->pbss);
        } else {
@@ -1922,10 +2104,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        struct ieee80211_channel *channel = info->chandef.chan;
        struct cfg80211_beacon_data *bcon = &info->beacon;
        struct cfg80211_crypto_settings *crypto = &info->crypto;
+       u8 wmi_edmg_channel;
        u8 hidden_ssid;
 
        wil_dbg_misc(wil, "start_ap\n");
 
+       rc = wil_get_wmi_edmg_channel(wil, info->chandef.edmg.bw_config,
+                                     info->chandef.edmg.channels,
+                                     &wmi_edmg_channel);
+       if (rc < 0)
+               return rc;
+
        if (!channel) {
                wil_err(wil, "AP: No channel???\n");
                return -EINVAL;
@@ -1965,7 +2154,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        rc = _wil_cfg80211_start_ap(wiphy, ndev,
                                    info->ssid, info->ssid_len, info->privacy,
                                    info->beacon_interval, channel->hw_value,
-                                   bcon, hidden_ssid, info->pbss);
+                                   wmi_edmg_channel, bcon, hidden_ssid,
+                                   info->pbss);
 
        return rc;
 }
index 71b7ad4..29a9a24 100644 (file)
@@ -1023,6 +1023,8 @@ skipping:
                stats->last_mcs_rx = wil_rx_status_get_mcs(msg);
                if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
                        stats->rx_per_mcs[stats->last_mcs_rx]++;
+
+               stats->last_cb_mode_rx  = wil_rx_status_get_cb_mode(msg);
        }
 
        if (!wil->use_rx_hw_reordering && !wil->use_compressed_rx_status &&
index e9e6ea9..724d223 100644 (file)
@@ -366,6 +366,12 @@ static inline u8 wil_rx_status_get_mcs(void *msg)
                            16, 21);
 }
 
+static inline u8 wil_rx_status_get_cb_mode(void *msg)
+{
+       return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
+                           22, 23);
+}
+
 static inline u16 wil_rx_status_get_flow_id(void *msg)
 {
        return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
index 25a1adc..ecda3ca 100644 (file)
@@ -590,6 +590,7 @@ struct wil_net_stats {
        unsigned long   rx_amsdu_error; /* eDMA specific */
        unsigned long   rx_csum_err;
        u16 last_mcs_rx;
+       u8 last_cb_mode_rx;
        u64 rx_per_mcs[WIL_MCS_MAX + 1];
        u32 ft_roams; /* relevant in STA mode */
 };
@@ -850,6 +851,7 @@ struct wil6210_vif {
        DECLARE_BITMAP(status, wil_vif_status_last);
        u32 privacy; /* secure connection? */
        u16 channel; /* relevant in AP mode */
+       u8 wmi_edmg_channel; /* relevant in AP mode */
        u8 hidden_ssid; /* relevant in AP mode */
        u32 ap_isolate; /* no intra-BSS communication */
        bool pbss;
@@ -1335,7 +1337,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil);
 
 int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
 int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan,
-                 u8 hidden_ssid, u8 is_go);
+                 u8 edmg_chan, u8 hidden_ssid, u8 is_go);
 int wmi_pcp_stop(struct wil6210_vif *vif);
 int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
 int wmi_abort_scan(struct wil6210_vif *vif);
@@ -1412,6 +1414,10 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
                    u8 channel, u16 duration_ms);
 int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold);
 
+int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch);
+int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch);
+void wil_update_supported_bands(struct wil6210_priv *wil);
+
 int reverse_memcmp(const void *cs, const void *ct, size_t count);
 
 /* WMI for enhanced DMA */
index 475b1a2..5760d14 100644 (file)
@@ -2163,8 +2163,8 @@ int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold)
        return rc;
 }
 
-int wmi_pcp_start(struct wil6210_vif *vif,
-                 int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
+int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype,
+                 u8 chan, u8 wmi_edmg_chan, u8 hidden_ssid, u8 is_go)
 {
        struct wil6210_priv *wil = vif_to_wil(vif);
        int rc;
@@ -2174,6 +2174,7 @@ int wmi_pcp_start(struct wil6210_vif *vif,
                .network_type = wmi_nettype,
                .disable_sec_offload = 1,
                .channel = chan - 1,
+               .edmg_channel = wmi_edmg_chan,
                .pcp_max_assoc_sta = wil->max_assoc_sta,
                .hidden_ssid = hidden_ssid,
                .is_go = is_go,
index 3e37229..d75022b 100644 (file)
@@ -97,6 +97,7 @@ enum wmi_fw_capability {
        WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE         = 13,
        WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP       = 14,
        WMI_FW_CAPABILITY_PNO                           = 15,
+       WMI_FW_CAPABILITY_CHANNEL_BONDING               = 17,
        WMI_FW_CAPABILITY_REF_CLOCK_CONTROL             = 18,
        WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE           = 19,
        WMI_FW_CAPABILITY_MULTI_VIFS                    = 20,
@@ -361,6 +362,19 @@ enum wmi_connect_ctrl_flag_bits {
 
 #define WMI_MAX_SSID_LEN       (32)
 
+enum wmi_channel {
+       WMI_CHANNEL_1   = 0x00,
+       WMI_CHANNEL_2   = 0x01,
+       WMI_CHANNEL_3   = 0x02,
+       WMI_CHANNEL_4   = 0x03,
+       WMI_CHANNEL_5   = 0x04,
+       WMI_CHANNEL_6   = 0x05,
+       WMI_CHANNEL_9   = 0x06,
+       WMI_CHANNEL_10  = 0x07,
+       WMI_CHANNEL_11  = 0x08,
+       WMI_CHANNEL_12  = 0x09,
+};
+
 /* WMI_CONNECT_CMDID */
 struct wmi_connect_cmd {
        u8 network_type;
@@ -372,8 +386,12 @@ struct wmi_connect_cmd {
        u8 group_crypto_len;
        u8 ssid_len;
        u8 ssid[WMI_MAX_SSID_LEN];
+       /* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is
+        * the primary channel number
+        */
        u8 channel;
-       u8 reserved0;
+       /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */
+       u8 edmg_channel;
        u8 bssid[WMI_MAC_LEN];
        __le32 ctrl_flags;
        u8 dst_mac[WMI_MAC_LEN];
@@ -2312,8 +2330,12 @@ struct wmi_notify_req_done_event {
 
 /* WMI_CONNECT_EVENTID */
 struct wmi_connect_event {
+       /* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is
+        * the primary channel number
+        */
        u8 channel;
-       u8 reserved0;
+       /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */
+       u8 edmg_channel;
        u8 bssid[WMI_MAC_LEN];
        __le16 listen_interval;
        __le16 beacon_interval;