aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-04-12 15:02:19 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-12 15:02:19 -0400
commitc2786e4a173f89ae81d6ba45d5bf129d77733eea (patch)
treeab83a1c7658262314548236a96fabce88be37cb5 /drivers/net
parent8065248069097dddf9945acfb2081025e9618c16 (diff)
parentd97c121bb23d32ef631c553d2656f8ccf8349507 (diff)
Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath6kl/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c417
-rw-r--r--drivers/net/wireless/ath/ath6kl/common.h4
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.c30
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h34
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c6
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif-ops.h34
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.h6
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc-ops.h113
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc.h98
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_mbox.c (renamed from drivers/net/wireless/ath/ath6kl/htc.c)85
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c1713
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c57
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c23
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c785
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c80
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h40
20 files changed, 3370 insertions, 165 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
index 85746c3eb027..8cae8886f17d 100644
--- a/drivers/net/wireless/ath/ath6kl/Makefile
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -25,7 +25,8 @@
25obj-$(CONFIG_ATH6KL) += ath6kl_core.o 25obj-$(CONFIG_ATH6KL) += ath6kl_core.o
26ath6kl_core-y += debug.o 26ath6kl_core-y += debug.o
27ath6kl_core-y += hif.o 27ath6kl_core-y += hif.o
28ath6kl_core-y += htc.o 28ath6kl_core-y += htc_mbox.o
29ath6kl_core-y += htc_pipe.o
29ath6kl_core-y += bmi.o 30ath6kl_core-y += bmi.o
30ath6kl_core-y += cfg80211.o 31ath6kl_core-y += cfg80211.o
31ath6kl_core-y += init.o 32ath6kl_core-y += init.o
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index bdcc68fb1e37..28a65d3a03d0 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -51,6 +51,8 @@
51 .max_power = 30, \ 51 .max_power = 30, \
52} 52}
53 53
54#define DEFAULT_BG_SCAN_PERIOD 60
55
54static struct ieee80211_rate ath6kl_rates[] = { 56static struct ieee80211_rate ath6kl_rates[] = {
55 RATETAB_ENT(10, 0x1, 0), 57 RATETAB_ENT(10, 0x1, 0),
56 RATETAB_ENT(20, 0x2, 0), 58 RATETAB_ENT(20, 0x2, 0),
@@ -71,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = {
71#define ath6kl_g_rates (ath6kl_rates + 0) 73#define ath6kl_g_rates (ath6kl_rates + 0)
72#define ath6kl_g_rates_size 12 74#define ath6kl_g_rates_size 12
73 75
74#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ 76#define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20
77#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
75 IEEE80211_HT_CAP_SGI_20 | \ 78 IEEE80211_HT_CAP_SGI_20 | \
76 IEEE80211_HT_CAP_SGI_40) 79 IEEE80211_HT_CAP_SGI_40)
77 80
@@ -128,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
128 .channels = ath6kl_5ghz_a_channels, 131 .channels = ath6kl_5ghz_a_channels,
129 .n_bitrates = ath6kl_a_rates_size, 132 .n_bitrates = ath6kl_a_rates_size,
130 .bitrates = ath6kl_a_rates, 133 .bitrates = ath6kl_a_rates,
131 .ht_cap.cap = ath6kl_g_htcap, 134 .ht_cap.cap = ath6kl_a_htcap,
132 .ht_cap.ht_supported = true, 135 .ht_cap.ht_supported = true,
133}; 136};
134 137
@@ -609,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
609 vif->req_bssid, vif->ch_hint, 612 vif->req_bssid, vif->ch_hint,
610 ar->connect_ctrl_flags, nw_subtype); 613 ar->connect_ctrl_flags, nw_subtype);
611 614
615 /* disable background scan if period is 0 */
616 if (sme->bg_scan_period == 0)
617 sme->bg_scan_period = 0xffff;
618
619 /* configure default value if not specified */
620 if (sme->bg_scan_period == -1)
621 sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
622
623 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
624 sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
625
612 up(&ar->sem); 626 up(&ar->sem);
613 627
614 if (status == -EINVAL) { 628 if (status == -EINVAL) {
@@ -943,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
943 if (test_bit(CONNECTED, &vif->flags)) 957 if (test_bit(CONNECTED, &vif->flags))
944 force_fg_scan = 1; 958 force_fg_scan = 1;
945 959
960 vif->scan_req = request;
961
946 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, 962 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
947 ar->fw_capabilities)) { 963 ar->fw_capabilities)) {
948 /* 964 /*
@@ -965,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
965 ATH6KL_FG_SCAN_INTERVAL, 981 ATH6KL_FG_SCAN_INTERVAL,
966 n_channels, channels); 982 n_channels, channels);
967 } 983 }
968 if (ret) 984 if (ret) {
969 ath6kl_err("wmi_startscan_cmd failed\n"); 985 ath6kl_err("wmi_startscan_cmd failed\n");
970 else 986 vif->scan_req = NULL;
971 vif->scan_req = request; 987 }
972 988
973 kfree(channels); 989 kfree(channels);
974 990
@@ -1438,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
1438 struct vif_params *params) 1454 struct vif_params *params)
1439{ 1455{
1440 struct ath6kl_vif *vif = netdev_priv(ndev); 1456 struct ath6kl_vif *vif = netdev_priv(ndev);
1457 int i;
1441 1458
1442 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); 1459 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
1443 1460
1461 /*
1462 * Don't bring up p2p on an interface which is not initialized
1463 * for p2p operation where fw does not have capability to switch
1464 * dynamically between non-p2p and p2p type interface.
1465 */
1466 if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
1467 vif->ar->fw_capabilities) &&
1468 (type == NL80211_IFTYPE_P2P_CLIENT ||
1469 type == NL80211_IFTYPE_P2P_GO)) {
1470 if (vif->ar->vif_max == 1) {
1471 if (vif->fw_vif_idx != 0)
1472 return -EINVAL;
1473 else
1474 goto set_iface_type;
1475 }
1476
1477 for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) {
1478 if (i == vif->fw_vif_idx)
1479 break;
1480 }
1481
1482 if (i == vif->ar->vif_max) {
1483 ath6kl_err("Invalid interface to bring up P2P\n");
1484 return -EINVAL;
1485 }
1486 }
1487
1488set_iface_type:
1444 switch (type) { 1489 switch (type) {
1445 case NL80211_IFTYPE_STATION: 1490 case NL80211_IFTYPE_STATION:
1446 vif->next_mode = INFRA_NETWORK; 1491 vif->next_mode = INFRA_NETWORK;
@@ -1926,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
1926 return 0; 1971 return 0;
1927} 1972}
1928 1973
1974static int is_hsleep_mode_procsed(struct ath6kl_vif *vif)
1975{
1976 return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
1977}
1978
1979static bool is_ctrl_ep_empty(struct ath6kl *ar)
1980{
1981 return !ar->tx_pending[ar->ctrl_ep];
1982}
1983
1984static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
1985{
1986 int ret, left;
1987
1988 clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
1989
1990 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
1991 ATH6KL_HOST_MODE_ASLEEP);
1992 if (ret)
1993 return ret;
1994
1995 left = wait_event_interruptible_timeout(ar->event_wq,
1996 is_hsleep_mode_procsed(vif),
1997 WMI_TIMEOUT);
1998 if (left == 0) {
1999 ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
2000 ret = -ETIMEDOUT;
2001 } else if (left < 0) {
2002 ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
2003 left);
2004 ret = left;
2005 }
2006
2007 if (ar->tx_pending[ar->ctrl_ep]) {
2008 left = wait_event_interruptible_timeout(ar->event_wq,
2009 is_ctrl_ep_empty(ar),
2010 WMI_TIMEOUT);
2011 if (left == 0) {
2012 ath6kl_warn("clear wmi ctrl data timeout\n");
2013 ret = -ETIMEDOUT;
2014 } else if (left < 0) {
2015 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
2016 ret = left;
2017 }
2018 }
2019
2020 return ret;
2021}
2022
1929static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) 2023static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
1930{ 2024{
1931 struct in_device *in_dev; 2025 struct in_device *in_dev;
1932 struct in_ifaddr *ifa; 2026 struct in_ifaddr *ifa;
1933 struct ath6kl_vif *vif; 2027 struct ath6kl_vif *vif;
1934 int ret, left; 2028 int ret;
1935 u32 filter = 0; 2029 u32 filter = 0;
1936 u16 i, bmiss_time; 2030 u16 i, bmiss_time;
1937 u8 index = 0; 2031 u8 index = 0;
@@ -2032,39 +2126,11 @@ skip_arp:
2032 if (ret) 2126 if (ret)
2033 return ret; 2127 return ret;
2034 2128
2035 clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); 2129 ret = ath6kl_cfg80211_host_sleep(ar, vif);
2036
2037 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2038 ATH6KL_HOST_MODE_ASLEEP);
2039 if (ret) 2130 if (ret)
2040 return ret; 2131 return ret;
2041 2132
2042 left = wait_event_interruptible_timeout(ar->event_wq, 2133 return 0;
2043 test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags),
2044 WMI_TIMEOUT);
2045 if (left == 0) {
2046 ath6kl_warn("timeout, didn't get host sleep cmd "
2047 "processed event\n");
2048 ret = -ETIMEDOUT;
2049 } else if (left < 0) {
2050 ath6kl_warn("error while waiting for host sleep cmd "
2051 "processed event %d\n", left);
2052 ret = left;
2053 }
2054
2055 if (ar->tx_pending[ar->ctrl_ep]) {
2056 left = wait_event_interruptible_timeout(ar->event_wq,
2057 ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
2058 if (left == 0) {
2059 ath6kl_warn("clear wmi ctrl data timeout\n");
2060 ret = -ETIMEDOUT;
2061 } else if (left < 0) {
2062 ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
2063 ret = left;
2064 }
2065 }
2066
2067 return ret;
2068} 2134}
2069 2135
2070static int ath6kl_wow_resume(struct ath6kl *ar) 2136static int ath6kl_wow_resume(struct ath6kl *ar)
@@ -2111,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
2111 return 0; 2177 return 0;
2112} 2178}
2113 2179
2180static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
2181{
2182 struct ath6kl_vif *vif;
2183 int ret;
2184
2185 vif = ath6kl_vif_first(ar);
2186 if (!vif)
2187 return -EIO;
2188
2189 if (!ath6kl_cfg80211_ready(vif))
2190 return -EIO;
2191
2192 ath6kl_cfg80211_stop_all(ar);
2193
2194 /* Save the current power mode before enabling power save */
2195 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2196
2197 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
2198 if (ret)
2199 return ret;
2200
2201 /* Disable WOW mode */
2202 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2203 ATH6KL_WOW_MODE_DISABLE,
2204 0, 0);
2205 if (ret)
2206 return ret;
2207
2208 /* Flush all non control pkts in TX path */
2209 ath6kl_tx_data_cleanup(ar);
2210
2211 ret = ath6kl_cfg80211_host_sleep(ar, vif);
2212 if (ret)
2213 return ret;
2214
2215 return 0;
2216}
2217
2218static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar)
2219{
2220 struct ath6kl_vif *vif;
2221 int ret;
2222
2223 vif = ath6kl_vif_first(ar);
2224
2225 if (!vif)
2226 return -EIO;
2227
2228 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
2229 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
2230 ar->wmi->saved_pwr_mode);
2231 if (ret)
2232 return ret;
2233 }
2234
2235 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2236 ATH6KL_HOST_MODE_AWAKE);
2237 if (ret)
2238 return ret;
2239
2240 ar->state = ATH6KL_STATE_ON;
2241
2242 /* Reset scan parameter to default values */
2243 ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2244 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
2245 if (ret)
2246 return ret;
2247
2248 return 0;
2249}
2250
2114int ath6kl_cfg80211_suspend(struct ath6kl *ar, 2251int ath6kl_cfg80211_suspend(struct ath6kl *ar,
2115 enum ath6kl_cfg_suspend_mode mode, 2252 enum ath6kl_cfg_suspend_mode mode,
2116 struct cfg80211_wowlan *wow) 2253 struct cfg80211_wowlan *wow)
2117{ 2254{
2255 struct ath6kl_vif *vif;
2118 enum ath6kl_state prev_state; 2256 enum ath6kl_state prev_state;
2119 int ret; 2257 int ret;
2120 2258
@@ -2139,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
2139 2277
2140 case ATH6KL_CFG_SUSPEND_DEEPSLEEP: 2278 case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
2141 2279
2142 ath6kl_cfg80211_stop_all(ar); 2280 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n");
2143
2144 /* save the current power mode before enabling power save */
2145 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
2146 2281
2147 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); 2282 ret = ath6kl_cfg80211_deepsleep_suspend(ar);
2148 if (ret) { 2283 if (ret) {
2149 ath6kl_warn("wmi powermode command failed during suspend: %d\n", 2284 ath6kl_err("deepsleep suspend failed: %d\n", ret);
2150 ret); 2285 return ret;
2151 } 2286 }
2152 2287
2153 ar->state = ATH6KL_STATE_DEEPSLEEP; 2288 ar->state = ATH6KL_STATE_DEEPSLEEP;
@@ -2187,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
2187 break; 2322 break;
2188 } 2323 }
2189 2324
2325 list_for_each_entry(vif, &ar->vif_list, list)
2326 ath6kl_cfg80211_scan_complete_event(vif, true);
2327
2190 return 0; 2328 return 0;
2191} 2329}
2192EXPORT_SYMBOL(ath6kl_cfg80211_suspend); 2330EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
@@ -2208,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
2208 break; 2346 break;
2209 2347
2210 case ATH6KL_STATE_DEEPSLEEP: 2348 case ATH6KL_STATE_DEEPSLEEP:
2211 if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { 2349 ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
2212 ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
2213 ar->wmi->saved_pwr_mode);
2214 if (ret) {
2215 ath6kl_warn("wmi powermode command failed during resume: %d\n",
2216 ret);
2217 }
2218 }
2219
2220 ar->state = ATH6KL_STATE_ON;
2221 2350
2351 ret = ath6kl_cfg80211_deepsleep_resume(ar);
2352 if (ret) {
2353 ath6kl_warn("deep sleep resume failed: %d\n", ret);
2354 return ret;
2355 }
2222 break; 2356 break;
2223 2357
2224 case ATH6KL_STATE_CUTPOWER: 2358 case ATH6KL_STATE_CUTPOWER:
@@ -2292,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
2292} 2426}
2293#endif 2427#endif
2294 2428
2295static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, 2429static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
2296 struct ieee80211_channel *chan, 2430 bool ht_enable)
2297 enum nl80211_channel_type channel_type)
2298{ 2431{
2299 struct ath6kl_vif *vif; 2432 struct ath6kl_htcap *htcap = &vif->htcap;
2300
2301 /*
2302 * 'dev' could be NULL if a channel change is required for the hardware
2303 * device itself, instead of a particular VIF.
2304 *
2305 * FIXME: To be handled properly when monitor mode is supported.
2306 */
2307 if (!dev)
2308 return -EBUSY;
2309
2310 vif = netdev_priv(dev);
2311 2433
2312 if (!ath6kl_cfg80211_ready(vif)) 2434 if (htcap->ht_enable == ht_enable)
2313 return -EIO; 2435 return 0;
2314 2436
2315 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", 2437 if (ht_enable) {
2316 __func__, chan->center_freq, chan->hw_value); 2438 /* Set default ht capabilities */
2317 vif->next_chan = chan->center_freq; 2439 htcap->ht_enable = true;
2440 htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ?
2441 ath6kl_g_htcap : ath6kl_a_htcap;
2442 htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K;
2443 } else /* Disable ht */
2444 memset(htcap, 0, sizeof(*htcap));
2318 2445
2319 return 0; 2446 return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx,
2447 band, htcap);
2320} 2448}
2321 2449
2322static bool ath6kl_is_p2p_ie(const u8 *pos) 2450static bool ath6kl_is_p2p_ie(const u8 *pos)
@@ -2393,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
2393 return 0; 2521 return 0;
2394} 2522}
2395 2523
2524static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
2525 struct ieee80211_channel *chan,
2526 enum nl80211_channel_type channel_type)
2527{
2528 struct ath6kl_vif *vif;
2529
2530 /*
2531 * 'dev' could be NULL if a channel change is required for the hardware
2532 * device itself, instead of a particular VIF.
2533 *
2534 * FIXME: To be handled properly when monitor mode is supported.
2535 */
2536 if (!dev)
2537 return -EBUSY;
2538
2539 vif = netdev_priv(dev);
2540
2541 if (!ath6kl_cfg80211_ready(vif))
2542 return -EIO;
2543
2544 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
2545 __func__, chan->center_freq, chan->hw_value);
2546 vif->next_chan = chan->center_freq;
2547 vif->next_ch_type = channel_type;
2548 vif->next_ch_band = chan->band;
2549
2550 return 0;
2551}
2552
2553static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
2554 u8 *rsn_capab)
2555{
2556 const u8 *rsn_ie;
2557 size_t rsn_ie_len;
2558 u16 cnt;
2559
2560 if (!beacon->tail)
2561 return -EINVAL;
2562
2563 rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len);
2564 if (!rsn_ie)
2565 return -EINVAL;
2566
2567 rsn_ie_len = *(rsn_ie + 1);
2568 /* skip element id and length */
2569 rsn_ie += 2;
2570
2571 /* skip version, group cipher */
2572 if (rsn_ie_len < 6)
2573 return -EINVAL;
2574 rsn_ie += 6;
2575 rsn_ie_len -= 6;
2576
2577 /* skip pairwise cipher suite */
2578 if (rsn_ie_len < 2)
2579 return -EINVAL;
2580 cnt = *((u16 *) rsn_ie);
2581 rsn_ie += (2 + cnt * 4);
2582 rsn_ie_len -= (2 + cnt * 4);
2583
2584 /* skip akm suite */
2585 if (rsn_ie_len < 2)
2586 return -EINVAL;
2587 cnt = *((u16 *) rsn_ie);
2588 rsn_ie += (2 + cnt * 4);
2589 rsn_ie_len -= (2 + cnt * 4);
2590
2591 if (rsn_ie_len < 2)
2592 return -EINVAL;
2593
2594 memcpy(rsn_capab, rsn_ie, 2);
2595
2596 return 0;
2597}
2598
2396static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, 2599static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2397 struct cfg80211_ap_settings *info) 2600 struct cfg80211_ap_settings *info)
2398{ 2601{
@@ -2405,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2405 struct wmi_connect_cmd p; 2608 struct wmi_connect_cmd p;
2406 int res; 2609 int res;
2407 int i, ret; 2610 int i, ret;
2611 u16 rsn_capab = 0;
2408 2612
2409 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); 2613 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
2410 2614
@@ -2534,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2534 p.nw_subtype = SUBTYPE_NONE; 2738 p.nw_subtype = SUBTYPE_NONE;
2535 } 2739 }
2536 2740
2741 if (info->inactivity_timeout) {
2742 res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
2743 info->inactivity_timeout);
2744 if (res < 0)
2745 return res;
2746 }
2747
2748 if (ath6kl_set_htcap(vif, vif->next_ch_band,
2749 vif->next_ch_type != NL80211_CHAN_NO_HT))
2750 return -EIO;
2751
2752 /*
2753 * Get the PTKSA replay counter in the RSN IE. Supplicant
2754 * will use the RSN IE in M3 message and firmware has to
2755 * advertise the same in beacon/probe response. Send
2756 * the complete RSN IE capability field to firmware
2757 */
2758 if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) &&
2759 test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
2760 ar->fw_capabilities)) {
2761 res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
2762 WLAN_EID_RSN, WMI_RSN_IE_CAPB,
2763 (const u8 *) &rsn_capab,
2764 sizeof(rsn_capab));
2765 if (res < 0)
2766 return res;
2767 }
2768
2537 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); 2769 res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
2538 if (res < 0) 2770 if (res < 0)
2539 return res; 2771 return res;
@@ -2568,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
2568 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); 2800 ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
2569 clear_bit(CONNECTED, &vif->flags); 2801 clear_bit(CONNECTED, &vif->flags);
2570 2802
2803 /* Restore ht setting in firmware */
2804 if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true))
2805 return -EIO;
2806
2807 if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true))
2808 return -EIO;
2809
2571 return 0; 2810 return 0;
2572} 2811}
2573 2812
@@ -2749,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
2749 return false; 2988 return false;
2750} 2989}
2751 2990
2991/* Check if SSID length is greater than DIRECT- */
2992static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
2993{
2994 const struct ieee80211_mgmt *mgmt;
2995 mgmt = (const struct ieee80211_mgmt *) buf;
2996
2997 /* variable[1] contains the SSID tag length */
2998 if (buf + len >= &mgmt->u.probe_resp.variable[1] &&
2999 (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) {
3000 return true;
3001 }
3002
3003 return false;
3004}
3005
2752static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, 3006static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2753 struct ieee80211_channel *chan, bool offchan, 3007 struct ieee80211_channel *chan, bool offchan,
2754 enum nl80211_channel_type channel_type, 3008 enum nl80211_channel_type channel_type,
@@ -2763,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
2763 bool more_data, queued; 3017 bool more_data, queued;
2764 3018
2765 mgmt = (const struct ieee80211_mgmt *) buf; 3019 mgmt = (const struct ieee80211_mgmt *) buf;
2766 if (buf + len >= mgmt->u.probe_resp.variable && 3020 if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
2767 vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && 3021 ieee80211_is_probe_resp(mgmt->frame_control) &&
2768 ieee80211_is_probe_resp(mgmt->frame_control)) { 3022 ath6kl_is_p2p_go_ssid(buf, len)) {
2769 /* 3023 /*
2770 * Send Probe Response frame in AP mode using a separate WMI 3024 * Send Probe Response frame in GO mode using a separate WMI
2771 * command to allow the target to fill in the generic IEs. 3025 * command to allow the target to fill in the generic IEs.
2772 */ 3026 */
2773 *cookie = 0; /* TX status not supported */ 3027 *cookie = 0; /* TX status not supported */
@@ -2835,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
2835 if (vif->sme_state != SME_DISCONNECTED) 3089 if (vif->sme_state != SME_DISCONNECTED)
2836 return -EBUSY; 3090 return -EBUSY;
2837 3091
3092 ath6kl_cfg80211_scan_complete_event(vif, true);
3093
2838 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { 3094 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
2839 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, 3095 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2840 i, DISABLE_SSID_FLAG, 3096 i, DISABLE_SSID_FLAG,
@@ -3096,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
3096 vif->next_mode = nw_type; 3352 vif->next_mode = nw_type;
3097 vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; 3353 vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
3098 vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; 3354 vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
3355 vif->htcap.ht_enable = true;
3099 3356
3100 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); 3357 memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
3101 if (fw_vif_idx != 0) 3358 if (fw_vif_idx != 0)
@@ -3183,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
3183 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) 3440 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
3184 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; 3441 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
3185 3442
3443 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
3444 ar->fw_capabilities))
3445 ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER;
3446
3186 ar->wiphy->probe_resp_offload = 3447 ar->wiphy->probe_resp_offload =
3187 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | 3448 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
3188 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | 3449 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h
index a60e78c0472f..98a886154d9c 100644
--- a/drivers/net/wireless/ath/ath6kl/common.h
+++ b/drivers/net/wireless/ath/ath6kl/common.h
@@ -22,7 +22,8 @@
22 22
23#define ATH6KL_MAX_IE 256 23#define ATH6KL_MAX_IE 256
24 24
25extern int ath6kl_printk(const char *level, const char *fmt, ...); 25extern __printf(2, 3)
26int ath6kl_printk(const char *level, const char *fmt, ...);
26 27
27/* 28/*
28 * Reflects the version of binary interface exposed by ATH6KL target 29 * Reflects the version of binary interface exposed by ATH6KL target
@@ -77,6 +78,7 @@ enum crypto_type {
77 78
78struct htc_endpoint_credit_dist; 79struct htc_endpoint_credit_dist;
79struct ath6kl; 80struct ath6kl;
81struct ath6kl_htcap;
80enum htc_credit_dist_reason; 82enum htc_credit_dist_reason;
81struct ath6kl_htc_credit_info; 83struct ath6kl_htc_credit_info;
82 84
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c
index 45e641f3a41b..fdb3b1decc76 100644
--- a/drivers/net/wireless/ath/ath6kl/core.c
+++ b/drivers/net/wireless/ath/ath6kl/core.c
@@ -20,9 +20,11 @@
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/moduleparam.h> 21#include <linux/moduleparam.h>
22#include <linux/export.h> 22#include <linux/export.h>
23#include <linux/vmalloc.h>
23 24
24#include "debug.h" 25#include "debug.h"
25#include "hif-ops.h" 26#include "hif-ops.h"
27#include "htc-ops.h"
26#include "cfg80211.h" 28#include "cfg80211.h"
27 29
28unsigned int debug_mask; 30unsigned int debug_mask;
@@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644);
39module_param(ath6kl_p2p, uint, 0644); 41module_param(ath6kl_p2p, uint, 0644);
40module_param(testmode, uint, 0644); 42module_param(testmode, uint, 0644);
41 43
42int ath6kl_core_init(struct ath6kl *ar) 44void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
45{
46 ath6kl_htc_tx_complete(ar, skb);
47}
48EXPORT_SYMBOL(ath6kl_core_tx_complete);
49
50void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe)
51{
52 ath6kl_htc_rx_complete(ar, skb, pipe);
53}
54EXPORT_SYMBOL(ath6kl_core_rx_complete);
55
56int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
43{ 57{
44 struct ath6kl_bmi_target_info targ_info; 58 struct ath6kl_bmi_target_info targ_info;
45 struct net_device *ndev; 59 struct net_device *ndev;
46 int ret = 0, i; 60 int ret = 0, i;
47 61
62 switch (htc_type) {
63 case ATH6KL_HTC_TYPE_MBOX:
64 ath6kl_htc_mbox_attach(ar);
65 break;
66 case ATH6KL_HTC_TYPE_PIPE:
67 ath6kl_htc_pipe_attach(ar);
68 break;
69 default:
70 WARN_ON(1);
71 return -ENOMEM;
72 }
73
48 ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); 74 ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
49 if (!ar->ath6kl_wq) 75 if (!ar->ath6kl_wq)
50 return -ENOMEM; 76 return -ENOMEM;
@@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
280 306
281 kfree(ar->fw_board); 307 kfree(ar->fw_board);
282 kfree(ar->fw_otp); 308 kfree(ar->fw_otp);
283 kfree(ar->fw); 309 vfree(ar->fw);
284 kfree(ar->fw_patch); 310 kfree(ar->fw_patch);
285 kfree(ar->fw_testscript); 311 kfree(ar->fw_testscript);
286 312
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index f1dd8906be45..9d67964a51dd 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -91,6 +91,15 @@ enum ath6kl_fw_capability {
91 */ 91 */
92 ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, 92 ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
93 93
94 /*
95 * Firmware has support to cleanup inactive stations
96 * in AP mode.
97 */
98 ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
99
100 /* Firmware has support to override rsn cap of rsn ie */
101 ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
102
94 /* this needs to be last */ 103 /* this needs to be last */
95 ATH6KL_FW_CAPABILITY_MAX, 104 ATH6KL_FW_CAPABILITY_MAX,
96}; 105};
@@ -205,6 +214,8 @@ struct ath6kl_fw_ie {
205#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) 214#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
206#define ATH6KL_CONF_UART_DEBUG BIT(4) 215#define ATH6KL_CONF_UART_DEBUG BIT(4)
207 216
217#define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */
218
208enum wlan_low_pwr_state { 219enum wlan_low_pwr_state {
209 WLAN_POWER_STATE_ON, 220 WLAN_POWER_STATE_ON,
210 WLAN_POWER_STATE_CUT_PWR, 221 WLAN_POWER_STATE_CUT_PWR,
@@ -454,6 +465,11 @@ enum ath6kl_hif_type {
454 ATH6KL_HIF_TYPE_USB, 465 ATH6KL_HIF_TYPE_USB,
455}; 466};
456 467
468enum ath6kl_htc_type {
469 ATH6KL_HTC_TYPE_MBOX,
470 ATH6KL_HTC_TYPE_PIPE,
471};
472
457/* Max number of filters that hw supports */ 473/* Max number of filters that hw supports */
458#define ATH6K_MAX_MC_FILTERS_PER_LIST 7 474#define ATH6K_MAX_MC_FILTERS_PER_LIST 7
459struct ath6kl_mc_filter { 475struct ath6kl_mc_filter {
@@ -461,6 +477,12 @@ struct ath6kl_mc_filter {
461 char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; 477 char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
462}; 478};
463 479
480struct ath6kl_htcap {
481 bool ht_enable;
482 u8 ampdu_factor;
483 unsigned short cap_info;
484};
485
464/* 486/*
465 * Driver's maximum limit, note that some firmwares support only one vif 487 * Driver's maximum limit, note that some firmwares support only one vif
466 * and the runtime (current) limit must be checked from ar->vif_max. 488 * and the runtime (current) limit must be checked from ar->vif_max.
@@ -509,6 +531,7 @@ struct ath6kl_vif {
509 struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; 531 struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
510 struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; 532 struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
511 struct aggr_info *aggr_cntxt; 533 struct aggr_info *aggr_cntxt;
534 struct ath6kl_htcap htcap;
512 535
513 struct timer_list disconnect_timer; 536 struct timer_list disconnect_timer;
514 struct timer_list sched_scan_timer; 537 struct timer_list sched_scan_timer;
@@ -521,6 +544,8 @@ struct ath6kl_vif {
521 u32 send_action_id; 544 u32 send_action_id;
522 bool probe_req_report; 545 bool probe_req_report;
523 u16 next_chan; 546 u16 next_chan;
547 enum nl80211_channel_type next_ch_type;
548 enum ieee80211_band next_ch_band;
524 u16 assoc_bss_beacon_int; 549 u16 assoc_bss_beacon_int;
525 u16 listen_intvl_t; 550 u16 listen_intvl_t;
526 u16 bmiss_time_t; 551 u16 bmiss_time_t;
@@ -568,6 +593,7 @@ struct ath6kl {
568 593
569 struct ath6kl_bmi bmi; 594 struct ath6kl_bmi bmi;
570 const struct ath6kl_hif_ops *hif_ops; 595 const struct ath6kl_hif_ops *hif_ops;
596 const struct ath6kl_htc_ops *htc_ops;
571 struct wmi *wmi; 597 struct wmi *wmi;
572 int tx_pending[ENDPOINT_MAX]; 598 int tx_pending[ENDPOINT_MAX];
573 int total_tx_data_pend; 599 int total_tx_data_pend;
@@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev);
746void ath6kl_cookie_init(struct ath6kl *ar); 772void ath6kl_cookie_init(struct ath6kl *ar);
747void ath6kl_cookie_cleanup(struct ath6kl *ar); 773void ath6kl_cookie_cleanup(struct ath6kl *ar);
748void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); 774void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
749void ath6kl_tx_complete(void *context, struct list_head *packet_queue); 775void ath6kl_tx_complete(struct htc_target *context,
776 struct list_head *packet_queue);
750enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, 777enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
751 struct htc_packet *packet); 778 struct htc_packet *packet);
752void ath6kl_stop_txrx(struct ath6kl *ar); 779void ath6kl_stop_txrx(struct ath6kl *ar);
@@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar);
821 848
822void ath6kl_check_wow_status(struct ath6kl *ar); 849void ath6kl_check_wow_status(struct ath6kl *ar);
823 850
851void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb);
852void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe);
853
824struct ath6kl *ath6kl_core_create(struct device *dev); 854struct ath6kl *ath6kl_core_create(struct device *dev);
825int ath6kl_core_init(struct ath6kl *ar); 855int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
826void ath6kl_core_cleanup(struct ath6kl *ar); 856void ath6kl_core_cleanup(struct ath6kl *ar);
827void ath6kl_core_destroy(struct ath6kl *ar); 857void ath6kl_core_destroy(struct ath6kl *ar);
828 858
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index d01403a263ff..1b76aff78508 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -616,6 +616,12 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
616 "Num disconnects", tgt_stats->cs_discon_cnt); 616 "Num disconnects", tgt_stats->cs_discon_cnt);
617 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 617 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
618 "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); 618 "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
619 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
620 "ARP pkt received", tgt_stats->arp_received);
621 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
622 "ARP pkt matched", tgt_stats->arp_matched);
623 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
624 "ARP pkt replied", tgt_stats->arp_replied);
619 625
620 if (len > buf_len) 626 if (len > buf_len)
621 len = buf_len; 627 len = buf_len;
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index 1803a0baae82..49639d8266c2 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -43,6 +43,7 @@ enum ATH6K_DEBUG_MASK {
43 ATH6KL_DBG_WMI_DUMP = BIT(19), 43 ATH6KL_DBG_WMI_DUMP = BIT(19),
44 ATH6KL_DBG_SUSPEND = BIT(20), 44 ATH6KL_DBG_SUSPEND = BIT(20),
45 ATH6KL_DBG_USB = BIT(21), 45 ATH6KL_DBG_USB = BIT(21),
46 ATH6KL_DBG_USB_BULK = BIT(22),
46 ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ 47 ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
47}; 48};
48 49
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h
index fd84086638e3..8c9e72d5250d 100644
--- a/drivers/net/wireless/ath/ath6kl/hif-ops.h
+++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h
@@ -150,4 +150,38 @@ static inline void ath6kl_hif_stop(struct ath6kl *ar)
150 ar->hif_ops->stop(ar); 150 ar->hif_ops->stop(ar);
151} 151}
152 152
153static inline int ath6kl_hif_pipe_send(struct ath6kl *ar,
154 u8 pipe, struct sk_buff *hdr_buf,
155 struct sk_buff *buf)
156{
157 ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe send\n");
158
159 return ar->hif_ops->pipe_send(ar, pipe, hdr_buf, buf);
160}
161
162static inline void ath6kl_hif_pipe_get_default(struct ath6kl *ar,
163 u8 *ul_pipe, u8 *dl_pipe)
164{
165 ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get default\n");
166
167 ar->hif_ops->pipe_get_default(ar, ul_pipe, dl_pipe);
168}
169
170static inline int ath6kl_hif_pipe_map_service(struct ath6kl *ar,
171 u16 service_id, u8 *ul_pipe,
172 u8 *dl_pipe)
173{
174 ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get default\n");
175
176 return ar->hif_ops->pipe_map_service(ar, service_id, ul_pipe, dl_pipe);
177}
178
179static inline u16 ath6kl_hif_pipe_get_free_queue_number(struct ath6kl *ar,
180 u8 pipe)
181{
182 ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get free queue number\n");
183
184 return ar->hif_ops->pipe_get_free_queue_number(ar, pipe);
185}
186
153#endif 187#endif
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h
index 20ed6b73517b..61f6b21fb0ae 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.h
+++ b/drivers/net/wireless/ath/ath6kl/hif.h
@@ -256,6 +256,12 @@ struct ath6kl_hif_ops {
256 int (*power_on)(struct ath6kl *ar); 256 int (*power_on)(struct ath6kl *ar);
257 int (*power_off)(struct ath6kl *ar); 257 int (*power_off)(struct ath6kl *ar);
258 void (*stop)(struct ath6kl *ar); 258 void (*stop)(struct ath6kl *ar);
259 int (*pipe_send)(struct ath6kl *ar, u8 pipe, struct sk_buff *hdr_buf,
260 struct sk_buff *buf);
261 void (*pipe_get_default)(struct ath6kl *ar, u8 *pipe_ul, u8 *pipe_dl);
262 int (*pipe_map_service)(struct ath6kl *ar, u16 service_id, u8 *pipe_ul,
263 u8 *pipe_dl);
264 u16 (*pipe_get_free_queue_number)(struct ath6kl *ar, u8 pipe);
259}; 265};
260 266
261int ath6kl_hif_setup(struct ath6kl_device *dev); 267int ath6kl_hif_setup(struct ath6kl_device *dev);
diff --git a/drivers/net/wireless/ath/ath6kl/htc-ops.h b/drivers/net/wireless/ath/ath6kl/htc-ops.h
new file mode 100644
index 000000000000..2d4eed55cfd1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc-ops.h
@@ -0,0 +1,113 @@
1/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef HTC_OPS_H
18#define HTC_OPS_H
19
20#include "htc.h"
21#include "debug.h"
22
23static inline void *ath6kl_htc_create(struct ath6kl *ar)
24{
25 return ar->htc_ops->create(ar);
26}
27
28static inline int ath6kl_htc_wait_target(struct htc_target *target)
29{
30 return target->dev->ar->htc_ops->wait_target(target);
31}
32
33static inline int ath6kl_htc_start(struct htc_target *target)
34{
35 return target->dev->ar->htc_ops->start(target);
36}
37
38static inline int ath6kl_htc_conn_service(struct htc_target *target,
39 struct htc_service_connect_req *req,
40 struct htc_service_connect_resp *resp)
41{
42 return target->dev->ar->htc_ops->conn_service(target, req, resp);
43}
44
45static inline int ath6kl_htc_tx(struct htc_target *target,
46 struct htc_packet *packet)
47{
48 return target->dev->ar->htc_ops->tx(target, packet);
49}
50
51static inline void ath6kl_htc_stop(struct htc_target *target)
52{
53 return target->dev->ar->htc_ops->stop(target);
54}
55
56static inline void ath6kl_htc_cleanup(struct htc_target *target)
57{
58 return target->dev->ar->htc_ops->cleanup(target);
59}
60
61static inline void ath6kl_htc_flush_txep(struct htc_target *target,
62 enum htc_endpoint_id endpoint,
63 u16 tag)
64{
65 return target->dev->ar->htc_ops->flush_txep(target, endpoint, tag);
66}
67
68static inline void ath6kl_htc_flush_rx_buf(struct htc_target *target)
69{
70 return target->dev->ar->htc_ops->flush_rx_buf(target);
71}
72
73static inline void ath6kl_htc_activity_changed(struct htc_target *target,
74 enum htc_endpoint_id endpoint,
75 bool active)
76{
77 return target->dev->ar->htc_ops->activity_changed(target, endpoint,
78 active);
79}
80
81static inline int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
82 enum htc_endpoint_id endpoint)
83{
84 return target->dev->ar->htc_ops->get_rxbuf_num(target, endpoint);
85}
86
87static inline int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
88 struct list_head *pktq)
89{
90 return target->dev->ar->htc_ops->add_rxbuf_multiple(target, pktq);
91}
92
93static inline int ath6kl_htc_credit_setup(struct htc_target *target,
94 struct ath6kl_htc_credit_info *info)
95{
96 return target->dev->ar->htc_ops->credit_setup(target, info);
97}
98
99static inline void ath6kl_htc_tx_complete(struct ath6kl *ar,
100 struct sk_buff *skb)
101{
102 ar->htc_ops->tx_complete(ar, skb);
103}
104
105
106static inline void ath6kl_htc_rx_complete(struct ath6kl *ar,
107 struct sk_buff *skb, u8 pipe)
108{
109 ar->htc_ops->rx_complete(ar, skb, pipe);
110}
111
112
113#endif
diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h
index 5027ccc36b62..a2c8ff809793 100644
--- a/drivers/net/wireless/ath/ath6kl/htc.h
+++ b/drivers/net/wireless/ath/ath6kl/htc.h
@@ -25,6 +25,7 @@
25/* send direction */ 25/* send direction */
26#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) 26#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
27#define HTC_FLAGS_SEND_BUNDLE (1 << 1) 27#define HTC_FLAGS_SEND_BUNDLE (1 << 1)
28#define HTC_FLAGS_TX_FIXUP_NETBUF (1 << 2)
28 29
29/* receive direction */ 30/* receive direction */
30#define HTC_FLG_RX_UNUSED (1 << 0) 31#define HTC_FLG_RX_UNUSED (1 << 0)
@@ -56,6 +57,10 @@
56#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2 57#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2
57#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4 58#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4
58#define HTC_CONN_FLGS_THRESH_MASK 0x3 59#define HTC_CONN_FLGS_THRESH_MASK 0x3
60/* disable credit flow control on a specific service */
61#define HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL (1 << 3)
62#define HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT 8
63#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK 0xFF00
59 64
60/* connect response status codes */ 65/* connect response status codes */
61#define HTC_SERVICE_SUCCESS 0 66#define HTC_SERVICE_SUCCESS 0
@@ -75,6 +80,7 @@
75#define HTC_RECORD_LOOKAHEAD_BUNDLE 3 80#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
76 81
77#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0) 82#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0)
83#define HTC_SETUP_COMP_FLG_DISABLE_TX_CREDIT_FLOW (1 << 1)
78 84
79#define MAKE_SERVICE_ID(group, index) \ 85#define MAKE_SERVICE_ID(group, index) \
80 (int)(((int)group << 8) | (int)(index)) 86 (int)(((int)group << 8) | (int)(index))
@@ -109,6 +115,8 @@
109 115
110/* HTC operational parameters */ 116/* HTC operational parameters */
111#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ 117#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
118#define HTC_TARGET_RESPONSE_POLL_WAIT 10
119#define HTC_TARGET_RESPONSE_POLL_COUNT 200
112#define HTC_TARGET_DEBUG_INTR_MASK 0x01 120#define HTC_TARGET_DEBUG_INTR_MASK 0x01
113#define HTC_TARGET_CREDIT_INTR_MASK 0xF0 121#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
114 122
@@ -128,6 +136,7 @@
128 136
129#define HTC_RECV_WAIT_BUFFERS (1 << 0) 137#define HTC_RECV_WAIT_BUFFERS (1 << 0)
130#define HTC_OP_STATE_STOPPING (1 << 0) 138#define HTC_OP_STATE_STOPPING (1 << 0)
139#define HTC_OP_STATE_SETUP_COMPLETE (1 << 1)
131 140
132/* 141/*
133 * The frame header length and message formats defined herein were selected 142 * The frame header length and message formats defined herein were selected
@@ -311,6 +320,14 @@ struct htc_packet {
311 320
312 void (*completion) (struct htc_target *, struct htc_packet *); 321 void (*completion) (struct htc_target *, struct htc_packet *);
313 struct htc_target *context; 322 struct htc_target *context;
323
324 /*
325 * optimization for network-oriented data, the HTC packet
326 * can pass the network buffer corresponding to the HTC packet
327 * lower layers may optimized the transfer knowing this is
328 * a network buffer
329 */
330 struct sk_buff *skb;
314}; 331};
315 332
316enum htc_send_full_action { 333enum htc_send_full_action {
@@ -319,12 +336,14 @@ enum htc_send_full_action {
319}; 336};
320 337
321struct htc_ep_callbacks { 338struct htc_ep_callbacks {
339 void (*tx_complete) (struct htc_target *, struct htc_packet *);
322 void (*rx) (struct htc_target *, struct htc_packet *); 340 void (*rx) (struct htc_target *, struct htc_packet *);
323 void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint); 341 void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint);
324 enum htc_send_full_action (*tx_full) (struct htc_target *, 342 enum htc_send_full_action (*tx_full) (struct htc_target *,
325 struct htc_packet *); 343 struct htc_packet *);
326 struct htc_packet *(*rx_allocthresh) (struct htc_target *, 344 struct htc_packet *(*rx_allocthresh) (struct htc_target *,
327 enum htc_endpoint_id, int); 345 enum htc_endpoint_id, int);
346 void (*tx_comp_multi) (struct htc_target *, struct list_head *);
328 int rx_alloc_thresh; 347 int rx_alloc_thresh;
329 int rx_refill_thresh; 348 int rx_refill_thresh;
330}; 349};
@@ -502,6 +521,13 @@ struct htc_endpoint {
502 u32 conn_flags; 521 u32 conn_flags;
503 struct htc_endpoint_stats ep_st; 522 struct htc_endpoint_stats ep_st;
504 u16 tx_drop_packet_threshold; 523 u16 tx_drop_packet_threshold;
524
525 struct {
526 u8 pipeid_ul;
527 u8 pipeid_dl;
528 struct list_head tx_lookup_queue;
529 bool tx_credit_flow_enabled;
530 } pipe;
505}; 531};
506 532
507struct htc_control_buffer { 533struct htc_control_buffer {
@@ -509,6 +535,42 @@ struct htc_control_buffer {
509 u8 *buf; 535 u8 *buf;
510}; 536};
511 537
538struct htc_pipe_txcredit_alloc {
539 u16 service_id;
540 u8 credit_alloc;
541};
542
543enum htc_send_queue_result {
544 HTC_SEND_QUEUE_OK = 0, /* packet was queued */
545 HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */
546};
547
548struct ath6kl_htc_ops {
549 void* (*create)(struct ath6kl *ar);
550 int (*wait_target)(struct htc_target *target);
551 int (*start)(struct htc_target *target);
552 int (*conn_service)(struct htc_target *target,
553 struct htc_service_connect_req *req,
554 struct htc_service_connect_resp *resp);
555 int (*tx)(struct htc_target *target, struct htc_packet *packet);
556 void (*stop)(struct htc_target *target);
557 void (*cleanup)(struct htc_target *target);
558 void (*flush_txep)(struct htc_target *target,
559 enum htc_endpoint_id endpoint, u16 tag);
560 void (*flush_rx_buf)(struct htc_target *target);
561 void (*activity_changed)(struct htc_target *target,
562 enum htc_endpoint_id endpoint,
563 bool active);
564 int (*get_rxbuf_num)(struct htc_target *target,
565 enum htc_endpoint_id endpoint);
566 int (*add_rxbuf_multiple)(struct htc_target *target,
567 struct list_head *pktq);
568 int (*credit_setup)(struct htc_target *target,
569 struct ath6kl_htc_credit_info *cred_info);
570 int (*tx_complete)(struct ath6kl *ar, struct sk_buff *skb);
571 int (*rx_complete)(struct ath6kl *ar, struct sk_buff *skb, u8 pipe);
572};
573
512struct ath6kl_device; 574struct ath6kl_device;
513 575
514/* our HTC target state */ 576/* our HTC target state */
@@ -557,36 +619,19 @@ struct htc_target {
557 619
558 /* counts the number of Tx without bundling continously per AC */ 620 /* counts the number of Tx without bundling continously per AC */
559 u32 ac_tx_count[WMM_NUM_AC]; 621 u32 ac_tx_count[WMM_NUM_AC];
622
623 struct {
624 struct htc_packet *htc_packet_pool;
625 u8 ctrl_response_buf[HTC_MAX_CTRL_MSG_LEN];
626 int ctrl_response_len;
627 bool ctrl_response_valid;
628 struct htc_pipe_txcredit_alloc txcredit_alloc[ENDPOINT_MAX];
629 } pipe;
560}; 630};
561 631
562void *ath6kl_htc_create(struct ath6kl *ar);
563void ath6kl_htc_set_credit_dist(struct htc_target *target,
564 struct ath6kl_htc_credit_info *cred_info,
565 u16 svc_pri_order[], int len);
566int ath6kl_htc_wait_target(struct htc_target *target);
567int ath6kl_htc_start(struct htc_target *target);
568int ath6kl_htc_conn_service(struct htc_target *target,
569 struct htc_service_connect_req *req,
570 struct htc_service_connect_resp *resp);
571int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet);
572void ath6kl_htc_stop(struct htc_target *target);
573void ath6kl_htc_cleanup(struct htc_target *target);
574void ath6kl_htc_flush_txep(struct htc_target *target,
575 enum htc_endpoint_id endpoint, u16 tag);
576void ath6kl_htc_flush_rx_buf(struct htc_target *target);
577void ath6kl_htc_indicate_activity_change(struct htc_target *target,
578 enum htc_endpoint_id endpoint,
579 bool active);
580int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
581 enum htc_endpoint_id endpoint);
582int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
583 struct list_head *pktq);
584int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, 632int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
585 u32 msg_look_ahead, int *n_pkts); 633 u32 msg_look_ahead, int *n_pkts);
586 634
587int ath6kl_credit_setup(void *htc_handle,
588 struct ath6kl_htc_credit_info *cred_info);
589
590static inline void set_htc_pkt_info(struct htc_packet *packet, void *context, 635static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
591 u8 *buf, unsigned int len, 636 u8 *buf, unsigned int len,
592 enum htc_endpoint_id eid, u16 tag) 637 enum htc_endpoint_id eid, u16 tag)
@@ -626,4 +671,7 @@ static inline int get_queue_depth(struct list_head *queue)
626 return depth; 671 return depth;
627} 672}
628 673
674void ath6kl_htc_pipe_attach(struct ath6kl *ar);
675void ath6kl_htc_mbox_attach(struct ath6kl *ar);
676
629#endif 677#endif
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
index 4849d99cce77..065e61516d7a 100644
--- a/drivers/net/wireless/ath/ath6kl/htc.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
@@ -23,6 +23,14 @@
23 23
24#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) 24#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
25 25
26static void ath6kl_htc_mbox_cleanup(struct htc_target *target);
27static void ath6kl_htc_mbox_stop(struct htc_target *target);
28static int ath6kl_htc_mbox_add_rxbuf_multiple(struct htc_target *target,
29 struct list_head *pkt_queue);
30static void ath6kl_htc_set_credit_dist(struct htc_target *target,
31 struct ath6kl_htc_credit_info *cred_info,
32 u16 svc_pri_order[], int len);
33
26/* threshold to re-enable Tx bundling for an AC*/ 34/* threshold to re-enable Tx bundling for an AC*/
27#define TX_RESUME_BUNDLE_THRESHOLD 1500 35#define TX_RESUME_BUNDLE_THRESHOLD 1500
28 36
@@ -130,8 +138,8 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
130} 138}
131 139
132/* initialize and setup credit distribution */ 140/* initialize and setup credit distribution */
133int ath6kl_credit_setup(void *htc_handle, 141static int ath6kl_htc_mbox_credit_setup(struct htc_target *htc_target,
134 struct ath6kl_htc_credit_info *cred_info) 142 struct ath6kl_htc_credit_info *cred_info)
135{ 143{
136 u16 servicepriority[5]; 144 u16 servicepriority[5];
137 145
@@ -144,7 +152,7 @@ int ath6kl_credit_setup(void *htc_handle,
144 servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ 152 servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
145 153
146 /* set priority list */ 154 /* set priority list */
147 ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5); 155 ath6kl_htc_set_credit_dist(htc_target, cred_info, servicepriority, 5);
148 156
149 return 0; 157 return 0;
150} 158}
@@ -432,7 +440,7 @@ static void htc_tx_complete(struct htc_endpoint *endpoint,
432 "htc tx complete ep %d pkts %d\n", 440 "htc tx complete ep %d pkts %d\n",
433 endpoint->eid, get_queue_depth(txq)); 441 endpoint->eid, get_queue_depth(txq));
434 442
435 ath6kl_tx_complete(endpoint->target->dev->ar, txq); 443 ath6kl_tx_complete(endpoint->target, txq);
436} 444}
437 445
438static void htc_tx_comp_handler(struct htc_target *target, 446static void htc_tx_comp_handler(struct htc_target *target,
@@ -1065,7 +1073,7 @@ static int htc_setup_tx_complete(struct htc_target *target)
1065 return status; 1073 return status;
1066} 1074}
1067 1075
1068void ath6kl_htc_set_credit_dist(struct htc_target *target, 1076static void ath6kl_htc_set_credit_dist(struct htc_target *target,
1069 struct ath6kl_htc_credit_info *credit_info, 1077 struct ath6kl_htc_credit_info *credit_info,
1070 u16 srvc_pri_order[], int list_len) 1078 u16 srvc_pri_order[], int list_len)
1071{ 1079{
@@ -1093,7 +1101,8 @@ void ath6kl_htc_set_credit_dist(struct htc_target *target,
1093 } 1101 }
1094} 1102}
1095 1103
1096int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) 1104static int ath6kl_htc_mbox_tx(struct htc_target *target,
1105 struct htc_packet *packet)
1097{ 1106{
1098 struct htc_endpoint *endpoint; 1107 struct htc_endpoint *endpoint;
1099 struct list_head queue; 1108 struct list_head queue;
@@ -1121,7 +1130,7 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
1121} 1130}
1122 1131
1123/* flush endpoint TX queue */ 1132/* flush endpoint TX queue */
1124void ath6kl_htc_flush_txep(struct htc_target *target, 1133static void ath6kl_htc_mbox_flush_txep(struct htc_target *target,
1125 enum htc_endpoint_id eid, u16 tag) 1134 enum htc_endpoint_id eid, u16 tag)
1126{ 1135{
1127 struct htc_packet *packet, *tmp_pkt; 1136 struct htc_packet *packet, *tmp_pkt;
@@ -1173,12 +1182,13 @@ static void ath6kl_htc_flush_txep_all(struct htc_target *target)
1173 if (endpoint->svc_id == 0) 1182 if (endpoint->svc_id == 0)
1174 /* not in use.. */ 1183 /* not in use.. */
1175 continue; 1184 continue;
1176 ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL); 1185 ath6kl_htc_mbox_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL);
1177 } 1186 }
1178} 1187}
1179 1188
1180void ath6kl_htc_indicate_activity_change(struct htc_target *target, 1189static void ath6kl_htc_mbox_activity_changed(struct htc_target *target,
1181 enum htc_endpoint_id eid, bool active) 1190 enum htc_endpoint_id eid,
1191 bool active)
1182{ 1192{
1183 struct htc_endpoint *endpoint = &target->endpoint[eid]; 1193 struct htc_endpoint *endpoint = &target->endpoint[eid];
1184 bool dist = false; 1194 bool dist = false;
@@ -1246,7 +1256,7 @@ static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet)
1246 1256
1247 INIT_LIST_HEAD(&queue); 1257 INIT_LIST_HEAD(&queue);
1248 list_add_tail(&packet->list, &queue); 1258 list_add_tail(&packet->list, &queue);
1249 return ath6kl_htc_add_rxbuf_multiple(target, &queue); 1259 return ath6kl_htc_mbox_add_rxbuf_multiple(target, &queue);
1250} 1260}
1251 1261
1252static void htc_reclaim_rxbuf(struct htc_target *target, 1262static void htc_reclaim_rxbuf(struct htc_target *target,
@@ -1353,7 +1363,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,
1353 sizeof(*htc_hdr)); 1363 sizeof(*htc_hdr));
1354 1364
1355 if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) { 1365 if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) {
1356 ath6kl_warn("Rx buffer requested with invalid length\n"); 1366 ath6kl_warn("Rx buffer requested with invalid length htc_hdr:eid %d, flags 0x%x, len %d\n",
1367 htc_hdr->eid, htc_hdr->flags,
1368 le16_to_cpu(htc_hdr->payld_len));
1357 return -EINVAL; 1369 return -EINVAL;
1358 } 1370 }
1359 1371
@@ -2288,7 +2300,7 @@ fail_ctrl_rx:
2288 return NULL; 2300 return NULL;
2289} 2301}
2290 2302
2291int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, 2303static int ath6kl_htc_mbox_add_rxbuf_multiple(struct htc_target *target,
2292 struct list_head *pkt_queue) 2304 struct list_head *pkt_queue)
2293{ 2305{
2294 struct htc_endpoint *endpoint; 2306 struct htc_endpoint *endpoint;
@@ -2350,7 +2362,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
2350 return status; 2362 return status;
2351} 2363}
2352 2364
2353void ath6kl_htc_flush_rx_buf(struct htc_target *target) 2365static void ath6kl_htc_mbox_flush_rx_buf(struct htc_target *target)
2354{ 2366{
2355 struct htc_endpoint *endpoint; 2367 struct htc_endpoint *endpoint;
2356 struct htc_packet *packet, *tmp_pkt; 2368 struct htc_packet *packet, *tmp_pkt;
@@ -2392,7 +2404,7 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target)
2392 } 2404 }
2393} 2405}
2394 2406
2395int ath6kl_htc_conn_service(struct htc_target *target, 2407static int ath6kl_htc_mbox_conn_service(struct htc_target *target,
2396 struct htc_service_connect_req *conn_req, 2408 struct htc_service_connect_req *conn_req,
2397 struct htc_service_connect_resp *conn_resp) 2409 struct htc_service_connect_resp *conn_resp)
2398{ 2410{
@@ -2564,7 +2576,7 @@ static void reset_ep_state(struct htc_target *target)
2564 INIT_LIST_HEAD(&target->cred_dist_list); 2576 INIT_LIST_HEAD(&target->cred_dist_list);
2565} 2577}
2566 2578
2567int ath6kl_htc_get_rxbuf_num(struct htc_target *target, 2579static int ath6kl_htc_mbox_get_rxbuf_num(struct htc_target *target,
2568 enum htc_endpoint_id endpoint) 2580 enum htc_endpoint_id endpoint)
2569{ 2581{
2570 int num; 2582 int num;
@@ -2624,7 +2636,7 @@ static void htc_setup_msg_bndl(struct htc_target *target)
2624 } 2636 }
2625} 2637}
2626 2638
2627int ath6kl_htc_wait_target(struct htc_target *target) 2639static int ath6kl_htc_mbox_wait_target(struct htc_target *target)
2628{ 2640{
2629 struct htc_packet *packet = NULL; 2641 struct htc_packet *packet = NULL;
2630 struct htc_ready_ext_msg *rdy_msg; 2642 struct htc_ready_ext_msg *rdy_msg;
@@ -2693,12 +2705,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
2693 connect.svc_id = HTC_CTRL_RSVD_SVC; 2705 connect.svc_id = HTC_CTRL_RSVD_SVC;
2694 2706
2695 /* connect fake service */ 2707 /* connect fake service */
2696 status = ath6kl_htc_conn_service((void *)target, &connect, &resp); 2708 status = ath6kl_htc_mbox_conn_service((void *)target, &connect, &resp);
2697 2709
2698 if (status) 2710 if (status)
2699 /* 2711 /*
2700 * FIXME: this call doesn't make sense, the caller should 2712 * FIXME: this call doesn't make sense, the caller should
2701 * call ath6kl_htc_cleanup() when it wants remove htc 2713 * call ath6kl_htc_mbox_cleanup() when it wants remove htc
2702 */ 2714 */
2703 ath6kl_hif_cleanup_scatter(target->dev->ar); 2715 ath6kl_hif_cleanup_scatter(target->dev->ar);
2704 2716
@@ -2715,7 +2727,7 @@ fail_wait_target:
2715 * Start HTC, enable interrupts and let the target know 2727 * Start HTC, enable interrupts and let the target know
2716 * host has finished setup. 2728 * host has finished setup.
2717 */ 2729 */
2718int ath6kl_htc_start(struct htc_target *target) 2730static int ath6kl_htc_mbox_start(struct htc_target *target)
2719{ 2731{
2720 struct htc_packet *packet; 2732 struct htc_packet *packet;
2721 int status; 2733 int status;
@@ -2752,7 +2764,7 @@ int ath6kl_htc_start(struct htc_target *target)
2752 status = ath6kl_hif_unmask_intrs(target->dev); 2764 status = ath6kl_hif_unmask_intrs(target->dev);
2753 2765
2754 if (status) 2766 if (status)
2755 ath6kl_htc_stop(target); 2767 ath6kl_htc_mbox_stop(target);
2756 2768
2757 return status; 2769 return status;
2758} 2770}
@@ -2796,7 +2808,7 @@ static int ath6kl_htc_reset(struct htc_target *target)
2796} 2808}
2797 2809
2798/* htc_stop: stop interrupt reception, and flush all queued buffers */ 2810/* htc_stop: stop interrupt reception, and flush all queued buffers */
2799void ath6kl_htc_stop(struct htc_target *target) 2811static void ath6kl_htc_mbox_stop(struct htc_target *target)
2800{ 2812{
2801 spin_lock_bh(&target->htc_lock); 2813 spin_lock_bh(&target->htc_lock);
2802 target->htc_flags |= HTC_OP_STATE_STOPPING; 2814 target->htc_flags |= HTC_OP_STATE_STOPPING;
@@ -2811,12 +2823,12 @@ void ath6kl_htc_stop(struct htc_target *target)
2811 2823
2812 ath6kl_htc_flush_txep_all(target); 2824 ath6kl_htc_flush_txep_all(target);
2813 2825
2814 ath6kl_htc_flush_rx_buf(target); 2826 ath6kl_htc_mbox_flush_rx_buf(target);
2815 2827
2816 ath6kl_htc_reset(target); 2828 ath6kl_htc_reset(target);
2817} 2829}
2818 2830
2819void *ath6kl_htc_create(struct ath6kl *ar) 2831static void *ath6kl_htc_mbox_create(struct ath6kl *ar)
2820{ 2832{
2821 struct htc_target *target = NULL; 2833 struct htc_target *target = NULL;
2822 int status = 0; 2834 int status = 0;
@@ -2857,13 +2869,13 @@ void *ath6kl_htc_create(struct ath6kl *ar)
2857 return target; 2869 return target;
2858 2870
2859err_htc_cleanup: 2871err_htc_cleanup:
2860 ath6kl_htc_cleanup(target); 2872 ath6kl_htc_mbox_cleanup(target);
2861 2873
2862 return NULL; 2874 return NULL;
2863} 2875}
2864 2876
2865/* cleanup the HTC instance */ 2877/* cleanup the HTC instance */
2866void ath6kl_htc_cleanup(struct htc_target *target) 2878static void ath6kl_htc_mbox_cleanup(struct htc_target *target)
2867{ 2879{
2868 struct htc_packet *packet, *tmp_packet; 2880 struct htc_packet *packet, *tmp_packet;
2869 2881
@@ -2888,3 +2900,24 @@ void ath6kl_htc_cleanup(struct htc_target *target)
2888 kfree(target->dev); 2900 kfree(target->dev);
2889 kfree(target); 2901 kfree(target);
2890} 2902}
2903
2904static const struct ath6kl_htc_ops ath6kl_htc_mbox_ops = {
2905 .create = ath6kl_htc_mbox_create,
2906 .wait_target = ath6kl_htc_mbox_wait_target,
2907 .start = ath6kl_htc_mbox_start,
2908 .conn_service = ath6kl_htc_mbox_conn_service,
2909 .tx = ath6kl_htc_mbox_tx,
2910 .stop = ath6kl_htc_mbox_stop,
2911 .cleanup = ath6kl_htc_mbox_cleanup,
2912 .flush_txep = ath6kl_htc_mbox_flush_txep,
2913 .flush_rx_buf = ath6kl_htc_mbox_flush_rx_buf,
2914 .activity_changed = ath6kl_htc_mbox_activity_changed,
2915 .get_rxbuf_num = ath6kl_htc_mbox_get_rxbuf_num,
2916 .add_rxbuf_multiple = ath6kl_htc_mbox_add_rxbuf_multiple,
2917 .credit_setup = ath6kl_htc_mbox_credit_setup,
2918};
2919
2920void ath6kl_htc_mbox_attach(struct ath6kl *ar)
2921{
2922 ar->htc_ops = &ath6kl_htc_mbox_ops;
2923}
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
new file mode 100644
index 000000000000..b277b3446882
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -0,0 +1,1713 @@
1/*
2 * Copyright (c) 2007-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "debug.h"
19#include "hif-ops.h"
20
21#define HTC_PACKET_CONTAINER_ALLOCATION 32
22#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH)
23
24static int ath6kl_htc_pipe_tx(struct htc_target *handle,
25 struct htc_packet *packet);
26static void ath6kl_htc_pipe_cleanup(struct htc_target *handle);
27
28/* htc pipe tx path */
29static inline void restore_tx_packet(struct htc_packet *packet)
30{
31 if (packet->info.tx.flags & HTC_FLAGS_TX_FIXUP_NETBUF) {
32 skb_pull(packet->skb, sizeof(struct htc_frame_hdr));
33 packet->info.tx.flags &= ~HTC_FLAGS_TX_FIXUP_NETBUF;
34 }
35}
36
37static void do_send_completion(struct htc_endpoint *ep,
38 struct list_head *queue_to_indicate)
39{
40 struct htc_packet *packet;
41
42 if (list_empty(queue_to_indicate)) {
43 /* nothing to indicate */
44 return;
45 }
46
47 if (ep->ep_cb.tx_comp_multi != NULL) {
48 ath6kl_dbg(ATH6KL_DBG_HTC,
49 "%s: calling ep %d, send complete multiple callback (%d pkts)\n",
50 __func__, ep->eid,
51 get_queue_depth(queue_to_indicate));
52 /*
53 * a multiple send complete handler is being used,
54 * pass the queue to the handler
55 */
56 ep->ep_cb.tx_comp_multi(ep->target, queue_to_indicate);
57 /*
58 * all packets are now owned by the callback,
59 * reset queue to be safe
60 */
61 INIT_LIST_HEAD(queue_to_indicate);
62 } else {
63 /* using legacy EpTxComplete */
64 do {
65 packet = list_first_entry(queue_to_indicate,
66 struct htc_packet, list);
67
68 list_del(&packet->list);
69 ath6kl_dbg(ATH6KL_DBG_HTC,
70 "%s: calling ep %d send complete callback on packet 0x%p\n",
71 __func__, ep->eid, packet);
72 ep->ep_cb.tx_complete(ep->target, packet);
73 } while (!list_empty(queue_to_indicate));
74 }
75}
76
77static void send_packet_completion(struct htc_target *target,
78 struct htc_packet *packet)
79{
80 struct htc_endpoint *ep = &target->endpoint[packet->endpoint];
81 struct list_head container;
82
83 restore_tx_packet(packet);
84 INIT_LIST_HEAD(&container);
85 list_add_tail(&packet->list, &container);
86
87 /* do completion */
88 do_send_completion(ep, &container);
89}
90
91static void get_htc_packet_credit_based(struct htc_target *target,
92 struct htc_endpoint *ep,
93 struct list_head *queue)
94{
95 int credits_required;
96 int remainder;
97 u8 send_flags;
98 struct htc_packet *packet;
99 unsigned int transfer_len;
100
101 /* NOTE : the TX lock is held when this function is called */
102
103 /* loop until we can grab as many packets out of the queue as we can */
104 while (true) {
105 send_flags = 0;
106 if (list_empty(&ep->txq))
107 break;
108
109 /* get packet at head, but don't remove it */
110 packet = list_first_entry(&ep->txq, struct htc_packet, list);
111 if (packet == NULL)
112 break;
113
114 ath6kl_dbg(ATH6KL_DBG_HTC,
115 "%s: got head packet:0x%p , queue depth: %d\n",
116 __func__, packet, get_queue_depth(&ep->txq));
117
118 transfer_len = packet->act_len + HTC_HDR_LENGTH;
119
120 if (transfer_len <= target->tgt_cred_sz) {
121 credits_required = 1;
122 } else {
123 /* figure out how many credits this message requires */
124 credits_required = transfer_len / target->tgt_cred_sz;
125 remainder = transfer_len % target->tgt_cred_sz;
126
127 if (remainder)
128 credits_required++;
129 }
130
131 ath6kl_dbg(ATH6KL_DBG_HTC, "%s: creds required:%d got:%d\n",
132 __func__, credits_required, ep->cred_dist.credits);
133
134 if (ep->eid == ENDPOINT_0) {
135 /*
136 * endpoint 0 is special, it always has a credit and
137 * does not require credit based flow control
138 */
139 credits_required = 0;
140
141 } else {
142
143 if (ep->cred_dist.credits < credits_required)
144 break;
145
146 ep->cred_dist.credits -= credits_required;
147 ep->ep_st.cred_cosumd += credits_required;
148
149 /* check if we need credits back from the target */
150 if (ep->cred_dist.credits <
151 ep->cred_dist.cred_per_msg) {
152 /* tell the target we need credits ASAP! */
153 send_flags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
154 ep->ep_st.cred_low_indicate += 1;
155 ath6kl_dbg(ATH6KL_DBG_HTC,
156 "%s: host needs credits\n",
157 __func__);
158 }
159 }
160
161 /* now we can fully dequeue */
162 packet = list_first_entry(&ep->txq, struct htc_packet, list);
163
164 list_del(&packet->list);
165 /* save the number of credits this packet consumed */
166 packet->info.tx.cred_used = credits_required;
167 /* save send flags */
168 packet->info.tx.flags = send_flags;
169 packet->info.tx.seqno = ep->seqno;
170 ep->seqno++;
171 /* queue this packet into the caller's queue */
172 list_add_tail(&packet->list, queue);
173 }
174
175}
176
177static void get_htc_packet(struct htc_target *target,
178 struct htc_endpoint *ep,
179 struct list_head *queue, int resources)
180{
181 struct htc_packet *packet;
182
183 /* NOTE : the TX lock is held when this function is called */
184
185 /* loop until we can grab as many packets out of the queue as we can */
186 while (resources) {
187 if (list_empty(&ep->txq))
188 break;
189
190 packet = list_first_entry(&ep->txq, struct htc_packet, list);
191 list_del(&packet->list);
192
193 ath6kl_dbg(ATH6KL_DBG_HTC,
194 "%s: got packet:0x%p , new queue depth: %d\n",
195 __func__, packet, get_queue_depth(&ep->txq));
196 packet->info.tx.seqno = ep->seqno;
197 packet->info.tx.flags = 0;
198 packet->info.tx.cred_used = 0;
199 ep->seqno++;
200
201 /* queue this packet into the caller's queue */
202 list_add_tail(&packet->list, queue);
203 resources--;
204 }
205}
206
207static int htc_issue_packets(struct htc_target *target,
208 struct htc_endpoint *ep,
209 struct list_head *pkt_queue)
210{
211 int status = 0;
212 u16 payload_len;
213 struct sk_buff *skb;
214 struct htc_frame_hdr *htc_hdr;
215 struct htc_packet *packet;
216
217 ath6kl_dbg(ATH6KL_DBG_HTC,
218 "%s: queue: 0x%p, pkts %d\n", __func__,
219 pkt_queue, get_queue_depth(pkt_queue));
220
221 while (!list_empty(pkt_queue)) {
222 packet = list_first_entry(pkt_queue, struct htc_packet, list);
223 list_del(&packet->list);
224
225 skb = packet->skb;
226 if (!skb) {
227 WARN_ON_ONCE(1);
228 status = -EINVAL;
229 break;
230 }
231
232 payload_len = packet->act_len;
233
234 /* setup HTC frame header */
235 htc_hdr = (struct htc_frame_hdr *) skb_push(skb,
236 sizeof(*htc_hdr));
237 if (!htc_hdr) {
238 WARN_ON_ONCE(1);
239 status = -EINVAL;
240 break;
241 }
242
243 packet->info.tx.flags |= HTC_FLAGS_TX_FIXUP_NETBUF;
244
245 /* Endianess? */
246 put_unaligned((u16) payload_len, &htc_hdr->payld_len);
247 htc_hdr->flags = packet->info.tx.flags;
248 htc_hdr->eid = (u8) packet->endpoint;
249 htc_hdr->ctrl[0] = 0;
250 htc_hdr->ctrl[1] = (u8) packet->info.tx.seqno;
251
252 spin_lock_bh(&target->tx_lock);
253
254 /* store in look up queue to match completions */
255 list_add_tail(&packet->list, &ep->pipe.tx_lookup_queue);
256 ep->ep_st.tx_issued += 1;
257 spin_unlock_bh(&target->tx_lock);
258
259 status = ath6kl_hif_pipe_send(target->dev->ar,
260 ep->pipe.pipeid_ul, NULL, skb);
261
262 if (status != 0) {
263 if (status != -ENOMEM) {
264 /* TODO: if more than 1 endpoint maps to the
265 * same PipeID, it is possible to run out of
266 * resources in the HIF layer.
267 * Don't emit the error
268 */
269 ath6kl_dbg(ATH6KL_DBG_HTC,
270 "%s: failed status:%d\n",
271 __func__, status);
272 }
273 spin_lock_bh(&target->tx_lock);
274 list_del(&packet->list);
275
276 /* reclaim credits */
277 ep->cred_dist.credits += packet->info.tx.cred_used;
278 spin_unlock_bh(&target->tx_lock);
279
280 /* put it back into the callers queue */
281 list_add(&packet->list, pkt_queue);
282 break;
283 }
284
285 }
286
287 if (status != 0) {
288 while (!list_empty(pkt_queue)) {
289 if (status != -ENOMEM) {
290 ath6kl_dbg(ATH6KL_DBG_HTC,
291 "%s: failed pkt:0x%p status:%d\n",
292 __func__, packet, status);
293 }
294
295 packet = list_first_entry(pkt_queue,
296 struct htc_packet, list);
297 list_del(&packet->list);
298 packet->status = status;
299 send_packet_completion(target, packet);
300 }
301 }
302
303 return status;
304}
305
306static enum htc_send_queue_result htc_try_send(struct htc_target *target,
307 struct htc_endpoint *ep,
308 struct list_head *txq)
309{
310 struct list_head send_queue; /* temp queue to hold packets */
311 struct htc_packet *packet, *tmp_pkt;
312 struct ath6kl *ar = target->dev->ar;
313 enum htc_send_full_action action;
314 int tx_resources, overflow, txqueue_depth, i, good_pkts;
315 u8 pipeid;
316
317 ath6kl_dbg(ATH6KL_DBG_HTC, "%s: (queue:0x%p depth:%d)\n",
318 __func__, txq,
319 (txq == NULL) ? 0 : get_queue_depth(txq));
320
321 /* init the local send queue */
322 INIT_LIST_HEAD(&send_queue);
323
324 /*
325 * txq equals to NULL means
326 * caller didn't provide a queue, just wants us to
327 * check queues and send
328 */
329 if (txq != NULL) {
330 if (list_empty(txq)) {
331 /* empty queue */
332 return HTC_SEND_QUEUE_DROP;
333 }
334
335 spin_lock_bh(&target->tx_lock);
336 txqueue_depth = get_queue_depth(&ep->txq);
337 spin_unlock_bh(&target->tx_lock);
338
339 if (txqueue_depth >= ep->max_txq_depth) {
340 /* we've already overflowed */
341 overflow = get_queue_depth(txq);
342 } else {
343 /* get how much we will overflow by */
344 overflow = txqueue_depth;
345 overflow += get_queue_depth(txq);
346 /* get how much we will overflow the TX queue by */
347 overflow -= ep->max_txq_depth;
348 }
349
350 /* if overflow is negative or zero, we are okay */
351 if (overflow > 0) {
352 ath6kl_dbg(ATH6KL_DBG_HTC,
353 "%s: Endpoint %d, TX queue will overflow :%d, Tx Depth:%d, Max:%d\n",
354 __func__, ep->eid, overflow, txqueue_depth,
355 ep->max_txq_depth);
356 }
357 if ((overflow <= 0) ||
358 (ep->ep_cb.tx_full == NULL)) {
359 /*
360 * all packets will fit or caller did not provide send
361 * full indication handler -- just move all of them
362 * to the local send_queue object
363 */
364 list_splice_tail_init(txq, &send_queue);
365 } else {
366 good_pkts = get_queue_depth(txq) - overflow;
367 if (good_pkts < 0) {
368 WARN_ON_ONCE(1);
369 return HTC_SEND_QUEUE_DROP;
370 }
371
372 /* we have overflowed, and a callback is provided */
373 /* dequeue all non-overflow packets to the sendqueue */
374 for (i = 0; i < good_pkts; i++) {
375 /* pop off caller's queue */
376 packet = list_first_entry(txq,
377 struct htc_packet,
378 list);
379 list_del(&packet->list);
380 /* insert into local queue */
381 list_add_tail(&packet->list, &send_queue);
382 }
383
384 /*
385 * the caller's queue has all the packets that won't fit
386 * walk through the caller's queue and indicate each to
387 * the send full handler
388 */
389 list_for_each_entry_safe(packet, tmp_pkt,
390 txq, list) {
391
392 ath6kl_dbg(ATH6KL_DBG_HTC,
393 "%s: Indicat overflowed TX pkts: %p\n",
394 __func__, packet);
395 action = ep->ep_cb.tx_full(ep->target, packet);
396 if (action == HTC_SEND_FULL_DROP) {
397 /* callback wants the packet dropped */
398 ep->ep_st.tx_dropped += 1;
399
400 /* leave this one in the caller's queue
401 * for cleanup */
402 } else {
403 /* callback wants to keep this packet,
404 * remove from caller's queue */
405 list_del(&packet->list);
406 /* put it in the send queue */
407 list_add_tail(&packet->list,
408 &send_queue);
409 }
410
411 }
412
413 if (list_empty(&send_queue)) {
414 /* no packets made it in, caller will cleanup */
415 return HTC_SEND_QUEUE_DROP;
416 }
417 }
418 }
419
420 if (!ep->pipe.tx_credit_flow_enabled) {
421 tx_resources =
422 ath6kl_hif_pipe_get_free_queue_number(ar,
423 ep->pipe.pipeid_ul);
424 } else {
425 tx_resources = 0;
426 }
427
428 spin_lock_bh(&target->tx_lock);
429 if (!list_empty(&send_queue)) {
430 /* transfer packets to tail */
431 list_splice_tail_init(&send_queue, &ep->txq);
432 if (!list_empty(&send_queue)) {
433 WARN_ON_ONCE(1);
434 spin_unlock_bh(&target->tx_lock);
435 return HTC_SEND_QUEUE_DROP;
436 }
437 INIT_LIST_HEAD(&send_queue);
438 }
439
440 /* increment tx processing count on entry */
441 ep->tx_proc_cnt++;
442
443 if (ep->tx_proc_cnt > 1) {
444 /*
445 * Another thread or task is draining the TX queues on this
446 * endpoint that thread will reset the tx processing count
447 * when the queue is drained.
448 */
449 ep->tx_proc_cnt--;
450 spin_unlock_bh(&target->tx_lock);
451 return HTC_SEND_QUEUE_OK;
452 }
453
454 /***** beyond this point only 1 thread may enter ******/
455
456 /*
457 * Now drain the endpoint TX queue for transmission as long as we have
458 * enough transmit resources.
459 */
460 while (true) {
461
462 if (get_queue_depth(&ep->txq) == 0)
463 break;
464
465 if (ep->pipe.tx_credit_flow_enabled) {
466 /*
467 * Credit based mechanism provides flow control
468 * based on target transmit resource availability,
469 * we assume that the HIF layer will always have
470 * bus resources greater than target transmit
471 * resources.
472 */
473 get_htc_packet_credit_based(target, ep, &send_queue);
474 } else {
475 /*
476 * Get all packets for this endpoint that we can
477 * for this pass.
478 */
479 get_htc_packet(target, ep, &send_queue, tx_resources);
480 }
481
482 if (get_queue_depth(&send_queue) == 0) {
483 /*
484 * Didn't get packets due to out of resources or TX
485 * queue was drained.
486 */
487 break;
488 }
489
490 spin_unlock_bh(&target->tx_lock);
491
492 /* send what we can */
493 htc_issue_packets(target, ep, &send_queue);
494
495 if (!ep->pipe.tx_credit_flow_enabled) {
496 pipeid = ep->pipe.pipeid_ul;
497 tx_resources =
498 ath6kl_hif_pipe_get_free_queue_number(ar, pipeid);
499 }
500
501 spin_lock_bh(&target->tx_lock);
502
503 }
504 /* done with this endpoint, we can clear the count */
505 ep->tx_proc_cnt = 0;
506 spin_unlock_bh(&target->tx_lock);
507
508 return HTC_SEND_QUEUE_OK;
509}
510
511/* htc control packet manipulation */
512static void destroy_htc_txctrl_packet(struct htc_packet *packet)
513{
514 struct sk_buff *skb;
515 skb = packet->skb;
516 if (skb != NULL)
517 dev_kfree_skb(skb);
518
519 kfree(packet);
520}
521
522static struct htc_packet *build_htc_txctrl_packet(void)
523{
524 struct htc_packet *packet = NULL;
525 struct sk_buff *skb;
526
527 packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL);
528 if (packet == NULL)
529 return NULL;
530
531 skb = __dev_alloc_skb(HTC_CONTROL_BUFFER_SIZE, GFP_KERNEL);
532
533 if (skb == NULL) {
534 kfree(packet);
535 return NULL;
536 }
537 packet->skb = skb;
538
539 return packet;
540}
541
542static void htc_free_txctrl_packet(struct htc_target *target,
543 struct htc_packet *packet)
544{
545 destroy_htc_txctrl_packet(packet);
546}
547
548static struct htc_packet *htc_alloc_txctrl_packet(struct htc_target *target)
549{
550 return build_htc_txctrl_packet();
551}
552
553static void htc_txctrl_complete(struct htc_target *target,
554 struct htc_packet *packet)
555{
556 htc_free_txctrl_packet(target, packet);
557}
558
559#define MAX_MESSAGE_SIZE 1536
560
561static int htc_setup_target_buffer_assignments(struct htc_target *target)
562{
563 int status, credits, credit_per_maxmsg, i;
564 struct htc_pipe_txcredit_alloc *entry;
565 unsigned int hif_usbaudioclass = 0;
566
567 credit_per_maxmsg = MAX_MESSAGE_SIZE / target->tgt_cred_sz;
568 if (MAX_MESSAGE_SIZE % target->tgt_cred_sz)
569 credit_per_maxmsg++;
570
571 /* TODO, this should be configured by the caller! */
572
573 credits = target->tgt_creds;
574 entry = &target->pipe.txcredit_alloc[0];
575
576 status = -ENOMEM;
577
578 /* FIXME: hif_usbaudioclass is always zero */
579 if (hif_usbaudioclass) {
580 ath6kl_dbg(ATH6KL_DBG_HTC,
581 "%s: For USB Audio Class- Total:%d\n",
582 __func__, credits);
583 entry++;
584 entry++;
585 /* Setup VO Service To have Max Credits */
586 entry->service_id = WMI_DATA_VO_SVC;
587 entry->credit_alloc = (credits - 6);
588 if (entry->credit_alloc == 0)
589 entry->credit_alloc++;
590
591 credits -= (int) entry->credit_alloc;
592 if (credits <= 0)
593 return status;
594
595 entry++;
596 entry->service_id = WMI_CONTROL_SVC;
597 entry->credit_alloc = credit_per_maxmsg;
598 credits -= (int) entry->credit_alloc;
599 if (credits <= 0)
600 return status;
601
602 /* leftovers go to best effort */
603 entry++;
604 entry++;
605 entry->service_id = WMI_DATA_BE_SVC;
606 entry->credit_alloc = (u8) credits;
607 status = 0;
608 } else {
609 entry++;
610 entry->service_id = WMI_DATA_VI_SVC;
611 entry->credit_alloc = credits / 4;
612 if (entry->credit_alloc == 0)
613 entry->credit_alloc++;
614
615 credits -= (int) entry->credit_alloc;
616 if (credits <= 0)
617 return status;
618
619 entry++;
620 entry->service_id = WMI_DATA_VO_SVC;
621 entry->credit_alloc = credits / 4;
622 if (entry->credit_alloc == 0)
623 entry->credit_alloc++;
624
625 credits -= (int) entry->credit_alloc;
626 if (credits <= 0)
627 return status;
628
629 entry++;
630 entry->service_id = WMI_CONTROL_SVC;
631 entry->credit_alloc = credit_per_maxmsg;
632 credits -= (int) entry->credit_alloc;
633 if (credits <= 0)
634 return status;
635
636 entry++;
637 entry->service_id = WMI_DATA_BK_SVC;
638 entry->credit_alloc = credit_per_maxmsg;
639 credits -= (int) entry->credit_alloc;
640 if (credits <= 0)
641 return status;
642
643 /* leftovers go to best effort */
644 entry++;
645 entry->service_id = WMI_DATA_BE_SVC;
646 entry->credit_alloc = (u8) credits;
647 status = 0;
648 }
649
650 if (status == 0) {
651 for (i = 0; i < ENDPOINT_MAX; i++) {
652 if (target->pipe.txcredit_alloc[i].service_id != 0) {
653 ath6kl_dbg(ATH6KL_DBG_HTC,
654 "HTC Service Index : %d TX : 0x%2.2X : alloc:%d\n",
655 i,
656 target->pipe.txcredit_alloc[i].
657 service_id,
658 target->pipe.txcredit_alloc[i].
659 credit_alloc);
660 }
661 }
662 }
663 return status;
664}
665
666/* process credit reports and call distribution function */
667static void htc_process_credit_report(struct htc_target *target,
668 struct htc_credit_report *rpt,
669 int num_entries,
670 enum htc_endpoint_id from_ep)
671{
672 int total_credits = 0, i;
673 struct htc_endpoint *ep;
674
675 /* lock out TX while we update credits */
676 spin_lock_bh(&target->tx_lock);
677
678 for (i = 0; i < num_entries; i++, rpt++) {
679 if (rpt->eid >= ENDPOINT_MAX) {
680 WARN_ON_ONCE(1);
681 spin_unlock_bh(&target->tx_lock);
682 return;
683 }
684
685 ep = &target->endpoint[rpt->eid];
686 ep->cred_dist.credits += rpt->credits;
687
688 if (ep->cred_dist.credits && get_queue_depth(&ep->txq)) {
689 spin_unlock_bh(&target->tx_lock);
690 htc_try_send(target, ep, NULL);
691 spin_lock_bh(&target->tx_lock);
692 }
693
694 total_credits += rpt->credits;
695 }
696 ath6kl_dbg(ATH6KL_DBG_HTC,
697 "Report indicated %d credits to distribute\n",
698 total_credits);
699
700 spin_unlock_bh(&target->tx_lock);
701}
702
703/* flush endpoint TX queue */
704static void htc_flush_tx_endpoint(struct htc_target *target,
705 struct htc_endpoint *ep, u16 tag)
706{
707 struct htc_packet *packet;
708
709 spin_lock_bh(&target->tx_lock);
710 while (get_queue_depth(&ep->txq)) {
711 packet = list_first_entry(&ep->txq, struct htc_packet, list);
712 list_del(&packet->list);
713 packet->status = 0;
714 send_packet_completion(target, packet);
715 }
716 spin_unlock_bh(&target->tx_lock);
717}
718
719/*
720 * In the adapted HIF layer, struct sk_buff * are passed between HIF and HTC,
721 * since upper layers expects struct htc_packet containers we use the completed
722 * skb and lookup it's corresponding HTC packet buffer from a lookup list.
723 * This is extra overhead that can be fixed by re-aligning HIF interfaces with
724 * HTC.
725 */
726static struct htc_packet *htc_lookup_tx_packet(struct htc_target *target,
727 struct htc_endpoint *ep,
728 struct sk_buff *skb)
729{
730 struct htc_packet *packet, *tmp_pkt, *found_packet = NULL;
731
732 spin_lock_bh(&target->tx_lock);
733
734 /*
735 * interate from the front of tx lookup queue
736 * this lookup should be fast since lower layers completes in-order and
737 * so the completed packet should be at the head of the list generally
738 */
739 list_for_each_entry_safe(packet, tmp_pkt, &ep->pipe.tx_lookup_queue,
740 list) {
741 /* check for removal */
742 if (skb == packet->skb) {
743 /* found it */
744 list_del(&packet->list);
745 found_packet = packet;
746 break;
747 }
748 }
749
750 spin_unlock_bh(&target->tx_lock);
751
752 return found_packet;
753}
754
755static int ath6kl_htc_pipe_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
756{
757 struct htc_target *target = ar->htc_target;
758 struct htc_frame_hdr *htc_hdr;
759 struct htc_endpoint *ep;
760 struct htc_packet *packet;
761 u8 ep_id, *netdata;
762 u32 netlen;
763
764 netdata = skb->data;
765 netlen = skb->len;
766
767 htc_hdr = (struct htc_frame_hdr *) netdata;
768
769 ep_id = htc_hdr->eid;
770 ep = &target->endpoint[ep_id];
771
772 packet = htc_lookup_tx_packet(target, ep, skb);
773 if (packet == NULL) {
774 /* may have already been flushed and freed */
775 ath6kl_err("HTC TX lookup failed!\n");
776 } else {
777 /* will be giving this buffer back to upper layers */
778 packet->status = 0;
779 send_packet_completion(target, packet);
780 }
781 skb = NULL;
782
783 if (!ep->pipe.tx_credit_flow_enabled) {
784 /*
785 * note: when using TX credit flow, the re-checking of queues
786 * happens when credits flow back from the target. in the
787 * non-TX credit case, we recheck after the packet completes
788 */
789 htc_try_send(target, ep, NULL);
790 }
791
792 return 0;
793}
794
795static int htc_send_packets_multiple(struct htc_target *target,
796 struct list_head *pkt_queue)
797{
798 struct htc_endpoint *ep;
799 struct htc_packet *packet, *tmp_pkt;
800
801 if (list_empty(pkt_queue))
802 return -EINVAL;
803
804 /* get first packet to find out which ep the packets will go into */
805 packet = list_first_entry(pkt_queue, struct htc_packet, list);
806 if (packet == NULL)
807 return -EINVAL;
808
809 if (packet->endpoint >= ENDPOINT_MAX) {
810 WARN_ON_ONCE(1);
811 return -EINVAL;
812 }
813 ep = &target->endpoint[packet->endpoint];
814
815 htc_try_send(target, ep, pkt_queue);
816
817 /* do completion on any packets that couldn't get in */
818 if (!list_empty(pkt_queue)) {
819 list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
820 packet->status = -ENOMEM;
821 }
822
823 do_send_completion(ep, pkt_queue);
824 }
825
826 return 0;
827}
828
829/* htc pipe rx path */
830static struct htc_packet *alloc_htc_packet_container(struct htc_target *target)
831{
832 struct htc_packet *packet;
833 spin_lock_bh(&target->rx_lock);
834
835 if (target->pipe.htc_packet_pool == NULL) {
836 spin_unlock_bh(&target->rx_lock);
837 return NULL;
838 }
839
840 packet = target->pipe.htc_packet_pool;
841 target->pipe.htc_packet_pool = (struct htc_packet *) packet->list.next;
842
843 spin_unlock_bh(&target->rx_lock);
844
845 packet->list.next = NULL;
846 return packet;
847}
848
849static void free_htc_packet_container(struct htc_target *target,
850 struct htc_packet *packet)
851{
852 struct list_head *lh;
853
854 spin_lock_bh(&target->rx_lock);
855
856 if (target->pipe.htc_packet_pool == NULL) {
857 target->pipe.htc_packet_pool = packet;
858 packet->list.next = NULL;
859 } else {
860 lh = (struct list_head *) target->pipe.htc_packet_pool;
861 packet->list.next = lh;
862 target->pipe.htc_packet_pool = packet;
863 }
864
865 spin_unlock_bh(&target->rx_lock);
866}
867
868static int htc_process_trailer(struct htc_target *target, u8 *buffer,
869 int len, enum htc_endpoint_id from_ep)
870{
871 struct htc_credit_report *report;
872 struct htc_record_hdr *record;
873 u8 *record_buf, *orig_buf;
874 int orig_len, status;
875
876 orig_buf = buffer;
877 orig_len = len;
878 status = 0;
879
880 while (len > 0) {
881 if (len < sizeof(struct htc_record_hdr)) {
882 status = -EINVAL;
883 break;
884 }
885
886 /* these are byte aligned structs */
887 record = (struct htc_record_hdr *) buffer;
888 len -= sizeof(struct htc_record_hdr);
889 buffer += sizeof(struct htc_record_hdr);
890
891 if (record->len > len) {
892 /* no room left in buffer for record */
893 ath6kl_dbg(ATH6KL_DBG_HTC,
894 "invalid length: %d (id:%d) buffer has: %d bytes left\n",
895 record->len, record->rec_id, len);
896 status = -EINVAL;
897 break;
898 }
899
900 /* start of record follows the header */
901 record_buf = buffer;
902
903 switch (record->rec_id) {
904 case HTC_RECORD_CREDITS:
905 if (record->len < sizeof(struct htc_credit_report)) {
906 WARN_ON_ONCE(1);
907 return -EINVAL;
908 }
909
910 report = (struct htc_credit_report *) record_buf;
911 htc_process_credit_report(target, report,
912 record->len / sizeof(*report),
913 from_ep);
914 break;
915 default:
916 ath6kl_dbg(ATH6KL_DBG_HTC,
917 "unhandled record: id:%d length:%d\n",
918 record->rec_id, record->len);
919 break;
920 }
921
922 if (status != 0)
923 break;
924
925 /* advance buffer past this record for next time around */
926 buffer += record->len;
927 len -= record->len;
928 }
929
930 return status;
931}
932
933static void do_recv_completion(struct htc_endpoint *ep,
934 struct list_head *queue_to_indicate)
935{
936 struct htc_packet *packet;
937
938 if (list_empty(queue_to_indicate)) {
939 /* nothing to indicate */
940 return;
941 }
942
943 /* using legacy EpRecv */
944 while (!list_empty(queue_to_indicate)) {
945 packet = list_first_entry(queue_to_indicate,
946 struct htc_packet, list);
947 list_del(&packet->list);
948 ep->ep_cb.rx(ep->target, packet);
949 }
950
951 return;
952}
953
954static void recv_packet_completion(struct htc_target *target,
955 struct htc_endpoint *ep,
956 struct htc_packet *packet)
957{
958 struct list_head container;
959 INIT_LIST_HEAD(&container);
960 list_add_tail(&packet->list, &container);
961
962 /* do completion */
963 do_recv_completion(ep, &container);
964}
965
966static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
967 u8 pipeid)
968{
969 struct htc_target *target = ar->htc_target;
970 u8 *netdata, *trailer, hdr_info;
971 struct htc_frame_hdr *htc_hdr;
972 u32 netlen, trailerlen = 0;
973 struct htc_packet *packet;
974 struct htc_endpoint *ep;
975 u16 payload_len;
976 int status = 0;
977
978 netdata = skb->data;
979 netlen = skb->len;
980
981 htc_hdr = (struct htc_frame_hdr *) netdata;
982
983 ep = &target->endpoint[htc_hdr->eid];
984
985 if (htc_hdr->eid >= ENDPOINT_MAX) {
986 ath6kl_dbg(ATH6KL_DBG_HTC,
987 "HTC Rx: invalid EndpointID=%d\n",
988 htc_hdr->eid);
989 status = -EINVAL;
990 goto free_skb;
991 }
992
993 payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
994
995 if (netlen < (payload_len + HTC_HDR_LENGTH)) {
996 ath6kl_dbg(ATH6KL_DBG_HTC,
997 "HTC Rx: insufficient length, got:%d expected =%u\n",
998 netlen, payload_len + HTC_HDR_LENGTH);
999 status = -EINVAL;
1000 goto free_skb;
1001 }
1002
1003 /* get flags to check for trailer */
1004 hdr_info = htc_hdr->flags;
1005 if (hdr_info & HTC_FLG_RX_TRAILER) {
1006 /* extract the trailer length */
1007 hdr_info = htc_hdr->ctrl[0];
1008 if ((hdr_info < sizeof(struct htc_record_hdr)) ||
1009 (hdr_info > payload_len)) {
1010 ath6kl_dbg(ATH6KL_DBG_HTC,
1011 "invalid header: payloadlen should be %d, CB[0]: %d\n",
1012 payload_len, hdr_info);
1013 status = -EINVAL;
1014 goto free_skb;
1015 }
1016
1017 trailerlen = hdr_info;
1018 /* process trailer after hdr/apps payload */
1019 trailer = (u8 *) htc_hdr + HTC_HDR_LENGTH +
1020 payload_len - hdr_info;
1021 status = htc_process_trailer(target, trailer, hdr_info,
1022 htc_hdr->eid);
1023 if (status != 0)
1024 goto free_skb;
1025 }
1026
1027 if (((int) payload_len - (int) trailerlen) <= 0) {
1028 /* zero length packet with trailer, just drop these */
1029 goto free_skb;
1030 }
1031
1032 if (htc_hdr->eid == ENDPOINT_0) {
1033 /* handle HTC control message */
1034 if (target->htc_flags & HTC_OP_STATE_SETUP_COMPLETE) {
1035 /*
1036 * fatal: target should not send unsolicited
1037 * messageson the endpoint 0
1038 */
1039 ath6kl_dbg(ATH6KL_DBG_HTC,
1040 "HTC ignores Rx Ctrl after setup complete\n");
1041 status = -EINVAL;
1042 goto free_skb;
1043 }
1044
1045 /* remove HTC header */
1046 skb_pull(skb, HTC_HDR_LENGTH);
1047
1048 netdata = skb->data;
1049 netlen = skb->len;
1050
1051 spin_lock_bh(&target->rx_lock);
1052
1053 target->pipe.ctrl_response_valid = true;
1054 target->pipe.ctrl_response_len = min_t(int, netlen,
1055 HTC_MAX_CTRL_MSG_LEN);
1056 memcpy(target->pipe.ctrl_response_buf, netdata,
1057 target->pipe.ctrl_response_len);
1058
1059 spin_unlock_bh(&target->rx_lock);
1060
1061 dev_kfree_skb(skb);
1062 skb = NULL;
1063 goto free_skb;
1064 }
1065
1066 /*
1067 * TODO: the message based HIF architecture allocates net bufs
1068 * for recv packets since it bridges that HIF to upper layers,
1069 * which expects HTC packets, we form the packets here
1070 */
1071 packet = alloc_htc_packet_container(target);
1072 if (packet == NULL) {
1073 status = -ENOMEM;
1074 goto free_skb;
1075 }
1076
1077 packet->status = 0;
1078 packet->endpoint = htc_hdr->eid;
1079 packet->pkt_cntxt = skb;
1080
1081 /* TODO: for backwards compatibility */
1082 packet->buf = skb_push(skb, 0) + HTC_HDR_LENGTH;
1083 packet->act_len = netlen - HTC_HDR_LENGTH - trailerlen;
1084
1085 /*
1086 * TODO: this is a hack because the driver layer will set the
1087 * actual len of the skb again which will just double the len
1088 */
1089 skb_trim(skb, 0);
1090
1091 recv_packet_completion(target, ep, packet);
1092
1093 /* recover the packet container */
1094 free_htc_packet_container(target, packet);
1095 skb = NULL;
1096
1097free_skb:
1098 if (skb != NULL)
1099 dev_kfree_skb(skb);
1100
1101 return status;
1102
1103}
1104
1105static void htc_flush_rx_queue(struct htc_target *target,
1106 struct htc_endpoint *ep)
1107{
1108 struct list_head container;
1109 struct htc_packet *packet;
1110
1111 spin_lock_bh(&target->rx_lock);
1112
1113 while (1) {
1114 if (list_empty(&ep->rx_bufq))
1115 break;
1116
1117 packet = list_first_entry(&ep->rx_bufq,
1118 struct htc_packet, list);
1119 list_del(&packet->list);
1120
1121 spin_unlock_bh(&target->rx_lock);
1122 packet->status = -ECANCELED;
1123 packet->act_len = 0;
1124
1125 ath6kl_dbg(ATH6KL_DBG_HTC,
1126 "Flushing RX packet:0x%p, length:%d, ep:%d\n",
1127 packet, packet->buf_len,
1128 packet->endpoint);
1129
1130 INIT_LIST_HEAD(&container);
1131 list_add_tail(&packet->list, &container);
1132
1133 /* give the packet back */
1134 do_recv_completion(ep, &container);
1135 spin_lock_bh(&target->rx_lock);
1136 }
1137
1138 spin_unlock_bh(&target->rx_lock);
1139}
1140
1141/* polling routine to wait for a control packet to be received */
1142static int htc_wait_recv_ctrl_message(struct htc_target *target)
1143{
1144 int count = HTC_TARGET_RESPONSE_POLL_COUNT;
1145
1146 while (count > 0) {
1147 spin_lock_bh(&target->rx_lock);
1148
1149 if (target->pipe.ctrl_response_valid) {
1150 target->pipe.ctrl_response_valid = false;
1151 spin_unlock_bh(&target->rx_lock);
1152 break;
1153 }
1154
1155 spin_unlock_bh(&target->rx_lock);
1156
1157 count--;
1158
1159 msleep_interruptible(HTC_TARGET_RESPONSE_POLL_WAIT);
1160 }
1161
1162 if (count <= 0) {
1163 ath6kl_dbg(ATH6KL_DBG_HTC, "%s: Timeout!\n", __func__);
1164 return -ECOMM;
1165 }
1166
1167 return 0;
1168}
1169
1170static void htc_rxctrl_complete(struct htc_target *context,
1171 struct htc_packet *packet)
1172{
1173 /* TODO, can't really receive HTC control messages yet.... */
1174 ath6kl_dbg(ATH6KL_DBG_HTC, "%s: invalid call function\n", __func__);
1175}
1176
1177/* htc pipe initialization */
1178static void reset_endpoint_states(struct htc_target *target)
1179{
1180 struct htc_endpoint *ep;
1181 int i;
1182
1183 for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1184 ep = &target->endpoint[i];
1185 ep->svc_id = 0;
1186 ep->len_max = 0;
1187 ep->max_txq_depth = 0;
1188 ep->eid = i;
1189 INIT_LIST_HEAD(&ep->txq);
1190 INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
1191 INIT_LIST_HEAD(&ep->rx_bufq);
1192 ep->target = target;
1193 ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */
1194 }
1195}
1196
1197/* start HTC, this is called after all services are connected */
1198static int htc_config_target_hif_pipe(struct htc_target *target)
1199{
1200 return 0;
1201}
1202
1203/* htc service functions */
1204static u8 htc_get_credit_alloc(struct htc_target *target, u16 service_id)
1205{
1206 u8 allocation = 0;
1207 int i;
1208
1209 for (i = 0; i < ENDPOINT_MAX; i++) {
1210 if (target->pipe.txcredit_alloc[i].service_id == service_id)
1211 allocation =
1212 target->pipe.txcredit_alloc[i].credit_alloc;
1213 }
1214
1215 if (allocation == 0) {
1216 ath6kl_dbg(ATH6KL_DBG_HTC,
1217 "HTC Service TX : 0x%2.2X : allocation is zero!\n",
1218 service_id);
1219 }
1220
1221 return allocation;
1222}
1223
1224static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
1225 struct htc_service_connect_req *conn_req,
1226 struct htc_service_connect_resp *conn_resp)
1227{
1228 struct ath6kl *ar = target->dev->ar;
1229 struct htc_packet *packet = NULL;
1230 struct htc_conn_service_resp *resp_msg;
1231 struct htc_conn_service_msg *conn_msg;
1232 enum htc_endpoint_id assigned_epid = ENDPOINT_MAX;
1233 bool disable_credit_flowctrl = false;
1234 unsigned int max_msg_size = 0;
1235 struct htc_endpoint *ep;
1236 int length, status = 0;
1237 struct sk_buff *skb;
1238 u8 tx_alloc;
1239 u16 flags;
1240
1241 if (conn_req->svc_id == 0) {
1242 WARN_ON_ONCE(1);
1243 status = -EINVAL;
1244 goto free_packet;
1245 }
1246
1247 if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) {
1248 /* special case for pseudo control service */
1249 assigned_epid = ENDPOINT_0;
1250 max_msg_size = HTC_MAX_CTRL_MSG_LEN;
1251 tx_alloc = 0;
1252
1253 } else {
1254
1255 tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id);
1256 if (tx_alloc == 0) {
1257 status = -ENOMEM;
1258 goto free_packet;
1259 }
1260
1261 /* allocate a packet to send to the target */
1262 packet = htc_alloc_txctrl_packet(target);
1263
1264 if (packet == NULL) {
1265 WARN_ON_ONCE(1);
1266 status = -ENOMEM;
1267 goto free_packet;
1268 }
1269
1270 skb = packet->skb;
1271 length = sizeof(struct htc_conn_service_msg);
1272
1273 /* assemble connect service message */
1274 conn_msg = (struct htc_conn_service_msg *) skb_put(skb,
1275 length);
1276 if (conn_msg == NULL) {
1277 WARN_ON_ONCE(1);
1278 status = -EINVAL;
1279 goto free_packet;
1280 }
1281
1282 memset(conn_msg, 0,
1283 sizeof(struct htc_conn_service_msg));
1284 conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID);
1285 conn_msg->svc_id = cpu_to_le16(conn_req->svc_id);
1286 conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags &
1287 ~HTC_CONN_FLGS_SET_RECV_ALLOC_MASK);
1288
1289 /* tell target desired recv alloc for this ep */
1290 flags = tx_alloc << HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT;
1291 conn_msg->conn_flags |= cpu_to_le16(flags);
1292
1293 if (conn_req->conn_flags &
1294 HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL) {
1295 disable_credit_flowctrl = true;
1296 }
1297
1298 set_htc_pkt_info(packet, NULL, (u8 *) conn_msg,
1299 length,
1300 ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
1301
1302 status = ath6kl_htc_pipe_tx(target, packet);
1303
1304 /* we don't own it anymore */
1305 packet = NULL;
1306 if (status != 0)
1307 goto free_packet;
1308
1309 /* wait for response */
1310 status = htc_wait_recv_ctrl_message(target);
1311 if (status != 0)
1312 goto free_packet;
1313
1314 /* we controlled the buffer creation so it has to be
1315 * properly aligned
1316 */
1317 resp_msg = (struct htc_conn_service_resp *)
1318 target->pipe.ctrl_response_buf;
1319
1320 if (resp_msg->msg_id != cpu_to_le16(HTC_MSG_CONN_SVC_RESP_ID) ||
1321 (target->pipe.ctrl_response_len < sizeof(*resp_msg))) {
1322 /* this message is not valid */
1323 WARN_ON_ONCE(1);
1324 status = -EINVAL;
1325 goto free_packet;
1326 }
1327
1328 ath6kl_dbg(ATH6KL_DBG_TRC,
1329 "%s: service 0x%X conn resp: status: %d ep: %d\n",
1330 __func__, resp_msg->svc_id, resp_msg->status,
1331 resp_msg->eid);
1332
1333 conn_resp->resp_code = resp_msg->status;
1334 /* check response status */
1335 if (resp_msg->status != HTC_SERVICE_SUCCESS) {
1336 ath6kl_dbg(ATH6KL_DBG_HTC,
1337 "Target failed service 0x%X connect request (status:%d)\n",
1338 resp_msg->svc_id, resp_msg->status);
1339 status = -EINVAL;
1340 goto free_packet;
1341 }
1342
1343 assigned_epid = (enum htc_endpoint_id) resp_msg->eid;
1344 max_msg_size = le16_to_cpu(resp_msg->max_msg_sz);
1345 }
1346
1347 /* the rest are parameter checks so set the error status */
1348 status = -EINVAL;
1349
1350 if (assigned_epid >= ENDPOINT_MAX) {
1351 WARN_ON_ONCE(1);
1352 goto free_packet;
1353 }
1354
1355 if (max_msg_size == 0) {
1356 WARN_ON_ONCE(1);
1357 goto free_packet;
1358 }
1359
1360 ep = &target->endpoint[assigned_epid];
1361 ep->eid = assigned_epid;
1362 if (ep->svc_id != 0) {
1363 /* endpoint already in use! */
1364 WARN_ON_ONCE(1);
1365 goto free_packet;
1366 }
1367
1368 /* return assigned endpoint to caller */
1369 conn_resp->endpoint = assigned_epid;
1370 conn_resp->len_max = max_msg_size;
1371
1372 /* setup the endpoint */
1373 ep->svc_id = conn_req->svc_id; /* this marks ep in use */
1374 ep->max_txq_depth = conn_req->max_txq_depth;
1375 ep->len_max = max_msg_size;
1376 ep->cred_dist.credits = tx_alloc;
1377 ep->cred_dist.cred_sz = target->tgt_cred_sz;
1378 ep->cred_dist.cred_per_msg = max_msg_size / target->tgt_cred_sz;
1379 if (max_msg_size % target->tgt_cred_sz)
1380 ep->cred_dist.cred_per_msg++;
1381
1382 /* copy all the callbacks */
1383 ep->ep_cb = conn_req->ep_cb;
1384
1385 status = ath6kl_hif_pipe_map_service(ar, ep->svc_id,
1386 &ep->pipe.pipeid_ul,
1387 &ep->pipe.pipeid_dl);
1388 if (status != 0)
1389 goto free_packet;
1390
1391 ath6kl_dbg(ATH6KL_DBG_HTC,
1392 "SVC Ready: 0x%4.4X: ULpipe:%d DLpipe:%d id:%d\n",
1393 ep->svc_id, ep->pipe.pipeid_ul,
1394 ep->pipe.pipeid_dl, ep->eid);
1395
1396 if (disable_credit_flowctrl && ep->pipe.tx_credit_flow_enabled) {
1397 ep->pipe.tx_credit_flow_enabled = false;
1398 ath6kl_dbg(ATH6KL_DBG_HTC,
1399 "SVC: 0x%4.4X ep:%d TX flow control off\n",
1400 ep->svc_id, assigned_epid);
1401 }
1402
1403free_packet:
1404 if (packet != NULL)
1405 htc_free_txctrl_packet(target, packet);
1406 return status;
1407}
1408
1409/* htc export functions */
1410static void *ath6kl_htc_pipe_create(struct ath6kl *ar)
1411{
1412 int status = 0;
1413 struct htc_endpoint *ep = NULL;
1414 struct htc_target *target = NULL;
1415 struct htc_packet *packet;
1416 int i;
1417
1418 target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
1419 if (target == NULL) {
1420 ath6kl_err("htc create unable to allocate memory\n");
1421 status = -ENOMEM;
1422 goto fail_htc_create;
1423 }
1424
1425 spin_lock_init(&target->htc_lock);
1426 spin_lock_init(&target->rx_lock);
1427 spin_lock_init(&target->tx_lock);
1428
1429 reset_endpoint_states(target);
1430
1431 for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) {
1432 packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL);
1433
1434 if (packet != NULL)
1435 free_htc_packet_container(target, packet);
1436 }
1437
1438 target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL);
1439 if (!target->dev) {
1440 ath6kl_err("unable to allocate memory\n");
1441 status = -ENOMEM;
1442 goto fail_htc_create;
1443 }
1444 target->dev->ar = ar;
1445 target->dev->htc_cnxt = target;
1446
1447 /* Get HIF default pipe for HTC message exchange */
1448 ep = &target->endpoint[ENDPOINT_0];
1449
1450 ath6kl_hif_pipe_get_default(ar, &ep->pipe.pipeid_ul,
1451 &ep->pipe.pipeid_dl);
1452
1453 return target;
1454
1455fail_htc_create:
1456 if (status != 0) {
1457 if (target != NULL)
1458 ath6kl_htc_pipe_cleanup(target);
1459
1460 target = NULL;
1461 }
1462 return target;
1463}
1464
1465/* cleanup the HTC instance */
1466static void ath6kl_htc_pipe_cleanup(struct htc_target *target)
1467{
1468 struct htc_packet *packet;
1469
1470 while (true) {
1471 packet = alloc_htc_packet_container(target);
1472 if (packet == NULL)
1473 break;
1474 kfree(packet);
1475 }
1476
1477 kfree(target->dev);
1478
1479 /* kfree our instance */
1480 kfree(target);
1481}
1482
1483static int ath6kl_htc_pipe_start(struct htc_target *target)
1484{
1485 struct sk_buff *skb;
1486 struct htc_setup_comp_ext_msg *setup;
1487 struct htc_packet *packet;
1488
1489 htc_config_target_hif_pipe(target);
1490
1491 /* allocate a buffer to send */
1492 packet = htc_alloc_txctrl_packet(target);
1493 if (packet == NULL) {
1494 WARN_ON_ONCE(1);
1495 return -ENOMEM;
1496 }
1497
1498 skb = packet->skb;
1499
1500 /* assemble setup complete message */
1501 setup = (struct htc_setup_comp_ext_msg *) skb_put(skb,
1502 sizeof(*setup));
1503 memset(setup, 0, sizeof(struct htc_setup_comp_ext_msg));
1504 setup->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID);
1505
1506 ath6kl_dbg(ATH6KL_DBG_HTC, "HTC using TX credit flow control\n");
1507
1508 set_htc_pkt_info(packet, NULL, (u8 *) setup,
1509 sizeof(struct htc_setup_comp_ext_msg),
1510 ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
1511
1512 target->htc_flags |= HTC_OP_STATE_SETUP_COMPLETE;
1513
1514 return ath6kl_htc_pipe_tx(target, packet);
1515}
1516
1517static void ath6kl_htc_pipe_stop(struct htc_target *target)
1518{
1519 int i;
1520 struct htc_endpoint *ep;
1521
1522 /* cleanup endpoints */
1523 for (i = 0; i < ENDPOINT_MAX; i++) {
1524 ep = &target->endpoint[i];
1525 htc_flush_rx_queue(target, ep);
1526 htc_flush_tx_endpoint(target, ep, HTC_TX_PACKET_TAG_ALL);
1527 }
1528
1529 reset_endpoint_states(target);
1530 target->htc_flags &= ~HTC_OP_STATE_SETUP_COMPLETE;
1531}
1532
1533static int ath6kl_htc_pipe_get_rxbuf_num(struct htc_target *target,
1534 enum htc_endpoint_id endpoint)
1535{
1536 int num;
1537
1538 spin_lock_bh(&target->rx_lock);
1539 num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq));
1540 spin_unlock_bh(&target->rx_lock);
1541
1542 return num;
1543}
1544
1545static int ath6kl_htc_pipe_tx(struct htc_target *target,
1546 struct htc_packet *packet)
1547{
1548 struct list_head queue;
1549
1550 ath6kl_dbg(ATH6KL_DBG_HTC,
1551 "%s: endPointId: %d, buffer: 0x%p, length: %d\n",
1552 __func__, packet->endpoint, packet->buf,
1553 packet->act_len);
1554
1555 INIT_LIST_HEAD(&queue);
1556 list_add_tail(&packet->list, &queue);
1557
1558 return htc_send_packets_multiple(target, &queue);
1559}
1560
1561static int ath6kl_htc_pipe_wait_target(struct htc_target *target)
1562{
1563 struct htc_ready_ext_msg *ready_msg;
1564 struct htc_service_connect_req connect;
1565 struct htc_service_connect_resp resp;
1566 int status = 0;
1567
1568 status = htc_wait_recv_ctrl_message(target);
1569
1570 if (status != 0)
1571 return status;
1572
1573 if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) {
1574 ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg len:%d!\n",
1575 target->pipe.ctrl_response_len);
1576 return -ECOMM;
1577 }
1578
1579 ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf;
1580
1581 if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) {
1582 ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg : 0x%X !\n",
1583 ready_msg->ver2_0_info.msg_id);
1584 return -ECOMM;
1585 }
1586
1587 ath6kl_dbg(ATH6KL_DBG_HTC,
1588 "Target Ready! : transmit resources : %d size:%d\n",
1589 ready_msg->ver2_0_info.cred_cnt,
1590 ready_msg->ver2_0_info.cred_sz);
1591
1592 target->tgt_creds = le16_to_cpu(ready_msg->ver2_0_info.cred_cnt);
1593 target->tgt_cred_sz = le16_to_cpu(ready_msg->ver2_0_info.cred_sz);
1594
1595 if ((target->tgt_creds == 0) || (target->tgt_cred_sz == 0))
1596 return -ECOMM;
1597
1598 htc_setup_target_buffer_assignments(target);
1599
1600 /* setup our pseudo HTC control endpoint connection */
1601 memset(&connect, 0, sizeof(connect));
1602 memset(&resp, 0, sizeof(resp));
1603 connect.ep_cb.tx_complete = htc_txctrl_complete;
1604 connect.ep_cb.rx = htc_rxctrl_complete;
1605 connect.max_txq_depth = NUM_CONTROL_TX_BUFFERS;
1606 connect.svc_id = HTC_CTRL_RSVD_SVC;
1607
1608 /* connect fake service */
1609 status = ath6kl_htc_pipe_conn_service(target, &connect, &resp);
1610
1611 return status;
1612}
1613
1614static void ath6kl_htc_pipe_flush_txep(struct htc_target *target,
1615 enum htc_endpoint_id endpoint, u16 tag)
1616{
1617 struct htc_endpoint *ep = &target->endpoint[endpoint];
1618
1619 if (ep->svc_id == 0) {
1620 WARN_ON_ONCE(1);
1621 /* not in use.. */
1622 return;
1623 }
1624
1625 htc_flush_tx_endpoint(target, ep, tag);
1626}
1627
1628static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target,
1629 struct list_head *pkt_queue)
1630{
1631 struct htc_packet *packet, *tmp_pkt, *first;
1632 struct htc_endpoint *ep;
1633 int status = 0;
1634
1635 if (list_empty(pkt_queue))
1636 return -EINVAL;
1637
1638 first = list_first_entry(pkt_queue, struct htc_packet, list);
1639 if (first == NULL) {
1640 WARN_ON_ONCE(1);
1641 return -EINVAL;
1642 }
1643
1644 if (first->endpoint >= ENDPOINT_MAX) {
1645 WARN_ON_ONCE(1);
1646 return -EINVAL;
1647 }
1648
1649 ath6kl_dbg(ATH6KL_DBG_HTC, "%s: epid: %d, cnt:%d, len: %d\n",
1650 __func__, first->endpoint, get_queue_depth(pkt_queue),
1651 first->buf_len);
1652
1653 ep = &target->endpoint[first->endpoint];
1654
1655 spin_lock_bh(&target->rx_lock);
1656
1657 /* store receive packets */
1658 list_splice_tail_init(pkt_queue, &ep->rx_bufq);
1659
1660 spin_unlock_bh(&target->rx_lock);
1661
1662 if (status != 0) {
1663 /* walk through queue and mark each one canceled */
1664 list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
1665 packet->status = -ECANCELED;
1666 }
1667
1668 do_recv_completion(ep, pkt_queue);
1669 }
1670
1671 return status;
1672}
1673
1674static void ath6kl_htc_pipe_activity_changed(struct htc_target *target,
1675 enum htc_endpoint_id ep,
1676 bool active)
1677{
1678 /* TODO */
1679}
1680
1681static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target)
1682{
1683 /* TODO */
1684}
1685
1686static int ath6kl_htc_pipe_credit_setup(struct htc_target *target,
1687 struct ath6kl_htc_credit_info *info)
1688{
1689 return 0;
1690}
1691
1692static const struct ath6kl_htc_ops ath6kl_htc_pipe_ops = {
1693 .create = ath6kl_htc_pipe_create,
1694 .wait_target = ath6kl_htc_pipe_wait_target,
1695 .start = ath6kl_htc_pipe_start,
1696 .conn_service = ath6kl_htc_pipe_conn_service,
1697 .tx = ath6kl_htc_pipe_tx,
1698 .stop = ath6kl_htc_pipe_stop,
1699 .cleanup = ath6kl_htc_pipe_cleanup,
1700 .flush_txep = ath6kl_htc_pipe_flush_txep,
1701 .flush_rx_buf = ath6kl_htc_pipe_flush_rx_buf,
1702 .activity_changed = ath6kl_htc_pipe_activity_changed,
1703 .get_rxbuf_num = ath6kl_htc_pipe_get_rxbuf_num,
1704 .add_rxbuf_multiple = ath6kl_htc_pipe_add_rxbuf_multiple,
1705 .credit_setup = ath6kl_htc_pipe_credit_setup,
1706 .tx_complete = ath6kl_htc_pipe_tx_complete,
1707 .rx_complete = ath6kl_htc_pipe_rx_complete,
1708};
1709
1710void ath6kl_htc_pipe_attach(struct ath6kl *ar)
1711{
1712 ar->htc_ops = &ath6kl_htc_pipe_ops;
1713}
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index eb7cc2f5b96f..29ef50ea07d5 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -23,12 +23,14 @@
23#include <linux/export.h> 23#include <linux/export.h>
24#include <linux/of.h> 24#include <linux/of.h>
25#include <linux/mmc/sdio_func.h> 25#include <linux/mmc/sdio_func.h>
26#include <linux/vmalloc.h>
26 27
27#include "core.h" 28#include "core.h"
28#include "cfg80211.h" 29#include "cfg80211.h"
29#include "target.h" 30#include "target.h"
30#include "debug.h" 31#include "debug.h"
31#include "hif-ops.h" 32#include "hif-ops.h"
33#include "htc-ops.h"
32 34
33static const struct ath6kl_hw hw_list[] = { 35static const struct ath6kl_hw hw_list[] = {
34 { 36 {
@@ -258,6 +260,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
258 memset(&connect, 0, sizeof(connect)); 260 memset(&connect, 0, sizeof(connect));
259 261
260 /* these fields are the same for all service endpoints */ 262 /* these fields are the same for all service endpoints */
263 connect.ep_cb.tx_comp_multi = ath6kl_tx_complete;
261 connect.ep_cb.rx = ath6kl_rx; 264 connect.ep_cb.rx = ath6kl_rx;
262 connect.ep_cb.rx_refill = ath6kl_rx_refill; 265 connect.ep_cb.rx_refill = ath6kl_rx_refill;
263 connect.ep_cb.tx_full = ath6kl_tx_queue_full; 266 connect.ep_cb.tx_full = ath6kl_tx_queue_full;
@@ -487,22 +490,31 @@ int ath6kl_configure_target(struct ath6kl *ar)
487 fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS); 490 fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
488 491
489 /* 492 /*
490 * By default, submodes : 493 * Submodes when fw does not support dynamic interface
494 * switching:
491 * vif[0] - AP/STA/IBSS 495 * vif[0] - AP/STA/IBSS
492 * vif[1] - "P2P dev"/"P2P GO"/"P2P Client" 496 * vif[1] - "P2P dev"/"P2P GO"/"P2P Client"
493 * vif[2] - "P2P dev"/"P2P GO"/"P2P Client" 497 * vif[2] - "P2P dev"/"P2P GO"/"P2P Client"
498 * Otherwise, All the interface are initialized to p2p dev.
494 */ 499 */
495 500
496 for (i = 0; i < ar->max_norm_iface; i++) 501 if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
497 fw_submode |= HI_OPTION_FW_SUBMODE_NONE << 502 ar->fw_capabilities)) {
498 (i * HI_OPTION_FW_SUBMODE_BITS); 503 for (i = 0; i < ar->vif_max; i++)
504 fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
505 (i * HI_OPTION_FW_SUBMODE_BITS);
506 } else {
507 for (i = 0; i < ar->max_norm_iface; i++)
508 fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
509 (i * HI_OPTION_FW_SUBMODE_BITS);
499 510
500 for (i = ar->max_norm_iface; i < ar->vif_max; i++) 511 for (i = ar->max_norm_iface; i < ar->vif_max; i++)
501 fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << 512 fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
502 (i * HI_OPTION_FW_SUBMODE_BITS); 513 (i * HI_OPTION_FW_SUBMODE_BITS);
503 514
504 if (ar->p2p && ar->vif_max == 1) 515 if (ar->p2p && ar->vif_max == 1)
505 fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; 516 fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
517 }
506 518
507 if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, 519 if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,
508 HTC_PROTOCOL_VERSION) != 0) { 520 HTC_PROTOCOL_VERSION) != 0) {
@@ -541,18 +553,20 @@ int ath6kl_configure_target(struct ath6kl *ar)
541 * but possible in theory. 553 * but possible in theory.
542 */ 554 */
543 555
544 param = ar->hw.board_ext_data_addr; 556 if (ar->target_type == TARGET_TYPE_AR6003) {
545 ram_reserved_size = ar->hw.reserved_ram_size; 557 param = ar->hw.board_ext_data_addr;
558 ram_reserved_size = ar->hw.reserved_ram_size;
546 559
547 if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { 560 if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
548 ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); 561 ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
549 return -EIO; 562 return -EIO;
550 } 563 }
551 564
552 if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 565 if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
553 ram_reserved_size) != 0) { 566 ram_reserved_size) != 0) {
554 ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); 567 ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
555 return -EIO; 568 return -EIO;
569 }
556 } 570 }
557 571
558 /* set the block size for the target */ 572 /* set the block size for the target */
@@ -926,13 +940,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
926 if (ar->fw != NULL) 940 if (ar->fw != NULL)
927 break; 941 break;
928 942
929 ar->fw = kmemdup(data, ie_len, GFP_KERNEL); 943 ar->fw = vmalloc(ie_len);
930 944
931 if (ar->fw == NULL) { 945 if (ar->fw == NULL) {
932 ret = -ENOMEM; 946 ret = -ENOMEM;
933 goto out; 947 goto out;
934 } 948 }
935 949
950 memcpy(ar->fw, data, ie_len);
936 ar->fw_len = ie_len; 951 ar->fw_len = ie_len;
937 break; 952 break;
938 case ATH6KL_FW_IE_PATCH_IMAGE: 953 case ATH6KL_FW_IE_PATCH_IMAGE:
@@ -1509,7 +1524,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
1509 } 1524 }
1510 1525
1511 /* setup credit distribution */ 1526 /* setup credit distribution */
1512 ath6kl_credit_setup(ar->htc_target, &ar->credit_state_info); 1527 ath6kl_htc_credit_setup(ar->htc_target, &ar->credit_state_info);
1513 1528
1514 /* start HTC */ 1529 /* start HTC */
1515 ret = ath6kl_htc_start(ar->htc_target); 1530 ret = ath6kl_htc_start(ar->htc_target);
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 07071fce8a0e..4d818f96c415 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -758,6 +758,10 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
758 stats->wow_evt_discarded += 758 stats->wow_evt_discarded +=
759 le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); 759 le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded);
760 760
761 stats->arp_received = le32_to_cpu(tgt_stats->arp_stats.arp_received);
762 stats->arp_replied = le32_to_cpu(tgt_stats->arp_stats.arp_replied);
763 stats->arp_matched = le32_to_cpu(tgt_stats->arp_stats.arp_matched);
764
761 if (test_bit(STATS_UPDATE_PEND, &vif->flags)) { 765 if (test_bit(STATS_UPDATE_PEND, &vif->flags)) {
762 clear_bit(STATS_UPDATE_PEND, &vif->flags); 766 clear_bit(STATS_UPDATE_PEND, &vif->flags);
763 wake_up(&ar->event_wq); 767 wake_up(&ar->event_wq);
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 53528648b425..44ea7a742101 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -1362,7 +1362,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
1362 goto err_core_alloc; 1362 goto err_core_alloc;
1363 } 1363 }
1364 1364
1365 ret = ath6kl_core_init(ar); 1365 ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_MBOX);
1366 if (ret) { 1366 if (ret) {
1367 ath6kl_err("Failed to init ath6kl core\n"); 1367 ath6kl_err("Failed to init ath6kl core\n");
1368 goto err_core_alloc; 1368 goto err_core_alloc;
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 521f0be990f1..82f2f5cb475b 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -19,6 +19,7 @@
19 19
20#include "core.h" 20#include "core.h"
21#include "debug.h" 21#include "debug.h"
22#include "htc-ops.h"
22 23
23/* 24/*
24 * tid - tid_mux0..tid_mux3 25 * tid - tid_mux0..tid_mux3
@@ -324,6 +325,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
324 cookie->map_no = 0; 325 cookie->map_no = 0;
325 set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, 326 set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
326 eid, ATH6KL_CONTROL_PKT_TAG); 327 eid, ATH6KL_CONTROL_PKT_TAG);
328 cookie->htc_pkt.skb = skb;
327 329
328 /* 330 /*
329 * This interface is asynchronous, if there is an error, cleanup 331 * This interface is asynchronous, if there is an error, cleanup
@@ -492,6 +494,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
492 cookie->map_no = map_no; 494 cookie->map_no = map_no;
493 set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, 495 set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
494 eid, htc_tag); 496 eid, htc_tag);
497 cookie->htc_pkt.skb = skb;
495 498
496 ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ", 499 ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ",
497 skb->data, skb->len); 500 skb->data, skb->len);
@@ -572,7 +575,7 @@ void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active)
572 575
573notify_htc: 576notify_htc:
574 /* notify HTC, this may cause credit distribution changes */ 577 /* notify HTC, this may cause credit distribution changes */
575 ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active); 578 ath6kl_htc_activity_changed(ar->htc_target, eid, active);
576} 579}
577 580
578enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, 581enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
@@ -668,9 +671,10 @@ static void ath6kl_tx_clear_node_map(struct ath6kl_vif *vif,
668 } 671 }
669} 672}
670 673
671void ath6kl_tx_complete(void *context, struct list_head *packet_queue) 674void ath6kl_tx_complete(struct htc_target *target,
675 struct list_head *packet_queue)
672{ 676{
673 struct ath6kl *ar = context; 677 struct ath6kl *ar = target->dev->ar;
674 struct sk_buff_head skb_queue; 678 struct sk_buff_head skb_queue;
675 struct htc_packet *packet; 679 struct htc_packet *packet;
676 struct sk_buff *skb; 680 struct sk_buff *skb;
@@ -889,6 +893,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
889 skb->data = PTR_ALIGN(skb->data - 4, 4); 893 skb->data = PTR_ALIGN(skb->data - 4, 4);
890 set_htc_rxpkt_info(packet, skb, skb->data, 894 set_htc_rxpkt_info(packet, skb, skb->data,
891 ATH6KL_BUFFER_SIZE, endpoint); 895 ATH6KL_BUFFER_SIZE, endpoint);
896 packet->skb = skb;
892 list_add_tail(&packet->list, &queue); 897 list_add_tail(&packet->list, &queue);
893 } 898 }
894 899
@@ -911,6 +916,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
911 skb->data = PTR_ALIGN(skb->data - 4, 4); 916 skb->data = PTR_ALIGN(skb->data - 4, 4);
912 set_htc_rxpkt_info(packet, skb, skb->data, 917 set_htc_rxpkt_info(packet, skb, skb->data,
913 ATH6KL_AMSDU_BUFFER_SIZE, 0); 918 ATH6KL_AMSDU_BUFFER_SIZE, 0);
919 packet->skb = skb;
920
914 spin_lock_bh(&ar->lock); 921 spin_lock_bh(&ar->lock);
915 list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue); 922 list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue);
916 spin_unlock_bh(&ar->lock); 923 spin_unlock_bh(&ar->lock);
@@ -1283,6 +1290,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
1283 struct wmi_data_hdr *dhdr; 1290 struct wmi_data_hdr *dhdr;
1284 int min_hdr_len; 1291 int min_hdr_len;
1285 u8 meta_type, dot11_hdr = 0; 1292 u8 meta_type, dot11_hdr = 0;
1293 u8 pad_before_data_start;
1286 int status = packet->status; 1294 int status = packet->status;
1287 enum htc_endpoint_id ept = packet->endpoint; 1295 enum htc_endpoint_id ept = packet->endpoint;
1288 bool is_amsdu, prev_ps, ps_state = false; 1296 bool is_amsdu, prev_ps, ps_state = false;
@@ -1494,6 +1502,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
1494 seq_no = wmi_data_hdr_get_seqno(dhdr); 1502 seq_no = wmi_data_hdr_get_seqno(dhdr);
1495 meta_type = wmi_data_hdr_get_meta(dhdr); 1503 meta_type = wmi_data_hdr_get_meta(dhdr);
1496 dot11_hdr = wmi_data_hdr_get_dot11(dhdr); 1504 dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
1505 pad_before_data_start =
1506 (le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT)
1507 & WMI_DATA_HDR_PAD_BEFORE_DATA_MASK;
1508
1497 skb_pull(skb, sizeof(struct wmi_data_hdr)); 1509 skb_pull(skb, sizeof(struct wmi_data_hdr));
1498 1510
1499 switch (meta_type) { 1511 switch (meta_type) {
@@ -1512,6 +1524,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
1512 break; 1524 break;
1513 } 1525 }
1514 1526
1527 skb_pull(skb, pad_before_data_start);
1528
1515 if (dot11_hdr) 1529 if (dot11_hdr)
1516 status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb); 1530 status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb);
1517 else if (!is_amsdu) 1531 else if (!is_amsdu)
@@ -1581,7 +1595,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
1581 /* aggregation code will handle the skb */ 1595 /* aggregation code will handle the skb */
1582 return; 1596 return;
1583 } 1597 }
1584 } 1598 } else if (!is_broadcast_ether_addr(datap->h_dest))
1599 vif->net_stats.multicast++;
1585 1600
1586 ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); 1601 ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);
1587} 1602}
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 325b1224c2b1..ec7f1f5fd1ca 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -21,15 +21,77 @@
21#include "debug.h" 21#include "debug.h"
22#include "core.h" 22#include "core.h"
23 23
24/* constants */
25#define TX_URB_COUNT 32
26#define RX_URB_COUNT 32
27#define ATH6KL_USB_RX_BUFFER_SIZE 1700
28
29/* tx/rx pipes for usb */
30enum ATH6KL_USB_PIPE_ID {
31 ATH6KL_USB_PIPE_TX_CTRL = 0,
32 ATH6KL_USB_PIPE_TX_DATA_LP,
33 ATH6KL_USB_PIPE_TX_DATA_MP,
34 ATH6KL_USB_PIPE_TX_DATA_HP,
35 ATH6KL_USB_PIPE_RX_CTRL,
36 ATH6KL_USB_PIPE_RX_DATA,
37 ATH6KL_USB_PIPE_RX_DATA2,
38 ATH6KL_USB_PIPE_RX_INT,
39 ATH6KL_USB_PIPE_MAX
40};
41
42#define ATH6KL_USB_PIPE_INVALID ATH6KL_USB_PIPE_MAX
43
44struct ath6kl_usb_pipe {
45 struct list_head urb_list_head;
46 struct usb_anchor urb_submitted;
47 u32 urb_alloc;
48 u32 urb_cnt;
49 u32 urb_cnt_thresh;
50 unsigned int usb_pipe_handle;
51 u32 flags;
52 u8 ep_address;
53 u8 logical_pipe_num;
54 struct ath6kl_usb *ar_usb;
55 u16 max_packet_size;
56 struct work_struct io_complete_work;
57 struct sk_buff_head io_comp_queue;
58 struct usb_endpoint_descriptor *ep_desc;
59};
60
61#define ATH6KL_USB_PIPE_FLAG_TX (1 << 0)
62
24/* usb device object */ 63/* usb device object */
25struct ath6kl_usb { 64struct ath6kl_usb {
65 /* protects pipe->urb_list_head and pipe->urb_cnt */
66 spinlock_t cs_lock;
67
26 struct usb_device *udev; 68 struct usb_device *udev;
27 struct usb_interface *interface; 69 struct usb_interface *interface;
70 struct ath6kl_usb_pipe pipes[ATH6KL_USB_PIPE_MAX];
28 u8 *diag_cmd_buffer; 71 u8 *diag_cmd_buffer;
29 u8 *diag_resp_buffer; 72 u8 *diag_resp_buffer;
30 struct ath6kl *ar; 73 struct ath6kl *ar;
31}; 74};
32 75
76/* usb urb object */
77struct ath6kl_urb_context {
78 struct list_head link;
79 struct ath6kl_usb_pipe *pipe;
80 struct sk_buff *skb;
81 struct ath6kl *ar;
82};
83
84/* USB endpoint definitions */
85#define ATH6KL_USB_EP_ADDR_APP_CTRL_IN 0x81
86#define ATH6KL_USB_EP_ADDR_APP_DATA_IN 0x82
87#define ATH6KL_USB_EP_ADDR_APP_DATA2_IN 0x83
88#define ATH6KL_USB_EP_ADDR_APP_INT_IN 0x84
89
90#define ATH6KL_USB_EP_ADDR_APP_CTRL_OUT 0x01
91#define ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT 0x02
92#define ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT 0x03
93#define ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT 0x04
94
33/* diagnostic command defnitions */ 95/* diagnostic command defnitions */
34#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 96#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1
35#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2 97#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2
@@ -55,11 +117,493 @@ struct ath6kl_usb_ctrl_diag_resp_read {
55 __le32 value; 117 __le32 value;
56} __packed; 118} __packed;
57 119
120/* function declarations */
121static void ath6kl_usb_recv_complete(struct urb *urb);
122
123#define ATH6KL_USB_IS_BULK_EP(attr) (((attr) & 3) == 0x02)
124#define ATH6KL_USB_IS_INT_EP(attr) (((attr) & 3) == 0x03)
125#define ATH6KL_USB_IS_ISOC_EP(attr) (((attr) & 3) == 0x01)
126#define ATH6KL_USB_IS_DIR_IN(addr) ((addr) & 0x80)
127
128/* pipe/urb operations */
129static struct ath6kl_urb_context *
130ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe)
131{
132 struct ath6kl_urb_context *urb_context = NULL;
133 unsigned long flags;
134
135 spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
136 if (!list_empty(&pipe->urb_list_head)) {
137 urb_context =
138 list_first_entry(&pipe->urb_list_head,
139 struct ath6kl_urb_context, link);
140 list_del(&urb_context->link);
141 pipe->urb_cnt--;
142 }
143 spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags);
144
145 return urb_context;
146}
147
148static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe,
149 struct ath6kl_urb_context *urb_context)
150{
151 unsigned long flags;
152
153 spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
154 pipe->urb_cnt++;
155
156 list_add(&urb_context->link, &pipe->urb_list_head);
157 spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags);
158}
159
160static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context)
161{
162 if (urb_context->skb != NULL) {
163 dev_kfree_skb(urb_context->skb);
164 urb_context->skb = NULL;
165 }
166
167 ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
168}
169
170static inline struct ath6kl_usb *ath6kl_usb_priv(struct ath6kl *ar)
171{
172 return ar->hif_priv;
173}
174
175/* pipe resource allocation/cleanup */
176static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
177 int urb_cnt)
178{
179 struct ath6kl_urb_context *urb_context;
180 int status = 0, i;
181
182 INIT_LIST_HEAD(&pipe->urb_list_head);
183 init_usb_anchor(&pipe->urb_submitted);
184
185 for (i = 0; i < urb_cnt; i++) {
186 urb_context = kzalloc(sizeof(struct ath6kl_urb_context),
187 GFP_KERNEL);
188 if (urb_context == NULL)
189 /* FIXME: set status to -ENOMEM */
190 break;
191
192 urb_context->pipe = pipe;
193
194 /*
195 * we are only allocate the urb contexts here, the actual URB
196 * is allocated from the kernel as needed to do a transaction
197 */
198 pipe->urb_alloc++;
199 ath6kl_usb_free_urb_to_pipe(pipe, urb_context);
200 }
201
202 ath6kl_dbg(ATH6KL_DBG_USB,
203 "ath6kl usb: alloc resources lpipe:%d hpipe:0x%X urbs:%d\n",
204 pipe->logical_pipe_num, pipe->usb_pipe_handle,
205 pipe->urb_alloc);
206
207 return status;
208}
209
210static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe)
211{
212 struct ath6kl_urb_context *urb_context;
213
214 if (pipe->ar_usb == NULL) {
215 /* nothing allocated for this pipe */
216 return;
217 }
218
219 ath6kl_dbg(ATH6KL_DBG_USB,
220 "ath6kl usb: free resources lpipe:%d"
221 "hpipe:0x%X urbs:%d avail:%d\n",
222 pipe->logical_pipe_num, pipe->usb_pipe_handle,
223 pipe->urb_alloc, pipe->urb_cnt);
224
225 if (pipe->urb_alloc != pipe->urb_cnt) {
226 ath6kl_dbg(ATH6KL_DBG_USB,
227 "ath6kl usb: urb leak! lpipe:%d"
228 "hpipe:0x%X urbs:%d avail:%d\n",
229 pipe->logical_pipe_num, pipe->usb_pipe_handle,
230 pipe->urb_alloc, pipe->urb_cnt);
231 }
232
233 while (true) {
234 urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe);
235 if (urb_context == NULL)
236 break;
237 kfree(urb_context);
238 }
239
240}
241
242static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb)
243{
244 int i;
245
246 for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++)
247 ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]);
248
249}
250
251static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb,
252 u8 ep_address, int *urb_count)
253{
254 u8 pipe_num = ATH6KL_USB_PIPE_INVALID;
255
256 switch (ep_address) {
257 case ATH6KL_USB_EP_ADDR_APP_CTRL_IN:
258 pipe_num = ATH6KL_USB_PIPE_RX_CTRL;
259 *urb_count = RX_URB_COUNT;
260 break;
261 case ATH6KL_USB_EP_ADDR_APP_DATA_IN:
262 pipe_num = ATH6KL_USB_PIPE_RX_DATA;
263 *urb_count = RX_URB_COUNT;
264 break;
265 case ATH6KL_USB_EP_ADDR_APP_INT_IN:
266 pipe_num = ATH6KL_USB_PIPE_RX_INT;
267 *urb_count = RX_URB_COUNT;
268 break;
269 case ATH6KL_USB_EP_ADDR_APP_DATA2_IN:
270 pipe_num = ATH6KL_USB_PIPE_RX_DATA2;
271 *urb_count = RX_URB_COUNT;
272 break;
273 case ATH6KL_USB_EP_ADDR_APP_CTRL_OUT:
274 pipe_num = ATH6KL_USB_PIPE_TX_CTRL;
275 *urb_count = TX_URB_COUNT;
276 break;
277 case ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT:
278 pipe_num = ATH6KL_USB_PIPE_TX_DATA_LP;
279 *urb_count = TX_URB_COUNT;
280 break;
281 case ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT:
282 pipe_num = ATH6KL_USB_PIPE_TX_DATA_MP;
283 *urb_count = TX_URB_COUNT;
284 break;
285 case ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT:
286 pipe_num = ATH6KL_USB_PIPE_TX_DATA_HP;
287 *urb_count = TX_URB_COUNT;
288 break;
289 default:
290 /* note: there may be endpoints not currently used */
291 break;
292 }
293
294 return pipe_num;
295}
296
297static int ath6kl_usb_setup_pipe_resources(struct ath6kl_usb *ar_usb)
298{
299 struct usb_interface *interface = ar_usb->interface;
300 struct usb_host_interface *iface_desc = interface->cur_altsetting;
301 struct usb_endpoint_descriptor *endpoint;
302 struct ath6kl_usb_pipe *pipe;
303 int i, urbcount, status = 0;
304 u8 pipe_num;
305
306 ath6kl_dbg(ATH6KL_DBG_USB, "setting up USB Pipes using interface\n");
307
308 /* walk decriptors and setup pipes */
309 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
310 endpoint = &iface_desc->endpoint[i].desc;
311
312 if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) {
313 ath6kl_dbg(ATH6KL_DBG_USB,
314 "%s Bulk Ep:0x%2.2X maxpktsz:%d\n",
315 ATH6KL_USB_IS_DIR_IN
316 (endpoint->bEndpointAddress) ?
317 "RX" : "TX", endpoint->bEndpointAddress,
318 le16_to_cpu(endpoint->wMaxPacketSize));
319 } else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) {
320 ath6kl_dbg(ATH6KL_DBG_USB,
321 "%s Int Ep:0x%2.2X maxpktsz:%d interval:%d\n",
322 ATH6KL_USB_IS_DIR_IN
323 (endpoint->bEndpointAddress) ?
324 "RX" : "TX", endpoint->bEndpointAddress,
325 le16_to_cpu(endpoint->wMaxPacketSize),
326 endpoint->bInterval);
327 } else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) {
328 /* TODO for ISO */
329 ath6kl_dbg(ATH6KL_DBG_USB,
330 "%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d\n",
331 ATH6KL_USB_IS_DIR_IN
332 (endpoint->bEndpointAddress) ?
333 "RX" : "TX", endpoint->bEndpointAddress,
334 le16_to_cpu(endpoint->wMaxPacketSize),
335 endpoint->bInterval);
336 }
337 urbcount = 0;
338
339 pipe_num =
340 ath6kl_usb_get_logical_pipe_num(ar_usb,
341 endpoint->bEndpointAddress,
342 &urbcount);
343 if (pipe_num == ATH6KL_USB_PIPE_INVALID)
344 continue;
345
346 pipe = &ar_usb->pipes[pipe_num];
347 if (pipe->ar_usb != NULL) {
348 /* hmmm..pipe was already setup */
349 continue;
350 }
351
352 pipe->ar_usb = ar_usb;
353 pipe->logical_pipe_num = pipe_num;
354 pipe->ep_address = endpoint->bEndpointAddress;
355 pipe->max_packet_size = le16_to_cpu(endpoint->wMaxPacketSize);
356
357 if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) {
358 if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) {
359 pipe->usb_pipe_handle =
360 usb_rcvbulkpipe(ar_usb->udev,
361 pipe->ep_address);
362 } else {
363 pipe->usb_pipe_handle =
364 usb_sndbulkpipe(ar_usb->udev,
365 pipe->ep_address);
366 }
367 } else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) {
368 if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) {
369 pipe->usb_pipe_handle =
370 usb_rcvintpipe(ar_usb->udev,
371 pipe->ep_address);
372 } else {
373 pipe->usb_pipe_handle =
374 usb_sndintpipe(ar_usb->udev,
375 pipe->ep_address);
376 }
377 } else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) {
378 /* TODO for ISO */
379 if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) {
380 pipe->usb_pipe_handle =
381 usb_rcvisocpipe(ar_usb->udev,
382 pipe->ep_address);
383 } else {
384 pipe->usb_pipe_handle =
385 usb_sndisocpipe(ar_usb->udev,
386 pipe->ep_address);
387 }
388 }
389
390 pipe->ep_desc = endpoint;
391
392 if (!ATH6KL_USB_IS_DIR_IN(pipe->ep_address))
393 pipe->flags |= ATH6KL_USB_PIPE_FLAG_TX;
394
395 status = ath6kl_usb_alloc_pipe_resources(pipe, urbcount);
396 if (status != 0)
397 break;
398 }
399
400 return status;
401}
402
403/* pipe operations */
404static void ath6kl_usb_post_recv_transfers(struct ath6kl_usb_pipe *recv_pipe,
405 int buffer_length)
406{
407 struct ath6kl_urb_context *urb_context;
408 struct urb *urb;
409 int usb_status;
410
411 while (true) {
412 urb_context = ath6kl_usb_alloc_urb_from_pipe(recv_pipe);
413 if (urb_context == NULL)
414 break;
415
416 urb_context->skb = dev_alloc_skb(buffer_length);
417 if (urb_context->skb == NULL)
418 goto err_cleanup_urb;
419
420 urb = usb_alloc_urb(0, GFP_ATOMIC);
421 if (urb == NULL)
422 goto err_cleanup_urb;
423
424 usb_fill_bulk_urb(urb,
425 recv_pipe->ar_usb->udev,
426 recv_pipe->usb_pipe_handle,
427 urb_context->skb->data,
428 buffer_length,
429 ath6kl_usb_recv_complete, urb_context);
430
431 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
432 "ath6kl usb: bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes buf:0x%p\n",
433 recv_pipe->logical_pipe_num,
434 recv_pipe->usb_pipe_handle, recv_pipe->ep_address,
435 buffer_length, urb_context->skb);
436
437 usb_anchor_urb(urb, &recv_pipe->urb_submitted);
438 usb_status = usb_submit_urb(urb, GFP_ATOMIC);
439
440 if (usb_status) {
441 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
442 "ath6kl usb : usb bulk recv failed %d\n",
443 usb_status);
444 usb_unanchor_urb(urb);
445 usb_free_urb(urb);
446 goto err_cleanup_urb;
447 }
448 usb_free_urb(urb);
449 }
450 return;
451
452err_cleanup_urb:
453 ath6kl_usb_cleanup_recv_urb(urb_context);
454 return;
455}
456
457static void ath6kl_usb_flush_all(struct ath6kl_usb *ar_usb)
458{
459 int i;
460
461 for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) {
462 if (ar_usb->pipes[i].ar_usb != NULL)
463 usb_kill_anchored_urbs(&ar_usb->pipes[i].urb_submitted);
464 }
465
466 /*
467 * Flushing any pending I/O may schedule work this call will block
468 * until all scheduled work runs to completion.
469 */
470 flush_scheduled_work();
471}
472
473static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
474{
475 /*
476 * note: control pipe is no longer used
477 * ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_cnt_thresh =
478 * ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_alloc/2;
479 * ath6kl_usb_post_recv_transfers(&ar_usb->
480 * pipes[ATH6KL_USB_PIPE_RX_CTRL],
481 * ATH6KL_USB_RX_BUFFER_SIZE);
482 */
483
484 ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh =
485 ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
486 ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
487 ATH6KL_USB_RX_BUFFER_SIZE);
488}
489
490/* hif usb rx/tx completion functions */
491static void ath6kl_usb_recv_complete(struct urb *urb)
492{
493 struct ath6kl_urb_context *urb_context = urb->context;
494 struct ath6kl_usb_pipe *pipe = urb_context->pipe;
495 struct sk_buff *skb = NULL;
496 int status = 0;
497
498 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
499 "%s: recv pipe: %d, stat:%d, len:%d urb:0x%p\n", __func__,
500 pipe->logical_pipe_num, urb->status, urb->actual_length,
501 urb);
502
503 if (urb->status != 0) {
504 status = -EIO;
505 switch (urb->status) {
506 case -ECONNRESET:
507 case -ENOENT:
508 case -ESHUTDOWN:
509 /*
510 * no need to spew these errors when device
511 * removed or urb killed due to driver shutdown
512 */
513 status = -ECANCELED;
514 break;
515 default:
516 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
517 "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n",
518 __func__, pipe->logical_pipe_num,
519 pipe->ep_address, urb->status);
520 break;
521 }
522 goto cleanup_recv_urb;
523 }
524
525 if (urb->actual_length == 0)
526 goto cleanup_recv_urb;
527
528 skb = urb_context->skb;
529
530 /* we are going to pass it up */
531 urb_context->skb = NULL;
532 skb_put(skb, urb->actual_length);
533
534 /* note: queue implements a lock */
535 skb_queue_tail(&pipe->io_comp_queue, skb);
536 schedule_work(&pipe->io_complete_work);
537
538cleanup_recv_urb:
539 ath6kl_usb_cleanup_recv_urb(urb_context);
540
541 if (status == 0 &&
542 pipe->urb_cnt >= pipe->urb_cnt_thresh) {
543 /* our free urbs are piling up, post more transfers */
544 ath6kl_usb_post_recv_transfers(pipe, ATH6KL_USB_RX_BUFFER_SIZE);
545 }
546}
547
548static void ath6kl_usb_usb_transmit_complete(struct urb *urb)
549{
550 struct ath6kl_urb_context *urb_context = urb->context;
551 struct ath6kl_usb_pipe *pipe = urb_context->pipe;
552 struct sk_buff *skb;
553
554 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
555 "%s: pipe: %d, stat:%d, len:%d\n",
556 __func__, pipe->logical_pipe_num, urb->status,
557 urb->actual_length);
558
559 if (urb->status != 0) {
560 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
561 "%s: pipe: %d, failed:%d\n",
562 __func__, pipe->logical_pipe_num, urb->status);
563 }
564
565 skb = urb_context->skb;
566 urb_context->skb = NULL;
567 ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
568
569 /* note: queue implements a lock */
570 skb_queue_tail(&pipe->io_comp_queue, skb);
571 schedule_work(&pipe->io_complete_work);
572}
573
574static void ath6kl_usb_io_comp_work(struct work_struct *work)
575{
576 struct ath6kl_usb_pipe *pipe = container_of(work,
577 struct ath6kl_usb_pipe,
578 io_complete_work);
579 struct ath6kl_usb *ar_usb;
580 struct sk_buff *skb;
581
582 ar_usb = pipe->ar_usb;
583
584 while ((skb = skb_dequeue(&pipe->io_comp_queue))) {
585 if (pipe->flags & ATH6KL_USB_PIPE_FLAG_TX) {
586 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
587 "ath6kl usb xmit callback buf:0x%p\n", skb);
588 ath6kl_core_tx_complete(ar_usb->ar, skb);
589 } else {
590 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
591 "ath6kl usb recv callback buf:0x%p\n", skb);
592 ath6kl_core_rx_complete(ar_usb->ar, skb,
593 pipe->logical_pipe_num);
594 }
595 }
596}
597
58#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)) 598#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
59#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read)) 599#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
60 600
61static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb) 601static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
62{ 602{
603 ath6kl_usb_flush_all(ar_usb);
604
605 ath6kl_usb_cleanup_pipe_resources(ar_usb);
606
63 usb_set_intfdata(ar_usb->interface, NULL); 607 usb_set_intfdata(ar_usb->interface, NULL);
64 608
65 kfree(ar_usb->diag_cmd_buffer); 609 kfree(ar_usb->diag_cmd_buffer);
@@ -70,19 +614,28 @@ static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
70 614
71static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface) 615static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
72{ 616{
73 struct ath6kl_usb *ar_usb = NULL;
74 struct usb_device *dev = interface_to_usbdev(interface); 617 struct usb_device *dev = interface_to_usbdev(interface);
618 struct ath6kl_usb *ar_usb;
619 struct ath6kl_usb_pipe *pipe;
75 int status = 0; 620 int status = 0;
621 int i;
76 622
77 ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL); 623 ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
78 if (ar_usb == NULL) 624 if (ar_usb == NULL)
79 goto fail_ath6kl_usb_create; 625 goto fail_ath6kl_usb_create;
80 626
81 memset(ar_usb, 0, sizeof(struct ath6kl_usb));
82 usb_set_intfdata(interface, ar_usb); 627 usb_set_intfdata(interface, ar_usb);
628 spin_lock_init(&(ar_usb->cs_lock));
83 ar_usb->udev = dev; 629 ar_usb->udev = dev;
84 ar_usb->interface = interface; 630 ar_usb->interface = interface;
85 631
632 for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) {
633 pipe = &ar_usb->pipes[i];
634 INIT_WORK(&pipe->io_complete_work,
635 ath6kl_usb_io_comp_work);
636 skb_queue_head_init(&pipe->io_comp_queue);
637 }
638
86 ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL); 639 ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
87 if (ar_usb->diag_cmd_buffer == NULL) { 640 if (ar_usb->diag_cmd_buffer == NULL) {
88 status = -ENOMEM; 641 status = -ENOMEM;
@@ -96,6 +649,8 @@ static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
96 goto fail_ath6kl_usb_create; 649 goto fail_ath6kl_usb_create;
97 } 650 }
98 651
652 status = ath6kl_usb_setup_pipe_resources(ar_usb);
653
99fail_ath6kl_usb_create: 654fail_ath6kl_usb_create:
100 if (status != 0) { 655 if (status != 0) {
101 ath6kl_usb_destroy(ar_usb); 656 ath6kl_usb_destroy(ar_usb);
@@ -114,11 +669,177 @@ static void ath6kl_usb_device_detached(struct usb_interface *interface)
114 669
115 ath6kl_stop_txrx(ar_usb->ar); 670 ath6kl_stop_txrx(ar_usb->ar);
116 671
672 /* Delay to wait for the target to reboot */
673 mdelay(20);
117 ath6kl_core_cleanup(ar_usb->ar); 674 ath6kl_core_cleanup(ar_usb->ar);
118
119 ath6kl_usb_destroy(ar_usb); 675 ath6kl_usb_destroy(ar_usb);
120} 676}
121 677
678/* exported hif usb APIs for htc pipe */
679static void hif_start(struct ath6kl *ar)
680{
681 struct ath6kl_usb *device = ath6kl_usb_priv(ar);
682 int i;
683
684 ath6kl_usb_start_recv_pipes(device);
685
686 /* set the TX resource avail threshold for each TX pipe */
687 for (i = ATH6KL_USB_PIPE_TX_CTRL;
688 i <= ATH6KL_USB_PIPE_TX_DATA_HP; i++) {
689 device->pipes[i].urb_cnt_thresh =
690 device->pipes[i].urb_alloc / 2;
691 }
692}
693
694static int ath6kl_usb_send(struct ath6kl *ar, u8 PipeID,
695 struct sk_buff *hdr_skb, struct sk_buff *skb)
696{
697 struct ath6kl_usb *device = ath6kl_usb_priv(ar);
698 struct ath6kl_usb_pipe *pipe = &device->pipes[PipeID];
699 struct ath6kl_urb_context *urb_context;
700 int usb_status, status = 0;
701 struct urb *urb;
702 u8 *data;
703 u32 len;
704
705 ath6kl_dbg(ATH6KL_DBG_USB_BULK, "+%s pipe : %d, buf:0x%p\n",
706 __func__, PipeID, skb);
707
708 urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe);
709
710 if (urb_context == NULL) {
711 /*
712 * TODO: it is possible to run out of urbs if
713 * 2 endpoints map to the same pipe ID
714 */
715 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
716 "%s pipe:%d no urbs left. URB Cnt : %d\n",
717 __func__, PipeID, pipe->urb_cnt);
718 status = -ENOMEM;
719 goto fail_hif_send;
720 }
721
722 urb_context->skb = skb;
723
724 data = skb->data;
725 len = skb->len;
726
727 urb = usb_alloc_urb(0, GFP_ATOMIC);
728 if (urb == NULL) {
729 status = -ENOMEM;
730 ath6kl_usb_free_urb_to_pipe(urb_context->pipe,
731 urb_context);
732 goto fail_hif_send;
733 }
734
735 usb_fill_bulk_urb(urb,
736 device->udev,
737 pipe->usb_pipe_handle,
738 data,
739 len,
740 ath6kl_usb_usb_transmit_complete, urb_context);
741
742 if ((len % pipe->max_packet_size) == 0) {
743 /* hit a max packet boundary on this pipe */
744 urb->transfer_flags |= URB_ZERO_PACKET;
745 }
746
747 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
748 "athusb bulk send submit:%d, 0x%X (ep:0x%2.2X), %d bytes\n",
749 pipe->logical_pipe_num, pipe->usb_pipe_handle,
750 pipe->ep_address, len);
751
752 usb_anchor_urb(urb, &pipe->urb_submitted);
753 usb_status = usb_submit_urb(urb, GFP_ATOMIC);
754
755 if (usb_status) {
756 ath6kl_dbg(ATH6KL_DBG_USB_BULK,
757 "ath6kl usb : usb bulk transmit failed %d\n",
758 usb_status);
759 usb_unanchor_urb(urb);
760 ath6kl_usb_free_urb_to_pipe(urb_context->pipe,
761 urb_context);
762 status = -EINVAL;
763 }
764 usb_free_urb(urb);
765
766fail_hif_send:
767 return status;
768}
769
770static void hif_stop(struct ath6kl *ar)
771{
772 struct ath6kl_usb *device = ath6kl_usb_priv(ar);
773
774 ath6kl_usb_flush_all(device);
775}
776
777static void ath6kl_usb_get_default_pipe(struct ath6kl *ar,
778 u8 *ul_pipe, u8 *dl_pipe)
779{
780 *ul_pipe = ATH6KL_USB_PIPE_TX_CTRL;
781 *dl_pipe = ATH6KL_USB_PIPE_RX_CTRL;
782}
783
784static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
785 u8 *ul_pipe, u8 *dl_pipe)
786{
787 int status = 0;
788
789 switch (svc_id) {
790 case HTC_CTRL_RSVD_SVC:
791 case WMI_CONTROL_SVC:
792 *ul_pipe = ATH6KL_USB_PIPE_TX_CTRL;
793 /* due to large control packets, shift to data pipe */
794 *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
795 break;
796 case WMI_DATA_BE_SVC:
797 case WMI_DATA_BK_SVC:
798 *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
799 /*
800 * Disable rxdata2 directly, it will be enabled
801 * if FW enable rxdata2
802 */
803 *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
804 break;
805 case WMI_DATA_VI_SVC:
806 *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
807 /*
808 * Disable rxdata2 directly, it will be enabled
809 * if FW enable rxdata2
810 */
811 *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
812 break;
813 case WMI_DATA_VO_SVC:
814 *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP;
815 /*
816 * Disable rxdata2 directly, it will be enabled
817 * if FW enable rxdata2
818 */
819 *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
820 break;
821 default:
822 status = -EPERM;
823 break;
824 }
825
826 return status;
827}
828
829static u16 ath6kl_usb_get_free_queue_number(struct ath6kl *ar, u8 pipe_id)
830{
831 struct ath6kl_usb *device = ath6kl_usb_priv(ar);
832
833 return device->pipes[pipe_id].urb_cnt;
834}
835
836static void hif_detach_htc(struct ath6kl *ar)
837{
838 struct ath6kl_usb *device = ath6kl_usb_priv(ar);
839
840 ath6kl_usb_flush_all(device);
841}
842
122static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, 843static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
123 u8 req, u16 value, u16 index, void *data, 844 u8 req, u16 value, u16 index, void *data,
124 u32 size) 845 u32 size)
@@ -301,14 +1022,21 @@ static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
301 1022
302static int ath6kl_usb_power_on(struct ath6kl *ar) 1023static int ath6kl_usb_power_on(struct ath6kl *ar)
303{ 1024{
1025 hif_start(ar);
304 return 0; 1026 return 0;
305} 1027}
306 1028
307static int ath6kl_usb_power_off(struct ath6kl *ar) 1029static int ath6kl_usb_power_off(struct ath6kl *ar)
308{ 1030{
1031 hif_detach_htc(ar);
309 return 0; 1032 return 0;
310} 1033}
311 1034
1035static void ath6kl_usb_stop(struct ath6kl *ar)
1036{
1037 hif_stop(ar);
1038}
1039
312static const struct ath6kl_hif_ops ath6kl_usb_ops = { 1040static const struct ath6kl_hif_ops ath6kl_usb_ops = {
313 .diag_read32 = ath6kl_usb_diag_read32, 1041 .diag_read32 = ath6kl_usb_diag_read32,
314 .diag_write32 = ath6kl_usb_diag_write32, 1042 .diag_write32 = ath6kl_usb_diag_write32,
@@ -316,6 +1044,11 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = {
316 .bmi_write = ath6kl_usb_bmi_write, 1044 .bmi_write = ath6kl_usb_bmi_write,
317 .power_on = ath6kl_usb_power_on, 1045 .power_on = ath6kl_usb_power_on,
318 .power_off = ath6kl_usb_power_off, 1046 .power_off = ath6kl_usb_power_off,
1047 .stop = ath6kl_usb_stop,
1048 .pipe_send = ath6kl_usb_send,
1049 .pipe_get_default = ath6kl_usb_get_default_pipe,
1050 .pipe_map_service = ath6kl_usb_map_service_pipe,
1051 .pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number,
319}; 1052};
320 1053
321/* ath6kl usb driver registered functions */ 1054/* ath6kl usb driver registered functions */
@@ -368,7 +1101,7 @@ static int ath6kl_usb_probe(struct usb_interface *interface,
368 1101
369 ar_usb->ar = ar; 1102 ar_usb->ar = ar;
370 1103
371 ret = ath6kl_core_init(ar); 1104 ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_PIPE);
372 if (ret) { 1105 if (ret) {
373 ath6kl_err("Failed to init ath6kl core: %d\n", ret); 1106 ath6kl_err("Failed to init ath6kl core: %d\n", ret);
374 goto err_core_free; 1107 goto err_core_free;
@@ -392,6 +1125,46 @@ static void ath6kl_usb_remove(struct usb_interface *interface)
392 ath6kl_usb_device_detached(interface); 1125 ath6kl_usb_device_detached(interface);
393} 1126}
394 1127
1128#ifdef CONFIG_PM
1129
1130static int ath6kl_usb_suspend(struct usb_interface *interface,
1131 pm_message_t message)
1132{
1133 struct ath6kl_usb *device;
1134 device = usb_get_intfdata(interface);
1135
1136 ath6kl_usb_flush_all(device);
1137 return 0;
1138}
1139
1140static int ath6kl_usb_resume(struct usb_interface *interface)
1141{
1142 struct ath6kl_usb *device;
1143 device = usb_get_intfdata(interface);
1144
1145 ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA],
1146 ATH6KL_USB_RX_BUFFER_SIZE);
1147 ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA2],
1148 ATH6KL_USB_RX_BUFFER_SIZE);
1149
1150 return 0;
1151}
1152
1153static int ath6kl_usb_reset_resume(struct usb_interface *intf)
1154{
1155 if (usb_get_intfdata(intf))
1156 ath6kl_usb_remove(intf);
1157 return 0;
1158}
1159
1160#else
1161
1162#define ath6kl_usb_suspend NULL
1163#define ath6kl_usb_resume NULL
1164#define ath6kl_usb_reset_resume NULL
1165
1166#endif
1167
395/* table of devices that work with this driver */ 1168/* table of devices that work with this driver */
396static struct usb_device_id ath6kl_usb_ids[] = { 1169static struct usb_device_id ath6kl_usb_ids[] = {
397 {USB_DEVICE(0x0cf3, 0x9374)}, 1170 {USB_DEVICE(0x0cf3, 0x9374)},
@@ -403,8 +1176,12 @@ MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids);
403static struct usb_driver ath6kl_usb_driver = { 1176static struct usb_driver ath6kl_usb_driver = {
404 .name = "ath6kl_usb", 1177 .name = "ath6kl_usb",
405 .probe = ath6kl_usb_probe, 1178 .probe = ath6kl_usb_probe,
1179 .suspend = ath6kl_usb_suspend,
1180 .resume = ath6kl_usb_resume,
1181 .reset_resume = ath6kl_usb_reset_resume,
406 .disconnect = ath6kl_usb_remove, 1182 .disconnect = ath6kl_usb_remove,
407 .id_table = ath6kl_usb_ids, 1183 .id_table = ath6kl_usb_ids,
1184 .supports_autosuspend = true,
408}; 1185};
409 1186
410static int ath6kl_usb_init(void) 1187static int ath6kl_usb_init(void)
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 2b442332cd0f..7c8a9977faf5 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2882,6 +2882,43 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
2882 return ret; 2882 return ret;
2883} 2883}
2884 2884
2885int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
2886 enum ieee80211_band band,
2887 struct ath6kl_htcap *htcap)
2888{
2889 struct sk_buff *skb;
2890 struct wmi_set_htcap_cmd *cmd;
2891
2892 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2893 if (!skb)
2894 return -ENOMEM;
2895
2896 cmd = (struct wmi_set_htcap_cmd *) skb->data;
2897
2898 /*
2899 * NOTE: Band in firmware matches enum ieee80211_band, it is unlikely
2900 * this will be changed in firmware. If at all there is any change in
2901 * band value, the host needs to be fixed.
2902 */
2903 cmd->band = band;
2904 cmd->ht_enable = !!htcap->ht_enable;
2905 cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20);
2906 cmd->ht40_supported =
2907 !!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
2908 cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40);
2909 cmd->intolerant_40mhz =
2910 !!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT);
2911 cmd->max_ampdu_len_exp = htcap->ampdu_factor;
2912
2913 ath6kl_dbg(ATH6KL_DBG_WMI,
2914 "Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n",
2915 cmd->band, cmd->ht_enable, cmd->ht40_supported,
2916 cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz,
2917 cmd->max_ampdu_len_exp);
2918 return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID,
2919 NO_SYNC_WMIFLAG);
2920}
2921
2885int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) 2922int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
2886{ 2923{
2887 struct sk_buff *skb; 2924 struct sk_buff *skb;
@@ -3032,6 +3069,9 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
3032 cm->reason = cpu_to_le16(reason); 3069 cm->reason = cpu_to_le16(reason);
3033 cm->cmd = cmd; 3070 cm->cmd = cmd;
3034 3071
3072 ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd,
3073 cm->reason);
3074
3035 return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID, 3075 return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID,
3036 NO_SYNC_WMIFLAG); 3076 NO_SYNC_WMIFLAG);
3037} 3077}
@@ -3181,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
3181 NO_SYNC_WMIFLAG); 3221 NO_SYNC_WMIFLAG);
3182} 3222}
3183 3223
3224int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
3225 const u8 *ie_info, u8 ie_len)
3226{
3227 struct sk_buff *skb;
3228 struct wmi_set_ie_cmd *p;
3229
3230 skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
3231 if (!skb)
3232 return -ENOMEM;
3233
3234 ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n",
3235 ie_id, ie_field, ie_len);
3236 p = (struct wmi_set_ie_cmd *) skb->data;
3237 p->ie_id = ie_id;
3238 p->ie_field = ie_field;
3239 p->ie_len = ie_len;
3240 if (ie_info && ie_len > 0)
3241 memcpy(p->ie_info, ie_info, ie_len);
3242
3243 return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID,
3244 NO_SYNC_WMIFLAG);
3245}
3246
3184int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) 3247int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
3185{ 3248{
3186 struct sk_buff *skb; 3249 struct sk_buff *skb;
@@ -3392,6 +3455,23 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx)
3392 WMI_CANCEL_REMAIN_ON_CHNL_CMDID); 3455 WMI_CANCEL_REMAIN_ON_CHNL_CMDID);
3393} 3456}
3394 3457
3458int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
3459{
3460 struct sk_buff *skb;
3461 struct wmi_set_inact_period_cmd *cmd;
3462
3463 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3464 if (!skb)
3465 return -ENOMEM;
3466
3467 cmd = (struct wmi_set_inact_period_cmd *) skb->data;
3468 cmd->inact_period = cpu_to_le32(inact_timeout);
3469 cmd->num_null_func = 0;
3470
3471 return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_CONN_INACT_CMDID,
3472 NO_SYNC_WMIFLAG);
3473}
3474
3395static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) 3475static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
3396{ 3476{
3397 struct wmix_cmd_hdr *cmd; 3477 struct wmix_cmd_hdr *cmd;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 4092e3e80790..d3d2ab5c1689 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -182,6 +182,9 @@ enum wmi_data_hdr_flags {
182#define WMI_DATA_HDR_META_MASK 0x7 182#define WMI_DATA_HDR_META_MASK 0x7
183#define WMI_DATA_HDR_META_SHIFT 13 183#define WMI_DATA_HDR_META_SHIFT 13
184 184
185#define WMI_DATA_HDR_PAD_BEFORE_DATA_MASK 0xFF
186#define WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT 0x8
187
185/* Macros for operating on WMI_DATA_HDR (info3) field */ 188/* Macros for operating on WMI_DATA_HDR (info3) field */
186#define WMI_DATA_HDR_IF_IDX_MASK 0xF 189#define WMI_DATA_HDR_IF_IDX_MASK 0xF
187 190
@@ -423,6 +426,7 @@ enum wmi_cmd_id {
423 WMI_SET_FRAMERATES_CMDID, 426 WMI_SET_FRAMERATES_CMDID,
424 WMI_SET_AP_PS_CMDID, 427 WMI_SET_AP_PS_CMDID,
425 WMI_SET_QOS_SUPP_CMDID, 428 WMI_SET_QOS_SUPP_CMDID,
429 WMI_SET_IE_CMDID,
426 430
427 /* WMI_THIN_RESERVED_... mark the start and end 431 /* WMI_THIN_RESERVED_... mark the start and end
428 * values for WMI_THIN_RESERVED command IDs. These 432 * values for WMI_THIN_RESERVED command IDs. These
@@ -629,6 +633,11 @@ enum wmi_mgmt_frame_type {
629 WMI_NUM_MGMT_FRAME 633 WMI_NUM_MGMT_FRAME
630}; 634};
631 635
636enum wmi_ie_field_type {
637 WMI_RSN_IE_CAPB = 0x1,
638 WMI_IE_FULL = 0xFF, /* indicats full IE */
639};
640
632/* WMI_CONNECT_CMDID */ 641/* WMI_CONNECT_CMDID */
633enum network_type { 642enum network_type {
634 INFRA_NETWORK = 0x01, 643 INFRA_NETWORK = 0x01,
@@ -1268,6 +1277,16 @@ struct wmi_mcast_filter_add_del_cmd {
1268 u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; 1277 u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
1269} __packed; 1278} __packed;
1270 1279
1280struct wmi_set_htcap_cmd {
1281 u8 band;
1282 u8 ht_enable;
1283 u8 ht40_supported;
1284 u8 ht20_sgi;
1285 u8 ht40_sgi;
1286 u8 intolerant_40mhz;
1287 u8 max_ampdu_len_exp;
1288} __packed;
1289
1271/* Command Replies */ 1290/* Command Replies */
1272 1291
1273/* WMI_GET_CHANNEL_LIST_CMDID reply */ 1292/* WMI_GET_CHANNEL_LIST_CMDID reply */
@@ -1913,6 +1932,14 @@ struct wmi_set_appie_cmd {
1913 u8 ie_info[0]; 1932 u8 ie_info[0];
1914} __packed; 1933} __packed;
1915 1934
1935struct wmi_set_ie_cmd {
1936 u8 ie_id;
1937 u8 ie_field; /* enum wmi_ie_field_type */
1938 u8 ie_len;
1939 u8 reserved;
1940 u8 ie_info[0];
1941} __packed;
1942
1916/* Notify the WSC registration status to the target */ 1943/* Notify the WSC registration status to the target */
1917#define WSC_REG_ACTIVE 1 1944#define WSC_REG_ACTIVE 1
1918#define WSC_REG_INACTIVE 0 1945#define WSC_REG_INACTIVE 0
@@ -2141,6 +2168,11 @@ struct wmi_ap_hidden_ssid_cmd {
2141 u8 hidden_ssid; 2168 u8 hidden_ssid;
2142} __packed; 2169} __packed;
2143 2170
2171struct wmi_set_inact_period_cmd {
2172 __le32 inact_period;
2173 u8 num_null_func;
2174} __packed;
2175
2144/* AP mode events */ 2176/* AP mode events */
2145struct wmi_ap_set_apsd_cmd { 2177struct wmi_ap_set_apsd_cmd {
2146 u8 enable; 2178 u8 enable;
@@ -2465,6 +2497,9 @@ int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi);
2465int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg); 2497int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg);
2466int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, 2498int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
2467 u8 keep_alive_intvl); 2499 u8 keep_alive_intvl);
2500int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
2501 enum ieee80211_band band,
2502 struct ath6kl_htcap *htcap);
2468int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); 2503int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
2469 2504
2470s32 ath6kl_wmi_get_rate(s8 rate_index); 2505s32 ath6kl_wmi_get_rate(s8 rate_index);
@@ -2515,6 +2550,9 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx,
2515int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, 2550int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
2516 const u8 *ie, u8 ie_len); 2551 const u8 *ie, u8 ie_len);
2517 2552
2553int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
2554 const u8 *ie_info, u8 ie_len);
2555
2518/* P2P */ 2556/* P2P */
2519int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); 2557int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
2520 2558
@@ -2538,6 +2576,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx);
2538int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, 2576int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
2539 const u8 *ie, u8 ie_len); 2577 const u8 *ie, u8 ie_len);
2540 2578
2579int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);
2580
2541void ath6kl_wmi_sscan_timer(unsigned long ptr); 2581void ath6kl_wmi_sscan_timer(unsigned long ptr);
2542 2582
2543struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); 2583struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);