mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 12:44:11 +08:00
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
This commit is contained in:
commit
59ef43e681
155
Documentation/nfc/nfc-hci.txt
Normal file
155
Documentation/nfc/nfc-hci.txt
Normal file
@ -0,0 +1,155 @@
|
||||
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.
|
27
MAINTAINERS
27
MAINTAINERS
@ -6669,6 +6669,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
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
|
||||
M: Jon Maloy <jon.maloy@ericsson.com>
|
||||
M: Allan Stephens <allan.stephens@windriver.com>
|
||||
@ -7425,23 +7435,6 @@ M: Miloslav Trmac <mitr@volny.cz>
|
||||
S: Maintained
|
||||
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
|
||||
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig"
|
||||
source "drivers/net/wireless/p54/Kconfig"
|
||||
source "drivers/net/wireless/rt2x00/Kconfig"
|
||||
source "drivers/net/wireless/rtlwifi/Kconfig"
|
||||
source "drivers/net/wireless/wl1251/Kconfig"
|
||||
source "drivers/net/wireless/wl12xx/Kconfig"
|
||||
source "drivers/net/wireless/ti/Kconfig"
|
||||
source "drivers/net/wireless/zd1211rw/Kconfig"
|
||||
source "drivers/net/wireless/mwifiex/Kconfig"
|
||||
|
||||
|
@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
|
||||
|
||||
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
|
||||
|
||||
obj-$(CONFIG_WL1251) += wl1251/
|
||||
obj-$(CONFIG_WL12XX) += wl12xx/
|
||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
|
||||
obj-$(CONFIG_WL_TI) += ti/
|
||||
|
||||
obj-$(CONFIG_IWM) += iwmc3200wifi/
|
||||
|
||||
|
@ -1991,19 +1991,4 @@ static struct pci_driver adm8211_driver = {
|
||||
#endif /* CONFIG_PM */
|
||||
};
|
||||
|
||||
|
||||
|
||||
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);
|
||||
module_pci_driver(adm8211_driver);
|
||||
|
@ -2512,10 +2512,8 @@ static void __exit at76_mod_exit(void)
|
||||
|
||||
printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n");
|
||||
usb_deregister(&at76_driver);
|
||||
for (i = 0; i < ARRAY_SIZE(firmwares); i++) {
|
||||
if (firmwares[i].fw)
|
||||
release_firmware(firmwares[i].fw);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(firmwares); i++)
|
||||
release_firmware(firmwares[i].fw);
|
||||
led_trigger_unregister_simple(ledtrig_tx);
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1527,7 @@ void ath5k_eeprom_detach(struct ath5k_hw *ah);
|
||||
|
||||
/* Protocol Control Unit Functions */
|
||||
/* 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);
|
||||
unsigned int ath5k_hw_get_default_slottime(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,
|
||||
|
||||
if (ieee80211_is_beacon(mgmt->frame_control) &&
|
||||
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*
|
||||
* 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)
|
||||
|
||||
/* only beacons from our BSSID */
|
||||
if (!ieee80211_is_beacon(mgmt->frame_control) ||
|
||||
memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
|
||||
compare_ether_addr(mgmt->bssid, common->curbssid) != 0)
|
||||
return;
|
||||
|
||||
ewma_add(&ah->ah_beacon_rssi_avg, rssi);
|
||||
|
@ -47,6 +47,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
|
||||
{ PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
|
||||
{ PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
|
||||
{ PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
|
||||
{ PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
|
||||
@ -339,28 +340,4 @@ static struct pci_driver ath5k_pci_driver = {
|
||||
.driver.pm = ATH5K_PM_OPS,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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);
|
||||
module_pci_driver(ath5k_pci_driver);
|
||||
|
@ -110,7 +110,7 @@ static const unsigned int ack_rates_high[] =
|
||||
* bwmodes.
|
||||
*/
|
||||
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 sifs, preamble, plcp_bits, sym_time;
|
||||
@ -120,7 +120,7 @@ ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
|
||||
/* Fallback */
|
||||
if (!ah->ah_bwmode) {
|
||||
__le16 raw_dur = ieee80211_generic_frame_duration(ah->hw,
|
||||
NULL, len, rate);
|
||||
NULL, band, len, rate);
|
||||
|
||||
/* subtract difference between long and short preamble */
|
||||
dur = le16_to_cpu(raw_dur);
|
||||
@ -302,14 +302,15 @@ ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
|
||||
* actual rate for this rate. See mac80211 tx.c
|
||||
* ieee80211_duration() for a brief description of
|
||||
* 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);
|
||||
|
||||
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
|
||||
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,
|
||||
reg + (AR5K_SET_SHORT_PREAMBLE << 2));
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
struct ieee80211_channel *channel = ah->ah_current_channel;
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_rate *rate;
|
||||
u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
|
||||
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)
|
||||
* Also we have different lowest rate for 802.11a
|
||||
*/
|
||||
if (channel->band == IEEE80211_BAND_5GHZ)
|
||||
rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0];
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
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 */
|
||||
eifs = ack_tx_time + sifs + 2 * slot_time;
|
||||
|
@ -25,7 +25,8 @@
|
||||
obj-$(CONFIG_ATH6KL) += ath6kl_core.o
|
||||
ath6kl_core-y += debug.o
|
||||
ath6kl_core-y += hif.o
|
||||
ath6kl_core-y += htc.o
|
||||
ath6kl_core-y += htc_mbox.o
|
||||
ath6kl_core-y += htc_pipe.o
|
||||
ath6kl_core-y += bmi.o
|
||||
ath6kl_core-y += cfg80211.o
|
||||
ath6kl_core-y += init.o
|
||||
|
@ -51,6 +51,8 @@
|
||||
.max_power = 30, \
|
||||
}
|
||||
|
||||
#define DEFAULT_BG_SCAN_PERIOD 60
|
||||
|
||||
static struct ieee80211_rate ath6kl_rates[] = {
|
||||
RATETAB_ENT(10, 0x1, 0),
|
||||
RATETAB_ENT(20, 0x2, 0),
|
||||
@ -71,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = {
|
||||
#define ath6kl_g_rates (ath6kl_rates + 0)
|
||||
#define ath6kl_g_rates_size 12
|
||||
|
||||
#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
|
||||
#define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20
|
||||
#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
|
||||
IEEE80211_HT_CAP_SGI_20 | \
|
||||
IEEE80211_HT_CAP_SGI_40)
|
||||
|
||||
@ -128,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
|
||||
.channels = ath6kl_5ghz_a_channels,
|
||||
.n_bitrates = ath6kl_a_rates_size,
|
||||
.bitrates = ath6kl_a_rates,
|
||||
.ht_cap.cap = ath6kl_g_htcap,
|
||||
.ht_cap.cap = ath6kl_a_htcap,
|
||||
.ht_cap.ht_supported = true,
|
||||
};
|
||||
|
||||
@ -609,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
vif->req_bssid, vif->ch_hint,
|
||||
ar->connect_ctrl_flags, nw_subtype);
|
||||
|
||||
/* disable background scan if period is 0 */
|
||||
if (sme->bg_scan_period == 0)
|
||||
sme->bg_scan_period = 0xffff;
|
||||
|
||||
/* configure default value if not specified */
|
||||
if (sme->bg_scan_period == -1)
|
||||
sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
|
||||
|
||||
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
|
||||
sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
|
||||
|
||||
up(&ar->sem);
|
||||
|
||||
if (status == -EINVAL) {
|
||||
@ -943,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
if (test_bit(CONNECTED, &vif->flags))
|
||||
force_fg_scan = 1;
|
||||
|
||||
vif->scan_req = request;
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
ar->fw_capabilities)) {
|
||||
/*
|
||||
@ -965,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
ATH6KL_FG_SCAN_INTERVAL,
|
||||
n_channels, channels);
|
||||
}
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath6kl_err("wmi_startscan_cmd failed\n");
|
||||
else
|
||||
vif->scan_req = request;
|
||||
vif->scan_req = NULL;
|
||||
}
|
||||
|
||||
kfree(channels);
|
||||
|
||||
@ -1438,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
int i;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
|
||||
|
||||
/*
|
||||
* Don't bring up p2p on an interface which is not initialized
|
||||
* for p2p operation where fw does not have capability to switch
|
||||
* dynamically between non-p2p and p2p type interface.
|
||||
*/
|
||||
if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
vif->ar->fw_capabilities) &&
|
||||
(type == NL80211_IFTYPE_P2P_CLIENT ||
|
||||
type == NL80211_IFTYPE_P2P_GO)) {
|
||||
if (vif->ar->vif_max == 1) {
|
||||
if (vif->fw_vif_idx != 0)
|
||||
return -EINVAL;
|
||||
else
|
||||
goto set_iface_type;
|
||||
}
|
||||
|
||||
for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) {
|
||||
if (i == vif->fw_vif_idx)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == vif->ar->vif_max) {
|
||||
ath6kl_err("Invalid interface to bring up P2P\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
set_iface_type:
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
vif->next_mode = INFRA_NETWORK;
|
||||
@ -1926,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_hsleep_mode_procsed(struct ath6kl_vif *vif)
|
||||
{
|
||||
return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
|
||||
}
|
||||
|
||||
static bool is_ctrl_ep_empty(struct ath6kl *ar)
|
||||
{
|
||||
return !ar->tx_pending[ar->ctrl_ep];
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
|
||||
{
|
||||
int ret, left;
|
||||
|
||||
clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_ASLEEP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
left = wait_event_interruptible_timeout(ar->event_wq,
|
||||
is_hsleep_mode_procsed(vif),
|
||||
WMI_TIMEOUT);
|
||||
if (left == 0) {
|
||||
ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (left < 0) {
|
||||
ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
|
||||
left);
|
||||
ret = left;
|
||||
}
|
||||
|
||||
if (ar->tx_pending[ar->ctrl_ep]) {
|
||||
left = wait_event_interruptible_timeout(ar->event_wq,
|
||||
is_ctrl_ep_empty(ar),
|
||||
WMI_TIMEOUT);
|
||||
if (left == 0) {
|
||||
ath6kl_warn("clear wmi ctrl data timeout\n");
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (left < 0) {
|
||||
ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
|
||||
ret = left;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
{
|
||||
struct in_device *in_dev;
|
||||
struct in_ifaddr *ifa;
|
||||
struct ath6kl_vif *vif;
|
||||
int ret, left;
|
||||
int ret;
|
||||
u32 filter = 0;
|
||||
u16 i, bmiss_time;
|
||||
u8 index = 0;
|
||||
@ -2032,39 +2126,11 @@ skip_arp:
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_ASLEEP);
|
||||
ret = ath6kl_cfg80211_host_sleep(ar, vif);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
left = wait_event_interruptible_timeout(ar->event_wq,
|
||||
test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags),
|
||||
WMI_TIMEOUT);
|
||||
if (left == 0) {
|
||||
ath6kl_warn("timeout, didn't get host sleep cmd "
|
||||
"processed event\n");
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (left < 0) {
|
||||
ath6kl_warn("error while waiting for host sleep cmd "
|
||||
"processed event %d\n", left);
|
||||
ret = left;
|
||||
}
|
||||
|
||||
if (ar->tx_pending[ar->ctrl_ep]) {
|
||||
left = wait_event_interruptible_timeout(ar->event_wq,
|
||||
ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
|
||||
if (left == 0) {
|
||||
ath6kl_warn("clear wmi ctrl data timeout\n");
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (left < 0) {
|
||||
ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
|
||||
ret = left;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
@ -2111,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
int ret;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (!vif)
|
||||
return -EIO;
|
||||
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
ath6kl_cfg80211_stop_all(ar);
|
||||
|
||||
/* Save the current power mode before enabling power save */
|
||||
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
|
||||
|
||||
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable WOW mode */
|
||||
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_WOW_MODE_DISABLE,
|
||||
0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Flush all non control pkts in TX path */
|
||||
ath6kl_tx_data_cleanup(ar);
|
||||
|
||||
ret = ath6kl_cfg80211_host_sleep(ar, vif);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
int ret;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
|
||||
if (!vif)
|
||||
return -EIO;
|
||||
|
||||
if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
|
||||
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
|
||||
ar->wmi->saved_pwr_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_AWAKE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
|
||||
/* Reset scan parameter to default values */
|
||||
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
enum ath6kl_cfg_suspend_mode mode,
|
||||
struct cfg80211_wowlan *wow)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
enum ath6kl_state prev_state;
|
||||
int ret;
|
||||
|
||||
@ -2139,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
|
||||
case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
|
||||
|
||||
ath6kl_cfg80211_stop_all(ar);
|
||||
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) {
|
||||
ath6kl_warn("wmi powermode command failed during suspend: %d\n",
|
||||
ret);
|
||||
ath6kl_err("deepsleep suspend failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_DEEPSLEEP;
|
||||
@ -2187,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
break;
|
||||
}
|
||||
|
||||
list_for_each_entry(vif, &ar->vif_list, list)
|
||||
ath6kl_cfg80211_scan_complete_event(vif, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
|
||||
@ -2208,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_DEEPSLEEP:
|
||||
if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
|
||||
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
|
||||
ar->wmi->saved_pwr_mode);
|
||||
if (ret) {
|
||||
ath6kl_warn("wmi powermode command failed during resume: %d\n",
|
||||
ret);
|
||||
}
|
||||
ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n");
|
||||
|
||||
ret = ath6kl_cfg80211_deepsleep_resume(ar);
|
||||
if (ret) {
|
||||
ath6kl_warn("deep sleep resume failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_CUTPOWER:
|
||||
@ -2292,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
|
||||
bool ht_enable)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
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;
|
||||
if (htcap->ht_enable == ht_enable)
|
||||
return 0;
|
||||
|
||||
vif = netdev_priv(dev);
|
||||
if (ht_enable) {
|
||||
/* Set default ht capabilities */
|
||||
htcap->ht_enable = true;
|
||||
htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ?
|
||||
ath6kl_g_htcap : ath6kl_a_htcap;
|
||||
htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K;
|
||||
} else /* Disable ht */
|
||||
memset(htcap, 0, sizeof(*htcap));
|
||||
|
||||
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;
|
||||
|
||||
return 0;
|
||||
return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx,
|
||||
band, htcap);
|
||||
}
|
||||
|
||||
static bool ath6kl_is_p2p_ie(const u8 *pos)
|
||||
@ -2393,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
|
||||
/*
|
||||
* 'dev' could be NULL if a channel change is required for the hardware
|
||||
* device itself, instead of a particular VIF.
|
||||
*
|
||||
* FIXME: To be handled properly when monitor mode is supported.
|
||||
*/
|
||||
if (!dev)
|
||||
return -EBUSY;
|
||||
|
||||
vif = netdev_priv(dev);
|
||||
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
|
||||
__func__, chan->center_freq, chan->hw_value);
|
||||
vif->next_chan = chan->center_freq;
|
||||
vif->next_ch_type = channel_type;
|
||||
vif->next_ch_band = chan->band;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
|
||||
u8 *rsn_capab)
|
||||
{
|
||||
const u8 *rsn_ie;
|
||||
size_t rsn_ie_len;
|
||||
u16 cnt;
|
||||
|
||||
if (!beacon->tail)
|
||||
return -EINVAL;
|
||||
|
||||
rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len);
|
||||
if (!rsn_ie)
|
||||
return -EINVAL;
|
||||
|
||||
rsn_ie_len = *(rsn_ie + 1);
|
||||
/* skip element id and length */
|
||||
rsn_ie += 2;
|
||||
|
||||
/* skip version, group cipher */
|
||||
if (rsn_ie_len < 6)
|
||||
return -EINVAL;
|
||||
rsn_ie += 6;
|
||||
rsn_ie_len -= 6;
|
||||
|
||||
/* skip pairwise cipher suite */
|
||||
if (rsn_ie_len < 2)
|
||||
return -EINVAL;
|
||||
cnt = *((u16 *) rsn_ie);
|
||||
rsn_ie += (2 + cnt * 4);
|
||||
rsn_ie_len -= (2 + cnt * 4);
|
||||
|
||||
/* skip akm suite */
|
||||
if (rsn_ie_len < 2)
|
||||
return -EINVAL;
|
||||
cnt = *((u16 *) rsn_ie);
|
||||
rsn_ie += (2 + cnt * 4);
|
||||
rsn_ie_len -= (2 + cnt * 4);
|
||||
|
||||
if (rsn_ie_len < 2)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(rsn_capab, rsn_ie, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_ap_settings *info)
|
||||
{
|
||||
@ -2405,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct wmi_connect_cmd p;
|
||||
int res;
|
||||
int i, ret;
|
||||
u16 rsn_capab = 0;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
|
||||
|
||||
@ -2534,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
p.nw_subtype = SUBTYPE_NONE;
|
||||
}
|
||||
|
||||
if (info->inactivity_timeout) {
|
||||
res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
|
||||
info->inactivity_timeout);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
if (ath6kl_set_htcap(vif, vif->next_ch_band,
|
||||
vif->next_ch_type != NL80211_CHAN_NO_HT))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Get the PTKSA replay counter in the RSN IE. Supplicant
|
||||
* will use the RSN IE in M3 message and firmware has to
|
||||
* advertise the same in beacon/probe response. Send
|
||||
* the complete RSN IE capability field to firmware
|
||||
*/
|
||||
if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) &&
|
||||
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
|
||||
ar->fw_capabilities)) {
|
||||
res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
|
||||
(const u8 *) &rsn_capab,
|
||||
sizeof(rsn_capab));
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
|
||||
if (res < 0)
|
||||
return res;
|
||||
@ -2568,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
|
||||
clear_bit(CONNECTED, &vif->flags);
|
||||
|
||||
/* Restore ht setting in firmware */
|
||||
if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true))
|
||||
return -EIO;
|
||||
|
||||
if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2749,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if SSID length is greater than DIRECT- */
|
||||
static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *mgmt;
|
||||
mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
|
||||
/* variable[1] contains the SSID tag length */
|
||||
if (buf + len >= &mgmt->u.probe_resp.variable[1] &&
|
||||
(mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_channel *chan, bool offchan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
@ -2763,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
||||
bool more_data, queued;
|
||||
|
||||
mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
if (buf + len >= mgmt->u.probe_resp.variable &&
|
||||
vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
|
||||
ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
|
||||
ieee80211_is_probe_resp(mgmt->frame_control) &&
|
||||
ath6kl_is_p2p_go_ssid(buf, len)) {
|
||||
/*
|
||||
* Send Probe Response frame in AP mode using a separate WMI
|
||||
* Send Probe Response frame in GO mode using a separate WMI
|
||||
* command to allow the target to fill in the generic IEs.
|
||||
*/
|
||||
*cookie = 0; /* TX status not supported */
|
||||
@ -2835,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
if (vif->sme_state != SME_DISCONNECTED)
|
||||
return -EBUSY;
|
||||
|
||||
ath6kl_cfg80211_scan_complete_event(vif, true);
|
||||
|
||||
for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
|
||||
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
i, DISABLE_SSID_FLAG,
|
||||
@ -3096,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
vif->next_mode = nw_type;
|
||||
vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
|
||||
vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
|
||||
vif->htcap.ht_enable = true;
|
||||
|
||||
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
|
||||
if (fw_vif_idx != 0)
|
||||
@ -3183,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
|
||||
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
|
||||
ar->fw_capabilities))
|
||||
ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER;
|
||||
|
||||
ar->wiphy->probe_resp_offload =
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
||||
|
@ -22,7 +22,8 @@
|
||||
|
||||
#define ATH6KL_MAX_IE 256
|
||||
|
||||
extern int ath6kl_printk(const char *level, const char *fmt, ...);
|
||||
extern __printf(2, 3)
|
||||
int ath6kl_printk(const char *level, const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* Reflects the version of binary interface exposed by ATH6KL target
|
||||
@ -77,6 +78,7 @@ enum crypto_type {
|
||||
|
||||
struct htc_endpoint_credit_dist;
|
||||
struct ath6kl;
|
||||
struct ath6kl_htcap;
|
||||
enum htc_credit_dist_reason;
|
||||
struct ath6kl_htc_credit_info;
|
||||
|
||||
|
@ -20,9 +20,11 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "hif-ops.h"
|
||||
#include "htc-ops.h"
|
||||
#include "cfg80211.h"
|
||||
|
||||
unsigned int debug_mask;
|
||||
@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644);
|
||||
module_param(ath6kl_p2p, uint, 0644);
|
||||
module_param(testmode, uint, 0644);
|
||||
|
||||
int ath6kl_core_init(struct ath6kl *ar)
|
||||
void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
|
||||
{
|
||||
ath6kl_htc_tx_complete(ar, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ath6kl_core_tx_complete);
|
||||
|
||||
void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe)
|
||||
{
|
||||
ath6kl_htc_rx_complete(ar, skb, pipe);
|
||||
}
|
||||
EXPORT_SYMBOL(ath6kl_core_rx_complete);
|
||||
|
||||
int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
|
||||
{
|
||||
struct ath6kl_bmi_target_info targ_info;
|
||||
struct net_device *ndev;
|
||||
int ret = 0, i;
|
||||
|
||||
switch (htc_type) {
|
||||
case ATH6KL_HTC_TYPE_MBOX:
|
||||
ath6kl_htc_mbox_attach(ar);
|
||||
break;
|
||||
case ATH6KL_HTC_TYPE_PIPE:
|
||||
ath6kl_htc_pipe_attach(ar);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
|
||||
if (!ar->ath6kl_wq)
|
||||
return -ENOMEM;
|
||||
@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
|
||||
|
||||
kfree(ar->fw_board);
|
||||
kfree(ar->fw_otp);
|
||||
kfree(ar->fw);
|
||||
vfree(ar->fw);
|
||||
kfree(ar->fw_patch);
|
||||
kfree(ar->fw_testscript);
|
||||
|
||||
|
@ -91,6 +91,15 @@ enum ath6kl_fw_capability {
|
||||
*/
|
||||
ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
|
||||
/*
|
||||
* Firmware has support to cleanup inactive stations
|
||||
* in AP mode.
|
||||
*/
|
||||
ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
|
||||
|
||||
/* Firmware has support to override rsn cap of rsn ie */
|
||||
ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
|
||||
|
||||
/* this needs to be last */
|
||||
ATH6KL_FW_CAPABILITY_MAX,
|
||||
};
|
||||
@ -205,6 +214,8 @@ struct ath6kl_fw_ie {
|
||||
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
|
||||
#define ATH6KL_CONF_UART_DEBUG BIT(4)
|
||||
|
||||
#define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */
|
||||
|
||||
enum wlan_low_pwr_state {
|
||||
WLAN_POWER_STATE_ON,
|
||||
WLAN_POWER_STATE_CUT_PWR,
|
||||
@ -454,6 +465,11 @@ enum ath6kl_hif_type {
|
||||
ATH6KL_HIF_TYPE_USB,
|
||||
};
|
||||
|
||||
enum ath6kl_htc_type {
|
||||
ATH6KL_HTC_TYPE_MBOX,
|
||||
ATH6KL_HTC_TYPE_PIPE,
|
||||
};
|
||||
|
||||
/* Max number of filters that hw supports */
|
||||
#define ATH6K_MAX_MC_FILTERS_PER_LIST 7
|
||||
struct ath6kl_mc_filter {
|
||||
@ -461,6 +477,12 @@ struct ath6kl_mc_filter {
|
||||
char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
|
||||
};
|
||||
|
||||
struct ath6kl_htcap {
|
||||
bool ht_enable;
|
||||
u8 ampdu_factor;
|
||||
unsigned short cap_info;
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver's maximum limit, note that some firmwares support only one vif
|
||||
* and the runtime (current) limit must be checked from ar->vif_max.
|
||||
@ -509,6 +531,7 @@ struct ath6kl_vif {
|
||||
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
|
||||
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
|
||||
struct aggr_info *aggr_cntxt;
|
||||
struct ath6kl_htcap htcap;
|
||||
|
||||
struct timer_list disconnect_timer;
|
||||
struct timer_list sched_scan_timer;
|
||||
@ -521,6 +544,8 @@ struct ath6kl_vif {
|
||||
u32 send_action_id;
|
||||
bool probe_req_report;
|
||||
u16 next_chan;
|
||||
enum nl80211_channel_type next_ch_type;
|
||||
enum ieee80211_band next_ch_band;
|
||||
u16 assoc_bss_beacon_int;
|
||||
u16 listen_intvl_t;
|
||||
u16 bmiss_time_t;
|
||||
@ -568,6 +593,7 @@ struct ath6kl {
|
||||
|
||||
struct ath6kl_bmi bmi;
|
||||
const struct ath6kl_hif_ops *hif_ops;
|
||||
const struct ath6kl_htc_ops *htc_ops;
|
||||
struct wmi *wmi;
|
||||
int tx_pending[ENDPOINT_MAX];
|
||||
int total_tx_data_pend;
|
||||
@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev);
|
||||
void ath6kl_cookie_init(struct ath6kl *ar);
|
||||
void ath6kl_cookie_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
|
||||
void ath6kl_tx_complete(void *context, struct list_head *packet_queue);
|
||||
void ath6kl_tx_complete(struct htc_target *context,
|
||||
struct list_head *packet_queue);
|
||||
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
struct htc_packet *packet);
|
||||
void ath6kl_stop_txrx(struct ath6kl *ar);
|
||||
@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_check_wow_status(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb);
|
||||
void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe);
|
||||
|
||||
struct ath6kl *ath6kl_core_create(struct device *dev);
|
||||
int ath6kl_core_init(struct ath6kl *ar);
|
||||
int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
|
||||
void ath6kl_core_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_core_destroy(struct ath6kl *ar);
|
||||
|
||||
|
@ -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);
|
||||
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
|
||||
"Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
|
||||
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
|
||||
"ARP pkt received", tgt_stats->arp_received);
|
||||
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
|
||||
"ARP pkt matched", tgt_stats->arp_matched);
|
||||
len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
|
||||
"ARP pkt replied", tgt_stats->arp_replied);
|
||||
|
||||
if (len > buf_len)
|
||||
len = buf_len;
|
||||
|
@ -43,6 +43,7 @@ enum ATH6K_DEBUG_MASK {
|
||||
ATH6KL_DBG_WMI_DUMP = BIT(19),
|
||||
ATH6KL_DBG_SUSPEND = BIT(20),
|
||||
ATH6KL_DBG_USB = BIT(21),
|
||||
ATH6KL_DBG_USB_BULK = BIT(22),
|
||||
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
|
||||
};
|
||||
|
||||
|
@ -150,4 +150,38 @@ static inline void ath6kl_hif_stop(struct ath6kl *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
|
||||
|
@ -256,6 +256,12 @@ struct ath6kl_hif_ops {
|
||||
int (*power_on)(struct ath6kl *ar);
|
||||
int (*power_off)(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);
|
||||
|
113
drivers/net/wireless/ath/ath6kl/htc-ops.h
Normal file
113
drivers/net/wireless/ath/ath6kl/htc-ops.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/* send direction */
|
||||
#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
|
||||
#define HTC_FLAGS_SEND_BUNDLE (1 << 1)
|
||||
#define HTC_FLAGS_TX_FIXUP_NETBUF (1 << 2)
|
||||
|
||||
/* receive direction */
|
||||
#define HTC_FLG_RX_UNUSED (1 << 0)
|
||||
@ -56,6 +57,10 @@
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2
|
||||
#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4
|
||||
#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 */
|
||||
#define HTC_SERVICE_SUCCESS 0
|
||||
@ -75,6 +80,7 @@
|
||||
#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
|
||||
|
||||
#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) \
|
||||
(int)(((int)group << 8) | (int)(index))
|
||||
@ -109,6 +115,8 @@
|
||||
|
||||
/* HTC operational parameters */
|
||||
#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_CREDIT_INTR_MASK 0xF0
|
||||
|
||||
@ -128,6 +136,7 @@
|
||||
|
||||
#define HTC_RECV_WAIT_BUFFERS (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
|
||||
@ -311,6 +320,14 @@ struct htc_packet {
|
||||
|
||||
void (*completion) (struct htc_target *, struct htc_packet *);
|
||||
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 {
|
||||
@ -319,12 +336,14 @@ enum htc_send_full_action {
|
||||
};
|
||||
|
||||
struct htc_ep_callbacks {
|
||||
void (*tx_complete) (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);
|
||||
enum htc_send_full_action (*tx_full) (struct htc_target *,
|
||||
struct htc_packet *);
|
||||
struct htc_packet *(*rx_allocthresh) (struct htc_target *,
|
||||
enum htc_endpoint_id, int);
|
||||
void (*tx_comp_multi) (struct htc_target *, struct list_head *);
|
||||
int rx_alloc_thresh;
|
||||
int rx_refill_thresh;
|
||||
};
|
||||
@ -502,6 +521,13 @@ struct htc_endpoint {
|
||||
u32 conn_flags;
|
||||
struct htc_endpoint_stats ep_st;
|
||||
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 {
|
||||
@ -509,6 +535,42 @@ struct htc_control_buffer {
|
||||
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;
|
||||
|
||||
/* our HTC target state */
|
||||
@ -557,36 +619,19 @@ struct htc_target {
|
||||
|
||||
/* counts the number of Tx without bundling continously per 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,
|
||||
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,
|
||||
u8 *buf, unsigned int len,
|
||||
enum htc_endpoint_id eid, u16 tag)
|
||||
@ -626,4 +671,7 @@ static inline int get_queue_depth(struct list_head *queue)
|
||||
return depth;
|
||||
}
|
||||
|
||||
void ath6kl_htc_pipe_attach(struct ath6kl *ar);
|
||||
void ath6kl_htc_mbox_attach(struct ath6kl *ar);
|
||||
|
||||
#endif
|
||||
|
@ -23,6 +23,14 @@
|
||||
|
||||
#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*/
|
||||
#define TX_RESUME_BUNDLE_THRESHOLD 1500
|
||||
|
||||
@ -130,8 +138,8 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
|
||||
}
|
||||
|
||||
/* initialize and setup credit distribution */
|
||||
int ath6kl_credit_setup(void *htc_handle,
|
||||
struct ath6kl_htc_credit_info *cred_info)
|
||||
static int ath6kl_htc_mbox_credit_setup(struct htc_target *htc_target,
|
||||
struct ath6kl_htc_credit_info *cred_info)
|
||||
{
|
||||
u16 servicepriority[5];
|
||||
|
||||
@ -144,7 +152,7 @@ int ath6kl_credit_setup(void *htc_handle,
|
||||
servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@ -432,7 +440,7 @@ static void htc_tx_complete(struct htc_endpoint *endpoint,
|
||||
"htc tx complete ep %d pkts %d\n",
|
||||
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,
|
||||
@ -1065,7 +1073,7 @@ static int htc_setup_tx_complete(struct htc_target *target)
|
||||
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,
|
||||
u16 srvc_pri_order[], int list_len)
|
||||
{
|
||||
@ -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 list_head queue;
|
||||
@ -1121,7 +1130,7 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct htc_packet *packet, *tmp_pkt;
|
||||
@ -1173,12 +1182,13 @@ static void ath6kl_htc_flush_txep_all(struct htc_target *target)
|
||||
if (endpoint->svc_id == 0)
|
||||
/* not in use.. */
|
||||
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,
|
||||
enum htc_endpoint_id eid, bool active)
|
||||
static void ath6kl_htc_mbox_activity_changed(struct htc_target *target,
|
||||
enum htc_endpoint_id eid,
|
||||
bool active)
|
||||
{
|
||||
struct htc_endpoint *endpoint = &target->endpoint[eid];
|
||||
bool dist = false;
|
||||
@ -1246,7 +1256,7 @@ static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet)
|
||||
|
||||
INIT_LIST_HEAD(&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,
|
||||
@ -1353,7 +1363,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,
|
||||
sizeof(*htc_hdr));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2288,7 +2300,7 @@ fail_ctrl_rx:
|
||||
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 htc_endpoint *endpoint;
|
||||
@ -2350,7 +2362,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
|
||||
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_packet *packet, *tmp_pkt;
|
||||
@ -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_resp *conn_resp)
|
||||
{
|
||||
@ -2564,7 +2576,7 @@ static void reset_ep_state(struct htc_target *target)
|
||||
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)
|
||||
{
|
||||
int num;
|
||||
@ -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_ready_ext_msg *rdy_msg;
|
||||
@ -2693,12 +2705,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
|
||||
connect.svc_id = HTC_CTRL_RSVD_SVC;
|
||||
|
||||
/* connect fake service */
|
||||
status = ath6kl_htc_conn_service((void *)target, &connect, &resp);
|
||||
status = ath6kl_htc_mbox_conn_service((void *)target, &connect, &resp);
|
||||
|
||||
if (status)
|
||||
/*
|
||||
* 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);
|
||||
|
||||
@ -2715,7 +2727,7 @@ fail_wait_target:
|
||||
* Start HTC, enable interrupts and let the target know
|
||||
* 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;
|
||||
int status;
|
||||
@ -2752,7 +2764,7 @@ int ath6kl_htc_start(struct htc_target *target)
|
||||
status = ath6kl_hif_unmask_intrs(target->dev);
|
||||
|
||||
if (status)
|
||||
ath6kl_htc_stop(target);
|
||||
ath6kl_htc_mbox_stop(target);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -2796,7 +2808,7 @@ static int ath6kl_htc_reset(struct htc_target *target)
|
||||
}
|
||||
|
||||
/* 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);
|
||||
target->htc_flags |= HTC_OP_STATE_STOPPING;
|
||||
@ -2811,12 +2823,12 @@ void ath6kl_htc_stop(struct htc_target *target)
|
||||
|
||||
ath6kl_htc_flush_txep_all(target);
|
||||
|
||||
ath6kl_htc_flush_rx_buf(target);
|
||||
ath6kl_htc_mbox_flush_rx_buf(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;
|
||||
int status = 0;
|
||||
@ -2857,13 +2869,13 @@ void *ath6kl_htc_create(struct ath6kl *ar)
|
||||
return target;
|
||||
|
||||
err_htc_cleanup:
|
||||
ath6kl_htc_cleanup(target);
|
||||
ath6kl_htc_mbox_cleanup(target);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
@ -2888,3 +2900,24 @@ void ath6kl_htc_cleanup(struct htc_target *target)
|
||||
kfree(target->dev);
|
||||
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;
|
||||
}
|
1713
drivers/net/wireless/ath/ath6kl/htc_pipe.c
Normal file
1713
drivers/net/wireless/ath/ath6kl/htc_pipe.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,12 +23,14 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "cfg80211.h"
|
||||
#include "target.h"
|
||||
#include "debug.h"
|
||||
#include "hif-ops.h"
|
||||
#include "htc-ops.h"
|
||||
|
||||
static const struct ath6kl_hw hw_list[] = {
|
||||
{
|
||||
@ -258,6 +260,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
|
||||
memset(&connect, 0, sizeof(connect));
|
||||
|
||||
/* these fields are the same for all service endpoints */
|
||||
connect.ep_cb.tx_comp_multi = ath6kl_tx_complete;
|
||||
connect.ep_cb.rx = ath6kl_rx;
|
||||
connect.ep_cb.rx_refill = ath6kl_rx_refill;
|
||||
connect.ep_cb.tx_full = ath6kl_tx_queue_full;
|
||||
@ -487,22 +490,31 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
|
||||
|
||||
/*
|
||||
* By default, submodes :
|
||||
* Submodes when fw does not support dynamic interface
|
||||
* switching:
|
||||
* vif[0] - AP/STA/IBSS
|
||||
* vif[1] - "P2P dev"/"P2P GO"/"P2P Client"
|
||||
* vif[2] - "P2P dev"/"P2P GO"/"P2P Client"
|
||||
* Otherwise, All the interface are initialized to p2p dev.
|
||||
*/
|
||||
|
||||
for (i = 0; i < ar->max_norm_iface; i++)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
ar->fw_capabilities)) {
|
||||
for (i = 0; i < ar->vif_max; i++)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
} else {
|
||||
for (i = 0; i < ar->max_norm_iface; i++)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
|
||||
for (i = ar->max_norm_iface; i < ar->vif_max; i++)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
for (i = ar->max_norm_iface; i < ar->vif_max; i++)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
|
||||
if (ar->p2p && ar->vif_max == 1)
|
||||
fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
|
||||
if (ar->p2p && ar->vif_max == 1)
|
||||
fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
|
||||
}
|
||||
|
||||
if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,
|
||||
HTC_PROTOCOL_VERSION) != 0) {
|
||||
@ -541,18 +553,20 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
* but possible in theory.
|
||||
*/
|
||||
|
||||
param = ar->hw.board_ext_data_addr;
|
||||
ram_reserved_size = ar->hw.reserved_ram_size;
|
||||
if (ar->target_type == TARGET_TYPE_AR6003) {
|
||||
param = ar->hw.board_ext_data_addr;
|
||||
ram_reserved_size = ar->hw.reserved_ram_size;
|
||||
|
||||
if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
|
||||
ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
|
||||
ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
|
||||
ram_reserved_size) != 0) {
|
||||
ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
|
||||
return -EIO;
|
||||
if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
|
||||
ram_reserved_size) != 0) {
|
||||
ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the block size for the target */
|
||||
@ -926,13 +940,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
if (ar->fw != NULL)
|
||||
break;
|
||||
|
||||
ar->fw = kmemdup(data, ie_len, GFP_KERNEL);
|
||||
ar->fw = vmalloc(ie_len);
|
||||
|
||||
if (ar->fw == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(ar->fw, data, ie_len);
|
||||
ar->fw_len = ie_len;
|
||||
break;
|
||||
case ATH6KL_FW_IE_PATCH_IMAGE:
|
||||
@ -1509,7 +1524,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
}
|
||||
|
||||
/* setup credit distribution */
|
||||
ath6kl_credit_setup(ar->htc_target, &ar->credit_state_info);
|
||||
ath6kl_htc_credit_setup(ar->htc_target, &ar->credit_state_info);
|
||||
|
||||
/* start HTC */
|
||||
ret = ath6kl_htc_start(ar->htc_target);
|
||||
|
@ -758,6 +758,10 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len)
|
||||
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)) {
|
||||
clear_bit(STATS_UPDATE_PEND, &vif->flags);
|
||||
wake_up(&ar->event_wq);
|
||||
|
@ -1362,7 +1362,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
|
||||
goto err_core_alloc;
|
||||
}
|
||||
|
||||
ret = ath6kl_core_init(ar);
|
||||
ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_MBOX);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to init ath6kl core\n");
|
||||
goto err_core_alloc;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "htc-ops.h"
|
||||
|
||||
/*
|
||||
* tid - tid_mux0..tid_mux3
|
||||
@ -324,6 +325,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
|
||||
cookie->map_no = 0;
|
||||
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
|
||||
eid, ATH6KL_CONTROL_PKT_TAG);
|
||||
cookie->htc_pkt.skb = skb;
|
||||
|
||||
/*
|
||||
* This interface is asynchronous, if there is an error, cleanup
|
||||
@ -492,6 +494,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
cookie->map_no = map_no;
|
||||
set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
|
||||
eid, htc_tag);
|
||||
cookie->htc_pkt.skb = skb;
|
||||
|
||||
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ",
|
||||
skb->data, skb->len);
|
||||
@ -572,7 +575,7 @@ void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active)
|
||||
|
||||
notify_htc:
|
||||
/* notify HTC, this may cause credit distribution changes */
|
||||
ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active);
|
||||
ath6kl_htc_activity_changed(ar->htc_target, eid, active);
|
||||
}
|
||||
|
||||
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
@ -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 htc_packet *packet;
|
||||
struct sk_buff *skb;
|
||||
@ -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);
|
||||
set_htc_rxpkt_info(packet, skb, skb->data,
|
||||
ATH6KL_BUFFER_SIZE, endpoint);
|
||||
packet->skb = skb;
|
||||
list_add_tail(&packet->list, &queue);
|
||||
}
|
||||
|
||||
@ -911,6 +916,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
|
||||
skb->data = PTR_ALIGN(skb->data - 4, 4);
|
||||
set_htc_rxpkt_info(packet, skb, skb->data,
|
||||
ATH6KL_AMSDU_BUFFER_SIZE, 0);
|
||||
packet->skb = skb;
|
||||
|
||||
spin_lock_bh(&ar->lock);
|
||||
list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue);
|
||||
spin_unlock_bh(&ar->lock);
|
||||
@ -1283,6 +1290,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
|
||||
struct wmi_data_hdr *dhdr;
|
||||
int min_hdr_len;
|
||||
u8 meta_type, dot11_hdr = 0;
|
||||
u8 pad_before_data_start;
|
||||
int status = packet->status;
|
||||
enum htc_endpoint_id ept = packet->endpoint;
|
||||
bool is_amsdu, prev_ps, ps_state = false;
|
||||
@ -1494,6 +1502,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
|
||||
seq_no = wmi_data_hdr_get_seqno(dhdr);
|
||||
meta_type = wmi_data_hdr_get_meta(dhdr);
|
||||
dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
|
||||
pad_before_data_start =
|
||||
(le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT)
|
||||
& WMI_DATA_HDR_PAD_BEFORE_DATA_MASK;
|
||||
|
||||
skb_pull(skb, sizeof(struct wmi_data_hdr));
|
||||
|
||||
switch (meta_type) {
|
||||
@ -1512,6 +1524,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
|
||||
break;
|
||||
}
|
||||
|
||||
skb_pull(skb, pad_before_data_start);
|
||||
|
||||
if (dot11_hdr)
|
||||
status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb);
|
||||
else if (!is_amsdu)
|
||||
@ -1581,7 +1595,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
|
||||
/* aggregation code will handle the skb */
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (!is_broadcast_ether_addr(datap->h_dest))
|
||||
vif->net_stats.multicast++;
|
||||
|
||||
ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);
|
||||
}
|
||||
|
@ -21,15 +21,77 @@
|
||||
#include "debug.h"
|
||||
#include "core.h"
|
||||
|
||||
/* constants */
|
||||
#define TX_URB_COUNT 32
|
||||
#define RX_URB_COUNT 32
|
||||
#define ATH6KL_USB_RX_BUFFER_SIZE 1700
|
||||
|
||||
/* tx/rx pipes for usb */
|
||||
enum ATH6KL_USB_PIPE_ID {
|
||||
ATH6KL_USB_PIPE_TX_CTRL = 0,
|
||||
ATH6KL_USB_PIPE_TX_DATA_LP,
|
||||
ATH6KL_USB_PIPE_TX_DATA_MP,
|
||||
ATH6KL_USB_PIPE_TX_DATA_HP,
|
||||
ATH6KL_USB_PIPE_RX_CTRL,
|
||||
ATH6KL_USB_PIPE_RX_DATA,
|
||||
ATH6KL_USB_PIPE_RX_DATA2,
|
||||
ATH6KL_USB_PIPE_RX_INT,
|
||||
ATH6KL_USB_PIPE_MAX
|
||||
};
|
||||
|
||||
#define ATH6KL_USB_PIPE_INVALID ATH6KL_USB_PIPE_MAX
|
||||
|
||||
struct ath6kl_usb_pipe {
|
||||
struct list_head urb_list_head;
|
||||
struct usb_anchor urb_submitted;
|
||||
u32 urb_alloc;
|
||||
u32 urb_cnt;
|
||||
u32 urb_cnt_thresh;
|
||||
unsigned int usb_pipe_handle;
|
||||
u32 flags;
|
||||
u8 ep_address;
|
||||
u8 logical_pipe_num;
|
||||
struct ath6kl_usb *ar_usb;
|
||||
u16 max_packet_size;
|
||||
struct work_struct io_complete_work;
|
||||
struct sk_buff_head io_comp_queue;
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
};
|
||||
|
||||
#define ATH6KL_USB_PIPE_FLAG_TX (1 << 0)
|
||||
|
||||
/* usb device object */
|
||||
struct ath6kl_usb {
|
||||
/* protects pipe->urb_list_head and pipe->urb_cnt */
|
||||
spinlock_t cs_lock;
|
||||
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *interface;
|
||||
struct ath6kl_usb_pipe pipes[ATH6KL_USB_PIPE_MAX];
|
||||
u8 *diag_cmd_buffer;
|
||||
u8 *diag_resp_buffer;
|
||||
struct ath6kl *ar;
|
||||
};
|
||||
|
||||
/* usb urb object */
|
||||
struct ath6kl_urb_context {
|
||||
struct list_head link;
|
||||
struct ath6kl_usb_pipe *pipe;
|
||||
struct sk_buff *skb;
|
||||
struct ath6kl *ar;
|
||||
};
|
||||
|
||||
/* USB endpoint definitions */
|
||||
#define ATH6KL_USB_EP_ADDR_APP_CTRL_IN 0x81
|
||||
#define ATH6KL_USB_EP_ADDR_APP_DATA_IN 0x82
|
||||
#define ATH6KL_USB_EP_ADDR_APP_DATA2_IN 0x83
|
||||
#define ATH6KL_USB_EP_ADDR_APP_INT_IN 0x84
|
||||
|
||||
#define ATH6KL_USB_EP_ADDR_APP_CTRL_OUT 0x01
|
||||
#define ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT 0x02
|
||||
#define ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT 0x03
|
||||
#define ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT 0x04
|
||||
|
||||
/* diagnostic command defnitions */
|
||||
#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1
|
||||
#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2
|
||||
@ -55,11 +117,493 @@ struct ath6kl_usb_ctrl_diag_resp_read {
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
/* function declarations */
|
||||
static void ath6kl_usb_recv_complete(struct urb *urb);
|
||||
|
||||
#define ATH6KL_USB_IS_BULK_EP(attr) (((attr) & 3) == 0x02)
|
||||
#define ATH6KL_USB_IS_INT_EP(attr) (((attr) & 3) == 0x03)
|
||||
#define ATH6KL_USB_IS_ISOC_EP(attr) (((attr) & 3) == 0x01)
|
||||
#define ATH6KL_USB_IS_DIR_IN(addr) ((addr) & 0x80)
|
||||
|
||||
/* pipe/urb operations */
|
||||
static struct ath6kl_urb_context *
|
||||
ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe)
|
||||
{
|
||||
struct ath6kl_urb_context *urb_context = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
|
||||
if (!list_empty(&pipe->urb_list_head)) {
|
||||
urb_context =
|
||||
list_first_entry(&pipe->urb_list_head,
|
||||
struct ath6kl_urb_context, link);
|
||||
list_del(&urb_context->link);
|
||||
pipe->urb_cnt--;
|
||||
}
|
||||
spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags);
|
||||
|
||||
return urb_context;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe,
|
||||
struct ath6kl_urb_context *urb_context)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
|
||||
pipe->urb_cnt++;
|
||||
|
||||
list_add(&urb_context->link, &pipe->urb_list_head);
|
||||
spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags);
|
||||
}
|
||||
|
||||
static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context)
|
||||
{
|
||||
if (urb_context->skb != NULL) {
|
||||
dev_kfree_skb(urb_context->skb);
|
||||
urb_context->skb = NULL;
|
||||
}
|
||||
|
||||
ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
|
||||
}
|
||||
|
||||
static inline struct ath6kl_usb *ath6kl_usb_priv(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_priv;
|
||||
}
|
||||
|
||||
/* pipe resource allocation/cleanup */
|
||||
static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
|
||||
int urb_cnt)
|
||||
{
|
||||
struct ath6kl_urb_context *urb_context;
|
||||
int status = 0, i;
|
||||
|
||||
INIT_LIST_HEAD(&pipe->urb_list_head);
|
||||
init_usb_anchor(&pipe->urb_submitted);
|
||||
|
||||
for (i = 0; i < urb_cnt; i++) {
|
||||
urb_context = kzalloc(sizeof(struct ath6kl_urb_context),
|
||||
GFP_KERNEL);
|
||||
if (urb_context == NULL)
|
||||
/* FIXME: set status to -ENOMEM */
|
||||
break;
|
||||
|
||||
urb_context->pipe = pipe;
|
||||
|
||||
/*
|
||||
* we are only allocate the urb contexts here, the actual URB
|
||||
* is allocated from the kernel as needed to do a transaction
|
||||
*/
|
||||
pipe->urb_alloc++;
|
||||
ath6kl_usb_free_urb_to_pipe(pipe, urb_context);
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB,
|
||||
"ath6kl usb: alloc resources lpipe:%d hpipe:0x%X urbs:%d\n",
|
||||
pipe->logical_pipe_num, pipe->usb_pipe_handle,
|
||||
pipe->urb_alloc);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe)
|
||||
{
|
||||
struct ath6kl_urb_context *urb_context;
|
||||
|
||||
if (pipe->ar_usb == NULL) {
|
||||
/* nothing allocated for this pipe */
|
||||
return;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB,
|
||||
"ath6kl usb: free resources lpipe:%d"
|
||||
"hpipe:0x%X urbs:%d avail:%d\n",
|
||||
pipe->logical_pipe_num, pipe->usb_pipe_handle,
|
||||
pipe->urb_alloc, pipe->urb_cnt);
|
||||
|
||||
if (pipe->urb_alloc != pipe->urb_cnt) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB,
|
||||
"ath6kl usb: urb leak! lpipe:%d"
|
||||
"hpipe:0x%X urbs:%d avail:%d\n",
|
||||
pipe->logical_pipe_num, pipe->usb_pipe_handle,
|
||||
pipe->urb_alloc, pipe->urb_cnt);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe);
|
||||
if (urb_context == NULL)
|
||||
break;
|
||||
kfree(urb_context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++)
|
||||
ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]);
|
||||
|
||||
}
|
||||
|
||||
static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb,
|
||||
u8 ep_address, int *urb_count)
|
||||
{
|
||||
u8 pipe_num = ATH6KL_USB_PIPE_INVALID;
|
||||
|
||||
switch (ep_address) {
|
||||
case ATH6KL_USB_EP_ADDR_APP_CTRL_IN:
|
||||
pipe_num = ATH6KL_USB_PIPE_RX_CTRL;
|
||||
*urb_count = RX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_DATA_IN:
|
||||
pipe_num = ATH6KL_USB_PIPE_RX_DATA;
|
||||
*urb_count = RX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_INT_IN:
|
||||
pipe_num = ATH6KL_USB_PIPE_RX_INT;
|
||||
*urb_count = RX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_DATA2_IN:
|
||||
pipe_num = ATH6KL_USB_PIPE_RX_DATA2;
|
||||
*urb_count = RX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_CTRL_OUT:
|
||||
pipe_num = ATH6KL_USB_PIPE_TX_CTRL;
|
||||
*urb_count = TX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT:
|
||||
pipe_num = ATH6KL_USB_PIPE_TX_DATA_LP;
|
||||
*urb_count = TX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT:
|
||||
pipe_num = ATH6KL_USB_PIPE_TX_DATA_MP;
|
||||
*urb_count = TX_URB_COUNT;
|
||||
break;
|
||||
case ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT:
|
||||
pipe_num = ATH6KL_USB_PIPE_TX_DATA_HP;
|
||||
*urb_count = TX_URB_COUNT;
|
||||
break;
|
||||
default:
|
||||
/* note: there may be endpoints not currently used */
|
||||
break;
|
||||
}
|
||||
|
||||
return pipe_num;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_setup_pipe_resources(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
struct usb_interface *interface = ar_usb->interface;
|
||||
struct usb_host_interface *iface_desc = interface->cur_altsetting;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct ath6kl_usb_pipe *pipe;
|
||||
int i, urbcount, status = 0;
|
||||
u8 pipe_num;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "setting up USB Pipes using interface\n");
|
||||
|
||||
/* walk decriptors and setup pipes */
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB,
|
||||
"%s Bulk Ep:0x%2.2X maxpktsz:%d\n",
|
||||
ATH6KL_USB_IS_DIR_IN
|
||||
(endpoint->bEndpointAddress) ?
|
||||
"RX" : "TX", endpoint->bEndpointAddress,
|
||||
le16_to_cpu(endpoint->wMaxPacketSize));
|
||||
} else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB,
|
||||
"%s Int Ep:0x%2.2X maxpktsz:%d interval:%d\n",
|
||||
ATH6KL_USB_IS_DIR_IN
|
||||
(endpoint->bEndpointAddress) ?
|
||||
"RX" : "TX", endpoint->bEndpointAddress,
|
||||
le16_to_cpu(endpoint->wMaxPacketSize),
|
||||
endpoint->bInterval);
|
||||
} else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) {
|
||||
/* TODO for ISO */
|
||||
ath6kl_dbg(ATH6KL_DBG_USB,
|
||||
"%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d\n",
|
||||
ATH6KL_USB_IS_DIR_IN
|
||||
(endpoint->bEndpointAddress) ?
|
||||
"RX" : "TX", endpoint->bEndpointAddress,
|
||||
le16_to_cpu(endpoint->wMaxPacketSize),
|
||||
endpoint->bInterval);
|
||||
}
|
||||
urbcount = 0;
|
||||
|
||||
pipe_num =
|
||||
ath6kl_usb_get_logical_pipe_num(ar_usb,
|
||||
endpoint->bEndpointAddress,
|
||||
&urbcount);
|
||||
if (pipe_num == ATH6KL_USB_PIPE_INVALID)
|
||||
continue;
|
||||
|
||||
pipe = &ar_usb->pipes[pipe_num];
|
||||
if (pipe->ar_usb != NULL) {
|
||||
/* hmmm..pipe was already setup */
|
||||
continue;
|
||||
}
|
||||
|
||||
pipe->ar_usb = ar_usb;
|
||||
pipe->logical_pipe_num = pipe_num;
|
||||
pipe->ep_address = endpoint->bEndpointAddress;
|
||||
pipe->max_packet_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
|
||||
if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) {
|
||||
if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) {
|
||||
pipe->usb_pipe_handle =
|
||||
usb_rcvbulkpipe(ar_usb->udev,
|
||||
pipe->ep_address);
|
||||
} else {
|
||||
pipe->usb_pipe_handle =
|
||||
usb_sndbulkpipe(ar_usb->udev,
|
||||
pipe->ep_address);
|
||||
}
|
||||
} else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) {
|
||||
if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) {
|
||||
pipe->usb_pipe_handle =
|
||||
usb_rcvintpipe(ar_usb->udev,
|
||||
pipe->ep_address);
|
||||
} else {
|
||||
pipe->usb_pipe_handle =
|
||||
usb_sndintpipe(ar_usb->udev,
|
||||
pipe->ep_address);
|
||||
}
|
||||
} else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) {
|
||||
/* TODO for ISO */
|
||||
if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) {
|
||||
pipe->usb_pipe_handle =
|
||||
usb_rcvisocpipe(ar_usb->udev,
|
||||
pipe->ep_address);
|
||||
} else {
|
||||
pipe->usb_pipe_handle =
|
||||
usb_sndisocpipe(ar_usb->udev,
|
||||
pipe->ep_address);
|
||||
}
|
||||
}
|
||||
|
||||
pipe->ep_desc = endpoint;
|
||||
|
||||
if (!ATH6KL_USB_IS_DIR_IN(pipe->ep_address))
|
||||
pipe->flags |= ATH6KL_USB_PIPE_FLAG_TX;
|
||||
|
||||
status = ath6kl_usb_alloc_pipe_resources(pipe, urbcount);
|
||||
if (status != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* pipe operations */
|
||||
static void ath6kl_usb_post_recv_transfers(struct ath6kl_usb_pipe *recv_pipe,
|
||||
int buffer_length)
|
||||
{
|
||||
struct ath6kl_urb_context *urb_context;
|
||||
struct urb *urb;
|
||||
int usb_status;
|
||||
|
||||
while (true) {
|
||||
urb_context = ath6kl_usb_alloc_urb_from_pipe(recv_pipe);
|
||||
if (urb_context == NULL)
|
||||
break;
|
||||
|
||||
urb_context->skb = dev_alloc_skb(buffer_length);
|
||||
if (urb_context->skb == NULL)
|
||||
goto err_cleanup_urb;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (urb == NULL)
|
||||
goto err_cleanup_urb;
|
||||
|
||||
usb_fill_bulk_urb(urb,
|
||||
recv_pipe->ar_usb->udev,
|
||||
recv_pipe->usb_pipe_handle,
|
||||
urb_context->skb->data,
|
||||
buffer_length,
|
||||
ath6kl_usb_recv_complete, urb_context);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"ath6kl usb: bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes buf:0x%p\n",
|
||||
recv_pipe->logical_pipe_num,
|
||||
recv_pipe->usb_pipe_handle, recv_pipe->ep_address,
|
||||
buffer_length, urb_context->skb);
|
||||
|
||||
usb_anchor_urb(urb, &recv_pipe->urb_submitted);
|
||||
usb_status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
|
||||
if (usb_status) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"ath6kl usb : usb bulk recv failed %d\n",
|
||||
usb_status);
|
||||
usb_unanchor_urb(urb);
|
||||
usb_free_urb(urb);
|
||||
goto err_cleanup_urb;
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
return;
|
||||
|
||||
err_cleanup_urb:
|
||||
ath6kl_usb_cleanup_recv_urb(urb_context);
|
||||
return;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_flush_all(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) {
|
||||
if (ar_usb->pipes[i].ar_usb != NULL)
|
||||
usb_kill_anchored_urbs(&ar_usb->pipes[i].urb_submitted);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flushing any pending I/O may schedule work this call will block
|
||||
* until all scheduled work runs to completion.
|
||||
*/
|
||||
flush_scheduled_work();
|
||||
}
|
||||
|
||||
static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
/*
|
||||
* note: control pipe is no longer used
|
||||
* ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_cnt_thresh =
|
||||
* ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_alloc/2;
|
||||
* ath6kl_usb_post_recv_transfers(&ar_usb->
|
||||
* pipes[ATH6KL_USB_PIPE_RX_CTRL],
|
||||
* ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
*/
|
||||
|
||||
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh =
|
||||
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
|
||||
ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
|
||||
ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/* hif usb rx/tx completion functions */
|
||||
static void ath6kl_usb_recv_complete(struct urb *urb)
|
||||
{
|
||||
struct ath6kl_urb_context *urb_context = urb->context;
|
||||
struct ath6kl_usb_pipe *pipe = urb_context->pipe;
|
||||
struct sk_buff *skb = NULL;
|
||||
int status = 0;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"%s: recv pipe: %d, stat:%d, len:%d urb:0x%p\n", __func__,
|
||||
pipe->logical_pipe_num, urb->status, urb->actual_length,
|
||||
urb);
|
||||
|
||||
if (urb->status != 0) {
|
||||
status = -EIO;
|
||||
switch (urb->status) {
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/*
|
||||
* no need to spew these errors when device
|
||||
* removed or urb killed due to driver shutdown
|
||||
*/
|
||||
status = -ECANCELED;
|
||||
break;
|
||||
default:
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"%s recv pipe: %d (ep:0x%2.2X), failed:%d\n",
|
||||
__func__, pipe->logical_pipe_num,
|
||||
pipe->ep_address, urb->status);
|
||||
break;
|
||||
}
|
||||
goto cleanup_recv_urb;
|
||||
}
|
||||
|
||||
if (urb->actual_length == 0)
|
||||
goto cleanup_recv_urb;
|
||||
|
||||
skb = urb_context->skb;
|
||||
|
||||
/* we are going to pass it up */
|
||||
urb_context->skb = NULL;
|
||||
skb_put(skb, urb->actual_length);
|
||||
|
||||
/* note: queue implements a lock */
|
||||
skb_queue_tail(&pipe->io_comp_queue, skb);
|
||||
schedule_work(&pipe->io_complete_work);
|
||||
|
||||
cleanup_recv_urb:
|
||||
ath6kl_usb_cleanup_recv_urb(urb_context);
|
||||
|
||||
if (status == 0 &&
|
||||
pipe->urb_cnt >= pipe->urb_cnt_thresh) {
|
||||
/* our free urbs are piling up, post more transfers */
|
||||
ath6kl_usb_post_recv_transfers(pipe, ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath6kl_usb_usb_transmit_complete(struct urb *urb)
|
||||
{
|
||||
struct ath6kl_urb_context *urb_context = urb->context;
|
||||
struct ath6kl_usb_pipe *pipe = urb_context->pipe;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"%s: pipe: %d, stat:%d, len:%d\n",
|
||||
__func__, pipe->logical_pipe_num, urb->status,
|
||||
urb->actual_length);
|
||||
|
||||
if (urb->status != 0) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"%s: pipe: %d, failed:%d\n",
|
||||
__func__, pipe->logical_pipe_num, urb->status);
|
||||
}
|
||||
|
||||
skb = urb_context->skb;
|
||||
urb_context->skb = NULL;
|
||||
ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
|
||||
|
||||
/* note: queue implements a lock */
|
||||
skb_queue_tail(&pipe->io_comp_queue, skb);
|
||||
schedule_work(&pipe->io_complete_work);
|
||||
}
|
||||
|
||||
static void ath6kl_usb_io_comp_work(struct work_struct *work)
|
||||
{
|
||||
struct ath6kl_usb_pipe *pipe = container_of(work,
|
||||
struct ath6kl_usb_pipe,
|
||||
io_complete_work);
|
||||
struct ath6kl_usb *ar_usb;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ar_usb = pipe->ar_usb;
|
||||
|
||||
while ((skb = skb_dequeue(&pipe->io_comp_queue))) {
|
||||
if (pipe->flags & ATH6KL_USB_PIPE_FLAG_TX) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"ath6kl usb xmit callback buf:0x%p\n", skb);
|
||||
ath6kl_core_tx_complete(ar_usb->ar, skb);
|
||||
} else {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"ath6kl usb recv callback buf:0x%p\n", skb);
|
||||
ath6kl_core_rx_complete(ar_usb->ar, skb,
|
||||
pipe->logical_pipe_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
|
||||
#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
|
||||
|
||||
static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
ath6kl_usb_flush_all(ar_usb);
|
||||
|
||||
ath6kl_usb_cleanup_pipe_resources(ar_usb);
|
||||
|
||||
usb_set_intfdata(ar_usb->interface, NULL);
|
||||
|
||||
kfree(ar_usb->diag_cmd_buffer);
|
||||
@ -70,19 +614,28 @@ static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
|
||||
|
||||
static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = NULL;
|
||||
struct usb_device *dev = interface_to_usbdev(interface);
|
||||
struct ath6kl_usb *ar_usb;
|
||||
struct ath6kl_usb_pipe *pipe;
|
||||
int status = 0;
|
||||
int i;
|
||||
|
||||
ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
|
||||
if (ar_usb == NULL)
|
||||
goto fail_ath6kl_usb_create;
|
||||
|
||||
memset(ar_usb, 0, sizeof(struct ath6kl_usb));
|
||||
usb_set_intfdata(interface, ar_usb);
|
||||
spin_lock_init(&(ar_usb->cs_lock));
|
||||
ar_usb->udev = dev;
|
||||
ar_usb->interface = interface;
|
||||
|
||||
for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) {
|
||||
pipe = &ar_usb->pipes[i];
|
||||
INIT_WORK(&pipe->io_complete_work,
|
||||
ath6kl_usb_io_comp_work);
|
||||
skb_queue_head_init(&pipe->io_comp_queue);
|
||||
}
|
||||
|
||||
ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
|
||||
if (ar_usb->diag_cmd_buffer == NULL) {
|
||||
status = -ENOMEM;
|
||||
@ -96,6 +649,8 @@ static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
|
||||
goto fail_ath6kl_usb_create;
|
||||
}
|
||||
|
||||
status = ath6kl_usb_setup_pipe_resources(ar_usb);
|
||||
|
||||
fail_ath6kl_usb_create:
|
||||
if (status != 0) {
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
@ -114,11 +669,177 @@ static void ath6kl_usb_device_detached(struct usb_interface *interface)
|
||||
|
||||
ath6kl_stop_txrx(ar_usb->ar);
|
||||
|
||||
/* Delay to wait for the target to reboot */
|
||||
mdelay(20);
|
||||
ath6kl_core_cleanup(ar_usb->ar);
|
||||
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
}
|
||||
|
||||
/* exported hif usb APIs for htc pipe */
|
||||
static void hif_start(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_usb *device = ath6kl_usb_priv(ar);
|
||||
int i;
|
||||
|
||||
ath6kl_usb_start_recv_pipes(device);
|
||||
|
||||
/* set the TX resource avail threshold for each TX pipe */
|
||||
for (i = ATH6KL_USB_PIPE_TX_CTRL;
|
||||
i <= ATH6KL_USB_PIPE_TX_DATA_HP; i++) {
|
||||
device->pipes[i].urb_cnt_thresh =
|
||||
device->pipes[i].urb_alloc / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath6kl_usb_send(struct ath6kl *ar, u8 PipeID,
|
||||
struct sk_buff *hdr_skb, struct sk_buff *skb)
|
||||
{
|
||||
struct ath6kl_usb *device = ath6kl_usb_priv(ar);
|
||||
struct ath6kl_usb_pipe *pipe = &device->pipes[PipeID];
|
||||
struct ath6kl_urb_context *urb_context;
|
||||
int usb_status, status = 0;
|
||||
struct urb *urb;
|
||||
u8 *data;
|
||||
u32 len;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK, "+%s pipe : %d, buf:0x%p\n",
|
||||
__func__, PipeID, skb);
|
||||
|
||||
urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe);
|
||||
|
||||
if (urb_context == NULL) {
|
||||
/*
|
||||
* TODO: it is possible to run out of urbs if
|
||||
* 2 endpoints map to the same pipe ID
|
||||
*/
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"%s pipe:%d no urbs left. URB Cnt : %d\n",
|
||||
__func__, PipeID, pipe->urb_cnt);
|
||||
status = -ENOMEM;
|
||||
goto fail_hif_send;
|
||||
}
|
||||
|
||||
urb_context->skb = skb;
|
||||
|
||||
data = skb->data;
|
||||
len = skb->len;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (urb == NULL) {
|
||||
status = -ENOMEM;
|
||||
ath6kl_usb_free_urb_to_pipe(urb_context->pipe,
|
||||
urb_context);
|
||||
goto fail_hif_send;
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(urb,
|
||||
device->udev,
|
||||
pipe->usb_pipe_handle,
|
||||
data,
|
||||
len,
|
||||
ath6kl_usb_usb_transmit_complete, urb_context);
|
||||
|
||||
if ((len % pipe->max_packet_size) == 0) {
|
||||
/* hit a max packet boundary on this pipe */
|
||||
urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"athusb bulk send submit:%d, 0x%X (ep:0x%2.2X), %d bytes\n",
|
||||
pipe->logical_pipe_num, pipe->usb_pipe_handle,
|
||||
pipe->ep_address, len);
|
||||
|
||||
usb_anchor_urb(urb, &pipe->urb_submitted);
|
||||
usb_status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
|
||||
if (usb_status) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB_BULK,
|
||||
"ath6kl usb : usb bulk transmit failed %d\n",
|
||||
usb_status);
|
||||
usb_unanchor_urb(urb);
|
||||
ath6kl_usb_free_urb_to_pipe(urb_context->pipe,
|
||||
urb_context);
|
||||
status = -EINVAL;
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
|
||||
fail_hif_send:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void hif_stop(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_usb *device = ath6kl_usb_priv(ar);
|
||||
|
||||
ath6kl_usb_flush_all(device);
|
||||
}
|
||||
|
||||
static void ath6kl_usb_get_default_pipe(struct ath6kl *ar,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_CTRL;
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_CTRL;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
switch (svc_id) {
|
||||
case HTC_CTRL_RSVD_SVC:
|
||||
case WMI_CONTROL_SVC:
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_CTRL;
|
||||
/* due to large control packets, shift to data pipe */
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
|
||||
break;
|
||||
case WMI_DATA_BE_SVC:
|
||||
case WMI_DATA_BK_SVC:
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
|
||||
/*
|
||||
* Disable rxdata2 directly, it will be enabled
|
||||
* if FW enable rxdata2
|
||||
*/
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
|
||||
break;
|
||||
case WMI_DATA_VI_SVC:
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
|
||||
/*
|
||||
* Disable rxdata2 directly, it will be enabled
|
||||
* if FW enable rxdata2
|
||||
*/
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
|
||||
break;
|
||||
case WMI_DATA_VO_SVC:
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP;
|
||||
/*
|
||||
* Disable rxdata2 directly, it will be enabled
|
||||
* if FW enable rxdata2
|
||||
*/
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
|
||||
break;
|
||||
default:
|
||||
status = -EPERM;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static u16 ath6kl_usb_get_free_queue_number(struct ath6kl *ar, u8 pipe_id)
|
||||
{
|
||||
struct ath6kl_usb *device = ath6kl_usb_priv(ar);
|
||||
|
||||
return device->pipes[pipe_id].urb_cnt;
|
||||
}
|
||||
|
||||
static void hif_detach_htc(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_usb *device = ath6kl_usb_priv(ar);
|
||||
|
||||
ath6kl_usb_flush_all(device);
|
||||
}
|
||||
|
||||
static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
|
||||
u8 req, u16 value, u16 index, void *data,
|
||||
u32 size)
|
||||
@ -301,14 +1022,21 @@ static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
|
||||
static int ath6kl_usb_power_on(struct ath6kl *ar)
|
||||
{
|
||||
hif_start(ar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_power_off(struct ath6kl *ar)
|
||||
{
|
||||
hif_detach_htc(ar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_stop(struct ath6kl *ar)
|
||||
{
|
||||
hif_stop(ar);
|
||||
}
|
||||
|
||||
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
|
||||
.diag_read32 = ath6kl_usb_diag_read32,
|
||||
.diag_write32 = ath6kl_usb_diag_write32,
|
||||
@ -316,6 +1044,11 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = {
|
||||
.bmi_write = ath6kl_usb_bmi_write,
|
||||
.power_on = ath6kl_usb_power_on,
|
||||
.power_off = ath6kl_usb_power_off,
|
||||
.stop = ath6kl_usb_stop,
|
||||
.pipe_send = ath6kl_usb_send,
|
||||
.pipe_get_default = ath6kl_usb_get_default_pipe,
|
||||
.pipe_map_service = ath6kl_usb_map_service_pipe,
|
||||
.pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number,
|
||||
};
|
||||
|
||||
/* ath6kl usb driver registered functions */
|
||||
@ -368,7 +1101,7 @@ static int ath6kl_usb_probe(struct usb_interface *interface,
|
||||
|
||||
ar_usb->ar = ar;
|
||||
|
||||
ret = ath6kl_core_init(ar);
|
||||
ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_PIPE);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to init ath6kl core: %d\n", ret);
|
||||
goto err_core_free;
|
||||
@ -392,6 +1125,46 @@ static void ath6kl_usb_remove(struct usb_interface *interface)
|
||||
ath6kl_usb_device_detached(interface);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int ath6kl_usb_suspend(struct usb_interface *interface,
|
||||
pm_message_t message)
|
||||
{
|
||||
struct ath6kl_usb *device;
|
||||
device = usb_get_intfdata(interface);
|
||||
|
||||
ath6kl_usb_flush_all(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_resume(struct usb_interface *interface)
|
||||
{
|
||||
struct ath6kl_usb *device;
|
||||
device = usb_get_intfdata(interface);
|
||||
|
||||
ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA],
|
||||
ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA2],
|
||||
ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_reset_resume(struct usb_interface *intf)
|
||||
{
|
||||
if (usb_get_intfdata(intf))
|
||||
ath6kl_usb_remove(intf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ath6kl_usb_suspend NULL
|
||||
#define ath6kl_usb_resume NULL
|
||||
#define ath6kl_usb_reset_resume NULL
|
||||
|
||||
#endif
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static struct usb_device_id ath6kl_usb_ids[] = {
|
||||
{USB_DEVICE(0x0cf3, 0x9374)},
|
||||
@ -403,8 +1176,12 @@ MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids);
|
||||
static struct usb_driver ath6kl_usb_driver = {
|
||||
.name = "ath6kl_usb",
|
||||
.probe = ath6kl_usb_probe,
|
||||
.suspend = ath6kl_usb_suspend,
|
||||
.resume = ath6kl_usb_resume,
|
||||
.reset_resume = ath6kl_usb_reset_resume,
|
||||
.disconnect = ath6kl_usb_remove,
|
||||
.id_table = ath6kl_usb_ids,
|
||||
.supports_autosuspend = true,
|
||||
};
|
||||
|
||||
static int ath6kl_usb_init(void)
|
||||
|
@ -2882,6 +2882,43 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
|
||||
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)
|
||||
{
|
||||
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,
|
||||
cm->reason = cpu_to_le16(reason);
|
||||
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,
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
@ -3181,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
|
||||
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)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -3392,6 +3455,23 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx)
|
||||
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)
|
||||
{
|
||||
struct wmix_cmd_hdr *cmd;
|
||||
|
@ -182,6 +182,9 @@ enum wmi_data_hdr_flags {
|
||||
#define WMI_DATA_HDR_META_MASK 0x7
|
||||
#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 */
|
||||
#define WMI_DATA_HDR_IF_IDX_MASK 0xF
|
||||
|
||||
@ -423,6 +426,7 @@ enum wmi_cmd_id {
|
||||
WMI_SET_FRAMERATES_CMDID,
|
||||
WMI_SET_AP_PS_CMDID,
|
||||
WMI_SET_QOS_SUPP_CMDID,
|
||||
WMI_SET_IE_CMDID,
|
||||
|
||||
/* WMI_THIN_RESERVED_... mark the start and end
|
||||
* values for WMI_THIN_RESERVED command IDs. These
|
||||
@ -629,6 +633,11 @@ enum wmi_mgmt_frame_type {
|
||||
WMI_NUM_MGMT_FRAME
|
||||
};
|
||||
|
||||
enum wmi_ie_field_type {
|
||||
WMI_RSN_IE_CAPB = 0x1,
|
||||
WMI_IE_FULL = 0xFF, /* indicats full IE */
|
||||
};
|
||||
|
||||
/* WMI_CONNECT_CMDID */
|
||||
enum network_type {
|
||||
INFRA_NETWORK = 0x01,
|
||||
@ -1268,6 +1277,16 @@ struct wmi_mcast_filter_add_del_cmd {
|
||||
u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
|
||||
} __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 */
|
||||
|
||||
/* WMI_GET_CHANNEL_LIST_CMDID reply */
|
||||
@ -1913,6 +1932,14 @@ struct wmi_set_appie_cmd {
|
||||
u8 ie_info[0];
|
||||
} __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 */
|
||||
#define WSC_REG_ACTIVE 1
|
||||
#define WSC_REG_INACTIVE 0
|
||||
@ -2141,6 +2168,11 @@ struct wmi_ap_hidden_ssid_cmd {
|
||||
u8 hidden_ssid;
|
||||
} __packed;
|
||||
|
||||
struct wmi_set_inact_period_cmd {
|
||||
__le32 inact_period;
|
||||
u8 num_null_func;
|
||||
} __packed;
|
||||
|
||||
/* AP mode events */
|
||||
struct wmi_ap_set_apsd_cmd {
|
||||
u8 enable;
|
||||
@ -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_keepalive_cmd(struct wmi *wmi, u8 if_idx,
|
||||
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);
|
||||
|
||||
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,
|
||||
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
|
||||
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 */
|
||||
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);
|
||||
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
|
||||
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);
|
||||
|
||||
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)
|
||||
aniState->rssiThrLow, aniState->rssiThrHigh);
|
||||
|
||||
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_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)
|
||||
immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
|
||||
|
||||
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_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
|
||||
|
@ -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);
|
||||
|
||||
ah->curchan = chan;
|
||||
ah->curchan_rad_index = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -136,6 +136,7 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
||||
}
|
||||
|
||||
if (sync_cause) {
|
||||
ath9k_debug_sync_cause(common, sync_cause);
|
||||
fatal_int =
|
||||
(sync_cause &
|
||||
(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)
|
||||
REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
|
||||
|
||||
ah->curchan = chan;
|
||||
ah->curchan_rad_index = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,11 +30,6 @@
|
||||
#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
|
||||
#define CTL_11G_EXT (CTL_11G | 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_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)
|
||||
#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)
|
||||
{
|
||||
return 0;
|
||||
@ -4070,7 +4056,7 @@ static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah,
|
||||
* targetpower piers stored on eeprom
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
@ -4106,7 +4092,7 @@ static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah,
|
||||
* from targetpower piers stored on eeprom
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
@ -4142,7 +4128,7 @@ static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah,
|
||||
* targetpower piers stored on eeprom
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
@ -4167,7 +4153,7 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah,
|
||||
* targetpower piers stored on eeprom
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
@ -4464,7 +4450,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
|
||||
is2GHz = 1;
|
||||
}
|
||||
|
||||
*pfrequency = FBIN2FREQ(*pCalPier, is2GHz);
|
||||
*pfrequency = ath9k_hw_fbin2freq(*pCalPier, is2GHz);
|
||||
*pcorrection = pCalPierStruct->refPower;
|
||||
*ptemperature = pCalPierStruct->tempMeas;
|
||||
*pvoltage = pCalPierStruct->voltMeas;
|
||||
@ -4789,30 +4775,8 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
|
||||
bool is2ghz = IS_CHAN_2GHZ(chan);
|
||||
|
||||
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
||||
scaledPower = 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);
|
||||
scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
|
||||
antenna_reduction);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
i, targetPowerValT2[i]);
|
||||
}
|
||||
|
||||
ah->txpower_limit = regulatory->max_power_level;
|
||||
|
||||
/* Write target power array to registers */
|
||||
ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
|
||||
ar9003_hw_calibration_apply(ah, chan->channel);
|
||||
|
@ -42,7 +42,6 @@
|
||||
#define AR9300_EEPMISC_WOW 0x02
|
||||
#define AR9300_CUSTOMER_DATA_SIZE 20
|
||||
|
||||
#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x))
|
||||
#define AR9300_MAX_CHAINS 3
|
||||
#define AR9300_ANT_16S 25
|
||||
#define AR9300_FUTURE_MODAL_SZ 6
|
||||
|
@ -305,11 +305,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
|
||||
ar9462_common_rx_gain_table_2p0,
|
||||
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 */
|
||||
INIT_INI_ARRAY(&ah->iniPcieSerdes,
|
||||
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)
|
||||
ar9003_mci_get_isr(ah, masked);
|
||||
|
||||
if (sync_cause) {
|
||||
ath9k_debug_sync_cause(common, sync_cause);
|
||||
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
|
||||
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
|
||||
REG_WRITE(ah, AR_RC, 0);
|
||||
|
@ -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);
|
||||
|
||||
ah->curchan = chan;
|
||||
ah->curchan_rad_index = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -209,11 +208,12 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
|
||||
continue;
|
||||
negative = 0;
|
||||
if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah))
|
||||
cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
|
||||
IS_CHAN_2GHZ(chan)) - synth_freq;
|
||||
cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i],
|
||||
IS_CHAN_2GHZ(chan));
|
||||
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) {
|
||||
negative = 1;
|
||||
cur_bb_spur = -cur_bb_spur;
|
||||
@ -443,7 +443,8 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
|
||||
ar9003_hw_spur_ofdm_clear(ah);
|
||||
|
||||
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) {
|
||||
ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
|
||||
break;
|
||||
@ -684,9 +685,6 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
|
||||
|
||||
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)
|
||||
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
|
||||
|
||||
|
@ -1115,9 +1115,9 @@ static const u32 ar9462_2p0_mac_core[][2] = {
|
||||
{0x000081f8, 0x00000000},
|
||||
{0x000081fc, 0x00000000},
|
||||
{0x00008240, 0x00100000},
|
||||
{0x00008244, 0x0010f400},
|
||||
{0x00008244, 0x0010f424},
|
||||
{0x00008248, 0x00000800},
|
||||
{0x0000824c, 0x0001e800},
|
||||
{0x0000824c, 0x0001e848},
|
||||
{0x00008250, 0x00000000},
|
||||
{0x00008254, 0x00000000},
|
||||
{0x00008258, 0x00000000},
|
||||
@ -1448,16 +1448,4 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = {
|
||||
{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 */
|
||||
|
@ -370,7 +370,7 @@ struct ath_vif {
|
||||
* number of beacon intervals, the game's up.
|
||||
*/
|
||||
#define BSTUCK_THRESH 9
|
||||
#define ATH_BCBUF 4
|
||||
#define ATH_BCBUF 8
|
||||
#define ATH_DEFAULT_BINTVAL 100 /* TU */
|
||||
#define ATH_DEFAULT_BMISS_LIMIT 10
|
||||
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
|
||||
|
@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
info.txpower = MAX_RATE_POWER;
|
||||
info.keyix = ATH9K_TXKEYIX_INVALID;
|
||||
info.keytype = ATH9K_KEY_TYPE_CLEAR;
|
||||
info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ;
|
||||
info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
|
||||
|
||||
info.buf_addr[0] = bf->bf_buf_addr;
|
||||
info.buf_len[0] = roundup(skb->len, 4);
|
||||
@ -359,6 +359,11 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
int slot;
|
||||
u32 bfaddr, bc = 0;
|
||||
|
||||
if (work_pending(&sc->hw_reset_work)) {
|
||||
ath_dbg(common, RESET,
|
||||
"reset work is pending, skip beaconing now\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Check if the previous beacon has gone out. If
|
||||
* not don't try to post another, skip this period
|
||||
@ -369,6 +374,9 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
|
||||
sc->beacon.bmisscnt++;
|
||||
|
||||
if (!ath9k_hw_check_alive(ah))
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
|
||||
|
||||
if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
|
||||
ath_dbg(common, BSTUCK,
|
||||
"missed %u consecutive beacons\n",
|
||||
@ -378,6 +386,7 @@ void ath_beacon_tasklet(unsigned long data)
|
||||
ath9k_hw_bstuck_nfcal(ah);
|
||||
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
||||
ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
|
||||
sc->beacon.bmisscnt = 0;
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
}
|
||||
@ -650,6 +659,8 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
||||
u32 tsf, intval, nexttbtt;
|
||||
|
||||
ath9k_reset_beacon_status(sc);
|
||||
if (!(sc->sc_flags & SC_OP_BEACONS))
|
||||
ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
|
||||
|
||||
intval = TU_TO_USEC(conf->beacon_interval);
|
||||
tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
|
||||
|
@ -380,63 +380,75 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char buf[512];
|
||||
unsigned int len = 0;
|
||||
int rv;
|
||||
int mxlen = 4000;
|
||||
char *buf = kmalloc(mxlen, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
#define PR_IS(a, s) \
|
||||
do { \
|
||||
len += snprintf(buf + len, mxlen - len, \
|
||||
"%21s: %10u\n", a, \
|
||||
sc->debug.stats.istats.s); \
|
||||
} while (0)
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "WATCHDOG",
|
||||
sc->debug.stats.istats.bb_watchdog);
|
||||
PR_IS("RXLP", rxlp);
|
||||
PR_IS("RXHP", rxhp);
|
||||
PR_IS("WATHDOG", bb_watchdog);
|
||||
} else {
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
|
||||
PR_IS("RX", rxok);
|
||||
}
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TX", sc->debug.stats.istats.txok);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "MIB", sc->debug.stats.istats.mib);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "CST", sc->debug.stats.istats.cst);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TIM", sc->debug.stats.istats.tim);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor);
|
||||
len += snprintf(buf + len, sizeof(buf) - len,
|
||||
"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
|
||||
PR_IS("RXEOL", rxeol);
|
||||
PR_IS("RXORN", rxorn);
|
||||
PR_IS("TX", txok);
|
||||
PR_IS("TXURN", txurn);
|
||||
PR_IS("MIB", mib);
|
||||
PR_IS("RXPHY", rxphyerr);
|
||||
PR_IS("RXKCM", rx_keycache_miss);
|
||||
PR_IS("SWBA", swba);
|
||||
PR_IS("BMISS", bmiss);
|
||||
PR_IS("BNR", bnr);
|
||||
PR_IS("CST", cst);
|
||||
PR_IS("GTT", gtt);
|
||||
PR_IS("TIM", tim);
|
||||
PR_IS("CABEND", cabend);
|
||||
PR_IS("DTIMSYNC", dtimsync);
|
||||
PR_IS("DTIM", dtim);
|
||||
PR_IS("TSFOOR", tsfoor);
|
||||
PR_IS("TOTAL", total);
|
||||
|
||||
len += snprintf(buf + len, mxlen - len,
|
||||
"SYNC_CAUSE stats:\n");
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
PR_IS("Sync-All", sync_cause_all);
|
||||
PR_IS("RTC-IRQ", sync_rtc_irq);
|
||||
PR_IS("MAC-IRQ", sync_mac_irq);
|
||||
PR_IS("EEPROM-Illegal-Access", eeprom_illegal_access);
|
||||
PR_IS("APB-Timeout", apb_timeout);
|
||||
PR_IS("PCI-Mode-Conflict", pci_mode_conflict);
|
||||
PR_IS("HOST1-Fatal", host1_fatal);
|
||||
PR_IS("HOST1-Perr", host1_perr);
|
||||
PR_IS("TRCV-FIFO-Perr", trcv_fifo_perr);
|
||||
PR_IS("RADM-CPL-EP", radm_cpl_ep);
|
||||
PR_IS("RADM-CPL-DLLP-Abort", radm_cpl_dllp_abort);
|
||||
PR_IS("RADM-CPL-TLP-Abort", radm_cpl_tlp_abort);
|
||||
PR_IS("RADM-CPL-ECRC-Err", radm_cpl_ecrc_err);
|
||||
PR_IS("RADM-CPL-Timeout", radm_cpl_timeout);
|
||||
PR_IS("Local-Bus-Timeout", local_timeout);
|
||||
PR_IS("PM-Access", pm_access);
|
||||
PR_IS("MAC-Awake", mac_awake);
|
||||
PR_IS("MAC-Asleep", mac_asleep);
|
||||
PR_IS("MAC-Sleep-Access", mac_sleep_access);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
if (len > mxlen)
|
||||
len = mxlen;
|
||||
|
||||
rv = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_interrupt = {
|
||||
@ -881,6 +893,13 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \
|
||||
sc->debug.stats.rxstats.phy_err_stats[p]);
|
||||
|
||||
#define RXS_ERR(s, e) \
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, \
|
||||
"%22s : %10u\n", s, \
|
||||
sc->debug.stats.rxstats.e); \
|
||||
} while (0)
|
||||
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 1600;
|
||||
@ -890,42 +909,18 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "CRC ERR",
|
||||
sc->debug.stats.rxstats.crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "DECRYPT CRC ERR",
|
||||
sc->debug.stats.rxstats.decrypt_crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "PHY ERR",
|
||||
sc->debug.stats.rxstats.phy_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "MIC ERR",
|
||||
sc->debug.stats.rxstats.mic_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "PRE-DELIM CRC ERR",
|
||||
sc->debug.stats.rxstats.pre_delim_crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "POST-DELIM CRC ERR",
|
||||
sc->debug.stats.rxstats.post_delim_crc_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "DECRYPT BUSY ERR",
|
||||
sc->debug.stats.rxstats.decrypt_busy_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-LENGTH-ERR",
|
||||
sc->debug.stats.rxstats.rx_len_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-OOM-ERR",
|
||||
sc->debug.stats.rxstats.rx_oom_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-RATE-ERR",
|
||||
sc->debug.stats.rxstats.rx_rate_err);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-DROP-RXFLUSH",
|
||||
sc->debug.stats.rxstats.rx_drop_rxflush);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-TOO-MANY-FRAGS",
|
||||
sc->debug.stats.rxstats.rx_too_many_frags_err);
|
||||
RXS_ERR("CRC ERR", crc_err);
|
||||
RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err);
|
||||
RXS_ERR("PHY ERR", phy_err);
|
||||
RXS_ERR("MIC ERR", mic_err);
|
||||
RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err);
|
||||
RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err);
|
||||
RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err);
|
||||
RXS_ERR("RX-LENGTH-ERR", rx_len_err);
|
||||
RXS_ERR("RX-OOM-ERR", rx_oom_err);
|
||||
RXS_ERR("RX-RATE-ERR", rx_rate_err);
|
||||
RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush);
|
||||
RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
|
||||
|
||||
PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
|
||||
PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING);
|
||||
@ -954,18 +949,10 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
|
||||
PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL);
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-Pkts-All",
|
||||
sc->debug.stats.rxstats.rx_pkts_all);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-Bytes-All",
|
||||
sc->debug.stats.rxstats.rx_bytes_all);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-Beacons",
|
||||
sc->debug.stats.rxstats.rx_beacons);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%22s : %10u\n", "RX-Frags",
|
||||
sc->debug.stats.rxstats.rx_frags);
|
||||
RXS_ERR("RX-Pkts-All", rx_pkts_all);
|
||||
RXS_ERR("RX-Bytes-All", rx_bytes_all);
|
||||
RXS_ERR("RX-Beacons", rx_beacons);
|
||||
RXS_ERR("RX-Frags", rx_frags);
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
@ -975,6 +962,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
|
||||
return retval;
|
||||
|
||||
#undef RXS_ERR
|
||||
#undef PHY_ERR
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ struct ath_buf;
|
||||
* @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
|
||||
* (programmable) threshold
|
||||
* @local_timeout: Internal bus timeout.
|
||||
*/
|
||||
struct ath_interrupt_stats {
|
||||
u32 total;
|
||||
@ -85,8 +86,30 @@ struct ath_interrupt_stats {
|
||||
u32 dtim;
|
||||
u32 bb_watchdog;
|
||||
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
|
||||
* @tx_pkts_all: No. of total frames transmitted, including ones that
|
||||
|
@ -16,14 +16,6 @@
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
|
||||
{
|
||||
if (fbin == AR5416_BCHAN_UNUSED)
|
||||
return fbin;
|
||||
|
||||
return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
|
||||
}
|
||||
|
||||
void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
|
||||
{
|
||||
REG_WRITE(ah, reg, val);
|
||||
@ -290,6 +282,34 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
|
||||
return twiceMaxEdgePower;
|
||||
}
|
||||
|
||||
u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
|
||||
u8 antenna_reduction)
|
||||
{
|
||||
u16 reduction = antenna_reduction;
|
||||
|
||||
/*
|
||||
* Reduce scaled Power by number of chains active
|
||||
* to get the per chain tx power level.
|
||||
*/
|
||||
switch (ar5416_get_ntxchains(ah->txchainmask)) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
|
||||
break;
|
||||
case 3:
|
||||
reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (power_limit > reduction)
|
||||
power_limit -= reduction;
|
||||
else
|
||||
power_limit = 0;
|
||||
|
||||
return power_limit;
|
||||
}
|
||||
|
||||
void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
@ -299,10 +319,10 @@ void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
|
||||
regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
|
||||
break;
|
||||
case 3:
|
||||
regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
|
||||
regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
|
||||
break;
|
||||
default:
|
||||
ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
|
||||
|
@ -79,8 +79,8 @@
|
||||
#define SUB_NUM_CTL_MODES_AT_5G_40 2
|
||||
#define SUB_NUM_CTL_MODES_AT_2G_40 3
|
||||
|
||||
#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
|
||||
#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */
|
||||
#define POWER_CORRECTION_FOR_TWO_CHAIN 6 /* 10*log10(2)*2 */
|
||||
#define POWER_CORRECTION_FOR_THREE_CHAIN 10 /* 10*log10(3)*2 */
|
||||
|
||||
/*
|
||||
* For AR9285 and later chipsets, the following bits are not being programmed
|
||||
@ -686,6 +686,8 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
|
||||
u16 numRates, bool isHt40Target);
|
||||
u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
|
||||
bool is2GHz, int num_band_edges);
|
||||
u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
|
||||
u8 antenna_reduction);
|
||||
void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
|
||||
int ath9k_hw_eeprom_init(struct ath_hw *ah);
|
||||
|
||||
@ -697,6 +699,14 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
|
||||
u16 *pPdGainBoundaries, u8 *pPDADCValues,
|
||||
u16 numXpdGains);
|
||||
|
||||
static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
|
||||
{
|
||||
if (fbin == AR5416_BCHAN_UNUSED)
|
||||
return fbin;
|
||||
|
||||
return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
|
||||
}
|
||||
|
||||
#define ar5416_get_ntxchains(_txchainmask) \
|
||||
(((_txchainmask >> 2) & 1) + \
|
||||
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
|
||||
|
@ -564,9 +564,6 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
|
||||
(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
|
||||
((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
|
||||
|
||||
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
|
||||
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
|
||||
|
||||
u16 twiceMaxEdgePower;
|
||||
int i;
|
||||
struct cal_ctl_data_ar9287 *rep;
|
||||
@ -591,29 +588,8 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
|
||||
tx_chainmask = ah->txchainmask;
|
||||
|
||||
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
||||
scaledPower = powerLimit - antenna_reduction;
|
||||
|
||||
/*
|
||||
* Reduce scaled Power by number of chains active
|
||||
* to get the per chain tx power level.
|
||||
*/
|
||||
switch (ar5416_get_ntxchains(tx_chainmask)) {
|
||||
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);
|
||||
scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
|
||||
antenna_reduction);
|
||||
|
||||
/*
|
||||
* Get TX power from EEPROM.
|
||||
@ -786,8 +762,6 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
|
||||
|
||||
#undef CMP_CTL
|
||||
#undef CMP_NO_CTL
|
||||
#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
|
||||
#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
|
||||
}
|
||||
|
||||
static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
|
||||
|
@ -991,9 +991,6 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
|
||||
u16 antenna_reduction,
|
||||
u16 powerLimit)
|
||||
{
|
||||
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
|
||||
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */
|
||||
|
||||
struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
|
||||
u16 twiceMaxEdgePower;
|
||||
int i;
|
||||
@ -1027,24 +1024,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
|
||||
|
||||
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
||||
|
||||
scaledPower = powerLimit - antenna_reduction;
|
||||
|
||||
switch (ar5416_get_ntxchains(tx_chainmask)) {
|
||||
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 = ath9k_hw_get_scaled_power(ah, powerLimit,
|
||||
antenna_reduction);
|
||||
|
||||
if (IS_CHAN_2GHZ(chan)) {
|
||||
numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
|
||||
@ -1263,20 +1244,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
|
||||
regulatory->max_power_level = ratesArray[i];
|
||||
}
|
||||
|
||||
switch(ar5416_get_ntxchains(ah->txchainmask)) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
|
||||
break;
|
||||
case 3:
|
||||
regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
|
||||
break;
|
||||
default:
|
||||
ath_dbg(ath9k_hw_common(ah), EEPROM,
|
||||
"Invalid chainmask configuration\n");
|
||||
break;
|
||||
}
|
||||
ath9k_hw_update_regulatory_maxpower(ah);
|
||||
|
||||
if (test)
|
||||
return;
|
||||
|
@ -41,6 +41,9 @@ void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (AR_SREV_9100(sc->sc_ah))
|
||||
return;
|
||||
|
||||
if (sc->sc_ah->led_pin < 0) {
|
||||
if (AR_SREV_9287(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9287;
|
||||
|
@ -53,6 +53,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
|
||||
.driver_info = AR9280_USB }, /* SMC Networks */
|
||||
{ USB_DEVICE(0x0411, 0x017f),
|
||||
.driver_info = AR9280_USB }, /* Sony UWA-BR100 */
|
||||
{ USB_DEVICE(0x04da, 0x3904),
|
||||
.driver_info = AR9280_USB },
|
||||
|
||||
{ USB_DEVICE(0x0cf3, 0x20ff),
|
||||
.driver_info = STORAGE_DEVICE },
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "rc.h"
|
||||
#include "ar9003_mac.h"
|
||||
#include "ar9003_mci.h"
|
||||
#include "debug.h"
|
||||
#include "ath9k.h"
|
||||
|
||||
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
|
||||
|
||||
@ -83,6 +85,53 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
|
||||
/* Helper Functions */
|
||||
/********************/
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
|
||||
void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause)
|
||||
{
|
||||
struct ath_softc *sc = common->priv;
|
||||
if (sync_cause)
|
||||
sc->debug.stats.istats.sync_cause_all++;
|
||||
if (sync_cause & AR_INTR_SYNC_RTC_IRQ)
|
||||
sc->debug.stats.istats.sync_rtc_irq++;
|
||||
if (sync_cause & AR_INTR_SYNC_MAC_IRQ)
|
||||
sc->debug.stats.istats.sync_mac_irq++;
|
||||
if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS)
|
||||
sc->debug.stats.istats.eeprom_illegal_access++;
|
||||
if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT)
|
||||
sc->debug.stats.istats.apb_timeout++;
|
||||
if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT)
|
||||
sc->debug.stats.istats.pci_mode_conflict++;
|
||||
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL)
|
||||
sc->debug.stats.istats.host1_fatal++;
|
||||
if (sync_cause & AR_INTR_SYNC_HOST1_PERR)
|
||||
sc->debug.stats.istats.host1_perr++;
|
||||
if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR)
|
||||
sc->debug.stats.istats.trcv_fifo_perr++;
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP)
|
||||
sc->debug.stats.istats.radm_cpl_ep++;
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT)
|
||||
sc->debug.stats.istats.radm_cpl_dllp_abort++;
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT)
|
||||
sc->debug.stats.istats.radm_cpl_tlp_abort++;
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR)
|
||||
sc->debug.stats.istats.radm_cpl_ecrc_err++;
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT)
|
||||
sc->debug.stats.istats.radm_cpl_timeout++;
|
||||
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
|
||||
sc->debug.stats.istats.local_timeout++;
|
||||
if (sync_cause & AR_INTR_SYNC_PM_ACCESS)
|
||||
sc->debug.stats.istats.pm_access++;
|
||||
if (sync_cause & AR_INTR_SYNC_MAC_AWAKE)
|
||||
sc->debug.stats.istats.mac_awake++;
|
||||
if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP)
|
||||
sc->debug.stats.istats.mac_asleep++;
|
||||
if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS)
|
||||
sc->debug.stats.istats.mac_sleep_access++;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void ath9k_hw_set_clockrate(struct ath_hw *ah)
|
||||
{
|
||||
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
|
||||
@ -388,8 +437,8 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
||||
{
|
||||
int i;
|
||||
|
||||
ah->config.dma_beacon_response_time = 2;
|
||||
ah->config.sw_beacon_response_time = 10;
|
||||
ah->config.dma_beacon_response_time = 1;
|
||||
ah->config.sw_beacon_response_time = 6;
|
||||
ah->config.additional_swba_backoff = 0;
|
||||
ah->config.ack_6mb = 0x0;
|
||||
ah->config.cwm_ignore_extcca = 0;
|
||||
@ -445,7 +494,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
||||
AR_STA_ID1_MCAST_KSRCH;
|
||||
if (AR_SREV_9100(ah))
|
||||
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
|
||||
ah->enable_32kHz_clock = DONT_USE_32KHZ;
|
||||
ah->slottime = ATH9K_SLOT_TIME_9;
|
||||
ah->globaltxtimeout = (u32) -1;
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
|
@ -708,7 +708,6 @@ struct ath_hw {
|
||||
struct ar5416Stats stats;
|
||||
struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
|
||||
|
||||
int16_t curchan_rad_index;
|
||||
enum ath9k_int imask;
|
||||
u32 imrs2_reg;
|
||||
u32 txok_interrupt_mask;
|
||||
@ -762,11 +761,6 @@ struct ath_hw {
|
||||
|
||||
u32 sta_id1_defaults;
|
||||
u32 misc_mode;
|
||||
enum {
|
||||
AUTO_32KHZ,
|
||||
USE_32KHZ,
|
||||
DONT_USE_32KHZ,
|
||||
} enable_32kHz_clock;
|
||||
|
||||
/* Private to hardware code */
|
||||
struct ath_hw_private_ops private_ops;
|
||||
@ -783,7 +777,6 @@ struct ath_hw {
|
||||
u32 *analogBank7Data;
|
||||
u32 *bank6Temp;
|
||||
|
||||
u8 txpower_limit;
|
||||
int coverage_class;
|
||||
u32 slottime;
|
||||
u32 globaltxtimeout;
|
||||
@ -848,7 +841,6 @@ struct ath_hw {
|
||||
struct ath_gen_timer_table hw_gen_timers;
|
||||
|
||||
struct ar9003_txs *ts_ring;
|
||||
void *ts_start;
|
||||
u32 ts_paddr_start;
|
||||
u32 ts_paddr_end;
|
||||
u16 ts_tail;
|
||||
@ -915,7 +907,6 @@ static inline u8 get_streams(int mask)
|
||||
}
|
||||
|
||||
/* Initialization, Detach, Reset */
|
||||
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
|
||||
void ath9k_hw_deinit(struct ath_hw *ah);
|
||||
int ath9k_hw_init(struct ath_hw *ah);
|
||||
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
@ -965,6 +956,12 @@ bool ath9k_hw_check_alive(struct ath_hw *ah);
|
||||
|
||||
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause);
|
||||
#else
|
||||
static void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause) {}
|
||||
#endif
|
||||
|
||||
/* Generic hw timer primitives */
|
||||
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
|
||||
void (*trigger)(void *),
|
||||
@ -1011,7 +1008,6 @@ int ar9003_paprd_create_curve(struct ath_hw *ah,
|
||||
int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
|
||||
int ar9003_paprd_init_table(struct ath_hw *ah);
|
||||
bool ar9003_paprd_is_done(struct ath_hw *ah);
|
||||
void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains);
|
||||
|
||||
/* Hardware family op attach helpers */
|
||||
void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
|
||||
|
@ -692,17 +692,6 @@ void ath9k_tasklet(unsigned long data)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only run the baseband hang check if beacons stop working in AP or
|
||||
* IBSS mode, because it has a high false positive rate. For station
|
||||
* mode it should not be necessary, since the upper layers will detect
|
||||
* this through a beacon miss automatically and the following channel
|
||||
* change will trigger a hardware reset anyway
|
||||
*/
|
||||
if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 &&
|
||||
!ath9k_hw_check_alive(ah))
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
|
||||
|
||||
if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
|
||||
/*
|
||||
* TSF sync does not look correct; remain awake to sync with
|
||||
|
@ -3989,8 +3989,7 @@ static int reset_atmel_card(struct net_device *dev)
|
||||
atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000);
|
||||
}
|
||||
|
||||
if (fw_entry)
|
||||
release_firmware(fw_entry);
|
||||
release_firmware(fw_entry);
|
||||
}
|
||||
|
||||
err = atmel_wakeup_firmware(priv);
|
||||
|
@ -74,15 +74,4 @@ static void __devexit atmel_pci_remove(struct pci_dev *pdev)
|
||||
stop_atmel_card(pci_get_drvdata(pdev));
|
||||
}
|
||||
|
||||
static int __init atmel_init_module(void)
|
||||
{
|
||||
return pci_register_driver(&atmel_driver);
|
||||
}
|
||||
|
||||
static void __exit atmel_cleanup_module(void)
|
||||
{
|
||||
pci_unregister_driver(&atmel_driver);
|
||||
}
|
||||
|
||||
module_init(atmel_init_module);
|
||||
module_exit(atmel_cleanup_module);
|
||||
module_pci_driver(atmel_driver);
|
||||
|
@ -290,7 +290,8 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
||||
txhdr->dur_fb = wlhdr->duration_id;
|
||||
} else {
|
||||
txhdr->dur_fb = ieee80211_generic_frame_duration(
|
||||
dev->wl->hw, info->control.vif, fragment_len, fbrate);
|
||||
dev->wl->hw, info->control.vif, info->band,
|
||||
fragment_len, fbrate);
|
||||
}
|
||||
|
||||
plcp_fragment_len = fragment_len + FCS_LEN;
|
||||
|
@ -1056,6 +1056,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
|
||||
b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
|
||||
dur = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
dev->wl->vif,
|
||||
IEEE80211_BAND_2GHZ,
|
||||
size,
|
||||
rate);
|
||||
/* Write PLCP in two parts and timing for packet transfer */
|
||||
@ -1121,6 +1122,7 @@ static const u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
dur = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
dev->wl->vif,
|
||||
IEEE80211_BAND_2GHZ,
|
||||
*dest_size,
|
||||
rate);
|
||||
hdr->duration_id = dur;
|
||||
|
@ -228,6 +228,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
|
||||
} else {
|
||||
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
info->control.vif,
|
||||
info->band,
|
||||
fragment_len,
|
||||
rate_fb);
|
||||
}
|
||||
|
@ -632,7 +632,6 @@ extern const struct bcmevent_name bcmevent_names[];
|
||||
extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
|
||||
char *buf, uint len);
|
||||
|
||||
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
|
||||
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
|
||||
|
||||
extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len);
|
||||
|
@ -421,6 +421,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
|
||||
pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
|
||||
|
||||
skb_pull(pktbuf, BDC_HEADER_LEN);
|
||||
skb_pull(pktbuf, h->data_offset << 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -799,7 +799,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
|
||||
{
|
||||
char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for
|
||||
"event_msgs" + '\0' + bitvec */
|
||||
uint up = 0;
|
||||
char buf[128], *ptr;
|
||||
u32 dongle_align = drvr->bus_if->align;
|
||||
u32 glom = 0;
|
||||
@ -853,9 +852,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
|
||||
brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
|
||||
sizeof(iovbuf));
|
||||
|
||||
/* Force STA UP */
|
||||
brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up));
|
||||
|
||||
/* Setup event_msgs */
|
||||
brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
|
||||
iovbuf, sizeof(iovbuf));
|
||||
|
@ -799,6 +799,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
|
||||
struct brcmf_bus *bus_if = drvr->bus_if;
|
||||
u32 toe_ol;
|
||||
s32 ret = 0;
|
||||
uint up = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
|
||||
|
||||
@ -822,6 +823,10 @@ static int brcmf_netdev_open(struct net_device *ndev)
|
||||
drvr->iflist[ifp->idx]->ndev->features &=
|
||||
~NETIF_F_IP_CSUM;
|
||||
}
|
||||
|
||||
/* make sure RF is ready for work */
|
||||
brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up));
|
||||
|
||||
/* Allow transmit calls */
|
||||
netif_start_queue(ndev);
|
||||
drvr->bus_if->drvr_up = true;
|
||||
@ -843,6 +848,63 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
|
||||
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
|
||||
};
|
||||
|
||||
static int brcmf_net_attach(struct brcmf_if *ifp)
|
||||
{
|
||||
struct brcmf_pub *drvr = ifp->drvr;
|
||||
struct net_device *ndev;
|
||||
u8 temp_addr[ETH_ALEN];
|
||||
|
||||
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
|
||||
|
||||
ndev = drvr->iflist[ifp->idx]->ndev;
|
||||
ndev->netdev_ops = &brcmf_netdev_ops_pri;
|
||||
|
||||
/*
|
||||
* determine mac address to use
|
||||
*/
|
||||
if (is_valid_ether_addr(ifp->mac_addr))
|
||||
memcpy(temp_addr, ifp->mac_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(temp_addr, drvr->mac, ETH_ALEN);
|
||||
|
||||
if (ifp->idx == 1) {
|
||||
brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
|
||||
/* ACCESSPOINT INTERFACE CASE */
|
||||
temp_addr[0] |= 0X02; /* set bit 2 ,
|
||||
- Locally Administered address */
|
||||
|
||||
}
|
||||
ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
|
||||
ndev->ethtool_ops = &brcmf_ethtool_ops;
|
||||
|
||||
drvr->rxsz = ndev->mtu + ndev->hard_header_len +
|
||||
drvr->hdrlen;
|
||||
|
||||
memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
|
||||
|
||||
/* attach to cfg80211 for primary interface */
|
||||
if (!ifp->idx) {
|
||||
drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr);
|
||||
if (drvr->config == NULL) {
|
||||
brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (register_netdev(ndev) != 0) {
|
||||
brcmf_dbg(ERROR, "couldn't register the net device\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ndev->netdev_ops = NULL;
|
||||
return -EBADE;
|
||||
}
|
||||
|
||||
int
|
||||
brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
|
||||
{
|
||||
@ -882,7 +944,7 @@ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
|
||||
if (mac_addr != NULL)
|
||||
memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
|
||||
|
||||
if (brcmf_net_attach(drvr, ifp->idx)) {
|
||||
if (brcmf_net_attach(ifp)) {
|
||||
brcmf_dbg(ERROR, "brcmf_net_attach failed");
|
||||
free_netdev(ifp->ndev);
|
||||
drvr->iflist[ifidx] = NULL;
|
||||
@ -1016,69 +1078,16 @@ int brcmf_bus_start(struct device *dev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* add primary networking interface */
|
||||
ret = brcmf_add_if(dev, 0, "wlan%d", drvr->mac);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* signal bus ready */
|
||||
bus_if->state = BRCMF_BUS_DATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
u8 temp_addr[ETH_ALEN] = {
|
||||
0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
|
||||
|
||||
brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
|
||||
|
||||
ndev = drvr->iflist[ifidx]->ndev;
|
||||
ndev->netdev_ops = &brcmf_netdev_ops_pri;
|
||||
|
||||
/*
|
||||
* We have to use the primary MAC for virtual interfaces
|
||||
*/
|
||||
if (ifidx != 0) {
|
||||
/* for virtual interfaces use the primary MAC */
|
||||
memcpy(temp_addr, drvr->mac, ETH_ALEN);
|
||||
|
||||
}
|
||||
|
||||
if (ifidx == 1) {
|
||||
brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
|
||||
/* ACCESSPOINT INTERFACE CASE */
|
||||
temp_addr[0] |= 0X02; /* set bit 2 ,
|
||||
- Locally Administered address */
|
||||
|
||||
}
|
||||
ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
|
||||
ndev->ethtool_ops = &brcmf_ethtool_ops;
|
||||
|
||||
drvr->rxsz = ndev->mtu + ndev->hard_header_len +
|
||||
drvr->hdrlen;
|
||||
|
||||
memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
|
||||
|
||||
/* attach to cfg80211 for primary interface */
|
||||
if (!ifidx) {
|
||||
drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr);
|
||||
if (drvr->config == NULL) {
|
||||
brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (register_netdev(ndev) != 0) {
|
||||
brcmf_dbg(ERROR, "couldn't register the net device\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ndev->netdev_ops = NULL;
|
||||
return -EBADE;
|
||||
}
|
||||
|
||||
static void brcmf_bus_detach(struct brcmf_pub *drvr)
|
||||
{
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
@ -3948,12 +3948,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
|
||||
}
|
||||
}
|
||||
|
||||
/* add interface and open for business */
|
||||
if (brcmf_add_if(bus->sdiodev->dev, 0, "wlan%d", NULL)) {
|
||||
brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return bus;
|
||||
|
||||
fail:
|
||||
|
@ -1383,14 +1383,6 @@ static int brcmf_usb_probe_cb(struct device *dev, const char *desc,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* add interface and open for business */
|
||||
ret = brcmf_add_if(dev, 0, "wlan%d", NULL);
|
||||
if (ret) {
|
||||
brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
|
||||
brcmf_detach(dev);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
/* Release resources in reverse order */
|
||||
|
@ -628,6 +628,40 @@ brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicates whether the country provided is valid to pass
|
||||
* to cfg80211 or not.
|
||||
*
|
||||
* returns true if valid; false if not.
|
||||
*/
|
||||
static bool brcms_c_country_valid(const char *ccode)
|
||||
{
|
||||
/*
|
||||
* only allow ascii alpha uppercase for the first 2
|
||||
* chars.
|
||||
*/
|
||||
if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
|
||||
(0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A &&
|
||||
ccode[2] == '\0'))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* do not match ISO 3166-1 user assigned country codes
|
||||
* that may be in the driver table
|
||||
*/
|
||||
if (!strcmp("AA", ccode) || /* AA */
|
||||
!strcmp("ZZ", ccode) || /* ZZ */
|
||||
ccode[0] == 'X' || /* XA - XZ */
|
||||
(ccode[0] == 'Q' && /* QM - QZ */
|
||||
(ccode[1] >= 'M' && ccode[1] <= 'Z')))
|
||||
return false;
|
||||
|
||||
if (!strcmp("NA", ccode))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Lookup a country info structure from a null terminated country
|
||||
* abbreviation and regrev directly with no translation.
|
||||
*/
|
||||
@ -1089,7 +1123,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
|
||||
|
||||
/* store the country code for passing up as a regulatory hint */
|
||||
ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
|
||||
if (ccode)
|
||||
if (ccode && brcms_c_country_valid(ccode))
|
||||
strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
|
||||
|
||||
/*
|
||||
|
@ -1069,11 +1069,7 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
|
||||
wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
|
||||
"%d\n", __func__, err);
|
||||
|
||||
if (wl->pub->srom_ccode[0])
|
||||
err = brcms_set_hint(wl, wl->pub->srom_ccode);
|
||||
else
|
||||
err = brcms_set_hint(wl, "US");
|
||||
if (err)
|
||||
if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode))
|
||||
wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
|
||||
__func__, err);
|
||||
|
||||
|
@ -207,8 +207,7 @@ static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
|
||||
};
|
||||
|
||||
static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
|
||||
sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
|
||||
sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
|
||||
ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
|
||||
};
|
||||
|
||||
static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
|
||||
|
@ -16353,11 +16353,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
|
||||
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
|
||||
rfseq_rx2tx_events_rev3_ipa,
|
||||
rfseq_rx2tx_dlys_rev3_ipa,
|
||||
sizeof
|
||||
(rfseq_rx2tx_events_rev3_ipa) /
|
||||
sizeof
|
||||
(rfseq_rx2tx_events_rev3_ipa
|
||||
[0]));
|
||||
ARRAY_SIZE(rfseq_rx2tx_events_rev3_ipa));
|
||||
|
||||
mod_phy_reg(pi, 0x299, (0x3 << 14), (0x1 << 14));
|
||||
mod_phy_reg(pi, 0x29d, (0x3 << 14), (0x1 << 14));
|
||||
@ -16858,18 +16854,13 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
|
||||
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX,
|
||||
rfseq_tx2rx_events_rev3,
|
||||
rfseq_tx2rx_dlys_rev3,
|
||||
sizeof(rfseq_tx2rx_events_rev3) /
|
||||
sizeof(rfseq_tx2rx_events_rev3[0]));
|
||||
ARRAY_SIZE(rfseq_tx2rx_events_rev3));
|
||||
|
||||
if (PHY_IPA(pi))
|
||||
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
|
||||
rfseq_rx2tx_events_rev3_ipa,
|
||||
rfseq_rx2tx_dlys_rev3_ipa,
|
||||
sizeof
|
||||
(rfseq_rx2tx_events_rev3_ipa) /
|
||||
sizeof
|
||||
(rfseq_rx2tx_events_rev3_ipa
|
||||
[0]));
|
||||
ARRAY_SIZE(rfseq_rx2tx_events_rev3_ipa));
|
||||
|
||||
if ((pi->sh->hw_phyrxchain != 0x3) &&
|
||||
(pi->sh->hw_phyrxchain != pi->sh->hw_phytxchain)) {
|
||||
@ -16885,8 +16876,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
|
||||
pi, NPHY_RFSEQ_RX2TX,
|
||||
rfseq_rx2tx_events_rev3,
|
||||
rfseq_rx2tx_dlys_rev3,
|
||||
sizeof(rfseq_rx2tx_events_rev3) /
|
||||
sizeof(rfseq_rx2tx_events_rev3[0]));
|
||||
ARRAY_SIZE(rfseq_rx2tx_events_rev3));
|
||||
}
|
||||
|
||||
if (CHSPEC_IS2G(pi->radio_chanspec))
|
||||
@ -17209,13 +17199,11 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
|
||||
|
||||
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events,
|
||||
rfseq_rx2tx_dlys,
|
||||
sizeof(rfseq_rx2tx_events) /
|
||||
sizeof(rfseq_rx2tx_events[0]));
|
||||
ARRAY_SIZE(rfseq_rx2tx_events));
|
||||
|
||||
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, rfseq_tx2rx_events,
|
||||
rfseq_tx2rx_dlys,
|
||||
sizeof(rfseq_tx2rx_events) /
|
||||
sizeof(rfseq_tx2rx_events[0]));
|
||||
ARRAY_SIZE(rfseq_tx2rx_events));
|
||||
|
||||
wlc_phy_workarounds_nphy_gainctrl(pi);
|
||||
|
||||
@ -19357,8 +19345,7 @@ static void wlc_phy_spurwar_nphy(struct brcms_phy *pi)
|
||||
}
|
||||
|
||||
if (isAdjustNoiseVar) {
|
||||
numTonesAdjust = sizeof(nphy_adj_tone_id_buf) /
|
||||
sizeof(nphy_adj_tone_id_buf[0]);
|
||||
numTonesAdjust = ARRAY_SIZE(nphy_adj_tone_id_buf);
|
||||
|
||||
wlc_phy_adjust_min_noisevar_nphy(
|
||||
pi,
|
||||
@ -25204,32 +25191,26 @@ static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core)
|
||||
|
||||
phy_a15 = pad_gain_codes_used_2057rev5;
|
||||
phy_a13 =
|
||||
sizeof(pad_gain_codes_used_2057rev5) /
|
||||
sizeof(pad_gain_codes_used_2057rev5
|
||||
[0]) - 1;
|
||||
ARRAY_SIZE(pad_gain_codes_used_2057rev5) - 1;
|
||||
|
||||
} else if ((pi->pubpi.radiorev == 7)
|
||||
|| (pi->pubpi.radiorev == 8)) {
|
||||
|
||||
phy_a15 = pad_gain_codes_used_2057rev7;
|
||||
phy_a13 =
|
||||
sizeof(pad_gain_codes_used_2057rev7) /
|
||||
sizeof(pad_gain_codes_used_2057rev7
|
||||
[0]) - 1;
|
||||
ARRAY_SIZE(pad_gain_codes_used_2057rev7) - 1;
|
||||
|
||||
} else {
|
||||
|
||||
phy_a15 = pad_all_gain_codes_2057;
|
||||
phy_a13 = sizeof(pad_all_gain_codes_2057) /
|
||||
sizeof(pad_all_gain_codes_2057[0]) -
|
||||
phy_a13 = ARRAY_SIZE(pad_all_gain_codes_2057) -
|
||||
1;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
phy_a15 = pga_all_gain_codes_2057;
|
||||
phy_a13 = sizeof(pga_all_gain_codes_2057) /
|
||||
sizeof(pga_all_gain_codes_2057[0]) - 1;
|
||||
phy_a13 = ARRAY_SIZE(pga_all_gain_codes_2057) - 1;
|
||||
}
|
||||
|
||||
phy_a14 = 0;
|
||||
|
@ -17,17 +17,7 @@
|
||||
#ifndef _BRCM_HW_IDS_H_
|
||||
#define _BRCM_HW_IDS_H_
|
||||
|
||||
#define BCM4325_D11DUAL_ID 0x431b
|
||||
#define BCM4325_D11G_ID 0x431c
|
||||
#define BCM4325_D11A_ID 0x431d
|
||||
|
||||
#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */
|
||||
#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */
|
||||
#define BCM4329_D11NDUAL_ID 0x432e
|
||||
|
||||
#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */
|
||||
#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */
|
||||
#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */
|
||||
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
|
||||
|
||||
#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
|
||||
#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */
|
||||
@ -37,23 +27,15 @@
|
||||
#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */
|
||||
#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */
|
||||
|
||||
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
|
||||
|
||||
/* Chip IDs */
|
||||
#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */
|
||||
#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */
|
||||
|
||||
#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */
|
||||
#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */
|
||||
#define BCM43421_CHIP_ID 43421 /* 43421 chipcommon chipid */
|
||||
#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */
|
||||
#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */
|
||||
#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */
|
||||
#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
|
||||
#define BCM4325_CHIP_ID 0x4325 /* 4325 chipcommon chipid */
|
||||
#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */
|
||||
#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */
|
||||
#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */
|
||||
#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */
|
||||
/* Chipcommon Core Chip IDs */
|
||||
#define BCM4313_CHIP_ID 0x4313
|
||||
#define BCM43224_CHIP_ID 43224
|
||||
#define BCM43225_CHIP_ID 43225
|
||||
#define BCM43235_CHIP_ID 43235
|
||||
#define BCM43236_CHIP_ID 43236
|
||||
#define BCM43238_CHIP_ID 43238
|
||||
#define BCM4329_CHIP_ID 0x4329
|
||||
#define BCM4330_CHIP_ID 0x4330
|
||||
#define BCM4331_CHIP_ID 0x4331
|
||||
|
||||
#endif /* _BRCM_HW_IDS_H_ */
|
||||
|
@ -244,8 +244,7 @@ u16 hostap_tx_callback_register(local_info_t *local,
|
||||
unsigned long flags;
|
||||
struct hostap_tx_callback_info *entry;
|
||||
|
||||
entry = kmalloc(sizeof(*entry),
|
||||
GFP_ATOMIC);
|
||||
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry == NULL)
|
||||
return 0;
|
||||
|
||||
|
@ -457,18 +457,4 @@ static struct pci_driver prism2_pci_driver = {
|
||||
#endif /* CONFIG_PM */
|
||||
};
|
||||
|
||||
|
||||
static int __init init_prism2_pci(void)
|
||||
{
|
||||
return pci_register_driver(&prism2_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit exit_prism2_pci(void)
|
||||
{
|
||||
pci_unregister_driver(&prism2_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(init_prism2_pci);
|
||||
module_exit(exit_prism2_pci);
|
||||
module_pci_driver(prism2_pci_driver);
|
||||
|
@ -616,18 +616,4 @@ static struct pci_driver prism2_plx_driver = {
|
||||
.remove = prism2_plx_remove,
|
||||
};
|
||||
|
||||
|
||||
static int __init init_prism2_plx(void)
|
||||
{
|
||||
return pci_register_driver(&prism2_plx_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit exit_prism2_plx(void)
|
||||
{
|
||||
pci_unregister_driver(&prism2_plx_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(init_prism2_plx);
|
||||
module_exit(exit_prism2_plx);
|
||||
module_pci_driver(prism2_plx_driver);
|
||||
|
23
drivers/net/wireless/ipw2x00/ipw.h
Normal file
23
drivers/net/wireless/ipw2x00/ipw.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver
|
||||
*
|
||||
* Copyright 2012 Stanislav Yakovlev <stas.yakovlev@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __IPW_H__
|
||||
#define __IPW_H__
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
static const u32 ipw_cipher_suites[] = {
|
||||
WLAN_CIPHER_SUITE_WEP40,
|
||||
WLAN_CIPHER_SUITE_WEP104,
|
||||
WLAN_CIPHER_SUITE_TKIP,
|
||||
WLAN_CIPHER_SUITE_CCMP,
|
||||
};
|
||||
|
||||
#endif
|
@ -166,6 +166,7 @@ that only one external action is invoked at a time.
|
||||
#include <net/lib80211.h>
|
||||
|
||||
#include "ipw2100.h"
|
||||
#include "ipw.h"
|
||||
|
||||
#define IPW2100_VERSION "git-1.2.2"
|
||||
|
||||
@ -1958,6 +1959,9 @@ static int ipw2100_wdev_init(struct net_device *dev)
|
||||
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
|
||||
}
|
||||
|
||||
wdev->wiphy->cipher_suites = ipw_cipher_suites;
|
||||
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
|
||||
|
||||
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
|
||||
if (wiphy_register(wdev->wiphy)) {
|
||||
ipw2100_down(priv);
|
||||
@ -8503,8 +8507,7 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv,
|
||||
struct ipw2100_fw *fw)
|
||||
{
|
||||
fw->version = 0;
|
||||
if (fw->fw_entry)
|
||||
release_firmware(fw->fw_entry);
|
||||
release_firmware(fw->fw_entry);
|
||||
fw->fw_entry = NULL;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <net/cfg80211-wext.h>
|
||||
#include "ipw2200.h"
|
||||
#include "ipw.h"
|
||||
|
||||
|
||||
#ifndef KBUILD_EXTMOD
|
||||
@ -3657,8 +3658,7 @@ static int ipw_load(struct ipw_priv *priv)
|
||||
priv->rxq = NULL;
|
||||
}
|
||||
ipw_tx_queue_free(priv);
|
||||
if (raw)
|
||||
release_firmware(raw);
|
||||
release_firmware(raw);
|
||||
#ifdef CONFIG_PM
|
||||
fw_loaded = 0;
|
||||
raw = NULL;
|
||||
@ -11533,6 +11533,9 @@ static int ipw_wdev_init(struct net_device *dev)
|
||||
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band;
|
||||
}
|
||||
|
||||
wdev->wiphy->cipher_suites = ipw_cipher_suites;
|
||||
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
|
||||
|
||||
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
|
||||
|
||||
/* With that information in place, we can now register the wiphy... */
|
||||
|
@ -113,20 +113,21 @@ config IWLWIFI_DEVICE_TESTMODE
|
||||
generic netlink message via NL80211_TESTMODE channel.
|
||||
|
||||
config IWLWIFI_P2P
|
||||
bool "iwlwifi experimental P2P support"
|
||||
depends on IWLWIFI
|
||||
help
|
||||
This option enables experimental P2P support for some devices
|
||||
based on microcode support. Since P2P support is still under
|
||||
development, this option may even enable it for some devices
|
||||
now that turn out to not support it in the future due to
|
||||
microcode restrictions.
|
||||
def_bool y
|
||||
bool "iwlwifi experimental P2P support"
|
||||
depends on IWLWIFI
|
||||
help
|
||||
This option enables experimental P2P support for some devices
|
||||
based on microcode support. Since P2P support is still under
|
||||
development, this option may even enable it for some devices
|
||||
now that turn out to not support it in the future due to
|
||||
microcode restrictions.
|
||||
|
||||
To determine if your microcode supports the experimental P2P
|
||||
offered by this option, check if the driver advertises AP
|
||||
support when it is loaded.
|
||||
To determine if your microcode supports the experimental P2P
|
||||
offered by this option, check if the driver advertises AP
|
||||
support when it is loaded.
|
||||
|
||||
Say Y only if you want to experiment with P2P.
|
||||
Say Y only if you want to experiment with P2P.
|
||||
|
||||
config IWLWIFI_EXPERIMENTAL_MFP
|
||||
bool "support MFP (802.11w) even if uCode doesn't advertise"
|
||||
|
@ -7,7 +7,7 @@ iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
|
||||
|
||||
iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o
|
||||
iwlwifi-objs += iwl-scan.o iwl-led.o
|
||||
iwlwifi-objs += iwl-agn-rxon.o
|
||||
iwlwifi-objs += iwl-agn-rxon.o iwl-agn-devices.o
|
||||
iwlwifi-objs += iwl-5000.o
|
||||
iwlwifi-objs += iwl-6000.o
|
||||
iwlwifi-objs += iwl-1000.o
|
||||
|
@ -24,26 +24,11 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-shared.h"
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-dev.h" /* still needed */
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL1000_UCODE_API_MAX 6
|
||||
@ -64,97 +49,6 @@
|
||||
#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
|
||||
/*
|
||||
* For 1000, use advance thermal throttling critical temperature threshold,
|
||||
* but legacy thermal management implementation for now.
|
||||
* This is for the reason of 1000 uCode using advance thermal throttling API
|
||||
* but not implement ct_kill_exit based on ct_kill exit temperature
|
||||
* so the thermal throttling will still based on legacy thermal throttling
|
||||
* management.
|
||||
* The code here need to be modified once 1000 uCode has the advanced thermal
|
||||
* throttling algorithm in place
|
||||
*/
|
||||
static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
|
||||
hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/* NIC configuration for 1000 series */
|
||||
static void iwl1000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* set CSR_HW_CONFIG_REG for uCode use */
|
||||
iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
|
||||
|
||||
/* Setting digital SVR for 1000 card to 1.32V */
|
||||
/* locking is acquired in iwl_set_bits_mask_prph() function */
|
||||
iwl_set_bits_mask_prph(trans(priv), APMG_DIGITAL_SVR_REG,
|
||||
APMG_SVR_DIGITAL_VOLTAGE_1_32,
|
||||
~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 120,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 240,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
.auto_corr_max_ofdm_x1 = 155,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 290,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 170,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 95,
|
||||
.nrg_th_ofdm = 95,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ);
|
||||
|
||||
hw_params(priv).tx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_tx_ant);
|
||||
if (cfg(priv)->rx_with_siso_diversity)
|
||||
hw_params(priv).rx_chains_num = 1;
|
||||
else
|
||||
hw_params(priv).rx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_rx_ant);
|
||||
|
||||
iwl1000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
hw_params(priv).sens = &iwl1000_sensitivity;
|
||||
}
|
||||
|
||||
static struct iwl_lib_ops iwl1000_lib = {
|
||||
.set_hw_params = iwl1000_hw_set_hw_params,
|
||||
.nic_config = iwl1000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
static const struct iwl_base_params iwl1000_base_params = {
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
@ -165,9 +59,8 @@ static const struct iwl_base_params iwl1000_base_params = {
|
||||
.support_ct_kill_exit = true,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
.wd_timeout = IWL_DEF_WD_TIMEOUT,
|
||||
.wd_timeout = IWL_WATCHHDOG_DISABLED,
|
||||
.max_event_log_size = 128,
|
||||
.wd_disable = true,
|
||||
};
|
||||
|
||||
static const struct iwl_ht_params iwl1000_ht_params = {
|
||||
@ -181,11 +74,11 @@ static const struct iwl_ht_params iwl1000_ht_params = {
|
||||
.ucode_api_max = IWL1000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL1000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL1000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_1000, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
.max_data_size = IWLAGN_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
|
||||
.lib = &iwl1000_lib, \
|
||||
.base_params = &iwl1000_base_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
|
||||
@ -205,11 +98,11 @@ const struct iwl_cfg iwl1000_bg_cfg = {
|
||||
.ucode_api_max = IWL100_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL100_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL100_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_100, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
.max_data_size = IWLAGN_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
|
||||
.lib = &iwl1000_lib, \
|
||||
.base_params = &iwl1000_base_params, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.rx_with_siso_diversity = true
|
||||
|
@ -24,25 +24,11 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-shared.h"
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-dev.h" /* still needed */
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL2030_UCODE_API_MAX 6
|
||||
@ -74,100 +60,6 @@
|
||||
#define IWL135_FW_PRE "iwlwifi-135-"
|
||||
#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD;
|
||||
hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/* NIC configuration for 2000 series */
|
||||
static void iwl2000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
|
||||
.min_nrg_cck = 97,
|
||||
.auto_corr_min_ofdm = 80,
|
||||
.auto_corr_min_ofdm_mrc = 128,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 192,
|
||||
|
||||
.auto_corr_max_ofdm = 145,
|
||||
.auto_corr_max_ofdm_mrc = 232,
|
||||
.auto_corr_max_ofdm_x1 = 110,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 232,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 175,
|
||||
.auto_corr_min_cck_mrc = 160,
|
||||
.auto_corr_max_cck_mrc = 310,
|
||||
.nrg_th_cck = 97,
|
||||
.nrg_th_ofdm = 100,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ);
|
||||
|
||||
hw_params(priv).tx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_tx_ant);
|
||||
if (cfg(priv)->rx_with_siso_diversity)
|
||||
hw_params(priv).rx_chains_num = 1;
|
||||
else
|
||||
hw_params(priv).rx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_rx_ant);
|
||||
|
||||
iwl2000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
hw_params(priv).sens = &iwl2000_sensitivity;
|
||||
}
|
||||
|
||||
static struct iwl_lib_ops iwl2000_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.nic_config = iwl2000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl2030_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.nic_config = iwl2000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
static const struct iwl_base_params iwl2000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
@ -223,11 +115,11 @@ static const struct iwl_bt_params iwl2030_bt_params = {
|
||||
.ucode_api_max = IWL2000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL2000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL2000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_2000, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.lib = &iwl2000_lib, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.temp_offset_v2 = true, \
|
||||
@ -250,11 +142,11 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
|
||||
.ucode_api_max = IWL2030_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL2030_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL2030_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_2030, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.lib = &iwl2030_lib, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
@ -273,11 +165,11 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
|
||||
.ucode_api_max = IWL105_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL105_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL105_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_105, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.lib = &iwl2000_lib, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.temp_offset_v2 = true, \
|
||||
@ -302,11 +194,11 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
|
||||
.ucode_api_max = IWL135_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL135_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL135_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_135, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.lib = &iwl2030_lib, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
|
@ -24,28 +24,11 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-shared.h"
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-dev.h" /* still needed */
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL5000_UCODE_API_MAX 5
|
||||
@ -61,250 +44,6 @@
|
||||
#define IWL5150_FW_PRE "iwlwifi-5150-"
|
||||
#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
/* NIC configuration for 5000 series */
|
||||
static void iwl5000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
/* W/A : NIC is stuck in a reset state after Early PCIe power off
|
||||
* (PCIe power is lost before PERST# is asserted),
|
||||
* causing ME FW to lose ownership and not being able to obtain it back.
|
||||
*/
|
||||
iwl_set_bits_mask_prph(trans(priv), APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
|
||||
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
|
||||
.min_nrg_cck = 100,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 220,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
.auto_corr_max_ofdm_x1 = 120,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 240,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 200,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 100,
|
||||
.nrg_th_ofdm = 100,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 220,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
/* max = min for performance bug in 5150 DSP */
|
||||
.auto_corr_max_ofdm_x1 = 105,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 220,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 170,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 95,
|
||||
.nrg_th_ofdm = 95,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5)
|
||||
|
||||
static s32 iwl_temp_calib_to_offset(struct iwl_shared *shrd)
|
||||
{
|
||||
u16 temperature, voltage;
|
||||
__le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(shrd,
|
||||
EEPROM_KELVIN_TEMPERATURE);
|
||||
|
||||
temperature = le16_to_cpu(temp_calib[0]);
|
||||
voltage = le16_to_cpu(temp_calib[1]);
|
||||
|
||||
/* offset = temp - volt / coeff */
|
||||
return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
|
||||
}
|
||||
|
||||
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
|
||||
s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
|
||||
iwl_temp_calib_to_offset(priv->shrd);
|
||||
|
||||
hw_params(priv).ct_kill_threshold = threshold * volt2temp_coef;
|
||||
}
|
||||
|
||||
static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
|
||||
}
|
||||
|
||||
static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
hw_params(priv).tx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_tx_ant);
|
||||
hw_params(priv).rx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_rx_ant);
|
||||
|
||||
iwl5000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
hw_params(priv).sens = &iwl5000_sensitivity;
|
||||
}
|
||||
|
||||
static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
hw_params(priv).tx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_tx_ant);
|
||||
hw_params(priv).rx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_rx_ant);
|
||||
|
||||
iwl5150_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
hw_params(priv).sens = &iwl5150_sensitivity;
|
||||
}
|
||||
|
||||
static void iwl5150_temperature(struct iwl_priv *priv)
|
||||
{
|
||||
u32 vt = 0;
|
||||
s32 offset = iwl_temp_calib_to_offset(priv->shrd);
|
||||
|
||||
vt = le32_to_cpu(priv->statistics.common.temperature);
|
||||
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
|
||||
/* now vt hold the temperature in Kelvin */
|
||||
priv->temperature = KELVIN_TO_CELSIUS(vt);
|
||||
iwl_tt_handler(priv);
|
||||
}
|
||||
|
||||
static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
/*
|
||||
* MULTI-FIXME
|
||||
* See iwlagn_mac_channel_switch.
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl5000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
u8 switch_count;
|
||||
u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_CHANNEL_SWITCH,
|
||||
.len = { sizeof(cmd), },
|
||||
.flags = CMD_SYNC,
|
||||
.data = { &cmd, },
|
||||
};
|
||||
|
||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||
ch = ch_switch->channel->hw_value;
|
||||
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
|
||||
ctx->active.channel, ch);
|
||||
cmd.channel = cpu_to_le16(ch);
|
||||
cmd.rxon_flags = ctx->staging.flags;
|
||||
cmd.rxon_filter_flags = ctx->staging.filter_flags;
|
||||
switch_count = ch_switch->count;
|
||||
tsf_low = ch_switch->timestamp & 0x0ffffffff;
|
||||
/*
|
||||
* calculate the ucode channel switch time
|
||||
* adding TSF as one of the factor for when to switch
|
||||
*/
|
||||
if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
|
||||
if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
|
||||
beacon_interval)) {
|
||||
switch_count -= (priv->ucode_beacon_time -
|
||||
tsf_low) / beacon_interval;
|
||||
} else
|
||||
switch_count = 0;
|
||||
}
|
||||
if (switch_count <= 1)
|
||||
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
|
||||
else {
|
||||
switch_time_in_usec =
|
||||
vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
|
||||
ucode_switch_time = iwl_usecs_to_beacons(priv,
|
||||
switch_time_in_usec,
|
||||
beacon_interval);
|
||||
cmd.switch_time = iwl_add_beacon_time(priv,
|
||||
priv->ucode_beacon_time,
|
||||
ucode_switch_time,
|
||||
beacon_interval);
|
||||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return iwl_dvm_send_cmd(priv, &hcmd);
|
||||
}
|
||||
|
||||
static struct iwl_lib_ops iwl5000_lib = {
|
||||
.set_hw_params = iwl5000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl5000_hw_channel_switch,
|
||||
.nic_config = iwl5000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl5150_lib = {
|
||||
.set_hw_params = iwl5150_hw_set_hw_params,
|
||||
.set_channel_switch = iwl5000_hw_channel_switch,
|
||||
.nic_config = iwl5000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
},
|
||||
.temperature = iwl5150_temperature,
|
||||
};
|
||||
|
||||
static const struct iwl_base_params iwl5000_base_params = {
|
||||
.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
@ -312,10 +51,9 @@ static const struct iwl_base_params iwl5000_base_params = {
|
||||
.led_compensation = 51,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
.wd_timeout = IWL_LONG_WD_TIMEOUT,
|
||||
.wd_timeout = IWL_WATCHHDOG_DISABLED,
|
||||
.max_event_log_size = 512,
|
||||
.no_idle_support = true,
|
||||
.wd_disable = true,
|
||||
};
|
||||
|
||||
static const struct iwl_ht_params iwl5000_ht_params = {
|
||||
@ -326,11 +64,11 @@ static const struct iwl_ht_params iwl5000_ht_params = {
|
||||
.fw_name_pre = IWL5000_FW_PRE, \
|
||||
.ucode_api_max = IWL5000_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL5000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_5000, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
.max_data_size = IWLAGN_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \
|
||||
.lib = &iwl5000_lib, \
|
||||
.base_params = &iwl5000_base_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
|
||||
@ -371,11 +109,11 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
||||
.fw_name_pre = IWL5000_FW_PRE,
|
||||
.ucode_api_max = IWL5000_UCODE_API_MAX,
|
||||
.ucode_api_min = IWL5000_UCODE_API_MIN,
|
||||
.device_family = IWL_DEVICE_FAMILY_5000,
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE,
|
||||
.max_data_size = IWLAGN_RTC_DATA_SIZE,
|
||||
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
|
||||
.lib = &iwl5000_lib,
|
||||
.base_params = &iwl5000_base_params,
|
||||
.ht_params = &iwl5000_ht_params,
|
||||
.led_mode = IWL_LED_BLINK,
|
||||
@ -386,11 +124,11 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
||||
.fw_name_pre = IWL5150_FW_PRE, \
|
||||
.ucode_api_max = IWL5150_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL5150_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_5150, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
.max_data_size = IWLAGN_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_5050_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \
|
||||
.lib = &iwl5150_lib, \
|
||||
.base_params = &iwl5000_base_params, \
|
||||
.no_xtal_calib = true, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
|
@ -24,26 +24,11 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-shared.h"
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-dev.h" /* still needed */
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL6000_UCODE_API_MAX 6
|
||||
@ -71,201 +56,6 @@
|
||||
#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
|
||||
#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD;
|
||||
hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
static void iwl6050_additional_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (iwl_eeprom_calib_version(priv->shrd) >= 6)
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
}
|
||||
|
||||
static void iwl6150_additional_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (iwl_eeprom_calib_version(priv->shrd) >= 6)
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_6050_1x2);
|
||||
}
|
||||
|
||||
static void iwl6000i_additional_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* 2x2 IPA phy type */
|
||||
iwl_write32(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
|
||||
}
|
||||
|
||||
/* NIC configuration for 6000 series */
|
||||
static void iwl6000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
/* do additional nic configuration if needed */
|
||||
if (cfg(priv)->additional_nic_config)
|
||||
cfg(priv)->additional_nic_config(priv);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
|
||||
.min_nrg_cck = 110,
|
||||
.auto_corr_min_ofdm = 80,
|
||||
.auto_corr_min_ofdm_mrc = 128,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 192,
|
||||
|
||||
.auto_corr_max_ofdm = 145,
|
||||
.auto_corr_max_ofdm_mrc = 232,
|
||||
.auto_corr_max_ofdm_x1 = 110,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 232,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 175,
|
||||
.auto_corr_min_cck_mrc = 160,
|
||||
.auto_corr_max_cck_mrc = 310,
|
||||
.nrg_th_cck = 110,
|
||||
.nrg_th_ofdm = 110,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 336,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
hw_params(priv).tx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_tx_ant);
|
||||
if (cfg(priv)->rx_with_siso_diversity)
|
||||
hw_params(priv).rx_chains_num = 1;
|
||||
else
|
||||
hw_params(priv).rx_chains_num =
|
||||
num_of_ant(hw_params(priv).valid_rx_ant);
|
||||
|
||||
iwl6000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
hw_params(priv).sens = &iwl6000_sensitivity;
|
||||
|
||||
}
|
||||
|
||||
static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
/*
|
||||
* MULTI-FIXME
|
||||
* See iwlagn_mac_channel_switch.
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl6000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
u8 switch_count;
|
||||
u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_CHANNEL_SWITCH,
|
||||
.len = { sizeof(cmd), },
|
||||
.flags = CMD_SYNC,
|
||||
.data = { &cmd, },
|
||||
};
|
||||
|
||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||
ch = ch_switch->channel->hw_value;
|
||||
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
cmd.channel = cpu_to_le16(ch);
|
||||
cmd.rxon_flags = ctx->staging.flags;
|
||||
cmd.rxon_filter_flags = ctx->staging.filter_flags;
|
||||
switch_count = ch_switch->count;
|
||||
tsf_low = ch_switch->timestamp & 0x0ffffffff;
|
||||
/*
|
||||
* calculate the ucode channel switch time
|
||||
* adding TSF as one of the factor for when to switch
|
||||
*/
|
||||
if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
|
||||
if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
|
||||
beacon_interval)) {
|
||||
switch_count -= (priv->ucode_beacon_time -
|
||||
tsf_low) / beacon_interval;
|
||||
} else
|
||||
switch_count = 0;
|
||||
}
|
||||
if (switch_count <= 1)
|
||||
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
|
||||
else {
|
||||
switch_time_in_usec =
|
||||
vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
|
||||
ucode_switch_time = iwl_usecs_to_beacons(priv,
|
||||
switch_time_in_usec,
|
||||
beacon_interval);
|
||||
cmd.switch_time = iwl_add_beacon_time(priv,
|
||||
priv->ucode_beacon_time,
|
||||
ucode_switch_time,
|
||||
beacon_interval);
|
||||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return iwl_dvm_send_cmd(priv, &hcmd);
|
||||
}
|
||||
|
||||
static struct iwl_lib_ops iwl6000_lib = {
|
||||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl6000_hw_channel_switch,
|
||||
.nic_config = iwl6000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl6030_lib = {
|
||||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl6000_hw_channel_switch,
|
||||
.nic_config = iwl6000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
static const struct iwl_base_params iwl6000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
@ -333,11 +123,11 @@ static const struct iwl_bt_params iwl6000_bt_params = {
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6000G2_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6005, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_6005_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
|
||||
.lib = &iwl6000_lib, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
@ -387,11 +177,11 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6000G2_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6030, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_6030_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
|
||||
.lib = &iwl6030_lib, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.bt_params = &iwl6000_bt_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
@ -458,14 +248,13 @@ const struct iwl_cfg iwl130_bg_cfg = {
|
||||
.ucode_api_max = IWL6000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6000i, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.valid_tx_ant = ANT_BC, /* .cfg overwrite */ \
|
||||
.valid_rx_ant = ANT_BC, /* .cfg overwrite */ \
|
||||
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \
|
||||
.lib = &iwl6000_lib, \
|
||||
.additional_nic_config = iwl6000i_additional_nic_config,\
|
||||
.base_params = &iwl6000_base_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
|
||||
@ -489,12 +278,11 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
|
||||
.fw_name_pre = IWL6050_FW_PRE, \
|
||||
.ucode_api_max = IWL6050_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL6050_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6050, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.valid_tx_ant = ANT_AB, /* .cfg overwrite */ \
|
||||
.valid_rx_ant = ANT_AB, /* .cfg overwrite */ \
|
||||
.lib = &iwl6000_lib, \
|
||||
.additional_nic_config = iwl6050_additional_nic_config, \
|
||||
.eeprom_ver = EEPROM_6050_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6050_base_params, \
|
||||
@ -516,10 +304,9 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
|
||||
.fw_name_pre = IWL6050_FW_PRE, \
|
||||
.ucode_api_max = IWL6050_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL6050_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6150, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.lib = &iwl6000_lib, \
|
||||
.additional_nic_config = iwl6150_additional_nic_config, \
|
||||
.eeprom_ver = EEPROM_6150_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6050_base_params, \
|
||||
@ -543,11 +330,11 @@ const struct iwl_cfg iwl6000_3agn_cfg = {
|
||||
.ucode_api_max = IWL6000_UCODE_API_MAX,
|
||||
.ucode_api_ok = IWL6000_UCODE_API_OK,
|
||||
.ucode_api_min = IWL6000_UCODE_API_MIN,
|
||||
.device_family = IWL_DEVICE_FAMILY_6000,
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE,
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE,
|
||||
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
|
||||
.lib = &iwl6000_lib,
|
||||
.base_params = &iwl6000_base_params,
|
||||
.ht_params = &iwl6000_ht_params,
|
||||
.led_mode = IWL_LED_BLINK,
|
||||
|
@ -190,7 +190,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
|
||||
u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
|
||||
u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens;
|
||||
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
@ -373,7 +373,7 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
|
||||
u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
|
||||
u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens;
|
||||
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
@ -597,9 +597,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
|
||||
int ret = 0;
|
||||
int i;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens;
|
||||
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
|
||||
|
||||
if (priv->disable_sens_cal)
|
||||
if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "Start iwl_init_sensitivity\n");
|
||||
@ -663,7 +663,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv)
|
||||
struct statistics_rx_phy *ofdm, *cck;
|
||||
struct statistics_general_data statis;
|
||||
|
||||
if (priv->disable_sens_cal)
|
||||
if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
|
||||
return;
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
@ -833,28 +833,28 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
|
||||
* To be safe, simply mask out any chains that we know
|
||||
* are not on the device.
|
||||
*/
|
||||
active_chains &= hw_params(priv).valid_rx_ant;
|
||||
active_chains &= priv->hw_params.valid_rx_ant;
|
||||
|
||||
num_tx_chains = 0;
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++) {
|
||||
/* loops on all the bits of
|
||||
* priv->hw_setting.valid_tx_ant */
|
||||
u8 ant_msk = (1 << i);
|
||||
if (!(hw_params(priv).valid_tx_ant & ant_msk))
|
||||
if (!(priv->hw_params.valid_tx_ant & ant_msk))
|
||||
continue;
|
||||
|
||||
num_tx_chains++;
|
||||
if (data->disconn_array[i] == 0)
|
||||
/* there is a Tx antenna connected */
|
||||
break;
|
||||
if (num_tx_chains == hw_params(priv).tx_chains_num &&
|
||||
if (num_tx_chains == priv->hw_params.tx_chains_num &&
|
||||
data->disconn_array[i]) {
|
||||
/*
|
||||
* If all chains are disconnected
|
||||
* connect the first valid tx chain
|
||||
*/
|
||||
first_chain =
|
||||
find_first_chain(hw_params(priv).valid_tx_ant);
|
||||
find_first_chain(priv->hw_params.valid_tx_ant);
|
||||
data->disconn_array[first_chain] = 0;
|
||||
active_chains |= BIT(first_chain);
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
@ -864,13 +864,13 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
|
||||
}
|
||||
}
|
||||
|
||||
if (active_chains != hw_params(priv).valid_rx_ant &&
|
||||
if (active_chains != priv->hw_params.valid_rx_ant &&
|
||||
active_chains != priv->chain_noise_data.active_chains)
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
"Detected that not all antennas are connected! "
|
||||
"Connected: %#x, valid: %#x.\n",
|
||||
active_chains,
|
||||
hw_params(priv).valid_rx_ant);
|
||||
priv->hw_params.valid_rx_ant);
|
||||
|
||||
/* Save for use within RXON, TX, SCAN commands, etc. */
|
||||
data->active_chains = active_chains;
|
||||
@ -970,7 +970,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
||||
if (priv->disable_chain_noise_cal)
|
||||
if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)
|
||||
return;
|
||||
|
||||
data = &(priv->chain_noise_data);
|
||||
@ -1055,7 +1055,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
|
||||
cfg(priv)->bt_params->advanced_bt_coexist) {
|
||||
/* Disable disconnected antenna algorithm for advanced
|
||||
bt coex, assuming valid antennas are connected */
|
||||
data->active_chains = hw_params(priv).valid_rx_ant;
|
||||
data->active_chains = priv->hw_params.valid_rx_ant;
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++)
|
||||
if (!(data->active_chains & (1<<i)))
|
||||
data->disconn_array[i] = 1;
|
||||
@ -1085,7 +1085,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
|
||||
min_average_noise, min_average_noise_antenna_i);
|
||||
|
||||
iwlagn_gain_computation(priv, average_noise,
|
||||
find_first_chain(hw_params(priv).valid_rx_ant));
|
||||
find_first_chain(priv->hw_params.valid_rx_ant));
|
||||
|
||||
/* Some power changes may have been made during the calibration.
|
||||
* Update and commit the RXON
|
||||
|
756
drivers/net/wireless/iwlwifi/iwl-agn-devices.c
Normal file
756
drivers/net/wireless/iwlwifi/iwl-agn-devices.c
Normal file
@ -0,0 +1,756 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called LICENSE.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* DVM device-specific data & functions
|
||||
*/
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-prph.h"
|
||||
|
||||
/*
|
||||
* 1000 series
|
||||
* ===========
|
||||
*/
|
||||
|
||||
/*
|
||||
* For 1000, use advance thermal throttling critical temperature threshold,
|
||||
* but legacy thermal management implementation for now.
|
||||
* This is for the reason of 1000 uCode using advance thermal throttling API
|
||||
* but not implement ct_kill_exit based on ct_kill exit temperature
|
||||
* so the thermal throttling will still based on legacy thermal throttling
|
||||
* management.
|
||||
* The code here need to be modified once 1000 uCode has the advanced thermal
|
||||
* throttling algorithm in place
|
||||
*/
|
||||
static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
|
||||
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/* NIC configuration for 1000 series */
|
||||
static void iwl1000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* set CSR_HW_CONFIG_REG for uCode use */
|
||||
iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
|
||||
|
||||
/* Setting digital SVR for 1000 card to 1.32V */
|
||||
/* locking is acquired in iwl_set_bits_mask_prph() function */
|
||||
iwl_set_bits_mask_prph(trans(priv), APMG_DIGITAL_SVR_REG,
|
||||
APMG_SVR_DIGITAL_VOLTAGE_1_32,
|
||||
~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
|
||||
* @priv -- pointer to iwl_priv data structure
|
||||
* @tsf_bits -- number of bits need to shift for masking)
|
||||
*/
|
||||
static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
{
|
||||
return (1 << tsf_bits) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
|
||||
* @priv -- pointer to iwl_priv data structure
|
||||
* @tsf_bits -- number of bits need to shift for masking)
|
||||
*/
|
||||
static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
{
|
||||
return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* extended beacon time format
|
||||
* time in usec will be changed into a 32-bit value in extended:internal format
|
||||
* the extended part is the beacon counts
|
||||
* the internal part is the time in usec within one beacon interval
|
||||
*/
|
||||
static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec,
|
||||
u32 beacon_interval)
|
||||
{
|
||||
u32 quot;
|
||||
u32 rem;
|
||||
u32 interval = beacon_interval * TIME_UNIT;
|
||||
|
||||
if (!interval || !usec)
|
||||
return 0;
|
||||
|
||||
quot = (usec / interval) &
|
||||
(iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
|
||||
return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
|
||||
}
|
||||
|
||||
/* base is usually what we get from ucode with each received frame,
|
||||
* the same as HW timer counter counting down
|
||||
*/
|
||||
static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
|
||||
u32 addon, u32 beacon_interval)
|
||||
{
|
||||
u32 base_low = base & iwl_beacon_time_mask_low(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
u32 interval = beacon_interval * TIME_UNIT;
|
||||
u32 res = (base & iwl_beacon_time_mask_high(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS)) +
|
||||
(addon & iwl_beacon_time_mask_high(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS));
|
||||
|
||||
if (base_low > addon_low)
|
||||
res += base_low - addon_low;
|
||||
else if (base_low < addon_low) {
|
||||
res += interval + base_low - addon_low;
|
||||
res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
|
||||
} else
|
||||
res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
|
||||
|
||||
return cpu_to_le32(res);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 120,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 240,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
.auto_corr_max_ofdm_x1 = 155,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 290,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 170,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 95,
|
||||
.nrg_th_ofdm = 95,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
if (cfg(priv)->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl1000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
priv->hw_params.sens = &iwl1000_sensitivity;
|
||||
}
|
||||
|
||||
struct iwl_lib_ops iwl1000_lib = {
|
||||
.set_hw_params = iwl1000_hw_set_hw_params,
|
||||
.nic_config = iwl1000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 2000 series
|
||||
* ===========
|
||||
*/
|
||||
|
||||
static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
|
||||
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/* NIC configuration for 2000 series */
|
||||
static void iwl2000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
|
||||
.min_nrg_cck = 97,
|
||||
.auto_corr_min_ofdm = 80,
|
||||
.auto_corr_min_ofdm_mrc = 128,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 192,
|
||||
|
||||
.auto_corr_max_ofdm = 145,
|
||||
.auto_corr_max_ofdm_mrc = 232,
|
||||
.auto_corr_max_ofdm_x1 = 110,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 232,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 175,
|
||||
.auto_corr_min_cck_mrc = 160,
|
||||
.auto_corr_max_cck_mrc = 310,
|
||||
.nrg_th_cck = 97,
|
||||
.nrg_th_ofdm = 100,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
if (cfg(priv)->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl2000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
priv->hw_params.sens = &iwl2000_sensitivity;
|
||||
}
|
||||
|
||||
struct iwl_lib_ops iwl2000_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.nic_config = iwl2000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
struct iwl_lib_ops iwl2030_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.nic_config = iwl2000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
/*
|
||||
* 5000 series
|
||||
* ===========
|
||||
*/
|
||||
|
||||
/* NIC configuration for 5000 series */
|
||||
static void iwl5000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
/* W/A : NIC is stuck in a reset state after Early PCIe power off
|
||||
* (PCIe power is lost before PERST# is asserted),
|
||||
* causing ME FW to lose ownership and not being able to obtain it back.
|
||||
*/
|
||||
iwl_set_bits_mask_prph(trans(priv), APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
|
||||
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
|
||||
.min_nrg_cck = 100,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 220,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
.auto_corr_max_ofdm_x1 = 120,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 240,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 200,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 100,
|
||||
.nrg_th_ofdm = 100,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 220,
|
||||
|
||||
.auto_corr_max_ofdm = 120,
|
||||
.auto_corr_max_ofdm_mrc = 210,
|
||||
/* max = min for performance bug in 5150 DSP */
|
||||
.auto_corr_max_ofdm_x1 = 105,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 220,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 200,
|
||||
.auto_corr_min_cck_mrc = 170,
|
||||
.auto_corr_max_cck_mrc = 400,
|
||||
.nrg_th_cck = 95,
|
||||
.nrg_th_ofdm = 95,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5)
|
||||
|
||||
static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
|
||||
{
|
||||
u16 temperature, voltage;
|
||||
__le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
|
||||
EEPROM_KELVIN_TEMPERATURE);
|
||||
|
||||
temperature = le16_to_cpu(temp_calib[0]);
|
||||
voltage = le16_to_cpu(temp_calib[1]);
|
||||
|
||||
/* offset = temp - volt / coeff */
|
||||
return (s32)(temperature -
|
||||
voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
|
||||
}
|
||||
|
||||
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
|
||||
s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
|
||||
iwl_temp_calib_to_offset(priv);
|
||||
|
||||
priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
|
||||
}
|
||||
|
||||
static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
|
||||
}
|
||||
|
||||
static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl5000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
priv->hw_params.sens = &iwl5000_sensitivity;
|
||||
}
|
||||
|
||||
static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl5150_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
priv->hw_params.sens = &iwl5150_sensitivity;
|
||||
}
|
||||
|
||||
static void iwl5150_temperature(struct iwl_priv *priv)
|
||||
{
|
||||
u32 vt = 0;
|
||||
s32 offset = iwl_temp_calib_to_offset(priv);
|
||||
|
||||
vt = le32_to_cpu(priv->statistics.common.temperature);
|
||||
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
|
||||
/* now vt hold the temperature in Kelvin */
|
||||
priv->temperature = KELVIN_TO_CELSIUS(vt);
|
||||
iwl_tt_handler(priv);
|
||||
}
|
||||
|
||||
static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
/*
|
||||
* MULTI-FIXME
|
||||
* See iwlagn_mac_channel_switch.
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl5000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
u8 switch_count;
|
||||
u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_CHANNEL_SWITCH,
|
||||
.len = { sizeof(cmd), },
|
||||
.flags = CMD_SYNC,
|
||||
.data = { &cmd, },
|
||||
};
|
||||
|
||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||
ch = ch_switch->channel->hw_value;
|
||||
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
|
||||
ctx->active.channel, ch);
|
||||
cmd.channel = cpu_to_le16(ch);
|
||||
cmd.rxon_flags = ctx->staging.flags;
|
||||
cmd.rxon_filter_flags = ctx->staging.filter_flags;
|
||||
switch_count = ch_switch->count;
|
||||
tsf_low = ch_switch->timestamp & 0x0ffffffff;
|
||||
/*
|
||||
* calculate the ucode channel switch time
|
||||
* adding TSF as one of the factor for when to switch
|
||||
*/
|
||||
if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
|
||||
if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
|
||||
beacon_interval)) {
|
||||
switch_count -= (priv->ucode_beacon_time -
|
||||
tsf_low) / beacon_interval;
|
||||
} else
|
||||
switch_count = 0;
|
||||
}
|
||||
if (switch_count <= 1)
|
||||
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
|
||||
else {
|
||||
switch_time_in_usec =
|
||||
vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
|
||||
ucode_switch_time = iwl_usecs_to_beacons(priv,
|
||||
switch_time_in_usec,
|
||||
beacon_interval);
|
||||
cmd.switch_time = iwl_add_beacon_time(priv,
|
||||
priv->ucode_beacon_time,
|
||||
ucode_switch_time,
|
||||
beacon_interval);
|
||||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return iwl_dvm_send_cmd(priv, &hcmd);
|
||||
}
|
||||
|
||||
struct iwl_lib_ops iwl5000_lib = {
|
||||
.set_hw_params = iwl5000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl5000_hw_channel_switch,
|
||||
.nic_config = iwl5000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
struct iwl_lib_ops iwl5150_lib = {
|
||||
.set_hw_params = iwl5150_hw_set_hw_params,
|
||||
.set_channel_switch = iwl5000_hw_channel_switch,
|
||||
.nic_config = iwl5000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
},
|
||||
.temperature = iwl5150_temperature,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 6000 series
|
||||
* ===========
|
||||
*/
|
||||
|
||||
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
|
||||
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/* NIC configuration for 6000 series */
|
||||
static void iwl6000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
switch (cfg(priv)->device_family) {
|
||||
case IWL_DEVICE_FAMILY_6005:
|
||||
case IWL_DEVICE_FAMILY_6030:
|
||||
case IWL_DEVICE_FAMILY_6000:
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_6000i:
|
||||
/* 2x2 IPA phy type */
|
||||
iwl_write32(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_6050:
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (iwl_eeprom_calib_version(priv) >= 6)
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_6150:
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (iwl_eeprom_calib_version(priv) >= 6)
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_6050_1x2);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
|
||||
.min_nrg_cck = 110,
|
||||
.auto_corr_min_ofdm = 80,
|
||||
.auto_corr_min_ofdm_mrc = 128,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 192,
|
||||
|
||||
.auto_corr_max_ofdm = 145,
|
||||
.auto_corr_max_ofdm_mrc = 232,
|
||||
.auto_corr_max_ofdm_x1 = 110,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 232,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 175,
|
||||
.auto_corr_min_cck_mrc = 160,
|
||||
.auto_corr_max_cck_mrc = 310,
|
||||
.nrg_th_cck = 110,
|
||||
.nrg_th_ofdm = 110,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 336,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
if (cfg(priv)->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl6000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
priv->hw_params.sens = &iwl6000_sensitivity;
|
||||
|
||||
}
|
||||
|
||||
static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
/*
|
||||
* MULTI-FIXME
|
||||
* See iwlagn_mac_channel_switch.
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl6000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
u8 switch_count;
|
||||
u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_CHANNEL_SWITCH,
|
||||
.len = { sizeof(cmd), },
|
||||
.flags = CMD_SYNC,
|
||||
.data = { &cmd, },
|
||||
};
|
||||
|
||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||
ch = ch_switch->channel->hw_value;
|
||||
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
cmd.channel = cpu_to_le16(ch);
|
||||
cmd.rxon_flags = ctx->staging.flags;
|
||||
cmd.rxon_filter_flags = ctx->staging.filter_flags;
|
||||
switch_count = ch_switch->count;
|
||||
tsf_low = ch_switch->timestamp & 0x0ffffffff;
|
||||
/*
|
||||
* calculate the ucode channel switch time
|
||||
* adding TSF as one of the factor for when to switch
|
||||
*/
|
||||
if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
|
||||
if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
|
||||
beacon_interval)) {
|
||||
switch_count -= (priv->ucode_beacon_time -
|
||||
tsf_low) / beacon_interval;
|
||||
} else
|
||||
switch_count = 0;
|
||||
}
|
||||
if (switch_count <= 1)
|
||||
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
|
||||
else {
|
||||
switch_time_in_usec =
|
||||
vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
|
||||
ucode_switch_time = iwl_usecs_to_beacons(priv,
|
||||
switch_time_in_usec,
|
||||
beacon_interval);
|
||||
cmd.switch_time = iwl_add_beacon_time(priv,
|
||||
priv->ucode_beacon_time,
|
||||
ucode_switch_time,
|
||||
beacon_interval);
|
||||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return iwl_dvm_send_cmd(priv, &hcmd);
|
||||
}
|
||||
|
||||
struct iwl_lib_ops iwl6000_lib = {
|
||||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl6000_hw_channel_switch,
|
||||
.nic_config = iwl6000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
struct iwl_lib_ops iwl6030_lib = {
|
||||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl6000_hw_channel_switch,
|
||||
.nic_config = iwl6000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
@ -94,77 +94,13 @@ void iwlagn_temperature(struct iwl_priv *priv)
|
||||
iwl_tt_handler(priv);
|
||||
}
|
||||
|
||||
u16 iwl_eeprom_calib_version(struct iwl_shared *shrd)
|
||||
{
|
||||
struct iwl_eeprom_calib_hdr *hdr;
|
||||
|
||||
hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(shrd,
|
||||
EEPROM_CALIB_ALL);
|
||||
return hdr->version;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* EEPROM
|
||||
*/
|
||||
static u32 eeprom_indirect_address(const struct iwl_shared *shrd, u32 address)
|
||||
{
|
||||
u16 offset = 0;
|
||||
|
||||
if ((address & INDIRECT_ADDRESS) == 0)
|
||||
return address;
|
||||
|
||||
switch (address & INDIRECT_TYPE_MSK) {
|
||||
case INDIRECT_HOST:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_HOST);
|
||||
break;
|
||||
case INDIRECT_GENERAL:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_GENERAL);
|
||||
break;
|
||||
case INDIRECT_REGULATORY:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_REGULATORY);
|
||||
break;
|
||||
case INDIRECT_TXP_LIMIT:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_TXP_LIMIT);
|
||||
break;
|
||||
case INDIRECT_TXP_LIMIT_SIZE:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_TXP_LIMIT_SIZE);
|
||||
break;
|
||||
case INDIRECT_CALIBRATION:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_CALIBRATION);
|
||||
break;
|
||||
case INDIRECT_PROCESS_ADJST:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_PROCESS_ADJST);
|
||||
break;
|
||||
case INDIRECT_OTHERS:
|
||||
offset = iwl_eeprom_query16(shrd, EEPROM_LINK_OTHERS);
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(shrd->trans, "illegal indirect type: 0x%X\n",
|
||||
address & INDIRECT_TYPE_MSK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* translate the offset from words to byte */
|
||||
return (address & ADDRESS_MSK) + (offset << 1);
|
||||
}
|
||||
|
||||
const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset)
|
||||
{
|
||||
u32 address = eeprom_indirect_address(shrd, offset);
|
||||
BUG_ON(address >= shrd->cfg->base_params->eeprom_size);
|
||||
return &shrd->eeprom[address];
|
||||
}
|
||||
|
||||
struct iwl_mod_params iwlagn_mod_params = {
|
||||
.amsdu_size_8K = 1,
|
||||
.restart_fw = 1,
|
||||
.plcp_check = true,
|
||||
.bt_coex_active = true,
|
||||
.no_sleep_autoadjust = true,
|
||||
.power_level = IWL_POWER_INDEX_1,
|
||||
.bt_ch_announce = true,
|
||||
.wanted_ucode_alternative = 1,
|
||||
.auto_agg = true,
|
||||
/* the rest are 0 by default */
|
||||
};
|
||||
@ -234,7 +170,7 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
|
||||
IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
|
||||
IWL_PAN_SCD_MULTICAST_MSK;
|
||||
|
||||
if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
|
||||
@ -369,24 +305,30 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
|
||||
.bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
|
||||
.bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
|
||||
};
|
||||
struct iwl6000_bt_cmd bt_cmd_6000;
|
||||
struct iwl2000_bt_cmd bt_cmd_2000;
|
||||
struct iwl_bt_cmd_v1 bt_cmd_v1;
|
||||
struct iwl_bt_cmd_v2 bt_cmd_v2;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
|
||||
sizeof(basic.bt3_lookup_table));
|
||||
|
||||
if (cfg(priv)->bt_params) {
|
||||
/*
|
||||
* newer generation of devices (2000 series and newer)
|
||||
* use the version 2 of the bt command
|
||||
* we need to make sure sending the host command
|
||||
* with correct data structure to avoid uCode assert
|
||||
*/
|
||||
if (cfg(priv)->bt_params->bt_session_2) {
|
||||
bt_cmd_2000.prio_boost = cpu_to_le32(
|
||||
bt_cmd_v2.prio_boost = cpu_to_le32(
|
||||
cfg(priv)->bt_params->bt_prio_boost);
|
||||
bt_cmd_2000.tx_prio_boost = 0;
|
||||
bt_cmd_2000.rx_prio_boost = 0;
|
||||
bt_cmd_v2.tx_prio_boost = 0;
|
||||
bt_cmd_v2.rx_prio_boost = 0;
|
||||
} else {
|
||||
bt_cmd_6000.prio_boost =
|
||||
bt_cmd_v1.prio_boost =
|
||||
cfg(priv)->bt_params->bt_prio_boost;
|
||||
bt_cmd_6000.tx_prio_boost = 0;
|
||||
bt_cmd_6000.rx_prio_boost = 0;
|
||||
bt_cmd_v1.tx_prio_boost = 0;
|
||||
bt_cmd_v1.rx_prio_boost = 0;
|
||||
}
|
||||
} else {
|
||||
IWL_ERR(priv, "failed to construct BT Coex Config\n");
|
||||
@ -433,15 +375,15 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
|
||||
"full concurrency" : "3-wire");
|
||||
|
||||
if (cfg(priv)->bt_params->bt_session_2) {
|
||||
memcpy(&bt_cmd_2000.basic, &basic,
|
||||
memcpy(&bt_cmd_v2.basic, &basic,
|
||||
sizeof(basic));
|
||||
ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
|
||||
CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000);
|
||||
CMD_SYNC, sizeof(bt_cmd_v2), &bt_cmd_v2);
|
||||
} else {
|
||||
memcpy(&bt_cmd_6000.basic, &basic,
|
||||
memcpy(&bt_cmd_v1.basic, &basic,
|
||||
sizeof(basic));
|
||||
ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
|
||||
CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000);
|
||||
CMD_SYNC, sizeof(bt_cmd_v1), &bt_cmd_v1);
|
||||
}
|
||||
if (ret)
|
||||
IWL_ERR(priv, "failed to send BT Coex Config\n");
|
||||
@ -868,7 +810,7 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
if (priv->chain_noise_data.active_chains)
|
||||
active_chains = priv->chain_noise_data.active_chains;
|
||||
else
|
||||
active_chains = hw_params(priv).valid_rx_ant;
|
||||
active_chains = priv->hw_params.valid_rx_ant;
|
||||
|
||||
if (cfg(priv)->bt_params &&
|
||||
cfg(priv)->bt_params->advanced_bt_coexist &&
|
||||
@ -1300,7 +1242,7 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||
|
||||
if (test_bit(STATUS_FW_ERROR, &priv->status)) {
|
||||
IWL_ERR(priv, "Command %s failed: FW Error\n",
|
||||
get_cmd_string(cmd->id));
|
||||
iwl_dvm_get_cmd_string(cmd->id));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -819,7 +819,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
|
||||
|
||||
if (num_of_ant(tbl->ant_type) > 1)
|
||||
tbl->ant_type =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
|
||||
tbl->is_ht40 = 0;
|
||||
tbl->is_SGI = 0;
|
||||
@ -1291,7 +1291,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
|
||||
return -1;
|
||||
|
||||
/* Need both Tx chains/antennas to support MIMO */
|
||||
if (hw_params(priv).tx_chains_num < 2)
|
||||
if (priv->hw_params.tx_chains_num < 2)
|
||||
return -1;
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
|
||||
@ -1347,7 +1347,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
|
||||
return -1;
|
||||
|
||||
/* Need both Tx chains/antennas to support MIMO */
|
||||
if (hw_params(priv).tx_chains_num < 3)
|
||||
if (priv->hw_params.tx_chains_num < 3)
|
||||
return -1;
|
||||
|
||||
IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
|
||||
@ -1446,8 +1446,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
u8 tx_chains_num = hw_params(priv).tx_chains_num;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
int ret = 0;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
|
||||
@ -1464,7 +1464,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
valid_tx_ant =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
|
||||
tbl->action != IWL_LEGACY_SWITCH_SISO)
|
||||
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
||||
@ -1488,7 +1488,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
||||
else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
|
||||
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
||||
valid_tx_ant =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
}
|
||||
|
||||
start_action = tbl->action;
|
||||
@ -1622,8 +1622,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
u8 tx_chains_num = hw_params(priv).tx_chains_num;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
||||
@ -1640,7 +1640,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
valid_tx_ant =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
break;
|
||||
@ -1658,7 +1658,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
||||
/* configure as 1x1 if bt full concurrency */
|
||||
if (priv->bt_full_concurrent) {
|
||||
valid_tx_ant =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
}
|
||||
@ -1794,8 +1794,8 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
u8 tx_chains_num = hw_params(priv).tx_chains_num;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
||||
@ -1964,8 +1964,8 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
u8 tx_chains_num = hw_params(priv).tx_chains_num;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
int ret;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
|
||||
@ -2698,7 +2698,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
|
||||
|
||||
i = lq_sta->last_txrate_idx;
|
||||
|
||||
valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
|
||||
if (!lq_sta->search_better_tbl)
|
||||
active_tbl = lq_sta->active_tbl;
|
||||
@ -2826,6 +2826,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
|
||||
struct iwl_station_priv *sta_priv;
|
||||
struct iwl_lq_sta *lq_sta;
|
||||
struct ieee80211_supported_band *sband;
|
||||
unsigned long supp; /* must be unsigned long for for_each_set_bit */
|
||||
|
||||
sta_priv = (struct iwl_station_priv *) sta->drv_priv;
|
||||
lq_sta = &sta_priv->lq_sta;
|
||||
@ -2855,8 +2856,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
|
||||
lq_sta->max_rate_idx = -1;
|
||||
lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
|
||||
lq_sta->is_green = rs_use_green(sta);
|
||||
lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
|
||||
lq_sta->band = priv->band;
|
||||
lq_sta->band = sband->band;
|
||||
/*
|
||||
* active legacy rates as per supported rates bitmap
|
||||
*/
|
||||
supp = sta->supp_rates[sband->band];
|
||||
lq_sta->active_legacy_rate = 0;
|
||||
for_each_set_bit(i, &supp, BITS_PER_LONG)
|
||||
lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
|
||||
|
||||
/*
|
||||
* active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
|
||||
* supp_rates[] does not; shift to convert format, force 9 MBits off.
|
||||
@ -2884,15 +2892,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
|
||||
|
||||
/* These values will be overridden later */
|
||||
lq_sta->lq.general_params.single_stream_ant_msk =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
lq_sta->lq.general_params.dual_stream_ant_msk =
|
||||
hw_params(priv).valid_tx_ant &
|
||||
~first_antenna(hw_params(priv).valid_tx_ant);
|
||||
priv->hw_params.valid_tx_ant &
|
||||
~first_antenna(priv->hw_params.valid_tx_ant);
|
||||
if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
|
||||
lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
|
||||
} else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) {
|
||||
} else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
|
||||
lq_sta->lq.general_params.dual_stream_ant_msk =
|
||||
hw_params(priv).valid_tx_ant;
|
||||
priv->hw_params.valid_tx_ant;
|
||||
}
|
||||
|
||||
/* as default allow aggregation for all tids */
|
||||
@ -2938,7 +2946,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||
if (priv && priv->bt_full_concurrent) {
|
||||
/* 1x1 only */
|
||||
tbl_type.ant_type =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
}
|
||||
|
||||
/* How many times should we repeat the initial rate? */
|
||||
@ -2970,7 +2978,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||
if (priv->bt_full_concurrent)
|
||||
valid_tx_ant = ANT_A;
|
||||
else
|
||||
valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
}
|
||||
|
||||
/* Fill rest of rate table */
|
||||
@ -3004,7 +3012,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||
if (priv && priv->bt_full_concurrent) {
|
||||
/* 1x1 only */
|
||||
tbl_type.ant_type =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
}
|
||||
|
||||
/* Indicate to uCode which entries might be MIMO.
|
||||
@ -3091,7 +3099,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
|
||||
u8 ant_sel_tx;
|
||||
|
||||
priv = lq_sta->drv;
|
||||
valid_tx_ant = hw_params(priv).valid_tx_ant;
|
||||
valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
if (lq_sta->dbg_fixed_rate) {
|
||||
ant_sel_tx =
|
||||
((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
|
||||
@ -3162,9 +3170,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
||||
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
|
||||
lq_sta->dbg_fixed_rate);
|
||||
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
|
||||
(hw_params(priv).valid_tx_ant & ANT_A) ? "ANT_A," : "",
|
||||
(hw_params(priv).valid_tx_ant & ANT_B) ? "ANT_B," : "",
|
||||
(hw_params(priv).valid_tx_ant & ANT_C) ? "ANT_C" : "");
|
||||
(priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
|
||||
(priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
|
||||
(priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
|
||||
desc += sprintf(buff+desc, "lq type %s\n",
|
||||
(is_legacy(tbl->lq_type)) ? "legacy" : "HT");
|
||||
if (is_Ht(tbl->lq_type)) {
|
||||
|
@ -40,89 +40,86 @@
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-shared.h"
|
||||
|
||||
const char *get_cmd_string(u8 cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
IWL_CMD(REPLY_ALIVE);
|
||||
IWL_CMD(REPLY_ERROR);
|
||||
IWL_CMD(REPLY_ECHO);
|
||||
IWL_CMD(REPLY_RXON);
|
||||
IWL_CMD(REPLY_RXON_ASSOC);
|
||||
IWL_CMD(REPLY_QOS_PARAM);
|
||||
IWL_CMD(REPLY_RXON_TIMING);
|
||||
IWL_CMD(REPLY_ADD_STA);
|
||||
IWL_CMD(REPLY_REMOVE_STA);
|
||||
IWL_CMD(REPLY_REMOVE_ALL_STA);
|
||||
IWL_CMD(REPLY_TXFIFO_FLUSH);
|
||||
IWL_CMD(REPLY_WEPKEY);
|
||||
IWL_CMD(REPLY_TX);
|
||||
IWL_CMD(REPLY_LEDS_CMD);
|
||||
IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
|
||||
IWL_CMD(COEX_PRIORITY_TABLE_CMD);
|
||||
IWL_CMD(COEX_MEDIUM_NOTIFICATION);
|
||||
IWL_CMD(COEX_EVENT_CMD);
|
||||
IWL_CMD(REPLY_QUIET_CMD);
|
||||
IWL_CMD(REPLY_CHANNEL_SWITCH);
|
||||
IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
|
||||
IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
|
||||
IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
|
||||
IWL_CMD(POWER_TABLE_CMD);
|
||||
IWL_CMD(PM_SLEEP_NOTIFICATION);
|
||||
IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
|
||||
IWL_CMD(REPLY_SCAN_CMD);
|
||||
IWL_CMD(REPLY_SCAN_ABORT_CMD);
|
||||
IWL_CMD(SCAN_START_NOTIFICATION);
|
||||
IWL_CMD(SCAN_RESULTS_NOTIFICATION);
|
||||
IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
|
||||
IWL_CMD(BEACON_NOTIFICATION);
|
||||
IWL_CMD(REPLY_TX_BEACON);
|
||||
IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
|
||||
IWL_CMD(QUIET_NOTIFICATION);
|
||||
IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
|
||||
IWL_CMD(MEASURE_ABORT_NOTIFICATION);
|
||||
IWL_CMD(REPLY_BT_CONFIG);
|
||||
IWL_CMD(REPLY_STATISTICS_CMD);
|
||||
IWL_CMD(STATISTICS_NOTIFICATION);
|
||||
IWL_CMD(REPLY_CARD_STATE_CMD);
|
||||
IWL_CMD(CARD_STATE_NOTIFICATION);
|
||||
IWL_CMD(MISSED_BEACONS_NOTIFICATION);
|
||||
IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
|
||||
IWL_CMD(SENSITIVITY_CMD);
|
||||
IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
|
||||
IWL_CMD(REPLY_RX_PHY_CMD);
|
||||
IWL_CMD(REPLY_RX_MPDU_CMD);
|
||||
IWL_CMD(REPLY_RX);
|
||||
IWL_CMD(REPLY_COMPRESSED_BA);
|
||||
IWL_CMD(CALIBRATION_CFG_CMD);
|
||||
IWL_CMD(CALIBRATION_RES_NOTIFICATION);
|
||||
IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
|
||||
IWL_CMD(REPLY_TX_POWER_DBM_CMD);
|
||||
IWL_CMD(TEMPERATURE_NOTIFICATION);
|
||||
IWL_CMD(TX_ANT_CONFIGURATION_CMD);
|
||||
IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
|
||||
IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
|
||||
IWL_CMD(REPLY_BT_COEX_PROT_ENV);
|
||||
IWL_CMD(REPLY_WIPAN_PARAMS);
|
||||
IWL_CMD(REPLY_WIPAN_RXON);
|
||||
IWL_CMD(REPLY_WIPAN_RXON_TIMING);
|
||||
IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
|
||||
IWL_CMD(REPLY_WIPAN_QOS_PARAM);
|
||||
IWL_CMD(REPLY_WIPAN_WEPKEY);
|
||||
IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
|
||||
IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
|
||||
IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE);
|
||||
IWL_CMD(REPLY_WOWLAN_PATTERNS);
|
||||
IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER);
|
||||
IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS);
|
||||
IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS);
|
||||
IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL);
|
||||
IWL_CMD(REPLY_WOWLAN_GET_STATUS);
|
||||
IWL_CMD(REPLY_D3_CONFIG);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
#define IWL_CMD_ENTRY(x) [x] = #x
|
||||
|
||||
}
|
||||
}
|
||||
const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
|
||||
IWL_CMD_ENTRY(REPLY_ALIVE),
|
||||
IWL_CMD_ENTRY(REPLY_ERROR),
|
||||
IWL_CMD_ENTRY(REPLY_ECHO),
|
||||
IWL_CMD_ENTRY(REPLY_RXON),
|
||||
IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
|
||||
IWL_CMD_ENTRY(REPLY_QOS_PARAM),
|
||||
IWL_CMD_ENTRY(REPLY_RXON_TIMING),
|
||||
IWL_CMD_ENTRY(REPLY_ADD_STA),
|
||||
IWL_CMD_ENTRY(REPLY_REMOVE_STA),
|
||||
IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
|
||||
IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
|
||||
IWL_CMD_ENTRY(REPLY_WEPKEY),
|
||||
IWL_CMD_ENTRY(REPLY_TX),
|
||||
IWL_CMD_ENTRY(REPLY_LEDS_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
|
||||
IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
|
||||
IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(COEX_EVENT_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_QUIET_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
|
||||
IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
|
||||
IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(POWER_TABLE_CMD),
|
||||
IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
|
||||
IWL_CMD_ENTRY(REPLY_SCAN_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
|
||||
IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(BEACON_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_TX_BEACON),
|
||||
IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(QUIET_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
|
||||
IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_BT_CONFIG),
|
||||
IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
|
||||
IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
|
||||
IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
|
||||
IWL_CMD_ENTRY(SENSITIVITY_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_RX),
|
||||
IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
|
||||
IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
|
||||
IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
|
||||
IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
|
||||
IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
|
||||
IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
|
||||
IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
|
||||
IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
|
||||
IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
|
||||
IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
|
||||
IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
|
||||
IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
|
||||
IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
|
||||
IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
|
||||
IWL_CMD_ENTRY(REPLY_D3_CONFIG),
|
||||
};
|
||||
#undef IWL_CMD_ENTRY
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
@ -137,10 +134,9 @@ static int iwlagn_rx_reply_error(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_error_resp *err_resp = (void *)pkt->data;
|
||||
|
||||
IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
|
||||
IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) "
|
||||
"seq 0x%04X ser 0x%08X\n",
|
||||
le32_to_cpu(err_resp->error_type),
|
||||
get_cmd_string(err_resp->cmd_id),
|
||||
err_resp->cmd_id,
|
||||
le16_to_cpu(err_resp->bad_cmd_seq_num),
|
||||
le32_to_cpu(err_resp->error_info));
|
||||
@ -216,8 +212,7 @@ static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
|
||||
u32 __maybe_unused len =
|
||||
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
|
||||
"notification for %s:\n", len,
|
||||
get_cmd_string(pkt->hdr.cmd));
|
||||
"notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
|
||||
iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
|
||||
return 0;
|
||||
}
|
||||
@ -246,69 +241,6 @@ static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
|
||||
#define ACK_CNT_RATIO (50)
|
||||
#define BA_TIMEOUT_CNT (5)
|
||||
#define BA_TIMEOUT_MAX (16)
|
||||
|
||||
/**
|
||||
* iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
|
||||
*
|
||||
* When the ACK count ratio is low and aggregated BA timeout retries exceeding
|
||||
* the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
|
||||
* operation state.
|
||||
*/
|
||||
static bool iwlagn_good_ack_health(struct iwl_priv *priv,
|
||||
struct statistics_tx *cur)
|
||||
{
|
||||
int actual_delta, expected_delta, ba_timeout_delta;
|
||||
struct statistics_tx *old;
|
||||
|
||||
if (priv->agg_tids_count)
|
||||
return true;
|
||||
|
||||
lockdep_assert_held(&priv->statistics.lock);
|
||||
|
||||
old = &priv->statistics.tx;
|
||||
|
||||
actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
|
||||
le32_to_cpu(old->actual_ack_cnt);
|
||||
expected_delta = le32_to_cpu(cur->expected_ack_cnt) -
|
||||
le32_to_cpu(old->expected_ack_cnt);
|
||||
|
||||
/* Values should not be negative, but we do not trust the firmware */
|
||||
if (actual_delta <= 0 || expected_delta <= 0)
|
||||
return true;
|
||||
|
||||
ba_timeout_delta = le32_to_cpu(cur->agg.ba_timeout) -
|
||||
le32_to_cpu(old->agg.ba_timeout);
|
||||
|
||||
if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO &&
|
||||
ba_timeout_delta > BA_TIMEOUT_CNT) {
|
||||
IWL_DEBUG_RADIO(priv,
|
||||
"deltas: actual %d expected %d ba_timeout %d\n",
|
||||
actual_delta, expected_delta, ba_timeout_delta);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/*
|
||||
* This is ifdef'ed on DEBUGFS because otherwise the
|
||||
* statistics aren't available. If DEBUGFS is set but
|
||||
* DEBUG is not, these will just compile out.
|
||||
*/
|
||||
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
|
||||
priv->delta_stats.tx.rx_detected_cnt);
|
||||
IWL_DEBUG_RADIO(priv,
|
||||
"ack_or_ba_timeout_collision delta %d\n",
|
||||
priv->delta_stats.tx.ack_or_ba_timeout_collision);
|
||||
#endif
|
||||
|
||||
if (ba_timeout_delta >= BA_TIMEOUT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_good_plcp_health - checks for plcp error.
|
||||
*
|
||||
@ -347,6 +279,45 @@ static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
|
||||
return true;
|
||||
}
|
||||
|
||||
int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
|
||||
{
|
||||
struct iwl_rf_reset *rf_reset;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EAGAIN;
|
||||
|
||||
if (!iwl_is_any_associated(priv)) {
|
||||
IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
rf_reset = &priv->rf_reset;
|
||||
rf_reset->reset_request_count++;
|
||||
if (!external && rf_reset->last_reset_jiffies &&
|
||||
time_after(rf_reset->last_reset_jiffies +
|
||||
IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
|
||||
IWL_DEBUG_INFO(priv, "RF reset rejected\n");
|
||||
rf_reset->reset_reject_count++;
|
||||
return -EAGAIN;
|
||||
}
|
||||
rf_reset->reset_success_count++;
|
||||
rf_reset->last_reset_jiffies = jiffies;
|
||||
|
||||
/*
|
||||
* There is no easy and better way to force reset the radio,
|
||||
* the only known method is switching channel which will force to
|
||||
* reset and tune the radio.
|
||||
* Use internal short scan (single channel) operation to should
|
||||
* achieve this objective.
|
||||
* Driver should reset the radio when number of consecutive missed
|
||||
* beacon, or any other uCode error condition detected.
|
||||
*/
|
||||
IWL_DEBUG_INFO(priv, "perform radio reset.\n");
|
||||
iwl_internal_short_hw_scan(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
|
||||
struct statistics_rx_phy *cur_ofdm,
|
||||
struct statistics_rx_ht_phy *cur_ofdm_ht,
|
||||
@ -368,15 +339,9 @@ static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
|
||||
if (msecs < 99)
|
||||
return;
|
||||
|
||||
if (iwlagn_mod_params.ack_check && !iwlagn_good_ack_health(priv, tx)) {
|
||||
IWL_ERR(priv, "low ack count detected, restart firmware\n");
|
||||
if (!iwl_force_reset(priv, IWL_FW_RESET, false))
|
||||
return;
|
||||
}
|
||||
|
||||
if (iwlagn_mod_params.plcp_check &&
|
||||
!iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
|
||||
iwl_force_reset(priv, IWL_RF_RESET, false);
|
||||
iwl_force_rf_reset(priv, false);
|
||||
}
|
||||
|
||||
/* Calculate noise level, based on measurements during network silence just
|
||||
@ -589,8 +554,8 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
|
||||
iwlagn_rx_calc_noise(priv);
|
||||
queue_work(priv->workqueue, &priv->run_time_calib_work);
|
||||
}
|
||||
if (cfg(priv)->lib->temperature && change)
|
||||
cfg(priv)->lib->temperature(priv);
|
||||
if (priv->lib->temperature && change)
|
||||
priv->lib->temperature(priv);
|
||||
|
||||
spin_unlock(&priv->statistics.lock);
|
||||
|
||||
@ -1182,9 +1147,9 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
|
||||
err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
|
||||
} else {
|
||||
/* No handling needed */
|
||||
IWL_DEBUG_RX(priv,
|
||||
"No handler needed for %s, 0x%02x\n",
|
||||
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
|
||||
IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
|
||||
iwl_dvm_get_cmd_string(pkt->hdr.cmd),
|
||||
pkt->hdr.cmd);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
@ -32,6 +32,78 @@
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-shared.h"
|
||||
|
||||
/*
|
||||
* initialize rxon structure with default values from eeprom
|
||||
*/
|
||||
void iwl_connection_init_rx_config(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
||||
memset(&ctx->staging, 0, sizeof(ctx->staging));
|
||||
|
||||
if (!ctx->vif) {
|
||||
ctx->staging.dev_type = ctx->unused_devtype;
|
||||
} else
|
||||
switch (ctx->vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
ctx->staging.dev_type = ctx->ap_devtype;
|
||||
break;
|
||||
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ctx->staging.dev_type = ctx->station_devtype;
|
||||
ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
|
||||
break;
|
||||
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ctx->staging.dev_type = ctx->ibss_devtype;
|
||||
ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
|
||||
RXON_FILTER_ACCEPT_GRP_MSK;
|
||||
break;
|
||||
|
||||
default:
|
||||
IWL_ERR(priv, "Unsupported interface type %d\n",
|
||||
ctx->vif->type);
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* TODO: Figure out when short_preamble would be set and cache from
|
||||
* that */
|
||||
if (!hw_to_local(priv->hw)->short_preamble)
|
||||
ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
else
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
#endif
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, priv->band,
|
||||
le16_to_cpu(ctx->active.channel));
|
||||
|
||||
if (!ch_info)
|
||||
ch_info = &priv->channel_info[0];
|
||||
|
||||
ctx->staging.channel = cpu_to_le16(ch_info->channel);
|
||||
priv->band = ch_info->band;
|
||||
|
||||
iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
|
||||
|
||||
ctx->staging.ofdm_basic_rates =
|
||||
(IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
|
||||
ctx->staging.cck_basic_rates =
|
||||
(IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
|
||||
|
||||
/* clear both MIX and PURE40 mode flag */
|
||||
ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
|
||||
RXON_FLG_CHANNEL_MODE_PURE_40);
|
||||
if (ctx->vif)
|
||||
memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
|
||||
|
||||
ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
|
||||
ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
|
||||
ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
|
||||
}
|
||||
|
||||
static int iwlagn_disable_bss(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct iwl_rxon_cmd *send)
|
||||
@ -105,8 +177,7 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwlagn_update_qos(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -133,8 +204,8 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
|
||||
IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
|
||||
}
|
||||
|
||||
static int iwlagn_update_beacon(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
int iwlagn_update_beacon(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
@ -335,6 +406,64 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
||||
{
|
||||
int ret;
|
||||
s8 prev_tx_power;
|
||||
bool defer;
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
||||
if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED)
|
||||
return 0;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (priv->tx_power_user_lmt == tx_power && !force)
|
||||
return 0;
|
||||
|
||||
if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
|
||||
IWL_WARN(priv,
|
||||
"Requested user TXPOWER %d below lower limit %d.\n",
|
||||
tx_power,
|
||||
IWLAGN_TX_POWER_TARGET_POWER_MIN);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tx_power > priv->tx_power_device_lmt) {
|
||||
IWL_WARN(priv,
|
||||
"Requested user TXPOWER %d above upper limit %d.\n",
|
||||
tx_power, priv->tx_power_device_lmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!iwl_is_ready_rf(priv))
|
||||
return -EIO;
|
||||
|
||||
/* scan complete and commit_rxon use tx_power_next value,
|
||||
* it always need to be updated for newest request */
|
||||
priv->tx_power_next = tx_power;
|
||||
|
||||
/* do not set tx power when scanning or channel changing */
|
||||
defer = test_bit(STATUS_SCANNING, &priv->status) ||
|
||||
memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
|
||||
if (defer && !force) {
|
||||
IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev_tx_power = priv->tx_power_user_lmt;
|
||||
priv->tx_power_user_lmt = tx_power;
|
||||
|
||||
ret = iwlagn_send_tx_power(priv);
|
||||
|
||||
/* if fail to set tx_power, restore the orig. tx power */
|
||||
if (ret) {
|
||||
priv->tx_power_user_lmt = prev_tx_power;
|
||||
priv->tx_power_next = prev_tx_power;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwlagn_rxon_connect(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
@ -501,6 +630,161 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _iwl_set_rxon_ht(struct iwl_priv *priv,
|
||||
struct iwl_ht_config *ht_conf,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
struct iwl_rxon_cmd *rxon = &ctx->staging;
|
||||
|
||||
if (!ctx->ht.enabled) {
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
|
||||
RXON_FLG_HT40_PROT_MSK |
|
||||
RXON_FLG_HT_PROT_MSK);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: if the definition of ht.protection changed, the "translation"
|
||||
* will be needed for rxon->flags
|
||||
*/
|
||||
rxon->flags |= cpu_to_le32(ctx->ht.protection <<
|
||||
RXON_FLG_HT_OPERATING_MODE_POS);
|
||||
|
||||
/* Set up channel bandwidth:
|
||||
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
|
||||
/* clear the HT channel mode before set the mode */
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
|
||||
if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
|
||||
/* pure ht40 */
|
||||
if (ctx->ht.protection ==
|
||||
IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
|
||||
/*
|
||||
* Note: control channel is opposite of extension
|
||||
* channel
|
||||
*/
|
||||
switch (ctx->ht.extension_chan_offset) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
rxon->flags &=
|
||||
~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
|
||||
break;
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
||||
rxon->flags |=
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Note: control channel is opposite of extension
|
||||
* channel
|
||||
*/
|
||||
switch (ctx->ht.extension_chan_offset) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
rxon->flags &=
|
||||
~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
|
||||
break;
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
||||
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
|
||||
break;
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
|
||||
default:
|
||||
/*
|
||||
* channel location only valid if in Mixed
|
||||
* mode
|
||||
*/
|
||||
IWL_ERR(priv,
|
||||
"invalid extension channel offset\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
|
||||
}
|
||||
|
||||
iwlagn_set_rxon_chain(priv, ctx);
|
||||
|
||||
IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
|
||||
"extension channel offset 0x%x\n",
|
||||
le32_to_cpu(rxon->flags), ctx->ht.protection,
|
||||
ctx->ht.extension_chan_offset);
|
||||
}
|
||||
|
||||
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
|
||||
{
|
||||
struct iwl_rxon_context *ctx;
|
||||
|
||||
for_each_context(priv, ctx)
|
||||
_iwl_set_rxon_ht(priv, ht_conf, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_set_rxon_channel - Set the band and channel values in staging RXON
|
||||
* @ch: requested channel as a pointer to struct ieee80211_channel
|
||||
|
||||
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
|
||||
* in the staging RXON flag structure based on the ch->band
|
||||
*/
|
||||
void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
enum ieee80211_band band = ch->band;
|
||||
u16 channel = ch->hw_value;
|
||||
|
||||
if ((le16_to_cpu(ctx->staging.channel) == channel) &&
|
||||
(priv->band == band))
|
||||
return;
|
||||
|
||||
ctx->staging.channel = cpu_to_le16(channel);
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
|
||||
else
|
||||
ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
|
||||
|
||||
priv->band = band;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
|
||||
|
||||
}
|
||||
|
||||
void iwl_set_flags_for_band(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
if (band == IEEE80211_BAND_5GHZ) {
|
||||
ctx->staging.flags &=
|
||||
~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
|
||||
| RXON_FLG_CCK_MSK);
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
} else {
|
||||
/* Copied from iwl_post_associate() */
|
||||
if (vif && vif->bss_conf.use_short_slot)
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
else
|
||||
ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
|
||||
|
||||
ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
|
||||
ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
|
||||
ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_set_rate(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_rxon_context *ctx;
|
||||
|
||||
for_each_context(priv, ctx) {
|
||||
ctx->staging.cck_basic_rates =
|
||||
(IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
|
||||
|
||||
ctx->staging.ofdm_basic_rates =
|
||||
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx, int hw_decrypt)
|
||||
{
|
||||
@ -594,8 +878,8 @@ static int iwl_check_rxon_cmd(struct iwl_priv *priv,
|
||||
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
|
||||
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
|
||||
*/
|
||||
static int iwl_full_rxon_required(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
int iwl_full_rxon_required(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
const struct iwl_rxon_cmd *staging = &ctx->staging;
|
||||
const struct iwl_rxon_cmd *active = &ctx->active;
|
||||
@ -649,6 +933,33 @@ static int iwl_full_rxon_required(struct iwl_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
void iwl_print_rx_config_cmd(struct iwl_priv *priv,
|
||||
enum iwl_rxon_context_id ctxid)
|
||||
{
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
|
||||
struct iwl_rxon_cmd *rxon = &ctx->staging;
|
||||
|
||||
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
|
||||
iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
|
||||
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n",
|
||||
le16_to_cpu(rxon->channel));
|
||||
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n",
|
||||
le32_to_cpu(rxon->flags));
|
||||
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
|
||||
le32_to_cpu(rxon->filter_flags));
|
||||
IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
|
||||
IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
|
||||
rxon->ofdm_basic_rates);
|
||||
IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n",
|
||||
rxon->cck_basic_rates);
|
||||
IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
|
||||
IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
|
||||
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n",
|
||||
le16_to_cpu(rxon->assoc_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* iwlagn_commit_rxon - commit staging_rxon to hardware
|
||||
*
|
||||
@ -692,7 +1003,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
* force CTS-to-self frames protection if RTS-CTS is not preferred
|
||||
* one aggregation protection method
|
||||
*/
|
||||
if (!hw_params(priv).use_rts_for_aggregation)
|
||||
if (!priv->hw_params.use_rts_for_aggregation)
|
||||
ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
|
||||
|
||||
if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
|
||||
@ -911,9 +1222,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
{
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_rxon_context *tmp;
|
||||
@ -1005,11 +1316,14 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
ht_conf->single_chain_sufficient = !need_multiple;
|
||||
}
|
||||
|
||||
static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
|
||||
void iwlagn_chain_noise_reset(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
|
||||
int ret;
|
||||
|
||||
if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED))
|
||||
return;
|
||||
|
||||
if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
|
||||
iwl_is_any_associated(priv)) {
|
||||
struct iwl_calib_chain_noise_reset_cmd cmd;
|
||||
@ -1162,8 +1476,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
|
||||
iwl_power_update_mode(priv, false);
|
||||
|
||||
/* Enable RX differential gain and sensitivity calibrations */
|
||||
if (!priv->disable_chain_noise_cal)
|
||||
iwlagn_chain_noise_reset(priv);
|
||||
iwlagn_chain_noise_reset(priv);
|
||||
priv->start_calib = 1;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
|
||||
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
|
||||
{
|
||||
lockdep_assert_held(&priv->sta_lock);
|
||||
@ -170,6 +172,50 @@ int iwl_send_add_sta(struct iwl_priv *priv,
|
||||
return cmd.handler_status;
|
||||
}
|
||||
|
||||
static bool iwl_is_channel_extension(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u16 channel, u8 extension_chan_offset)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||
if (!is_channel_valid(ch_info))
|
||||
return false;
|
||||
|
||||
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta_ht_cap *ht_cap)
|
||||
{
|
||||
if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
|
||||
* the bit will not set if it is pure 40MHz case
|
||||
*/
|
||||
if (ht_cap && !ht_cap->ht_supported)
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (priv->disable_ht40)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return iwl_is_channel_extension(priv, priv->band,
|
||||
le16_to_cpu(ctx->staging.channel),
|
||||
ctx->ht.extension_chan_offset);
|
||||
}
|
||||
|
||||
static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_rxon_context *ctx,
|
||||
@ -581,6 +627,56 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
|
||||
spin_unlock_bh(&priv->sta_lock);
|
||||
}
|
||||
|
||||
static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
|
||||
{
|
||||
int i, r;
|
||||
u32 rate_flags = 0;
|
||||
__le32 rate_n_flags;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
memset(link_cmd, 0, sizeof(*link_cmd));
|
||||
|
||||
/* Set up the rate scaling to start at selected rate, fall back
|
||||
* all the way down to 1M in IEEE order, and then spin on 1M */
|
||||
if (priv->band == IEEE80211_BAND_5GHZ)
|
||||
r = IWL_RATE_6M_INDEX;
|
||||
else if (ctx && ctx->vif && ctx->vif->p2p)
|
||||
r = IWL_RATE_6M_INDEX;
|
||||
else
|
||||
r = IWL_RATE_1M_INDEX;
|
||||
|
||||
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
|
||||
RATE_MCS_ANT_POS;
|
||||
rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
|
||||
|
||||
link_cmd->general_params.single_stream_ant_msk =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant &
|
||||
~first_antenna(priv->hw_params.valid_tx_ant);
|
||||
if (!link_cmd->general_params.dual_stream_ant_msk) {
|
||||
link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
|
||||
} else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant;
|
||||
}
|
||||
|
||||
link_cmd->agg_params.agg_dis_start_th =
|
||||
LINK_QUAL_AGG_DISABLE_START_DEF;
|
||||
link_cmd->agg_params.agg_time_limit =
|
||||
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||
|
||||
link_cmd->sta_id = sta_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_clear_ucode_stations - clear ucode station table bits
|
||||
*
|
||||
@ -841,56 +937,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
}
|
||||
|
||||
|
||||
void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
|
||||
{
|
||||
int i, r;
|
||||
u32 rate_flags = 0;
|
||||
__le32 rate_n_flags;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
memset(link_cmd, 0, sizeof(*link_cmd));
|
||||
|
||||
/* Set up the rate scaling to start at selected rate, fall back
|
||||
* all the way down to 1M in IEEE order, and then spin on 1M */
|
||||
if (priv->band == IEEE80211_BAND_5GHZ)
|
||||
r = IWL_RATE_6M_INDEX;
|
||||
else if (ctx && ctx->vif && ctx->vif->p2p)
|
||||
r = IWL_RATE_6M_INDEX;
|
||||
else
|
||||
r = IWL_RATE_1M_INDEX;
|
||||
|
||||
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
rate_flags |= first_antenna(hw_params(priv).valid_tx_ant) <<
|
||||
RATE_MCS_ANT_POS;
|
||||
rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
|
||||
|
||||
link_cmd->general_params.single_stream_ant_msk =
|
||||
first_antenna(hw_params(priv).valid_tx_ant);
|
||||
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
hw_params(priv).valid_tx_ant &
|
||||
~first_antenna(hw_params(priv).valid_tx_ant);
|
||||
if (!link_cmd->general_params.dual_stream_ant_msk) {
|
||||
link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
|
||||
} else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) {
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
hw_params(priv).valid_tx_ant;
|
||||
}
|
||||
|
||||
link_cmd->agg_params.agg_dis_start_th =
|
||||
LINK_QUAL_AGG_DISABLE_START_DEF;
|
||||
link_cmd->agg_params.agg_time_limit =
|
||||
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||
|
||||
link_cmd->sta_id = sta_id;
|
||||
}
|
||||
|
||||
static struct iwl_link_quality_cmd *
|
||||
iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
u8 sta_id)
|
||||
|
@ -208,10 +208,10 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
|
||||
priv->bt_full_concurrent) {
|
||||
/* operated as 1x1 in full concurrency mode */
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
first_antenna(hw_params(priv).valid_tx_ant));
|
||||
first_antenna(priv->hw_params.valid_tx_ant));
|
||||
} else
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
hw_params(priv).valid_tx_ant);
|
||||
priv->hw_params.valid_tx_ant);
|
||||
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
|
||||
|
||||
/* Set the rate in the TX cmd */
|
||||
@ -689,7 +689,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
||||
sta_priv->max_agg_bufsize =
|
||||
min(sta_priv->max_agg_bufsize, buf_size);
|
||||
|
||||
if (hw_params(priv).use_rts_for_aggregation) {
|
||||
if (priv->hw_params.use_rts_for_aggregation) {
|
||||
/*
|
||||
* switch to RTS/CTS if it is the prefer protection
|
||||
* method for HT traffic
|
||||
|
@ -180,7 +180,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
|
||||
rate = info->control.rates[0].idx;
|
||||
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
hw_params(priv).valid_tx_ant);
|
||||
priv->hw_params.valid_tx_ant);
|
||||
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
|
||||
|
||||
/* In mac80211, rates for 5 GHz start at 0 */
|
||||
@ -289,6 +289,25 @@ out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
|
||||
{
|
||||
struct iwl_statistics_cmd statistics_cmd = {
|
||||
.configuration_flags =
|
||||
clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
|
||||
};
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
|
||||
CMD_ASYNC,
|
||||
sizeof(struct iwl_statistics_cmd),
|
||||
&statistics_cmd);
|
||||
else
|
||||
return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
|
||||
CMD_SYNC,
|
||||
sizeof(struct iwl_statistics_cmd),
|
||||
&statistics_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_bg_statistics_periodic - Timer callback to queue statistics
|
||||
*
|
||||
@ -578,7 +597,7 @@ static const u8 iwlagn_pan_queue_to_ac[] = {
|
||||
IEEE80211_AC_VO,
|
||||
};
|
||||
|
||||
static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
||||
void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -645,7 +664,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
||||
BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
|
||||
}
|
||||
|
||||
static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_ct_kill_config cmd;
|
||||
struct iwl_ct_kill_throttling_config adv_cmd;
|
||||
@ -658,9 +677,9 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
|
||||
if (cfg(priv)->base_params->support_ct_kill_exit) {
|
||||
adv_cmd.critical_temperature_enter =
|
||||
cpu_to_le32(hw_params(priv).ct_kill_threshold);
|
||||
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
||||
adv_cmd.critical_temperature_exit =
|
||||
cpu_to_le32(hw_params(priv).ct_kill_exit_threshold);
|
||||
cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
|
||||
|
||||
ret = iwl_dvm_send_cmd_pdu(priv,
|
||||
REPLY_CT_KILL_CONFIG_CMD,
|
||||
@ -671,11 +690,11 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
||||
"succeeded, critical temperature enter is %d,"
|
||||
"exit is %d\n",
|
||||
hw_params(priv).ct_kill_threshold,
|
||||
hw_params(priv).ct_kill_exit_threshold);
|
||||
priv->hw_params.ct_kill_threshold,
|
||||
priv->hw_params.ct_kill_exit_threshold);
|
||||
} else {
|
||||
cmd.critical_temperature_R =
|
||||
cpu_to_le32(hw_params(priv).ct_kill_threshold);
|
||||
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
||||
|
||||
ret = iwl_dvm_send_cmd_pdu(priv,
|
||||
REPLY_CT_KILL_CONFIG_CMD,
|
||||
@ -686,7 +705,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
||||
"succeeded, "
|
||||
"critical temperature is %d\n",
|
||||
hw_params(priv).ct_kill_threshold);
|
||||
priv->hw_params.ct_kill_threshold);
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,6 +745,29 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_send_bt_config(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_bt_cmd bt_cmd = {
|
||||
.lead_time = BT_LEAD_TIME_DEF,
|
||||
.max_kill = BT_MAX_KILL_DEF,
|
||||
.kill_ack_mask = 0,
|
||||
.kill_cts_mask = 0,
|
||||
};
|
||||
|
||||
if (!iwlagn_mod_params.bt_coex_active)
|
||||
bt_cmd.flags = BT_COEX_DISABLE;
|
||||
else
|
||||
bt_cmd.flags = BT_COEX_ENABLE;
|
||||
|
||||
priv->bt_enable_flag = bt_cmd.flags;
|
||||
IWL_DEBUG_INFO(priv, "BT coex %s\n",
|
||||
(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
|
||||
|
||||
if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
|
||||
CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
|
||||
IWL_ERR(priv, "failed to send BT Coex Config\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_alive_start - called after REPLY_ALIVE notification received
|
||||
* from protocol/runtime uCode (initialization uCode's
|
||||
@ -741,9 +783,6 @@ int iwl_alive_start(struct iwl_priv *priv)
|
||||
/* After the ALIVE response, we can send host commands to the uCode */
|
||||
set_bit(STATUS_ALIVE, &priv->status);
|
||||
|
||||
/* Enable watchdog to monitor the driver tx queues */
|
||||
iwl_setup_watchdog(priv);
|
||||
|
||||
if (iwl_is_rfkill(priv))
|
||||
return -ERFKILL;
|
||||
|
||||
@ -793,10 +832,8 @@ int iwl_alive_start(struct iwl_priv *priv)
|
||||
|
||||
ieee80211_wake_queues(priv->hw);
|
||||
|
||||
priv->active_rate = IWL_RATES_MASK;
|
||||
|
||||
/* Configure Tx antenna selection based on H/W config */
|
||||
iwlagn_send_tx_ant_config(priv, hw_params(priv).valid_tx_ant);
|
||||
iwlagn_send_tx_ant_config(priv, priv->hw_params.valid_tx_ant);
|
||||
|
||||
if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
|
||||
struct iwl_rxon_cmd *active_rxon =
|
||||
@ -887,10 +924,6 @@ void iwl_down(struct iwl_priv *priv)
|
||||
exit_pending =
|
||||
test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
|
||||
/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
|
||||
* to prevent rearm timer */
|
||||
del_timer_sync(&priv->watchdog);
|
||||
|
||||
iwl_clear_ucode_stations(priv, NULL);
|
||||
iwl_dealloc_bcast_stations(priv);
|
||||
iwl_clear_driver_stations(priv);
|
||||
@ -1067,7 +1100,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
priv->workqueue = create_singlethread_workqueue(DRV_NAME);
|
||||
|
||||
@ -1092,10 +1125,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
init_timer(&priv->ucode_trace);
|
||||
priv->ucode_trace.data = (unsigned long)priv;
|
||||
priv->ucode_trace.function = iwl_bg_ucode_trace;
|
||||
|
||||
init_timer(&priv->watchdog);
|
||||
priv->watchdog.data = (unsigned long)priv;
|
||||
priv->watchdog.function = iwl_bg_watchdog;
|
||||
}
|
||||
|
||||
void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
||||
@ -1143,8 +1172,8 @@ static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
u16 max_bit_rate = 0;
|
||||
u8 rx_chains_num = hw_params(priv).rx_chains_num;
|
||||
u8 tx_chains_num = hw_params(priv).tx_chains_num;
|
||||
u8 rx_chains_num = priv->hw_params.rx_chains_num;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
|
||||
ht_info->cap = 0;
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
@ -1156,7 +1185,7 @@ static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
|
||||
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||
if (hw_params(priv).ht40_channel & BIT(band)) {
|
||||
if (priv->hw_params.ht40_channel & BIT(band)) {
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
|
||||
ht_info->mcs.rx_mask[4] = 0x01;
|
||||
@ -1228,7 +1257,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
|
||||
sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
|
||||
sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
|
||||
|
||||
if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
iwl_init_ht_hw_capab(priv, &sband->ht_cap,
|
||||
IEEE80211_BAND_5GHZ);
|
||||
|
||||
@ -1238,7 +1267,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
|
||||
sband->bitrates = rates;
|
||||
sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
|
||||
|
||||
if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
iwl_init_ht_hw_capab(priv, &sband->ht_cap,
|
||||
IEEE80211_BAND_2GHZ);
|
||||
|
||||
@ -1293,11 +1322,11 @@ static int iwl_init_geos(struct iwl_priv *priv)
|
||||
priv->tx_power_next = max_tx_power;
|
||||
|
||||
if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
|
||||
hw_params(priv).sku & EEPROM_SKU_CAP_BAND_52GHZ) {
|
||||
priv->hw_params.sku & EEPROM_SKU_CAP_BAND_52GHZ) {
|
||||
IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
|
||||
"Please send your %s to maintainer.\n",
|
||||
trans(priv)->hw_id_str);
|
||||
hw_params(priv).sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
|
||||
priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
|
||||
}
|
||||
|
||||
IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
|
||||
@ -1319,7 +1348,7 @@ static void iwl_free_geos(struct iwl_priv *priv)
|
||||
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
|
||||
}
|
||||
|
||||
static int iwl_init_drv(struct iwl_priv *priv)
|
||||
int iwl_init_drv(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1343,12 +1372,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
|
||||
|
||||
priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
|
||||
|
||||
/* initialize force reset */
|
||||
priv->force_reset[IWL_RF_RESET].reset_duration =
|
||||
IWL_DELAY_NEXT_FORCE_RF_RESET;
|
||||
priv->force_reset[IWL_FW_RESET].reset_duration =
|
||||
IWL_DELAY_NEXT_FORCE_FW_RELOAD;
|
||||
|
||||
priv->rx_statistics_jiffies = jiffies;
|
||||
|
||||
/* Choose which receivers/antennas to use */
|
||||
@ -1388,7 +1411,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_uninit_drv(struct iwl_priv *priv)
|
||||
void iwl_uninit_drv(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_free_geos(priv);
|
||||
iwl_free_channel_map(priv);
|
||||
@ -1401,35 +1424,22 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Size of one Rx buffer in host DRAM */
|
||||
#define IWL_RX_BUF_SIZE_4K (4 * 1024)
|
||||
#define IWL_RX_BUF_SIZE_8K (8 * 1024)
|
||||
|
||||
static void iwl_set_hw_params(struct iwl_priv *priv)
|
||||
void iwl_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
if (cfg(priv)->ht_params)
|
||||
hw_params(priv).use_rts_for_aggregation =
|
||||
priv->hw_params.use_rts_for_aggregation =
|
||||
cfg(priv)->ht_params->use_rts_for_aggregation;
|
||||
|
||||
if (iwlagn_mod_params.amsdu_size_8K)
|
||||
hw_params(priv).rx_page_order =
|
||||
get_order(IWL_RX_BUF_SIZE_8K);
|
||||
else
|
||||
hw_params(priv).rx_page_order =
|
||||
get_order(IWL_RX_BUF_SIZE_4K);
|
||||
|
||||
if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
|
||||
hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
|
||||
|
||||
hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
|
||||
priv->hw_params.sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
|
||||
|
||||
/* Device-specific setup */
|
||||
cfg(priv)->lib->set_hw_params(priv);
|
||||
priv->lib->set_hw_params(priv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void iwl_debug_config(struct iwl_priv *priv)
|
||||
void iwl_debug_config(struct iwl_priv *priv)
|
||||
{
|
||||
dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUG "
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
@ -1501,6 +1511,42 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
priv->shrd = trans->shrd;
|
||||
priv->fw = fw;
|
||||
|
||||
switch (cfg(priv)->device_family) {
|
||||
case IWL_DEVICE_FAMILY_1000:
|
||||
case IWL_DEVICE_FAMILY_100:
|
||||
priv->lib = &iwl1000_lib;
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_2000:
|
||||
case IWL_DEVICE_FAMILY_105:
|
||||
priv->lib = &iwl2000_lib;
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_2030:
|
||||
case IWL_DEVICE_FAMILY_135:
|
||||
priv->lib = &iwl2030_lib;
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_5000:
|
||||
priv->lib = &iwl5000_lib;
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_5150:
|
||||
priv->lib = &iwl5150_lib;
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_6000:
|
||||
case IWL_DEVICE_FAMILY_6005:
|
||||
case IWL_DEVICE_FAMILY_6000i:
|
||||
case IWL_DEVICE_FAMILY_6050:
|
||||
case IWL_DEVICE_FAMILY_6150:
|
||||
priv->lib = &iwl6000_lib;
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_6030:
|
||||
priv->lib = &iwl6030_lib;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN_ON(!priv->lib))
|
||||
goto out_free_traffic_mem;
|
||||
|
||||
/*
|
||||
* Populate the state variables that the transport layer needs
|
||||
* to know about.
|
||||
@ -1508,11 +1554,18 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
trans_cfg.op_mode = op_mode;
|
||||
trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
|
||||
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
|
||||
trans_cfg.rx_buf_size_8k = iwlagn_mod_params.amsdu_size_8K;
|
||||
if (!iwlagn_mod_params.wd_disable)
|
||||
trans_cfg.queue_watchdog_timeout =
|
||||
cfg(priv)->base_params->wd_timeout;
|
||||
else
|
||||
trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;
|
||||
trans_cfg.command_names = iwl_dvm_cmd_strings;
|
||||
|
||||
ucode_flags = fw->ucode_capa.flags;
|
||||
|
||||
#ifndef CONFIG_IWLWIFI_P2P
|
||||
ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
|
||||
ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
|
||||
#endif
|
||||
|
||||
if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
|
||||
@ -1574,11 +1627,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
if (iwl_trans_start_hw(trans(priv)))
|
||||
goto out_free_traffic_mem;
|
||||
|
||||
/*****************
|
||||
* 3. Read EEPROM
|
||||
*****************/
|
||||
/* Read the EEPROM */
|
||||
if (iwl_eeprom_init(trans(priv), trans(priv)->hw_rev)) {
|
||||
if (iwl_eeprom_init(priv, trans(priv)->hw_rev)) {
|
||||
IWL_ERR(priv, "Unable to init EEPROM\n");
|
||||
goto out_free_traffic_mem;
|
||||
}
|
||||
@ -1592,11 +1642,11 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
goto out_free_eeprom;
|
||||
|
||||
/* extract MAC Address */
|
||||
iwl_eeprom_get_mac(priv->shrd, priv->addresses[0].addr);
|
||||
iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
|
||||
IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
|
||||
priv->hw->wiphy->addresses = priv->addresses;
|
||||
priv->hw->wiphy->n_addresses = 1;
|
||||
num_mac = iwl_eeprom_query16(priv->shrd, EEPROM_NUM_MAC_ADDRESS);
|
||||
num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS);
|
||||
if (num_mac > 1) {
|
||||
memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
|
||||
ETH_ALEN);
|
||||
@ -1609,7 +1659,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
************************/
|
||||
iwl_set_hw_params(priv);
|
||||
|
||||
if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
|
||||
if (!(priv->hw_params.sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
|
||||
IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
|
||||
ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
|
||||
/*
|
||||
@ -1694,7 +1744,7 @@ out_destroy_workqueue:
|
||||
priv->workqueue = NULL;
|
||||
iwl_uninit_drv(priv);
|
||||
out_free_eeprom:
|
||||
iwl_eeprom_free(priv->shrd);
|
||||
iwl_eeprom_free(priv);
|
||||
out_free_traffic_mem:
|
||||
iwl_free_traffic_mem(priv);
|
||||
ieee80211_free_hw(priv->hw);
|
||||
@ -1703,7 +1753,7 @@ out:
|
||||
return op_mode;
|
||||
}
|
||||
|
||||
static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
|
||||
void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
@ -1720,7 +1770,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
|
||||
priv->ucode_loaded = false;
|
||||
iwl_trans_stop_device(trans(priv));
|
||||
|
||||
iwl_eeprom_free(priv->shrd);
|
||||
iwl_eeprom_free(priv);
|
||||
|
||||
/*netif_stop_queue(dev); */
|
||||
flush_workqueue(priv->workqueue);
|
||||
@ -1838,7 +1888,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
||||
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
|
||||
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
|
||||
IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
|
||||
priv->shrd->status, table.valid);
|
||||
priv->status, table.valid);
|
||||
}
|
||||
|
||||
trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
|
||||
@ -2112,7 +2162,63 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void iwl_nic_error(struct iwl_op_mode *op_mode)
|
||||
static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
|
||||
{
|
||||
unsigned int reload_msec;
|
||||
unsigned long reload_jiffies;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
|
||||
iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
|
||||
#endif
|
||||
|
||||
/* uCode is no longer loaded. */
|
||||
priv->ucode_loaded = false;
|
||||
|
||||
/* Set the FW error flag -- cleared on iwl_down */
|
||||
set_bit(STATUS_FW_ERROR, &priv->status);
|
||||
|
||||
iwl_abort_notification_waits(&priv->notif_wait);
|
||||
|
||||
/* Keep the restart process from trying to send host
|
||||
* commands by clearing the ready bit */
|
||||
clear_bit(STATUS_READY, &priv->status);
|
||||
|
||||
wake_up(&trans(priv)->wait_command_queue);
|
||||
|
||||
if (!ondemand) {
|
||||
/*
|
||||
* If firmware keep reloading, then it indicate something
|
||||
* serious wrong and firmware having problem to recover
|
||||
* from it. Instead of keep trying which will fill the syslog
|
||||
* and hang the system, let's just stop it
|
||||
*/
|
||||
reload_jiffies = jiffies;
|
||||
reload_msec = jiffies_to_msecs((long) reload_jiffies -
|
||||
(long) priv->reload_jiffies);
|
||||
priv->reload_jiffies = reload_jiffies;
|
||||
if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
|
||||
priv->reload_count++;
|
||||
if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
|
||||
IWL_ERR(priv, "BUG_ON, Stop restarting\n");
|
||||
return;
|
||||
}
|
||||
} else
|
||||
priv->reload_count = 0;
|
||||
}
|
||||
|
||||
if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
if (iwlagn_mod_params.restart_fw) {
|
||||
IWL_DEBUG_FW_ERRORS(priv,
|
||||
"Restarting adapter due to uCode error.\n");
|
||||
queue_work(priv->workqueue, &priv->restart);
|
||||
} else
|
||||
IWL_DEBUG_FW_ERRORS(priv,
|
||||
"Detected FW error, but not restarting\n");
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_nic_error(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
@ -2125,7 +2231,7 @@ static void iwl_nic_error(struct iwl_op_mode *op_mode)
|
||||
iwlagn_fw_error(priv, false);
|
||||
}
|
||||
|
||||
static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
|
||||
void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
@ -2135,14 +2241,22 @@ static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_nic_config(struct iwl_op_mode *op_mode)
|
||||
void iwl_nic_config(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
cfg(priv)->lib->nic_config(priv);
|
||||
priv->lib->nic_config(priv);
|
||||
}
|
||||
|
||||
static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
static void iwl_wimax_active(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
clear_bit(STATUS_READY, &priv->status);
|
||||
IWL_ERR(priv, "RF is used by WiMAX\n");
|
||||
}
|
||||
|
||||
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
int ac = priv->queue_to_ac[queue];
|
||||
@ -2161,7 +2275,7 @@ static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
ieee80211_stop_queue(priv->hw, ac);
|
||||
}
|
||||
|
||||
static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
int ac = priv->queue_to_ac[queue];
|
||||
@ -2201,6 +2315,27 @@ void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
|
||||
priv->passive_no_rx = false;
|
||||
}
|
||||
|
||||
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
if (state)
|
||||
set_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
else
|
||||
clear_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
|
||||
wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
|
||||
}
|
||||
|
||||
const struct iwl_op_mode_ops iwl_dvm_ops = {
|
||||
.start = iwl_op_mode_dvm_start,
|
||||
.stop = iwl_op_mode_dvm_stop,
|
||||
@ -2212,6 +2347,7 @@ const struct iwl_op_mode_ops iwl_dvm_ops = {
|
||||
.nic_error = iwl_nic_error,
|
||||
.cmd_queue_full = iwl_cmd_queue_full,
|
||||
.nic_config = iwl_nic_config,
|
||||
.wimax_active = iwl_wimax_active,
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
@ -2280,12 +2416,6 @@ MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
|
||||
module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
|
||||
|
||||
module_param_named(ucode_alternative,
|
||||
iwlagn_mod_params.wanted_ucode_alternative,
|
||||
int, S_IRUGO);
|
||||
MODULE_PARM_DESC(ucode_alternative,
|
||||
"specify ucode alternative to use from ucode file");
|
||||
|
||||
module_param_named(antenna_coupling, iwlagn_mod_params.ant_coupling,
|
||||
int, S_IRUGO);
|
||||
MODULE_PARM_DESC(antenna_coupling,
|
||||
@ -2299,9 +2429,6 @@ MODULE_PARM_DESC(bt_ch_inhibition,
|
||||
module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
|
||||
|
||||
module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
|
||||
|
||||
module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(wd_disable,
|
||||
"Disable stuck queue watchdog timer 0=system default, "
|
||||
@ -2345,13 +2472,3 @@ module_param_named(auto_agg, iwlagn_mod_params.auto_agg,
|
||||
bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(auto_agg,
|
||||
"enable agg w/o check traffic load (default: enable)");
|
||||
|
||||
/*
|
||||
* For now, keep using power level 1 instead of automatically
|
||||
* adjusting ...
|
||||
*/
|
||||
module_param_named(no_sleep_autoadjust, iwlagn_mod_params.no_sleep_autoadjust,
|
||||
bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(no_sleep_autoadjust,
|
||||
"don't automatically adjust sleep level "
|
||||
"according to maximum network latency (default: true)");
|
||||
|
@ -71,6 +71,34 @@
|
||||
/* AUX (TX during scan dwell) queue */
|
||||
#define IWL_AUX_QUEUE 10
|
||||
|
||||
/* device operations */
|
||||
extern struct iwl_lib_ops iwl1000_lib;
|
||||
extern struct iwl_lib_ops iwl2000_lib;
|
||||
extern struct iwl_lib_ops iwl2030_lib;
|
||||
extern struct iwl_lib_ops iwl5000_lib;
|
||||
extern struct iwl_lib_ops iwl5150_lib;
|
||||
extern struct iwl_lib_ops iwl6000_lib;
|
||||
extern struct iwl_lib_ops iwl6030_lib;
|
||||
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* DRIVER STATUS FUNCTIONS
|
||||
******************************************************/
|
||||
#define STATUS_RF_KILL_HW 0
|
||||
#define STATUS_CT_KILL 1
|
||||
#define STATUS_ALIVE 2
|
||||
#define STATUS_READY 3
|
||||
#define STATUS_GEO_CONFIGURED 4
|
||||
#define STATUS_EXIT_PENDING 5
|
||||
#define STATUS_STATISTICS 6
|
||||
#define STATUS_SCANNING 7
|
||||
#define STATUS_SCAN_ABORTING 8
|
||||
#define STATUS_SCAN_HW 9
|
||||
#define STATUS_FW_ERROR 10
|
||||
#define STATUS_CHANNEL_SWITCH_PENDING 11
|
||||
#define STATUS_SCAN_COMPLETE 12
|
||||
#define STATUS_POWER_PMI 13
|
||||
|
||||
struct iwl_ucode_capabilities;
|
||||
|
||||
@ -87,11 +115,9 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
|
||||
void iwl_down(struct iwl_priv *priv);
|
||||
void iwl_cancel_deferred_work(struct iwl_priv *priv);
|
||||
void iwlagn_prepare_restart(struct iwl_priv *priv);
|
||||
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
|
||||
int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd);
|
||||
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
|
||||
|
||||
bool iwl_check_for_ct_kill(struct iwl_priv *priv);
|
||||
|
||||
@ -109,6 +135,8 @@ int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
|
||||
u32 flags, u16 len, const void *data);
|
||||
|
||||
/* RXON */
|
||||
void iwl_connection_init_rx_config(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
int iwlagn_set_pan_params(struct iwl_priv *priv);
|
||||
int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
@ -119,6 +147,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
|
||||
u32 changes);
|
||||
void iwlagn_config_ht40(struct ieee80211_conf *conf,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
|
||||
void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_set_flags_for_band(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_set_rate(struct iwl_priv *priv);
|
||||
|
||||
/* uCode */
|
||||
int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
|
||||
@ -131,17 +167,25 @@ int iwl_send_calib_results(struct iwl_priv *priv);
|
||||
int iwl_calib_set(struct iwl_priv *priv,
|
||||
const struct iwl_calib_hdr *cmd, int len);
|
||||
void iwl_calib_free_results(struct iwl_priv *priv);
|
||||
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
|
||||
int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||
char **buf, bool display);
|
||||
int iwlagn_hw_valid_rtc_data_addr(u32 addr);
|
||||
|
||||
/* lib */
|
||||
int iwlagn_send_tx_power(struct iwl_priv *priv);
|
||||
void iwlagn_temperature(struct iwl_priv *priv);
|
||||
u16 iwl_eeprom_calib_version(struct iwl_shared *shrd);
|
||||
int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
|
||||
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
|
||||
int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
|
||||
int iwl_send_statistics_request(struct iwl_priv *priv,
|
||||
u8 flags, bool clear);
|
||||
|
||||
static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
|
||||
struct iwl_priv *priv, enum ieee80211_band band)
|
||||
{
|
||||
return priv->hw->wiphy->bands[band];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int iwlagn_send_patterns(struct iwl_priv *priv,
|
||||
struct cfg80211_wowlan *wowlan);
|
||||
@ -151,6 +195,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan);
|
||||
/* rx */
|
||||
int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
|
||||
void iwl_setup_rx_handlers(struct iwl_priv *priv);
|
||||
void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
|
||||
|
||||
|
||||
/* tx */
|
||||
@ -195,6 +240,31 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
|
||||
/* scan */
|
||||
void iwlagn_post_scan(struct iwl_priv *priv);
|
||||
void iwlagn_disable_roc(struct iwl_priv *priv);
|
||||
int iwl_force_rf_reset(struct iwl_priv *priv, bool external);
|
||||
void iwl_init_scan_params(struct iwl_priv *priv);
|
||||
int iwl_scan_cancel(struct iwl_priv *priv);
|
||||
void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
|
||||
void iwl_force_scan_end(struct iwl_priv *priv);
|
||||
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
|
||||
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
|
||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
|
||||
void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
|
||||
int __must_check iwl_scan_initiate(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
enum iwl_scan_type scan_type,
|
||||
enum ieee80211_band band);
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
* ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
|
||||
* time if it's a quiet channel (nothing responded to our probe, and there's
|
||||
* no other traffic).
|
||||
* Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
|
||||
#define IWL_ACTIVE_QUIET_TIME cpu_to_le16(10) /* msec */
|
||||
#define IWL_PLCP_QUIET_THRESH cpu_to_le16(1) /* packets */
|
||||
|
||||
#define IWL_SCAN_CHECK_WATCHDOG (HZ * 7)
|
||||
|
||||
|
||||
/* bt coex */
|
||||
void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
|
||||
@ -207,6 +277,12 @@ void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
|
||||
void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
|
||||
void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
|
||||
|
||||
static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
|
||||
{
|
||||
return cfg(priv)->bt_params &&
|
||||
cfg(priv)->bt_params->advanced_bt_coexist;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
const char *iwl_get_tx_fail_reason(u32 status);
|
||||
const char *iwl_get_agg_tx_fail_reason(u16 status);
|
||||
@ -245,8 +321,6 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
|
||||
u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
|
||||
|
||||
void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
u8 sta_id, struct iwl_link_quality_cmd *link_cmd);
|
||||
int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
struct iwl_link_quality_cmd *lq, u8 flags, bool init);
|
||||
int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
||||
@ -254,6 +328,9 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
||||
int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta *sta);
|
||||
|
||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta_ht_cap *ht_cap);
|
||||
|
||||
static inline int iwl_sta_id(struct ieee80211_sta *sta)
|
||||
{
|
||||
@ -311,9 +388,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
|
||||
return cpu_to_le32(flags|(u32)rate);
|
||||
}
|
||||
|
||||
/* eeprom */
|
||||
void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac);
|
||||
|
||||
extern int iwl_alive_start(struct iwl_priv *priv);
|
||||
/* svtool */
|
||||
#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
|
||||
@ -421,4 +495,95 @@ do { \
|
||||
} while (0)
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
|
||||
|
||||
static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
|
||||
{
|
||||
const char *s = iwl_dvm_cmd_strings[cmd];
|
||||
if (s)
|
||||
return s;
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/* API method exported for mvm hybrid state */
|
||||
void iwl_setup_deferred_work(struct iwl_priv *priv);
|
||||
int iwl_send_wimax_coex(struct iwl_priv *priv);
|
||||
int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
|
||||
void iwl_debug_config(struct iwl_priv *priv);
|
||||
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
|
||||
void iwl_set_hw_params(struct iwl_priv *priv);
|
||||
void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags);
|
||||
int iwl_init_drv(struct iwl_priv *priv);
|
||||
void iwl_uninit_drv(struct iwl_priv *priv);
|
||||
void iwl_send_bt_config(struct iwl_priv *priv);
|
||||
void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
||||
int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwl_teardown_interface(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
bool mode_change);
|
||||
int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf);
|
||||
void iwlagn_chain_noise_reset(struct iwl_priv *priv);
|
||||
int iwlagn_update_beacon(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_tt_handler(struct iwl_priv *priv);
|
||||
void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode);
|
||||
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue);
|
||||
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
|
||||
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
|
||||
void iwl_nic_error(struct iwl_op_mode *op_mode);
|
||||
void iwl_cmd_queue_full(struct iwl_op_mode *op_mode);
|
||||
void iwl_nic_config(struct iwl_op_mode *op_mode);
|
||||
int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta, bool set);
|
||||
void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
|
||||
enum ieee80211_rssi_event rssi_event);
|
||||
int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw);
|
||||
int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
|
||||
void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
|
||||
void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue);
|
||||
void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ieee80211_sta_state old_state,
|
||||
enum ieee80211_sta_state new_state);
|
||||
int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta);
|
||||
void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast);
|
||||
int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *data);
|
||||
void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 iv32, u16 *phase1key);
|
||||
int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
void iwlagn_mac_stop(struct ieee80211_hw *hw);
|
||||
void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
|
||||
#endif /* __iwl_agn_h__ */
|
||||
|
@ -1918,7 +1918,7 @@ struct iwl_basic_bt_cmd {
|
||||
__le16 valid;
|
||||
};
|
||||
|
||||
struct iwl6000_bt_cmd {
|
||||
struct iwl_bt_cmd_v1 {
|
||||
struct iwl_basic_bt_cmd basic;
|
||||
u8 prio_boost;
|
||||
/*
|
||||
@ -1929,7 +1929,7 @@ struct iwl6000_bt_cmd {
|
||||
__le16 rx_prio_boost; /* SW boost of WiFi rx priority */
|
||||
};
|
||||
|
||||
struct iwl2000_bt_cmd {
|
||||
struct iwl_bt_cmd_v2 {
|
||||
struct iwl_basic_bt_cmd basic;
|
||||
__le32 prio_boost;
|
||||
/*
|
||||
|
227
drivers/net/wireless/iwlwifi/iwl-config.h
Normal file
227
drivers/net/wireless/iwlwifi/iwl-config.h
Normal file
@ -0,0 +1,227 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef __IWL_CONFIG_H__
|
||||
#define __IWL_CONFIG_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
|
||||
enum iwl_device_family {
|
||||
IWL_DEVICE_FAMILY_UNDEFINED,
|
||||
IWL_DEVICE_FAMILY_1000,
|
||||
IWL_DEVICE_FAMILY_100,
|
||||
IWL_DEVICE_FAMILY_2000,
|
||||
IWL_DEVICE_FAMILY_2030,
|
||||
IWL_DEVICE_FAMILY_105,
|
||||
IWL_DEVICE_FAMILY_135,
|
||||
IWL_DEVICE_FAMILY_5000,
|
||||
IWL_DEVICE_FAMILY_5150,
|
||||
IWL_DEVICE_FAMILY_6000,
|
||||
IWL_DEVICE_FAMILY_6000i,
|
||||
IWL_DEVICE_FAMILY_6005,
|
||||
IWL_DEVICE_FAMILY_6030,
|
||||
IWL_DEVICE_FAMILY_6050,
|
||||
IWL_DEVICE_FAMILY_6150,
|
||||
};
|
||||
|
||||
/*
|
||||
* LED mode
|
||||
* IWL_LED_DEFAULT: use device default
|
||||
* IWL_LED_RF_STATE: turn LED on/off based on RF state
|
||||
* LED ON = RF ON
|
||||
* LED OFF = RF OFF
|
||||
* IWL_LED_BLINK: adjust led blink rate based on blink table
|
||||
* IWL_LED_DISABLE: led disabled
|
||||
*/
|
||||
enum iwl_led_mode {
|
||||
IWL_LED_DEFAULT,
|
||||
IWL_LED_RF_STATE,
|
||||
IWL_LED_BLINK,
|
||||
IWL_LED_DISABLE,
|
||||
};
|
||||
|
||||
/*
|
||||
* @max_ll_items: max number of OTP blocks
|
||||
* @shadow_ram_support: shadow support for OTP memory
|
||||
* @led_compensation: compensate on the led on/off time per HW according
|
||||
* to the deviation to achieve the desired led frequency.
|
||||
* The detail algorithm is described in iwl-led.c
|
||||
* @chain_noise_num_beacons: number of beacons used to compute chain noise
|
||||
* @adv_thermal_throttle: support advance thermal throttle
|
||||
* @support_ct_kill_exit: support ct kill exit condition
|
||||
* @plcp_delta_threshold: plcp error rate threshold used to trigger
|
||||
* radio tuning when there is a high receiving plcp error rate
|
||||
* @chain_noise_scale: default chain noise scale used for gain computation
|
||||
* @wd_timeout: TX queues watchdog timeout
|
||||
* @max_event_log_size: size of event log buffer size for ucode event logging
|
||||
* @shadow_reg_enable: HW shadhow register bit
|
||||
* @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
|
||||
* @no_idle_support: do not support idle mode
|
||||
*/
|
||||
struct iwl_base_params {
|
||||
int eeprom_size;
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
/* for iwl_apm_init() */
|
||||
u32 pll_cfg_val;
|
||||
|
||||
const u16 max_ll_items;
|
||||
const bool shadow_ram_support;
|
||||
u16 led_compensation;
|
||||
bool adv_thermal_throttle;
|
||||
bool support_ct_kill_exit;
|
||||
u8 plcp_delta_threshold;
|
||||
s32 chain_noise_scale;
|
||||
unsigned int wd_timeout;
|
||||
u32 max_event_log_size;
|
||||
const bool shadow_reg_enable;
|
||||
const bool hd_v2;
|
||||
const bool no_idle_support;
|
||||
};
|
||||
|
||||
/*
|
||||
* @advanced_bt_coexist: support advanced bt coexist
|
||||
* @bt_init_traffic_load: specify initial bt traffic load
|
||||
* @bt_prio_boost: default bt priority boost value
|
||||
* @agg_time_limit: maximum number of uSec in aggregation
|
||||
* @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
|
||||
*/
|
||||
struct iwl_bt_params {
|
||||
bool advanced_bt_coexist;
|
||||
u8 bt_init_traffic_load;
|
||||
u8 bt_prio_boost;
|
||||
u16 agg_time_limit;
|
||||
bool bt_sco_disable;
|
||||
bool bt_session_2;
|
||||
};
|
||||
/*
|
||||
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
|
||||
*/
|
||||
struct iwl_ht_params {
|
||||
const bool ht_greenfield_support; /* if used set to true */
|
||||
bool use_rts_for_aggregation;
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_cfg
|
||||
* @name: Offical name of the device
|
||||
* @fw_name_pre: Firmware filename prefix. The api version and extension
|
||||
* (.ucode) will be added to filename before loading from disk. The
|
||||
* filename is constructed as fw_name_pre<api>.ucode.
|
||||
* @ucode_api_max: Highest version of uCode API supported by driver.
|
||||
* @ucode_api_ok: oldest version of the uCode API that is OK to load
|
||||
* without a warning, for use in transitions
|
||||
* @ucode_api_min: Lowest version of uCode API supported by driver.
|
||||
* @max_inst_size: The maximal length of the fw inst section
|
||||
* @max_data_size: The maximal length of the fw data section
|
||||
* @valid_tx_ant: valid transmit antenna
|
||||
* @valid_rx_ant: valid receive antenna
|
||||
* @eeprom_ver: EEPROM version
|
||||
* @eeprom_calib_ver: EEPROM calibration version
|
||||
* @lib: pointer to the lib ops
|
||||
* @base_params: pointer to basic parameters
|
||||
* @ht_params: point to ht patameters
|
||||
* @bt_params: pointer to bt parameters
|
||||
* @need_temp_offset_calib: need to perform temperature offset calibration
|
||||
* @no_xtal_calib: some devices do not need crystal calibration data,
|
||||
* don't send it to those
|
||||
* @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off)
|
||||
* @adv_pm: advance power management
|
||||
* @rx_with_siso_diversity: 1x1 device with rx antenna diversity
|
||||
* @internal_wimax_coex: internal wifi/wimax combo device
|
||||
* @temp_offset_v2: support v2 of temperature offset calibration
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt. hardware features.
|
||||
* API differences in uCode shouldn't be handled here but through TLVs
|
||||
* and/or the uCode API version instead.
|
||||
*/
|
||||
struct iwl_cfg {
|
||||
/* params specific to an individual device within a device family */
|
||||
const char *name;
|
||||
const char *fw_name_pre;
|
||||
const unsigned int ucode_api_max;
|
||||
const unsigned int ucode_api_ok;
|
||||
const unsigned int ucode_api_min;
|
||||
const enum iwl_device_family device_family;
|
||||
const u32 max_data_size;
|
||||
const u32 max_inst_size;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u16 eeprom_ver;
|
||||
u16 eeprom_calib_ver;
|
||||
/* params not likely to change within a device family */
|
||||
const struct iwl_base_params *base_params;
|
||||
/* params likely to change within a device family */
|
||||
const struct iwl_ht_params *ht_params;
|
||||
const struct iwl_bt_params *bt_params;
|
||||
const bool need_temp_offset_calib; /* if used set to true */
|
||||
const bool no_xtal_calib;
|
||||
enum iwl_led_mode led_mode;
|
||||
const bool adv_pm;
|
||||
const bool rx_with_siso_diversity;
|
||||
const bool internal_wimax_coex;
|
||||
const bool temp_offset_v2;
|
||||
};
|
||||
|
||||
#endif /* __IWL_CONFIG_H__ */
|
@ -41,477 +41,6 @@
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
|
||||
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
static bool iwl_is_channel_extension(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u16 channel, u8 extension_chan_offset)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||
if (!is_channel_valid(ch_info))
|
||||
return false;
|
||||
|
||||
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta_ht_cap *ht_cap)
|
||||
{
|
||||
if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
|
||||
* the bit will not set if it is pure 40MHz case
|
||||
*/
|
||||
if (ht_cap && !ht_cap->ht_supported)
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (priv->disable_ht40)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return iwl_is_channel_extension(priv, priv->band,
|
||||
le16_to_cpu(ctx->staging.channel),
|
||||
ctx->ht.extension_chan_offset);
|
||||
}
|
||||
|
||||
static void _iwl_set_rxon_ht(struct iwl_priv *priv,
|
||||
struct iwl_ht_config *ht_conf,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
struct iwl_rxon_cmd *rxon = &ctx->staging;
|
||||
|
||||
if (!ctx->ht.enabled) {
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
|
||||
RXON_FLG_HT40_PROT_MSK |
|
||||
RXON_FLG_HT_PROT_MSK);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: if the definition of ht.protection changed, the "translation"
|
||||
* will be needed for rxon->flags
|
||||
*/
|
||||
rxon->flags |= cpu_to_le32(ctx->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS);
|
||||
|
||||
/* Set up channel bandwidth:
|
||||
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
|
||||
/* clear the HT channel mode before set the mode */
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
|
||||
if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
|
||||
/* pure ht40 */
|
||||
if (ctx->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
|
||||
/* Note: control channel is opposite of extension channel */
|
||||
switch (ctx->ht.extension_chan_offset) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
|
||||
break;
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
||||
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Note: control channel is opposite of extension channel */
|
||||
switch (ctx->ht.extension_chan_offset) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
|
||||
break;
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
||||
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
|
||||
break;
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
|
||||
default:
|
||||
/* channel location only valid if in Mixed mode */
|
||||
IWL_ERR(priv, "invalid extension channel offset\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
|
||||
}
|
||||
|
||||
iwlagn_set_rxon_chain(priv, ctx);
|
||||
|
||||
IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
|
||||
"extension channel offset 0x%x\n",
|
||||
le32_to_cpu(rxon->flags), ctx->ht.protection,
|
||||
ctx->ht.extension_chan_offset);
|
||||
}
|
||||
|
||||
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
|
||||
{
|
||||
struct iwl_rxon_context *ctx;
|
||||
|
||||
for_each_context(priv, ctx)
|
||||
_iwl_set_rxon_ht(priv, ht_conf, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_set_rxon_channel - Set the band and channel values in staging RXON
|
||||
* @ch: requested channel as a pointer to struct ieee80211_channel
|
||||
|
||||
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
|
||||
* in the staging RXON flag structure based on the ch->band
|
||||
*/
|
||||
void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
enum ieee80211_band band = ch->band;
|
||||
u16 channel = ch->hw_value;
|
||||
|
||||
if ((le16_to_cpu(ctx->staging.channel) == channel) &&
|
||||
(priv->band == band))
|
||||
return;
|
||||
|
||||
ctx->staging.channel = cpu_to_le16(channel);
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
|
||||
else
|
||||
ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
|
||||
|
||||
priv->band = band;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
|
||||
|
||||
}
|
||||
|
||||
void iwl_set_flags_for_band(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
if (band == IEEE80211_BAND_5GHZ) {
|
||||
ctx->staging.flags &=
|
||||
~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
|
||||
| RXON_FLG_CCK_MSK);
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
} else {
|
||||
/* Copied from iwl_post_associate() */
|
||||
if (vif && vif->bss_conf.use_short_slot)
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
else
|
||||
ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
|
||||
|
||||
ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
|
||||
ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
|
||||
ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize rxon structure with default values from eeprom
|
||||
*/
|
||||
void iwl_connection_init_rx_config(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
||||
memset(&ctx->staging, 0, sizeof(ctx->staging));
|
||||
|
||||
if (!ctx->vif) {
|
||||
ctx->staging.dev_type = ctx->unused_devtype;
|
||||
} else switch (ctx->vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
ctx->staging.dev_type = ctx->ap_devtype;
|
||||
break;
|
||||
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ctx->staging.dev_type = ctx->station_devtype;
|
||||
ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
|
||||
break;
|
||||
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ctx->staging.dev_type = ctx->ibss_devtype;
|
||||
ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
|
||||
RXON_FILTER_ACCEPT_GRP_MSK;
|
||||
break;
|
||||
|
||||
default:
|
||||
IWL_ERR(priv, "Unsupported interface type %d\n",
|
||||
ctx->vif->type);
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* TODO: Figure out when short_preamble would be set and cache from
|
||||
* that */
|
||||
if (!hw_to_local(priv->hw)->short_preamble)
|
||||
ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
else
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
#endif
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, priv->band,
|
||||
le16_to_cpu(ctx->active.channel));
|
||||
|
||||
if (!ch_info)
|
||||
ch_info = &priv->channel_info[0];
|
||||
|
||||
ctx->staging.channel = cpu_to_le16(ch_info->channel);
|
||||
priv->band = ch_info->band;
|
||||
|
||||
iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
|
||||
|
||||
ctx->staging.ofdm_basic_rates =
|
||||
(IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
|
||||
ctx->staging.cck_basic_rates =
|
||||
(IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
|
||||
|
||||
/* clear both MIX and PURE40 mode flag */
|
||||
ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
|
||||
RXON_FLG_CHANNEL_MODE_PURE_40);
|
||||
if (ctx->vif)
|
||||
memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
|
||||
|
||||
ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
|
||||
ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
|
||||
ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
|
||||
}
|
||||
|
||||
void iwl_set_rate(struct iwl_priv *priv)
|
||||
{
|
||||
const struct ieee80211_supported_band *hw = NULL;
|
||||
struct ieee80211_rate *rate;
|
||||
struct iwl_rxon_context *ctx;
|
||||
int i;
|
||||
|
||||
hw = iwl_get_hw_mode(priv, priv->band);
|
||||
if (!hw) {
|
||||
IWL_ERR(priv, "Failed to set rate: unable to get hw mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
priv->active_rate = 0;
|
||||
|
||||
for (i = 0; i < hw->n_bitrates; i++) {
|
||||
rate = &(hw->bitrates[i]);
|
||||
if (rate->hw_value < IWL_RATE_COUNT_LEGACY)
|
||||
priv->active_rate |= (1 << rate->hw_value);
|
||||
}
|
||||
|
||||
IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate);
|
||||
|
||||
for_each_context(priv, ctx) {
|
||||
ctx->staging.cck_basic_rates =
|
||||
(IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
|
||||
|
||||
ctx->staging.ofdm_basic_rates =
|
||||
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
|
||||
{
|
||||
/*
|
||||
* MULTI-FIXME
|
||||
* See iwlagn_mac_channel_switch.
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
|
||||
ieee80211_chswitch_done(ctx->vif, is_success);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
void iwl_print_rx_config_cmd(struct iwl_priv *priv,
|
||||
enum iwl_rxon_context_id ctxid)
|
||||
{
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
|
||||
struct iwl_rxon_cmd *rxon = &ctx->staging;
|
||||
|
||||
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
|
||||
iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
|
||||
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
|
||||
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
|
||||
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
|
||||
le32_to_cpu(rxon->filter_flags));
|
||||
IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
|
||||
IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
|
||||
rxon->ofdm_basic_rates);
|
||||
IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
|
||||
IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
|
||||
IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
|
||||
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
|
||||
{
|
||||
unsigned int reload_msec;
|
||||
unsigned long reload_jiffies;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
|
||||
iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
|
||||
#endif
|
||||
|
||||
/* uCode is no longer loaded. */
|
||||
priv->ucode_loaded = false;
|
||||
|
||||
/* Set the FW error flag -- cleared on iwl_down */
|
||||
set_bit(STATUS_FW_ERROR, &priv->status);
|
||||
|
||||
/* Cancel currently queued command. */
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
|
||||
|
||||
iwl_abort_notification_waits(&priv->notif_wait);
|
||||
|
||||
/* Keep the restart process from trying to send host
|
||||
* commands by clearing the ready bit */
|
||||
clear_bit(STATUS_READY, &priv->status);
|
||||
|
||||
wake_up(&trans(priv)->wait_command_queue);
|
||||
|
||||
if (!ondemand) {
|
||||
/*
|
||||
* If firmware keep reloading, then it indicate something
|
||||
* serious wrong and firmware having problem to recover
|
||||
* from it. Instead of keep trying which will fill the syslog
|
||||
* and hang the system, let's just stop it
|
||||
*/
|
||||
reload_jiffies = jiffies;
|
||||
reload_msec = jiffies_to_msecs((long) reload_jiffies -
|
||||
(long) priv->reload_jiffies);
|
||||
priv->reload_jiffies = reload_jiffies;
|
||||
if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
|
||||
priv->reload_count++;
|
||||
if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
|
||||
IWL_ERR(priv, "BUG_ON, Stop restarting\n");
|
||||
return;
|
||||
}
|
||||
} else
|
||||
priv->reload_count = 0;
|
||||
}
|
||||
|
||||
if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
if (iwlagn_mod_params.restart_fw) {
|
||||
IWL_DEBUG_FW_ERRORS(priv,
|
||||
"Restarting adapter due to uCode error.\n");
|
||||
queue_work(priv->workqueue, &priv->restart);
|
||||
} else
|
||||
IWL_DEBUG_FW_ERRORS(priv,
|
||||
"Detected FW error, but not restarting\n");
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
||||
{
|
||||
int ret;
|
||||
s8 prev_tx_power;
|
||||
bool defer;
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (priv->tx_power_user_lmt == tx_power && !force)
|
||||
return 0;
|
||||
|
||||
if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
|
||||
IWL_WARN(priv,
|
||||
"Requested user TXPOWER %d below lower limit %d.\n",
|
||||
tx_power,
|
||||
IWLAGN_TX_POWER_TARGET_POWER_MIN);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tx_power > priv->tx_power_device_lmt) {
|
||||
IWL_WARN(priv,
|
||||
"Requested user TXPOWER %d above upper limit %d.\n",
|
||||
tx_power, priv->tx_power_device_lmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!iwl_is_ready_rf(priv))
|
||||
return -EIO;
|
||||
|
||||
/* scan complete and commit_rxon use tx_power_next value,
|
||||
* it always need to be updated for newest request */
|
||||
priv->tx_power_next = tx_power;
|
||||
|
||||
/* do not set tx power when scanning or channel changing */
|
||||
defer = test_bit(STATUS_SCANNING, &priv->status) ||
|
||||
memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
|
||||
if (defer && !force) {
|
||||
IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev_tx_power = priv->tx_power_user_lmt;
|
||||
priv->tx_power_user_lmt = tx_power;
|
||||
|
||||
ret = iwlagn_send_tx_power(priv);
|
||||
|
||||
/* if fail to set tx_power, restore the orig. tx power */
|
||||
if (ret) {
|
||||
priv->tx_power_user_lmt = prev_tx_power;
|
||||
priv->tx_power_next = prev_tx_power;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_send_bt_config(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_bt_cmd bt_cmd = {
|
||||
.lead_time = BT_LEAD_TIME_DEF,
|
||||
.max_kill = BT_MAX_KILL_DEF,
|
||||
.kill_ack_mask = 0,
|
||||
.kill_cts_mask = 0,
|
||||
};
|
||||
|
||||
if (!iwlagn_mod_params.bt_coex_active)
|
||||
bt_cmd.flags = BT_COEX_DISABLE;
|
||||
else
|
||||
bt_cmd.flags = BT_COEX_ENABLE;
|
||||
|
||||
priv->bt_enable_flag = bt_cmd.flags;
|
||||
IWL_DEBUG_INFO(priv, "BT coex %s\n",
|
||||
(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
|
||||
|
||||
if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
|
||||
CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
|
||||
IWL_ERR(priv, "failed to send BT Coex Config\n");
|
||||
}
|
||||
|
||||
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
|
||||
{
|
||||
struct iwl_statistics_cmd statistics_cmd = {
|
||||
.configuration_flags =
|
||||
clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
|
||||
};
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
|
||||
CMD_ASYNC,
|
||||
sizeof(struct iwl_statistics_cmd),
|
||||
&statistics_cmd);
|
||||
else
|
||||
return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
|
||||
CMD_SYNC,
|
||||
sizeof(struct iwl_statistics_cmd),
|
||||
&statistics_cmd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
@ -611,6 +140,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
||||
|
||||
const char *get_mgmt_string(int cmd)
|
||||
{
|
||||
#define IWL_CMD(x) case x: return #x
|
||||
switch (cmd) {
|
||||
IWL_CMD(MANAGEMENT_ASSOC_REQ);
|
||||
IWL_CMD(MANAGEMENT_ASSOC_RESP);
|
||||
@ -628,10 +158,12 @@ const char *get_mgmt_string(int cmd)
|
||||
return "UNKNOWN";
|
||||
|
||||
}
|
||||
#undef IWL_CMD
|
||||
}
|
||||
|
||||
const char *get_ctrl_string(int cmd)
|
||||
{
|
||||
#define IWL_CMD(x) case x: return #x
|
||||
switch (cmd) {
|
||||
IWL_CMD(CONTROL_BACK_REQ);
|
||||
IWL_CMD(CONTROL_BACK);
|
||||
@ -645,6 +177,7 @@ const char *get_ctrl_string(int cmd)
|
||||
return "UNKNOWN";
|
||||
|
||||
}
|
||||
#undef IWL_CMD
|
||||
}
|
||||
|
||||
void iwl_clear_traffic_stats(struct iwl_priv *priv)
|
||||
@ -746,80 +279,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void iwl_force_rf_reset(struct iwl_priv *priv)
|
||||
{
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (!iwl_is_any_associated(priv)) {
|
||||
IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* There is no easy and better way to force reset the radio,
|
||||
* the only known method is switching channel which will force to
|
||||
* reset and tune the radio.
|
||||
* Use internal short scan (single channel) operation to should
|
||||
* achieve this objective.
|
||||
* Driver should reset the radio when number of consecutive missed
|
||||
* beacon, or any other uCode error condition detected.
|
||||
*/
|
||||
IWL_DEBUG_INFO(priv, "perform radio reset.\n");
|
||||
iwl_internal_short_hw_scan(priv);
|
||||
}
|
||||
|
||||
|
||||
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
|
||||
{
|
||||
struct iwl_force_reset *force_reset;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EINVAL;
|
||||
|
||||
if (mode >= IWL_MAX_FORCE_RESET) {
|
||||
IWL_DEBUG_INFO(priv, "invalid reset request.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
force_reset = &priv->force_reset[mode];
|
||||
force_reset->reset_request_count++;
|
||||
if (!external) {
|
||||
if (force_reset->last_force_reset_jiffies &&
|
||||
time_after(force_reset->last_force_reset_jiffies +
|
||||
force_reset->reset_duration, jiffies)) {
|
||||
IWL_DEBUG_INFO(priv, "force reset rejected\n");
|
||||
force_reset->reset_reject_count++;
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
force_reset->reset_success_count++;
|
||||
force_reset->last_force_reset_jiffies = jiffies;
|
||||
IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
|
||||
switch (mode) {
|
||||
case IWL_RF_RESET:
|
||||
iwl_force_rf_reset(priv);
|
||||
break;
|
||||
case IWL_FW_RESET:
|
||||
/*
|
||||
* if the request is from external(ex: debugfs),
|
||||
* then always perform the request in regardless the module
|
||||
* parameter setting
|
||||
* if the request is from internal (uCode error or driver
|
||||
* detect failure), then fw_restart module parameter
|
||||
* need to be check before performing firmware reload
|
||||
*/
|
||||
if (!external && !iwlagn_mod_params.restart_fw) {
|
||||
IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
|
||||
"module parameter setting\n");
|
||||
break;
|
||||
}
|
||||
IWL_ERR(priv, "On demand firmware reload\n");
|
||||
iwlagn_fw_error(priv, true);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int iwl_cmd_echo_test(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
@ -836,165 +295,3 @@ int iwl_cmd_echo_test(struct iwl_priv *priv)
|
||||
IWL_DEBUG_INFO(priv, "echo testing pass\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq)
|
||||
{
|
||||
if (iwl_trans_check_stuck_queue(trans(priv), txq)) {
|
||||
int ret;
|
||||
ret = iwl_force_reset(priv, IWL_FW_RESET, false);
|
||||
return (ret == -EAGAIN) ? 0 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Making watchdog tick be a quarter of timeout assure we will
|
||||
* discover the queue hung between timeout and 1.25*timeout
|
||||
*/
|
||||
#define IWL_WD_TICK(timeout) ((timeout) / 4)
|
||||
|
||||
/*
|
||||
* Watchdog timer callback, we check each tx queue for stuck, if if hung
|
||||
* we reset the firmware. If everything is fine just rearm the timer.
|
||||
*/
|
||||
void iwl_bg_watchdog(unsigned long data)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)data;
|
||||
int cnt;
|
||||
unsigned long timeout;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (iwl_is_rfkill(priv))
|
||||
return;
|
||||
|
||||
timeout = hw_params(priv).wd_timeout;
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
/* monitor and check for stuck queues */
|
||||
for (cnt = 0; cnt < cfg(priv)->base_params->num_of_queues; cnt++)
|
||||
if (iwl_check_stuck_queue(priv, cnt))
|
||||
return;
|
||||
|
||||
mod_timer(&priv->watchdog, jiffies +
|
||||
msecs_to_jiffies(IWL_WD_TICK(timeout)));
|
||||
}
|
||||
|
||||
void iwl_setup_watchdog(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned int timeout = hw_params(priv).wd_timeout;
|
||||
|
||||
if (!iwlagn_mod_params.wd_disable) {
|
||||
/* use system default */
|
||||
if (timeout && !cfg(priv)->base_params->wd_disable)
|
||||
mod_timer(&priv->watchdog,
|
||||
jiffies +
|
||||
msecs_to_jiffies(IWL_WD_TICK(timeout)));
|
||||
else
|
||||
del_timer(&priv->watchdog);
|
||||
} else {
|
||||
/* module parameter overwrite default configuration */
|
||||
if (timeout && iwlagn_mod_params.wd_disable == 2)
|
||||
mod_timer(&priv->watchdog,
|
||||
jiffies +
|
||||
msecs_to_jiffies(IWL_WD_TICK(timeout)));
|
||||
else
|
||||
del_timer(&priv->watchdog);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
|
||||
* @priv -- pointer to iwl_priv data structure
|
||||
* @tsf_bits -- number of bits need to shift for masking)
|
||||
*/
|
||||
static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
{
|
||||
return (1 << tsf_bits) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
|
||||
* @priv -- pointer to iwl_priv data structure
|
||||
* @tsf_bits -- number of bits need to shift for masking)
|
||||
*/
|
||||
static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
{
|
||||
return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* extended beacon time format
|
||||
* time in usec will be changed into a 32-bit value in extended:internal format
|
||||
* the extended part is the beacon counts
|
||||
* the internal part is the time in usec within one beacon interval
|
||||
*/
|
||||
u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
|
||||
{
|
||||
u32 quot;
|
||||
u32 rem;
|
||||
u32 interval = beacon_interval * TIME_UNIT;
|
||||
|
||||
if (!interval || !usec)
|
||||
return 0;
|
||||
|
||||
quot = (usec / interval) &
|
||||
(iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
|
||||
return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
|
||||
}
|
||||
|
||||
/* base is usually what we get from ucode with each received frame,
|
||||
* the same as HW timer counter counting down
|
||||
*/
|
||||
__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
|
||||
u32 addon, u32 beacon_interval)
|
||||
{
|
||||
u32 base_low = base & iwl_beacon_time_mask_low(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS);
|
||||
u32 interval = beacon_interval * TIME_UNIT;
|
||||
u32 res = (base & iwl_beacon_time_mask_high(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS)) +
|
||||
(addon & iwl_beacon_time_mask_high(priv,
|
||||
IWLAGN_EXT_BEACON_TIME_POS));
|
||||
|
||||
if (base_low > addon_low)
|
||||
res += base_low - addon_low;
|
||||
else if (base_low < addon_low) {
|
||||
res += interval + base_low - addon_low;
|
||||
res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
|
||||
} else
|
||||
res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
|
||||
|
||||
return cpu_to_le32(res);
|
||||
}
|
||||
|
||||
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
if (state)
|
||||
set_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
else
|
||||
clear_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
|
||||
wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
|
||||
}
|
||||
|
||||
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
@ -74,38 +74,10 @@ struct iwl_cmd;
|
||||
|
||||
#define TIME_UNIT 1024
|
||||
|
||||
struct iwl_lib_ops {
|
||||
/* set hw dependent parameters */
|
||||
void (*set_hw_params)(struct iwl_priv *priv);
|
||||
int (*set_channel_switch)(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
/* device specific configuration */
|
||||
void (*nic_config)(struct iwl_priv *priv);
|
||||
|
||||
/* eeprom operations (as defined in iwl-eeprom.h) */
|
||||
struct iwl_eeprom_ops eeprom_ops;
|
||||
|
||||
/* temperature */
|
||||
void (*temperature)(struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
/***************************
|
||||
* L i b *
|
||||
***************************/
|
||||
|
||||
void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_set_flags_for_band(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
|
||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta_ht_cap *ht_cap);
|
||||
void iwl_connection_init_rx_config(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_set_rate(struct iwl_priv *priv);
|
||||
int iwl_cmd_echo_test(struct iwl_priv *priv);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
|
||||
@ -146,45 +118,9 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************
|
||||
* RX
|
||||
******************************************************/
|
||||
void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
|
||||
|
||||
void iwl_setup_watchdog(struct iwl_priv *priv);
|
||||
/*****************************************************
|
||||
* TX power
|
||||
****************************************************/
|
||||
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
|
||||
|
||||
/*******************************************************************************
|
||||
* Scanning
|
||||
******************************************************************************/
|
||||
void iwl_init_scan_params(struct iwl_priv *priv);
|
||||
int iwl_scan_cancel(struct iwl_priv *priv);
|
||||
void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
|
||||
void iwl_force_scan_end(struct iwl_priv *priv);
|
||||
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
|
||||
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
|
||||
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
|
||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
|
||||
void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
|
||||
int __must_check iwl_scan_initiate(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
enum iwl_scan_type scan_type,
|
||||
enum ieee80211_band band);
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
* ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
|
||||
* time if it's a quiet channel (nothing responded to our probe, and there's
|
||||
* no other traffic).
|
||||
* Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
|
||||
#define IWL_ACTIVE_QUIET_TIME cpu_to_le16(10) /* msec */
|
||||
#define IWL_PLCP_QUIET_THRESH cpu_to_le16(1) /* packets */
|
||||
|
||||
#define IWL_SCAN_CHECK_WATCHDOG (HZ * 7)
|
||||
|
||||
/* traffic log definitions */
|
||||
#define IWL_TRAFFIC_ENTRIES (256)
|
||||
#define IWL_TRAFFIC_ENTRY_SIZE (64)
|
||||
@ -192,28 +128,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
|
||||
/*****************************************************
|
||||
* S e n d i n g H o s t C o m m a n d s *
|
||||
*****************************************************/
|
||||
|
||||
void iwl_bg_watchdog(unsigned long data);
|
||||
u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
|
||||
__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
|
||||
u32 addon, u32 beacon_interval);
|
||||
|
||||
extern void iwl_send_bt_config(struct iwl_priv *priv);
|
||||
extern int iwl_send_statistics_request(struct iwl_priv *priv,
|
||||
u8 flags, bool clear);
|
||||
|
||||
static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
|
||||
struct iwl_priv *priv, enum ieee80211_band band)
|
||||
{
|
||||
return priv->hw->wiphy->bands[band];
|
||||
}
|
||||
|
||||
static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
|
||||
{
|
||||
return cfg(priv)->bt_params &&
|
||||
cfg(priv)->bt_params->advanced_bt_coexist;
|
||||
}
|
||||
|
||||
extern bool bt_siso_mode;
|
||||
|
||||
#endif /* __iwl_core_h__ */
|
||||
|
@ -430,6 +430,9 @@
|
||||
#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
|
||||
#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
|
||||
|
||||
/* Used to enable DBGM */
|
||||
#define HBUS_TARG_TEST_REG (HBUS_BASE+0x05c)
|
||||
|
||||
/*
|
||||
* Per-Tx-queue write pointer (index, really!)
|
||||
* Indicates index to next TFD that driver will fill (1 past latest filled).
|
||||
|
@ -416,7 +416,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
ptr = priv->shrd->eeprom;
|
||||
ptr = priv->eeprom;
|
||||
if (!ptr) {
|
||||
IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
|
||||
return -ENOMEM;
|
||||
@ -428,10 +428,10 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
|
||||
IWL_ERR(priv, "Can not allocate Buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
eeprom_ver = iwl_eeprom_query16(priv->shrd, EEPROM_VERSION);
|
||||
eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
|
||||
pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
|
||||
"version: 0x%x\n",
|
||||
(trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
|
||||
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
|
||||
? "OTP" : "EEPROM", eeprom_ver);
|
||||
for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
|
||||
pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
|
||||
@ -526,8 +526,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
|
||||
test_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
|
||||
test_bit(STATUS_RF_KILL_HW, &priv->status));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
|
||||
@ -577,7 +575,7 @@ static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
|
||||
if (priv->rx_handlers_stats[cnt] > 0)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tRx handler[%36s]:\t\t %u\n",
|
||||
get_cmd_string(cnt),
|
||||
iwl_dvm_get_cmd_string(cnt),
|
||||
priv->rx_handlers_stats[cnt]);
|
||||
}
|
||||
|
||||
@ -1541,17 +1539,17 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
|
||||
if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"tx power: (1/2 dB step)\n");
|
||||
if ((hw_params(priv).valid_tx_ant & ANT_A) &&
|
||||
if ((priv->hw_params.valid_tx_ant & ANT_A) &&
|
||||
tx->tx_power.ant_a)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_hex, "antenna A:",
|
||||
tx->tx_power.ant_a);
|
||||
if ((hw_params(priv).valid_tx_ant & ANT_B) &&
|
||||
if ((priv->hw_params.valid_tx_ant & ANT_B) &&
|
||||
tx->tx_power.ant_b)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_hex, "antenna B:",
|
||||
tx->tx_power.ant_b);
|
||||
if ((hw_params(priv).valid_tx_ant & ANT_C) &&
|
||||
if ((priv->hw_params.valid_tx_ant & ANT_C) &&
|
||||
tx->tx_power.ant_c)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_hex, "antenna C:",
|
||||
@ -2267,59 +2265,39 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t iwl_dbgfs_rf_reset_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int i, pos = 0;
|
||||
int pos = 0;
|
||||
char buf[300];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
struct iwl_force_reset *force_reset;
|
||||
struct iwl_rf_reset *rf_reset = &priv->rf_reset;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"RF reset statistics\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tnumber of reset request: %d\n",
|
||||
rf_reset->reset_request_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tnumber of reset request success: %d\n",
|
||||
rf_reset->reset_success_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tnumber of reset request reject: %d\n",
|
||||
rf_reset->reset_reject_count);
|
||||
|
||||
for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
|
||||
force_reset = &priv->force_reset[i];
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Force reset method %d\n", i);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tnumber of reset request: %d\n",
|
||||
force_reset->reset_request_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tnumber of reset request success: %d\n",
|
||||
force_reset->reset_success_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tnumber of reset request reject: %d\n",
|
||||
force_reset->reset_reject_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\treset duration: %lu\n",
|
||||
force_reset->reset_duration);
|
||||
}
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
|
||||
static ssize_t iwl_dbgfs_rf_reset_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int reset, ret;
|
||||
int ret;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &reset) != 1)
|
||||
return -EINVAL;
|
||||
switch (reset) {
|
||||
case IWL_RF_RESET:
|
||||
case IWL_FW_RESET:
|
||||
ret = iwl_force_reset(priv, reset, true);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = iwl_force_rf_reset(priv, true);
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
@ -2347,29 +2325,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int timeout;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &timeout) != 1)
|
||||
return -EINVAL;
|
||||
if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
|
||||
timeout = IWL_DEF_WD_TIMEOUT;
|
||||
|
||||
hw_params(priv).wd_timeout = timeout;
|
||||
iwl_setup_watchdog(priv);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
@ -2428,7 +2383,7 @@ static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
|
||||
if (cfg(priv)->ht_params)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"use %s for aggregation\n",
|
||||
(hw_params(priv).use_rts_for_aggregation) ?
|
||||
(priv->hw_params.use_rts_for_aggregation) ?
|
||||
"rts/cts" : "cts-to-self");
|
||||
else
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "N/A");
|
||||
@ -2455,9 +2410,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
|
||||
if (sscanf(buf, "%d", &rts) != 1)
|
||||
return -EINVAL;
|
||||
if (rts)
|
||||
hw_params(priv).use_rts_for_aggregation = true;
|
||||
priv->hw_params.use_rts_for_aggregation = true;
|
||||
else
|
||||
hw_params(priv).use_rts_for_aggregation = false;
|
||||
priv->hw_params.use_rts_for_aggregation = false;
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -2516,6 +2471,34 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[120];
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Sensitivity calibrations %s\n",
|
||||
(priv->calib_disabled &
|
||||
IWL_SENSITIVITY_CALIB_DISABLED) ?
|
||||
"DISABLED" : "ENABLED");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Chain noise calibrations %s\n",
|
||||
(priv->calib_disabled &
|
||||
IWL_CHAIN_NOISE_CALIB_DISABLED) ?
|
||||
"DISABLED" : "ENABLED");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Tx power calibrations %s\n",
|
||||
(priv->calib_disabled &
|
||||
IWL_TX_POWER_CALIB_DISABLED) ?
|
||||
"DISABLED" : "ENABLED");
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
DEBUGFS_READ_FILE_OPS(rx_statistics);
|
||||
DEBUGFS_READ_FILE_OPS(tx_statistics);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
|
||||
@ -2530,17 +2513,17 @@ DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(rf_reset);
|
||||
DEBUGFS_READ_FILE_OPS(rxon_flags);
|
||||
DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
|
||||
DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
|
||||
DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
|
||||
DEBUGFS_WRITE_FILE_OPS(wd_timeout);
|
||||
DEBUGFS_READ_FILE_OPS(bt_traffic);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
|
||||
DEBUGFS_READ_FILE_OPS(reply_tx_error);
|
||||
DEBUGFS_WRITE_FILE_OPS(echo_test);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(log_event);
|
||||
DEBUGFS_READ_FILE_OPS(calib_disabled);
|
||||
|
||||
/*
|
||||
* Create the debugfs files and directories
|
||||
@ -2589,7 +2572,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
||||
DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
|
||||
@ -2602,17 +2585,14 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
||||
DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
|
||||
|
||||
if (iwl_advanced_bt_coexist(priv))
|
||||
DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
|
||||
|
||||
DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
|
||||
&priv->disable_sens_cal);
|
||||
DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
|
||||
&priv->disable_chain_noise_cal);
|
||||
/* Calibrations disabled/enabled status*/
|
||||
DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IRUSR);
|
||||
|
||||
if (iwl_trans_dbgfs_register(trans(priv), dir_debug))
|
||||
goto err;
|
||||
|
@ -51,8 +51,6 @@
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-notif-wait.h"
|
||||
|
||||
struct iwl_tx_queue;
|
||||
|
||||
/* CT-KILL constants */
|
||||
#define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */
|
||||
#define CT_KILL_THRESHOLD 114 /* in Celsius */
|
||||
@ -582,9 +580,9 @@ struct iwl_event_log {
|
||||
#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE (0)
|
||||
|
||||
#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
|
||||
#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
|
||||
|
||||
/* TX queue watchdog timeouts in mSecs */
|
||||
#define IWL_WATCHHDOG_DISABLED (0)
|
||||
#define IWL_DEF_WD_TIMEOUT (2000)
|
||||
#define IWL_LONG_WD_TIMEOUT (10000)
|
||||
#define IWL_MAX_WD_TIMEOUT (120000)
|
||||
@ -597,18 +595,11 @@ struct iwl_event_log {
|
||||
#define IWL_MAX_CONTINUE_RELOAD_CNT 4
|
||||
|
||||
|
||||
enum iwl_reset {
|
||||
IWL_RF_RESET = 0,
|
||||
IWL_FW_RESET,
|
||||
IWL_MAX_FORCE_RESET,
|
||||
};
|
||||
|
||||
struct iwl_force_reset {
|
||||
struct iwl_rf_reset {
|
||||
int reset_request_count;
|
||||
int reset_success_count;
|
||||
int reset_reject_count;
|
||||
unsigned long reset_duration;
|
||||
unsigned long last_force_reset_jiffies;
|
||||
unsigned long last_reset_jiffies;
|
||||
};
|
||||
|
||||
/* extend beacon time format bit shifting */
|
||||
@ -680,6 +671,52 @@ enum iwl_scan_type {
|
||||
IWL_SCAN_ROC,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_hw_params
|
||||
*
|
||||
* Holds the module parameters
|
||||
*
|
||||
* @tx_chains_num: Number of TX chains
|
||||
* @rx_chains_num: Number of RX chains
|
||||
* @valid_tx_ant: usable antennas for TX
|
||||
* @valid_rx_ant: usable antennas for RX
|
||||
* @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
|
||||
* @sku: sku read from EEPROM
|
||||
* @ct_kill_threshold: temperature threshold - in hw dependent unit
|
||||
* @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
|
||||
* relevant for 1000, 6000 and up
|
||||
* @struct iwl_sensitivity_ranges: range of sensitivity values
|
||||
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
|
||||
*/
|
||||
struct iwl_hw_params {
|
||||
u8 tx_chains_num;
|
||||
u8 rx_chains_num;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u8 ht40_channel;
|
||||
bool use_rts_for_aggregation;
|
||||
u16 sku;
|
||||
u32 ct_kill_threshold;
|
||||
u32 ct_kill_exit_threshold;
|
||||
|
||||
const struct iwl_sensitivity_ranges *sens;
|
||||
};
|
||||
|
||||
struct iwl_lib_ops {
|
||||
/* set hw dependent parameters */
|
||||
void (*set_hw_params)(struct iwl_priv *priv);
|
||||
int (*set_channel_switch)(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
/* device specific configuration */
|
||||
void (*nic_config)(struct iwl_priv *priv);
|
||||
|
||||
/* eeprom operations (as defined in iwl-eeprom.h) */
|
||||
struct iwl_eeprom_ops eeprom_ops;
|
||||
|
||||
/* temperature */
|
||||
void (*temperature)(struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
|
||||
struct iwl_testmode_trace {
|
||||
u32 buff_size;
|
||||
@ -704,6 +741,14 @@ struct iwl_wipan_noa_data {
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
/* Calibration disabling bit mask */
|
||||
#define IWL_SENSITIVITY_CALIB_DISABLED BIT(1)
|
||||
#define IWL_CHAIN_NOISE_CALIB_DISABLED BIT(2)
|
||||
#define IWL_TX_POWER_CALIB_DISABLED BIT(3)
|
||||
|
||||
#define IWL_CALIB_ENABLE_ALL 0
|
||||
#define IWL_CALIB_DISABLE_ALL 0xFFFFFFFF
|
||||
|
||||
#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
|
||||
((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
|
||||
|
||||
@ -716,6 +761,7 @@ struct iwl_priv {
|
||||
/*data shared among all the driver's layers */
|
||||
struct iwl_shared *shrd;
|
||||
const struct iwl_fw *fw;
|
||||
const struct iwl_lib_ops *lib;
|
||||
unsigned long status;
|
||||
|
||||
spinlock_t sta_lock;
|
||||
@ -738,6 +784,8 @@ struct iwl_priv {
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
|
||||
struct iwl_hw_params hw_params;
|
||||
|
||||
enum ieee80211_band band;
|
||||
u8 valid_contexts;
|
||||
|
||||
@ -772,8 +820,8 @@ struct iwl_priv {
|
||||
/*counters */
|
||||
u32 rx_handlers_stats[REPLY_MAX];
|
||||
|
||||
/* force reset */
|
||||
struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
|
||||
/* rf reset */
|
||||
struct iwl_rf_reset rf_reset;
|
||||
|
||||
/* firmware reload counter and timestamp */
|
||||
unsigned long reload_jiffies;
|
||||
@ -819,8 +867,6 @@ struct iwl_priv {
|
||||
|
||||
__le16 switch_channel;
|
||||
|
||||
u16 active_rate;
|
||||
|
||||
u8 start_calib;
|
||||
struct iwl_sensitivity_data sensitivity_data;
|
||||
struct iwl_chain_noise_data chain_noise_data;
|
||||
@ -967,13 +1013,15 @@ struct iwl_priv {
|
||||
void *wowlan_sram;
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
||||
/* eeprom -- this is in the card's little endian byte order */
|
||||
u8 *eeprom;
|
||||
enum iwl_nvm_type nvm_device_type;
|
||||
|
||||
struct work_struct txpower_work;
|
||||
u32 disable_sens_cal;
|
||||
u32 disable_chain_noise_cal;
|
||||
u32 calib_disabled;
|
||||
struct work_struct run_time_calib_work;
|
||||
struct timer_list statistics_periodic;
|
||||
struct timer_list ucode_trace;
|
||||
struct timer_list watchdog;
|
||||
|
||||
struct iwl_event_log event_log;
|
||||
|
||||
|
@ -284,6 +284,7 @@ static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces,
|
||||
|
||||
sec->offset = le32_to_cpu(sec_parse->offset);
|
||||
sec->data = sec_parse->data;
|
||||
sec->size = size - sizeof(sec_parse->offset);
|
||||
|
||||
++img->sec_counter;
|
||||
|
||||
@ -414,9 +415,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
struct iwl_ucode_tlv *tlv;
|
||||
size_t len = ucode_raw->size;
|
||||
const u8 *data;
|
||||
int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative;
|
||||
int tmp;
|
||||
u64 alternatives;
|
||||
u32 tlv_len;
|
||||
enum iwl_ucode_tlv_type tlv_type;
|
||||
const u8 *tlv_data;
|
||||
@ -434,23 +432,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check which alternatives are present, and "downgrade"
|
||||
* when the chosen alternative is not present, warning
|
||||
* the user when that happens. Some files may not have
|
||||
* any alternatives, so don't warn in that case.
|
||||
*/
|
||||
alternatives = le64_to_cpu(ucode->alternatives);
|
||||
tmp = wanted_alternative;
|
||||
if (wanted_alternative > 63)
|
||||
wanted_alternative = 63;
|
||||
while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
|
||||
wanted_alternative--;
|
||||
if (wanted_alternative && wanted_alternative != tmp)
|
||||
IWL_WARN(drv,
|
||||
"uCode alternative %d not available, choosing %d\n",
|
||||
tmp, wanted_alternative);
|
||||
|
||||
drv->fw.ucode_ver = le32_to_cpu(ucode->ver);
|
||||
build = le32_to_cpu(ucode->build);
|
||||
|
||||
@ -475,14 +456,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
len -= sizeof(*ucode);
|
||||
|
||||
while (len >= sizeof(*tlv)) {
|
||||
u16 tlv_alt;
|
||||
|
||||
len -= sizeof(*tlv);
|
||||
tlv = (void *)data;
|
||||
|
||||
tlv_len = le32_to_cpu(tlv->length);
|
||||
tlv_type = le16_to_cpu(tlv->type);
|
||||
tlv_alt = le16_to_cpu(tlv->alternative);
|
||||
tlv_type = le32_to_cpu(tlv->type);
|
||||
tlv_data = tlv->data;
|
||||
|
||||
if (len < tlv_len) {
|
||||
@ -493,14 +471,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
len -= ALIGN(tlv_len, 4);
|
||||
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
|
||||
|
||||
/*
|
||||
* Alternative 0 is always valid.
|
||||
*
|
||||
* Skip alternative TLVs that are not selected.
|
||||
*/
|
||||
if (tlv_alt != 0 && tlv_alt != wanted_alternative)
|
||||
continue;
|
||||
|
||||
switch (tlv_type) {
|
||||
case IWL_UCODE_TLV_INST:
|
||||
set_sec_data(pieces, IWL_UCODE_REGULAR,
|
||||
@ -837,42 +807,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
||||
|
||||
IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version);
|
||||
|
||||
/*
|
||||
* For any of the failures below (before allocating pci memory)
|
||||
* we will try to load a version with a smaller API -- maybe the
|
||||
* user just got a corrupted version of the latest API.
|
||||
*/
|
||||
|
||||
IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n",
|
||||
drv->fw.ucode_ver);
|
||||
IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n",
|
||||
get_sec_size(&pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_INST));
|
||||
IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n",
|
||||
get_sec_size(&pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_DATA));
|
||||
IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n",
|
||||
get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST));
|
||||
IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n",
|
||||
get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA));
|
||||
|
||||
/* Verify that uCode images will fit in card's SRAM */
|
||||
if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) >
|
||||
cfg->max_inst_size) {
|
||||
IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n",
|
||||
get_sec_size(&pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_INST));
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) >
|
||||
cfg->max_data_size) {
|
||||
IWL_ERR(drv, "uCode data len %Zd too large to fit in\n",
|
||||
get_sec_size(&pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_DATA));
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
/*
|
||||
* In mvm uCode there is no difference between data and instructions
|
||||
* sections.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user