Loading drivers/net/wireless/ath/ath6kl/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,8 @@ obj-$(CONFIG_ATH6KL) += ath6kl_core.o ath6kl_core-y += debug.o ath6kl_core-y += hif.o ath6kl_core-y += htc.o ath6kl_core-y += htc_mbox.o ath6kl_core-y += htc_pipe.o ath6kl_core-y += bmi.o ath6kl_core-y += cfg80211.o ath6kl_core-y += init.o Loading drivers/net/wireless/ath/ath6kl/cfg80211.c +339 −78 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ .max_power = 30, \ } #define DEFAULT_BG_SCAN_PERIOD 60 static struct ieee80211_rate ath6kl_rates[] = { RATETAB_ENT(10, 0x1, 0), RATETAB_ENT(20, 0x2, 0), Loading @@ -71,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 #define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ #define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20 #define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_40) Loading Loading @@ -128,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, .ht_cap.cap = ath6kl_g_htcap, .ht_cap.cap = ath6kl_a_htcap, .ht_cap.ht_supported = true, }; Loading Loading @@ -609,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->req_bssid, vif->ch_hint, ar->connect_ctrl_flags, nw_subtype); /* disable background scan if period is 0 */ if (sme->bg_scan_period == 0) sme->bg_scan_period = 0xffff; /* configure default value if not specified */ if (sme->bg_scan_period == -1) sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); up(&ar->sem); if (status == -EINVAL) { Loading Loading @@ -943,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (test_bit(CONNECTED, &vif->flags)) force_fg_scan = 1; vif->scan_req = request; if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, ar->fw_capabilities)) { /* Loading @@ -965,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ATH6KL_FG_SCAN_INTERVAL, n_channels, channels); } if (ret) if (ret) { ath6kl_err("wmi_startscan_cmd failed\n"); else vif->scan_req = request; vif->scan_req = NULL; } kfree(channels); Loading Loading @@ -1438,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, struct vif_params *params) { struct ath6kl_vif *vif = netdev_priv(ndev); int i; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); /* * Don't bring up p2p on an interface which is not initialized * for p2p operation where fw does not have capability to switch * dynamically between non-p2p and p2p type interface. */ if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, vif->ar->fw_capabilities) && (type == NL80211_IFTYPE_P2P_CLIENT || type == NL80211_IFTYPE_P2P_GO)) { if (vif->ar->vif_max == 1) { if (vif->fw_vif_idx != 0) return -EINVAL; else goto set_iface_type; } for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) { if (i == vif->fw_vif_idx) break; } if (i == vif->ar->vif_max) { ath6kl_err("Invalid interface to bring up P2P\n"); return -EINVAL; } } set_iface_type: switch (type) { case NL80211_IFTYPE_STATION: vif->next_mode = INFRA_NETWORK; Loading Loading @@ -1926,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) return 0; } static int is_hsleep_mode_procsed(struct ath6kl_vif *vif) { return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); } static bool is_ctrl_ep_empty(struct ath6kl *ar) { return !ar->tx_pending[ar->ctrl_ep]; } static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) { int ret, left; clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_ASLEEP); if (ret) return ret; left = wait_event_interruptible_timeout(ar->event_wq, is_hsleep_mode_procsed(vif), WMI_TIMEOUT); if (left == 0) { ath6kl_warn("timeout, didn't get host sleep cmd processed event\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("error while waiting for host sleep cmd processed event %d\n", left); ret = left; } if (ar->tx_pending[ar->ctrl_ep]) { left = wait_event_interruptible_timeout(ar->event_wq, is_ctrl_ep_empty(ar), WMI_TIMEOUT); if (left == 0) { ath6kl_warn("clear wmi ctrl data timeout\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("clear wmi ctrl data failed: %d\n", left); ret = left; } } return ret; } static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) { struct in_device *in_dev; struct in_ifaddr *ifa; struct ath6kl_vif *vif; int ret, left; int ret; u32 filter = 0; u16 i, bmiss_time; u8 index = 0; Loading Loading @@ -2032,39 +2126,11 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) return ret; clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_ASLEEP); ret = ath6kl_cfg80211_host_sleep(ar, vif); if (ret) return ret; left = wait_event_interruptible_timeout(ar->event_wq, test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags), WMI_TIMEOUT); if (left == 0) { ath6kl_warn("timeout, didn't get host sleep cmd " "processed event\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("error while waiting for host sleep cmd " "processed event %d\n", left); ret = left; } if (ar->tx_pending[ar->ctrl_ep]) { left = wait_event_interruptible_timeout(ar->event_wq, ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); if (left == 0) { ath6kl_warn("clear wmi ctrl data timeout\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("clear wmi ctrl data failed: %d\n", left); ret = left; } } return ret; return 0; } static int ath6kl_wow_resume(struct ath6kl *ar) Loading Loading @@ -2111,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return 0; } static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) { struct ath6kl_vif *vif; int ret; vif = ath6kl_vif_first(ar); if (!vif) return -EIO; if (!ath6kl_cfg80211_ready(vif)) return -EIO; ath6kl_cfg80211_stop_all(ar); /* Save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); if (ret) return ret; /* Disable WOW mode */ ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_WOW_MODE_DISABLE, 0, 0); if (ret) return ret; /* Flush all non control pkts in TX path */ ath6kl_tx_data_cleanup(ar); ret = ath6kl_cfg80211_host_sleep(ar, vif); if (ret) return ret; return 0; } static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar) { struct ath6kl_vif *vif; int ret; vif = ath6kl_vif_first(ar); if (!vif) return -EIO; if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, ar->wmi->saved_pwr_mode); if (ret) return ret; } ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); if (ret) return ret; ar->state = ATH6KL_STATE_ON; /* Reset scan parameter to default values */ ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); if (ret) return ret; return 0; } int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) { struct ath6kl_vif *vif; enum ath6kl_state prev_state; int ret; Loading @@ -2139,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, case ATH6KL_CFG_SUSPEND_DEEPSLEEP: ath6kl_cfg80211_stop_all(ar); /* save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n"); ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); ret = ath6kl_cfg80211_deepsleep_suspend(ar); if (ret) { ath6kl_warn("wmi powermode command failed during suspend: %d\n", ret); ath6kl_err("deepsleep suspend failed: %d\n", ret); return ret; } ar->state = ATH6KL_STATE_DEEPSLEEP; Loading Loading @@ -2187,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, break; } list_for_each_entry(vif, &ar->vif_list, list) ath6kl_cfg80211_scan_complete_event(vif, true); return 0; } EXPORT_SYMBOL(ath6kl_cfg80211_suspend); Loading @@ -2208,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) break; case ATH6KL_STATE_DEEPSLEEP: if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, ar->wmi->saved_pwr_mode); ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n"); ret = ath6kl_cfg80211_deepsleep_resume(ar); if (ret) { ath6kl_warn("wmi powermode command failed during resume: %d\n", ret); } ath6kl_warn("deep sleep resume failed: %d\n", ret); return ret; } ar->state = ATH6KL_STATE_ON; break; case ATH6KL_STATE_CUTPOWER: Loading Loading @@ -2292,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar) } #endif static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, bool ht_enable) { struct ath6kl_vif *vif; /* * 'dev' could be NULL if a channel change is required for the hardware * device itself, instead of a particular VIF. * * FIXME: To be handled properly when monitor mode is supported. */ if (!dev) return -EBUSY; struct ath6kl_htcap *htcap = &vif->htcap; vif = netdev_priv(dev); if (htcap->ht_enable == ht_enable) return 0; if (!ath6kl_cfg80211_ready(vif)) return -EIO; if (ht_enable) { /* Set default ht capabilities */ htcap->ht_enable = true; htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ? ath6kl_g_htcap : ath6kl_a_htcap; htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; } else /* Disable ht */ memset(htcap, 0, sizeof(*htcap)); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", __func__, chan->center_freq, chan->hw_value); vif->next_chan = chan->center_freq; return 0; return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx, band, htcap); } static bool ath6kl_is_p2p_ie(const u8 *pos) Loading Loading @@ -2393,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, return 0; } static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { struct ath6kl_vif *vif; /* * 'dev' could be NULL if a channel change is required for the hardware * device itself, instead of a particular VIF. * * FIXME: To be handled properly when monitor mode is supported. */ if (!dev) return -EBUSY; vif = netdev_priv(dev); if (!ath6kl_cfg80211_ready(vif)) return -EIO; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", __func__, chan->center_freq, chan->hw_value); vif->next_chan = chan->center_freq; vif->next_ch_type = channel_type; vif->next_ch_band = chan->band; return 0; } static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, u8 *rsn_capab) { const u8 *rsn_ie; size_t rsn_ie_len; u16 cnt; if (!beacon->tail) return -EINVAL; rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len); if (!rsn_ie) return -EINVAL; rsn_ie_len = *(rsn_ie + 1); /* skip element id and length */ rsn_ie += 2; /* skip version, group cipher */ if (rsn_ie_len < 6) return -EINVAL; rsn_ie += 6; rsn_ie_len -= 6; /* skip pairwise cipher suite */ if (rsn_ie_len < 2) return -EINVAL; cnt = *((u16 *) rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); /* skip akm suite */ if (rsn_ie_len < 2) return -EINVAL; cnt = *((u16 *) rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); if (rsn_ie_len < 2) return -EINVAL; memcpy(rsn_capab, rsn_ie, 2); return 0; } static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *info) { Loading @@ -2405,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct wmi_connect_cmd p; int res; int i, ret; u16 rsn_capab = 0; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); Loading Loading @@ -2534,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.nw_subtype = SUBTYPE_NONE; } if (info->inactivity_timeout) { res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, info->inactivity_timeout); if (res < 0) return res; } if (ath6kl_set_htcap(vif, vif->next_ch_band, vif->next_ch_type != NL80211_CHAN_NO_HT)) return -EIO; /* * Get the PTKSA replay counter in the RSN IE. Supplicant * will use the RSN IE in M3 message and firmware has to * advertise the same in beacon/probe response. Send * the complete RSN IE capability field to firmware */ if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) && test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, ar->fw_capabilities)) { res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, WLAN_EID_RSN, WMI_RSN_IE_CAPB, (const u8 *) &rsn_capab, sizeof(rsn_capab)); if (res < 0) return res; } res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); if (res < 0) return res; Loading Loading @@ -2568,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); clear_bit(CONNECTED, &vif->flags); /* Restore ht setting in firmware */ if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true)) return -EIO; if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true)) return -EIO; return 0; } Loading Loading @@ -2749,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, return false; } /* Check if SSID length is greater than DIRECT- */ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) { const struct ieee80211_mgmt *mgmt; mgmt = (const struct ieee80211_mgmt *) buf; /* variable[1] contains the SSID tag length */ if (buf + len >= &mgmt->u.probe_resp.variable[1] && (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) { return true; } return false; } static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, Loading @@ -2763,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; if (buf + len >= mgmt->u.probe_resp.variable && vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && ieee80211_is_probe_resp(mgmt->frame_control)) { if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && ieee80211_is_probe_resp(mgmt->frame_control) && ath6kl_is_p2p_go_ssid(buf, len)) { /* * Send Probe Response frame in AP mode using a separate WMI * Send Probe Response frame in GO mode using a separate WMI * command to allow the target to fill in the generic IEs. */ *cookie = 0; /* TX status not supported */ Loading Loading @@ -2835,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; ath6kl_cfg80211_scan_complete_event(vif, true); for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, DISABLE_SSID_FLAG, Loading Loading @@ -3096,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; vif->htcap.ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) Loading Loading @@ -3183,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, ar->fw_capabilities)) ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER; ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | Loading drivers/net/wireless/ath/ath6kl/common.h +3 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,8 @@ #define ATH6KL_MAX_IE 256 extern int ath6kl_printk(const char *level, const char *fmt, ...); extern __printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...); /* * Reflects the version of binary interface exposed by ATH6KL target Loading Loading @@ -77,6 +78,7 @@ enum crypto_type { struct htc_endpoint_credit_dist; struct ath6kl; struct ath6kl_htcap; enum htc_credit_dist_reason; struct ath6kl_htc_credit_info; Loading drivers/net/wireless/ath/ath6kl/core.c +28 −2 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/export.h> #include <linux/vmalloc.h> #include "debug.h" #include "hif-ops.h" #include "htc-ops.h" #include "cfg80211.h" unsigned int debug_mask; Loading @@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644); module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); int ath6kl_core_init(struct ath6kl *ar) void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { ath6kl_htc_tx_complete(ar, skb); } EXPORT_SYMBOL(ath6kl_core_tx_complete); void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe) { ath6kl_htc_rx_complete(ar, skb, pipe); } EXPORT_SYMBOL(ath6kl_core_rx_complete); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) { struct ath6kl_bmi_target_info targ_info; struct net_device *ndev; int ret = 0, i; switch (htc_type) { case ATH6KL_HTC_TYPE_MBOX: ath6kl_htc_mbox_attach(ar); break; case ATH6KL_HTC_TYPE_PIPE: ath6kl_htc_pipe_attach(ar); break; default: WARN_ON(1); return -ENOMEM; } ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); if (!ar->ath6kl_wq) return -ENOMEM; Loading Loading @@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar) kfree(ar->fw_board); kfree(ar->fw_otp); kfree(ar->fw); vfree(ar->fw); kfree(ar->fw_patch); kfree(ar->fw_testscript); Loading drivers/net/wireless/ath/ath6kl/core.h +32 −2 Original line number Diff line number Diff line Loading @@ -91,6 +91,15 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, /* * Firmware has support to cleanup inactive stations * in AP mode. */ ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, /* Firmware has support to override rsn cap of rsn ie */ ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; Loading Loading @@ -205,6 +214,8 @@ struct ath6kl_fw_ie { #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) #define ATH6KL_CONF_UART_DEBUG BIT(4) #define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */ enum wlan_low_pwr_state { WLAN_POWER_STATE_ON, WLAN_POWER_STATE_CUT_PWR, Loading Loading @@ -454,6 +465,11 @@ enum ath6kl_hif_type { ATH6KL_HIF_TYPE_USB, }; enum ath6kl_htc_type { ATH6KL_HTC_TYPE_MBOX, ATH6KL_HTC_TYPE_PIPE, }; /* Max number of filters that hw supports */ #define ATH6K_MAX_MC_FILTERS_PER_LIST 7 struct ath6kl_mc_filter { Loading @@ -461,6 +477,12 @@ struct ath6kl_mc_filter { char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; }; struct ath6kl_htcap { bool ht_enable; u8 ampdu_factor; unsigned short cap_info; }; /* * Driver's maximum limit, note that some firmwares support only one vif * and the runtime (current) limit must be checked from ar->vif_max. Loading Loading @@ -509,6 +531,7 @@ struct ath6kl_vif { struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; struct aggr_info *aggr_cntxt; struct ath6kl_htcap htcap; struct timer_list disconnect_timer; struct timer_list sched_scan_timer; Loading @@ -521,6 +544,8 @@ struct ath6kl_vif { u32 send_action_id; bool probe_req_report; u16 next_chan; enum nl80211_channel_type next_ch_type; enum ieee80211_band next_ch_band; u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; Loading Loading @@ -568,6 +593,7 @@ struct ath6kl { struct ath6kl_bmi bmi; const struct ath6kl_hif_ops *hif_ops; const struct ath6kl_htc_ops *htc_ops; struct wmi *wmi; int tx_pending[ENDPOINT_MAX]; int total_tx_data_pend; Loading Loading @@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev); void ath6kl_cookie_init(struct ath6kl *ar); void ath6kl_cookie_cleanup(struct ath6kl *ar); void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); void ath6kl_tx_complete(void *context, struct list_head *packet_queue); void ath6kl_tx_complete(struct htc_target *context, struct list_head *packet_queue); enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, struct htc_packet *packet); void ath6kl_stop_txrx(struct ath6kl *ar); Loading Loading @@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar); void ath6kl_check_wow_status(struct ath6kl *ar); void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb); void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe); struct ath6kl *ath6kl_core_create(struct device *dev); int ath6kl_core_init(struct ath6kl *ar); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar); Loading Loading
drivers/net/wireless/ath/ath6kl/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,8 @@ obj-$(CONFIG_ATH6KL) += ath6kl_core.o ath6kl_core-y += debug.o ath6kl_core-y += hif.o ath6kl_core-y += htc.o ath6kl_core-y += htc_mbox.o ath6kl_core-y += htc_pipe.o ath6kl_core-y += bmi.o ath6kl_core-y += cfg80211.o ath6kl_core-y += init.o Loading
drivers/net/wireless/ath/ath6kl/cfg80211.c +339 −78 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ .max_power = 30, \ } #define DEFAULT_BG_SCAN_PERIOD 60 static struct ieee80211_rate ath6kl_rates[] = { RATETAB_ENT(10, 0x1, 0), RATETAB_ENT(20, 0x2, 0), Loading @@ -71,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 #define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ #define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20 #define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_40) Loading Loading @@ -128,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, .ht_cap.cap = ath6kl_g_htcap, .ht_cap.cap = ath6kl_a_htcap, .ht_cap.ht_supported = true, }; Loading Loading @@ -609,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->req_bssid, vif->ch_hint, ar->connect_ctrl_flags, nw_subtype); /* disable background scan if period is 0 */ if (sme->bg_scan_period == 0) sme->bg_scan_period = 0xffff; /* configure default value if not specified */ if (sme->bg_scan_period == -1) sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); up(&ar->sem); if (status == -EINVAL) { Loading Loading @@ -943,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (test_bit(CONNECTED, &vif->flags)) force_fg_scan = 1; vif->scan_req = request; if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, ar->fw_capabilities)) { /* Loading @@ -965,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ATH6KL_FG_SCAN_INTERVAL, n_channels, channels); } if (ret) if (ret) { ath6kl_err("wmi_startscan_cmd failed\n"); else vif->scan_req = request; vif->scan_req = NULL; } kfree(channels); Loading Loading @@ -1438,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, struct vif_params *params) { struct ath6kl_vif *vif = netdev_priv(ndev); int i; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); /* * Don't bring up p2p on an interface which is not initialized * for p2p operation where fw does not have capability to switch * dynamically between non-p2p and p2p type interface. */ if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, vif->ar->fw_capabilities) && (type == NL80211_IFTYPE_P2P_CLIENT || type == NL80211_IFTYPE_P2P_GO)) { if (vif->ar->vif_max == 1) { if (vif->fw_vif_idx != 0) return -EINVAL; else goto set_iface_type; } for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) { if (i == vif->fw_vif_idx) break; } if (i == vif->ar->vif_max) { ath6kl_err("Invalid interface to bring up P2P\n"); return -EINVAL; } } set_iface_type: switch (type) { case NL80211_IFTYPE_STATION: vif->next_mode = INFRA_NETWORK; Loading Loading @@ -1926,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) return 0; } static int is_hsleep_mode_procsed(struct ath6kl_vif *vif) { return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); } static bool is_ctrl_ep_empty(struct ath6kl *ar) { return !ar->tx_pending[ar->ctrl_ep]; } static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) { int ret, left; clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_ASLEEP); if (ret) return ret; left = wait_event_interruptible_timeout(ar->event_wq, is_hsleep_mode_procsed(vif), WMI_TIMEOUT); if (left == 0) { ath6kl_warn("timeout, didn't get host sleep cmd processed event\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("error while waiting for host sleep cmd processed event %d\n", left); ret = left; } if (ar->tx_pending[ar->ctrl_ep]) { left = wait_event_interruptible_timeout(ar->event_wq, is_ctrl_ep_empty(ar), WMI_TIMEOUT); if (left == 0) { ath6kl_warn("clear wmi ctrl data timeout\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("clear wmi ctrl data failed: %d\n", left); ret = left; } } return ret; } static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) { struct in_device *in_dev; struct in_ifaddr *ifa; struct ath6kl_vif *vif; int ret, left; int ret; u32 filter = 0; u16 i, bmiss_time; u8 index = 0; Loading Loading @@ -2032,39 +2126,11 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) return ret; clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_ASLEEP); ret = ath6kl_cfg80211_host_sleep(ar, vif); if (ret) return ret; left = wait_event_interruptible_timeout(ar->event_wq, test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags), WMI_TIMEOUT); if (left == 0) { ath6kl_warn("timeout, didn't get host sleep cmd " "processed event\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("error while waiting for host sleep cmd " "processed event %d\n", left); ret = left; } if (ar->tx_pending[ar->ctrl_ep]) { left = wait_event_interruptible_timeout(ar->event_wq, ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); if (left == 0) { ath6kl_warn("clear wmi ctrl data timeout\n"); ret = -ETIMEDOUT; } else if (left < 0) { ath6kl_warn("clear wmi ctrl data failed: %d\n", left); ret = left; } } return ret; return 0; } static int ath6kl_wow_resume(struct ath6kl *ar) Loading Loading @@ -2111,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return 0; } static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) { struct ath6kl_vif *vif; int ret; vif = ath6kl_vif_first(ar); if (!vif) return -EIO; if (!ath6kl_cfg80211_ready(vif)) return -EIO; ath6kl_cfg80211_stop_all(ar); /* Save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); if (ret) return ret; /* Disable WOW mode */ ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_WOW_MODE_DISABLE, 0, 0); if (ret) return ret; /* Flush all non control pkts in TX path */ ath6kl_tx_data_cleanup(ar); ret = ath6kl_cfg80211_host_sleep(ar, vif); if (ret) return ret; return 0; } static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar) { struct ath6kl_vif *vif; int ret; vif = ath6kl_vif_first(ar); if (!vif) return -EIO; if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, ar->wmi->saved_pwr_mode); if (ret) return ret; } ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); if (ret) return ret; ar->state = ATH6KL_STATE_ON; /* Reset scan parameter to default values */ ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); if (ret) return ret; return 0; } int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) { struct ath6kl_vif *vif; enum ath6kl_state prev_state; int ret; Loading @@ -2139,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, case ATH6KL_CFG_SUSPEND_DEEPSLEEP: ath6kl_cfg80211_stop_all(ar); /* save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n"); ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); ret = ath6kl_cfg80211_deepsleep_suspend(ar); if (ret) { ath6kl_warn("wmi powermode command failed during suspend: %d\n", ret); ath6kl_err("deepsleep suspend failed: %d\n", ret); return ret; } ar->state = ATH6KL_STATE_DEEPSLEEP; Loading Loading @@ -2187,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, break; } list_for_each_entry(vif, &ar->vif_list, list) ath6kl_cfg80211_scan_complete_event(vif, true); return 0; } EXPORT_SYMBOL(ath6kl_cfg80211_suspend); Loading @@ -2208,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) break; case ATH6KL_STATE_DEEPSLEEP: if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, ar->wmi->saved_pwr_mode); ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n"); ret = ath6kl_cfg80211_deepsleep_resume(ar); if (ret) { ath6kl_warn("wmi powermode command failed during resume: %d\n", ret); } ath6kl_warn("deep sleep resume failed: %d\n", ret); return ret; } ar->state = ATH6KL_STATE_ON; break; case ATH6KL_STATE_CUTPOWER: Loading Loading @@ -2292,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar) } #endif static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, bool ht_enable) { struct ath6kl_vif *vif; /* * 'dev' could be NULL if a channel change is required for the hardware * device itself, instead of a particular VIF. * * FIXME: To be handled properly when monitor mode is supported. */ if (!dev) return -EBUSY; struct ath6kl_htcap *htcap = &vif->htcap; vif = netdev_priv(dev); if (htcap->ht_enable == ht_enable) return 0; if (!ath6kl_cfg80211_ready(vif)) return -EIO; if (ht_enable) { /* Set default ht capabilities */ htcap->ht_enable = true; htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ? ath6kl_g_htcap : ath6kl_a_htcap; htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; } else /* Disable ht */ memset(htcap, 0, sizeof(*htcap)); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", __func__, chan->center_freq, chan->hw_value); vif->next_chan = chan->center_freq; return 0; return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx, band, htcap); } static bool ath6kl_is_p2p_ie(const u8 *pos) Loading Loading @@ -2393,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, return 0; } static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { struct ath6kl_vif *vif; /* * 'dev' could be NULL if a channel change is required for the hardware * device itself, instead of a particular VIF. * * FIXME: To be handled properly when monitor mode is supported. */ if (!dev) return -EBUSY; vif = netdev_priv(dev); if (!ath6kl_cfg80211_ready(vif)) return -EIO; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", __func__, chan->center_freq, chan->hw_value); vif->next_chan = chan->center_freq; vif->next_ch_type = channel_type; vif->next_ch_band = chan->band; return 0; } static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, u8 *rsn_capab) { const u8 *rsn_ie; size_t rsn_ie_len; u16 cnt; if (!beacon->tail) return -EINVAL; rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len); if (!rsn_ie) return -EINVAL; rsn_ie_len = *(rsn_ie + 1); /* skip element id and length */ rsn_ie += 2; /* skip version, group cipher */ if (rsn_ie_len < 6) return -EINVAL; rsn_ie += 6; rsn_ie_len -= 6; /* skip pairwise cipher suite */ if (rsn_ie_len < 2) return -EINVAL; cnt = *((u16 *) rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); /* skip akm suite */ if (rsn_ie_len < 2) return -EINVAL; cnt = *((u16 *) rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); if (rsn_ie_len < 2) return -EINVAL; memcpy(rsn_capab, rsn_ie, 2); return 0; } static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *info) { Loading @@ -2405,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct wmi_connect_cmd p; int res; int i, ret; u16 rsn_capab = 0; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); Loading Loading @@ -2534,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.nw_subtype = SUBTYPE_NONE; } if (info->inactivity_timeout) { res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, info->inactivity_timeout); if (res < 0) return res; } if (ath6kl_set_htcap(vif, vif->next_ch_band, vif->next_ch_type != NL80211_CHAN_NO_HT)) return -EIO; /* * Get the PTKSA replay counter in the RSN IE. Supplicant * will use the RSN IE in M3 message and firmware has to * advertise the same in beacon/probe response. Send * the complete RSN IE capability field to firmware */ if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) && test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, ar->fw_capabilities)) { res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, WLAN_EID_RSN, WMI_RSN_IE_CAPB, (const u8 *) &rsn_capab, sizeof(rsn_capab)); if (res < 0) return res; } res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); if (res < 0) return res; Loading Loading @@ -2568,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); clear_bit(CONNECTED, &vif->flags); /* Restore ht setting in firmware */ if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true)) return -EIO; if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true)) return -EIO; return 0; } Loading Loading @@ -2749,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, return false; } /* Check if SSID length is greater than DIRECT- */ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) { const struct ieee80211_mgmt *mgmt; mgmt = (const struct ieee80211_mgmt *) buf; /* variable[1] contains the SSID tag length */ if (buf + len >= &mgmt->u.probe_resp.variable[1] && (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) { return true; } return false; } static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, Loading @@ -2763,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; if (buf + len >= mgmt->u.probe_resp.variable && vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && ieee80211_is_probe_resp(mgmt->frame_control)) { if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && ieee80211_is_probe_resp(mgmt->frame_control) && ath6kl_is_p2p_go_ssid(buf, len)) { /* * Send Probe Response frame in AP mode using a separate WMI * Send Probe Response frame in GO mode using a separate WMI * command to allow the target to fill in the generic IEs. */ *cookie = 0; /* TX status not supported */ Loading Loading @@ -2835,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; ath6kl_cfg80211_scan_complete_event(vif, true); for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, DISABLE_SSID_FLAG, Loading Loading @@ -3096,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; vif->htcap.ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) Loading Loading @@ -3183,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, ar->fw_capabilities)) ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER; ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | Loading
drivers/net/wireless/ath/ath6kl/common.h +3 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,8 @@ #define ATH6KL_MAX_IE 256 extern int ath6kl_printk(const char *level, const char *fmt, ...); extern __printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...); /* * Reflects the version of binary interface exposed by ATH6KL target Loading Loading @@ -77,6 +78,7 @@ enum crypto_type { struct htc_endpoint_credit_dist; struct ath6kl; struct ath6kl_htcap; enum htc_credit_dist_reason; struct ath6kl_htc_credit_info; Loading
drivers/net/wireless/ath/ath6kl/core.c +28 −2 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/export.h> #include <linux/vmalloc.h> #include "debug.h" #include "hif-ops.h" #include "htc-ops.h" #include "cfg80211.h" unsigned int debug_mask; Loading @@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644); module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); int ath6kl_core_init(struct ath6kl *ar) void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { ath6kl_htc_tx_complete(ar, skb); } EXPORT_SYMBOL(ath6kl_core_tx_complete); void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe) { ath6kl_htc_rx_complete(ar, skb, pipe); } EXPORT_SYMBOL(ath6kl_core_rx_complete); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) { struct ath6kl_bmi_target_info targ_info; struct net_device *ndev; int ret = 0, i; switch (htc_type) { case ATH6KL_HTC_TYPE_MBOX: ath6kl_htc_mbox_attach(ar); break; case ATH6KL_HTC_TYPE_PIPE: ath6kl_htc_pipe_attach(ar); break; default: WARN_ON(1); return -ENOMEM; } ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); if (!ar->ath6kl_wq) return -ENOMEM; Loading Loading @@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar) kfree(ar->fw_board); kfree(ar->fw_otp); kfree(ar->fw); vfree(ar->fw); kfree(ar->fw_patch); kfree(ar->fw_testscript); Loading
drivers/net/wireless/ath/ath6kl/core.h +32 −2 Original line number Diff line number Diff line Loading @@ -91,6 +91,15 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, /* * Firmware has support to cleanup inactive stations * in AP mode. */ ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, /* Firmware has support to override rsn cap of rsn ie */ ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; Loading Loading @@ -205,6 +214,8 @@ struct ath6kl_fw_ie { #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) #define ATH6KL_CONF_UART_DEBUG BIT(4) #define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */ enum wlan_low_pwr_state { WLAN_POWER_STATE_ON, WLAN_POWER_STATE_CUT_PWR, Loading Loading @@ -454,6 +465,11 @@ enum ath6kl_hif_type { ATH6KL_HIF_TYPE_USB, }; enum ath6kl_htc_type { ATH6KL_HTC_TYPE_MBOX, ATH6KL_HTC_TYPE_PIPE, }; /* Max number of filters that hw supports */ #define ATH6K_MAX_MC_FILTERS_PER_LIST 7 struct ath6kl_mc_filter { Loading @@ -461,6 +477,12 @@ struct ath6kl_mc_filter { char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; }; struct ath6kl_htcap { bool ht_enable; u8 ampdu_factor; unsigned short cap_info; }; /* * Driver's maximum limit, note that some firmwares support only one vif * and the runtime (current) limit must be checked from ar->vif_max. Loading Loading @@ -509,6 +531,7 @@ struct ath6kl_vif { struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; struct aggr_info *aggr_cntxt; struct ath6kl_htcap htcap; struct timer_list disconnect_timer; struct timer_list sched_scan_timer; Loading @@ -521,6 +544,8 @@ struct ath6kl_vif { u32 send_action_id; bool probe_req_report; u16 next_chan; enum nl80211_channel_type next_ch_type; enum ieee80211_band next_ch_band; u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; Loading Loading @@ -568,6 +593,7 @@ struct ath6kl { struct ath6kl_bmi bmi; const struct ath6kl_hif_ops *hif_ops; const struct ath6kl_htc_ops *htc_ops; struct wmi *wmi; int tx_pending[ENDPOINT_MAX]; int total_tx_data_pend; Loading Loading @@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev); void ath6kl_cookie_init(struct ath6kl *ar); void ath6kl_cookie_cleanup(struct ath6kl *ar); void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); void ath6kl_tx_complete(void *context, struct list_head *packet_queue); void ath6kl_tx_complete(struct htc_target *context, struct list_head *packet_queue); enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, struct htc_packet *packet); void ath6kl_stop_txrx(struct ath6kl *ar); Loading Loading @@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar); void ath6kl_check_wow_status(struct ath6kl *ar); void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb); void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe); struct ath6kl *ath6kl_core_create(struct device *dev); int ath6kl_core_init(struct ath6kl *ar); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar); Loading