* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/moduleparam.h>
#include <linux/inetdevice.h>
#include <linux/export.h>
.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),
#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)
.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,
};
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) {
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)) {
/*
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);
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;
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;
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)
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;
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;
break;
}
+ list_for_each_entry(vif, &ar->vif_list, list)
+ ath6kl_cfg80211_scan_complete_event(vif, true);
+
return 0;
}
EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
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);
- if (ret) {
- ath6kl_warn("wmi powermode command failed during resume: %d\n",
- ret);
- }
- }
-
- ar->state = ATH6KL_STATE_ON;
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
+ ret = ath6kl_cfg80211_deepsleep_resume(ar);
+ if (ret) {
+ ath6kl_warn("deep sleep resume failed: %d\n", ret);
+ return ret;
+ }
break;
case ATH6KL_STATE_CUTPOWER:
}
#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;
-
- vif = netdev_priv(dev);
+ struct ath6kl_htcap *htcap = &vif->htcap;
- if (!ath6kl_cfg80211_ready(vif))
- return -EIO;
+ if (htcap->ht_enable == ht_enable)
+ return 0;
- 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;
+ 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));
- 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)
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)
{
struct wmi_connect_cmd p;
int res;
int i, ret;
+ u16 rsn_capab = 0;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
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;
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;
}
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,
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 */
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,
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)
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 |
target->credit_info->cur_free_credits);
}
-static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
{
switch (war) {
static const struct file_operations fops_war_stats = {
.read = read_file_war_stats,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
}
static const struct file_operations fops_fwlog_mask = {
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.read = ath6kl_fwlog_mask_read,
.write = ath6kl_fwlog_mask_write,
.owner = THIS_MODULE,
"Num disconnects", tgt_stats->cs_discon_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
+ "ARP pkt received", tgt_stats->arp_received);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
+ "ARP pkt matched", tgt_stats->arp_matched);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
+ "ARP pkt replied", tgt_stats->arp_replied);
if (len > buf_len)
len = buf_len;
static const struct file_operations fops_tgt_stats = {
.read = read_file_tgt_stats,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_credit_dist_stats = {
.read = read_file_credit_dist_stats,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
}
static const struct file_operations fops_endpoint_stats = {
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.read = ath6kl_endpoint_stats_read,
.write = ath6kl_endpoint_stats_write,
.owner = THIS_MODULE,
static const struct file_operations fops_diag_reg_read = {
.read = ath6kl_regread_read,
.write = ath6kl_regread_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_lrssi_roam_threshold = {
.read = ath6kl_lrssi_roam_read,
.write = ath6kl_lrssi_roam_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_diag_reg_write = {
.read = ath6kl_regwrite_read,
.write = ath6kl_regwrite_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_roam_table = {
.read = ath6kl_roam_table_read,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_force_roam = {
.write = ath6kl_force_roam_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_roam_mode = {
.write = ath6kl_roam_mode_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
}
static const struct file_operations fops_keepalive = {
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.read = ath6kl_keepalive_read,
.write = ath6kl_keepalive_write,
.owner = THIS_MODULE,
}
static const struct file_operations fops_disconnect_timeout = {
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.read = ath6kl_disconnect_timeout_read,
.write = ath6kl_disconnect_timeout_write,
.owner = THIS_MODULE,
static const struct file_operations fops_create_qos = {
.write = ath6kl_create_qos_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_delete_qos = {
.write = ath6kl_delete_qos_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_bgscan_int = {
.write = ath6kl_bgscan_int_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_listen_int = {
.read = ath6kl_listen_int_read,
.write = ath6kl_listen_int_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static const struct file_operations fops_power_params = {
.write = ath6kl_power_params_write,
- .open = ath6kl_debugfs_open,
+ .open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/mmc/sdio_func.h>
+ #include <linux/vmalloc.h>
#include "core.h"
#include "cfg80211.h"
#include "target.h"
#include "debug.h"
#include "hif-ops.h"
+ #include "htc-ops.h"
static const struct ath6kl_hw hw_list[] = {
{
memset(&connect, 0, sizeof(connect));
/* these fields are the same for all service endpoints */
+ connect.ep_cb.tx_comp_multi = ath6kl_tx_complete;
connect.ep_cb.rx = ath6kl_rx;
connect.ep_cb.rx_refill = ath6kl_rx_refill;
connect.ep_cb.tx_full = ath6kl_tx_queue_full;
fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
/*
- * By default, submodes :
+ * Submodes when fw does not support dynamic interface
+ * switching:
* vif[0] - AP/STA/IBSS
* vif[1] - "P2P dev"/"P2P GO"/"P2P Client"
* vif[2] - "P2P dev"/"P2P GO"/"P2P Client"
+ * Otherwise, All the interface are initialized to p2p dev.
*/
- for (i = 0; i < ar->max_norm_iface; i++)
- fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
- (i * HI_OPTION_FW_SUBMODE_BITS);
+ if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
+ ar->fw_capabilities)) {
+ for (i = 0; i < ar->vif_max; i++)
+ fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
+ (i * HI_OPTION_FW_SUBMODE_BITS);
+ } else {
+ for (i = 0; i < ar->max_norm_iface; i++)
+ fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
+ (i * HI_OPTION_FW_SUBMODE_BITS);
- for (i = ar->max_norm_iface; i < ar->vif_max; i++)
- fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
- (i * HI_OPTION_FW_SUBMODE_BITS);
+ for (i = ar->max_norm_iface; i < ar->vif_max; i++)
+ fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
+ (i * HI_OPTION_FW_SUBMODE_BITS);
- if (ar->p2p && ar->vif_max == 1)
- fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
+ if (ar->p2p && ar->vif_max == 1)
+ fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
+ }
if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,
HTC_PROTOCOL_VERSION) != 0) {
* but possible in theory.
*/
- param = ar->hw.board_ext_data_addr;
- ram_reserved_size = ar->hw.reserved_ram_size;
+ if (ar->target_type == TARGET_TYPE_AR6003) {
+ param = ar->hw.board_ext_data_addr;
+ ram_reserved_size = ar->hw.reserved_ram_size;
- if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
- ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
- return -EIO;
- }
+ if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
+ ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
+ return -EIO;
+ }
- if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
- ram_reserved_size) != 0) {
- ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
- return -EIO;
+ if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
+ ram_reserved_size) != 0) {
+ ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
+ return -EIO;
+ }
}
/* set the block size for the target */
if (ar->fw != NULL)
break;
- ar->fw = kmemdup(data, ie_len, GFP_KERNEL);
+ ar->fw = vmalloc(ie_len);
if (ar->fw == NULL) {
ret = -ENOMEM;
goto out;
}
+ memcpy(ar->fw, data, ie_len);
ar->fw_len = ie_len;
break;
case ATH6KL_FW_IE_PATCH_IMAGE:
}
/* setup credit distribution */
- ath6kl_credit_setup(ar->htc_target, &ar->credit_state_info);
+ ath6kl_htc_credit_setup(ar->htc_target, &ar->credit_state_info);
/* start HTC */
ret = ath6kl_htc_start(ar->htc_target);
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "core.h"
#include "debug.h"
+ #include "htc-ops.h"
/*
* tid - tid_mux0..tid_mux3
cookie->map_no = 0;
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
eid, ATH6KL_CONTROL_PKT_TAG);
+ cookie->htc_pkt.skb = skb;
/*
* This interface is asynchronous, if there is an error, cleanup
cookie->map_no = map_no;
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
eid, htc_tag);
+ cookie->htc_pkt.skb = skb;
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ",
skb->data, skb->len);
notify_htc:
/* notify HTC, this may cause credit distribution changes */
- ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active);
+ ath6kl_htc_activity_changed(ar->htc_target, eid, active);
}
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
}
}
- void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
+ void ath6kl_tx_complete(struct htc_target *target,
+ struct list_head *packet_queue)
{
- struct ath6kl *ar = context;
+ struct ath6kl *ar = target->dev->ar;
struct sk_buff_head skb_queue;
struct htc_packet *packet;
struct sk_buff *skb;
skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_BUFFER_SIZE, endpoint);
+ packet->skb = skb;
list_add_tail(&packet->list, &queue);
}
skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_AMSDU_BUFFER_SIZE, 0);
+ packet->skb = skb;
+
spin_lock_bh(&ar->lock);
list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue);
spin_unlock_bh(&ar->lock);
struct wmi_data_hdr *dhdr;
int min_hdr_len;
u8 meta_type, dot11_hdr = 0;
+ u8 pad_before_data_start;
int status = packet->status;
enum htc_endpoint_id ept = packet->endpoint;
bool is_amsdu, prev_ps, ps_state = false;
seq_no = wmi_data_hdr_get_seqno(dhdr);
meta_type = wmi_data_hdr_get_meta(dhdr);
dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
+ pad_before_data_start =
+ (le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT)
+ & WMI_DATA_HDR_PAD_BEFORE_DATA_MASK;
+
skb_pull(skb, sizeof(struct wmi_data_hdr));
switch (meta_type) {
break;
}
+ skb_pull(skb, pad_before_data_start);
+
if (dot11_hdr)
status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb);
else if (!is_amsdu)
/* aggregation code will handle the skb */
return;
}
- }
+ } else if (!is_broadcast_ether_addr(datap->h_dest))
+ vif->net_stats.multicast++;
ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);
}