Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2786e4a authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-linville' of git://github.com/kvalo/ath6kl

parents 80652480 d97c121b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
+339 −78
Original line number Diff line number Diff line
@@ -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),
@@ -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)

@@ -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,
};

@@ -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) {
@@ -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)) {
		/*
@@ -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);

@@ -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;
@@ -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;
@@ -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)
@@ -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;

@@ -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;
@@ -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);
@@ -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:
@@ -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)
@@ -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)
{
@@ -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__);

@@ -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;
@@ -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;
}

@@ -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,
@@ -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 */
@@ -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,
@@ -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)
@@ -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 |
+3 −1
Original line number Diff line number Diff line
@@ -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
@@ -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;

+28 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);

+32 −2
Original line number Diff line number Diff line
@@ -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,
};
@@ -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,
@@ -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 {
@@ -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.
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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