diff options
Diffstat (limited to 'drivers/net/wireless/quantenna/qtnfmac')
-rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 103 | ||||
-rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/commands.c | 211 | ||||
-rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/commands.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/core.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/core.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/quantenna/qtnfmac/qlink.h | 105 |
6 files changed, 428 insertions, 23 deletions
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index ae0ca8006849..4aa332f4646b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -843,6 +843,88 @@ static int qtnf_set_mac_acl(struct wiphy *wiphy, return ret; } +static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_pm_set(vif, enabled ? QLINK_PM_AUTO_STANDBY : + QLINK_PM_OFF, timeout); + if (ret) { + pr_err("%s: failed to set PM mode ret=%d\n", dev->name, ret); + return ret; + } + + return ret; +} + +#ifdef CONFIG_PM +static int qtnf_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif; + int ret = 0; + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + ret = -EFAULT; + goto exit; + } + + if (!wowlan) { + pr_debug("WoWLAN triggers are not enabled\n"); + qtnf_virtual_intf_cleanup(vif->netdev); + goto exit; + } + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_wowlan_set(vif, wowlan); + if (ret) { + pr_err("MAC%u: failed to set WoWLAN triggers\n", + mac->macid); + goto exit; + } + +exit: + return ret; +} + +static int qtnf_resume(struct wiphy *wiphy) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif; + int ret = 0; + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + ret = -EFAULT; + goto exit; + } + + ret = qtnf_cmd_send_wowlan_set(vif, NULL); + if (ret) { + pr_err("MAC%u: failed to reset WoWLAN triggers\n", + mac->macid); + goto exit; + } + +exit: + return ret; +} + +static void qtnf_set_wakeup(struct wiphy *wiphy, bool enabled) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_bus *bus = mac->bus; + + device_set_wakeup_enable(bus->dev, enabled); +} +#endif + static struct cfg80211_ops qtn_cfg80211_ops = { .add_virtual_intf = qtnf_add_virtual_intf, .change_virtual_intf = qtnf_change_virtual_intf, @@ -869,6 +951,12 @@ static struct cfg80211_ops qtn_cfg80211_ops = { .channel_switch = qtnf_channel_switch, .start_radar_detection = qtnf_start_radar_detection, .set_mac_acl = qtnf_set_mac_acl, + .set_power_mgmt = qtnf_set_power_mgmt, +#ifdef CONFIG_PM + .suspend = qtnf_suspend, + .resume = qtnf_resume, + .set_wakeup = qtnf_set_wakeup, +#endif }; static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in, @@ -921,6 +1009,9 @@ struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus) if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD) qtn_cfg80211_ops.start_radar_detection = NULL; + if (!(bus->hw_info.hw_capab & QLINK_HW_CAPAB_PWR_MGMT)) + qtn_cfg80211_ops.set_power_mgmt = NULL; + wiphy = wiphy_new(&qtn_cfg80211_ops, sizeof(struct qtnf_wmac)); if (!wiphy) return NULL; @@ -975,7 +1066,8 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) wiphy->retry_long = macinfo->lretry_limit; wiphy->coverage_class = macinfo->coverage_class; - wiphy->max_scan_ssids = QTNF_MAX_SSID_LIST_LENGTH; + wiphy->max_scan_ssids = + (hw_info->max_scan_ssids) ? hw_info->max_scan_ssids : 1; wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN; wiphy->mgmt_stypes = qtnf_mgmt_stypes; wiphy->max_remain_on_channel_duration = 5000; @@ -994,6 +1086,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; if (hw_info->hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD); @@ -1013,6 +1106,14 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) if (hw_info->hw_capab & QLINK_HW_CAPAB_STA_INACT_TIMEOUT) wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; + if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR) + wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + +#ifdef CONFIG_PM + if (macinfo->wowlan) + wiphy->wowlan = macinfo->wowlan; +#endif + if (hw_info->hw_capab & QLINK_HW_CAPAB_REG_UPDATE) { wiphy->regulatory_flags |= REGULATORY_STRICT_REG | REGULATORY_CUSTOM_REG; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index c5d94a95e21a..ae9e77300533 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -640,83 +640,83 @@ qtnf_cmd_sta_info_parse(struct station_info *sinfo, return; if (qtnf_sta_stat_avail(inactive_time, QLINK_STA_INFO_INACTIVE_TIME)) { - sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME); sinfo->inactive_time = le32_to_cpu(stats->inactive_time); } if (qtnf_sta_stat_avail(connected_time, QLINK_STA_INFO_CONNECTED_TIME)) { - sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME); sinfo->connected_time = le32_to_cpu(stats->connected_time); } if (qtnf_sta_stat_avail(signal, QLINK_STA_INFO_SIGNAL)) { - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); sinfo->signal = stats->signal - QLINK_RSSI_OFFSET; } if (qtnf_sta_stat_avail(signal_avg, QLINK_STA_INFO_SIGNAL_AVG)) { - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); sinfo->signal_avg = stats->signal_avg - QLINK_RSSI_OFFSET; } if (qtnf_sta_stat_avail(rxrate, QLINK_STA_INFO_RX_BITRATE)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); qtnf_sta_info_parse_rate(&sinfo->rxrate, &stats->rxrate); } if (qtnf_sta_stat_avail(txrate, QLINK_STA_INFO_TX_BITRATE)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); qtnf_sta_info_parse_rate(&sinfo->txrate, &stats->txrate); } if (qtnf_sta_stat_avail(sta_flags, QLINK_STA_INFO_STA_FLAGS)) { - sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS); qtnf_sta_info_parse_flags(&sinfo->sta_flags, &stats->sta_flags); } if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES); sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes); } if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES); sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes); } if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES64)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes); } if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES64)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes); } if (qtnf_sta_stat_avail(rx_packets, QLINK_STA_INFO_RX_PACKETS)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); sinfo->rx_packets = le32_to_cpu(stats->rx_packets); } if (qtnf_sta_stat_avail(tx_packets, QLINK_STA_INFO_TX_PACKETS)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); sinfo->tx_packets = le32_to_cpu(stats->tx_packets); } if (qtnf_sta_stat_avail(rx_beacon, QLINK_STA_INFO_BEACON_RX)) { - sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX); sinfo->rx_beacon = le64_to_cpu(stats->rx_beacon); } if (qtnf_sta_stat_avail(rx_dropped_misc, QLINK_STA_INFO_RX_DROP_MISC)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC); sinfo->rx_dropped_misc = le32_to_cpu(stats->rx_dropped_misc); } if (qtnf_sta_stat_avail(tx_failed, QLINK_STA_INFO_TX_FAILED)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); sinfo->tx_failed = le32_to_cpu(stats->tx_failed); } @@ -1092,6 +1092,9 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, case QTN_TLV_ID_UBOOT_VER: uboot_ver = (const void *)tlv->val; break; + case QTN_TLV_ID_MAX_SCAN_SSIDS: + hwinfo->max_scan_ssids = *tlv->val; + break; default: break; } @@ -1135,6 +1138,37 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, return 0; } +static void +qtnf_parse_wowlan_info(struct qtnf_wmac *mac, + const struct qlink_wowlan_capab_data *wowlan) +{ + struct qtnf_mac_info *mac_info = &mac->macinfo; + const struct qlink_wowlan_support *data1; + struct wiphy_wowlan_support *supp; + + supp = kzalloc(sizeof(*supp), GFP_KERNEL); + if (!supp) + return; + + switch (le16_to_cpu(wowlan->version)) { + case 0x1: + data1 = (struct qlink_wowlan_support *)wowlan->data; + + supp->flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT; + supp->n_patterns = le32_to_cpu(data1->n_patterns); + supp->pattern_max_len = le32_to_cpu(data1->pattern_max_len); + supp->pattern_min_len = le32_to_cpu(data1->pattern_min_len); + + mac_info->wowlan = supp; + break; + default: + pr_warn("MAC%u: unsupported WoWLAN version 0x%x\n", + mac->macid, le16_to_cpu(wowlan->version)); + kfree(supp); + break; + } +} + static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, const u8 *tlv_buf, size_t tlv_buf_size) { @@ -1144,6 +1178,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, const struct qlink_iface_comb_num *comb_num; const struct qlink_iface_limit_record *rec; const struct qlink_iface_limit *lim; + const struct qlink_wowlan_capab_data *wowlan; u16 rec_len; u16 tlv_type; u16 tlv_value_len; @@ -1252,7 +1287,31 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, ext_capa_mask = (u8 *)tlv->val; ext_capa_mask_len = tlv_value_len; break; + case QTN_TLV_ID_WOWLAN_CAPAB: + if (tlv_value_len < sizeof(*wowlan)) + return -EINVAL; + + wowlan = (void *)tlv->val; + if (!le16_to_cpu(wowlan->len)) { + pr_warn("MAC%u: skip empty WoWLAN data\n", + mac->macid); + break; + } + + rec_len = sizeof(*wowlan) + le16_to_cpu(wowlan->len); + if (unlikely(tlv_value_len != rec_len)) { + pr_warn("MAC%u: WoWLAN data size mismatch\n", + mac->macid); + return -EINVAL; + } + + kfree(mac->macinfo.wowlan); + mac->macinfo.wowlan = NULL; + qtnf_parse_wowlan_info(mac, wowlan); + break; default: + pr_warn("MAC%u: unknown TLV type %u\n", + mac->macid, tlv_type); break; } @@ -2234,6 +2293,22 @@ static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb, qchan->chan.flags = cpu_to_le32(flags); } +static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb, + const u8 *mac_addr, + const u8 *mac_addr_mask) +{ + struct qlink_random_mac_addr *randmac; + struct qlink_tlv_hdr *hdr = + skb_put(cmd_skb, sizeof(*hdr) + sizeof(*randmac)); + + hdr->type = cpu_to_le16(QTN_TLV_ID_RANDOM_MAC_ADDR); + hdr->len = cpu_to_le16(sizeof(*randmac)); + randmac = (struct qlink_random_mac_addr *)hdr->val; + + memcpy(randmac->mac_addr, mac_addr, ETH_ALEN); + memcpy(randmac->mac_addr_mask, mac_addr_mask, ETH_ALEN); +} + int qtnf_cmd_send_scan(struct qtnf_wmac *mac) { struct sk_buff *cmd_skb; @@ -2244,11 +2319,6 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) int count = 0; int ret; - if (scan_req->n_ssids > QTNF_MAX_SSID_LIST_LENGTH) { - pr_err("MAC%u: too many SSIDs in scan request\n", mac->macid); - return -EINVAL; - } - cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, QLINK_CMD_SCAN, sizeof(struct qlink_cmd)); @@ -2291,6 +2361,15 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) } } + if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + pr_debug("MAC%u: scan with random addr=%pM, mask=%pM\n", + mac->macid, + scan_req->mac_addr, scan_req->mac_addr_mask); + + qtnf_cmd_randmac_tlv_add(cmd_skb, scan_req->mac_addr, + scan_req->mac_addr_mask); + } + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); if (unlikely(ret)) @@ -2774,3 +2853,93 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, return ret; } + +int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout) +{ + struct qtnf_bus *bus = vif->mac->bus; + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + struct qlink_cmd_pm_set *cmd; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_PM_SET, sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_pm_set *)cmd_skb->data; + cmd->pm_mode = pm_mode; + cmd->pm_standby_timer = cpu_to_le32(timeout); + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send(bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + } + +out: + qtnf_bus_unlock(bus); + return ret; +} + +int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, + const struct cfg80211_wowlan *wowl) +{ + struct qtnf_bus *bus = vif->mac->bus; + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + struct qlink_cmd_wowlan_set *cmd; + u32 triggers = 0; + int count = 0; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_WOWLAN_SET, sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + qtnf_bus_lock(bus); + + cmd = (struct qlink_cmd_wowlan_set *)cmd_skb->data; + + if (wowl) { + if (wowl->disconnect) + triggers |= QLINK_WOWLAN_TRIG_DISCONNECT; + + if (wowl->magic_pkt) + triggers |= QLINK_WOWLAN_TRIG_MAGIC_PKT; + + if (wowl->n_patterns && wowl->patterns) { + triggers |= QLINK_WOWLAN_TRIG_PATTERN_PKT; + while (count < wowl->n_patterns) { + qtnf_cmd_skb_put_tlv_arr(cmd_skb, + QTN_TLV_ID_WOWLAN_PATTERN, + wowl->patterns[count].pattern, + wowl->patterns[count].pattern_len); + count++; + } + } + } + + cmd->triggers = cpu_to_le32(triggers); + + ret = qtnf_cmd_send(bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + } + +out: + qtnf_bus_unlock(bus); + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index cf9274add26d..1ac41156c192 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -76,5 +76,8 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif, u32 cac_time_ms); int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, const struct cfg80211_acl_data *params); +int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout); +int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, + const struct cfg80211_wowlan *wowl); #endif /* QLINK_COMMANDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index a6a450984f9a..19abbc4e23e0 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -179,6 +179,30 @@ static void qtnf_netdev_tx_timeout(struct net_device *ndev) } } +static int qtnf_netdev_set_mac_address(struct net_device *ndev, void *addr) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + struct sockaddr *sa = addr; + int ret; + unsigned char old_addr[ETH_ALEN]; + + memcpy(old_addr, sa->sa_data, sizeof(old_addr)); + + ret = eth_mac_addr(ndev, sa); + if (ret) + return ret; + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_change_intf_type(vif, vif->wdev.iftype, + sa->sa_data); + + if (ret) + memcpy(ndev->dev_addr, old_addr, ETH_ALEN); + + return ret; +} + /* Network device ops handlers */ const struct net_device_ops qtnf_netdev_ops = { .ndo_open = qtnf_netdev_open, @@ -186,6 +210,7 @@ const struct net_device_ops qtnf_netdev_ops = { .ndo_start_xmit = qtnf_netdev_hard_start_xmit, .ndo_tx_timeout = qtnf_netdev_tx_timeout, .ndo_get_stats64 = qtnf_netdev_get_stats64, + .ndo_set_mac_address = qtnf_netdev_set_mac_address, }; static int qtnf_mac_init_single_band(struct wiphy *wiphy, @@ -470,6 +495,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) qtnf_mac_iface_comb_free(mac); kfree(mac->macinfo.extended_capabilities); kfree(mac->macinfo.extended_capabilities_mask); + kfree(mac->macinfo.wowlan); wiphy_free(wiphy); bus->mac[macid] = NULL; } diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index 214435448335..a1e338a1f055 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -40,7 +40,6 @@ #undef pr_fmt #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ -#define QTNF_MAX_SSID_LIST_LENGTH 2 #define QTNF_MAX_VSIE_LEN 255 #define QTNF_MAX_INTF 8 #define QTNF_MAX_EVENT_QUEUE_LEN 255 @@ -111,6 +110,7 @@ struct qtnf_mac_info { u8 *extended_capabilities; u8 *extended_capabilities_mask; u8 extended_capabilities_len; + struct wiphy_wowlan_support *wowlan; }; struct qtnf_chan_stats { @@ -145,6 +145,7 @@ struct qtnf_hw_info { u8 total_rx_chain; char fw_version[ETHTOOL_FWVERS_LEN]; u32 hw_version; + u8 max_scan_ssids; }; struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac); diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index f85deda703fb..99d37e3efba6 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -69,11 +69,15 @@ struct qlink_msg_header { * associated STAs due to inactivity. Inactivity timeout period is taken * from QLINK_CMD_START_AP parameters. * @QLINK_HW_CAPAB_DFS_OFFLOAD: device implements DFS offload functionality + * @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address + * Randomization in probe requests. */ enum qlink_hw_capab { QLINK_HW_CAPAB_REG_UPDATE = BIT(0), QLINK_HW_CAPAB_STA_INACT_TIMEOUT = BIT(1), QLINK_HW_CAPAB_DFS_OFFLOAD = BIT(2), + QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR = BIT(3), + QLINK_HW_CAPAB_PWR_MGMT = BIT(4), }; enum qlink_iface_type { @@ -253,6 +257,8 @@ enum qlink_cmd_type { QLINK_CMD_CHAN_STATS = 0x0054, QLINK_CMD_CONNECT = 0x0060, QLINK_CMD_DISCONNECT = 0x0061, + QLINK_CMD_PM_SET = 0x0062, + QLINK_CMD_WOWLAN_SET = 0x0063, }; /** @@ -665,6 +671,54 @@ struct qlink_acl_data { struct qlink_mac_address mac_addrs[0]; } __packed; +/** + * enum qlink_pm_mode - Power Management mode + * + * @QLINK_PM_OFF: normal mode, no power saving enabled + * @QLINK_PM_AUTO_STANDBY: enable auto power save mode + */ +enum qlink_pm_mode { + QLINK_PM_OFF = 0, + QLINK_PM_AUTO_STANDBY = 1, +}; + +/** + * struct qlink_cmd_pm_set - data for QLINK_CMD_PM_SET command + * + * @pm_standby timer: period of network inactivity in seconds before + * putting a radio in power save mode + * @pm_mode: power management mode + */ +struct qlink_cmd_pm_set { + struct qlink_cmd chdr; + __le32 pm_standby_timer; + u8 pm_mode; +} __packed; + +/** + * enum qlink_wowlan_trigger + * + * @QLINK_WOWLAN_TRIG_DISCONNECT: wakeup on disconnect + * @QLINK_WOWLAN_TRIG_MAGIC_PKT: wakeup on magic packet + * @QLINK_WOWLAN_TRIG_PATTERN_PKT: wakeup on user-defined packet + */ +enum qlink_wowlan_trigger { + QLINK_WOWLAN_TRIG_DISCONNECT = BIT(0), + QLINK_WOWLAN_TRIG_MAGIC_PKT = BIT(1), + QLINK_WOWLAN_TRIG_PATTERN_PKT = BIT(2), +}; + +/** + * struct qlink_cmd_wowlan_set - data for QLINK_CMD_WOWLAN_SET command + * + * @triggers: requested bitmask of WoWLAN triggers + */ +struct qlink_cmd_wowlan_set { + struct qlink_cmd chdr; + __le32 triggers; + u8 data[0]; +} __packed; + /* QLINK Command Responses messages related definitions */ @@ -1062,6 +1116,8 @@ struct qlink_event_radar { * @QTN_TLV_ID_STA_STATS: per-STA statistics as defined by * &struct qlink_sta_stats. Valid values are marked as such in a bitmap * carried by QTN_TLV_ID_STA_STATS_MAP. + * @QTN_TLV_ID_MAX_SCAN_SSIDS: maximum number of SSIDs the device can scan + * for in any given scan. */ enum qlink_tlv_id { QTN_TLV_ID_FRAG_THRESH = 0x0201, @@ -1089,6 +1145,10 @@ enum qlink_tlv_id { QTN_TLV_ID_HW_ID = 0x0405, QTN_TLV_ID_CALIBRATION_VER = 0x0406, QTN_TLV_ID_UBOOT_VER = 0x0407, + QTN_TLV_ID_RANDOM_MAC_ADDR = 0x0408, + QTN_TLV_ID_MAX_SCAN_SSIDS = 0x0409, + QTN_TLV_ID_WOWLAN_CAPAB = 0x0410, + QTN_TLV_ID_WOWLAN_PATTERN = 0x0411, }; struct qlink_tlv_hdr { @@ -1360,4 +1420,49 @@ struct qlink_sta_stats { u8 rsvd[1]; }; +/** + * struct qlink_random_mac_addr - data for QTN_TLV_ID_RANDOM_MAC_ADDR TLV + * + * Specifies MAC address mask/value for generation random MAC address + * during scan. + * + * @mac_addr: MAC address used with randomisation + * @mac_addr_mask: MAC address mask used with randomisation, bits that + * are 0 in the mask should be randomised, bits that are 1 should + * be taken from the @mac_addr + */ +struct qlink_random_mac_addr { + u8 mac_addr[ETH_ALEN]; + u8 mac_addr_mask[ETH_ALEN]; +} __packed; + +/** + * struct qlink_wowlan_capab_data - data for QTN_TLV_ID_WOWLAN_CAPAB TLV + * + * WoWLAN capabilities supported by cards. + * + * @version: version of WoWLAN data structure, to ensure backward + * compatibility for firmwares with limited WoWLAN support + * @len: Total length of WoWLAN data + * @data: supported WoWLAN features + */ +struct qlink_wowlan_capab_data { + __le16 version; + __le16 len; + u8 data[0]; +} __packed; + +/** + * struct qlink_wowlan_support - supported WoWLAN capabilities + * + * @n_patterns: number of supported wakeup patterns + * @pattern_max_len: maximum length of each pattern + * @pattern_min_len: minimum length of each pattern + */ +struct qlink_wowlan_support { + __le32 n_patterns; + __le32 pattern_max_len; + __le32 pattern_min_len; +} __packed; + #endif /* _QTN_QLINK_H_ */ |