mirror of https://gitee.com/openkylin/linux.git
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 5.4. Major changes: wil6210 * add support for Enhanced Directional Multi-Gigabit (EDMG) channels 9-11 * add debugfs file to show PCM ring content * report boottime_ns in scan results ath9k * add a separate loader for AR92XX (and older) pci(e) without eeprom, enabled with the new ATH9K_PCI_NO_EEPROM Kconfig option
This commit is contained in:
commit
f9e5687545
|
@ -2151,6 +2151,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
struct ath10k_peer *peer;
|
||||
struct htt_rx_indication_mpdu_range *mpdu_ranges;
|
||||
struct fw_rx_desc_hl *fw_desc;
|
||||
enum htt_txrx_sec_cast_type sec_index;
|
||||
enum htt_security_types sec_type;
|
||||
union htt_rx_pn_t new_pn = {0};
|
||||
struct htt_hl_rx_desc *rx_desc;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_rx_status *rx_status;
|
||||
u16 peer_id;
|
||||
|
@ -2158,9 +2162,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
int num_mpdu_ranges;
|
||||
size_t tot_hdr_len;
|
||||
struct ieee80211_channel *ch;
|
||||
bool pn_invalid;
|
||||
bool pn_invalid, qos, first_msdu;
|
||||
u32 tid, rx_desc_info;
|
||||
|
||||
peer_id = __le16_to_cpu(rx->hdr.peer_id);
|
||||
tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
|
@ -2168,6 +2174,9 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
if (!peer && peer_id != HTT_INVALID_PEERID)
|
||||
ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id);
|
||||
|
||||
if (!peer)
|
||||
return true;
|
||||
|
||||
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
|
||||
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
|
||||
mpdu_ranges = htt_rx_ind_get_mpdu_ranges_hl(rx);
|
||||
|
@ -2192,10 +2201,24 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (check_pn_type == HTT_RX_PN_CHECK) {
|
||||
rx_desc = (struct htt_hl_rx_desc *)&rx->mpdu_ranges[num_mpdu_ranges];
|
||||
rx_desc_info = __le32_to_cpu(rx_desc->info);
|
||||
|
||||
if (MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST))
|
||||
sec_index = HTT_TXRX_SEC_MCAST;
|
||||
else
|
||||
sec_index = HTT_TXRX_SEC_UCAST;
|
||||
|
||||
sec_type = peer->rx_pn[sec_index].sec_type;
|
||||
first_msdu = rx->fw_desc.flags & FW_RX_DESC_FLAGS_FIRST_MSDU;
|
||||
|
||||
ath10k_htt_rx_mpdu_desc_pn_hl(rx_desc, &new_pn, peer->rx_pn[sec_index].pn_len);
|
||||
|
||||
if (check_pn_type == HTT_RX_PN_CHECK && tid >= IEEE80211_NUM_TIDS) {
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
pn_invalid = ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (pn_invalid)
|
||||
goto err;
|
||||
}
|
||||
|
@ -2211,6 +2234,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
skb_pull(skb, tot_hdr_len);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
qos = ieee80211_is_data_qos(hdr->frame_control);
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
rx_status->chains |= BIT(0);
|
||||
if (rx->ppdu.combined_rssi == 0) {
|
||||
|
@ -2254,6 +2278,55 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
rx_status->flag |= RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
|
||||
if (tid < IEEE80211_NUM_TIDS &&
|
||||
first_msdu &&
|
||||
check_pn_type == HTT_RX_PN_CHECK &&
|
||||
(sec_type == HTT_SECURITY_AES_CCMP ||
|
||||
sec_type == HTT_SECURITY_TKIP ||
|
||||
sec_type == HTT_SECURITY_TKIP_NOMIC)) {
|
||||
u8 offset, *ivp, i;
|
||||
s8 keyidx = 0;
|
||||
__le64 pn48 = cpu_to_le64(new_pn.pn48);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
offset = ieee80211_hdrlen(hdr->frame_control);
|
||||
hdr->frame_control |= __cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
rx_status->flag &= ~RX_FLAG_IV_STRIPPED;
|
||||
|
||||
memmove(skb->data - IEEE80211_CCMP_HDR_LEN,
|
||||
skb->data, offset);
|
||||
skb_push(skb, IEEE80211_CCMP_HDR_LEN);
|
||||
ivp = skb->data + offset;
|
||||
memset(skb->data + offset, 0, IEEE80211_CCMP_HDR_LEN);
|
||||
/* Ext IV */
|
||||
ivp[IEEE80211_WEP_IV_LEN - 1] |= ATH10K_IEEE80211_EXTIV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
|
||||
if (peer->keys[i] &&
|
||||
peer->keys[i]->flags & IEEE80211_KEY_FLAG_PAIRWISE)
|
||||
keyidx = peer->keys[i]->keyidx;
|
||||
}
|
||||
|
||||
/* Key ID */
|
||||
ivp[IEEE80211_WEP_IV_LEN - 1] |= keyidx << 6;
|
||||
|
||||
if (sec_type == HTT_SECURITY_AES_CCMP) {
|
||||
rx_status->flag |= RX_FLAG_MIC_STRIPPED;
|
||||
/* pn 0, pn 1 */
|
||||
memcpy(skb->data + offset, &pn48, 2);
|
||||
/* pn 1, pn 3 , pn 34 , pn 5 */
|
||||
memcpy(skb->data + offset + 4, ((u8 *)&pn48) + 2, 4);
|
||||
} else {
|
||||
rx_status->flag |= RX_FLAG_ICV_STRIPPED;
|
||||
/* TSC 0 */
|
||||
memcpy(skb->data + offset + 2, &pn48, 1);
|
||||
/* TSC 1 */
|
||||
memcpy(skb->data + offset, ((u8 *)&pn48) + 1, 1);
|
||||
/* TSC 2 , TSC 3 , TSC 4 , TSC 5*/
|
||||
memcpy(skb->data + offset + 4, ((u8 *)&pn48) + 2, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tkip_mic_type == HTT_RX_TKIP_MIC)
|
||||
|
@ -2263,6 +2336,20 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
|||
if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
|
||||
rx_status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (!qos && tid < IEEE80211_NUM_TIDS) {
|
||||
u8 offset;
|
||||
__le16 qos_ctrl = 0;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
offset = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
memmove(skb->data - IEEE80211_QOS_CTL_LEN, skb->data, offset);
|
||||
skb_push(skb, IEEE80211_QOS_CTL_LEN);
|
||||
qos_ctrl = cpu_to_le16(tid);
|
||||
memcpy(skb->data + offset, &qos_ctrl, IEEE80211_QOS_CTL_LEN);
|
||||
}
|
||||
|
||||
ieee80211_rx_ni(ar->hw, skb);
|
||||
|
||||
/* We have delivered the skb to the upper layers (mac80211) so we
|
||||
|
|
|
@ -1237,6 +1237,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
|
|||
struct ath10k *ar = htt->ar;
|
||||
int res, data_len;
|
||||
struct htt_cmd_hdr *cmd_hdr;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
struct htt_data_tx_desc *tx_desc;
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
|
||||
struct sk_buff *tmp_skb;
|
||||
|
@ -1247,6 +1248,13 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
|
|||
u16 flags1 = 0;
|
||||
u16 msdu_id = 0;
|
||||
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
|
||||
}
|
||||
|
||||
data_len = msdu->len;
|
||||
|
||||
switch (txmode) {
|
||||
|
|
|
@ -5503,10 +5503,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ath10k_mac_vif_beacon_cleanup(arvif);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ret = ath10k_spectral_vif_stop(arvif);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
|
||||
|
@ -5575,6 +5571,11 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
|||
peer->vif = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean this up late, less opportunity for firmware to access
|
||||
* DMA memory we have deleted.
|
||||
*/
|
||||
ath10k_mac_vif_beacon_cleanup(arvif);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ath10k_peer_cleanup(ar, arvif->vdev_id);
|
||||
|
|
|
@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
|
|||
struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
|
||||
bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
u16 payload_len;
|
||||
u8 *trailer;
|
||||
int ret;
|
||||
|
||||
payload_len = le16_to_cpu(htc_hdr->len);
|
||||
skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
|
||||
|
||||
if (trailer_present) {
|
||||
trailer = skb->data + sizeof(*htc_hdr) +
|
||||
payload_len - htc_hdr->trailer_len;
|
||||
trailer = skb->data + skb->len - htc_hdr->trailer_len;
|
||||
|
||||
eid = pipe_id_to_eid(htc_hdr->eid);
|
||||
|
||||
|
@ -632,13 +627,31 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
|
|||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
struct ath10k_htc_hdr *htc_hdr;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
|
||||
skb->data, pkt->alloc_len);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Update actual length. The original length may be incorrect,
|
||||
* as the FW will bundle multiple packets as long as their sizes
|
||||
* fit within the same aligned length (pkt->alloc_len).
|
||||
*/
|
||||
htc_hdr = (struct ath10k_htc_hdr *)skb->data;
|
||||
pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
|
||||
if (pkt->act_len > pkt->alloc_len) {
|
||||
ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
|
||||
pkt->act_len, pkt->alloc_len);
|
||||
ret = -EMSGSIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
skb_put(skb, pkt->act_len);
|
||||
|
||||
out:
|
||||
pkt->status = ret;
|
||||
if (!ret)
|
||||
skb_put(skb, pkt->act_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -841,7 +841,7 @@ static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar,
|
|||
struct wmi_ch_info_ev_arg *arg)
|
||||
{
|
||||
const void **tb;
|
||||
const struct wmi_chan_info_event *ev;
|
||||
const struct wmi_tlv_chan_info_event *ev;
|
||||
int ret;
|
||||
|
||||
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
|
||||
|
|
|
@ -1615,6 +1615,22 @@ struct chan_info_params {
|
|||
|
||||
#define WMI_TLV_FLAG_MGMT_BUNDLE_TX_COMPL BIT(9)
|
||||
|
||||
struct wmi_tlv_chan_info_event {
|
||||
__le32 err_code;
|
||||
__le32 freq;
|
||||
__le32 cmd_flags;
|
||||
__le32 noise_floor;
|
||||
__le32 rx_clear_count;
|
||||
__le32 cycle_count;
|
||||
__le32 chan_tx_pwr_range;
|
||||
__le32 chan_tx_pwr_tp;
|
||||
__le32 rx_frame_count;
|
||||
__le32 my_bss_rx_cycle_count;
|
||||
__le32 rx_11b_mode_data_duration;
|
||||
__le32 tx_frame_cnt;
|
||||
__le32 mac_clk_mhz;
|
||||
} __packed;
|
||||
|
||||
struct wmi_tlv_mgmt_tx_compl_ev {
|
||||
__le32 desc_id;
|
||||
__le32 status;
|
||||
|
|
|
@ -6533,14 +6533,6 @@ struct wmi_chan_info_event {
|
|||
__le32 noise_floor;
|
||||
__le32 rx_clear_count;
|
||||
__le32 cycle_count;
|
||||
__le32 chan_tx_pwr_range;
|
||||
__le32 chan_tx_pwr_tp;
|
||||
__le32 rx_frame_count;
|
||||
__le32 my_bss_rx_cycle_count;
|
||||
__le32 rx_11b_mode_data_duration;
|
||||
__le32 tx_frame_cnt;
|
||||
__le32 mac_clk_mhz;
|
||||
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_4_chan_info_event {
|
||||
|
|
|
@ -2855,8 +2855,8 @@ static void *ath6kl_htc_mbox_create(struct ath6kl *ar)
|
|||
target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL);
|
||||
if (!target->dev) {
|
||||
ath6kl_err("unable to allocate memory\n");
|
||||
status = -ENOMEM;
|
||||
goto err_htc_cleanup;
|
||||
kfree(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock_init(&target->htc_lock);
|
||||
|
|
|
@ -132,6 +132,10 @@ ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe)
|
|||
struct ath6kl_urb_context *urb_context = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
/* bail if this pipe is not initialized */
|
||||
if (!pipe->ar_usb)
|
||||
return NULL;
|
||||
|
||||
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
|
||||
if (!list_empty(&pipe->urb_list_head)) {
|
||||
urb_context =
|
||||
|
@ -150,6 +154,10 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe,
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* bail if this pipe is not initialized */
|
||||
if (!pipe->ar_usb)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
|
||||
pipe->urb_cnt++;
|
||||
|
||||
|
|
|
@ -157,6 +157,22 @@ config ATH9K_PCOEM
|
|||
depends on ATH9K
|
||||
default y
|
||||
|
||||
config ATH9K_PCI_NO_EEPROM
|
||||
tristate "Atheros ath9k pci loader for EEPROM-less chips"
|
||||
depends on ATH9K_PCI
|
||||
default n
|
||||
help
|
||||
This separate driver provides a loader in order to support the
|
||||
AR500X to AR92XX-generation of ath9k PCI(e) WiFi chips, which have
|
||||
their initialization data (which contains the real PCI Device ID
|
||||
that ath9k will need) stored together with the calibration data out
|
||||
of reach for the ath9k chip.
|
||||
|
||||
These devices are usually various network appliances, routers or
|
||||
access Points and such.
|
||||
|
||||
If unsure say N.
|
||||
|
||||
config ATH9K_HTC
|
||||
tristate "Atheros HTC based wireless cards support"
|
||||
depends on USB && MAC80211
|
||||
|
|
|
@ -77,3 +77,5 @@ ath9k_htc-y += htc_hst.o \
|
|||
ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o
|
||||
|
||||
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
|
||||
|
||||
obj-$(CONFIG_ATH9K_PCI_NO_EEPROM) += ath9k_pci_owl_loader.o
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Initialize Owl Emulation Devices
|
||||
*
|
||||
* Copyright (C) 2016 Christian Lamparter <chunkeey@gmail.com>
|
||||
* Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
*
|
||||
* Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway)
|
||||
* need to be able to initialize the PCIe wifi device. Normally, this is done
|
||||
* during the early stages as a pci quirk.
|
||||
* However, this isn't possible for devices which have the init code for the
|
||||
* Atheros chip stored on UBI Volume on NAND. Hence, this module can be used to
|
||||
* initialize the chip when the user-space is ready to extract the init code.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ath9k_platform.h>
|
||||
|
||||
struct owl_ctx {
|
||||
struct completion eeprom_load;
|
||||
};
|
||||
|
||||
#define EEPROM_FILENAME_LEN 100
|
||||
|
||||
#define AR5416_EEPROM_MAGIC 0xa55a
|
||||
|
||||
static int ath9k_pci_fixup(struct pci_dev *pdev, const u16 *cal_data,
|
||||
size_t cal_len)
|
||||
{
|
||||
void __iomem *mem;
|
||||
const void *cal_end = (void *)cal_data + cal_len;
|
||||
const struct {
|
||||
u16 reg;
|
||||
u16 low_val;
|
||||
u16 high_val;
|
||||
} __packed * data;
|
||||
u16 cmd;
|
||||
u32 bar0;
|
||||
bool swap_needed = false;
|
||||
|
||||
if (*cal_data != AR5416_EEPROM_MAGIC) {
|
||||
if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) {
|
||||
dev_err(&pdev->dev, "invalid calibration data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "calibration data needs swapping\n");
|
||||
swap_needed = true;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "fixup device configuration\n");
|
||||
|
||||
mem = pcim_iomap(pdev, 0, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "ioremap error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0);
|
||||
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0,
|
||||
pci_resource_start(pdev, 0));
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
||||
cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
||||
pci_write_config_word(pdev, PCI_COMMAND, cmd);
|
||||
|
||||
/* set pointer to first reg address */
|
||||
for (data = (const void *)(cal_data + 3);
|
||||
(const void *)data <= cal_end && data->reg != (u16)~0;
|
||||
data++) {
|
||||
u32 val;
|
||||
u16 reg;
|
||||
|
||||
reg = data->reg;
|
||||
val = data->low_val;
|
||||
val |= ((u32)data->high_val) << 16;
|
||||
|
||||
if (swap_needed) {
|
||||
reg = swab16(reg);
|
||||
val = swahb32(val);
|
||||
}
|
||||
|
||||
__raw_writel(val, mem + reg);
|
||||
usleep_range(100, 120);
|
||||
}
|
||||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
||||
cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
|
||||
pci_write_config_word(pdev, PCI_COMMAND, cmd);
|
||||
|
||||
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, bar0);
|
||||
pcim_iounmap(pdev, mem);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void owl_fw_cb(const struct firmware *fw, void *context)
|
||||
{
|
||||
struct pci_dev *pdev = (struct pci_dev *)context;
|
||||
struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev);
|
||||
struct pci_bus *bus;
|
||||
|
||||
complete(&ctx->eeprom_load);
|
||||
|
||||
if (!fw) {
|
||||
dev_err(&pdev->dev, "no eeprom data received.\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
/* also note that we are doing *u16 operations on the file */
|
||||
if (fw->size > 4096 || fw->size < 0x200 || (fw->size & 1) == 1) {
|
||||
dev_err(&pdev->dev, "eeprom file has an invalid size.\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size))
|
||||
goto release;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
bus = pdev->bus;
|
||||
pci_stop_and_remove_bus_device(pdev);
|
||||
/* the device should come back with the proper
|
||||
* ProductId. But we have to initiate a rescan.
|
||||
*/
|
||||
pci_rescan_bus(bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
release:
|
||||
release_firmware(fw);
|
||||
}
|
||||
|
||||
static const char *owl_get_eeprom_name(struct pci_dev *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
char *eeprom_name;
|
||||
|
||||
dev_dbg(dev, "using auto-generated eeprom filename\n");
|
||||
|
||||
eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL);
|
||||
if (!eeprom_name)
|
||||
return NULL;
|
||||
|
||||
/* this should match the pattern used in ath9k/init.c */
|
||||
scnprintf(eeprom_name, EEPROM_FILENAME_LEN, "ath9k-eeprom-pci-%s.bin",
|
||||
dev_name(dev));
|
||||
|
||||
return eeprom_name;
|
||||
}
|
||||
|
||||
static int owl_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct owl_ctx *ctx;
|
||||
const char *eeprom_name;
|
||||
int err = 0;
|
||||
|
||||
if (pcim_enable_device(pdev))
|
||||
return -EIO;
|
||||
|
||||
pcim_pin_device(pdev);
|
||||
|
||||
eeprom_name = owl_get_eeprom_name(pdev);
|
||||
if (!eeprom_name) {
|
||||
dev_err(&pdev->dev, "no eeprom filename found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
init_completion(&ctx->eeprom_load);
|
||||
|
||||
pci_set_drvdata(pdev, ctx);
|
||||
err = request_firmware_nowait(THIS_MODULE, true, eeprom_name,
|
||||
&pdev->dev, GFP_KERNEL, pdev, owl_fw_cb);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "failed to request caldata (%d).\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void owl_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct owl_ctx *ctx = pci_get_drvdata(pdev);
|
||||
|
||||
if (ctx) {
|
||||
wait_for_completion(&ctx->eeprom_load);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pci_device_id owl_pci_table[] = {
|
||||
{ PCI_VDEVICE(ATHEROS, 0xff1c) }, /* PCIe */
|
||||
{ PCI_VDEVICE(ATHEROS, 0xff1d) }, /* PCI */
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, owl_pci_table);
|
||||
|
||||
static struct pci_driver owl_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = owl_pci_table,
|
||||
.probe = owl_probe,
|
||||
.remove = owl_remove,
|
||||
};
|
||||
module_pci_driver(owl_driver);
|
||||
MODULE_AUTHOR("Christian Lamparter <chunkeey@gmail.com>");
|
||||
MODULE_DESCRIPTION("External EEPROM data loader for Atheros AR500X to AR92XX");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -20,11 +20,30 @@
|
|||
|
||||
#define COMPUTE_TO (5 * HZ)
|
||||
#define LATEACK_DELAY (10 * HZ)
|
||||
#define LATEACK_TO 256
|
||||
#define MAX_DELAY 300
|
||||
#define EWMA_LEVEL 96
|
||||
#define EWMA_DIV 128
|
||||
|
||||
/**
|
||||
* ath_dynack_get_max_to - set max timeout according to channel width
|
||||
* @ah: ath hw
|
||||
*
|
||||
*/
|
||||
static u32 ath_dynack_get_max_to(struct ath_hw *ah)
|
||||
{
|
||||
const struct ath9k_channel *chan = ah->curchan;
|
||||
|
||||
if (!chan)
|
||||
return 300;
|
||||
|
||||
if (IS_CHAN_HT40(chan))
|
||||
return 300;
|
||||
if (IS_CHAN_HALF_RATE(chan))
|
||||
return 750;
|
||||
if (IS_CHAN_QUARTER_RATE(chan))
|
||||
return 1500;
|
||||
return 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
|
||||
*
|
||||
|
@ -78,6 +97,24 @@ static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath_dynack_set_timeout - configure timeouts/slottime registers
|
||||
* @ah: ath hw
|
||||
* @to: timeout value
|
||||
*
|
||||
*/
|
||||
static void ath_dynack_set_timeout(struct ath_hw *ah, int to)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int slottime = (to - 3) / 2;
|
||||
|
||||
ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n",
|
||||
to, slottime);
|
||||
ath9k_hw_setslottime(ah, slottime);
|
||||
ath9k_hw_set_ack_timeout(ah, to);
|
||||
ath9k_hw_set_cts_timeout(ah, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout
|
||||
* @ah: ath hw
|
||||
|
@ -86,7 +123,6 @@ static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac)
|
|||
*/
|
||||
static void ath_dynack_compute_ackto(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
struct ath_node *an;
|
||||
int to = 0;
|
||||
|
@ -96,15 +132,8 @@ static void ath_dynack_compute_ackto(struct ath_hw *ah)
|
|||
to = an->ackto;
|
||||
|
||||
if (to && da->ackto != to) {
|
||||
u32 slottime;
|
||||
|
||||
slottime = (to - 3) / 2;
|
||||
ath_dynack_set_timeout(ah, to);
|
||||
da->ackto = to;
|
||||
ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n",
|
||||
da->ackto, slottime);
|
||||
ath9k_hw_setslottime(ah, slottime);
|
||||
ath9k_hw_set_ack_timeout(ah, da->ackto);
|
||||
ath9k_hw_set_cts_timeout(ah, da->ackto);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,15 +145,16 @@ static void ath_dynack_compute_ackto(struct ath_hw *ah)
|
|||
*/
|
||||
static void ath_dynack_compute_to(struct ath_hw *ah)
|
||||
{
|
||||
u32 ackto, ack_ts;
|
||||
u8 *dst, *src;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath_node *an;
|
||||
struct ts_info *st_ts;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
u32 ackto, ack_ts, max_to;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ts_info *st_ts;
|
||||
struct ath_node *an;
|
||||
u8 *dst, *src;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
max_to = ath_dynack_get_max_to(ah);
|
||||
while (da->st_rbf.h_rb != da->st_rbf.t_rb &&
|
||||
da->ack_rbf.h_rb != da->ack_rbf.t_rb) {
|
||||
ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb];
|
||||
|
@ -140,7 +170,7 @@ static void ath_dynack_compute_to(struct ath_hw *ah)
|
|||
if (ack_ts > st_ts->tstamp + st_ts->dur) {
|
||||
ackto = ack_ts - st_ts->tstamp - st_ts->dur;
|
||||
|
||||
if (ackto < MAX_DELAY) {
|
||||
if (ackto < max_to) {
|
||||
sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst,
|
||||
src);
|
||||
if (sta) {
|
||||
|
@ -197,11 +227,10 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
|
|||
if (ieee80211_is_assoc_req(hdr->frame_control) ||
|
||||
ieee80211_is_assoc_resp(hdr->frame_control) ||
|
||||
ieee80211_is_auth(hdr->frame_control)) {
|
||||
ath_dbg(common, DYNACK, "late ack\n");
|
||||
u32 max_to = ath_dynack_get_max_to(ah);
|
||||
|
||||
ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
|
||||
ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
|
||||
ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
|
||||
ath_dbg(common, DYNACK, "late ack\n");
|
||||
ath_dynack_set_timeout(ah, max_to);
|
||||
if (sta) {
|
||||
struct ath_node *an;
|
||||
|
||||
|
@ -292,15 +321,13 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
|
|||
*/
|
||||
void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
|
||||
{
|
||||
/* ackto = slottime + sifs + air delay */
|
||||
u32 ackto = 9 + 16 + 64;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
|
||||
an->ackto = ackto;
|
||||
an->ackto = da->ackto;
|
||||
|
||||
spin_lock(&da->qlock);
|
||||
spin_lock_bh(&da->qlock);
|
||||
list_add_tail(&an->list, &da->nodes);
|
||||
spin_unlock(&da->qlock);
|
||||
spin_unlock_bh(&da->qlock);
|
||||
}
|
||||
EXPORT_SYMBOL(ath_dynack_node_init);
|
||||
|
||||
|
@ -314,9 +341,9 @@ void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an)
|
|||
{
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
|
||||
spin_lock(&da->qlock);
|
||||
spin_lock_bh(&da->qlock);
|
||||
list_del(&an->list);
|
||||
spin_unlock(&da->qlock);
|
||||
spin_unlock_bh(&da->qlock);
|
||||
}
|
||||
EXPORT_SYMBOL(ath_dynack_node_deinit);
|
||||
|
||||
|
@ -327,22 +354,26 @@ EXPORT_SYMBOL(ath_dynack_node_deinit);
|
|||
*/
|
||||
void ath_dynack_reset(struct ath_hw *ah)
|
||||
{
|
||||
/* ackto = slottime + sifs + air delay */
|
||||
u32 ackto = 9 + 16 + 64;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
struct ath_node *an;
|
||||
|
||||
da->lto = jiffies;
|
||||
da->ackto = ackto;
|
||||
spin_lock_bh(&da->qlock);
|
||||
|
||||
da->lto = jiffies + COMPUTE_TO;
|
||||
|
||||
da->st_rbf.t_rb = 0;
|
||||
da->st_rbf.h_rb = 0;
|
||||
da->ack_rbf.t_rb = 0;
|
||||
da->ack_rbf.h_rb = 0;
|
||||
|
||||
da->ackto = ath_dynack_get_max_to(ah);
|
||||
list_for_each_entry(an, &da->nodes, list)
|
||||
an->ackto = da->ackto;
|
||||
|
||||
/* init acktimeout */
|
||||
ath9k_hw_setslottime(ah, (ackto - 3) / 2);
|
||||
ath9k_hw_set_ack_timeout(ah, ackto);
|
||||
ath9k_hw_set_cts_timeout(ah, ackto);
|
||||
ath_dynack_set_timeout(ah, da->ackto);
|
||||
|
||||
spin_unlock_bh(&da->qlock);
|
||||
}
|
||||
EXPORT_SYMBOL(ath_dynack_reset);
|
||||
|
||||
|
@ -359,6 +390,8 @@ void ath_dynack_init(struct ath_hw *ah)
|
|||
|
||||
spin_lock_init(&da->qlock);
|
||||
INIT_LIST_HEAD(&da->nodes);
|
||||
/* ackto = slottime + sifs + air delay */
|
||||
da->ackto = 9 + 16 + 64;
|
||||
|
||||
ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION;
|
||||
}
|
||||
|
|
|
@ -463,7 +463,7 @@ static void ath9k_enable_rmw_buffer(void *hw_priv)
|
|||
atomic_inc(&priv->wmi->m_rmw_cnt);
|
||||
}
|
||||
|
||||
static u32 ath9k_reg_rmw_single(void *hw_priv,
|
||||
static void ath9k_reg_rmw_single(void *hw_priv,
|
||||
u32 reg_offset, u32 set, u32 clr)
|
||||
{
|
||||
struct ath_hw *ah = hw_priv;
|
||||
|
@ -471,7 +471,6 @@ static u32 ath9k_reg_rmw_single(void *hw_priv,
|
|||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
struct register_rmw buf, buf_ret;
|
||||
int ret;
|
||||
u32 val = 0;
|
||||
|
||||
buf.reg = cpu_to_be32(reg_offset);
|
||||
buf.set = cpu_to_be32(set);
|
||||
|
@ -485,7 +484,6 @@ static u32 ath9k_reg_rmw_single(void *hw_priv,
|
|||
ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n",
|
||||
reg_offset, ret);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
|
||||
|
|
|
@ -170,6 +170,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
|
|||
time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
|
||||
if (!time_left) {
|
||||
dev_err(target->dev, "HTC credit config timeout\n");
|
||||
kfree_skb(skb);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -205,6 +206,7 @@ static int htc_setup_complete(struct htc_target *target)
|
|||
time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
|
||||
if (!time_left) {
|
||||
dev_err(target->dev, "HTC start timeout\n");
|
||||
kfree_skb(skb);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -277,6 +279,7 @@ int htc_connect_service(struct htc_target *target,
|
|||
if (!time_left) {
|
||||
dev_err(target->dev, "Service connection timeout for: %d\n",
|
||||
service_connreq->service_id);
|
||||
kfree_skb(skb);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
|
@ -336,6 +336,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
|
|||
ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
|
||||
wmi_cmd_to_name(cmd_id));
|
||||
mutex_unlock(&wmi->op_mutex);
|
||||
kfree_skb(skb);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
|
@ -1107,12 +1107,10 @@ static int carl9170_usb_probe(struct usb_interface *intf,
|
|||
static void carl9170_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct ar9170 *ar = usb_get_intfdata(intf);
|
||||
struct usb_device *udev;
|
||||
|
||||
if (WARN_ON(!ar))
|
||||
return;
|
||||
|
||||
udev = ar->udev;
|
||||
wait_for_completion(&ar->fw_load_wait);
|
||||
|
||||
if (IS_INITIALIZED(ar)) {
|
||||
|
|
|
@ -641,52 +641,58 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
|||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
|
||||
struct wcn36xx_hal_start_scan_offload_req_msg msg_body;
|
||||
struct wcn36xx_hal_start_scan_offload_req_msg *msg_body;
|
||||
int ret, i;
|
||||
|
||||
if (req->ie_len > WCN36XX_MAX_SCAN_IE_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&wcn->hal_mutex);
|
||||
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_OFFLOAD_REQ);
|
||||
|
||||
msg_body.scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE;
|
||||
msg_body.min_ch_time = 30;
|
||||
msg_body.max_ch_time = 100;
|
||||
msg_body.scan_hidden = 1;
|
||||
memcpy(msg_body.mac, vif->addr, ETH_ALEN);
|
||||
msg_body.bss_type = vif_priv->bss_type;
|
||||
msg_body.p2p_search = vif->p2p;
|
||||
|
||||
msg_body.num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body.ssids));
|
||||
for (i = 0; i < msg_body.num_ssid; i++) {
|
||||
msg_body.ssids[i].length = min_t(u8, req->ssids[i].ssid_len,
|
||||
sizeof(msg_body.ssids[i].ssid));
|
||||
memcpy(msg_body.ssids[i].ssid, req->ssids[i].ssid,
|
||||
msg_body.ssids[i].length);
|
||||
msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);
|
||||
if (!msg_body) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg_body.num_channel = min_t(u8, req->n_channels,
|
||||
sizeof(msg_body.channels));
|
||||
for (i = 0; i < msg_body.num_channel; i++)
|
||||
msg_body.channels[i] = req->channels[i]->hw_value;
|
||||
INIT_HAL_MSG((*msg_body), WCN36XX_HAL_START_SCAN_OFFLOAD_REQ);
|
||||
|
||||
msg_body.header.len -= WCN36XX_MAX_SCAN_IE_LEN;
|
||||
msg_body->scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE;
|
||||
msg_body->min_ch_time = 30;
|
||||
msg_body->max_ch_time = 100;
|
||||
msg_body->scan_hidden = 1;
|
||||
memcpy(msg_body->mac, vif->addr, ETH_ALEN);
|
||||
msg_body->bss_type = vif_priv->bss_type;
|
||||
msg_body->p2p_search = vif->p2p;
|
||||
|
||||
msg_body->num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body->ssids));
|
||||
for (i = 0; i < msg_body->num_ssid; i++) {
|
||||
msg_body->ssids[i].length = min_t(u8, req->ssids[i].ssid_len,
|
||||
sizeof(msg_body->ssids[i].ssid));
|
||||
memcpy(msg_body->ssids[i].ssid, req->ssids[i].ssid,
|
||||
msg_body->ssids[i].length);
|
||||
}
|
||||
|
||||
msg_body->num_channel = min_t(u8, req->n_channels,
|
||||
sizeof(msg_body->channels));
|
||||
for (i = 0; i < msg_body->num_channel; i++)
|
||||
msg_body->channels[i] = req->channels[i]->hw_value;
|
||||
|
||||
msg_body->header.len -= WCN36XX_MAX_SCAN_IE_LEN;
|
||||
|
||||
if (req->ie_len > 0) {
|
||||
msg_body.ie_len = req->ie_len;
|
||||
msg_body.header.len += req->ie_len;
|
||||
memcpy(msg_body.ie, req->ie, req->ie_len);
|
||||
msg_body->ie_len = req->ie_len;
|
||||
msg_body->header.len += req->ie_len;
|
||||
memcpy(msg_body->ie, req->ie, req->ie_len);
|
||||
}
|
||||
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_HAL,
|
||||
"hal start hw-scan (channels: %u; ssids: %u; p2p: %s)\n",
|
||||
msg_body.num_channel, msg_body.num_ssid,
|
||||
msg_body.p2p_search ? "yes" : "no");
|
||||
msg_body->num_channel, msg_body->num_ssid,
|
||||
msg_body->p2p_search ? "yes" : "no");
|
||||
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);
|
||||
if (ret) {
|
||||
wcn36xx_err("Sending hal_start_scan_offload failed\n");
|
||||
goto out;
|
||||
|
@ -698,6 +704,7 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
|||
goto out;
|
||||
}
|
||||
out:
|
||||
kfree(msg_body);
|
||||
mutex_unlock(&wcn->hal_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1257,96 +1264,104 @@ int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
|||
static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
|
||||
const struct wcn36xx_hal_config_bss_req_msg *orig)
|
||||
{
|
||||
struct wcn36xx_hal_config_bss_req_msg_v1 msg_body;
|
||||
struct wcn36xx_hal_config_bss_params_v1 *bss = &msg_body.bss_params;
|
||||
struct wcn36xx_hal_config_sta_params_v1 *sta = &bss->sta;
|
||||
struct wcn36xx_hal_config_bss_req_msg_v1 *msg_body;
|
||||
struct wcn36xx_hal_config_bss_params_v1 *bss;
|
||||
struct wcn36xx_hal_config_sta_params_v1 *sta;
|
||||
int ret;
|
||||
|
||||
INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_BSS_REQ);
|
||||
msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);
|
||||
if (!msg_body)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_HAL_MSG((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ);
|
||||
|
||||
bss = &msg_body->bss_params;
|
||||
sta = &bss->sta;
|
||||
|
||||
/* convert orig to v1 */
|
||||
memcpy(&msg_body.bss_params.bssid,
|
||||
memcpy(&msg_body->bss_params.bssid,
|
||||
&orig->bss_params.bssid, ETH_ALEN);
|
||||
memcpy(&msg_body.bss_params.self_mac_addr,
|
||||
memcpy(&msg_body->bss_params.self_mac_addr,
|
||||
&orig->bss_params.self_mac_addr, ETH_ALEN);
|
||||
|
||||
msg_body.bss_params.bss_type = orig->bss_params.bss_type;
|
||||
msg_body.bss_params.oper_mode = orig->bss_params.oper_mode;
|
||||
msg_body.bss_params.nw_type = orig->bss_params.nw_type;
|
||||
msg_body->bss_params.bss_type = orig->bss_params.bss_type;
|
||||
msg_body->bss_params.oper_mode = orig->bss_params.oper_mode;
|
||||
msg_body->bss_params.nw_type = orig->bss_params.nw_type;
|
||||
|
||||
msg_body.bss_params.short_slot_time_supported =
|
||||
msg_body->bss_params.short_slot_time_supported =
|
||||
orig->bss_params.short_slot_time_supported;
|
||||
msg_body.bss_params.lla_coexist = orig->bss_params.lla_coexist;
|
||||
msg_body.bss_params.llb_coexist = orig->bss_params.llb_coexist;
|
||||
msg_body.bss_params.llg_coexist = orig->bss_params.llg_coexist;
|
||||
msg_body.bss_params.ht20_coexist = orig->bss_params.ht20_coexist;
|
||||
msg_body.bss_params.lln_non_gf_coexist =
|
||||
msg_body->bss_params.lla_coexist = orig->bss_params.lla_coexist;
|
||||
msg_body->bss_params.llb_coexist = orig->bss_params.llb_coexist;
|
||||
msg_body->bss_params.llg_coexist = orig->bss_params.llg_coexist;
|
||||
msg_body->bss_params.ht20_coexist = orig->bss_params.ht20_coexist;
|
||||
msg_body->bss_params.lln_non_gf_coexist =
|
||||
orig->bss_params.lln_non_gf_coexist;
|
||||
|
||||
msg_body.bss_params.lsig_tx_op_protection_full_support =
|
||||
msg_body->bss_params.lsig_tx_op_protection_full_support =
|
||||
orig->bss_params.lsig_tx_op_protection_full_support;
|
||||
msg_body.bss_params.rifs_mode = orig->bss_params.rifs_mode;
|
||||
msg_body.bss_params.beacon_interval = orig->bss_params.beacon_interval;
|
||||
msg_body.bss_params.dtim_period = orig->bss_params.dtim_period;
|
||||
msg_body.bss_params.tx_channel_width_set =
|
||||
msg_body->bss_params.rifs_mode = orig->bss_params.rifs_mode;
|
||||
msg_body->bss_params.beacon_interval = orig->bss_params.beacon_interval;
|
||||
msg_body->bss_params.dtim_period = orig->bss_params.dtim_period;
|
||||
msg_body->bss_params.tx_channel_width_set =
|
||||
orig->bss_params.tx_channel_width_set;
|
||||
msg_body.bss_params.oper_channel = orig->bss_params.oper_channel;
|
||||
msg_body.bss_params.ext_channel = orig->bss_params.ext_channel;
|
||||
msg_body->bss_params.oper_channel = orig->bss_params.oper_channel;
|
||||
msg_body->bss_params.ext_channel = orig->bss_params.ext_channel;
|
||||
|
||||
msg_body.bss_params.reserved = orig->bss_params.reserved;
|
||||
msg_body->bss_params.reserved = orig->bss_params.reserved;
|
||||
|
||||
memcpy(&msg_body.bss_params.ssid,
|
||||
memcpy(&msg_body->bss_params.ssid,
|
||||
&orig->bss_params.ssid,
|
||||
sizeof(orig->bss_params.ssid));
|
||||
|
||||
msg_body.bss_params.action = orig->bss_params.action;
|
||||
msg_body.bss_params.rateset = orig->bss_params.rateset;
|
||||
msg_body.bss_params.ht = orig->bss_params.ht;
|
||||
msg_body.bss_params.obss_prot_enabled =
|
||||
msg_body->bss_params.action = orig->bss_params.action;
|
||||
msg_body->bss_params.rateset = orig->bss_params.rateset;
|
||||
msg_body->bss_params.ht = orig->bss_params.ht;
|
||||
msg_body->bss_params.obss_prot_enabled =
|
||||
orig->bss_params.obss_prot_enabled;
|
||||
msg_body.bss_params.rmf = orig->bss_params.rmf;
|
||||
msg_body.bss_params.ht_oper_mode = orig->bss_params.ht_oper_mode;
|
||||
msg_body.bss_params.dual_cts_protection =
|
||||
msg_body->bss_params.rmf = orig->bss_params.rmf;
|
||||
msg_body->bss_params.ht_oper_mode = orig->bss_params.ht_oper_mode;
|
||||
msg_body->bss_params.dual_cts_protection =
|
||||
orig->bss_params.dual_cts_protection;
|
||||
|
||||
msg_body.bss_params.max_probe_resp_retry_limit =
|
||||
msg_body->bss_params.max_probe_resp_retry_limit =
|
||||
orig->bss_params.max_probe_resp_retry_limit;
|
||||
msg_body.bss_params.hidden_ssid = orig->bss_params.hidden_ssid;
|
||||
msg_body.bss_params.proxy_probe_resp =
|
||||
msg_body->bss_params.hidden_ssid = orig->bss_params.hidden_ssid;
|
||||
msg_body->bss_params.proxy_probe_resp =
|
||||
orig->bss_params.proxy_probe_resp;
|
||||
msg_body.bss_params.edca_params_valid =
|
||||
msg_body->bss_params.edca_params_valid =
|
||||
orig->bss_params.edca_params_valid;
|
||||
|
||||
memcpy(&msg_body.bss_params.acbe,
|
||||
memcpy(&msg_body->bss_params.acbe,
|
||||
&orig->bss_params.acbe,
|
||||
sizeof(orig->bss_params.acbe));
|
||||
memcpy(&msg_body.bss_params.acbk,
|
||||
memcpy(&msg_body->bss_params.acbk,
|
||||
&orig->bss_params.acbk,
|
||||
sizeof(orig->bss_params.acbk));
|
||||
memcpy(&msg_body.bss_params.acvi,
|
||||
memcpy(&msg_body->bss_params.acvi,
|
||||
&orig->bss_params.acvi,
|
||||
sizeof(orig->bss_params.acvi));
|
||||
memcpy(&msg_body.bss_params.acvo,
|
||||
memcpy(&msg_body->bss_params.acvo,
|
||||
&orig->bss_params.acvo,
|
||||
sizeof(orig->bss_params.acvo));
|
||||
|
||||
msg_body.bss_params.ext_set_sta_key_param_valid =
|
||||
msg_body->bss_params.ext_set_sta_key_param_valid =
|
||||
orig->bss_params.ext_set_sta_key_param_valid;
|
||||
|
||||
memcpy(&msg_body.bss_params.ext_set_sta_key_param,
|
||||
memcpy(&msg_body->bss_params.ext_set_sta_key_param,
|
||||
&orig->bss_params.ext_set_sta_key_param,
|
||||
sizeof(orig->bss_params.acvo));
|
||||
|
||||
msg_body.bss_params.wcn36xx_hal_persona =
|
||||
msg_body->bss_params.wcn36xx_hal_persona =
|
||||
orig->bss_params.wcn36xx_hal_persona;
|
||||
msg_body.bss_params.spectrum_mgt_enable =
|
||||
msg_body->bss_params.spectrum_mgt_enable =
|
||||
orig->bss_params.spectrum_mgt_enable;
|
||||
msg_body.bss_params.tx_mgmt_power = orig->bss_params.tx_mgmt_power;
|
||||
msg_body.bss_params.max_tx_power = orig->bss_params.max_tx_power;
|
||||
msg_body->bss_params.tx_mgmt_power = orig->bss_params.tx_mgmt_power;
|
||||
msg_body->bss_params.max_tx_power = orig->bss_params.max_tx_power;
|
||||
|
||||
wcn36xx_smd_convert_sta_to_v1(wcn, &orig->bss_params.sta,
|
||||
&msg_body.bss_params.sta);
|
||||
&msg_body->bss_params.sta);
|
||||
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_HAL,
|
||||
"hal config bss v1 bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",
|
||||
|
@ -1358,7 +1373,10 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
|
|||
sta->bssid, sta->action, sta->sta_index,
|
||||
sta->bssid_index, sta->aid, sta->type, sta->mac);
|
||||
|
||||
return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);
|
||||
kfree(msg_body);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1410,16 +1428,21 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
|||
struct ieee80211_sta *sta, const u8 *bssid,
|
||||
bool update)
|
||||
{
|
||||
struct wcn36xx_hal_config_bss_req_msg msg;
|
||||
struct wcn36xx_hal_config_bss_req_msg *msg;
|
||||
struct wcn36xx_hal_config_bss_params *bss;
|
||||
struct wcn36xx_hal_config_sta_params *sta_params;
|
||||
struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wcn->hal_mutex);
|
||||
INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_BSS_REQ);
|
||||
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
|
||||
if (!msg) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
INIT_HAL_MSG((*msg), WCN36XX_HAL_CONFIG_BSS_REQ);
|
||||
|
||||
bss = &msg.bss_params;
|
||||
bss = &msg->bss_params;
|
||||
sta_params = &bss->sta;
|
||||
|
||||
WARN_ON(is_zero_ether_addr(bssid));
|
||||
|
@ -1514,11 +1537,11 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
|||
sta_params->mac);
|
||||
|
||||
if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
|
||||
ret = wcn36xx_smd_config_bss_v1(wcn, &msg);
|
||||
ret = wcn36xx_smd_config_bss_v1(wcn, msg);
|
||||
} else {
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, msg);
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, (*msg));
|
||||
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len);
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg->header.len);
|
||||
}
|
||||
if (ret) {
|
||||
wcn36xx_err("Sending hal_config_bss failed\n");
|
||||
|
@ -1534,6 +1557,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
|||
goto out;
|
||||
}
|
||||
out:
|
||||
kfree(msg);
|
||||
mutex_unlock(&wcn->hal_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,22 @@
|
|||
|
||||
#define WIL_MAX_ROC_DURATION_MS 5000
|
||||
|
||||
#define WIL_EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1))
|
||||
#define WIL_EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2))
|
||||
#define WIL_EDMG_CHANNEL_11_SUBCHANNELS (BIT(2) | BIT(3))
|
||||
|
||||
/* WIL_EDMG_BW_CONFIGURATION define the allowed channel bandwidth
|
||||
* configurations as defined by IEEE 802.11 section 9.4.2.251, Table 13.
|
||||
* The value 5 allowing CB1 and CB2 of adjacent channels.
|
||||
*/
|
||||
#define WIL_EDMG_BW_CONFIGURATION 5
|
||||
|
||||
/* WIL_EDMG_CHANNELS is a bitmap that indicates the 2.16 GHz channel(s) that
|
||||
* are allowed to be used for EDMG transmissions in the BSS as defined by
|
||||
* IEEE 802.11 section 9.4.2.251.
|
||||
*/
|
||||
#define WIL_EDMG_CHANNELS (BIT(0) | BIT(1) | BIT(2) | BIT(3))
|
||||
|
||||
bool disable_ap_sme;
|
||||
module_param(disable_ap_sme, bool, 0444);
|
||||
MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
|
||||
|
@ -51,6 +67,39 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
|
|||
CHAN60G(4, 0),
|
||||
};
|
||||
|
||||
/* Rx channel bonding mode */
|
||||
enum wil_rx_cb_mode {
|
||||
WIL_RX_CB_MODE_DMG,
|
||||
WIL_RX_CB_MODE_EDMG,
|
||||
WIL_RX_CB_MODE_WIDE,
|
||||
};
|
||||
|
||||
static int wil_rx_cb_mode_to_n_bonded(u8 cb_mode)
|
||||
{
|
||||
switch (cb_mode) {
|
||||
case WIL_RX_CB_MODE_DMG:
|
||||
case WIL_RX_CB_MODE_EDMG:
|
||||
return 1;
|
||||
case WIL_RX_CB_MODE_WIDE:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_tx_cb_mode_to_n_bonded(u8 cb_mode)
|
||||
{
|
||||
switch (cb_mode) {
|
||||
case WMI_TX_MODE_DMG:
|
||||
case WMI_TX_MODE_EDMG_CB1:
|
||||
return 1;
|
||||
case WMI_TX_MODE_EDMG_CB2:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len)
|
||||
{
|
||||
|
@ -82,6 +131,13 @@ void update_supported_bands(struct wil6210_priv *wil)
|
|||
|
||||
wiphy->bands[NL80211_BAND_60GHZ]->n_channels =
|
||||
wil_num_supported_channels(wil);
|
||||
|
||||
if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) {
|
||||
wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.channels =
|
||||
WIL_EDMG_CHANNELS;
|
||||
wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.bw_config =
|
||||
WIL_EDMG_BW_CONFIGURATION;
|
||||
}
|
||||
}
|
||||
|
||||
/* Vendor id to be used in vendor specific command and events
|
||||
|
@ -275,6 +331,8 @@ static const char * const key_usage_str[] = {
|
|||
[WMI_KEY_USE_PAIRWISE] = "PTK",
|
||||
[WMI_KEY_USE_RX_GROUP] = "RX_GTK",
|
||||
[WMI_KEY_USE_TX_GROUP] = "TX_GTK",
|
||||
[WMI_KEY_USE_STORE_PTK] = "STORE_PTK",
|
||||
[WMI_KEY_USE_APPLY_PTK] = "APPLY_PTK",
|
||||
};
|
||||
|
||||
int wil_iftype_nl2wmi(enum nl80211_iftype type)
|
||||
|
@ -300,6 +358,86 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch)
|
||||
{
|
||||
switch (spec_ch) {
|
||||
case 1:
|
||||
*wmi_ch = WMI_CHANNEL_1;
|
||||
break;
|
||||
case 2:
|
||||
*wmi_ch = WMI_CHANNEL_2;
|
||||
break;
|
||||
case 3:
|
||||
*wmi_ch = WMI_CHANNEL_3;
|
||||
break;
|
||||
case 4:
|
||||
*wmi_ch = WMI_CHANNEL_4;
|
||||
break;
|
||||
case 5:
|
||||
*wmi_ch = WMI_CHANNEL_5;
|
||||
break;
|
||||
case 6:
|
||||
*wmi_ch = WMI_CHANNEL_6;
|
||||
break;
|
||||
case 9:
|
||||
*wmi_ch = WMI_CHANNEL_9;
|
||||
break;
|
||||
case 10:
|
||||
*wmi_ch = WMI_CHANNEL_10;
|
||||
break;
|
||||
case 11:
|
||||
*wmi_ch = WMI_CHANNEL_11;
|
||||
break;
|
||||
case 12:
|
||||
*wmi_ch = WMI_CHANNEL_12;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch)
|
||||
{
|
||||
switch (wmi_ch) {
|
||||
case WMI_CHANNEL_1:
|
||||
*spec_ch = 1;
|
||||
break;
|
||||
case WMI_CHANNEL_2:
|
||||
*spec_ch = 2;
|
||||
break;
|
||||
case WMI_CHANNEL_3:
|
||||
*spec_ch = 3;
|
||||
break;
|
||||
case WMI_CHANNEL_4:
|
||||
*spec_ch = 4;
|
||||
break;
|
||||
case WMI_CHANNEL_5:
|
||||
*spec_ch = 5;
|
||||
break;
|
||||
case WMI_CHANNEL_6:
|
||||
*spec_ch = 6;
|
||||
break;
|
||||
case WMI_CHANNEL_9:
|
||||
*spec_ch = 9;
|
||||
break;
|
||||
case WMI_CHANNEL_10:
|
||||
*spec_ch = 10;
|
||||
break;
|
||||
case WMI_CHANNEL_11:
|
||||
*spec_ch = 11;
|
||||
break;
|
||||
case WMI_CHANNEL_12:
|
||||
*spec_ch = 12;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
|
@ -314,6 +452,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
|
|||
} __packed reply;
|
||||
struct wil_net_stats *stats = &wil->sta[cid].stats;
|
||||
int rc;
|
||||
u8 txflag = RATE_INFO_FLAGS_DMG;
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
|
||||
|
@ -327,7 +466,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
|
|||
" MCS %d TSF 0x%016llx\n"
|
||||
" BF status 0x%08x RSSI %d SQI %d%%\n"
|
||||
" Tx Tpt %d goodput %d Rx goodput %d\n"
|
||||
" Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
|
||||
" Sectors(rx:tx) my %d:%d peer %d:%d\n"
|
||||
" Tx mode %d}\n",
|
||||
cid, vif->mid, le16_to_cpu(reply.evt.bf_mcs),
|
||||
le64_to_cpu(reply.evt.tsf), reply.evt.status,
|
||||
reply.evt.rssi,
|
||||
|
@ -338,7 +478,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
|
|||
le16_to_cpu(reply.evt.my_rx_sector),
|
||||
le16_to_cpu(reply.evt.my_tx_sector),
|
||||
le16_to_cpu(reply.evt.other_rx_sector),
|
||||
le16_to_cpu(reply.evt.other_tx_sector));
|
||||
le16_to_cpu(reply.evt.other_tx_sector),
|
||||
reply.evt.tx_mode);
|
||||
|
||||
sinfo->generation = wil->sinfo_gen;
|
||||
|
||||
|
@ -351,9 +492,16 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
|
|||
BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) |
|
||||
BIT_ULL(NL80211_STA_INFO_TX_FAILED);
|
||||
|
||||
sinfo->txrate.flags = RATE_INFO_FLAGS_DMG;
|
||||
if (wil->use_enhanced_dma_hw && reply.evt.tx_mode != WMI_TX_MODE_DMG)
|
||||
txflag = RATE_INFO_FLAGS_EDMG;
|
||||
|
||||
sinfo->txrate.flags = txflag;
|
||||
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
|
||||
sinfo->rxrate.mcs = stats->last_mcs_rx;
|
||||
sinfo->txrate.n_bonded_ch =
|
||||
wil_tx_cb_mode_to_n_bonded(reply.evt.tx_mode);
|
||||
sinfo->rxrate.n_bonded_ch =
|
||||
wil_rx_cb_mode_to_n_bonded(stats->last_cb_mode_rx);
|
||||
sinfo->rx_bytes = stats->rx_bytes;
|
||||
sinfo->rx_packets = stats->rx_packets;
|
||||
sinfo->rx_dropped_misc = stats->rx_dropped;
|
||||
|
@ -396,7 +544,7 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy,
|
|||
/*
|
||||
* Find @idx-th active STA for specific MID for station dump.
|
||||
*/
|
||||
static int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx)
|
||||
int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1022,6 +1170,33 @@ static int wil_ft_connect(struct wiphy *wiphy,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int wil_get_wmi_edmg_channel(struct wil6210_priv *wil, u8 edmg_bw_config,
|
||||
u8 edmg_channels, u8 *wmi_ch)
|
||||
{
|
||||
if (!edmg_bw_config) {
|
||||
*wmi_ch = 0;
|
||||
return 0;
|
||||
} else if (edmg_bw_config == WIL_EDMG_BW_CONFIGURATION) {
|
||||
/* convert from edmg channel bitmap into edmg channel number */
|
||||
switch (edmg_channels) {
|
||||
case WIL_EDMG_CHANNEL_9_SUBCHANNELS:
|
||||
return wil_spec2wmi_ch(9, wmi_ch);
|
||||
case WIL_EDMG_CHANNEL_10_SUBCHANNELS:
|
||||
return wil_spec2wmi_ch(10, wmi_ch);
|
||||
case WIL_EDMG_CHANNEL_11_SUBCHANNELS:
|
||||
return wil_spec2wmi_ch(11, wmi_ch);
|
||||
default:
|
||||
wil_err(wil, "Unsupported edmg channel bitmap 0x%x\n",
|
||||
edmg_channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
wil_err(wil, "Unsupported EDMG BW configuration %d\n",
|
||||
edmg_bw_config);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_connect_params *sme)
|
||||
|
@ -1167,6 +1342,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
|||
memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
|
||||
conn.channel = ch - 1;
|
||||
|
||||
rc = wil_get_wmi_edmg_channel(wil, sme->edmg.bw_config,
|
||||
sme->edmg.channels, &conn.edmg_channel);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
ether_addr_copy(conn.bssid, bss->bssid);
|
||||
ether_addr_copy(conn.dst_mac, bss->bssid);
|
||||
|
||||
|
@ -1376,6 +1556,7 @@ void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
|
|||
return;
|
||||
|
||||
switch (key_usage) {
|
||||
case WMI_KEY_USE_STORE_PTK:
|
||||
case WMI_KEY_USE_PAIRWISE:
|
||||
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
|
||||
cc = &cs->tid_crypto_rx[tid].key_id[key_index];
|
||||
|
@ -1473,6 +1654,16 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&wil->eap_lock);
|
||||
if (pairwise && wdev->iftype == NL80211_IFTYPE_STATION &&
|
||||
(vif->ptk_rekey_state == WIL_REKEY_M3_RECEIVED ||
|
||||
vif->ptk_rekey_state == WIL_REKEY_WAIT_M4_SENT)) {
|
||||
key_usage = WMI_KEY_USE_STORE_PTK;
|
||||
vif->ptk_rekey_state = WIL_REKEY_WAIT_M4_SENT;
|
||||
wil_dbg_misc(wil, "Store EAPOL key\n");
|
||||
}
|
||||
spin_unlock_bh(&wil->eap_lock);
|
||||
|
||||
rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
|
||||
params->key, key_usage);
|
||||
if (!rc && !IS_ERR(cs)) {
|
||||
|
@ -1728,7 +1919,7 @@ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
|
|||
static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
const u8 *ssid, size_t ssid_len, u32 privacy,
|
||||
int bi, u8 chan,
|
||||
int bi, u8 chan, u8 wmi_edmg_channel,
|
||||
struct cfg80211_beacon_data *bcon,
|
||||
u8 hidden_ssid, u32 pbss)
|
||||
{
|
||||
|
@ -1791,6 +1982,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
|
||||
vif->privacy = privacy;
|
||||
vif->channel = chan;
|
||||
vif->wmi_edmg_channel = wmi_edmg_channel;
|
||||
vif->hidden_ssid = hidden_ssid;
|
||||
vif->pbss = pbss;
|
||||
vif->bi = bi;
|
||||
|
@ -1801,7 +1993,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
|
||||
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
|
||||
|
||||
rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go);
|
||||
rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, wmi_edmg_channel,
|
||||
hidden_ssid, is_go);
|
||||
if (rc)
|
||||
goto err_pcp_start;
|
||||
|
||||
|
@ -1853,7 +2046,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
|
|||
rc = _wil_cfg80211_start_ap(wiphy, ndev,
|
||||
vif->ssid, vif->ssid_len,
|
||||
vif->privacy, vif->bi,
|
||||
vif->channel, &bcon,
|
||||
vif->channel,
|
||||
vif->wmi_edmg_channel, &bcon,
|
||||
vif->hidden_ssid, vif->pbss);
|
||||
if (rc) {
|
||||
wil_err(wil, "vif %d recovery failed (%d)\n", i, rc);
|
||||
|
@ -1903,7 +2097,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
|||
rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid,
|
||||
vif->ssid_len, privacy,
|
||||
wdev->beacon_interval,
|
||||
vif->channel, bcon,
|
||||
vif->channel,
|
||||
vif->wmi_edmg_channel, bcon,
|
||||
vif->hidden_ssid,
|
||||
vif->pbss);
|
||||
} else {
|
||||
|
@ -1922,10 +2117,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
struct ieee80211_channel *channel = info->chandef.chan;
|
||||
struct cfg80211_beacon_data *bcon = &info->beacon;
|
||||
struct cfg80211_crypto_settings *crypto = &info->crypto;
|
||||
u8 wmi_edmg_channel;
|
||||
u8 hidden_ssid;
|
||||
|
||||
wil_dbg_misc(wil, "start_ap\n");
|
||||
|
||||
rc = wil_get_wmi_edmg_channel(wil, info->chandef.edmg.bw_config,
|
||||
info->chandef.edmg.channels,
|
||||
&wmi_edmg_channel);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (!channel) {
|
||||
wil_err(wil, "AP: No channel???\n");
|
||||
return -EINVAL;
|
||||
|
@ -1965,7 +2167,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
rc = _wil_cfg80211_start_ap(wiphy, ndev,
|
||||
info->ssid, info->ssid_len, info->privacy,
|
||||
info->beacon_interval, channel->hw_value,
|
||||
bcon, hidden_ssid, info->pbss);
|
||||
wmi_edmg_channel, bcon, hidden_ssid,
|
||||
info->pbss);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -393,7 +393,8 @@ static int wil_debugfs_iomem_x32_set(void *data, u64 val)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
writel(val, (void __iomem *)d->offset);
|
||||
writel_relaxed(val, (void __iomem *)d->offset);
|
||||
|
||||
wmb(); /* make sure write propagated to HW */
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
@ -959,6 +960,18 @@ static const struct file_operations fops_pmcdata = {
|
|||
.llseek = wil_pmc_llseek,
|
||||
};
|
||||
|
||||
static int wil_pmcring_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_pmcring_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_pmcring = {
|
||||
.open = wil_pmcring_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---tx_mgmt---*/
|
||||
/* Write mgmt frame to this file to send it */
|
||||
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
||||
|
@ -2371,6 +2384,7 @@ static const struct {
|
|||
{"back", 0644, &fops_back},
|
||||
{"pmccfg", 0644, &fops_pmccfg},
|
||||
{"pmcdata", 0444, &fops_pmcdata},
|
||||
{"pmcring", 0444, &fops_pmcring},
|
||||
{"temp", 0444, &temp_fops},
|
||||
{"freq", 0444, &freq_fops},
|
||||
{"link", 0444, &link_fops},
|
||||
|
|
|
@ -373,6 +373,7 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
|
|||
}
|
||||
clear_bit(wil_vif_fwconnecting, vif->status);
|
||||
clear_bit(wil_vif_ft_roam, vif->status);
|
||||
vif->ptk_rekey_state = WIL_REKEY_IDLE;
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
|
@ -724,6 +725,8 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
INIT_LIST_HEAD(&wil->pending_wmi_ev);
|
||||
spin_lock_init(&wil->wmi_ev_lock);
|
||||
spin_lock_init(&wil->net_queue_lock);
|
||||
spin_lock_init(&wil->eap_lock);
|
||||
|
||||
init_waitqueue_head(&wil->wq);
|
||||
init_rwsem(&wil->mem_lock);
|
||||
|
||||
|
@ -1654,6 +1657,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
cancel_work_sync(&vif->disconnect_worker);
|
||||
wil6210_disconnect(vif, NULL,
|
||||
WLAN_REASON_DEAUTH_LEAVING);
|
||||
vif->ptk_rekey_state = WIL_REKEY_IDLE;
|
||||
}
|
||||
}
|
||||
wil_bcast_fini_all(wil);
|
||||
|
|
|
@ -218,6 +218,7 @@ static void wil_vif_deinit(struct wil6210_vif *vif)
|
|||
cancel_work_sync(&vif->p2p.delayed_listen_work);
|
||||
wil_probe_client_flush(vif);
|
||||
cancel_work_sync(&vif->probe_client_worker);
|
||||
cancel_work_sync(&vif->enable_tx_key_worker);
|
||||
}
|
||||
|
||||
void wil_vif_free(struct wil6210_vif *vif)
|
||||
|
@ -283,7 +284,9 @@ static void wil_vif_init(struct wil6210_vif *vif)
|
|||
|
||||
INIT_WORK(&vif->probe_client_worker, wil_probe_client_worker);
|
||||
INIT_WORK(&vif->disconnect_worker, wil_disconnect_worker);
|
||||
INIT_WORK(&vif->p2p.discovery_expired_work, wil_p2p_listen_expired);
|
||||
INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
|
||||
INIT_WORK(&vif->enable_tx_key_worker, wil_enable_tx_key_worker);
|
||||
|
||||
INIT_LIST_HEAD(&vif->probe_client_pending);
|
||||
|
||||
|
@ -540,6 +543,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
|
|||
cancel_work_sync(&vif->disconnect_worker);
|
||||
wil_probe_client_flush(vif);
|
||||
cancel_work_sync(&vif->probe_client_worker);
|
||||
cancel_work_sync(&vif->enable_tx_key_worker);
|
||||
/* for VIFs, ndev will be freed by destructor after RTNL is unlocked.
|
||||
* the main interface will be freed in wil_if_free, we need to keep it
|
||||
* a bit longer so logging macros will work.
|
||||
|
|
|
@ -435,7 +435,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
mutex_unlock(&wil->mutex);
|
||||
if (rc) {
|
||||
wil_err(wil, "failed to load WMI only FW\n");
|
||||
goto if_remove;
|
||||
/* ignore the error to allow debugging */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,8 +455,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
return 0;
|
||||
|
||||
if_remove:
|
||||
wil_if_remove(wil);
|
||||
bus_disable:
|
||||
wil_if_pcie_disable(wil);
|
||||
err_iounmap:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include "wmi.h"
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
|
@ -431,3 +432,28 @@ loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence)
|
|||
|
||||
return newpos;
|
||||
}
|
||||
|
||||
int wil_pmcring_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
size_t pmc_ring_size =
|
||||
sizeof(struct vring_rx_desc) * pmc->num_descriptors;
|
||||
|
||||
mutex_lock(&pmc->lock);
|
||||
|
||||
if (!wil_is_pmc_allocated(pmc)) {
|
||||
wil_err(wil, "error, pmc is not allocated!\n");
|
||||
pmc->last_cmd_status = -EPERM;
|
||||
mutex_unlock(&pmc->lock);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "pmcring_read: size %zu\n", pmc_ring_size);
|
||||
|
||||
seq_write(s, pmc->pring_va, pmc_ring_size);
|
||||
|
||||
mutex_unlock(&pmc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,3 +25,4 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd);
|
|||
int wil_pmc_last_cmd_status(struct wil6210_priv *wil);
|
||||
ssize_t wil_pmc_read(struct file *, char __user *, size_t, loff_t *);
|
||||
loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence);
|
||||
int wil_pmcring_read(struct seq_file *s, void *data);
|
||||
|
|
|
@ -260,7 +260,6 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
|
|||
r->reorder_buf =
|
||||
kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
|
||||
if (!r->reorder_buf) {
|
||||
kfree(r->reorder_buf);
|
||||
kfree(r);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -724,25 +724,199 @@ static void wil_get_netif_rx_params(struct sk_buff *skb, int *cid,
|
|||
*security = wil_rxdesc_security(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if skb is ptk eapol key message
|
||||
*
|
||||
* returns a pointer to the start of the eapol key structure, NULL
|
||||
* if frame is not PTK eapol key
|
||||
*/
|
||||
static struct wil_eapol_key *wil_is_ptk_eapol_key(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u8 *buf;
|
||||
const struct wil_1x_hdr *hdr;
|
||||
struct wil_eapol_key *key;
|
||||
u16 key_info;
|
||||
int len = skb->len;
|
||||
|
||||
if (!skb_mac_header_was_set(skb)) {
|
||||
wil_err(wil, "mac header was not set\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len -= skb_mac_offset(skb);
|
||||
|
||||
if (len < sizeof(struct ethhdr) + sizeof(struct wil_1x_hdr) +
|
||||
sizeof(struct wil_eapol_key))
|
||||
return NULL;
|
||||
|
||||
buf = skb_mac_header(skb) + sizeof(struct ethhdr);
|
||||
|
||||
hdr = (const struct wil_1x_hdr *)buf;
|
||||
if (hdr->type != WIL_1X_TYPE_EAPOL_KEY)
|
||||
return NULL;
|
||||
|
||||
key = (struct wil_eapol_key *)(buf + sizeof(struct wil_1x_hdr));
|
||||
if (key->type != WIL_EAPOL_KEY_TYPE_WPA &&
|
||||
key->type != WIL_EAPOL_KEY_TYPE_RSN)
|
||||
return NULL;
|
||||
|
||||
key_info = be16_to_cpu(key->key_info);
|
||||
if (!(key_info & WIL_KEY_INFO_KEY_TYPE)) /* check if pairwise */
|
||||
return NULL;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static bool wil_skb_is_eap_3(struct wil6210_priv *wil, struct sk_buff *skb)
|
||||
{
|
||||
struct wil_eapol_key *key;
|
||||
u16 key_info;
|
||||
|
||||
key = wil_is_ptk_eapol_key(wil, skb);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
key_info = be16_to_cpu(key->key_info);
|
||||
if (key_info & (WIL_KEY_INFO_MIC |
|
||||
WIL_KEY_INFO_ENCR_KEY_DATA)) {
|
||||
/* 3/4 of 4-Way Handshake */
|
||||
wil_dbg_misc(wil, "EAPOL key message 3\n");
|
||||
return true;
|
||||
}
|
||||
/* 1/4 of 4-Way Handshake */
|
||||
wil_dbg_misc(wil, "EAPOL key message 1\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool wil_skb_is_eap_4(struct wil6210_priv *wil, struct sk_buff *skb)
|
||||
{
|
||||
struct wil_eapol_key *key;
|
||||
u32 *nonce, i;
|
||||
|
||||
key = wil_is_ptk_eapol_key(wil, skb);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
nonce = (u32 *)key->key_nonce;
|
||||
for (i = 0; i < WIL_EAP_NONCE_LEN / sizeof(u32); i++, nonce++) {
|
||||
if (*nonce != 0) {
|
||||
/* message 2/4 */
|
||||
wil_dbg_misc(wil, "EAPOL key message 2\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wil_dbg_misc(wil, "EAPOL key message 4\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wil_enable_tx_key_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_vif *vif = container_of(work,
|
||||
struct wil6210_vif, enable_tx_key_worker);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc, cid;
|
||||
|
||||
rtnl_lock();
|
||||
if (vif->ptk_rekey_state != WIL_REKEY_WAIT_M4_SENT) {
|
||||
wil_dbg_misc(wil, "Invalid rekey state = %d\n",
|
||||
vif->ptk_rekey_state);
|
||||
rtnl_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
cid = wil_find_cid_by_idx(wil, vif->mid, 0);
|
||||
if (!wil_cid_valid(wil, cid)) {
|
||||
wil_err(wil, "Invalid cid = %d\n", cid);
|
||||
rtnl_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "Apply PTK key after eapol was sent out\n");
|
||||
rc = wmi_add_cipher_key(vif, 0, wil->sta[cid].addr, 0, NULL,
|
||||
WMI_KEY_USE_APPLY_PTK);
|
||||
|
||||
vif->ptk_rekey_state = WIL_REKEY_IDLE;
|
||||
rtnl_unlock();
|
||||
|
||||
if (rc)
|
||||
wil_err(wil, "Apply PTK key failed %d\n", rc);
|
||||
}
|
||||
|
||||
void wil_tx_complete_handle_eapol(struct wil6210_vif *vif, struct sk_buff *skb)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
bool q = false;
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_STATION ||
|
||||
!test_bit(WMI_FW_CAPABILITY_SPLIT_REKEY, wil->fw_capabilities))
|
||||
return;
|
||||
|
||||
/* check if skb is an EAP message 4/4 */
|
||||
if (!wil_skb_is_eap_4(wil, skb))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&wil->eap_lock);
|
||||
switch (vif->ptk_rekey_state) {
|
||||
case WIL_REKEY_IDLE:
|
||||
/* ignore idle state, can happen due to M4 retransmission */
|
||||
break;
|
||||
case WIL_REKEY_M3_RECEIVED:
|
||||
vif->ptk_rekey_state = WIL_REKEY_IDLE;
|
||||
break;
|
||||
case WIL_REKEY_WAIT_M4_SENT:
|
||||
q = true;
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unknown rekey state = %d",
|
||||
vif->ptk_rekey_state);
|
||||
}
|
||||
spin_unlock_bh(&wil->eap_lock);
|
||||
|
||||
if (q) {
|
||||
q = queue_work(wil->wmi_wq, &vif->enable_tx_key_worker);
|
||||
wil_dbg_misc(wil, "queue_work of enable_tx_key_worker -> %d\n",
|
||||
q);
|
||||
}
|
||||
}
|
||||
|
||||
static void wil_rx_handle_eapol(struct wil6210_vif *vif, struct sk_buff *skb)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_STATION ||
|
||||
!test_bit(WMI_FW_CAPABILITY_SPLIT_REKEY, wil->fw_capabilities))
|
||||
return;
|
||||
|
||||
/* check if skb is a EAP message 3/4 */
|
||||
if (!wil_skb_is_eap_3(wil, skb))
|
||||
return;
|
||||
|
||||
if (vif->ptk_rekey_state == WIL_REKEY_IDLE)
|
||||
vif->ptk_rekey_state = WIL_REKEY_M3_RECEIVED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass Rx packet to the netif. Update statistics.
|
||||
* Called in softirq context (NAPI poll).
|
||||
*/
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid,
|
||||
struct wil_net_stats *stats, bool gro)
|
||||
{
|
||||
gro_result_t rc = GRO_NORMAL;
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
unsigned int len = skb->len;
|
||||
int cid;
|
||||
int security;
|
||||
u8 *sa, *da = wil_skb_get_da(skb);
|
||||
/* here looking for DA, not A1, thus Rxdesc's 'mcast' indication
|
||||
* is not suitable, need to look at data
|
||||
*/
|
||||
int mcast = is_multicast_ether_addr(da);
|
||||
struct wil_net_stats *stats;
|
||||
struct sk_buff *xmit_skb = NULL;
|
||||
static const char * const gro_res_str[] = {
|
||||
[GRO_MERGED] = "GRO_MERGED",
|
||||
|
@ -753,25 +927,6 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
[GRO_CONSUMED] = "GRO_CONSUMED",
|
||||
};
|
||||
|
||||
wil->txrx_ops.get_netif_rx_params(skb, &cid, &security);
|
||||
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) {
|
||||
rc = GRO_DROP;
|
||||
dev_kfree_skb(skb);
|
||||
stats->rx_replay++;
|
||||
goto stats;
|
||||
}
|
||||
|
||||
/* check errors reported by HW and update statistics */
|
||||
if (unlikely(wil->txrx_ops.rx_error_check(wil, skb, stats))) {
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wdev->iftype == NL80211_IFTYPE_STATION) {
|
||||
sa = wil_skb_get_sa(skb);
|
||||
if (mcast && ether_addr_equal(sa, ndev->dev_addr)) {
|
||||
|
@ -817,7 +972,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
if (skb) { /* deliver to local stack */
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
skb->dev = ndev;
|
||||
rc = napi_gro_receive(&wil->napi_rx, skb);
|
||||
|
||||
if (skb->protocol == cpu_to_be16(ETH_P_PAE))
|
||||
wil_rx_handle_eapol(vif, skb);
|
||||
|
||||
if (gro)
|
||||
rc = napi_gro_receive(&wil->napi_rx, skb);
|
||||
else
|
||||
netif_rx_ni(skb);
|
||||
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
|
||||
len, gro_res_str[rc]);
|
||||
}
|
||||
|
@ -837,6 +999,36 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
}
|
||||
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
int cid, security;
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct wil_net_stats *stats;
|
||||
|
||||
wil->txrx_ops.get_netif_rx_params(skb, &cid, &security);
|
||||
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) {
|
||||
dev_kfree_skb(skb);
|
||||
ndev->stats.rx_dropped++;
|
||||
stats->rx_replay++;
|
||||
stats->rx_dropped++;
|
||||
wil_dbg_txrx(wil, "Rx drop %d bytes\n", skb->len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check errors reported by HW and update statistics */
|
||||
if (unlikely(wil->txrx_ops.rx_error_check(wil, skb, stats))) {
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
wil_netif_rx(skb, ndev, cid, stats, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceed all completed skb's from Rx VRING
|
||||
*
|
||||
|
@ -2320,6 +2512,10 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid)
|
|||
if (stats)
|
||||
stats->tx_errors++;
|
||||
}
|
||||
|
||||
if (skb->protocol == cpu_to_be16(ETH_P_PAE))
|
||||
wil_tx_complete_handle_eapol(vif, skb);
|
||||
|
||||
wil_consume_skb(skb, d->dma.error == 0);
|
||||
}
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
|
|
@ -423,6 +423,46 @@ struct vring_rx_mac {
|
|||
#define RX_DMA_STATUS_PHY_INFO BIT(6)
|
||||
#define RX_DMA_STATUS_FFM BIT(7) /* EtherType Flex Filter Match */
|
||||
|
||||
/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
|
||||
#define WIL_KEY_INFO_KEY_TYPE BIT(3) /* val of 1 = Pairwise, 0 = Group key */
|
||||
|
||||
#define WIL_KEY_INFO_MIC BIT(8)
|
||||
#define WIL_KEY_INFO_ENCR_KEY_DATA BIT(12) /* for rsn only */
|
||||
|
||||
#define WIL_EAP_NONCE_LEN 32
|
||||
#define WIL_EAP_KEY_RSC_LEN 8
|
||||
#define WIL_EAP_REPLAY_COUNTER_LEN 8
|
||||
#define WIL_EAP_KEY_IV_LEN 16
|
||||
#define WIL_EAP_KEY_ID_LEN 8
|
||||
|
||||
enum {
|
||||
WIL_1X_TYPE_EAP_PACKET = 0,
|
||||
WIL_1X_TYPE_EAPOL_START = 1,
|
||||
WIL_1X_TYPE_EAPOL_LOGOFF = 2,
|
||||
WIL_1X_TYPE_EAPOL_KEY = 3,
|
||||
};
|
||||
|
||||
#define WIL_EAPOL_KEY_TYPE_RSN 2
|
||||
#define WIL_EAPOL_KEY_TYPE_WPA 254
|
||||
|
||||
struct wil_1x_hdr {
|
||||
u8 version;
|
||||
u8 type;
|
||||
__be16 length;
|
||||
/* followed by data */
|
||||
} __packed;
|
||||
|
||||
struct wil_eapol_key {
|
||||
u8 type;
|
||||
__be16 key_info;
|
||||
__be16 key_length;
|
||||
u8 replay_counter[WIL_EAP_REPLAY_COUNTER_LEN];
|
||||
u8 key_nonce[WIL_EAP_NONCE_LEN];
|
||||
u8 key_iv[WIL_EAP_KEY_IV_LEN];
|
||||
u8 key_rsc[WIL_EAP_KEY_RSC_LEN];
|
||||
u8 key_id[WIL_EAP_KEY_ID_LEN];
|
||||
} __packed;
|
||||
|
||||
struct vring_rx_dma {
|
||||
u32 d0;
|
||||
struct wil_ring_dma_addr addr;
|
||||
|
@ -646,6 +686,8 @@ static inline void wil_skb_set_cid(struct sk_buff *skb, u8 cid)
|
|||
}
|
||||
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
|
||||
void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid,
|
||||
struct wil_net_stats *stats, bool gro);
|
||||
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
|
||||
void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
u8 cid, u8 tid, u16 seq);
|
||||
|
|
|
@ -221,10 +221,17 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
|
|||
}
|
||||
|
||||
static inline
|
||||
void wil_get_next_rx_status_msg(struct wil_status_ring *sring, void *msg)
|
||||
void wil_get_next_rx_status_msg(struct wil_status_ring *sring, u8 *dr_bit,
|
||||
void *msg)
|
||||
{
|
||||
memcpy(msg, (void *)(sring->va + (sring->elem_size * sring->swhead)),
|
||||
sring->elem_size);
|
||||
struct wil_rx_status_compressed *_msg;
|
||||
|
||||
_msg = (struct wil_rx_status_compressed *)
|
||||
(sring->va + (sring->elem_size * sring->swhead));
|
||||
*dr_bit = WIL_GET_BITS(_msg->d0, 31, 31);
|
||||
/* make sure dr_bit is read before the rest of status msg */
|
||||
rmb();
|
||||
memcpy(msg, (void *)_msg, sring->elem_size);
|
||||
}
|
||||
|
||||
static inline void wil_sring_advance_swhead(struct wil_status_ring *sring)
|
||||
|
@ -587,8 +594,7 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil)
|
|||
if (!sring->va)
|
||||
continue;
|
||||
|
||||
wil_get_next_rx_status_msg(sring, msg);
|
||||
dr_bit = wil_rx_status_get_desc_rdy_bit(msg);
|
||||
wil_get_next_rx_status_msg(sring, &dr_bit, msg);
|
||||
|
||||
/* Check if there are unhandled RX status messages */
|
||||
if (dr_bit == sring->desc_rdy_pol)
|
||||
|
@ -878,8 +884,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
|
|||
BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb));
|
||||
|
||||
again:
|
||||
wil_get_next_rx_status_msg(sring, msg);
|
||||
dr_bit = wil_rx_status_get_desc_rdy_bit(msg);
|
||||
wil_get_next_rx_status_msg(sring, &dr_bit, msg);
|
||||
|
||||
/* Completed handling all the ready status messages */
|
||||
if (dr_bit != sring->desc_rdy_pol)
|
||||
|
@ -959,8 +964,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
|
|||
}
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN)) {
|
||||
wil_dbg_txrx(wil, "Short frame, len = %d\n", skb->len);
|
||||
if (unlikely(dmalen < ETH_HLEN)) {
|
||||
wil_dbg_txrx(wil, "Short frame, len = %d\n", dmalen);
|
||||
stats->rx_short_frame++;
|
||||
rxdata->skipping = true;
|
||||
goto skipping;
|
||||
|
@ -1023,6 +1028,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
|
|||
stats->last_mcs_rx = wil_rx_status_get_mcs(msg);
|
||||
if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
|
||||
stats->rx_per_mcs[stats->last_mcs_rx]++;
|
||||
|
||||
stats->last_cb_mode_rx = wil_rx_status_get_cb_mode(msg);
|
||||
}
|
||||
|
||||
if (!wil->use_rx_hw_reordering && !wil->use_compressed_rx_status &&
|
||||
|
@ -1133,12 +1140,15 @@ static int wil_tx_desc_map_edma(union wil_tx_desc *desc,
|
|||
}
|
||||
|
||||
static inline void
|
||||
wil_get_next_tx_status_msg(struct wil_status_ring *sring,
|
||||
wil_get_next_tx_status_msg(struct wil_status_ring *sring, u8 *dr_bit,
|
||||
struct wil_ring_tx_status *msg)
|
||||
{
|
||||
struct wil_ring_tx_status *_msg = (struct wil_ring_tx_status *)
|
||||
(sring->va + (sring->elem_size * sring->swhead));
|
||||
|
||||
*dr_bit = _msg->desc_ready >> TX_STATUS_DESC_READY_POS;
|
||||
/* make sure dr_bit is read before the rest of status msg */
|
||||
rmb();
|
||||
*msg = *_msg;
|
||||
}
|
||||
|
||||
|
@ -1167,8 +1177,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
|
|||
int used_before_complete;
|
||||
int used_new;
|
||||
|
||||
wil_get_next_tx_status_msg(sring, &msg);
|
||||
dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS;
|
||||
wil_get_next_tx_status_msg(sring, &dr_bit, &msg);
|
||||
|
||||
/* Process completion messages while DR bit has the expected polarity */
|
||||
while (dr_bit == sring->desc_rdy_pol) {
|
||||
|
@ -1255,6 +1264,10 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
|
|||
if (stats)
|
||||
stats->tx_errors++;
|
||||
}
|
||||
|
||||
if (skb->protocol == cpu_to_be16(ETH_P_PAE))
|
||||
wil_tx_complete_handle_eapol(vif, skb);
|
||||
|
||||
wil_consume_skb(skb, msg.status == 0);
|
||||
}
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
@ -1287,8 +1300,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
|
|||
|
||||
wil_sring_advance_swhead(sring);
|
||||
|
||||
wil_get_next_tx_status_msg(sring, &msg);
|
||||
dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS;
|
||||
wil_get_next_tx_status_msg(sring, &dr_bit, &msg);
|
||||
}
|
||||
|
||||
/* shall we wake net queues? */
|
||||
|
|
|
@ -366,6 +366,12 @@ static inline u8 wil_rx_status_get_mcs(void *msg)
|
|||
16, 21);
|
||||
}
|
||||
|
||||
static inline u8 wil_rx_status_get_cb_mode(void *msg)
|
||||
{
|
||||
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
|
||||
22, 23);
|
||||
}
|
||||
|
||||
static inline u16 wil_rx_status_get_flow_id(void *msg)
|
||||
{
|
||||
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
|
||||
|
@ -415,12 +421,6 @@ static inline u8 wil_rx_status_get_tid(void *msg)
|
|||
return val & WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK;
|
||||
}
|
||||
|
||||
static inline int wil_rx_status_get_desc_rdy_bit(void *msg)
|
||||
{
|
||||
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
|
||||
31, 31);
|
||||
}
|
||||
|
||||
static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */
|
||||
{
|
||||
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
|
||||
|
|
|
@ -590,6 +590,7 @@ struct wil_net_stats {
|
|||
unsigned long rx_amsdu_error; /* eDMA specific */
|
||||
unsigned long rx_csum_err;
|
||||
u16 last_mcs_rx;
|
||||
u8 last_cb_mode_rx;
|
||||
u64 rx_per_mcs[WIL_MCS_MAX + 1];
|
||||
u32 ft_roams; /* relevant in STA mode */
|
||||
};
|
||||
|
@ -730,6 +731,12 @@ enum wil_sta_status {
|
|||
wil_sta_connected = 2,
|
||||
};
|
||||
|
||||
enum wil_rekey_state {
|
||||
WIL_REKEY_IDLE = 0,
|
||||
WIL_REKEY_M3_RECEIVED = 1,
|
||||
WIL_REKEY_WAIT_M4_SENT = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wil_sta_info - data for peer
|
||||
*
|
||||
|
@ -850,6 +857,7 @@ struct wil6210_vif {
|
|||
DECLARE_BITMAP(status, wil_vif_status_last);
|
||||
u32 privacy; /* secure connection? */
|
||||
u16 channel; /* relevant in AP mode */
|
||||
u8 wmi_edmg_channel; /* relevant in AP mode */
|
||||
u8 hidden_ssid; /* relevant in AP mode */
|
||||
u32 ap_isolate; /* no intra-BSS communication */
|
||||
bool pbss;
|
||||
|
@ -877,6 +885,10 @@ struct wil6210_vif {
|
|||
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
|
||||
bool fw_stats_ready; /* per-cid statistics are ready inside sta_info */
|
||||
u64 fw_stats_tsf; /* measurement timestamp */
|
||||
|
||||
/* PTK rekey race prevention, this is relevant to station mode only */
|
||||
enum wil_rekey_state ptk_rekey_state;
|
||||
struct work_struct enable_tx_key_worker;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -977,6 +989,7 @@ struct wil6210_priv {
|
|||
*/
|
||||
spinlock_t wmi_ev_lock;
|
||||
spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
|
||||
spinlock_t eap_lock; /* guarding access to eap rekey fields */
|
||||
struct napi_struct napi_rx;
|
||||
struct napi_struct napi_tx;
|
||||
struct net_device napi_ndev; /* dummy net_device serving all VIFs */
|
||||
|
@ -1144,7 +1157,7 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val)
|
|||
/**
|
||||
* wil_cid_valid - check cid is valid
|
||||
*/
|
||||
static inline bool wil_cid_valid(struct wil6210_priv *wil, u8 cid)
|
||||
static inline bool wil_cid_valid(struct wil6210_priv *wil, int cid)
|
||||
{
|
||||
return (cid >= 0 && cid < wil->max_assoc_sta);
|
||||
}
|
||||
|
@ -1224,6 +1237,7 @@ int __wil_down(struct wil6210_priv *wil);
|
|||
void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac);
|
||||
int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx);
|
||||
void wil_set_ethtoolops(struct net_device *ndev);
|
||||
|
||||
struct fw_map *wil_find_fw_mapping(const char *section);
|
||||
|
@ -1335,7 +1349,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil);
|
|||
|
||||
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
|
||||
int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan,
|
||||
u8 hidden_ssid, u8 is_go);
|
||||
u8 edmg_chan, u8 hidden_ssid, u8 is_go);
|
||||
int wmi_pcp_stop(struct wil6210_vif *vif);
|
||||
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
|
||||
int wmi_abort_scan(struct wil6210_vif *vif);
|
||||
|
@ -1349,6 +1363,7 @@ void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid,
|
|||
void wil_probe_client_flush(struct wil6210_vif *vif);
|
||||
void wil_probe_client_worker(struct work_struct *work);
|
||||
void wil_disconnect_worker(struct work_struct *work);
|
||||
void wil_enable_tx_key_worker(struct work_struct *work);
|
||||
|
||||
void wil_init_txrx_ops(struct wil6210_priv *wil);
|
||||
|
||||
|
@ -1365,6 +1380,8 @@ void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
|||
struct wil_ring *ring, bool check_stop);
|
||||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
int wil_tx_complete(struct wil6210_vif *vif, int ringid);
|
||||
void wil_tx_complete_handle_eapol(struct wil6210_vif *vif,
|
||||
struct sk_buff *skb);
|
||||
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
|
||||
void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil);
|
||||
|
||||
|
@ -1412,6 +1429,10 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
|
|||
u8 channel, u16 duration_ms);
|
||||
int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold);
|
||||
|
||||
int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch);
|
||||
int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch);
|
||||
void wil_update_supported_bands(struct wil6210_priv *wil);
|
||||
|
||||
int reverse_memcmp(const void *cs, const void *ct, size_t count);
|
||||
|
||||
/* WMI for enhanced DMA */
|
||||
|
|
|
@ -878,6 +878,12 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
|
|||
|
||||
if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
|
||||
struct cfg80211_bss *bss;
|
||||
struct cfg80211_inform_bss bss_data = {
|
||||
.chan = channel,
|
||||
.scan_width = NL80211_BSS_CHAN_WIDTH_20,
|
||||
.signal = signal,
|
||||
.boottime_ns = ktime_to_ns(ktime_get_boottime()),
|
||||
};
|
||||
u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
|
||||
u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
|
||||
u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
|
||||
|
@ -892,8 +898,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
|
|||
|
||||
wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
|
||||
|
||||
bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
|
||||
d_len, signal, GFP_KERNEL);
|
||||
bss = cfg80211_inform_bss_frame_data(wiphy, &bss_data,
|
||||
rx_mgmt_frame,
|
||||
d_len, GFP_KERNEL);
|
||||
if (bss) {
|
||||
wil_dbg_wmi(wil, "Added BSS %pM\n",
|
||||
rx_mgmt_frame->bssid);
|
||||
|
@ -1332,6 +1339,12 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
cid = evt->cid;
|
||||
tid = evt->tid;
|
||||
}
|
||||
|
||||
if (!wil_cid_valid(wil, cid)) {
|
||||
wil_err(wil, "DELBA: Invalid CID %d\n", cid);
|
||||
return;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil, "DELBA MID %d CID %d TID %d from %s reason %d\n",
|
||||
vif->mid, cid, tid,
|
||||
evt->from_initiator ? "originator" : "recipient",
|
||||
|
@ -1385,6 +1398,10 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len)
|
|||
__le16 fc;
|
||||
u32 d_len;
|
||||
struct cfg80211_bss *bss;
|
||||
struct cfg80211_inform_bss bss_data = {
|
||||
.scan_width = NL80211_BSS_CHAN_WIDTH_20,
|
||||
.boottime_ns = ktime_to_ns(ktime_get_boottime()),
|
||||
};
|
||||
|
||||
if (flen < 0) {
|
||||
wil_err(wil, "sched scan result event too short, len %d\n",
|
||||
|
@ -1427,8 +1444,10 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len)
|
|||
return;
|
||||
}
|
||||
|
||||
bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
|
||||
d_len, signal, GFP_KERNEL);
|
||||
bss_data.signal = signal;
|
||||
bss_data.chan = channel;
|
||||
bss = cfg80211_inform_bss_frame_data(wiphy, &bss_data, rx_mgmt_frame,
|
||||
d_len, GFP_KERNEL);
|
||||
if (bss) {
|
||||
wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
|
@ -2163,8 +2182,8 @@ int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wmi_pcp_start(struct wil6210_vif *vif,
|
||||
int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
|
||||
int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype,
|
||||
u8 chan, u8 wmi_edmg_chan, u8 hidden_ssid, u8 is_go)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
|
@ -2174,6 +2193,7 @@ int wmi_pcp_start(struct wil6210_vif *vif,
|
|||
.network_type = wmi_nettype,
|
||||
.disable_sec_offload = 1,
|
||||
.channel = chan - 1,
|
||||
.edmg_channel = wmi_edmg_chan,
|
||||
.pcp_max_assoc_sta = wil->max_assoc_sta,
|
||||
.hidden_ssid = hidden_ssid,
|
||||
.is_go = is_go,
|
||||
|
@ -2437,10 +2457,17 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
|
|||
.key_len = key_len,
|
||||
};
|
||||
|
||||
if (!key || (key_len > sizeof(cmd.key)))
|
||||
if (key_len > sizeof(cmd.key))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(cmd.key, key, key_len);
|
||||
/* key len = 0 is allowed only for usage of WMI_KEY_USE_APPLY */
|
||||
if ((key_len == 0 || !key) &&
|
||||
key_usage != WMI_KEY_USE_APPLY_PTK)
|
||||
return -EINVAL;
|
||||
|
||||
if (key)
|
||||
memcpy(cmd.key, key, key_len);
|
||||
|
||||
if (mac_addr)
|
||||
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ enum wmi_fw_capability {
|
|||
WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13,
|
||||
WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14,
|
||||
WMI_FW_CAPABILITY_PNO = 15,
|
||||
WMI_FW_CAPABILITY_CHANNEL_BONDING = 17,
|
||||
WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18,
|
||||
WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19,
|
||||
WMI_FW_CAPABILITY_MULTI_VIFS = 20,
|
||||
|
@ -108,6 +109,7 @@ enum wmi_fw_capability {
|
|||
WMI_FW_CAPABILITY_CHANNEL_4 = 26,
|
||||
WMI_FW_CAPABILITY_IPA = 27,
|
||||
WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF = 30,
|
||||
WMI_FW_CAPABILITY_SPLIT_REKEY = 31,
|
||||
WMI_FW_CAPABILITY_MAX,
|
||||
};
|
||||
|
||||
|
@ -361,6 +363,19 @@ enum wmi_connect_ctrl_flag_bits {
|
|||
|
||||
#define WMI_MAX_SSID_LEN (32)
|
||||
|
||||
enum wmi_channel {
|
||||
WMI_CHANNEL_1 = 0x00,
|
||||
WMI_CHANNEL_2 = 0x01,
|
||||
WMI_CHANNEL_3 = 0x02,
|
||||
WMI_CHANNEL_4 = 0x03,
|
||||
WMI_CHANNEL_5 = 0x04,
|
||||
WMI_CHANNEL_6 = 0x05,
|
||||
WMI_CHANNEL_9 = 0x06,
|
||||
WMI_CHANNEL_10 = 0x07,
|
||||
WMI_CHANNEL_11 = 0x08,
|
||||
WMI_CHANNEL_12 = 0x09,
|
||||
};
|
||||
|
||||
/* WMI_CONNECT_CMDID */
|
||||
struct wmi_connect_cmd {
|
||||
u8 network_type;
|
||||
|
@ -372,8 +387,12 @@ struct wmi_connect_cmd {
|
|||
u8 group_crypto_len;
|
||||
u8 ssid_len;
|
||||
u8 ssid[WMI_MAX_SSID_LEN];
|
||||
/* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is
|
||||
* the primary channel number
|
||||
*/
|
||||
u8 channel;
|
||||
u8 reserved0;
|
||||
/* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */
|
||||
u8 edmg_channel;
|
||||
u8 bssid[WMI_MAC_LEN];
|
||||
__le32 ctrl_flags;
|
||||
u8 dst_mac[WMI_MAC_LEN];
|
||||
|
@ -403,6 +422,8 @@ enum wmi_key_usage {
|
|||
WMI_KEY_USE_PAIRWISE = 0x00,
|
||||
WMI_KEY_USE_RX_GROUP = 0x01,
|
||||
WMI_KEY_USE_TX_GROUP = 0x02,
|
||||
WMI_KEY_USE_STORE_PTK = 0x03,
|
||||
WMI_KEY_USE_APPLY_PTK = 0x04,
|
||||
};
|
||||
|
||||
struct wmi_add_cipher_key_cmd {
|
||||
|
@ -2312,8 +2333,12 @@ struct wmi_notify_req_done_event {
|
|||
|
||||
/* WMI_CONNECT_EVENTID */
|
||||
struct wmi_connect_event {
|
||||
/* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is
|
||||
* the primary channel number
|
||||
*/
|
||||
u8 channel;
|
||||
u8 reserved0;
|
||||
/* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */
|
||||
u8 edmg_channel;
|
||||
u8 bssid[WMI_MAC_LEN];
|
||||
__le16 listen_interval;
|
||||
__le16 beacon_interval;
|
||||
|
|
Loading…
Reference in New Issue