mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 10:33:41 +02:00
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for v5.19. Major changes: ath11k * enable keepalive during WoWLAN suspend * implement remain-on-channel support
This commit is contained in:
commit
d93185a929
|
|
@ -1233,6 +1233,7 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
|
|||
static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
char boardname[100];
|
||||
|
||||
if (bd_ie_type == ATH10K_BD_IE_BOARD) {
|
||||
if (!ar->hw_params.fw.board) {
|
||||
|
|
@ -1240,9 +1241,19 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin",
|
||||
ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
|
||||
|
||||
ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
boardname);
|
||||
if (IS_ERR(ar->normal_mode_fw.board)) {
|
||||
fw = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
ar->normal_mode_fw.board = fw;
|
||||
}
|
||||
|
||||
if (IS_ERR(ar->normal_mode_fw.board))
|
||||
return PTR_ERR(ar->normal_mode_fw.board);
|
||||
|
||||
|
|
|
|||
|
|
@ -2692,8 +2692,10 @@ static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
|
|||
static enum wmi_phy_mode ath10k_mac_get_phymode_vht(struct ath10k *ar,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
|
||||
|
||||
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) {
|
||||
switch (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||
switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||
return MODE_11AC_VHT160;
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
|
||||
|
|
@ -6926,6 +6928,9 @@ static int ath10k_mac_validate_rate_mask(struct ath10k *ar,
|
|||
struct ieee80211_sta *sta,
|
||||
u32 rate_ctrl_flag, u8 nss)
|
||||
{
|
||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
|
||||
|
||||
if (nss > sta->deflink.rx_nss) {
|
||||
ath10k_warn(ar, "Invalid nss field, configured %u limit %u\n",
|
||||
nss, sta->deflink.rx_nss);
|
||||
|
|
@ -6933,19 +6938,19 @@ static int ath10k_mac_validate_rate_mask(struct ath10k *ar,
|
|||
}
|
||||
|
||||
if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_VHT) {
|
||||
if (!sta->deflink.vht_cap.vht_supported) {
|
||||
if (!vht_cap->vht_supported) {
|
||||
ath10k_warn(ar, "Invalid VHT rate for sta %pM\n",
|
||||
sta->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_HT) {
|
||||
if (!sta->deflink.ht_cap.ht_supported || sta->deflink.vht_cap.vht_supported) {
|
||||
if (!ht_cap->ht_supported || vht_cap->vht_supported) {
|
||||
ath10k_warn(ar, "Invalid HT rate for sta %pM\n",
|
||||
sta->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (sta->deflink.ht_cap.ht_supported || sta->deflink.vht_cap.vht_supported)
|
||||
if (ht_cap->ht_supported || vht_cap->vht_supported)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/iommu.h>
|
||||
#include "ahb.h"
|
||||
#include "debug.h"
|
||||
#include "hif.h"
|
||||
|
|
@ -757,6 +759,172 @@ static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
|
||||
{
|
||||
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
|
||||
struct device *dev = ab->dev;
|
||||
struct device_node *node;
|
||||
struct resource r;
|
||||
int ret;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
ret = of_address_to_resource(node, 0, &r);
|
||||
of_node_put(node);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to resolve msa fixed region\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ab_ahb->fw.msa_paddr = r.start;
|
||||
ab_ahb->fw.msa_size = resource_size(&r);
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 1);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
ret = of_address_to_resource(node, 0, &r);
|
||||
of_node_put(node);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to resolve ce fixed region\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ab_ahb->fw.ce_paddr = r.start;
|
||||
ab_ahb->fw.ce_size = resource_size(&r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
|
||||
{
|
||||
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
|
||||
struct device *host_dev = ab->dev;
|
||||
struct platform_device_info info = {0};
|
||||
struct iommu_domain *iommu_dom;
|
||||
struct platform_device *pdev;
|
||||
struct device_node *node;
|
||||
int ret;
|
||||
|
||||
/* Chipsets not requiring MSA need not initialize
|
||||
* MSA resources, return success in such cases.
|
||||
*/
|
||||
if (!ab->hw_params.fixed_fw_mem)
|
||||
return 0;
|
||||
|
||||
ret = ath11k_ahb_setup_msa_resources(ab);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "failed to setup msa resources\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
|
||||
if (!node) {
|
||||
ab_ahb->fw.use_tz = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
info.fwnode = &node->fwnode;
|
||||
info.parent = host_dev;
|
||||
info.name = node->name;
|
||||
info.dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
pdev = platform_device_register_full(&info);
|
||||
if (IS_ERR(pdev)) {
|
||||
of_node_put(node);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
ret = of_dma_configure(&pdev->dev, node, true);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "dma configure fail: %d\n", ret);
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ab_ahb->fw.dev = &pdev->dev;
|
||||
|
||||
iommu_dom = iommu_domain_alloc(&platform_bus_type);
|
||||
if (!iommu_dom) {
|
||||
ath11k_err(ab, "failed to allocate iommu domain\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ret = iommu_attach_device(iommu_dom, ab_ahb->fw.dev);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "could not attach device: %d\n", ret);
|
||||
goto err_iommu_free;
|
||||
}
|
||||
|
||||
ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,
|
||||
ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,
|
||||
IOMMU_READ | IOMMU_WRITE);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "failed to map firmware region: %d\n", ret);
|
||||
goto err_iommu_detach;
|
||||
}
|
||||
|
||||
ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,
|
||||
ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,
|
||||
IOMMU_READ | IOMMU_WRITE);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);
|
||||
goto err_iommu_unmap;
|
||||
}
|
||||
|
||||
ab_ahb->fw.use_tz = false;
|
||||
ab_ahb->fw.iommu_domain = iommu_dom;
|
||||
of_node_put(node);
|
||||
|
||||
return 0;
|
||||
|
||||
err_iommu_unmap:
|
||||
iommu_unmap(iommu_dom, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
|
||||
|
||||
err_iommu_detach:
|
||||
iommu_detach_device(iommu_dom, ab_ahb->fw.dev);
|
||||
|
||||
err_iommu_free:
|
||||
iommu_domain_free(iommu_dom);
|
||||
|
||||
err_unregister:
|
||||
platform_device_unregister(pdev);
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
|
||||
{
|
||||
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
|
||||
struct iommu_domain *iommu;
|
||||
size_t unmapped_size;
|
||||
|
||||
if (ab_ahb->fw.use_tz)
|
||||
return 0;
|
||||
|
||||
iommu = ab_ahb->fw.iommu_domain;
|
||||
|
||||
unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
|
||||
if (unmapped_size != ab_ahb->fw.msa_size)
|
||||
ath11k_err(ab, "failed to unmap firmware: %zu\n",
|
||||
unmapped_size);
|
||||
|
||||
unmapped_size = iommu_unmap(iommu, ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size);
|
||||
if (unmapped_size != ab_ahb->fw.ce_size)
|
||||
ath11k_err(ab, "failed to unmap firmware CE memory: %zu\n",
|
||||
unmapped_size);
|
||||
|
||||
iommu_detach_device(iommu, ab_ahb->fw.dev);
|
||||
iommu_domain_free(iommu);
|
||||
|
||||
platform_device_unregister(to_platform_device(ab_ahb->fw.dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath11k_ahb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ath11k_base *ab;
|
||||
|
|
@ -816,10 +984,14 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_core_free;
|
||||
|
||||
ret = ath11k_hal_srng_init(ab);
|
||||
ret = ath11k_ahb_fw_resources_init(ab);
|
||||
if (ret)
|
||||
goto err_core_free;
|
||||
|
||||
ret = ath11k_hal_srng_init(ab);
|
||||
if (ret)
|
||||
goto err_fw_deinit;
|
||||
|
||||
ret = ath11k_ce_alloc_pipes(ab);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
|
||||
|
|
@ -856,6 +1028,9 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
|
|||
err_hal_srng_deinit:
|
||||
ath11k_hal_srng_deinit(ab);
|
||||
|
||||
err_fw_deinit:
|
||||
ath11k_ahb_fw_resource_deinit(ab);
|
||||
|
||||
err_core_free:
|
||||
ath11k_core_free(ab);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
|
@ -891,6 +1066,7 @@ static int ath11k_ahb_remove(struct platform_device *pdev)
|
|||
qmi_fail:
|
||||
ath11k_ahb_free_irq(ab);
|
||||
ath11k_hal_srng_deinit(ab);
|
||||
ath11k_ahb_fw_resource_deinit(ab);
|
||||
ath11k_ce_free_pipes(ab);
|
||||
ath11k_core_free(ab);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@ struct ath11k_base;
|
|||
|
||||
struct ath11k_ahb {
|
||||
struct rproc *tgt_rproc;
|
||||
struct {
|
||||
struct device *dev;
|
||||
struct iommu_domain *iommu_domain;
|
||||
dma_addr_t msa_paddr;
|
||||
u32 msa_size;
|
||||
dma_addr_t ce_paddr;
|
||||
u32 ce_size;
|
||||
bool use_tz;
|
||||
} fw;
|
||||
};
|
||||
|
||||
static inline struct ath11k_ahb *ath11k_ahb_priv(struct ath11k_base *ab)
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 0,
|
||||
.ce_window_idx = 0,
|
||||
.fixed_fw_mem = false,
|
||||
.support_off_channel_tx = false,
|
||||
},
|
||||
{
|
||||
.hw_rev = ATH11K_HW_IPQ6018_HW10,
|
||||
|
|
@ -185,6 +186,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 0,
|
||||
.ce_window_idx = 0,
|
||||
.fixed_fw_mem = false,
|
||||
.support_off_channel_tx = false,
|
||||
},
|
||||
{
|
||||
.name = "qca6390 hw2.0",
|
||||
|
|
@ -259,6 +261,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 0,
|
||||
.ce_window_idx = 0,
|
||||
.fixed_fw_mem = false,
|
||||
.support_off_channel_tx = true,
|
||||
},
|
||||
{
|
||||
.name = "qcn9074 hw1.0",
|
||||
|
|
@ -333,6 +336,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 3,
|
||||
.ce_window_idx = 2,
|
||||
.fixed_fw_mem = false,
|
||||
.support_off_channel_tx = false,
|
||||
},
|
||||
{
|
||||
.name = "wcn6855 hw2.0",
|
||||
|
|
@ -407,6 +411,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 0,
|
||||
.ce_window_idx = 0,
|
||||
.fixed_fw_mem = false,
|
||||
.support_off_channel_tx = true,
|
||||
},
|
||||
{
|
||||
.name = "wcn6855 hw2.1",
|
||||
|
|
@ -480,6 +485,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 0,
|
||||
.ce_window_idx = 0,
|
||||
.fixed_fw_mem = false,
|
||||
.support_off_channel_tx = true,
|
||||
},
|
||||
{
|
||||
.name = "wcn6750 hw1.0",
|
||||
|
|
@ -553,6 +559,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||
.dp_window_idx = 1,
|
||||
.ce_window_idx = 2,
|
||||
.fixed_fw_mem = true,
|
||||
.support_off_channel_tx = false,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1620,9 +1627,11 @@ static void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)
|
|||
|
||||
ieee80211_stop_queues(ar->hw);
|
||||
ath11k_mac_drain_tx(ar);
|
||||
ar->state_11d = ATH11K_11D_IDLE;
|
||||
complete(&ar->completed_11d_scan);
|
||||
complete(&ar->scan.started);
|
||||
complete(&ar->scan.completed);
|
||||
complete(&ar->scan.on_channel);
|
||||
complete(&ar->peer_assoc_done);
|
||||
complete(&ar->peer_delete_done);
|
||||
complete(&ar->install_key_done);
|
||||
|
|
@ -1768,7 +1777,6 @@ static void ath11k_core_reset(struct work_struct *work)
|
|||
ATH11K_RECOVER_START_TIMEOUT_HZ);
|
||||
|
||||
ath11k_hif_power_down(ab);
|
||||
ath11k_qmi_free_resource(ab);
|
||||
ath11k_hif_power_up(ab);
|
||||
|
||||
ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n");
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ struct ath11k_base;
|
|||
#define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008
|
||||
#define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c
|
||||
#define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010
|
||||
#define HAL_REO1_MISC_CTL 0x00000630
|
||||
#define HAL_REO1_MISC_CTL(ab) ab->hw_params.regs->hal_reo1_misc_ctl
|
||||
#define HAL_REO1_RING_BASE_LSB(ab) ab->hw_params.regs->hal_reo1_ring_base_lsb
|
||||
#define HAL_REO1_RING_BASE_MSB(ab) ab->hw_params.regs->hal_reo1_ring_base_msb
|
||||
#define HAL_REO1_RING_ID(ab) ab->hw_params.regs->hal_reo1_ring_id
|
||||
|
|
|
|||
|
|
@ -771,10 +771,10 @@ static void ath11k_hw_wcn6855_reo_setup(struct ath11k_base *ab)
|
|||
FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1);
|
||||
ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val);
|
||||
|
||||
val = ath11k_hif_read32(ab, reo_base + HAL_REO1_MISC_CTL);
|
||||
val = ath11k_hif_read32(ab, reo_base + HAL_REO1_MISC_CTL(ab));
|
||||
val &= ~HAL_REO1_MISC_CTL_FRAGMENT_DST_RING;
|
||||
val |= FIELD_PREP(HAL_REO1_MISC_CTL_FRAGMENT_DST_RING, HAL_SRNG_RING_ID_REO2SW1);
|
||||
ath11k_hif_write32(ab, reo_base + HAL_REO1_MISC_CTL, val);
|
||||
ath11k_hif_write32(ab, reo_base + HAL_REO1_MISC_CTL(ab), val);
|
||||
|
||||
ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab),
|
||||
HAL_DEFAULT_REO_TIMEOUT_USEC);
|
||||
|
|
@ -1983,6 +1983,9 @@ const struct ath11k_hw_regs ipq8074_regs = {
|
|||
|
||||
/* Shadow register area */
|
||||
.hal_shadow_base_addr = 0x0,
|
||||
|
||||
/* REO misc control register, not used in IPQ8074 */
|
||||
.hal_reo1_misc_ctl = 0x0,
|
||||
};
|
||||
|
||||
const struct ath11k_hw_regs qca6390_regs = {
|
||||
|
|
@ -2065,6 +2068,9 @@ const struct ath11k_hw_regs qca6390_regs = {
|
|||
|
||||
/* Shadow register area */
|
||||
.hal_shadow_base_addr = 0x000008fc,
|
||||
|
||||
/* REO misc control register, not used in QCA6390 */
|
||||
.hal_reo1_misc_ctl = 0x0,
|
||||
};
|
||||
|
||||
const struct ath11k_hw_regs qcn9074_regs = {
|
||||
|
|
@ -2147,6 +2153,9 @@ const struct ath11k_hw_regs qcn9074_regs = {
|
|||
|
||||
/* Shadow register area */
|
||||
.hal_shadow_base_addr = 0x0,
|
||||
|
||||
/* REO misc control register, not used in QCN9074 */
|
||||
.hal_reo1_misc_ctl = 0x0,
|
||||
};
|
||||
|
||||
const struct ath11k_hw_regs wcn6855_regs = {
|
||||
|
|
@ -2229,6 +2238,11 @@ const struct ath11k_hw_regs wcn6855_regs = {
|
|||
|
||||
/* Shadow register area */
|
||||
.hal_shadow_base_addr = 0x000008fc,
|
||||
|
||||
/* REO misc control register, used for fragment
|
||||
* destination ring config in WCN6855.
|
||||
*/
|
||||
.hal_reo1_misc_ctl = 0x00000630,
|
||||
};
|
||||
|
||||
const struct ath11k_hw_regs wcn6750_regs = {
|
||||
|
|
@ -2311,6 +2325,11 @@ const struct ath11k_hw_regs wcn6750_regs = {
|
|||
|
||||
/* Shadow register area */
|
||||
.hal_shadow_base_addr = 0x00000504,
|
||||
|
||||
/* REO misc control register, used for fragment
|
||||
* destination ring config in WCN6750.
|
||||
*/
|
||||
.hal_reo1_misc_ctl = 0x000005d8,
|
||||
};
|
||||
|
||||
const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = {
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ struct ath11k_hw_params {
|
|||
u8 dp_window_idx;
|
||||
u8 ce_window_idx;
|
||||
bool fixed_fw_mem;
|
||||
bool support_off_channel_tx;
|
||||
};
|
||||
|
||||
struct ath11k_hw_ops {
|
||||
|
|
@ -379,6 +380,7 @@ struct ath11k_hw_regs {
|
|||
u32 pcie_pcs_osc_dtct_config_base;
|
||||
|
||||
u32 hal_shadow_base_addr;
|
||||
u32 hal_reo1_misc_ctl;
|
||||
};
|
||||
|
||||
extern const struct ath11k_hw_regs ipq8074_regs;
|
||||
|
|
|
|||
|
|
@ -1951,7 +1951,7 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
|
|||
/* Calculate peer NSS capability from VHT capabilities if STA
|
||||
* supports VHT.
|
||||
*/
|
||||
for (i = 0, max_nss = 0, vht_mcs = 0; i < NL80211_VHT_NSS_MAX; i++) {
|
||||
for (i = 0, max_nss = 0; i < NL80211_VHT_NSS_MAX; i++) {
|
||||
vht_mcs = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) >>
|
||||
(2 * i) & 3;
|
||||
|
||||
|
|
@ -2272,7 +2272,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
|
|||
/* Calculate peer NSS capability from HE capabilities if STA
|
||||
* supports HE.
|
||||
*/
|
||||
for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) {
|
||||
for (i = 0, max_nss = 0; i < NL80211_HE_NSS_MAX; i++) {
|
||||
he_mcs = he_tx_mcs >> (2 * i) & 3;
|
||||
|
||||
/* In case of fixed rates, MCS Range in he_tx_mcs might have
|
||||
|
|
@ -5551,8 +5551,8 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
arvif = ath11k_vif_to_arvif(skb_cb->vif);
|
||||
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
|
||||
arvif->is_started) {
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) {
|
||||
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n",
|
||||
|
|
@ -5570,6 +5570,7 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
|||
arvif->is_started);
|
||||
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
|
||||
}
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6155,6 +6156,11 @@ void ath11k_mac_11d_scan_stop(struct ath11k *ar)
|
|||
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n",
|
||||
ar->vdev_id_11d_scan);
|
||||
|
||||
if (ar->state_11d == ATH11K_11D_PREPARING) {
|
||||
ar->state_11d = ATH11K_11D_IDLE;
|
||||
complete(&ar->completed_11d_scan);
|
||||
}
|
||||
|
||||
if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) {
|
||||
vdev_id = ar->vdev_id_11d_scan;
|
||||
|
||||
|
|
@ -7741,6 +7747,7 @@ ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_b
|
|||
bool he_fixed_rate = false, vht_fixed_rate = false;
|
||||
struct ath11k_peer *peer, *tmp;
|
||||
const u16 *vht_mcs_mask, *he_mcs_mask;
|
||||
struct ieee80211_link_sta *deflink;
|
||||
u8 vht_nss, he_nss;
|
||||
bool ret = true;
|
||||
|
||||
|
|
@ -7763,13 +7770,16 @@ ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_b
|
|||
spin_lock_bh(&ar->ab->base_lock);
|
||||
list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) {
|
||||
if (peer->sta) {
|
||||
if (vht_fixed_rate && (!peer->sta->deflink.vht_cap.vht_supported ||
|
||||
peer->sta->deflink.rx_nss < vht_nss)) {
|
||||
deflink = &peer->sta->deflink;
|
||||
|
||||
if (vht_fixed_rate && (!deflink->vht_cap.vht_supported ||
|
||||
deflink->rx_nss < vht_nss)) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
if (he_fixed_rate && (!peer->sta->deflink.he_cap.has_he ||
|
||||
peer->sta->deflink.rx_nss < he_nss)) {
|
||||
|
||||
if (he_fixed_rate && (!deflink->he_cap.has_he ||
|
||||
deflink->rx_nss < he_nss)) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -8345,6 +8355,118 @@ static int ath11k_mac_op_set_bios_sar_specs(struct ieee80211_hw *hw,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ath11k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath11k *ar = hw->priv;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->scan.roc_notify = false;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ath11k_scan_abort(ar);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&ar->scan.timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan,
|
||||
int duration,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
struct ath11k *ar = hw->priv;
|
||||
struct ath11k_vif *arvif = (void *)vif->drv_priv;
|
||||
struct scan_req_params arg;
|
||||
int ret;
|
||||
u32 scan_time_msec;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
switch (ar->scan.state) {
|
||||
case ATH11K_SCAN_IDLE:
|
||||
reinit_completion(&ar->scan.started);
|
||||
reinit_completion(&ar->scan.completed);
|
||||
reinit_completion(&ar->scan.on_channel);
|
||||
ar->scan.state = ATH11K_SCAN_STARTING;
|
||||
ar->scan.is_roc = true;
|
||||
ar->scan.vdev_id = arvif->vdev_id;
|
||||
ar->scan.roc_freq = chan->center_freq;
|
||||
ar->scan.roc_notify = true;
|
||||
ret = 0;
|
||||
break;
|
||||
case ATH11K_SCAN_STARTING:
|
||||
case ATH11K_SCAN_RUNNING:
|
||||
case ATH11K_SCAN_ABORTING:
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
ath11k_wmi_start_scan_init(ar, &arg);
|
||||
arg.num_chan = 1;
|
||||
arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list),
|
||||
GFP_KERNEL);
|
||||
if (!arg.chan_list) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arg.vdev_id = arvif->vdev_id;
|
||||
arg.scan_id = ATH11K_SCAN_ID;
|
||||
arg.chan_list[0] = chan->center_freq;
|
||||
arg.dwell_time_active = scan_time_msec;
|
||||
arg.dwell_time_passive = scan_time_msec;
|
||||
arg.max_scan_time = scan_time_msec;
|
||||
arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE;
|
||||
arg.scan_flags |= WMI_SCAN_FILTER_PROBE_REQ;
|
||||
arg.burst_duration = duration;
|
||||
|
||||
ret = ath11k_start_scan(ar, &arg);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to start roc scan: %d\n", ret);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->scan.state = ATH11K_SCAN_IDLE;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
goto free_chan_list;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
|
||||
if (ret == 0) {
|
||||
ath11k_warn(ar->ab, "failed to switch to channel for roc scan\n");
|
||||
ret = ath11k_scan_stop(ar);
|
||||
if (ret)
|
||||
ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret);
|
||||
ret = -ETIMEDOUT;
|
||||
goto free_chan_list;
|
||||
}
|
||||
|
||||
ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
|
||||
msecs_to_jiffies(duration));
|
||||
|
||||
ret = 0;
|
||||
|
||||
free_chan_list:
|
||||
kfree(arg.chan_list);
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath11k_ops = {
|
||||
.tx = ath11k_mac_op_tx,
|
||||
.start = ath11k_mac_op_start,
|
||||
|
|
@ -8397,6 +8519,8 @@ static const struct ieee80211_ops ath11k_ops = {
|
|||
#endif
|
||||
|
||||
.set_sar_specs = ath11k_mac_op_set_bios_sar_specs,
|
||||
.remain_on_channel = ath11k_mac_op_remain_on_channel,
|
||||
.cancel_remain_on_channel = ath11k_mac_op_cancel_remain_on_channel,
|
||||
};
|
||||
|
||||
static void ath11k_mac_update_ch_list(struct ath11k *ar,
|
||||
|
|
@ -8986,6 +9110,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
|
|||
init_completion(&ar->bss_survey_done);
|
||||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->thermal.wmi_sync);
|
||||
|
||||
INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work);
|
||||
|
|
@ -9026,3 +9151,34 @@ void ath11k_mac_destroy(struct ath11k_base *ab)
|
|||
pdev->ar = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif,
|
||||
enum wmi_sta_keepalive_method method,
|
||||
u32 interval)
|
||||
{
|
||||
struct ath11k *ar = arvif->ar;
|
||||
struct wmi_sta_keepalive_arg arg = {};
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
|
||||
return 0;
|
||||
|
||||
if (!test_bit(WMI_TLV_SERVICE_STA_KEEP_ALIVE, ar->ab->wmi_ab.svc_map))
|
||||
return 0;
|
||||
|
||||
arg.vdev_id = arvif->vdev_id;
|
||||
arg.enabled = 1;
|
||||
arg.method = method;
|
||||
arg.interval = interval;
|
||||
|
||||
ret = ath11k_wmi_sta_keepalive(ar, &arg);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to set keepalive on vdev %i: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <net/mac80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "wmi.h"
|
||||
|
||||
struct ath11k;
|
||||
struct ath11k_base;
|
||||
|
|
@ -173,4 +174,7 @@ void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb);
|
|||
void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id);
|
||||
void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif);
|
||||
int ath11k_mac_wait_tx_complete(struct ath11k *ar);
|
||||
int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif,
|
||||
enum wmi_sta_keepalive_method method,
|
||||
u32 interval);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1970,6 +1970,21 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
|
|||
|
||||
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||
chunk = &ab->qmi.target_mem[i];
|
||||
|
||||
/* Firmware reloads in coldboot/firmware recovery.
|
||||
* in such case, no need to allocate memory for FW again.
|
||||
*/
|
||||
if (chunk->vaddr) {
|
||||
if (chunk->prev_type == chunk->type ||
|
||||
chunk->prev_size == chunk->size)
|
||||
continue;
|
||||
|
||||
/* cannot reuse the existing chunk */
|
||||
dma_free_coherent(ab->dev, chunk->size,
|
||||
chunk->vaddr, chunk->paddr);
|
||||
chunk->vaddr = NULL;
|
||||
}
|
||||
|
||||
chunk->vaddr = dma_alloc_coherent(ab->dev,
|
||||
chunk->size,
|
||||
&chunk->paddr,
|
||||
|
|
@ -1990,6 +2005,8 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
|
|||
chunk->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
chunk->prev_type = chunk->type;
|
||||
chunk->prev_size = chunk->size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -2466,9 +2483,6 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab)
|
|||
char path[100];
|
||||
int ret;
|
||||
|
||||
if (m3_mem->vaddr || m3_mem->size)
|
||||
return 0;
|
||||
|
||||
fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE);
|
||||
if (IS_ERR(fw)) {
|
||||
ret = PTR_ERR(fw);
|
||||
|
|
@ -2478,6 +2492,9 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (m3_mem->vaddr || m3_mem->size)
|
||||
goto skip_m3_alloc;
|
||||
|
||||
m3_mem->vaddr = dma_alloc_coherent(ab->dev,
|
||||
fw->size, &m3_mem->paddr,
|
||||
GFP_KERNEL);
|
||||
|
|
@ -2488,6 +2505,7 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
skip_m3_alloc:
|
||||
memcpy(m3_mem->vaddr, fw->data, fw->size);
|
||||
m3_mem->size = fw->size;
|
||||
release_firmware(fw);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ struct ath11k_qmi_event_msg {
|
|||
struct target_mem_chunk {
|
||||
u32 size;
|
||||
u32 type;
|
||||
u32 prev_size;
|
||||
u32 prev_type;
|
||||
dma_addr_t paddr;
|
||||
u32 *vaddr;
|
||||
void __iomem *iaddr;
|
||||
|
|
|
|||
|
|
@ -139,6 +139,9 @@ int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait)
|
|||
"reg hw scan wait left time %d\n", left);
|
||||
}
|
||||
|
||||
if (ar->state == ATH11K_STATE_RESTARTING)
|
||||
return 0;
|
||||
|
||||
bands = hw->wiphy->bands;
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
if (!bands[band])
|
||||
|
|
|
|||
|
|
@ -625,10 +625,25 @@ struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len)
|
|||
return skb;
|
||||
}
|
||||
|
||||
static u32 ath11k_wmi_mgmt_get_freq(struct ath11k *ar,
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
u32 freq = 0;
|
||||
|
||||
if (ab->hw_params.support_off_channel_tx &&
|
||||
ar->scan.is_roc &&
|
||||
(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN))
|
||||
freq = ar->scan.roc_freq;
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id,
|
||||
struct sk_buff *frame)
|
||||
{
|
||||
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame);
|
||||
struct wmi_mgmt_send_cmd *cmd;
|
||||
struct wmi_tlv *frame_tlv;
|
||||
struct sk_buff *skb;
|
||||
|
|
@ -649,7 +664,7 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id,
|
|||
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||
cmd->vdev_id = vdev_id;
|
||||
cmd->desc_id = buf_id;
|
||||
cmd->chanfreq = 0;
|
||||
cmd->chanfreq = ath11k_wmi_mgmt_get_freq(ar, info);
|
||||
cmd->paddr_lo = lower_32_bits(ATH11K_SKB_CB(frame)->paddr);
|
||||
cmd->paddr_hi = upper_32_bits(ATH11K_SKB_CB(frame)->paddr);
|
||||
cmd->frame_len = frame->len;
|
||||
|
|
@ -5264,6 +5279,8 @@ static void ath11k_wmi_event_scan_started(struct ath11k *ar)
|
|||
break;
|
||||
case ATH11K_SCAN_STARTING:
|
||||
ar->scan.state = ATH11K_SCAN_RUNNING;
|
||||
if (ar->scan.is_roc)
|
||||
ieee80211_ready_on_channel(ar->hw);
|
||||
complete(&ar->scan.started);
|
||||
break;
|
||||
}
|
||||
|
|
@ -5346,6 +5363,8 @@ static void ath11k_wmi_event_scan_foreign_chan(struct ath11k *ar, u32 freq)
|
|||
case ATH11K_SCAN_RUNNING:
|
||||
case ATH11K_SCAN_ABORTING:
|
||||
ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
|
||||
if (ar->scan.is_roc && ar->scan.roc_freq == freq)
|
||||
complete(&ar->scan.on_channel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -8959,3 +8978,44 @@ int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar)
|
|||
|
||||
return ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
|
||||
}
|
||||
|
||||
int ath11k_wmi_sta_keepalive(struct ath11k *ar,
|
||||
const struct wmi_sta_keepalive_arg *arg)
|
||||
{
|
||||
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||
struct wmi_sta_keepalive_cmd *cmd;
|
||||
struct wmi_sta_keepalive_arp_resp *arp;
|
||||
struct sk_buff *skb;
|
||||
size_t len;
|
||||
|
||||
len = sizeof(*cmd) + sizeof(*arp);
|
||||
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_sta_keepalive_cmd *)skb->data;
|
||||
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
|
||||
WMI_TAG_STA_KEEPALIVE_CMD) |
|
||||
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||
cmd->vdev_id = arg->vdev_id;
|
||||
cmd->enabled = arg->enabled;
|
||||
cmd->interval = arg->interval;
|
||||
cmd->method = arg->method;
|
||||
|
||||
if (arg->method == WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE ||
|
||||
arg->method == WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST) {
|
||||
arp = (struct wmi_sta_keepalive_arp_resp *)(cmd + 1);
|
||||
arp->tlv_header = FIELD_PREP(WMI_TLV_TAG,
|
||||
WMI_TAG_STA_KEEPALVE_ARP_RESPONSE) |
|
||||
FIELD_PREP(WMI_TLV_LEN, sizeof(*arp) - TLV_HDR_SIZE);
|
||||
arp->src_ip4_addr = arg->src_ip4_addr;
|
||||
arp->dest_ip4_addr = arg->dest_ip4_addr;
|
||||
ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr);
|
||||
}
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
||||
"wmi sta keepalive vdev %d enabled %d method %d interval %d\n",
|
||||
arg->vdev_id, arg->enabled, arg->method, arg->interval);
|
||||
|
||||
return ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5907,6 +5907,50 @@ struct wmi_pdev_set_geo_table_cmd {
|
|||
u32 rsvd_len;
|
||||
} __packed;
|
||||
|
||||
struct wmi_sta_keepalive_cmd {
|
||||
u32 tlv_header;
|
||||
u32 vdev_id;
|
||||
u32 enabled;
|
||||
|
||||
/* WMI_STA_KEEPALIVE_METHOD_ */
|
||||
u32 method;
|
||||
|
||||
/* in seconds */
|
||||
u32 interval;
|
||||
|
||||
/* following this structure is the TLV for struct
|
||||
* wmi_sta_keepalive_arp_resp
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
struct wmi_sta_keepalive_arp_resp {
|
||||
u32 tlv_header;
|
||||
u32 src_ip4_addr;
|
||||
u32 dest_ip4_addr;
|
||||
struct wmi_mac_addr dest_mac_addr;
|
||||
} __packed;
|
||||
|
||||
struct wmi_sta_keepalive_arg {
|
||||
u32 vdev_id;
|
||||
u32 enabled;
|
||||
u32 method;
|
||||
u32 interval;
|
||||
u32 src_ip4_addr;
|
||||
u32 dest_ip4_addr;
|
||||
const u8 dest_mac_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
enum wmi_sta_keepalive_method {
|
||||
WMI_STA_KEEPALIVE_METHOD_NULL_FRAME = 1,
|
||||
WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE = 2,
|
||||
WMI_STA_KEEPALIVE_METHOD_ETHERNET_LOOPBACK = 3,
|
||||
WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST = 4,
|
||||
WMI_STA_KEEPALIVE_METHOD_MGMT_VENDOR_ACTION = 5,
|
||||
};
|
||||
|
||||
#define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30
|
||||
#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
|
||||
|
||||
int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
|
||||
u32 cmd_id);
|
||||
struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
|
||||
|
|
@ -6087,5 +6131,7 @@ int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
|
|||
struct ath11k_vif *arvif);
|
||||
int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_val);
|
||||
int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar);
|
||||
int ath11k_wmi_sta_keepalive(struct ath11k *ar,
|
||||
const struct wmi_sta_keepalive_arg *arg);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -640,6 +640,24 @@ static int ath11k_wow_protocol_offload(struct ath11k *ar, bool enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath11k_wow_set_keepalive(struct ath11k *ar,
|
||||
enum wmi_sta_keepalive_method method,
|
||||
u32 interval)
|
||||
{
|
||||
struct ath11k_vif *arvif;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ret = ath11k_mac_vif_set_keepalive(arvif, method, interval);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath11k_wow_op_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
|
|
@ -691,6 +709,14 @@ int ath11k_wow_op_suspend(struct ieee80211_hw *hw,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = ath11k_wow_set_keepalive(ar,
|
||||
WMI_STA_KEEPALIVE_METHOD_NULL_FRAME,
|
||||
WMI_STA_KEEPALIVE_INTERVAL_DEFAULT);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to enable wow keepalive: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = ath11k_wow_enable(ar->ab);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to start wow: %d\n", ret);
|
||||
|
|
@ -786,6 +812,14 @@ int ath11k_wow_op_resume(struct ieee80211_hw *hw)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath11k_wow_set_keepalive(ar,
|
||||
WMI_STA_KEEPALIVE_METHOD_NULL_FRAME,
|
||||
WMI_STA_KEEPALIVE_INTERVAL_DISABLE);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to disable wow keepalive: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret) {
|
||||
switch (ar->state) {
|
||||
|
|
|
|||
|
|
@ -1391,19 +1391,6 @@ static int temp_show(struct seq_file *s, void *data)
|
|||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(temp);
|
||||
|
||||
/*---------freq------------*/
|
||||
static int freq_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
|
||||
u32 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
|
||||
|
||||
seq_printf(s, "Freq = %d\n", freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(freq);
|
||||
|
||||
/*---------link------------*/
|
||||
static int link_show(struct seq_file *s, void *data)
|
||||
{
|
||||
|
|
@ -2380,7 +2367,6 @@ static const struct {
|
|||
{"pmcdata", 0444, &fops_pmcdata},
|
||||
{"pmcring", 0444, &fops_pmcring},
|
||||
{"temp", 0444, &temp_fops},
|
||||
{"freq", 0444, &freq_fops},
|
||||
{"link", 0444, &link_fops},
|
||||
{"info", 0444, &info_fops},
|
||||
{"recovery", 0644, &fops_recovery},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user