提交 59ef43e6 编写于 作者: J John W. Linville

Merge branch 'master' of...

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

Conflicts:
	drivers/net/wireless/iwlwifi/iwl-testmode.c
	include/net/nfc/nfc.h
	net/nfc/netlink.c
	net/wireless/nl80211.c
HCI backend for NFC Core
Author: Eric Lapuyade, Samuel Ortiz
Contact: eric.lapuyade@intel.com, samuel.ortiz@intel.com
General
-------
The HCI layer implements much of the ETSI TS 102 622 V10.2.0 specification. It
enables easy writing of HCI-based NFC drivers. The HCI layer runs as an NFC Core
backend, implementing an abstract nfc device and translating NFC Core API
to HCI commands and events.
HCI
---
HCI registers as an nfc device with NFC Core. Requests coming from userspace are
routed through netlink sockets to NFC Core and then to HCI. From this point,
they are translated in a sequence of HCI commands sent to the HCI layer in the
host controller (the chip). The sending context blocks while waiting for the
response to arrive.
HCI events can also be received from the host controller. They will be handled
and a translation will be forwarded to NFC Core as needed.
HCI uses 2 execution contexts:
- one if for executing commands : nfc_hci_msg_tx_work(). Only one command
can be executing at any given moment.
- one if for dispatching received events and responses : nfc_hci_msg_rx_work()
HCI Session initialization:
---------------------------
The Session initialization is an HCI standard which must unfortunately
support proprietary gates. This is the reason why the driver will pass a list
of proprietary gates that must be part of the session. HCI will ensure all
those gates have pipes connected when the hci device is set up.
HCI Gates and Pipes
-------------------
A gate defines the 'port' where some service can be found. In order to access
a service, one must create a pipe to that gate and open it. In this
implementation, pipes are totally hidden. The public API only knows gates.
This is consistent with the driver need to send commands to proprietary gates
without knowing the pipe connected to it.
Driver interface
----------------
A driver would normally register itself with HCI and provide the following
entry points:
struct nfc_hci_ops {
int (*open)(struct nfc_hci_dev *hdev);
void (*close)(struct nfc_hci_dev *hdev);
int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
};
open() and close() shall turn the hardware on and off. xmit() shall simply
write a frame to the chip. start_poll() is an optional entrypoint that shall
set the hardware in polling mode. This must be implemented only if the hardware
uses proprietary gates or a mechanism slightly different from the HCI standard.
target_from_gate() is another optional entrypoint to return the protocols
corresponding to a proprietary gate.
On the rx path, the driver is responsible to push incoming HCP frames to HCI
using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
This must be done from a context that can sleep.
SHDLC
-----
Most chips use shdlc to ensure integrity and delivery ordering of the HCP
frames between the host controller (the chip) and hosts (entities connected
to the chip, like the cpu). In order to simplify writing the driver, an shdlc
layer is available for use by the driver.
When used, the driver actually registers with shdlc, and shdlc will register
with HCI. HCI sees shdlc as the driver and thus send its HCP frames
through shdlc->xmit.
SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state
machine and handle both its rx and tx path.
Included Drivers
----------------
An HCI based driver for an NXP PN544, connected through I2C bus, and using
shdlc is included.
Execution Contexts
------------------
The execution contexts are the following:
- IRQ handler (IRQH):
fast, cannot sleep. stores incoming frames into an shdlc rx queue
- SHDLC State Machine worker (SMW)
handles shdlc rx & tx queues. Dispatches HCI cmd responses.
- HCI Tx Cmd worker (MSGTXWQ)
Serialize execution of HCI commands. Complete execution in case of resp timeout.
- HCI Rx worker (MSGRXWQ)
Dispatches incoming HCI commands or events.
- Syscall context from a userspace call (SYSCALL)
Any entrypoint in HCI called from NFC Core
Workflow executing an HCI command (using shdlc)
-----------------------------------------------
Executing an HCI command can easily be performed synchronously using the
following API:
int nfc_hci_send_cmd (struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
const u8 *param, size_t param_len, struct sk_buff **skb)
The API must be invoked from a context that can sleep. Most of the time, this
will be the syscall context. skb will return the result that was received in
the response.
Internally, execution is asynchronous. So all this API does is to enqueue the
HCI command, setup a local wait queue on stack, and wait_event() for completion.
The wait is not interruptible because it is guaranteed that the command will
complete after some short timeout anyway.
MSGTXWQ context will then be scheduled and invoke nfc_hci_msg_tx_work().
This function will dequeue the next pending command and send its HCP fragments
to the lower layer which happens to be shdlc. It will then start a timer to be
able to complete the command with a timeout error if no response arrive.
SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function
handles shdlc framing in and out. It uses the driver xmit to send frames and
receives incoming frames in an skb queue filled from the driver IRQ handler.
SHDLC I(nformation) frames payload are HCP fragments. They are agregated to
form complete HCI frames, which can be a response, command, or event.
HCI Responses are dispatched immediately from this context to unblock
waiting command execution. Reponse processing involves invoking the completion
callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
The completion callback will then wake the syscall context.
Workflow receiving an HCI event or command
------------------------------------------
HCI commands or events are not dispatched from SMW context. Instead, they are
queued to HCI rx_queue and will be dispatched from HCI rx worker
context (MSGRXWQ). This is done this way to allow a cmd or event handler
to also execute other commands (for example, handling the
NFC_HCI_EVT_TARGET_DISCOVERED event from PN544 requires to issue an
ANY_GET_PARAMETER to the reader A gate to get information on the target
that was discovered).
Typically, such an event will be propagated to NFC Core from MSGRXWQ context.
...@@ -6669,6 +6669,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) ...@@ -6669,6 +6669,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: sound/soc/codecs/twl4030* F: sound/soc/codecs/twl4030*
TI WILINK WIRELESS DRIVERS
M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
W: http://wireless.kernel.org/en/users/Drivers/wl1251
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
F: drivers/net/wireless/ti/
F: include/linux/wl12xx.h
TIPC NETWORK LAYER TIPC NETWORK LAYER
M: Jon Maloy <jon.maloy@ericsson.com> M: Jon Maloy <jon.maloy@ericsson.com>
M: Allan Stephens <allan.stephens@windriver.com> M: Allan Stephens <allan.stephens@windriver.com>
...@@ -7425,23 +7435,6 @@ M: Miloslav Trmac <mitr@volny.cz> ...@@ -7425,23 +7435,6 @@ M: Miloslav Trmac <mitr@volny.cz>
S: Maintained S: Maintained
F: drivers/input/misc/wistron_btns.c F: drivers/input/misc/wistron_btns.c
WL1251 WIRELESS DRIVER
M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl1251
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/wl1251/*
WL1271 WIRELESS DRIVER
M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
F: drivers/net/wireless/wl12xx/
F: include/linux/wl12xx.h
WL3501 WIRELESS PCMCIA CARD DRIVER WL3501 WIRELESS PCMCIA CARD DRIVER
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig" ...@@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/rtlwifi/Kconfig" source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig" source "drivers/net/wireless/mwifiex/Kconfig"
......
...@@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/ ...@@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL_TI) += ti/
obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/ obj-$(CONFIG_IWM) += iwmc3200wifi/
......
...@@ -1991,19 +1991,4 @@ static struct pci_driver adm8211_driver = { ...@@ -1991,19 +1991,4 @@ static struct pci_driver adm8211_driver = {
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
}; };
module_pci_driver(adm8211_driver);
static int __init adm8211_init(void)
{
return pci_register_driver(&adm8211_driver);
}
static void __exit adm8211_exit(void)
{
pci_unregister_driver(&adm8211_driver);
}
module_init(adm8211_init);
module_exit(adm8211_exit);
...@@ -2512,10 +2512,8 @@ static void __exit at76_mod_exit(void) ...@@ -2512,10 +2512,8 @@ static void __exit at76_mod_exit(void)
printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n"); printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n");
usb_deregister(&at76_driver); usb_deregister(&at76_driver);
for (i = 0; i < ARRAY_SIZE(firmwares); i++) { for (i = 0; i < ARRAY_SIZE(firmwares); i++)
if (firmwares[i].fw) release_firmware(firmwares[i].fw);
release_firmware(firmwares[i].fw);
}
led_trigger_unregister_simple(ledtrig_tx); led_trigger_unregister_simple(ledtrig_tx);
} }
......
...@@ -1527,7 +1527,7 @@ void ath5k_eeprom_detach(struct ath5k_hw *ah); ...@@ -1527,7 +1527,7 @@ void ath5k_eeprom_detach(struct ath5k_hw *ah);
/* Protocol Control Unit Functions */ /* Protocol Control Unit Functions */
/* Helpers */ /* Helpers */
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, enum ieee80211_band band,
int len, struct ieee80211_rate *rate, bool shortpre); int len, struct ieee80211_rate *rate, bool shortpre);
unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
......
...@@ -1170,7 +1170,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb, ...@@ -1170,7 +1170,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,
if (ieee80211_is_beacon(mgmt->frame_control) && if (ieee80211_is_beacon(mgmt->frame_control) &&
le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { compare_ether_addr(mgmt->bssid, common->curbssid) == 0) {
/* /*
* Received an IBSS beacon with the same BSSID. Hardware *must* * Received an IBSS beacon with the same BSSID. Hardware *must*
* have updated the local TSF. We have to work around various * have updated the local TSF. We have to work around various
...@@ -1234,7 +1234,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi) ...@@ -1234,7 +1234,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi)
/* only beacons from our BSSID */ /* only beacons from our BSSID */
if (!ieee80211_is_beacon(mgmt->frame_control) || if (!ieee80211_is_beacon(mgmt->frame_control) ||
memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) compare_ether_addr(mgmt->bssid, common->curbssid) != 0)
return; return;
ewma_add(&ah->ah_beacon_rssi_avg, rssi); ewma_add(&ah->ah_beacon_rssi_avg, rssi);
......
...@@ -47,6 +47,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = { ...@@ -47,6 +47,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
{ PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
{ PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
{ PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */
{ 0 } { 0 }
}; };
MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
...@@ -339,28 +340,4 @@ static struct pci_driver ath5k_pci_driver = { ...@@ -339,28 +340,4 @@ static struct pci_driver ath5k_pci_driver = {
.driver.pm = ATH5K_PM_OPS, .driver.pm = ATH5K_PM_OPS,
}; };
/* module_pci_driver(ath5k_pci_driver);
* Module init/exit functions
*/
static int __init
init_ath5k_pci(void)
{
int ret;
ret = pci_register_driver(&ath5k_pci_driver);
if (ret) {
pr_err("pci: can't register pci driver\n");
return ret;
}
return 0;
}
static void __exit
exit_ath5k_pci(void)
{
pci_unregister_driver(&ath5k_pci_driver);
}
module_init(init_ath5k_pci);
module_exit(exit_ath5k_pci);
...@@ -110,7 +110,7 @@ static const unsigned int ack_rates_high[] = ...@@ -110,7 +110,7 @@ static const unsigned int ack_rates_high[] =
* bwmodes. * bwmodes.
*/ */
int int
ath5k_hw_get_frame_duration(struct ath5k_hw *ah, ath5k_hw_get_frame_duration(struct ath5k_hw *ah, enum ieee80211_band band,
int len, struct ieee80211_rate *rate, bool shortpre) int len, struct ieee80211_rate *rate, bool shortpre)
{ {
int sifs, preamble, plcp_bits, sym_time; int sifs, preamble, plcp_bits, sym_time;
...@@ -120,7 +120,7 @@ ath5k_hw_get_frame_duration(struct ath5k_hw *ah, ...@@ -120,7 +120,7 @@ ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
/* Fallback */ /* Fallback */
if (!ah->ah_bwmode) { if (!ah->ah_bwmode) {
__le16 raw_dur = ieee80211_generic_frame_duration(ah->hw, __le16 raw_dur = ieee80211_generic_frame_duration(ah->hw,
NULL, len, rate); NULL, band, len, rate);
/* subtract difference between long and short preamble */ /* subtract difference between long and short preamble */
dur = le16_to_cpu(raw_dur); dur = le16_to_cpu(raw_dur);
...@@ -302,14 +302,15 @@ ath5k_hw_write_rate_duration(struct ath5k_hw *ah) ...@@ -302,14 +302,15 @@ ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
* actual rate for this rate. See mac80211 tx.c * actual rate for this rate. See mac80211 tx.c
* ieee80211_duration() for a brief description of * ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */ * what rate we should choose to TX ACKs. */
tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); tx_time = ath5k_hw_get_frame_duration(ah, band, 10,
rate, false);
ath5k_hw_reg_write(ah, tx_time, reg); ath5k_hw_reg_write(ah, tx_time, reg);
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
continue; continue;
tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, true);
ath5k_hw_reg_write(ah, tx_time, ath5k_hw_reg_write(ah, tx_time,
reg + (AR5K_SET_SHORT_PREAMBLE << 2)); reg + (AR5K_SET_SHORT_PREAMBLE << 2));
} }
......
...@@ -565,6 +565,7 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) ...@@ -565,6 +565,7 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
{ {
struct ieee80211_channel *channel = ah->ah_current_channel; struct ieee80211_channel *channel = ah->ah_current_channel;
enum ieee80211_band band;
struct ieee80211_rate *rate; struct ieee80211_rate *rate;
u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock; u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
...@@ -600,11 +601,12 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) ...@@ -600,11 +601,12 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
* Also we have different lowest rate for 802.11a * Also we have different lowest rate for 802.11a
*/ */
if (channel->band == IEEE80211_BAND_5GHZ) if (channel->band == IEEE80211_BAND_5GHZ)
rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; band = IEEE80211_BAND_5GHZ;
else else
rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; band = IEEE80211_BAND_2GHZ;
ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); rate = &ah->sbands[band].bitrates[0];
ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false);
/* ack_tx_time includes an SIFS already */ /* ack_tx_time includes an SIFS already */
eifs = ack_tx_time + sifs + 2 * slot_time; eifs = ack_tx_time + sifs + 2 * slot_time;
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
obj-$(CONFIG_ATH6KL) += ath6kl_core.o obj-$(CONFIG_ATH6KL) += ath6kl_core.o
ath6kl_core-y += debug.o ath6kl_core-y += debug.o
ath6kl_core-y += hif.o ath6kl_core-y += hif.o
ath6kl_core-y += htc.o ath6kl_core-y += htc_mbox.o
ath6kl_core-y += htc_pipe.o
ath6kl_core-y += bmi.o ath6kl_core-y += bmi.o
ath6kl_core-y += cfg80211.o ath6kl_core-y += cfg80211.o
ath6kl_core-y += init.o ath6kl_core-y += init.o
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
.max_power = 30, \ .max_power = 30, \
} }
#define DEFAULT_BG_SCAN_PERIOD 60
static struct ieee80211_rate ath6kl_rates[] = { static struct ieee80211_rate ath6kl_rates[] = {
RATETAB_ENT(10, 0x1, 0), RATETAB_ENT(10, 0x1, 0),
RATETAB_ENT(20, 0x2, 0), RATETAB_ENT(20, 0x2, 0),
...@@ -71,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = { ...@@ -71,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = {
#define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates (ath6kl_rates + 0)
#define ath6kl_g_rates_size 12 #define ath6kl_g_rates_size 12
#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ #define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20
#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_20 | \
IEEE80211_HT_CAP_SGI_40) IEEE80211_HT_CAP_SGI_40)
...@@ -128,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { ...@@ -128,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
.channels = ath6kl_5ghz_a_channels, .channels = ath6kl_5ghz_a_channels,
.n_bitrates = ath6kl_a_rates_size, .n_bitrates = ath6kl_a_rates_size,
.bitrates = ath6kl_a_rates, .bitrates = ath6kl_a_rates,
.ht_cap.cap = ath6kl_g_htcap, .ht_cap.cap = ath6kl_a_htcap,
.ht_cap.ht_supported = true, .ht_cap.ht_supported = true,
}; };
...@@ -609,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -609,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->req_bssid, vif->ch_hint, vif->req_bssid, vif->ch_hint,
ar->connect_ctrl_flags, nw_subtype); ar->connect_ctrl_flags, nw_subtype);
/* disable background scan if period is 0 */
if (sme->bg_scan_period == 0)
sme->bg_scan_period = 0xffff;
/* configure default value if not specified */
if (sme->bg_scan_period == -1)
sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
up(&ar->sem); up(&ar->sem);
if (status == -EINVAL) { if (status == -EINVAL) {
...@@ -943,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ...@@ -943,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (test_bit(CONNECTED, &vif->flags)) if (test_bit(CONNECTED, &vif->flags))
force_fg_scan = 1; force_fg_scan = 1;
vif->scan_req = request;
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
ar->fw_capabilities)) { ar->fw_capabilities)) {
/* /*
...@@ -965,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ...@@ -965,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
ATH6KL_FG_SCAN_INTERVAL, ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels); n_channels, channels);
} }
if (ret) if (ret) {
ath6kl_err("wmi_startscan_cmd failed\n"); ath6kl_err("wmi_startscan_cmd failed\n");
else vif->scan_req = NULL;
vif->scan_req = request; }
kfree(channels); kfree(channels);
...@@ -1438,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, ...@@ -1438,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
struct vif_params *params) struct vif_params *params)
{ {
struct ath6kl_vif *vif = netdev_priv(ndev); struct ath6kl_vif *vif = netdev_priv(ndev);
int i;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
/*
* Don't bring up p2p on an interface which is not initialized
* for p2p operation where fw does not have capability to switch
* dynamically between non-p2p and p2p type interface.
*/
if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
vif->ar->fw_capabilities) &&
(type == NL80211_IFTYPE_P2P_CLIENT ||
type == NL80211_IFTYPE_P2P_GO)) {
if (vif->ar->vif_max == 1) {
if (vif->fw_vif_idx != 0)
return -EINVAL;
else
goto set_iface_type;
}
for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) {
if (i == vif->fw_vif_idx)
break;
}
if (i == vif->ar->vif_max) {
ath6kl_err("Invalid interface to bring up P2P\n");
return -EINVAL;
}
}
set_iface_type:
switch (type) { switch (type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
vif->next_mode = INFRA_NETWORK; vif->next_mode = INFRA_NETWORK;
...@@ -1926,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) ...@@ -1926,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
return 0; return 0;
} }
static int is_hsleep_mode_procsed(struct ath6kl_vif *vif)
{
return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
}
static bool is_ctrl_ep_empty(struct ath6kl *ar)
{
return !ar->tx_pending[ar->ctrl_ep];
}
static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
{
int ret, left;
clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_ASLEEP);
if (ret)
return ret;
left = wait_event_interruptible_timeout(ar->event_wq,
is_hsleep_mode_procsed(vif),
WMI_TIMEOUT);
if (left == 0) {
ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
ret = -ETIMEDOUT;
} else if (left < 0) {
ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
left);
ret = left;
}
if (ar->tx_pending[ar->ctrl_ep]) {
left = wait_event_interruptible_timeout(ar->event_wq,
is_ctrl_ep_empty(ar),
WMI_TIMEOUT);
if (left == 0) {
ath6kl_warn("clear wmi ctrl data timeout\n");
ret = -ETIMEDOUT;
} else if (left < 0) {
ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
ret = left;
}
}
return ret;
}
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
{ {
struct in_device *in_dev; struct in_device *in_dev;
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
struct ath6kl_vif *vif; struct ath6kl_vif *vif;
int ret, left; int ret;
u32 filter = 0; u32 filter = 0;
u16 i, bmiss_time; u16 i, bmiss_time;
u8 index = 0; u8 index = 0;
...@@ -2032,39 +2126,11 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -2032,39 +2126,11 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (ret) if (ret)
return ret; return ret;
clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); ret = ath6kl_cfg80211_host_sleep(ar, vif);
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_ASLEEP);
if (ret) if (ret)
return ret; return ret;
left = wait_event_interruptible_timeout(ar->event_wq, return 0;
test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags),
WMI_TIMEOUT);
if (left == 0) {
ath6kl_warn("timeout, didn't get host sleep cmd "
"processed event\n");
ret = -ETIMEDOUT;
} else if (left < 0) {
ath6kl_warn("error while waiting for host sleep cmd "
"processed event %d\n", left);
ret = left;
}
if (ar->tx_pending[ar->ctrl_ep]) {
left = wait_event_interruptible_timeout(ar->event_wq,
ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
if (left == 0) {
ath6kl_warn("clear wmi ctrl data timeout\n");
ret = -ETIMEDOUT;
} else if (left < 0) {
ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
ret = left;
}
}
return ret;
} }
static int ath6kl_wow_resume(struct ath6kl *ar) static int ath6kl_wow_resume(struct ath6kl *ar)
...@@ -2111,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ...@@ -2111,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
return 0; return 0;
} }
static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
{
struct ath6kl_vif *vif;
int ret;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
ath6kl_cfg80211_stop_all(ar);
/* Save the current power mode before enabling power save */
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
if (ret)
return ret;
/* Disable WOW mode */
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_DISABLE,
0, 0);
if (ret)
return ret;
/* Flush all non control pkts in TX path */
ath6kl_tx_data_cleanup(ar);
ret = ath6kl_cfg80211_host_sleep(ar, vif);
if (ret)
return ret;
return 0;
}
static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar)
{
struct ath6kl_vif *vif;
int ret;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
ar->wmi->saved_pwr_mode);
if (ret)
return ret;
}
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ret)
return ret;
ar->state = ATH6KL_STATE_ON;
/* Reset scan parameter to default values */
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
if (ret)
return ret;
return 0;
}
int ath6kl_cfg80211_suspend(struct ath6kl *ar, int ath6kl_cfg80211_suspend(struct ath6kl *ar,
enum ath6kl_cfg_suspend_mode mode, enum ath6kl_cfg_suspend_mode mode,
struct cfg80211_wowlan *wow) struct cfg80211_wowlan *wow)
{ {
struct ath6kl_vif *vif;
enum ath6kl_state prev_state; enum ath6kl_state prev_state;
int ret; int ret;
...@@ -2139,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, ...@@ -2139,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
case ATH6KL_CFG_SUSPEND_DEEPSLEEP: case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
ath6kl_cfg80211_stop_all(ar); ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n");
/* save the current power mode before enabling power save */
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); ret = ath6kl_cfg80211_deepsleep_suspend(ar);
if (ret) { if (ret) {
ath6kl_warn("wmi powermode command failed during suspend: %d\n", ath6kl_err("deepsleep suspend failed: %d\n", ret);
ret); return ret;
} }
ar->state = ATH6KL_STATE_DEEPSLEEP; ar->state = ATH6KL_STATE_DEEPSLEEP;
...@@ -2187,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, ...@@ -2187,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
break; break;
} }
list_for_each_entry(vif, &ar->vif_list, list)
ath6kl_cfg80211_scan_complete_event(vif, true);
return 0; return 0;
} }
EXPORT_SYMBOL(ath6kl_cfg80211_suspend); EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
...@@ -2208,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) ...@@ -2208,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
break; break;
case ATH6KL_STATE_DEEPSLEEP: case ATH6KL_STATE_DEEPSLEEP:
if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
ar->wmi->saved_pwr_mode);
if (ret) {
ath6kl_warn("wmi powermode command failed during resume: %d\n",
ret);
}
}
ar->state = ATH6KL_STATE_ON;
ret = ath6kl_cfg80211_deepsleep_resume(ar);
if (ret) {
ath6kl_warn("deep sleep resume failed: %d\n", ret);
return ret;
}
break; break;
case ATH6KL_STATE_CUTPOWER: case ATH6KL_STATE_CUTPOWER:
...@@ -2292,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar) ...@@ -2292,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
} }
#endif #endif
static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
struct ieee80211_channel *chan, bool ht_enable)
enum nl80211_channel_type channel_type)
{ {
struct ath6kl_vif *vif; struct ath6kl_htcap *htcap = &vif->htcap;
/*
* 'dev' could be NULL if a channel change is required for the hardware
* device itself, instead of a particular VIF.
*
* FIXME: To be handled properly when monitor mode is supported.
*/
if (!dev)
return -EBUSY;
vif = netdev_priv(dev);
if (!ath6kl_cfg80211_ready(vif)) if (htcap->ht_enable == ht_enable)
return -EIO; return 0;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", if (ht_enable) {
__func__, chan->center_freq, chan->hw_value); /* Set default ht capabilities */
vif->next_chan = chan->center_freq; htcap->ht_enable = true;
htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ?
ath6kl_g_htcap : ath6kl_a_htcap;
htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K;
} else /* Disable ht */
memset(htcap, 0, sizeof(*htcap));
return 0; return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx,
band, htcap);
} }
static bool ath6kl_is_p2p_ie(const u8 *pos) static bool ath6kl_is_p2p_ie(const u8 *pos)
...@@ -2393,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, ...@@ -2393,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
return 0; return 0;
} }
static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
struct ath6kl_vif *vif;
/*
* 'dev' could be NULL if a channel change is required for the hardware
* device itself, instead of a particular VIF.
*
* FIXME: To be handled properly when monitor mode is supported.
*/
if (!dev)
return -EBUSY;
vif = netdev_priv(dev);
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
__func__, chan->center_freq, chan->hw_value);
vif->next_chan = chan->center_freq;
vif->next_ch_type = channel_type;
vif->next_ch_band = chan->band;
return 0;
}
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
u8 *rsn_capab)
{
const u8 *rsn_ie;
size_t rsn_ie_len;
u16 cnt;
if (!beacon->tail)
return -EINVAL;
rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len);
if (!rsn_ie)
return -EINVAL;
rsn_ie_len = *(rsn_ie + 1);
/* skip element id and length */
rsn_ie += 2;
/* skip version, group cipher */
if (rsn_ie_len < 6)
return -EINVAL;
rsn_ie += 6;
rsn_ie_len -= 6;
/* skip pairwise cipher suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
/* skip akm suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
if (rsn_ie_len < 2)
return -EINVAL;
memcpy(rsn_capab, rsn_ie, 2);
return 0;
}
static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ap_settings *info) struct cfg80211_ap_settings *info)
{ {
...@@ -2405,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2405,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
struct wmi_connect_cmd p; struct wmi_connect_cmd p;
int res; int res;
int i, ret; int i, ret;
u16 rsn_capab = 0;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
...@@ -2534,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2534,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
p.nw_subtype = SUBTYPE_NONE; p.nw_subtype = SUBTYPE_NONE;
} }
if (info->inactivity_timeout) {
res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
info->inactivity_timeout);
if (res < 0)
return res;
}
if (ath6kl_set_htcap(vif, vif->next_ch_band,
vif->next_ch_type != NL80211_CHAN_NO_HT))
return -EIO;
/*
* Get the PTKSA replay counter in the RSN IE. Supplicant
* will use the RSN IE in M3 message and firmware has to
* advertise the same in beacon/probe response. Send
* the complete RSN IE capability field to firmware
*/
if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) &&
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities)) {
res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
(const u8 *) &rsn_capab,
sizeof(rsn_capab));
if (res < 0)
return res;
}
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
if (res < 0) if (res < 0)
return res; return res;
...@@ -2568,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) ...@@ -2568,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
clear_bit(CONNECTED, &vif->flags); clear_bit(CONNECTED, &vif->flags);
/* Restore ht setting in firmware */
if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true))
return -EIO;
if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true))
return -EIO;
return 0; return 0;
} }
...@@ -2749,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, ...@@ -2749,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
return false; return false;
} }
/* Check if SSID length is greater than DIRECT- */
static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
{
const struct ieee80211_mgmt *mgmt;
mgmt = (const struct ieee80211_mgmt *) buf;
/* variable[1] contains the SSID tag length */
if (buf + len >= &mgmt->u.probe_resp.variable[1] &&
(mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) {
return true;
}
return false;
}
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
...@@ -2763,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -2763,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
bool more_data, queued; bool more_data, queued;
mgmt = (const struct ieee80211_mgmt *) buf; mgmt = (const struct ieee80211_mgmt *) buf;
if (buf + len >= mgmt->u.probe_resp.variable && if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && ieee80211_is_probe_resp(mgmt->frame_control) &&
ieee80211_is_probe_resp(mgmt->frame_control)) { ath6kl_is_p2p_go_ssid(buf, len)) {
/* /*
* Send Probe Response frame in AP mode using a separate WMI * Send Probe Response frame in GO mode using a separate WMI
* command to allow the target to fill in the generic IEs. * command to allow the target to fill in the generic IEs.
*/ */
*cookie = 0; /* TX status not supported */ *cookie = 0; /* TX status not supported */
...@@ -2835,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ...@@ -2835,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (vif->sme_state != SME_DISCONNECTED) if (vif->sme_state != SME_DISCONNECTED)
return -EBUSY; return -EBUSY;
ath6kl_cfg80211_scan_complete_event(vif, true);
for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, DISABLE_SSID_FLAG, i, DISABLE_SSID_FLAG,
...@@ -3096,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, ...@@ -3096,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
vif->next_mode = nw_type; vif->next_mode = nw_type;
vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
vif->htcap.ht_enable = true;
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
if (fw_vif_idx != 0) if (fw_vif_idx != 0)
...@@ -3183,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ...@@ -3183,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
ar->fw_capabilities))
ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER;
ar->wiphy->probe_resp_offload = ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
......
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
#define ATH6KL_MAX_IE 256 #define ATH6KL_MAX_IE 256
extern int ath6kl_printk(const char *level, const char *fmt, ...); extern __printf(2, 3)
int ath6kl_printk(const char *level, const char *fmt, ...);
/* /*
* Reflects the version of binary interface exposed by ATH6KL target * Reflects the version of binary interface exposed by ATH6KL target
...@@ -77,6 +78,7 @@ enum crypto_type { ...@@ -77,6 +78,7 @@ enum crypto_type {
struct htc_endpoint_credit_dist; struct htc_endpoint_credit_dist;
struct ath6kl; struct ath6kl;
struct ath6kl_htcap;
enum htc_credit_dist_reason; enum htc_credit_dist_reason;
struct ath6kl_htc_credit_info; struct ath6kl_htc_credit_info;
......
...@@ -20,9 +20,11 @@ ...@@ -20,9 +20,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/vmalloc.h>
#include "debug.h" #include "debug.h"
#include "hif-ops.h" #include "hif-ops.h"
#include "htc-ops.h"
#include "cfg80211.h" #include "cfg80211.h"
unsigned int debug_mask; unsigned int debug_mask;
...@@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644); ...@@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644);
module_param(ath6kl_p2p, uint, 0644); module_param(ath6kl_p2p, uint, 0644);
module_param(testmode, uint, 0644); module_param(testmode, uint, 0644);
int ath6kl_core_init(struct ath6kl *ar) void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
{
ath6kl_htc_tx_complete(ar, skb);
}
EXPORT_SYMBOL(ath6kl_core_tx_complete);
void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe)
{
ath6kl_htc_rx_complete(ar, skb, pipe);
}
EXPORT_SYMBOL(ath6kl_core_rx_complete);
int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
{ {
struct ath6kl_bmi_target_info targ_info; struct ath6kl_bmi_target_info targ_info;
struct net_device *ndev; struct net_device *ndev;
int ret = 0, i; int ret = 0, i;
switch (htc_type) {
case ATH6KL_HTC_TYPE_MBOX:
ath6kl_htc_mbox_attach(ar);
break;
case ATH6KL_HTC_TYPE_PIPE:
ath6kl_htc_pipe_attach(ar);
break;
default:
WARN_ON(1);
return -ENOMEM;
}
ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
if (!ar->ath6kl_wq) if (!ar->ath6kl_wq)
return -ENOMEM; return -ENOMEM;
...@@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar) ...@@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
kfree(ar->fw_board); kfree(ar->fw_board);
kfree(ar->fw_otp); kfree(ar->fw_otp);
kfree(ar->fw); vfree(ar->fw);
kfree(ar->fw_patch); kfree(ar->fw_patch);
kfree(ar->fw_testscript); kfree(ar->fw_testscript);
......
...@@ -91,6 +91,15 @@ enum ath6kl_fw_capability { ...@@ -91,6 +91,15 @@ enum ath6kl_fw_capability {
*/ */
ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
/*
* Firmware has support to cleanup inactive stations
* in AP mode.
*/
ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
/* Firmware has support to override rsn cap of rsn ie */
ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
/* this needs to be last */ /* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX, ATH6KL_FW_CAPABILITY_MAX,
}; };
...@@ -205,6 +214,8 @@ struct ath6kl_fw_ie { ...@@ -205,6 +214,8 @@ struct ath6kl_fw_ie {
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
#define ATH6KL_CONF_UART_DEBUG BIT(4) #define ATH6KL_CONF_UART_DEBUG BIT(4)
#define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */
enum wlan_low_pwr_state { enum wlan_low_pwr_state {
WLAN_POWER_STATE_ON, WLAN_POWER_STATE_ON,
WLAN_POWER_STATE_CUT_PWR, WLAN_POWER_STATE_CUT_PWR,
...@@ -454,6 +465,11 @@ enum ath6kl_hif_type { ...@@ -454,6 +465,11 @@ enum ath6kl_hif_type {
ATH6KL_HIF_TYPE_USB, ATH6KL_HIF_TYPE_USB,
}; };
enum ath6kl_htc_type {
ATH6KL_HTC_TYPE_MBOX,
ATH6KL_HTC_TYPE_PIPE,
};
/* Max number of filters that hw supports */ /* Max number of filters that hw supports */
#define ATH6K_MAX_MC_FILTERS_PER_LIST 7 #define ATH6K_MAX_MC_FILTERS_PER_LIST 7
struct ath6kl_mc_filter { struct ath6kl_mc_filter {
...@@ -461,6 +477,12 @@ struct ath6kl_mc_filter { ...@@ -461,6 +477,12 @@ struct ath6kl_mc_filter {
char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
}; };
struct ath6kl_htcap {
bool ht_enable;
u8 ampdu_factor;
unsigned short cap_info;
};
/* /*
* Driver's maximum limit, note that some firmwares support only one vif * Driver's maximum limit, note that some firmwares support only one vif
* and the runtime (current) limit must be checked from ar->vif_max. * and the runtime (current) limit must be checked from ar->vif_max.
...@@ -509,6 +531,7 @@ struct ath6kl_vif { ...@@ -509,6 +531,7 @@ struct ath6kl_vif {
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
struct aggr_info *aggr_cntxt; struct aggr_info *aggr_cntxt;
struct ath6kl_htcap htcap;
struct timer_list disconnect_timer; struct timer_list disconnect_timer;
struct timer_list sched_scan_timer; struct timer_list sched_scan_timer;
...@@ -521,6 +544,8 @@ struct ath6kl_vif { ...@@ -521,6 +544,8 @@ struct ath6kl_vif {
u32 send_action_id; u32 send_action_id;
bool probe_req_report; bool probe_req_report;
u16 next_chan; u16 next_chan;
enum nl80211_channel_type next_ch_type;
enum ieee80211_band next_ch_band;
u16 assoc_bss_beacon_int; u16 assoc_bss_beacon_int;
u16 listen_intvl_t; u16 listen_intvl_t;
u16 bmiss_time_t; u16 bmiss_time_t;
...@@ -568,6 +593,7 @@ struct ath6kl { ...@@ -568,6 +593,7 @@ struct ath6kl {
struct ath6kl_bmi bmi; struct ath6kl_bmi bmi;
const struct ath6kl_hif_ops *hif_ops; const struct ath6kl_hif_ops *hif_ops;
const struct ath6kl_htc_ops *htc_ops;
struct wmi *wmi; struct wmi *wmi;
int tx_pending[ENDPOINT_MAX]; int tx_pending[ENDPOINT_MAX];
int total_tx_data_pend; int total_tx_data_pend;
...@@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev); ...@@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev);
void ath6kl_cookie_init(struct ath6kl *ar); void ath6kl_cookie_init(struct ath6kl *ar);
void ath6kl_cookie_cleanup(struct ath6kl *ar); void ath6kl_cookie_cleanup(struct ath6kl *ar);
void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
void ath6kl_tx_complete(void *context, struct list_head *packet_queue); void ath6kl_tx_complete(struct htc_target *context,
struct list_head *packet_queue);
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
struct htc_packet *packet); struct htc_packet *packet);
void ath6kl_stop_txrx(struct ath6kl *ar); void ath6kl_stop_txrx(struct ath6kl *ar);
...@@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar); ...@@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar);
void ath6kl_check_wow_status(struct ath6kl *ar); void ath6kl_check_wow_status(struct ath6kl *ar);
void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb);
void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe);
struct ath6kl *ath6kl_core_create(struct device *dev); struct ath6kl *ath6kl_core_create(struct device *dev);
int ath6kl_core_init(struct ath6kl *ar); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_cleanup(struct ath6kl *ar);
void ath6kl_core_destroy(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar);
......
...@@ -616,6 +616,12 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, ...@@ -616,6 +616,12 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
"Num disconnects", tgt_stats->cs_discon_cnt); "Num disconnects", tgt_stats->cs_discon_cnt);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"ARP pkt received", tgt_stats->arp_received);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"ARP pkt matched", tgt_stats->arp_matched);
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
"ARP pkt replied", tgt_stats->arp_replied);
if (len > buf_len) if (len > buf_len)
len = buf_len; len = buf_len;
......
...@@ -43,6 +43,7 @@ enum ATH6K_DEBUG_MASK { ...@@ -43,6 +43,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_WMI_DUMP = BIT(19), ATH6KL_DBG_WMI_DUMP = BIT(19),
ATH6KL_DBG_SUSPEND = BIT(20), ATH6KL_DBG_SUSPEND = BIT(20),
ATH6KL_DBG_USB = BIT(21), ATH6KL_DBG_USB = BIT(21),
ATH6KL_DBG_USB_BULK = BIT(22),
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
}; };
......
...@@ -150,4 +150,38 @@ static inline void ath6kl_hif_stop(struct ath6kl *ar) ...@@ -150,4 +150,38 @@ static inline void ath6kl_hif_stop(struct ath6kl *ar)
ar->hif_ops->stop(ar); ar->hif_ops->stop(ar);
} }
static inline int ath6kl_hif_pipe_send(struct ath6kl *ar,
u8 pipe, struct sk_buff *hdr_buf,
struct sk_buff *buf)
{
ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe send\n");
return ar->hif_ops->pipe_send(ar, pipe, hdr_buf, buf);
}
static inline void ath6kl_hif_pipe_get_default(struct ath6kl *ar,
u8 *ul_pipe, u8 *dl_pipe)
{
ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get default\n");
ar->hif_ops->pipe_get_default(ar, ul_pipe, dl_pipe);
}
static inline int ath6kl_hif_pipe_map_service(struct ath6kl *ar,
u16 service_id, u8 *ul_pipe,
u8 *dl_pipe)
{
ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get default\n");
return ar->hif_ops->pipe_map_service(ar, service_id, ul_pipe, dl_pipe);
}
static inline u16 ath6kl_hif_pipe_get_free_queue_number(struct ath6kl *ar,
u8 pipe)
{
ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get free queue number\n");
return ar->hif_ops->pipe_get_free_queue_number(ar, pipe);
}
#endif #endif
...@@ -256,6 +256,12 @@ struct ath6kl_hif_ops { ...@@ -256,6 +256,12 @@ struct ath6kl_hif_ops {
int (*power_on)(struct ath6kl *ar); int (*power_on)(struct ath6kl *ar);
int (*power_off)(struct ath6kl *ar); int (*power_off)(struct ath6kl *ar);
void (*stop)(struct ath6kl *ar); void (*stop)(struct ath6kl *ar);
int (*pipe_send)(struct ath6kl *ar, u8 pipe, struct sk_buff *hdr_buf,
struct sk_buff *buf);
void (*pipe_get_default)(struct ath6kl *ar, u8 *pipe_ul, u8 *pipe_dl);
int (*pipe_map_service)(struct ath6kl *ar, u16 service_id, u8 *pipe_ul,
u8 *pipe_dl);
u16 (*pipe_get_free_queue_number)(struct ath6kl *ar, u8 pipe);
}; };
int ath6kl_hif_setup(struct ath6kl_device *dev); int ath6kl_hif_setup(struct ath6kl_device *dev);
......
/*
* Copyright (c) 2004-2011 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef HTC_OPS_H
#define HTC_OPS_H
#include "htc.h"
#include "debug.h"
static inline void *ath6kl_htc_create(struct ath6kl *ar)
{
return ar->htc_ops->create(ar);
}
static inline int ath6kl_htc_wait_target(struct htc_target *target)
{
return target->dev->ar->htc_ops->wait_target(target);
}
static inline int ath6kl_htc_start(struct htc_target *target)
{
return target->dev->ar->htc_ops->start(target);
}
static inline int ath6kl_htc_conn_service(struct htc_target *target,
struct htc_service_connect_req *req,
struct htc_service_connect_resp *resp)
{
return target->dev->ar->htc_ops->conn_service(target, req, resp);
}
static inline int ath6kl_htc_tx(struct htc_target *target,
struct htc_packet *packet)
{
return target->dev->ar->htc_ops->tx(target, packet);
}
static inline void ath6kl_htc_stop(struct htc_target *target)
{
return target->dev->ar->htc_ops->stop(target);
}
static inline void ath6kl_htc_cleanup(struct htc_target *target)
{
return target->dev->ar->htc_ops->cleanup(target);
}
static inline void ath6kl_htc_flush_txep(struct htc_target *target,
enum htc_endpoint_id endpoint,
u16 tag)
{
return target->dev->ar->htc_ops->flush_txep(target, endpoint, tag);
}
static inline void ath6kl_htc_flush_rx_buf(struct htc_target *target)
{
return target->dev->ar->htc_ops->flush_rx_buf(target);
}
static inline void ath6kl_htc_activity_changed(struct htc_target *target,
enum htc_endpoint_id endpoint,
bool active)
{
return target->dev->ar->htc_ops->activity_changed(target, endpoint,
active);
}
static inline int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
enum htc_endpoint_id endpoint)
{
return target->dev->ar->htc_ops->get_rxbuf_num(target, endpoint);
}
static inline int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
struct list_head *pktq)
{
return target->dev->ar->htc_ops->add_rxbuf_multiple(target, pktq);
}
static inline int ath6kl_htc_credit_setup(struct htc_target *target,
struct ath6kl_htc_credit_info *info)
{
return target->dev->ar->htc_ops->credit_setup(target, info);
}
static inline void ath6kl_htc_tx_complete(struct ath6kl *ar,
struct sk_buff *skb)
{
ar->htc_ops->tx_complete(ar, skb);
}
static inline void ath6kl_htc_rx_complete(struct ath6kl *ar,
struct sk_buff *skb, u8 pipe)
{
ar->htc_ops->rx_complete(ar, skb, pipe);
}
#endif
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
/* send direction */ /* send direction */
#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) #define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
#define HTC_FLAGS_SEND_BUNDLE (1 << 1) #define HTC_FLAGS_SEND_BUNDLE (1 << 1)
#define HTC_FLAGS_TX_FIXUP_NETBUF (1 << 2)
/* receive direction */ /* receive direction */
#define HTC_FLG_RX_UNUSED (1 << 0) #define HTC_FLG_RX_UNUSED (1 << 0)
...@@ -56,6 +57,10 @@ ...@@ -56,6 +57,10 @@
#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2 #define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2
#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4 #define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4
#define HTC_CONN_FLGS_THRESH_MASK 0x3 #define HTC_CONN_FLGS_THRESH_MASK 0x3
/* disable credit flow control on a specific service */
#define HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL (1 << 3)
#define HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT 8
#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK 0xFF00
/* connect response status codes */ /* connect response status codes */
#define HTC_SERVICE_SUCCESS 0 #define HTC_SERVICE_SUCCESS 0
...@@ -75,6 +80,7 @@ ...@@ -75,6 +80,7 @@
#define HTC_RECORD_LOOKAHEAD_BUNDLE 3 #define HTC_RECORD_LOOKAHEAD_BUNDLE 3
#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0) #define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0)
#define HTC_SETUP_COMP_FLG_DISABLE_TX_CREDIT_FLOW (1 << 1)
#define MAKE_SERVICE_ID(group, index) \ #define MAKE_SERVICE_ID(group, index) \
(int)(((int)group << 8) | (int)(index)) (int)(((int)group << 8) | (int)(index))
...@@ -109,6 +115,8 @@ ...@@ -109,6 +115,8 @@
/* HTC operational parameters */ /* HTC operational parameters */
#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ #define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
#define HTC_TARGET_RESPONSE_POLL_WAIT 10
#define HTC_TARGET_RESPONSE_POLL_COUNT 200
#define HTC_TARGET_DEBUG_INTR_MASK 0x01 #define HTC_TARGET_DEBUG_INTR_MASK 0x01
#define HTC_TARGET_CREDIT_INTR_MASK 0xF0 #define HTC_TARGET_CREDIT_INTR_MASK 0xF0
...@@ -128,6 +136,7 @@ ...@@ -128,6 +136,7 @@
#define HTC_RECV_WAIT_BUFFERS (1 << 0) #define HTC_RECV_WAIT_BUFFERS (1 << 0)
#define HTC_OP_STATE_STOPPING (1 << 0) #define HTC_OP_STATE_STOPPING (1 << 0)
#define HTC_OP_STATE_SETUP_COMPLETE (1 << 1)
/* /*
* The frame header length and message formats defined herein were selected * The frame header length and message formats defined herein were selected
...@@ -311,6 +320,14 @@ struct htc_packet { ...@@ -311,6 +320,14 @@ struct htc_packet {
void (*completion) (struct htc_target *, struct htc_packet *); void (*completion) (struct htc_target *, struct htc_packet *);
struct htc_target *context; struct htc_target *context;
/*
* optimization for network-oriented data, the HTC packet
* can pass the network buffer corresponding to the HTC packet
* lower layers may optimized the transfer knowing this is
* a network buffer
*/
struct sk_buff *skb;
}; };
enum htc_send_full_action { enum htc_send_full_action {
...@@ -319,12 +336,14 @@ enum htc_send_full_action { ...@@ -319,12 +336,14 @@ enum htc_send_full_action {
}; };
struct htc_ep_callbacks { struct htc_ep_callbacks {
void (*tx_complete) (struct htc_target *, struct htc_packet *);
void (*rx) (struct htc_target *, struct htc_packet *); void (*rx) (struct htc_target *, struct htc_packet *);
void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint); void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint);
enum htc_send_full_action (*tx_full) (struct htc_target *, enum htc_send_full_action (*tx_full) (struct htc_target *,
struct htc_packet *); struct htc_packet *);
struct htc_packet *(*rx_allocthresh) (struct htc_target *, struct htc_packet *(*rx_allocthresh) (struct htc_target *,
enum htc_endpoint_id, int); enum htc_endpoint_id, int);
void (*tx_comp_multi) (struct htc_target *, struct list_head *);
int rx_alloc_thresh; int rx_alloc_thresh;
int rx_refill_thresh; int rx_refill_thresh;
}; };
...@@ -502,6 +521,13 @@ struct htc_endpoint { ...@@ -502,6 +521,13 @@ struct htc_endpoint {
u32 conn_flags; u32 conn_flags;
struct htc_endpoint_stats ep_st; struct htc_endpoint_stats ep_st;
u16 tx_drop_packet_threshold; u16 tx_drop_packet_threshold;
struct {
u8 pipeid_ul;
u8 pipeid_dl;
struct list_head tx_lookup_queue;
bool tx_credit_flow_enabled;
} pipe;
}; };
struct htc_control_buffer { struct htc_control_buffer {
...@@ -509,6 +535,42 @@ struct htc_control_buffer { ...@@ -509,6 +535,42 @@ struct htc_control_buffer {
u8 *buf; u8 *buf;
}; };
struct htc_pipe_txcredit_alloc {
u16 service_id;
u8 credit_alloc;
};
enum htc_send_queue_result {
HTC_SEND_QUEUE_OK = 0, /* packet was queued */
HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */
};
struct ath6kl_htc_ops {
void* (*create)(struct ath6kl *ar);
int (*wait_target)(struct htc_target *target);
int (*start)(struct htc_target *target);
int (*conn_service)(struct htc_target *target,
struct htc_service_connect_req *req,
struct htc_service_connect_resp *resp);
int (*tx)(struct htc_target *target, struct htc_packet *packet);
void (*stop)(struct htc_target *target);
void (*cleanup)(struct htc_target *target);
void (*flush_txep)(struct htc_target *target,
enum htc_endpoint_id endpoint, u16 tag);
void (*flush_rx_buf)(struct htc_target *target);
void (*activity_changed)(struct htc_target *target,
enum htc_endpoint_id endpoint,
bool active);
int (*get_rxbuf_num)(struct htc_target *target,
enum htc_endpoint_id endpoint);
int (*add_rxbuf_multiple)(struct htc_target *target,
struct list_head *pktq);
int (*credit_setup)(struct htc_target *target,
struct ath6kl_htc_credit_info *cred_info);
int (*tx_complete)(struct ath6kl *ar, struct sk_buff *skb);
int (*rx_complete)(struct ath6kl *ar, struct sk_buff *skb, u8 pipe);
};
struct ath6kl_device; struct ath6kl_device;
/* our HTC target state */ /* our HTC target state */
...@@ -557,36 +619,19 @@ struct htc_target { ...@@ -557,36 +619,19 @@ struct htc_target {
/* counts the number of Tx without bundling continously per AC */ /* counts the number of Tx without bundling continously per AC */
u32 ac_tx_count[WMM_NUM_AC]; u32 ac_tx_count[WMM_NUM_AC];
struct {
struct htc_packet *htc_packet_pool;
u8 ctrl_response_buf[HTC_MAX_CTRL_MSG_LEN];
int ctrl_response_len;
bool ctrl_response_valid;
struct htc_pipe_txcredit_alloc txcredit_alloc[ENDPOINT_MAX];
} pipe;
}; };
void *ath6kl_htc_create(struct ath6kl *ar);
void ath6kl_htc_set_credit_dist(struct htc_target *target,
struct ath6kl_htc_credit_info *cred_info,
u16 svc_pri_order[], int len);
int ath6kl_htc_wait_target(struct htc_target *target);
int ath6kl_htc_start(struct htc_target *target);
int ath6kl_htc_conn_service(struct htc_target *target,
struct htc_service_connect_req *req,
struct htc_service_connect_resp *resp);
int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet);
void ath6kl_htc_stop(struct htc_target *target);
void ath6kl_htc_cleanup(struct htc_target *target);
void ath6kl_htc_flush_txep(struct htc_target *target,
enum htc_endpoint_id endpoint, u16 tag);
void ath6kl_htc_flush_rx_buf(struct htc_target *target);
void ath6kl_htc_indicate_activity_change(struct htc_target *target,
enum htc_endpoint_id endpoint,
bool active);
int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
enum htc_endpoint_id endpoint);
int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
struct list_head *pktq);
int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
u32 msg_look_ahead, int *n_pkts); u32 msg_look_ahead, int *n_pkts);
int ath6kl_credit_setup(void *htc_handle,
struct ath6kl_htc_credit_info *cred_info);
static inline void set_htc_pkt_info(struct htc_packet *packet, void *context, static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
u8 *buf, unsigned int len, u8 *buf, unsigned int len,
enum htc_endpoint_id eid, u16 tag) enum htc_endpoint_id eid, u16 tag)
...@@ -626,4 +671,7 @@ static inline int get_queue_depth(struct list_head *queue) ...@@ -626,4 +671,7 @@ static inline int get_queue_depth(struct list_head *queue)
return depth; return depth;
} }
void ath6kl_htc_pipe_attach(struct ath6kl *ar);
void ath6kl_htc_mbox_attach(struct ath6kl *ar);
#endif #endif
...@@ -23,6 +23,14 @@ ...@@ -23,6 +23,14 @@
#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
static void ath6kl_htc_mbox_cleanup(struct htc_target *target);
static void ath6kl_htc_mbox_stop(struct htc_target *target);
static int ath6kl_htc_mbox_add_rxbuf_multiple(struct htc_target *target,
struct list_head *pkt_queue);
static void ath6kl_htc_set_credit_dist(struct htc_target *target,
struct ath6kl_htc_credit_info *cred_info,
u16 svc_pri_order[], int len);
/* threshold to re-enable Tx bundling for an AC*/ /* threshold to re-enable Tx bundling for an AC*/
#define TX_RESUME_BUNDLE_THRESHOLD 1500 #define TX_RESUME_BUNDLE_THRESHOLD 1500
...@@ -130,8 +138,8 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, ...@@ -130,8 +138,8 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
} }
/* initialize and setup credit distribution */ /* initialize and setup credit distribution */
int ath6kl_credit_setup(void *htc_handle, static int ath6kl_htc_mbox_credit_setup(struct htc_target *htc_target,
struct ath6kl_htc_credit_info *cred_info) struct ath6kl_htc_credit_info *cred_info)
{ {
u16 servicepriority[5]; u16 servicepriority[5];
...@@ -144,7 +152,7 @@ int ath6kl_credit_setup(void *htc_handle, ...@@ -144,7 +152,7 @@ int ath6kl_credit_setup(void *htc_handle,
servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
/* set priority list */ /* set priority list */
ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5); ath6kl_htc_set_credit_dist(htc_target, cred_info, servicepriority, 5);
return 0; return 0;
} }
...@@ -432,7 +440,7 @@ static void htc_tx_complete(struct htc_endpoint *endpoint, ...@@ -432,7 +440,7 @@ static void htc_tx_complete(struct htc_endpoint *endpoint,
"htc tx complete ep %d pkts %d\n", "htc tx complete ep %d pkts %d\n",
endpoint->eid, get_queue_depth(txq)); endpoint->eid, get_queue_depth(txq));
ath6kl_tx_complete(endpoint->target->dev->ar, txq); ath6kl_tx_complete(endpoint->target, txq);
} }
static void htc_tx_comp_handler(struct htc_target *target, static void htc_tx_comp_handler(struct htc_target *target,
...@@ -1065,7 +1073,7 @@ static int htc_setup_tx_complete(struct htc_target *target) ...@@ -1065,7 +1073,7 @@ static int htc_setup_tx_complete(struct htc_target *target)
return status; return status;
} }
void ath6kl_htc_set_credit_dist(struct htc_target *target, static void ath6kl_htc_set_credit_dist(struct htc_target *target,
struct ath6kl_htc_credit_info *credit_info, struct ath6kl_htc_credit_info *credit_info,
u16 srvc_pri_order[], int list_len) u16 srvc_pri_order[], int list_len)
{ {
...@@ -1093,7 +1101,8 @@ void ath6kl_htc_set_credit_dist(struct htc_target *target, ...@@ -1093,7 +1101,8 @@ void ath6kl_htc_set_credit_dist(struct htc_target *target,
} }
} }
int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) static int ath6kl_htc_mbox_tx(struct htc_target *target,
struct htc_packet *packet)
{ {
struct htc_endpoint *endpoint; struct htc_endpoint *endpoint;
struct list_head queue; struct list_head queue;
...@@ -1121,7 +1130,7 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) ...@@ -1121,7 +1130,7 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
} }
/* flush endpoint TX queue */ /* flush endpoint TX queue */
void ath6kl_htc_flush_txep(struct htc_target *target, static void ath6kl_htc_mbox_flush_txep(struct htc_target *target,
enum htc_endpoint_id eid, u16 tag) enum htc_endpoint_id eid, u16 tag)
{ {
struct htc_packet *packet, *tmp_pkt; struct htc_packet *packet, *tmp_pkt;
...@@ -1173,12 +1182,13 @@ static void ath6kl_htc_flush_txep_all(struct htc_target *target) ...@@ -1173,12 +1182,13 @@ static void ath6kl_htc_flush_txep_all(struct htc_target *target)
if (endpoint->svc_id == 0) if (endpoint->svc_id == 0)
/* not in use.. */ /* not in use.. */
continue; continue;
ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL); ath6kl_htc_mbox_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL);
} }
} }
void ath6kl_htc_indicate_activity_change(struct htc_target *target, static void ath6kl_htc_mbox_activity_changed(struct htc_target *target,
enum htc_endpoint_id eid, bool active) enum htc_endpoint_id eid,
bool active)
{ {
struct htc_endpoint *endpoint = &target->endpoint[eid]; struct htc_endpoint *endpoint = &target->endpoint[eid];
bool dist = false; bool dist = false;
...@@ -1246,7 +1256,7 @@ static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet) ...@@ -1246,7 +1256,7 @@ static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet)
INIT_LIST_HEAD(&queue); INIT_LIST_HEAD(&queue);
list_add_tail(&packet->list, &queue); list_add_tail(&packet->list, &queue);
return ath6kl_htc_add_rxbuf_multiple(target, &queue); return ath6kl_htc_mbox_add_rxbuf_multiple(target, &queue);
} }
static void htc_reclaim_rxbuf(struct htc_target *target, static void htc_reclaim_rxbuf(struct htc_target *target,
...@@ -1353,7 +1363,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target, ...@@ -1353,7 +1363,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,
sizeof(*htc_hdr)); sizeof(*htc_hdr));
if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) { if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) {
ath6kl_warn("Rx buffer requested with invalid length\n"); ath6kl_warn("Rx buffer requested with invalid length htc_hdr:eid %d, flags 0x%x, len %d\n",
htc_hdr->eid, htc_hdr->flags,
le16_to_cpu(htc_hdr->payld_len));
return -EINVAL; return -EINVAL;
} }
...@@ -2288,7 +2300,7 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) ...@@ -2288,7 +2300,7 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
return NULL; return NULL;
} }
int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, static int ath6kl_htc_mbox_add_rxbuf_multiple(struct htc_target *target,
struct list_head *pkt_queue) struct list_head *pkt_queue)
{ {
struct htc_endpoint *endpoint; struct htc_endpoint *endpoint;
...@@ -2350,7 +2362,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, ...@@ -2350,7 +2362,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
return status; return status;
} }
void ath6kl_htc_flush_rx_buf(struct htc_target *target) static void ath6kl_htc_mbox_flush_rx_buf(struct htc_target *target)
{ {
struct htc_endpoint *endpoint; struct htc_endpoint *endpoint;
struct htc_packet *packet, *tmp_pkt; struct htc_packet *packet, *tmp_pkt;
...@@ -2392,7 +2404,7 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target) ...@@ -2392,7 +2404,7 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target)
} }
} }
int ath6kl_htc_conn_service(struct htc_target *target, static int ath6kl_htc_mbox_conn_service(struct htc_target *target,
struct htc_service_connect_req *conn_req, struct htc_service_connect_req *conn_req,
struct htc_service_connect_resp *conn_resp) struct htc_service_connect_resp *conn_resp)
{ {
...@@ -2564,7 +2576,7 @@ static void reset_ep_state(struct htc_target *target) ...@@ -2564,7 +2576,7 @@ static void reset_ep_state(struct htc_target *target)
INIT_LIST_HEAD(&target->cred_dist_list); INIT_LIST_HEAD(&target->cred_dist_list);
} }
int ath6kl_htc_get_rxbuf_num(struct htc_target *target, static int ath6kl_htc_mbox_get_rxbuf_num(struct htc_target *target,
enum htc_endpoint_id endpoint) enum htc_endpoint_id endpoint)
{ {
int num; int num;
...@@ -2624,7 +2636,7 @@ static void htc_setup_msg_bndl(struct htc_target *target) ...@@ -2624,7 +2636,7 @@ static void htc_setup_msg_bndl(struct htc_target *target)
} }
} }
int ath6kl_htc_wait_target(struct htc_target *target) static int ath6kl_htc_mbox_wait_target(struct htc_target *target)
{ {
struct htc_packet *packet = NULL; struct htc_packet *packet = NULL;
struct htc_ready_ext_msg *rdy_msg; struct htc_ready_ext_msg *rdy_msg;
...@@ -2693,12 +2705,12 @@ int ath6kl_htc_wait_target(struct htc_target *target) ...@@ -2693,12 +2705,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
connect.svc_id = HTC_CTRL_RSVD_SVC; connect.svc_id = HTC_CTRL_RSVD_SVC;
/* connect fake service */ /* connect fake service */
status = ath6kl_htc_conn_service((void *)target, &connect, &resp); status = ath6kl_htc_mbox_conn_service((void *)target, &connect, &resp);
if (status) if (status)
/* /*
* FIXME: this call doesn't make sense, the caller should * FIXME: this call doesn't make sense, the caller should
* call ath6kl_htc_cleanup() when it wants remove htc * call ath6kl_htc_mbox_cleanup() when it wants remove htc
*/ */
ath6kl_hif_cleanup_scatter(target->dev->ar); ath6kl_hif_cleanup_scatter(target->dev->ar);
...@@ -2715,7 +2727,7 @@ int ath6kl_htc_wait_target(struct htc_target *target) ...@@ -2715,7 +2727,7 @@ int ath6kl_htc_wait_target(struct htc_target *target)
* Start HTC, enable interrupts and let the target know * Start HTC, enable interrupts and let the target know
* host has finished setup. * host has finished setup.
*/ */
int ath6kl_htc_start(struct htc_target *target) static int ath6kl_htc_mbox_start(struct htc_target *target)
{ {
struct htc_packet *packet; struct htc_packet *packet;
int status; int status;
...@@ -2752,7 +2764,7 @@ int ath6kl_htc_start(struct htc_target *target) ...@@ -2752,7 +2764,7 @@ int ath6kl_htc_start(struct htc_target *target)
status = ath6kl_hif_unmask_intrs(target->dev); status = ath6kl_hif_unmask_intrs(target->dev);
if (status) if (status)
ath6kl_htc_stop(target); ath6kl_htc_mbox_stop(target);
return status; return status;
} }
...@@ -2796,7 +2808,7 @@ static int ath6kl_htc_reset(struct htc_target *target) ...@@ -2796,7 +2808,7 @@ static int ath6kl_htc_reset(struct htc_target *target)
} }
/* htc_stop: stop interrupt reception, and flush all queued buffers */ /* htc_stop: stop interrupt reception, and flush all queued buffers */
void ath6kl_htc_stop(struct htc_target *target) static void ath6kl_htc_mbox_stop(struct htc_target *target)
{ {
spin_lock_bh(&target->htc_lock); spin_lock_bh(&target->htc_lock);
target->htc_flags |= HTC_OP_STATE_STOPPING; target->htc_flags |= HTC_OP_STATE_STOPPING;
...@@ -2811,12 +2823,12 @@ void ath6kl_htc_stop(struct htc_target *target) ...@@ -2811,12 +2823,12 @@ void ath6kl_htc_stop(struct htc_target *target)
ath6kl_htc_flush_txep_all(target); ath6kl_htc_flush_txep_all(target);
ath6kl_htc_flush_rx_buf(target); ath6kl_htc_mbox_flush_rx_buf(target);
ath6kl_htc_reset(target); ath6kl_htc_reset(target);
} }
void *ath6kl_htc_create(struct ath6kl *ar) static void *ath6kl_htc_mbox_create(struct ath6kl *ar)
{ {
struct htc_target *target = NULL; struct htc_target *target = NULL;
int status = 0; int status = 0;
...@@ -2857,13 +2869,13 @@ void *ath6kl_htc_create(struct ath6kl *ar) ...@@ -2857,13 +2869,13 @@ void *ath6kl_htc_create(struct ath6kl *ar)
return target; return target;
err_htc_cleanup: err_htc_cleanup:
ath6kl_htc_cleanup(target); ath6kl_htc_mbox_cleanup(target);
return NULL; return NULL;
} }
/* cleanup the HTC instance */ /* cleanup the HTC instance */
void ath6kl_htc_cleanup(struct htc_target *target) static void ath6kl_htc_mbox_cleanup(struct htc_target *target)
{ {
struct htc_packet *packet, *tmp_packet; struct htc_packet *packet, *tmp_packet;
...@@ -2888,3 +2900,24 @@ void ath6kl_htc_cleanup(struct htc_target *target) ...@@ -2888,3 +2900,24 @@ void ath6kl_htc_cleanup(struct htc_target *target)
kfree(target->dev); kfree(target->dev);
kfree(target); kfree(target);
} }
static const struct ath6kl_htc_ops ath6kl_htc_mbox_ops = {
.create = ath6kl_htc_mbox_create,
.wait_target = ath6kl_htc_mbox_wait_target,
.start = ath6kl_htc_mbox_start,
.conn_service = ath6kl_htc_mbox_conn_service,
.tx = ath6kl_htc_mbox_tx,
.stop = ath6kl_htc_mbox_stop,
.cleanup = ath6kl_htc_mbox_cleanup,
.flush_txep = ath6kl_htc_mbox_flush_txep,
.flush_rx_buf = ath6kl_htc_mbox_flush_rx_buf,
.activity_changed = ath6kl_htc_mbox_activity_changed,
.get_rxbuf_num = ath6kl_htc_mbox_get_rxbuf_num,
.add_rxbuf_multiple = ath6kl_htc_mbox_add_rxbuf_multiple,
.credit_setup = ath6kl_htc_mbox_credit_setup,
};
void ath6kl_htc_mbox_attach(struct ath6kl *ar)
{
ar->htc_ops = &ath6kl_htc_mbox_ops;
}
此差异已折叠。
...@@ -23,12 +23,14 @@ ...@@ -23,12 +23,14 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_func.h>
#include <linux/vmalloc.h>
#include "core.h" #include "core.h"
#include "cfg80211.h" #include "cfg80211.h"
#include "target.h" #include "target.h"
#include "debug.h" #include "debug.h"
#include "hif-ops.h" #include "hif-ops.h"
#include "htc-ops.h"
static const struct ath6kl_hw hw_list[] = { static const struct ath6kl_hw hw_list[] = {
{ {
...@@ -258,6 +260,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) ...@@ -258,6 +260,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
memset(&connect, 0, sizeof(connect)); memset(&connect, 0, sizeof(connect));
/* these fields are the same for all service endpoints */ /* these fields are the same for all service endpoints */
connect.ep_cb.tx_comp_multi = ath6kl_tx_complete;
connect.ep_cb.rx = ath6kl_rx; connect.ep_cb.rx = ath6kl_rx;
connect.ep_cb.rx_refill = ath6kl_rx_refill; connect.ep_cb.rx_refill = ath6kl_rx_refill;
connect.ep_cb.tx_full = ath6kl_tx_queue_full; connect.ep_cb.tx_full = ath6kl_tx_queue_full;
...@@ -487,22 +490,31 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -487,22 +490,31 @@ int ath6kl_configure_target(struct ath6kl *ar)
fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS); fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
/* /*
* By default, submodes : * Submodes when fw does not support dynamic interface
* switching:
* vif[0] - AP/STA/IBSS * vif[0] - AP/STA/IBSS
* vif[1] - "P2P dev"/"P2P GO"/"P2P Client" * vif[1] - "P2P dev"/"P2P GO"/"P2P Client"
* vif[2] - "P2P dev"/"P2P GO"/"P2P Client" * vif[2] - "P2P dev"/"P2P GO"/"P2P Client"
* Otherwise, All the interface are initialized to p2p dev.
*/ */
for (i = 0; i < ar->max_norm_iface; i++) if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
fw_submode |= HI_OPTION_FW_SUBMODE_NONE << ar->fw_capabilities)) {
(i * HI_OPTION_FW_SUBMODE_BITS); for (i = 0; i < ar->vif_max; i++)
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
(i * HI_OPTION_FW_SUBMODE_BITS);
} else {
for (i = 0; i < ar->max_norm_iface; i++)
fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
(i * HI_OPTION_FW_SUBMODE_BITS);
for (i = ar->max_norm_iface; i < ar->vif_max; i++) for (i = ar->max_norm_iface; i < ar->vif_max; i++)
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
(i * HI_OPTION_FW_SUBMODE_BITS); (i * HI_OPTION_FW_SUBMODE_BITS);
if (ar->p2p && ar->vif_max == 1) if (ar->p2p && ar->vif_max == 1)
fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
}
if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,
HTC_PROTOCOL_VERSION) != 0) { HTC_PROTOCOL_VERSION) != 0) {
...@@ -541,18 +553,20 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -541,18 +553,20 @@ int ath6kl_configure_target(struct ath6kl *ar)
* but possible in theory. * but possible in theory.
*/ */
param = ar->hw.board_ext_data_addr; if (ar->target_type == TARGET_TYPE_AR6003) {
ram_reserved_size = ar->hw.reserved_ram_size; param = ar->hw.board_ext_data_addr;
ram_reserved_size = ar->hw.reserved_ram_size;
if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
return -EIO; return -EIO;
} }
if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
ram_reserved_size) != 0) { ram_reserved_size) != 0) {
ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
return -EIO; return -EIO;
}
} }
/* set the block size for the target */ /* set the block size for the target */
...@@ -926,13 +940,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ...@@ -926,13 +940,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
if (ar->fw != NULL) if (ar->fw != NULL)
break; break;
ar->fw = kmemdup(data, ie_len, GFP_KERNEL); ar->fw = vmalloc(ie_len);
if (ar->fw == NULL) { if (ar->fw == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
memcpy(ar->fw, data, ie_len);
ar->fw_len = ie_len; ar->fw_len = ie_len;
break; break;
case ATH6KL_FW_IE_PATCH_IMAGE: case ATH6KL_FW_IE_PATCH_IMAGE:
...@@ -1509,7 +1524,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar) ...@@ -1509,7 +1524,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
} }
/* setup credit distribution */ /* setup credit distribution */
ath6kl_credit_setup(ar->htc_target, &ar->credit_state_info); ath6kl_htc_credit_setup(ar->htc_target, &ar->credit_state_info);
/* start HTC */ /* start HTC */
ret = ath6kl_htc_start(ar->htc_target); ret = ath6kl_htc_start(ar->htc_target);
......
...@@ -758,6 +758,10 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) ...@@ -758,6 +758,10 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
stats->wow_evt_discarded += stats->wow_evt_discarded +=
le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded);
stats->arp_received = le32_to_cpu(tgt_stats->arp_stats.arp_received);
stats->arp_replied = le32_to_cpu(tgt_stats->arp_stats.arp_replied);
stats->arp_matched = le32_to_cpu(tgt_stats->arp_stats.arp_matched);
if (test_bit(STATS_UPDATE_PEND, &vif->flags)) { if (test_bit(STATS_UPDATE_PEND, &vif->flags)) {
clear_bit(STATS_UPDATE_PEND, &vif->flags); clear_bit(STATS_UPDATE_PEND, &vif->flags);
wake_up(&ar->event_wq); wake_up(&ar->event_wq);
......
...@@ -1362,7 +1362,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, ...@@ -1362,7 +1362,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
goto err_core_alloc; goto err_core_alloc;
} }
ret = ath6kl_core_init(ar); ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_MBOX);
if (ret) { if (ret) {
ath6kl_err("Failed to init ath6kl core\n"); ath6kl_err("Failed to init ath6kl core\n");
goto err_core_alloc; goto err_core_alloc;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "core.h" #include "core.h"
#include "debug.h" #include "debug.h"
#include "htc-ops.h"
/* /*
* tid - tid_mux0..tid_mux3 * tid - tid_mux0..tid_mux3
...@@ -324,6 +325,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, ...@@ -324,6 +325,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
cookie->map_no = 0; cookie->map_no = 0;
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
eid, ATH6KL_CONTROL_PKT_TAG); eid, ATH6KL_CONTROL_PKT_TAG);
cookie->htc_pkt.skb = skb;
/* /*
* This interface is asynchronous, if there is an error, cleanup * 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,6 +494,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
cookie->map_no = map_no; cookie->map_no = map_no;
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
eid, htc_tag); eid, htc_tag);
cookie->htc_pkt.skb = skb;
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ", ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ",
skb->data, skb->len); skb->data, skb->len);
...@@ -572,7 +575,7 @@ void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active) ...@@ -572,7 +575,7 @@ void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active)
notify_htc: notify_htc:
/* notify HTC, this may cause credit distribution changes */ /* notify HTC, this may cause credit distribution changes */
ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active); ath6kl_htc_activity_changed(ar->htc_target, eid, active);
} }
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, enum 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,9 +671,10 @@ static void ath6kl_tx_clear_node_map(struct ath6kl_vif *vif,
} }
} }
void ath6kl_tx_complete(void *context, struct list_head *packet_queue) void ath6kl_tx_complete(struct htc_target *target,
struct list_head *packet_queue)
{ {
struct ath6kl *ar = context; struct ath6kl *ar = target->dev->ar;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
struct htc_packet *packet; struct htc_packet *packet;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -889,6 +893,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) ...@@ -889,6 +893,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
skb->data = PTR_ALIGN(skb->data - 4, 4); skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_BUFFER_SIZE, endpoint); ATH6KL_BUFFER_SIZE, endpoint);
packet->skb = skb;
list_add_tail(&packet->list, &queue); list_add_tail(&packet->list, &queue);
} }
...@@ -911,6 +916,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) ...@@ -911,6 +916,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
skb->data = PTR_ALIGN(skb->data - 4, 4); skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_AMSDU_BUFFER_SIZE, 0); ATH6KL_AMSDU_BUFFER_SIZE, 0);
packet->skb = skb;
spin_lock_bh(&ar->lock); spin_lock_bh(&ar->lock);
list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue); list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue);
spin_unlock_bh(&ar->lock); spin_unlock_bh(&ar->lock);
...@@ -1283,6 +1290,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1283,6 +1290,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
struct wmi_data_hdr *dhdr; struct wmi_data_hdr *dhdr;
int min_hdr_len; int min_hdr_len;
u8 meta_type, dot11_hdr = 0; u8 meta_type, dot11_hdr = 0;
u8 pad_before_data_start;
int status = packet->status; int status = packet->status;
enum htc_endpoint_id ept = packet->endpoint; enum htc_endpoint_id ept = packet->endpoint;
bool is_amsdu, prev_ps, ps_state = false; bool is_amsdu, prev_ps, ps_state = false;
...@@ -1494,6 +1502,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1494,6 +1502,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
seq_no = wmi_data_hdr_get_seqno(dhdr); seq_no = wmi_data_hdr_get_seqno(dhdr);
meta_type = wmi_data_hdr_get_meta(dhdr); meta_type = wmi_data_hdr_get_meta(dhdr);
dot11_hdr = wmi_data_hdr_get_dot11(dhdr); dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
pad_before_data_start =
(le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT)
& WMI_DATA_HDR_PAD_BEFORE_DATA_MASK;
skb_pull(skb, sizeof(struct wmi_data_hdr)); skb_pull(skb, sizeof(struct wmi_data_hdr));
switch (meta_type) { switch (meta_type) {
...@@ -1512,6 +1524,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1512,6 +1524,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
break; break;
} }
skb_pull(skb, pad_before_data_start);
if (dot11_hdr) if (dot11_hdr)
status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb); status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb);
else if (!is_amsdu) else if (!is_amsdu)
...@@ -1581,7 +1595,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1581,7 +1595,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
/* aggregation code will handle the skb */ /* aggregation code will handle the skb */
return; return;
} }
} } else if (!is_broadcast_ether_addr(datap->h_dest))
vif->net_stats.multicast++;
ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);
} }
......
...@@ -2882,6 +2882,43 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2882,6 +2882,43 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
return ret; return ret;
} }
int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
enum ieee80211_band band,
struct ath6kl_htcap *htcap)
{
struct sk_buff *skb;
struct wmi_set_htcap_cmd *cmd;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_set_htcap_cmd *) skb->data;
/*
* NOTE: Band in firmware matches enum ieee80211_band, it is unlikely
* this will be changed in firmware. If at all there is any change in
* band value, the host needs to be fixed.
*/
cmd->band = band;
cmd->ht_enable = !!htcap->ht_enable;
cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20);
cmd->ht40_supported =
!!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40);
cmd->intolerant_40mhz =
!!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT);
cmd->max_ampdu_len_exp = htcap->ampdu_factor;
ath6kl_dbg(ATH6KL_DBG_WMI,
"Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n",
cmd->band, cmd->ht_enable, cmd->ht40_supported,
cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz,
cmd->max_ampdu_len_exp);
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID,
NO_SYNC_WMIFLAG);
}
int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
{ {
struct sk_buff *skb; 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,6 +3069,9 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
cm->reason = cpu_to_le16(reason); cm->reason = cpu_to_le16(reason);
cm->cmd = cmd; cm->cmd = cmd;
ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd,
cm->reason);
return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID, return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID,
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
...@@ -3181,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, ...@@ -3181,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
const u8 *ie_info, u8 ie_len)
{
struct sk_buff *skb;
struct wmi_set_ie_cmd *p;
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
if (!skb)
return -ENOMEM;
ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n",
ie_id, ie_field, ie_len);
p = (struct wmi_set_ie_cmd *) skb->data;
p->ie_id = ie_id;
p->ie_field = ie_field;
p->ie_len = ie_len;
if (ie_info && ie_len > 0)
memcpy(p->ie_info, ie_info, ie_len);
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID,
NO_SYNC_WMIFLAG);
}
int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -3392,6 +3455,23 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx) ...@@ -3392,6 +3455,23 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx)
WMI_CANCEL_REMAIN_ON_CHNL_CMDID); WMI_CANCEL_REMAIN_ON_CHNL_CMDID);
} }
int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
{
struct sk_buff *skb;
struct wmi_set_inact_period_cmd *cmd;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_set_inact_period_cmd *) skb->data;
cmd->inact_period = cpu_to_le32(inact_timeout);
cmd->num_null_func = 0;
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_CONN_INACT_CMDID,
NO_SYNC_WMIFLAG);
}
static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
{ {
struct wmix_cmd_hdr *cmd; struct wmix_cmd_hdr *cmd;
......
...@@ -182,6 +182,9 @@ enum wmi_data_hdr_flags { ...@@ -182,6 +182,9 @@ enum wmi_data_hdr_flags {
#define WMI_DATA_HDR_META_MASK 0x7 #define WMI_DATA_HDR_META_MASK 0x7
#define WMI_DATA_HDR_META_SHIFT 13 #define WMI_DATA_HDR_META_SHIFT 13
#define WMI_DATA_HDR_PAD_BEFORE_DATA_MASK 0xFF
#define WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT 0x8
/* Macros for operating on WMI_DATA_HDR (info3) field */ /* Macros for operating on WMI_DATA_HDR (info3) field */
#define WMI_DATA_HDR_IF_IDX_MASK 0xF #define WMI_DATA_HDR_IF_IDX_MASK 0xF
...@@ -423,6 +426,7 @@ enum wmi_cmd_id { ...@@ -423,6 +426,7 @@ enum wmi_cmd_id {
WMI_SET_FRAMERATES_CMDID, WMI_SET_FRAMERATES_CMDID,
WMI_SET_AP_PS_CMDID, WMI_SET_AP_PS_CMDID,
WMI_SET_QOS_SUPP_CMDID, WMI_SET_QOS_SUPP_CMDID,
WMI_SET_IE_CMDID,
/* WMI_THIN_RESERVED_... mark the start and end /* WMI_THIN_RESERVED_... mark the start and end
* values for WMI_THIN_RESERVED command IDs. These * values for WMI_THIN_RESERVED command IDs. These
...@@ -629,6 +633,11 @@ enum wmi_mgmt_frame_type { ...@@ -629,6 +633,11 @@ enum wmi_mgmt_frame_type {
WMI_NUM_MGMT_FRAME WMI_NUM_MGMT_FRAME
}; };
enum wmi_ie_field_type {
WMI_RSN_IE_CAPB = 0x1,
WMI_IE_FULL = 0xFF, /* indicats full IE */
};
/* WMI_CONNECT_CMDID */ /* WMI_CONNECT_CMDID */
enum network_type { enum network_type {
INFRA_NETWORK = 0x01, INFRA_NETWORK = 0x01,
...@@ -1268,6 +1277,16 @@ struct wmi_mcast_filter_add_del_cmd { ...@@ -1268,6 +1277,16 @@ struct wmi_mcast_filter_add_del_cmd {
u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
} __packed; } __packed;
struct wmi_set_htcap_cmd {
u8 band;
u8 ht_enable;
u8 ht40_supported;
u8 ht20_sgi;
u8 ht40_sgi;
u8 intolerant_40mhz;
u8 max_ampdu_len_exp;
} __packed;
/* Command Replies */ /* Command Replies */
/* WMI_GET_CHANNEL_LIST_CMDID reply */ /* WMI_GET_CHANNEL_LIST_CMDID reply */
...@@ -1913,6 +1932,14 @@ struct wmi_set_appie_cmd { ...@@ -1913,6 +1932,14 @@ struct wmi_set_appie_cmd {
u8 ie_info[0]; u8 ie_info[0];
} __packed; } __packed;
struct wmi_set_ie_cmd {
u8 ie_id;
u8 ie_field; /* enum wmi_ie_field_type */
u8 ie_len;
u8 reserved;
u8 ie_info[0];
} __packed;
/* Notify the WSC registration status to the target */ /* Notify the WSC registration status to the target */
#define WSC_REG_ACTIVE 1 #define WSC_REG_ACTIVE 1
#define WSC_REG_INACTIVE 0 #define WSC_REG_INACTIVE 0
...@@ -2141,6 +2168,11 @@ struct wmi_ap_hidden_ssid_cmd { ...@@ -2141,6 +2168,11 @@ struct wmi_ap_hidden_ssid_cmd {
u8 hidden_ssid; u8 hidden_ssid;
} __packed; } __packed;
struct wmi_set_inact_period_cmd {
__le32 inact_period;
u8 num_null_func;
} __packed;
/* AP mode events */ /* AP mode events */
struct wmi_ap_set_apsd_cmd { struct wmi_ap_set_apsd_cmd {
u8 enable; u8 enable;
...@@ -2465,6 +2497,9 @@ int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi); ...@@ -2465,6 +2497,9 @@ int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi);
int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg); int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg);
int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
u8 keep_alive_intvl); u8 keep_alive_intvl);
int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
enum ieee80211_band band,
struct ath6kl_htcap *htcap);
int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
s32 ath6kl_wmi_get_rate(s8 rate_index); s32 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, ...@@ -2515,6 +2550,9 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx,
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
const u8 *ie, u8 ie_len); const u8 *ie, u8 ie_len);
int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
const u8 *ie_info, u8 ie_len);
/* P2P */ /* P2P */
int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
...@@ -2538,6 +2576,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx); ...@@ -2538,6 +2576,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx);
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
const u8 *ie, u8 ie_len); const u8 *ie, u8 ie_len);
int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);
void ath6kl_wmi_sscan_timer(unsigned long ptr); void ath6kl_wmi_sscan_timer(unsigned long ptr);
struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
......
...@@ -274,7 +274,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) ...@@ -274,7 +274,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
aniState->rssiThrLow, aniState->rssiThrHigh); aniState->rssiThrLow, aniState->rssiThrHigh);
if (aniState->update_ani) if (aniState->update_ani)
aniState->ofdmNoiseImmunityLevel = immunityLevel; aniState->ofdmNoiseImmunityLevel =
(immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ?
immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL;
entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
...@@ -340,7 +342,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) ...@@ -340,7 +342,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
if (aniState->update_ani) if (aniState->update_ani)
aniState->cckNoiseImmunityLevel = immunityLevel; aniState->cckNoiseImmunityLevel =
(immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ?
immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL;
entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
......
...@@ -245,7 +245,6 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -245,7 +245,6 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
REG_WRITE(ah, AR_PHY(0x37), reg32); REG_WRITE(ah, AR_PHY(0x37), reg32);
ah->curchan = chan; ah->curchan = chan;
ah->curchan_rad_index = -1;
return 0; return 0;
} }
......
...@@ -136,6 +136,7 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -136,6 +136,7 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
} }
if (sync_cause) { if (sync_cause) {
ath9k_debug_sync_cause(common, sync_cause);
fatal_int = fatal_int =
(sync_cause & (sync_cause &
(AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
......
...@@ -152,7 +152,6 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -152,7 +152,6 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
ah->curchan = chan; ah->curchan = chan;
ah->curchan_rad_index = -1;
return 0; return 0;
} }
......
...@@ -30,11 +30,6 @@ ...@@ -30,11 +30,6 @@
#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */
#define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */
#define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */
#define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */
#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */
#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */
...@@ -2936,15 +2931,6 @@ static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id) ...@@ -2936,15 +2931,6 @@ static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id)
#undef N_LOOP #undef N_LOOP
} }
static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
{
if (fbin == AR5416_BCHAN_UNUSED)
return fbin;
return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
}
static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah)
{ {
return 0; return 0;
...@@ -4070,7 +4056,7 @@ static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah, ...@@ -4070,7 +4056,7 @@ static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah,
* targetpower piers stored on eeprom * targetpower piers stored on eeprom
*/ */
for (i = 0; i < numPiers; i++) { for (i = 0; i < numPiers; i++) {
freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], is2GHz);
targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
} }
...@@ -4106,7 +4092,7 @@ static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah, ...@@ -4106,7 +4092,7 @@ static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah,
* from targetpower piers stored on eeprom * from targetpower piers stored on eeprom
*/ */
for (i = 0; i < numPiers; i++) { for (i = 0; i < numPiers; i++) {
freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], is2GHz);
targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
} }
...@@ -4142,7 +4128,7 @@ static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah, ...@@ -4142,7 +4128,7 @@ static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah,
* targetpower piers stored on eeprom * targetpower piers stored on eeprom
*/ */
for (i = 0; i < numPiers; i++) { for (i = 0; i < numPiers; i++) {
freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], is2GHz);
targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
} }
...@@ -4167,7 +4153,7 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah, ...@@ -4167,7 +4153,7 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah,
* targetpower piers stored on eeprom * targetpower piers stored on eeprom
*/ */
for (i = 0; i < numPiers; i++) { for (i = 0; i < numPiers; i++) {
freqArray[i] = FBIN2FREQ(pFreqBin[i], 1); freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], 1);
targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
} }
...@@ -4464,7 +4450,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, ...@@ -4464,7 +4450,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
is2GHz = 1; is2GHz = 1;
} }
*pfrequency = FBIN2FREQ(*pCalPier, is2GHz); *pfrequency = ath9k_hw_fbin2freq(*pCalPier, is2GHz);
*pcorrection = pCalPierStruct->refPower; *pcorrection = pCalPierStruct->refPower;
*ptemperature = pCalPierStruct->tempMeas; *ptemperature = pCalPierStruct->tempMeas;
*pvoltage = pCalPierStruct->voltMeas; *pvoltage = pCalPierStruct->voltMeas;
...@@ -4789,30 +4775,8 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, ...@@ -4789,30 +4775,8 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
bool is2ghz = IS_CHAN_2GHZ(chan); bool is2ghz = IS_CHAN_2GHZ(chan);
ath9k_hw_get_channel_centers(ah, chan, &centers); ath9k_hw_get_channel_centers(ah, chan, &centers);
scaledPower = powerLimit - antenna_reduction; scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
antenna_reduction);
/*
* Reduce scaled Power by number of chains active to get
* to per chain tx power level
*/
switch (ar5416_get_ntxchains(ah->txchainmask)) {
case 1:
break;
case 2:
if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
else
scaledPower = 0;
break;
case 3:
if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
else
scaledPower = 0;
break;
}
scaledPower = max((u16)0, scaledPower);
/* /*
* Get target powers from EEPROM - our baseline for TX Power * Get target powers from EEPROM - our baseline for TX Power
...@@ -5060,8 +5024,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, ...@@ -5060,8 +5024,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
i, targetPowerValT2[i]); i, targetPowerValT2[i]);
} }
ah->txpower_limit = regulatory->max_power_level;
/* Write target power array to registers */ /* Write target power array to registers */
ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
ar9003_hw_calibration_apply(ah, chan->channel); ar9003_hw_calibration_apply(ah, chan->channel);
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#define AR9300_EEPMISC_WOW 0x02 #define AR9300_EEPMISC_WOW 0x02
#define AR9300_CUSTOMER_DATA_SIZE 20 #define AR9300_CUSTOMER_DATA_SIZE 20
#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x))
#define AR9300_MAX_CHAINS 3 #define AR9300_MAX_CHAINS 3
#define AR9300_ANT_16S 25 #define AR9300_ANT_16S 25
#define AR9300_FUTURE_MODAL_SZ 6 #define AR9300_FUTURE_MODAL_SZ 6
......
...@@ -305,11 +305,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -305,11 +305,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ar9462_common_rx_gain_table_2p0, ar9462_common_rx_gain_table_2p0,
ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), 2); ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), 2);
INIT_INI_ARRAY(&ah->ini_BTCOEX_MAX_TXPWR,
ar9462_2p0_BTCOEX_MAX_TXPWR_table,
ARRAY_SIZE(ar9462_2p0_BTCOEX_MAX_TXPWR_table),
2);
/* Awake -> Sleep Setting */ /* Awake -> Sleep Setting */
INIT_INI_ARRAY(&ah->iniPcieSerdes, INIT_INI_ARRAY(&ah->iniPcieSerdes,
PCIE_PLL_ON_CREQ_DIS_L1_2P0, PCIE_PLL_ON_CREQ_DIS_L1_2P0,
......
...@@ -306,6 +306,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ...@@ -306,6 +306,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
ar9003_mci_get_isr(ah, masked); ar9003_mci_get_isr(ah, masked);
if (sync_cause) { if (sync_cause) {
ath9k_debug_sync_cause(common, sync_cause);
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
REG_WRITE(ah, AR_RC, 0); REG_WRITE(ah, AR_RC, 0);
......
...@@ -152,7 +152,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -152,7 +152,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
ah->curchan = chan; ah->curchan = chan;
ah->curchan_rad_index = -1;
return 0; return 0;
} }
...@@ -209,11 +208,12 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, ...@@ -209,11 +208,12 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
continue; continue;
negative = 0; negative = 0;
if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah))
cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i],
IS_CHAN_2GHZ(chan)) - synth_freq; IS_CHAN_2GHZ(chan));
else else
cur_bb_spur = spur_freq[i] - synth_freq; cur_bb_spur = spur_freq[i];
cur_bb_spur -= synth_freq;
if (cur_bb_spur < 0) { if (cur_bb_spur < 0) {
negative = 1; negative = 1;
cur_bb_spur = -cur_bb_spur; cur_bb_spur = -cur_bb_spur;
...@@ -443,7 +443,8 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, ...@@ -443,7 +443,8 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
ar9003_hw_spur_ofdm_clear(ah); ar9003_hw_spur_ofdm_clear(ah);
for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) { for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) {
freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; freq_offset = ath9k_hw_fbin2freq(spurChansPtr[i], mode);
freq_offset -= synth_freq;
if (abs(freq_offset) < range) { if (abs(freq_offset) < range) {
ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
break; break;
...@@ -684,9 +685,6 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, ...@@ -684,9 +685,6 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
if (AR_SREV_9462(ah))
ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1);
if (chan->channel == 2484) if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
......
...@@ -1115,9 +1115,9 @@ static const u32 ar9462_2p0_mac_core[][2] = { ...@@ -1115,9 +1115,9 @@ static const u32 ar9462_2p0_mac_core[][2] = {
{0x000081f8, 0x00000000}, {0x000081f8, 0x00000000},
{0x000081fc, 0x00000000}, {0x000081fc, 0x00000000},
{0x00008240, 0x00100000}, {0x00008240, 0x00100000},
{0x00008244, 0x0010f400}, {0x00008244, 0x0010f424},
{0x00008248, 0x00000800}, {0x00008248, 0x00000800},
{0x0000824c, 0x0001e800}, {0x0000824c, 0x0001e848},
{0x00008250, 0x00000000}, {0x00008250, 0x00000000},
{0x00008254, 0x00000000}, {0x00008254, 0x00000000},
{0x00008258, 0x00000000}, {0x00008258, 0x00000000},
...@@ -1448,16 +1448,4 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { ...@@ -1448,16 +1448,4 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = {
{0x0000b1fc, 0x00000196}, {0x0000b1fc, 0x00000196},
}; };
static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = {
/* Addr allmodes */
{0x000018c0, 0x10101010},
{0x000018c4, 0x10101010},
{0x000018c8, 0x10101010},
{0x000018cc, 0x10101010},
{0x000018d0, 0x10101010},
{0x000018d4, 0x10101010},
{0x000018d8, 0x10101010},
{0x000018dc, 0x10101010},
};
#endif /* INITVALS_9462_2P0_H */ #endif /* INITVALS_9462_2P0_H */
...@@ -370,7 +370,7 @@ struct ath_vif { ...@@ -370,7 +370,7 @@ struct ath_vif {
* number of beacon intervals, the game's up. * number of beacon intervals, the game's up.
*/ */
#define BSTUCK_THRESH 9 #define BSTUCK_THRESH 9
#define ATH_BCBUF 4 #define ATH_BCBUF 8
#define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BINTVAL 100 /* TU */
#define ATH_DEFAULT_BMISS_LIMIT 10 #define ATH_DEFAULT_BMISS_LIMIT 10
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
......
...@@ -60,6 +60,7 @@ struct ath_buf; ...@@ -60,6 +60,7 @@ struct ath_buf;
* @tsfoor: TSF out of range, indicates that the corrected TSF received * @tsfoor: TSF out of range, indicates that the corrected TSF received
* from a beacon differs from the PCU's internal TSF by more than a * from a beacon differs from the PCU's internal TSF by more than a
* (programmable) threshold * (programmable) threshold
* @local_timeout: Internal bus timeout.
*/ */
struct ath_interrupt_stats { struct ath_interrupt_stats {
u32 total; u32 total;
...@@ -85,8 +86,30 @@ struct ath_interrupt_stats { ...@@ -85,8 +86,30 @@ struct ath_interrupt_stats {
u32 dtim; u32 dtim;
u32 bb_watchdog; u32 bb_watchdog;
u32 tsfoor; u32 tsfoor;
/* Sync-cause stats */
u32 sync_cause_all;
u32 sync_rtc_irq;
u32 sync_mac_irq;
u32 eeprom_illegal_access;
u32 apb_timeout;
u32 pci_mode_conflict;
u32 host1_fatal;
u32 host1_perr;
u32 trcv_fifo_perr;
u32 radm_cpl_ep;
u32 radm_cpl_dllp_abort;
u32 radm_cpl_tlp_abort;
u32 radm_cpl_ecrc_err;
u32 radm_cpl_timeout;
u32 local_timeout;
u32 pm_access;
u32 mac_awake;
u32 mac_asleep;
u32 mac_sleep_access;
}; };
/** /**
* struct ath_tx_stats - Statistics about TX * struct ath_tx_stats - Statistics about TX
* @tx_pkts_all: No. of total frames transmitted, including ones that * @tx_pkts_all: No. of total frames transmitted, including ones that
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册