Merge tag 'wireless-next-2025-09-25' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says: ==================== Quite a bit more things, including pull requests from drivers: - mt76: MLO support, HW restart improvements - rtw88/89: small features, prep for RTL8922DE support - ath10k: GTK rekey fixes - cfg80211/mac80211: - additions for more NAN support - S1G channel representation cleanup * tag 'wireless-next-2025-09-25' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (167 commits) wifi: libertas: add WQ_UNBOUND to alloc_workqueue users Revert "wifi: libertas: WQ_PERCPU added to alloc_workqueue users" wifi: libertas: WQ_PERCPU added to alloc_workqueue users wifi: cfg80211: fix width unit in cfg80211_radio_chandef_valid() wifi: ath11k: HAL SRNG: don't deinitialize and re-initialize again wifi: ath12k: enforce CPU endian format for all QMI data wifi: ath12k: Use 1KB Cache Flush Command for QoS TID Descriptors wifi: ath12k: Fix flush cache failure during RX queue update wifi: ath12k: Add Retry Mechanism for REO RX Queue Update Failures wifi: ath12k: Refactor REO command to use ath12k_dp_rx_tid_rxq wifi: ath12k: Refactor RX TID buffer cleanup into helper function wifi: ath12k: Refactor RX TID deletion handling into helper function wifi: ath12k: Increase DP_REO_CMD_RING_SIZE to 256 wifi: cfg80211: remove IEEE80211_CHAN_{1,2,4,8,16}MHZ flags wifi: rtw89: avoid circular locking dependency in ser_state_run() wifi: rtw89: fix leak in rtw89_core_send_nullfunc() wifi: rtw89: avoid possible TX wait initialization race wifi: rtw89: fix use-after-free in rtw89_core_tx_kick_off_and_wait() wifi: ath12k: Fix peer lookup in ath12k_dp_mon_rx_deliver_msdu() wifi: mac80211: fix Rx packet handling when pubsta information is not available ... ==================== Link: https://patch.msgid.link/20250925232341.4544-3-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -27,7 +27,7 @@ static int ath10k_leds_set_brightness_blocking(struct led_classdev *led_cdev,
|
||||
goto out;
|
||||
|
||||
ar->leds.gpio_state_pin = (brightness != LED_OFF) ^ led->active_low;
|
||||
ath10k_wmi_gpio_output(ar, led->gpio, ar->leds.gpio_state_pin);
|
||||
ath10k_wmi_gpio_output(ar, ar->hw_params.led_pin, ar->leds.gpio_state_pin);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
@@ -64,7 +64,6 @@ int ath10k_leds_register(struct ath10k *ar)
|
||||
snprintf(ar->leds.label, sizeof(ar->leds.label), "ath10k-%s",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
ar->leds.wifi_led.active_low = 1;
|
||||
ar->leds.wifi_led.gpio = ar->hw_params.led_pin;
|
||||
ar->leds.wifi_led.name = ar->leds.label;
|
||||
ar->leds.wifi_led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "hif.h"
|
||||
#include "core.h"
|
||||
@@ -290,8 +291,15 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
|
||||
if (cmd == DISABLE_KEY) {
|
||||
arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_NONE];
|
||||
arg.key_data = NULL;
|
||||
if (flags & WMI_KEY_GROUP) {
|
||||
/* Not all hardware handles group-key deletion operation
|
||||
* correctly. Replace the key with a junk value to invalidate it.
|
||||
*/
|
||||
get_random_bytes(key->key, key->keylen);
|
||||
} else {
|
||||
arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_NONE];
|
||||
arg.key_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ath10k_wmi_vdev_install_key(arvif->ar, &arg);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/remoteproc/qcom_rproc.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include "ce.h"
|
||||
@@ -1559,19 +1559,11 @@ static void ath10k_modem_deinit(struct ath10k *ar)
|
||||
static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)
|
||||
{
|
||||
struct device *dev = ar->dev;
|
||||
struct device_node *node;
|
||||
struct resource r;
|
||||
int ret;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (node) {
|
||||
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;
|
||||
}
|
||||
|
||||
ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &r);
|
||||
if (!ret) {
|
||||
ar->msa.paddr = r.start;
|
||||
ar->msa.mem_size = resource_size(&r);
|
||||
ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,
|
||||
|
||||
@@ -1764,33 +1764,32 @@ void ath10k_wmi_put_wmi_channel(struct ath10k *ar, struct wmi_channel *ch,
|
||||
|
||||
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
|
||||
{
|
||||
unsigned long timeout = jiffies + WMI_SERVICE_READY_TIMEOUT_HZ;
|
||||
unsigned long time_left, i;
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->wmi.service_ready,
|
||||
WMI_SERVICE_READY_TIMEOUT_HZ);
|
||||
if (!time_left) {
|
||||
/* Sometimes the PCI HIF doesn't receive interrupt
|
||||
* for the service ready message even if the buffer
|
||||
* was completed. PCIe sniffer shows that it's
|
||||
* because the corresponding CE ring doesn't fires
|
||||
* it. Workaround here by polling CE rings once.
|
||||
*/
|
||||
ath10k_warn(ar, "failed to receive service ready completion, polling..\n");
|
||||
|
||||
/* Sometimes the PCI HIF doesn't receive interrupt
|
||||
* for the service ready message even if the buffer
|
||||
* was completed. PCIe sniffer shows that it's
|
||||
* because the corresponding CE ring doesn't fires
|
||||
* it. Workaround here by polling CE rings. Since
|
||||
* the message could arrive at any time, continue
|
||||
* polling until timeout.
|
||||
*/
|
||||
do {
|
||||
for (i = 0; i < CE_COUNT; i++)
|
||||
ath10k_hif_send_complete_check(ar, i, 1);
|
||||
|
||||
/* The 100 ms granularity is a tradeoff considering scheduler
|
||||
* overhead and response latency
|
||||
*/
|
||||
time_left = wait_for_completion_timeout(&ar->wmi.service_ready,
|
||||
WMI_SERVICE_READY_TIMEOUT_HZ);
|
||||
if (!time_left) {
|
||||
ath10k_warn(ar, "polling timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msecs_to_jiffies(100));
|
||||
if (time_left)
|
||||
return 0;
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
ath10k_warn(ar, "service ready completion received, continuing normally\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
ath10k_warn(ar, "failed to receive service ready completion\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/iommu.h>
|
||||
#include "ahb.h"
|
||||
#include "debug.h"
|
||||
@@ -919,16 +919,10 @@ 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);
|
||||
ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &r);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to resolve msa fixed region\n");
|
||||
return ret;
|
||||
@@ -937,12 +931,7 @@ static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
|
||||
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);
|
||||
ret = of_reserved_mem_region_to_resource(dev->of_node, 1, &r);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to resolve ce fixed region\n");
|
||||
return ret;
|
||||
|
||||
@@ -354,7 +354,8 @@ static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe)
|
||||
ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr);
|
||||
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret);
|
||||
ath11k_dbg(ab, ATH11K_DBG_CE, "failed to enqueue rx buf: %d\n",
|
||||
ret);
|
||||
dma_unmap_single(ab->dev, paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
@@ -2215,14 +2215,10 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
|
||||
mutex_unlock(&ab->core_lock);
|
||||
|
||||
ath11k_dp_free(ab);
|
||||
ath11k_hal_srng_deinit(ab);
|
||||
ath11k_hal_srng_clear(ab);
|
||||
|
||||
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;
|
||||
|
||||
ret = ath11k_hal_srng_init(ab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
|
||||
|
||||
ret = ath11k_core_qmi_firmware_ready(ab);
|
||||
|
||||
@@ -4615,7 +4615,6 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
|
||||
msdu_details[i].buf_addr_info.info0) == 0) {
|
||||
msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
|
||||
msdu_desc_info->info0 |= last;
|
||||
;
|
||||
break;
|
||||
}
|
||||
msdu_desc_info = &msdu_details[i].rx_msdu_info;
|
||||
|
||||
@@ -1386,6 +1386,22 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab)
|
||||
}
|
||||
EXPORT_SYMBOL(ath11k_hal_srng_deinit);
|
||||
|
||||
void ath11k_hal_srng_clear(struct ath11k_base *ab)
|
||||
{
|
||||
/* No need to memset rdp and wrp memory since each individual
|
||||
* segment would get cleared in ath11k_hal_srng_src_hw_init()
|
||||
* and ath11k_hal_srng_dst_hw_init().
|
||||
*/
|
||||
memset(ab->hal.srng_list, 0,
|
||||
sizeof(ab->hal.srng_list));
|
||||
memset(ab->hal.shadow_reg_addr, 0,
|
||||
sizeof(ab->hal.shadow_reg_addr));
|
||||
ab->hal.avail_blk_resource = 0;
|
||||
ab->hal.current_blk_index = 0;
|
||||
ab->hal.num_shadow_reg_configured = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath11k_hal_srng_clear);
|
||||
|
||||
void ath11k_hal_dump_srng_stats(struct ath11k_base *ab)
|
||||
{
|
||||
struct hal_srng *srng;
|
||||
|
||||
@@ -965,6 +965,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
|
||||
struct hal_srng_params *params);
|
||||
int ath11k_hal_srng_init(struct ath11k_base *ath11k);
|
||||
void ath11k_hal_srng_deinit(struct ath11k_base *ath11k);
|
||||
void ath11k_hal_srng_clear(struct ath11k_base *ab);
|
||||
void ath11k_hal_dump_srng_stats(struct ath11k_base *ab);
|
||||
void ath11k_hal_srng_get_shadow_config(struct ath11k_base *ab,
|
||||
u32 **cfg, u32 *len);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "debug.h"
|
||||
#include "hif.h"
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/of_irq.h>
|
||||
@@ -2040,23 +2040,14 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
|
||||
static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
||||
{
|
||||
struct device *dev = ab->dev;
|
||||
struct device_node *hremote_node = NULL;
|
||||
struct resource res;
|
||||
struct resource res = {};
|
||||
u32 host_ddr_sz;
|
||||
int i, idx, ret;
|
||||
|
||||
for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||
switch (ab->qmi.target_mem[i].type) {
|
||||
case HOST_DDR_REGION_TYPE:
|
||||
hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (!hremote_node) {
|
||||
ath11k_dbg(ab, ATH11K_DBG_QMI,
|
||||
"fail to get hremote_node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(hremote_node, 0, &res);
|
||||
of_node_put(hremote_node);
|
||||
ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
|
||||
if (ret) {
|
||||
ath11k_dbg(ab, ATH11K_DBG_QMI,
|
||||
"fail to get reg from hremote\n");
|
||||
@@ -2095,7 +2086,7 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
||||
}
|
||||
|
||||
if (ath11k_core_coldboot_cal_support(ab)) {
|
||||
if (hremote_node) {
|
||||
if (resource_size(&res)) {
|
||||
ab->qmi.target_mem[idx].paddr =
|
||||
res.start + host_ddr_sz;
|
||||
ab->qmi.target_mem[idx].iaddr =
|
||||
@@ -2557,7 +2548,7 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab)
|
||||
GFP_KERNEL);
|
||||
if (!m3_mem->vaddr) {
|
||||
ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n",
|
||||
fw->size);
|
||||
m3_len);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,8 @@ static int ath12k_ce_rx_post_pipe(struct ath12k_ce_pipe *pipe)
|
||||
|
||||
ret = ath12k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to enqueue rx buf: %d\n", ret);
|
||||
ath12k_dbg(ab, ATH12K_DBG_CE, "failed to enqueue rx buf: %d\n",
|
||||
ret);
|
||||
dma_unmap_single(ab->dev, paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
@@ -478,7 +479,7 @@ static void ath12k_ce_recv_process_cb(struct ath12k_ce_pipe *pipe)
|
||||
}
|
||||
|
||||
while ((skb = __skb_dequeue(&list))) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_AHB, "rx ce pipe %d len %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_CE, "rx ce pipe %d len %d\n",
|
||||
pipe->pipe_num, skb->len);
|
||||
pipe->recv_cb(ab, skb);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef ATH12K_CORE_H
|
||||
@@ -72,6 +72,9 @@
|
||||
#define ATH12K_MAX_MLO_PEERS 256
|
||||
#define ATH12K_MLO_PEER_ID_INVALID 0xFFFF
|
||||
|
||||
#define ATH12K_INVALID_RSSI_FULL -1
|
||||
#define ATH12K_INVALID_RSSI_EMPTY -128
|
||||
|
||||
enum ath12k_bdf_search {
|
||||
ATH12K_BDF_SEARCH_DEFAULT,
|
||||
ATH12K_BDF_SEARCH_BUS_AND_BOARD,
|
||||
@@ -560,6 +563,7 @@ struct ath12k_link_sta {
|
||||
u32 bw_prev;
|
||||
u32 peer_nss;
|
||||
s8 rssi_beacon;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
|
||||
/* For now the assoc link will be considered primary */
|
||||
bool is_assoc_link;
|
||||
@@ -730,6 +734,7 @@ struct ath12k {
|
||||
u32 txpower_scale;
|
||||
u32 power_scale;
|
||||
u32 chan_tx_pwr;
|
||||
u32 rts_threshold;
|
||||
u32 num_stations;
|
||||
u32 max_num_stations;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ enum ath12k_debug_mask {
|
||||
ATH12K_DBG_DP_TX = 0x00002000,
|
||||
ATH12K_DBG_DP_RX = 0x00004000,
|
||||
ATH12K_DBG_WOW = 0x00008000,
|
||||
ATH12K_DBG_CE = 0x00010000,
|
||||
ATH12K_DBG_ANY = 0xffffffff,
|
||||
};
|
||||
|
||||
|
||||
@@ -1745,7 +1745,9 @@ int ath12k_dp_alloc(struct ath12k_base *ab)
|
||||
|
||||
INIT_LIST_HEAD(&dp->reo_cmd_list);
|
||||
INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list);
|
||||
INIT_LIST_HEAD(&dp->reo_cmd_update_rx_queue_list);
|
||||
spin_lock_init(&dp->reo_cmd_lock);
|
||||
spin_lock_init(&dp->reo_rxq_flush_lock);
|
||||
|
||||
dp->reo_cmd_cache_flush_count = 0;
|
||||
dp->idle_link_rbm = ath12k_dp_get_idle_link_rbm(ab);
|
||||
|
||||
@@ -184,7 +184,7 @@ struct ath12k_pdev_dp {
|
||||
#define DP_REO_REINJECT_RING_SIZE 32
|
||||
#define DP_RX_RELEASE_RING_SIZE 1024
|
||||
#define DP_REO_EXCEPTION_RING_SIZE 128
|
||||
#define DP_REO_CMD_RING_SIZE 128
|
||||
#define DP_REO_CMD_RING_SIZE 256
|
||||
#define DP_REO_STATUS_RING_SIZE 2048
|
||||
#define DP_RXDMA_BUF_RING_SIZE 4096
|
||||
#define DP_RX_MAC_BUF_RING_SIZE 2048
|
||||
@@ -389,15 +389,19 @@ struct ath12k_dp {
|
||||
struct dp_srng reo_dst_ring[DP_REO_DST_RING_MAX];
|
||||
struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX];
|
||||
struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
|
||||
struct list_head reo_cmd_list;
|
||||
struct list_head reo_cmd_update_rx_queue_list;
|
||||
struct list_head reo_cmd_cache_flush_list;
|
||||
u32 reo_cmd_cache_flush_count;
|
||||
|
||||
/* protects access to below fields,
|
||||
* - reo_cmd_list
|
||||
* - reo_cmd_update_rx_queue_list
|
||||
* - reo_cmd_cache_flush_list
|
||||
* - reo_cmd_cache_flush_count
|
||||
*/
|
||||
spinlock_t reo_rxq_flush_lock;
|
||||
struct list_head reo_cmd_list;
|
||||
/* protects access to below fields,
|
||||
* - reo_cmd_list
|
||||
*/
|
||||
spinlock_t reo_cmd_lock;
|
||||
struct ath12k_hp_update_timer reo_cmd_timer;
|
||||
struct ath12k_hp_update_timer tx_ring_timer[DP_TCL_NUM_RING_MAX];
|
||||
|
||||
@@ -1440,6 +1440,34 @@ static void ath12k_dp_mon_parse_rx_msdu_end_err(u32 info, u32 *errmap)
|
||||
*errmap |= HAL_RX_MPDU_ERR_MPDU_LEN;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_parse_cmn_usr_info(const struct hal_phyrx_common_user_info *cmn_usr_info,
|
||||
struct hal_rx_mon_ppdu_info *ppdu_info)
|
||||
{
|
||||
struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
|
||||
u32 known, data, cp_setting, ltf_size;
|
||||
|
||||
known = __le32_to_cpu(eht->known);
|
||||
known |= IEEE80211_RADIOTAP_EHT_KNOWN_GI |
|
||||
IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF;
|
||||
eht->known = cpu_to_le32(known);
|
||||
|
||||
cp_setting = le32_get_bits(cmn_usr_info->info0,
|
||||
HAL_RX_CMN_USR_INFO0_CP_SETTING);
|
||||
ltf_size = le32_get_bits(cmn_usr_info->info0,
|
||||
HAL_RX_CMN_USR_INFO0_LTF_SIZE);
|
||||
|
||||
data = __le32_to_cpu(eht->data[0]);
|
||||
data |= u32_encode_bits(cp_setting, IEEE80211_RADIOTAP_EHT_DATA0_GI);
|
||||
data |= u32_encode_bits(ltf_size, IEEE80211_RADIOTAP_EHT_DATA0_LTF);
|
||||
eht->data[0] = cpu_to_le32(data);
|
||||
|
||||
if (!ppdu_info->ltf_size)
|
||||
ppdu_info->ltf_size = ltf_size;
|
||||
if (!ppdu_info->gi)
|
||||
ppdu_info->gi = cp_setting;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_dp_mon_parse_status_msdu_end(struct ath12k_mon_data *pmon,
|
||||
const struct hal_rx_msdu_end *msdu_end)
|
||||
@@ -1627,25 +1655,22 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k *ar,
|
||||
const struct hal_rx_phyrx_rssi_legacy_info *rssi = tlv_data;
|
||||
|
||||
info[0] = __le32_to_cpu(rssi->info0);
|
||||
info[1] = __le32_to_cpu(rssi->info1);
|
||||
info[2] = __le32_to_cpu(rssi->info2);
|
||||
|
||||
/* TODO: Please note that the combined rssi will not be accurate
|
||||
* in MU case. Rssi in MU needs to be retrieved from
|
||||
* PHYRX_OTHER_RECEIVE_INFO TLV.
|
||||
*/
|
||||
ppdu_info->rssi_comb =
|
||||
u32_get_bits(info[1],
|
||||
HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB);
|
||||
u32_get_bits(info[2],
|
||||
HAL_RX_RSSI_LEGACY_INFO_INFO2_RSSI_COMB_PPDU);
|
||||
|
||||
ppdu_info->bw = u32_get_bits(info[0],
|
||||
HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW);
|
||||
HAL_RX_RSSI_LEGACY_INFO_INFO0_RX_BW);
|
||||
break;
|
||||
}
|
||||
case HAL_PHYRX_OTHER_RECEIVE_INFO: {
|
||||
const struct hal_phyrx_common_user_info *cmn_usr_info = tlv_data;
|
||||
|
||||
ppdu_info->gi = le32_get_bits(cmn_usr_info->info0,
|
||||
HAL_RX_PHY_CMN_USER_INFO0_GI);
|
||||
case HAL_PHYRX_COMMON_USER_INFO: {
|
||||
ath12k_parse_cmn_usr_info(tlv_data, ppdu_info);
|
||||
break;
|
||||
}
|
||||
case HAL_RX_PPDU_START_USER_INFO:
|
||||
@@ -2154,8 +2179,12 @@ static void ath12k_dp_mon_update_radiotap(struct ath12k *ar,
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
rxs->flag |= RX_FLAG_MACTIME_START;
|
||||
rxs->signal = ppduinfo->rssi_comb + noise_floor;
|
||||
rxs->nss = ppduinfo->nss + 1;
|
||||
if (test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,
|
||||
ar->ab->wmi_ab.svc_map))
|
||||
rxs->signal = ppduinfo->rssi_comb;
|
||||
else
|
||||
rxs->signal = ppduinfo->rssi_comb + noise_floor;
|
||||
|
||||
if (ppduinfo->userstats[ppduinfo->userid].ampdu_present) {
|
||||
rxs->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
@@ -2244,6 +2273,7 @@ static void ath12k_dp_mon_update_radiotap(struct ath12k *ar,
|
||||
|
||||
static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi,
|
||||
struct sk_buff *msdu,
|
||||
const struct hal_rx_mon_ppdu_info *ppduinfo,
|
||||
struct ieee80211_rx_status *status,
|
||||
u8 decap)
|
||||
{
|
||||
@@ -2257,7 +2287,6 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
|
||||
struct ieee80211_sta *pubsta = NULL;
|
||||
struct ath12k_peer *peer;
|
||||
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
|
||||
struct ath12k_dp_rx_info rx_info;
|
||||
bool is_mcbc = rxcb->is_mcbc;
|
||||
bool is_eapol_tkip = rxcb->is_eapol;
|
||||
|
||||
@@ -2271,8 +2300,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->ab->base_lock);
|
||||
rx_info.addr2_present = false;
|
||||
peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu, &rx_info);
|
||||
peer = ath12k_peer_find_by_id(ar->ab, ppduinfo->peer_id);
|
||||
if (peer && peer->sta) {
|
||||
pubsta = peer->sta;
|
||||
if (pubsta->valid_links) {
|
||||
@@ -2365,7 +2393,7 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k *ar,
|
||||
decap = mon_mpdu->decap_format;
|
||||
|
||||
ath12k_dp_mon_update_radiotap(ar, ppduinfo, mon_skb, rxs);
|
||||
ath12k_dp_mon_rx_deliver_msdu(ar, napi, mon_skb, rxs, decap);
|
||||
ath12k_dp_mon_rx_deliver_msdu(ar, napi, mon_skb, ppduinfo, rxs, decap);
|
||||
mon_skb = skb_next;
|
||||
} while (mon_skb);
|
||||
rxs->flag = 0;
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
#define ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ)
|
||||
|
||||
static int ath12k_dp_rx_tid_delete_handler(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid);
|
||||
|
||||
static enum hal_encrypt_type ath12k_dp_rx_h_enctype(struct ath12k_base *ab,
|
||||
struct hal_rx_desc *desc)
|
||||
{
|
||||
@@ -581,49 +584,71 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_dp_init_rx_tid_rxq(struct ath12k_dp_rx_tid_rxq *rx_tid_rxq,
|
||||
struct ath12k_dp_rx_tid *rx_tid)
|
||||
{
|
||||
rx_tid_rxq->tid = rx_tid->tid;
|
||||
rx_tid_rxq->active = rx_tid->active;
|
||||
rx_tid_rxq->qbuf = rx_tid->qbuf;
|
||||
}
|
||||
|
||||
static void ath12k_dp_rx_tid_cleanup(struct ath12k_base *ab,
|
||||
struct ath12k_reoq_buf *tid_qbuf)
|
||||
{
|
||||
if (tid_qbuf->vaddr) {
|
||||
dma_unmap_single(ab->dev, tid_qbuf->paddr_aligned,
|
||||
tid_qbuf->size, DMA_BIDIRECTIONAL);
|
||||
kfree(tid_qbuf->vaddr);
|
||||
tid_qbuf->vaddr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ath12k_dp_rx_reo_cmd_list_cleanup(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
struct ath12k_dp_rx_reo_cmd *cmd, *tmp;
|
||||
struct ath12k_dp_rx_reo_cache_flush_elem *cmd_cache, *tmp_cache;
|
||||
struct dp_reo_update_rx_queue_elem *cmd_queue, *tmp_queue;
|
||||
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
||||
list_del(&cmd->list);
|
||||
dma_unmap_single(ab->dev, cmd->data.qbuf.paddr_aligned,
|
||||
cmd->data.qbuf.size, DMA_BIDIRECTIONAL);
|
||||
kfree(cmd->data.qbuf.vaddr);
|
||||
kfree(cmd);
|
||||
spin_lock_bh(&dp->reo_rxq_flush_lock);
|
||||
list_for_each_entry_safe(cmd_queue, tmp_queue, &dp->reo_cmd_update_rx_queue_list,
|
||||
list) {
|
||||
list_del(&cmd_queue->list);
|
||||
ath12k_dp_rx_tid_cleanup(ab, &cmd_queue->rx_tid.qbuf);
|
||||
kfree(cmd_queue);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(cmd_cache, tmp_cache,
|
||||
&dp->reo_cmd_cache_flush_list, list) {
|
||||
list_del(&cmd_cache->list);
|
||||
dp->reo_cmd_cache_flush_count--;
|
||||
dma_unmap_single(ab->dev, cmd_cache->data.qbuf.paddr_aligned,
|
||||
cmd_cache->data.qbuf.size, DMA_BIDIRECTIONAL);
|
||||
kfree(cmd_cache->data.qbuf.vaddr);
|
||||
ath12k_dp_rx_tid_cleanup(ab, &cmd_cache->data.qbuf);
|
||||
kfree(cmd_cache);
|
||||
}
|
||||
spin_unlock_bh(&dp->reo_rxq_flush_lock);
|
||||
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
||||
list_del(&cmd->list);
|
||||
ath12k_dp_rx_tid_cleanup(ab, &cmd->data.qbuf);
|
||||
kfree(cmd);
|
||||
}
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
}
|
||||
|
||||
static void ath12k_dp_reo_cmd_free(struct ath12k_dp *dp, void *ctx,
|
||||
enum hal_reo_cmd_status status)
|
||||
{
|
||||
struct ath12k_dp_rx_tid *rx_tid = ctx;
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid = ctx;
|
||||
|
||||
if (status != HAL_REO_CMD_SUCCESS)
|
||||
ath12k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
|
||||
rx_tid->tid, status);
|
||||
|
||||
dma_unmap_single(dp->ab->dev, rx_tid->qbuf.paddr_aligned, rx_tid->qbuf.size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->qbuf.vaddr);
|
||||
rx_tid->qbuf.vaddr = NULL;
|
||||
ath12k_dp_rx_tid_cleanup(dp->ab, &rx_tid->qbuf);
|
||||
}
|
||||
|
||||
static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_tid *rx_tid,
|
||||
static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid,
|
||||
enum hal_reo_cmd_type type,
|
||||
struct ath12k_hal_reo_cmd *cmd,
|
||||
void (*cb)(struct ath12k_dp *dp, void *ctx,
|
||||
@@ -668,51 +693,95 @@ static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_ti
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_dp_reo_cache_flush(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid *rx_tid)
|
||||
static int ath12k_dp_reo_cache_flush(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid)
|
||||
{
|
||||
struct ath12k_hal_reo_cmd cmd = {};
|
||||
unsigned long tot_desc_sz, desc_sz;
|
||||
int ret;
|
||||
|
||||
tot_desc_sz = rx_tid->qbuf.size;
|
||||
desc_sz = ath12k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID);
|
||||
|
||||
while (tot_desc_sz > desc_sz) {
|
||||
tot_desc_sz -= desc_sz;
|
||||
cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned + tot_desc_sz);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
ret = ath12k_dp_reo_cmd_send(ab, rx_tid,
|
||||
HAL_REO_CMD_FLUSH_CACHE, &cmd,
|
||||
NULL);
|
||||
if (ret)
|
||||
ath12k_warn(ab,
|
||||
"failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n",
|
||||
rx_tid->tid, ret);
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
|
||||
/* HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS - all pending MPDUs
|
||||
*in the bitmap will be forwarded/flushed to REO output rings
|
||||
*/
|
||||
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS |
|
||||
HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS;
|
||||
|
||||
/* For all QoS TIDs (except NON_QOS), the driver allocates a maximum
|
||||
* window size of 1024. In such cases, the driver can issue a single
|
||||
* 1KB descriptor flush command instead of sending multiple 128-byte
|
||||
* flush commands for each QoS TID, improving efficiency.
|
||||
*/
|
||||
|
||||
if (rx_tid->tid != HAL_DESC_REO_NON_QOS_TID)
|
||||
cmd.flag |= HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC;
|
||||
|
||||
ret = ath12k_dp_reo_cmd_send(ab, rx_tid,
|
||||
HAL_REO_CMD_FLUSH_CACHE,
|
||||
&cmd, ath12k_dp_reo_cmd_free);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
|
||||
rx_tid->tid, ret);
|
||||
dma_unmap_single(ab->dev, rx_tid->qbuf.paddr_aligned, rx_tid->qbuf.size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->qbuf.vaddr);
|
||||
rx_tid->qbuf.vaddr = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u16 tid)
|
||||
{
|
||||
struct ath12k_reo_queue_ref *qref;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
bool ml_peer = false;
|
||||
|
||||
if (!ab->hw_params->reoq_lut_support)
|
||||
return;
|
||||
|
||||
if (peer_id & ATH12K_PEER_ML_ID_VALID) {
|
||||
peer_id &= ~ATH12K_PEER_ML_ID_VALID;
|
||||
ml_peer = true;
|
||||
}
|
||||
|
||||
if (ml_peer)
|
||||
qref = (struct ath12k_reo_queue_ref *)dp->ml_reoq_lut.vaddr +
|
||||
(peer_id * (IEEE80211_NUM_TIDS + 1) + tid);
|
||||
else
|
||||
qref = (struct ath12k_reo_queue_ref *)dp->reoq_lut.vaddr +
|
||||
(peer_id * (IEEE80211_NUM_TIDS + 1) + tid);
|
||||
|
||||
qref->info0 = u32_encode_bits(0, BUFFER_ADDR_INFO0_ADDR);
|
||||
qref->info1 = u32_encode_bits(0, BUFFER_ADDR_INFO1_ADDR) |
|
||||
u32_encode_bits(tid, DP_REO_QREF_NUM);
|
||||
}
|
||||
|
||||
static void ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(struct ath12k_dp *dp)
|
||||
{
|
||||
struct ath12k_base *ab = dp->ab;
|
||||
struct dp_reo_update_rx_queue_elem *elem, *tmp;
|
||||
|
||||
spin_lock_bh(&dp->reo_rxq_flush_lock);
|
||||
|
||||
list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_update_rx_queue_list, list) {
|
||||
if (elem->rx_tid.active)
|
||||
continue;
|
||||
|
||||
if (ath12k_dp_rx_tid_delete_handler(ab, &elem->rx_tid))
|
||||
break;
|
||||
|
||||
ath12k_peer_rx_tid_qref_reset(ab,
|
||||
elem->is_ml_peer ? elem->ml_peer_id :
|
||||
elem->peer_id,
|
||||
elem->rx_tid.tid);
|
||||
|
||||
if (ab->hw_params->reoq_lut_support)
|
||||
ath12k_hal_reo_shared_qaddr_cache_clear(ab);
|
||||
|
||||
list_del(&elem->list);
|
||||
kfree(elem);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dp->reo_rxq_flush_lock);
|
||||
}
|
||||
|
||||
static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx,
|
||||
enum hal_reo_cmd_status status)
|
||||
{
|
||||
struct ath12k_base *ab = dp->ab;
|
||||
struct ath12k_dp_rx_tid *rx_tid = ctx;
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid = ctx;
|
||||
struct ath12k_dp_rx_reo_cache_flush_elem *elem, *tmp;
|
||||
|
||||
if (status == HAL_REO_CMD_DRAIN) {
|
||||
@@ -724,6 +793,13 @@ static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Retry the HAL_REO_CMD_UPDATE_RX_QUEUE command for entries
|
||||
* in the pending queue list marked TID as inactive
|
||||
*/
|
||||
spin_lock_bh(&dp->ab->base_lock);
|
||||
ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(dp);
|
||||
spin_unlock_bh(&dp->ab->base_lock);
|
||||
|
||||
elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
|
||||
if (!elem)
|
||||
goto free_desc;
|
||||
@@ -731,7 +807,7 @@ static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx,
|
||||
elem->ts = jiffies;
|
||||
memcpy(&elem->data, rx_tid, sizeof(*rx_tid));
|
||||
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
spin_lock_bh(&dp->reo_rxq_flush_lock);
|
||||
list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list);
|
||||
dp->reo_cmd_cache_flush_count++;
|
||||
|
||||
@@ -741,32 +817,44 @@ static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx,
|
||||
if (dp->reo_cmd_cache_flush_count > ATH12K_DP_RX_REO_DESC_FREE_THRES ||
|
||||
time_after(jiffies, elem->ts +
|
||||
msecs_to_jiffies(ATH12K_DP_RX_REO_DESC_FREE_TIMEOUT_MS))) {
|
||||
/* The reo_cmd_cache_flush_list is used in only two contexts,
|
||||
* one is in this function called from napi and the
|
||||
* other in ath12k_dp_free during core destroy.
|
||||
* If cache command sent is success, delete the element in
|
||||
* the cache list. ath12k_dp_rx_reo_cmd_list_cleanup
|
||||
* will be called during core destroy.
|
||||
*/
|
||||
|
||||
if (ath12k_dp_reo_cache_flush(ab, &elem->data))
|
||||
break;
|
||||
|
||||
list_del(&elem->list);
|
||||
dp->reo_cmd_cache_flush_count--;
|
||||
|
||||
/* Unlock the reo_cmd_lock before using ath12k_dp_reo_cmd_send()
|
||||
* within ath12k_dp_reo_cache_flush. The reo_cmd_cache_flush_list
|
||||
* is used in only two contexts, one is in this function called
|
||||
* from napi and the other in ath12k_dp_free during core destroy.
|
||||
* Before dp_free, the irqs would be disabled and would wait to
|
||||
* synchronize. Hence there wouldn’t be any race against add or
|
||||
* delete to this list. Hence unlock-lock is safe here.
|
||||
*/
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
|
||||
ath12k_dp_reo_cache_flush(ab, &elem->data);
|
||||
kfree(elem);
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
spin_unlock_bh(&dp->reo_rxq_flush_lock);
|
||||
|
||||
return;
|
||||
free_desc:
|
||||
dma_unmap_single(ab->dev, rx_tid->qbuf.paddr_aligned, rx_tid->qbuf.size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->qbuf.vaddr);
|
||||
rx_tid->qbuf.vaddr = NULL;
|
||||
ath12k_dp_rx_tid_cleanup(ab, &rx_tid->qbuf);
|
||||
}
|
||||
|
||||
static int ath12k_dp_rx_tid_delete_handler(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid)
|
||||
{
|
||||
struct ath12k_hal_reo_cmd cmd = {};
|
||||
|
||||
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
|
||||
cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.upd0 |= HAL_REO_CMD_UPD0_VLD;
|
||||
/* Observed flush cache failure, to avoid that set vld bit during delete */
|
||||
cmd.upd1 |= HAL_REO_CMD_UPD1_VLD;
|
||||
|
||||
return ath12k_dp_reo_cmd_send(ab, rx_tid,
|
||||
HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
|
||||
ath12k_dp_rx_tid_del_func);
|
||||
}
|
||||
|
||||
static void ath12k_peer_rx_tid_qref_setup(struct ath12k_base *ab, u16 peer_id, u16 tid,
|
||||
@@ -799,64 +887,38 @@ static void ath12k_peer_rx_tid_qref_setup(struct ath12k_base *ab, u16 peer_id, u
|
||||
ath12k_hal_reo_shared_qaddr_cache_clear(ab);
|
||||
}
|
||||
|
||||
static void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u16 tid)
|
||||
static void ath12k_dp_mark_tid_as_inactive(struct ath12k_dp *dp, int peer_id, u8 tid)
|
||||
{
|
||||
struct ath12k_reo_queue_ref *qref;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
bool ml_peer = false;
|
||||
struct dp_reo_update_rx_queue_elem *elem;
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid;
|
||||
|
||||
if (!ab->hw_params->reoq_lut_support)
|
||||
return;
|
||||
|
||||
if (peer_id & ATH12K_PEER_ML_ID_VALID) {
|
||||
peer_id &= ~ATH12K_PEER_ML_ID_VALID;
|
||||
ml_peer = true;
|
||||
spin_lock_bh(&dp->reo_rxq_flush_lock);
|
||||
list_for_each_entry(elem, &dp->reo_cmd_update_rx_queue_list, list) {
|
||||
if (elem->peer_id == peer_id) {
|
||||
rx_tid = &elem->rx_tid;
|
||||
if (rx_tid->tid == tid) {
|
||||
rx_tid->active = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ml_peer)
|
||||
qref = (struct ath12k_reo_queue_ref *)dp->ml_reoq_lut.vaddr +
|
||||
(peer_id * (IEEE80211_NUM_TIDS + 1) + tid);
|
||||
else
|
||||
qref = (struct ath12k_reo_queue_ref *)dp->reoq_lut.vaddr +
|
||||
(peer_id * (IEEE80211_NUM_TIDS + 1) + tid);
|
||||
|
||||
qref->info0 = u32_encode_bits(0, BUFFER_ADDR_INFO0_ADDR);
|
||||
qref->info1 = u32_encode_bits(0, BUFFER_ADDR_INFO1_ADDR) |
|
||||
u32_encode_bits(tid, DP_REO_QREF_NUM);
|
||||
spin_unlock_bh(&dp->reo_rxq_flush_lock);
|
||||
}
|
||||
|
||||
void ath12k_dp_rx_peer_tid_delete(struct ath12k *ar,
|
||||
struct ath12k_peer *peer, u8 tid)
|
||||
{
|
||||
struct ath12k_hal_reo_cmd cmd = {};
|
||||
struct ath12k_dp_rx_tid *rx_tid = &peer->rx_tid[tid];
|
||||
int ret;
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
|
||||
if (!rx_tid->active)
|
||||
return;
|
||||
|
||||
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
|
||||
cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.upd0 = HAL_REO_CMD_UPD0_VLD;
|
||||
ret = ath12k_dp_reo_cmd_send(ar->ab, rx_tid,
|
||||
HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
|
||||
ath12k_dp_rx_tid_del_func);
|
||||
if (ret) {
|
||||
ath12k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
|
||||
tid, ret);
|
||||
dma_unmap_single(ar->ab->dev, rx_tid->qbuf.paddr_aligned,
|
||||
rx_tid->qbuf.size, DMA_BIDIRECTIONAL);
|
||||
kfree(rx_tid->qbuf.vaddr);
|
||||
rx_tid->qbuf.vaddr = NULL;
|
||||
}
|
||||
|
||||
if (peer->mlo)
|
||||
ath12k_peer_rx_tid_qref_reset(ar->ab, peer->ml_id, tid);
|
||||
else
|
||||
ath12k_peer_rx_tid_qref_reset(ar->ab, peer->peer_id, tid);
|
||||
|
||||
rx_tid->active = false;
|
||||
|
||||
ath12k_dp_mark_tid_as_inactive(dp, peer->peer_id, tid);
|
||||
ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(dp);
|
||||
}
|
||||
|
||||
int ath12k_dp_rx_link_desc_return(struct ath12k_base *ab,
|
||||
@@ -941,9 +1003,12 @@ static int ath12k_peer_rx_tid_reo_update(struct ath12k *ar,
|
||||
{
|
||||
struct ath12k_hal_reo_cmd cmd = {};
|
||||
int ret;
|
||||
struct ath12k_dp_rx_tid_rxq rx_tid_rxq;
|
||||
|
||||
cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
ath12k_dp_init_rx_tid_rxq(&rx_tid_rxq, rx_tid);
|
||||
|
||||
cmd.addr_lo = lower_32_bits(rx_tid_rxq.qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid_rxq.qbuf.paddr_aligned);
|
||||
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
|
||||
cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE;
|
||||
cmd.ba_window_size = ba_win_sz;
|
||||
@@ -953,12 +1018,12 @@ static int ath12k_peer_rx_tid_reo_update(struct ath12k *ar,
|
||||
cmd.upd2 = u32_encode_bits(ssn, HAL_REO_CMD_UPD2_SSN);
|
||||
}
|
||||
|
||||
ret = ath12k_dp_reo_cmd_send(ar->ab, rx_tid,
|
||||
ret = ath12k_dp_reo_cmd_send(ar->ab, &rx_tid_rxq,
|
||||
HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
|
||||
NULL);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n",
|
||||
rx_tid->tid, ret);
|
||||
rx_tid_rxq.tid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1018,6 +1083,29 @@ static int ath12k_dp_rx_assign_reoq(struct ath12k_base *ab,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_dp_prepare_reo_update_elem(struct ath12k_dp *dp,
|
||||
struct ath12k_peer *peer,
|
||||
struct ath12k_dp_rx_tid *rx_tid)
|
||||
{
|
||||
struct dp_reo_update_rx_queue_elem *elem;
|
||||
|
||||
elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
|
||||
if (!elem)
|
||||
return -ENOMEM;
|
||||
|
||||
elem->peer_id = peer->peer_id;
|
||||
elem->is_ml_peer = peer->mlo;
|
||||
elem->ml_peer_id = peer->ml_id;
|
||||
|
||||
ath12k_dp_init_rx_tid_rxq(&elem->rx_tid, rx_tid);
|
||||
|
||||
spin_lock_bh(&dp->reo_rxq_flush_lock);
|
||||
list_add_tail(&elem->list, &dp->reo_cmd_update_rx_queue_list);
|
||||
spin_unlock_bh(&dp->reo_rxq_flush_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id,
|
||||
u8 tid, u32 ba_win_sz, u16 ssn,
|
||||
enum hal_pn_type pn_type)
|
||||
@@ -1098,6 +1186,19 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Pre-allocate the update_rxq_list for the corresponding tid
|
||||
* This will be used during the tid delete. The reason we are not
|
||||
* allocating during tid delete is that, if any alloc fail in update_rxq_list
|
||||
* we may not be able to delete the tid vaddr/paddr and may lead to leak
|
||||
*/
|
||||
ret = ath12k_dp_prepare_reo_update_elem(dp, peer, rx_tid);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to alloc update_rxq_list for rx tid %u\n", tid);
|
||||
ath12k_dp_rx_tid_cleanup(ab, &rx_tid->qbuf);
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
paddr_aligned = rx_tid->qbuf.paddr_aligned;
|
||||
if (ab->hw_params->reoq_lut_support) {
|
||||
/* Update the REO queue LUT at the corresponding peer id
|
||||
@@ -1207,6 +1308,7 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
|
||||
struct ath12k_hal_reo_cmd cmd = {};
|
||||
struct ath12k_peer *peer;
|
||||
struct ath12k_dp_rx_tid *rx_tid;
|
||||
struct ath12k_dp_rx_tid_rxq rx_tid_rxq;
|
||||
u8 tid;
|
||||
int ret = 0;
|
||||
|
||||
@@ -1253,9 +1355,11 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
|
||||
rx_tid = &peer->rx_tid[tid];
|
||||
if (!rx_tid->active)
|
||||
continue;
|
||||
cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned);
|
||||
ret = ath12k_dp_reo_cmd_send(ab, rx_tid,
|
||||
|
||||
ath12k_dp_init_rx_tid_rxq(&rx_tid_rxq, rx_tid);
|
||||
cmd.addr_lo = lower_32_bits(rx_tid_rxq.qbuf.paddr_aligned);
|
||||
cmd.addr_hi = upper_32_bits(rx_tid_rxq.qbuf.paddr_aligned);
|
||||
ret = ath12k_dp_reo_cmd_send(ab, &rx_tid_rxq,
|
||||
HAL_REO_CMD_UPDATE_RX_QUEUE,
|
||||
&cmd, NULL);
|
||||
if (ret) {
|
||||
@@ -2533,6 +2637,8 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info)
|
||||
channel_num = meta_data;
|
||||
center_freq = meta_data >> 16;
|
||||
|
||||
rx_status->band = NUM_NL80211_BANDS;
|
||||
|
||||
if (center_freq >= ATH12K_MIN_6GHZ_FREQ &&
|
||||
center_freq <= ATH12K_MAX_6GHZ_FREQ) {
|
||||
rx_status->band = NL80211_BAND_6GHZ;
|
||||
@@ -2541,21 +2647,33 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info)
|
||||
rx_status->band = NL80211_BAND_2GHZ;
|
||||
} else if (channel_num >= 36 && channel_num <= 173) {
|
||||
rx_status->band = NL80211_BAND_5GHZ;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (unlikely(rx_status->band == NUM_NL80211_BANDS ||
|
||||
!ath12k_ar_to_hw(ar)->wiphy->bands[rx_status->band])) {
|
||||
ath12k_warn(ar->ab, "sband is NULL for status band %d channel_num %d center_freq %d pdev_id %d\n",
|
||||
rx_status->band, channel_num, center_freq, ar->pdev_idx);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
channel = ar->rx_channel;
|
||||
if (channel) {
|
||||
rx_status->band = channel->band;
|
||||
channel_num =
|
||||
ieee80211_frequency_to_channel(channel->center_freq);
|
||||
rx_status->freq = ieee80211_channel_to_frequency(channel_num,
|
||||
rx_status->band);
|
||||
} else {
|
||||
ath12k_err(ar->ab, "unable to determine channel, band for rx packet");
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
goto h_rate;
|
||||
}
|
||||
|
||||
if (rx_status->band != NL80211_BAND_6GHZ)
|
||||
rx_status->freq = ieee80211_channel_to_frequency(channel_num,
|
||||
rx_status->band);
|
||||
|
||||
h_rate:
|
||||
ath12k_dp_rx_h_rate(ar, rx_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,15 +31,29 @@ struct ath12k_dp_rx_tid {
|
||||
struct ath12k_base *ab;
|
||||
};
|
||||
|
||||
struct ath12k_dp_rx_tid_rxq {
|
||||
u8 tid;
|
||||
bool active;
|
||||
struct ath12k_reoq_buf qbuf;
|
||||
};
|
||||
|
||||
struct ath12k_dp_rx_reo_cache_flush_elem {
|
||||
struct list_head list;
|
||||
struct ath12k_dp_rx_tid data;
|
||||
struct ath12k_dp_rx_tid_rxq data;
|
||||
unsigned long ts;
|
||||
};
|
||||
|
||||
struct dp_reo_update_rx_queue_elem {
|
||||
struct list_head list;
|
||||
struct ath12k_dp_rx_tid_rxq rx_tid;
|
||||
int peer_id;
|
||||
bool is_ml_peer;
|
||||
u16 ml_peer_id;
|
||||
};
|
||||
|
||||
struct ath12k_dp_rx_reo_cmd {
|
||||
struct list_head list;
|
||||
struct ath12k_dp_rx_tid data;
|
||||
struct ath12k_dp_rx_tid_rxq data;
|
||||
int cmd_num;
|
||||
void (*handler)(struct ath12k_dp *dp, void *ctx,
|
||||
enum hal_reo_cmd_status status);
|
||||
|
||||
@@ -832,6 +832,7 @@ enum hal_rx_buf_return_buf_manager {
|
||||
#define HAL_REO_CMD_FLG_FLUSH_ALL BIT(6)
|
||||
#define HAL_REO_CMD_FLG_UNBLK_RESOURCE BIT(7)
|
||||
#define HAL_REO_CMD_FLG_UNBLK_CACHE BIT(8)
|
||||
#define HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC BIT(9)
|
||||
|
||||
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* fields */
|
||||
#define HAL_REO_CMD_UPD0_RX_QUEUE_NUM BIT(8)
|
||||
|
||||
@@ -1225,6 +1225,7 @@ struct hal_reo_flush_queue {
|
||||
#define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_WO_INVALIDATE BIT(12)
|
||||
#define HAL_REO_FLUSH_CACHE_INFO0_BLOCK_CACHE_USAGE BIT(13)
|
||||
#define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL BIT(14)
|
||||
#define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_QUEUE_1K_DESC BIT(15)
|
||||
|
||||
struct hal_reo_flush_cache {
|
||||
struct hal_reo_cmd_hdr cmd;
|
||||
|
||||
@@ -89,6 +89,9 @@ static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal,
|
||||
if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_ALL)
|
||||
desc->info0 |= cpu_to_le32(HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL);
|
||||
|
||||
if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC)
|
||||
desc->info0 |= cpu_to_le32(HAL_REO_FLUSH_CACHE_INFO0_FLUSH_QUEUE_1K_DESC);
|
||||
|
||||
return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER);
|
||||
}
|
||||
|
||||
|
||||
@@ -483,15 +483,16 @@ enum hal_rx_ul_reception_type {
|
||||
HAL_RECEPTION_TYPE_FRAMELESS
|
||||
};
|
||||
|
||||
#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0)
|
||||
#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5)
|
||||
#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8)
|
||||
#define HAL_RX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0)
|
||||
#define HAL_RX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5)
|
||||
#define HAL_RX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8)
|
||||
#define HAL_RX_RSSI_LEGACY_INFO_INFO2_RSSI_COMB_PPDU GENMASK(7, 0)
|
||||
|
||||
struct hal_rx_phyrx_rssi_legacy_info {
|
||||
__le32 info0;
|
||||
__le32 rsvd0[39];
|
||||
__le32 info1;
|
||||
__le32 rsvd1;
|
||||
__le32 info2;
|
||||
} __packed;
|
||||
|
||||
#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16)
|
||||
@@ -695,7 +696,8 @@ struct hal_rx_resp_req_info {
|
||||
#define HAL_RX_MPDU_ERR_MPDU_LEN BIT(6)
|
||||
#define HAL_RX_MPDU_ERR_UNENCRYPTED_FRAME BIT(7)
|
||||
|
||||
#define HAL_RX_PHY_CMN_USER_INFO0_GI GENMASK(17, 16)
|
||||
#define HAL_RX_CMN_USR_INFO0_CP_SETTING GENMASK(17, 16)
|
||||
#define HAL_RX_CMN_USR_INFO0_LTF_SIZE GENMASK(19, 18)
|
||||
|
||||
struct hal_phyrx_common_user_info {
|
||||
__le32 rsvd[2];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <net/mac80211.h>
|
||||
@@ -1822,22 +1822,16 @@ void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb)
|
||||
skb);
|
||||
}
|
||||
|
||||
static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
|
||||
struct ath12k_link_vif *arvif)
|
||||
{
|
||||
u32 *vdev_id = data;
|
||||
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
|
||||
struct ath12k_link_vif *arvif = &ahvif->deflink;
|
||||
struct ieee80211_hw *hw;
|
||||
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
|
||||
struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
|
||||
|
||||
if (!arvif->is_created || arvif->vdev_id != *vdev_id)
|
||||
return;
|
||||
|
||||
if (!arvif->is_up)
|
||||
if (!(arvif->is_created && arvif->is_up))
|
||||
return;
|
||||
|
||||
ieee80211_beacon_loss(vif);
|
||||
hw = ath12k_ar_to_hw(arvif->ar);
|
||||
|
||||
/* Firmware doesn't report beacon loss events repeatedly. If AP probe
|
||||
* (done by mac80211) succeeds but beacons do not resume then it
|
||||
@@ -1848,14 +1842,6 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
|
||||
ATH12K_CONNECTION_LOSS_HZ);
|
||||
}
|
||||
|
||||
void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id)
|
||||
{
|
||||
ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar),
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath12k_mac_handle_beacon_miss_iter,
|
||||
&vdev_id);
|
||||
}
|
||||
|
||||
static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
|
||||
{
|
||||
struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif,
|
||||
@@ -9860,6 +9846,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
|
||||
|
||||
param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
|
||||
param_value = hw->wiphy->rts_threshold;
|
||||
ar->rts_threshold = param_value;
|
||||
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
|
||||
param_id, param_value);
|
||||
if (ret) {
|
||||
@@ -11240,8 +11227,8 @@ void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
|
||||
struct ieee80211_channel *chan, *temp_chan;
|
||||
u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
|
||||
bool is_psd_power = false, is_tpe_present = false;
|
||||
s8 max_tx_power[ATH12K_NUM_PWR_LEVELS],
|
||||
psd_power, tx_power, eirp_power;
|
||||
s8 max_tx_power[ATH12K_NUM_PWR_LEVELS], psd_power, tx_power;
|
||||
s8 eirp_power = 0;
|
||||
struct ath12k_vif *ahvif = arvif->ahvif;
|
||||
u16 start_freq, center_freq;
|
||||
u8 reg_6ghz_power_mode;
|
||||
@@ -11447,8 +11434,10 @@ static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
|
||||
|
||||
tpc_info->num_pwr_levels = max(local_psd->count,
|
||||
reg_psd->count);
|
||||
if (tpc_info->num_pwr_levels > ATH12K_NUM_PWR_LEVELS)
|
||||
tpc_info->num_pwr_levels = ATH12K_NUM_PWR_LEVELS;
|
||||
tpc_info->num_pwr_levels =
|
||||
min3(tpc_info->num_pwr_levels,
|
||||
IEEE80211_TPE_PSD_ENTRIES_320MHZ,
|
||||
ATH12K_NUM_PWR_LEVELS);
|
||||
|
||||
for (i = 0; i < tpc_info->num_pwr_levels; i++) {
|
||||
tpc_info->tpe[i] = min(local_psd->power[i],
|
||||
@@ -11463,8 +11452,10 @@ static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
|
||||
|
||||
tpc_info->num_pwr_levels = max(local_non_psd->count,
|
||||
reg_non_psd->count);
|
||||
if (tpc_info->num_pwr_levels > ATH12K_NUM_PWR_LEVELS)
|
||||
tpc_info->num_pwr_levels = ATH12K_NUM_PWR_LEVELS;
|
||||
tpc_info->num_pwr_levels =
|
||||
min3(tpc_info->num_pwr_levels,
|
||||
IEEE80211_TPE_EIRP_ENTRIES_320MHZ,
|
||||
ATH12K_NUM_PWR_LEVELS);
|
||||
|
||||
for (i = 0; i < tpc_info->num_pwr_levels; i++) {
|
||||
tpc_info->tpe[i] = min(local_non_psd->power[i],
|
||||
@@ -11687,16 +11678,32 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw,
|
||||
int radio_idx, u32 value)
|
||||
{
|
||||
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
struct ath12k *ar;
|
||||
int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret = 0, i;
|
||||
int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
|
||||
int ret = 0, ret_err, i;
|
||||
|
||||
lockdep_assert_wiphy(hw->wiphy);
|
||||
|
||||
/* Currently we set the rts threshold value to all the vifs across
|
||||
* all radios of the single wiphy.
|
||||
* TODO Once support for vif specific RTS threshold in mac80211 is
|
||||
* available, ath12k can make use of it.
|
||||
*/
|
||||
if (radio_idx >= wiphy->n_radio || radio_idx < -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (radio_idx != -1) {
|
||||
/* Update RTS threshold in specified radio */
|
||||
ar = ath12k_ah_to_ar(ah, radio_idx);
|
||||
ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to set RTS config for all vdevs of pdev %d",
|
||||
ar->pdev->pdev_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->rts_threshold = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Radio_index passed is -1, so set RTS threshold for all radios. */
|
||||
for_each_ar(ah, ar, i) {
|
||||
ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value);
|
||||
if (ret) {
|
||||
@@ -11705,6 +11712,25 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
/* Setting new RTS threshold for vdevs of all radios passed, so update
|
||||
* the RTS threshold value for all radios
|
||||
*/
|
||||
for_each_ar(ah, ar, i)
|
||||
ar->rts_threshold = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RTS threshold config failed, revert to the previous RTS threshold */
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
ar = ath12k_ah_to_ar(ah, i);
|
||||
ret_err = ath12k_set_vdev_param_to_all_vifs(ar, param_id,
|
||||
ar->rts_threshold);
|
||||
if (ret_err)
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to restore RTS threshold for all vdevs of pdev %d",
|
||||
ar->pdev->pdev_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -12610,6 +12636,27 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_mac_put_chain_rssi(struct station_info *sinfo,
|
||||
struct ath12k_link_sta *arsta)
|
||||
{
|
||||
s8 rssi;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
|
||||
sinfo->chains &= ~BIT(i);
|
||||
rssi = arsta->chain_signal[i];
|
||||
|
||||
if (rssi != ATH12K_DEFAULT_NOISE_FLOOR &&
|
||||
rssi != ATH12K_INVALID_RSSI_FULL &&
|
||||
rssi != ATH12K_INVALID_RSSI_EMPTY &&
|
||||
rssi != 0) {
|
||||
sinfo->chain_signal[i] = rssi;
|
||||
sinfo->chains |= BIT(i);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
@@ -12667,6 +12714,12 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
|
||||
!(ath12k_mac_get_fw_stats(ar, ¶ms)))
|
||||
signal = arsta->rssi_beacon;
|
||||
|
||||
params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT;
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) &&
|
||||
ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
|
||||
!(ath12k_mac_get_fw_stats(ar, ¶ms)))
|
||||
ath12k_mac_put_chain_rssi(sinfo, arsta);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
noise_floor = ath12k_pdev_get_noise_floor(ar);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
@@ -168,7 +168,8 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
|
||||
int ath12k_mac_rfkill_config(struct ath12k *ar);
|
||||
int ath12k_mac_wait_tx_complete(struct ath12k *ar);
|
||||
void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb);
|
||||
void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id);
|
||||
void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
|
||||
struct ath12k_link_vif *arvif);
|
||||
int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif,
|
||||
enum wmi_sta_keepalive_method method,
|
||||
u32 interval);
|
||||
|
||||
@@ -3307,20 +3307,28 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab)
|
||||
/* This is number of CE configs */
|
||||
req->tgt_cfg_len = ab->qmi.ce_cfg.tgt_ce_len;
|
||||
for (pipe_num = 0; pipe_num < req->tgt_cfg_len ; pipe_num++) {
|
||||
req->tgt_cfg[pipe_num].pipe_num = ce_cfg[pipe_num].pipenum;
|
||||
req->tgt_cfg[pipe_num].pipe_dir = ce_cfg[pipe_num].pipedir;
|
||||
req->tgt_cfg[pipe_num].nentries = ce_cfg[pipe_num].nentries;
|
||||
req->tgt_cfg[pipe_num].nbytes_max = ce_cfg[pipe_num].nbytes_max;
|
||||
req->tgt_cfg[pipe_num].flags = ce_cfg[pipe_num].flags;
|
||||
req->tgt_cfg[pipe_num].pipe_num =
|
||||
__le32_to_cpu(ce_cfg[pipe_num].pipenum);
|
||||
req->tgt_cfg[pipe_num].pipe_dir =
|
||||
__le32_to_cpu(ce_cfg[pipe_num].pipedir);
|
||||
req->tgt_cfg[pipe_num].nentries =
|
||||
__le32_to_cpu(ce_cfg[pipe_num].nentries);
|
||||
req->tgt_cfg[pipe_num].nbytes_max =
|
||||
__le32_to_cpu(ce_cfg[pipe_num].nbytes_max);
|
||||
req->tgt_cfg[pipe_num].flags =
|
||||
__le32_to_cpu(ce_cfg[pipe_num].flags);
|
||||
}
|
||||
|
||||
req->svc_cfg_valid = 1;
|
||||
/* This is number of Service/CE configs */
|
||||
req->svc_cfg_len = ab->qmi.ce_cfg.svc_to_ce_map_len;
|
||||
for (pipe_num = 0; pipe_num < req->svc_cfg_len; pipe_num++) {
|
||||
req->svc_cfg[pipe_num].service_id = svc_cfg[pipe_num].service_id;
|
||||
req->svc_cfg[pipe_num].pipe_dir = svc_cfg[pipe_num].pipedir;
|
||||
req->svc_cfg[pipe_num].pipe_num = svc_cfg[pipe_num].pipenum;
|
||||
req->svc_cfg[pipe_num].service_id =
|
||||
__le32_to_cpu(svc_cfg[pipe_num].service_id);
|
||||
req->svc_cfg[pipe_num].pipe_dir =
|
||||
__le32_to_cpu(svc_cfg[pipe_num].pipedir);
|
||||
req->svc_cfg[pipe_num].pipe_num =
|
||||
__le32_to_cpu(svc_cfg[pipe_num].pipenum);
|
||||
}
|
||||
|
||||
/* set shadow v3 configuration */
|
||||
|
||||
@@ -392,17 +392,17 @@ enum qmi_wlanfw_pipedir_enum_v01 {
|
||||
};
|
||||
|
||||
struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01 {
|
||||
__le32 pipe_num;
|
||||
__le32 pipe_dir;
|
||||
__le32 nentries;
|
||||
__le32 nbytes_max;
|
||||
__le32 flags;
|
||||
u32 pipe_num;
|
||||
u32 pipe_dir;
|
||||
u32 nentries;
|
||||
u32 nbytes_max;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01 {
|
||||
__le32 service_id;
|
||||
__le32 pipe_dir;
|
||||
__le32 pipe_num;
|
||||
u32 service_id;
|
||||
u32 pipe_dir;
|
||||
u32 pipe_num;
|
||||
};
|
||||
|
||||
struct qmi_wlanfw_shadow_reg_cfg_s_v01 {
|
||||
|
||||
@@ -30,6 +30,9 @@ struct ath12k_wmi_svc_ready_parse {
|
||||
struct wmi_tlv_fw_stats_parse {
|
||||
const struct wmi_stats_event *ev;
|
||||
struct ath12k_fw_stats *stats;
|
||||
const struct wmi_per_chain_rssi_stat_params *rssi;
|
||||
int rssi_num;
|
||||
bool chain_rssi_done;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_dma_ring_caps_parse {
|
||||
@@ -185,6 +188,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
|
||||
.min_len = sizeof(struct wmi_p2p_noa_event) },
|
||||
[WMI_TAG_11D_NEW_COUNTRY_EVENT] = {
|
||||
.min_len = sizeof(struct wmi_11d_new_cc_event) },
|
||||
[WMI_TAG_PER_CHAIN_RSSI_STATS] = {
|
||||
.min_len = sizeof(struct wmi_per_chain_rssi_stat_params) },
|
||||
};
|
||||
|
||||
__le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
|
||||
@@ -6462,6 +6467,8 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
|
||||
}
|
||||
|
||||
arg->mac_addr = ev->peer_macaddr.addr;
|
||||
arg->reason = le32_to_cpu(ev->reason);
|
||||
arg->rssi = le32_to_cpu(ev->rssi);
|
||||
|
||||
kfree(tb);
|
||||
return 0;
|
||||
@@ -7298,8 +7305,10 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
{
|
||||
struct wmi_peer_sta_kickout_arg arg = {};
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath12k_peer *peer;
|
||||
unsigned int link_id;
|
||||
struct ath12k *ar;
|
||||
|
||||
if (ath12k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) {
|
||||
@@ -7319,25 +7328,49 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ar = ath12k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
|
||||
if (!ar) {
|
||||
arvif = ath12k_mac_get_arvif_by_vdev_id(ab, peer->vdev_id);
|
||||
if (!arvif) {
|
||||
ath12k_warn(ab, "invalid vdev id in peer sta kickout ev %d",
|
||||
peer->vdev_id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
|
||||
arg.mac_addr, NULL);
|
||||
ar = arvif->ar;
|
||||
|
||||
if (peer->mlo) {
|
||||
sta = ieee80211_find_sta_by_link_addrs(ath12k_ar_to_hw(ar),
|
||||
arg.mac_addr,
|
||||
NULL, &link_id);
|
||||
if (peer->link_id != link_id) {
|
||||
ath12k_warn(ab,
|
||||
"Spurious quick kickout for MLO STA %pM with invalid link_id, peer: %d, sta: %d\n",
|
||||
arg.mac_addr, peer->link_id, link_id);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
|
||||
arg.mac_addr, NULL);
|
||||
}
|
||||
if (!sta) {
|
||||
ath12k_warn(ab, "Spurious quick kickout for STA %pM\n",
|
||||
arg.mac_addr);
|
||||
ath12k_warn(ab, "Spurious quick kickout for %sSTA %pM\n",
|
||||
peer->mlo ? "MLO " : "", arg.mac_addr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "peer sta kickout event %pM",
|
||||
arg.mac_addr);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"peer sta kickout event %pM reason: %d rssi: %d\n",
|
||||
arg.mac_addr, arg.reason, arg.rssi);
|
||||
|
||||
ieee80211_report_low_ack(sta, 10);
|
||||
switch (arg.reason) {
|
||||
case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY:
|
||||
if (arvif->ahvif->vif->type == NL80211_IFTYPE_STATION) {
|
||||
ath12k_mac_handle_beacon_miss(ar, arvif);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
ieee80211_report_low_ack(sta, 10);
|
||||
}
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
@@ -7346,6 +7379,7 @@ exit:
|
||||
|
||||
static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
{
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct wmi_roam_event roam_ev = {};
|
||||
struct ath12k *ar;
|
||||
u32 vdev_id;
|
||||
@@ -7364,21 +7398,22 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
"wmi roam event vdev %u reason %d rssi %d\n",
|
||||
vdev_id, roam_reason, roam_ev.rssi);
|
||||
|
||||
rcu_read_lock();
|
||||
ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
|
||||
if (!ar) {
|
||||
guard(rcu)();
|
||||
arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_id);
|
||||
if (!arvif) {
|
||||
ath12k_warn(ab, "invalid vdev id in roam ev %d", vdev_id);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
ar = arvif->ar;
|
||||
|
||||
if (roam_reason >= WMI_ROAM_REASON_MAX)
|
||||
ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n",
|
||||
roam_reason, vdev_id);
|
||||
|
||||
switch (roam_reason) {
|
||||
case WMI_ROAM_REASON_BEACON_MISS:
|
||||
ath12k_mac_handle_beacon_miss(ar, vdev_id);
|
||||
ath12k_mac_handle_beacon_miss(ar, arvif);
|
||||
break;
|
||||
case WMI_ROAM_REASON_BETTER_AP:
|
||||
case WMI_ROAM_REASON_LOW_RSSI:
|
||||
@@ -7388,8 +7423,6 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
roam_reason, vdev_id);
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
@@ -8219,6 +8252,77 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
|
||||
u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
{
|
||||
const struct wmi_rssi_stat_params *stats_rssi = ptr;
|
||||
struct wmi_tlv_fw_stats_parse *parse = data;
|
||||
const struct wmi_stats_event *ev = parse->ev;
|
||||
struct ath12k_fw_stats *stats = parse->stats;
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ath12k_link_sta *arsta;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath12k_sta *ahsta;
|
||||
struct ath12k *ar;
|
||||
int vdev_id;
|
||||
int j;
|
||||
|
||||
if (!ev) {
|
||||
ath12k_warn(ab, "failed to fetch update stats ev");
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (tag != WMI_TAG_RSSI_STATS)
|
||||
return -EPROTO;
|
||||
|
||||
if (!stats)
|
||||
return -EINVAL;
|
||||
|
||||
stats->pdev_id = le32_to_cpu(ev->pdev_id);
|
||||
vdev_id = le32_to_cpu(stats_rssi->vdev_id);
|
||||
guard(rcu)();
|
||||
ar = ath12k_mac_get_ar_by_pdev_id(ab, stats->pdev_id);
|
||||
if (!ar) {
|
||||
ath12k_warn(ab, "invalid pdev id %d in rssi chain parse\n",
|
||||
stats->pdev_id);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
arvif = ath12k_mac_get_arvif(ar, vdev_id);
|
||||
if (!arvif) {
|
||||
ath12k_warn(ab, "not found vif for vdev id %d\n", vdev_id);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"stats bssid %pM vif %p\n",
|
||||
arvif->bssid, arvif->ahvif->vif);
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
|
||||
arvif->bssid,
|
||||
NULL);
|
||||
if (!sta) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"not found station of bssid %pM for rssi chain\n",
|
||||
arvif->bssid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
ahsta = ath12k_sta_to_ahsta(sta);
|
||||
arsta = &ahsta->deflink;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
|
||||
ARRAY_SIZE(stats_rssi->rssi_avg_beacon));
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(arsta->chain_signal); j++)
|
||||
arsta->chain_signal[j] = le32_to_cpu(stats_rssi->rssi_avg_beacon[j]);
|
||||
|
||||
stats->stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_wmi_tlv_fw_stats_parse(struct ath12k_base *ab,
|
||||
u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
@@ -8233,6 +8337,22 @@ static int ath12k_wmi_tlv_fw_stats_parse(struct ath12k_base *ab,
|
||||
case WMI_TAG_ARRAY_BYTE:
|
||||
ret = ath12k_wmi_tlv_fw_stats_data_parse(ab, parse, ptr, len);
|
||||
break;
|
||||
case WMI_TAG_PER_CHAIN_RSSI_STATS:
|
||||
parse->rssi = ptr;
|
||||
if (le32_to_cpu(parse->ev->stats_id) & WMI_REQUEST_RSSI_PER_CHAIN_STAT)
|
||||
parse->rssi_num = le32_to_cpu(parse->rssi->num_per_chain_rssi);
|
||||
break;
|
||||
case WMI_TAG_ARRAY_STRUCT:
|
||||
if (parse->rssi_num && !parse->chain_rssi_done) {
|
||||
ret = ath12k_wmi_tlv_iter(ab, ptr, len,
|
||||
ath12k_wmi_tlv_rssi_chain_parse,
|
||||
parse);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
parse->chain_rssi_done = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -8346,6 +8466,12 @@ static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *sk
|
||||
goto complete;
|
||||
}
|
||||
|
||||
/* Handle WMI_REQUEST_RSSI_PER_CHAIN_STAT status update */
|
||||
if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
|
||||
complete(&ar->fw_stats_done);
|
||||
goto complete;
|
||||
}
|
||||
|
||||
/* Handle WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT updates. */
|
||||
ath12k_wmi_fw_stats_process(ar, &stats);
|
||||
|
||||
|
||||
@@ -4548,12 +4548,27 @@ struct wmi_scan_event {
|
||||
__le32 tsf_timestamp;
|
||||
} __packed;
|
||||
|
||||
enum wmi_peer_sta_kickout_reason {
|
||||
WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED = 0,
|
||||
WMI_PEER_STA_KICKOUT_REASON_XRETRY = 1,
|
||||
WMI_PEER_STA_KICKOUT_REASON_INACTIVITY = 2,
|
||||
WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT = 3,
|
||||
WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT = 4,
|
||||
WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT = 5,
|
||||
WMI_PEER_STA_KICKOUT_REASON_ROAMING_EVENT = 6,
|
||||
WMI_PEER_STA_KICKOUT_REASON_PMF_ERROR = 7,
|
||||
};
|
||||
|
||||
struct wmi_peer_sta_kickout_arg {
|
||||
const u8 *mac_addr;
|
||||
enum wmi_peer_sta_kickout_reason reason;
|
||||
u32 rssi;
|
||||
};
|
||||
|
||||
struct wmi_peer_sta_kickout_event {
|
||||
struct ath12k_wmi_mac_addr_params peer_macaddr;
|
||||
__le32 reason;
|
||||
__le32 rssi;
|
||||
} __packed;
|
||||
|
||||
#define WMI_ROAM_REASON_MASK GENMASK(3, 0)
|
||||
@@ -5875,9 +5890,10 @@ struct wmi_stats_event {
|
||||
} __packed;
|
||||
|
||||
enum wmi_stats_id {
|
||||
WMI_REQUEST_PDEV_STAT = BIT(2),
|
||||
WMI_REQUEST_VDEV_STAT = BIT(3),
|
||||
WMI_REQUEST_BCN_STAT = BIT(11),
|
||||
WMI_REQUEST_PDEV_STAT = BIT(2),
|
||||
WMI_REQUEST_VDEV_STAT = BIT(3),
|
||||
WMI_REQUEST_RSSI_PER_CHAIN_STAT = BIT(8),
|
||||
WMI_REQUEST_BCN_STAT = BIT(11),
|
||||
};
|
||||
|
||||
struct wmi_request_stats_cmd {
|
||||
@@ -5888,6 +5904,17 @@ struct wmi_request_stats_cmd {
|
||||
__le32 pdev_id;
|
||||
} __packed;
|
||||
|
||||
struct wmi_rssi_stat_params {
|
||||
__le32 vdev_id;
|
||||
__le32 rssi_avg_beacon[WMI_MAX_CHAINS];
|
||||
__le32 rssi_avg_data[WMI_MAX_CHAINS];
|
||||
struct ath12k_wmi_mac_addr_params peer_macaddr;
|
||||
} __packed;
|
||||
|
||||
struct wmi_per_chain_rssi_stat_params {
|
||||
__le32 num_per_chain_rssi;
|
||||
} __packed;
|
||||
|
||||
#define WLAN_MAX_AC 4
|
||||
#define MAX_TX_RATE_VALUES 10
|
||||
|
||||
|
||||
@@ -1181,7 +1181,8 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||
spin_lock_init(&card->lock);
|
||||
INIT_LIST_HEAD(&card->packets);
|
||||
|
||||
card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0);
|
||||
card->workqueue = alloc_workqueue("libertas_sdio",
|
||||
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
if (unlikely(!card->workqueue)) {
|
||||
ret = -ENOMEM;
|
||||
goto err_queue;
|
||||
|
||||
@@ -1153,7 +1153,8 @@ static int if_spi_probe(struct spi_device *spi)
|
||||
priv->fw_ready = 1;
|
||||
|
||||
/* Initialize interrupt handling stuff. */
|
||||
card->workqueue = alloc_workqueue("libertas_spi", WQ_MEM_RECLAIM, 0);
|
||||
card->workqueue = alloc_workqueue("libertas_spi",
|
||||
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
if (!card->workqueue) {
|
||||
err = -ENOMEM;
|
||||
goto remove_card;
|
||||
|
||||
@@ -708,7 +708,7 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
|
||||
static int __init lbtf_init_module(void)
|
||||
{
|
||||
lbtf_deb_enter(LBTF_DEB_MAIN);
|
||||
lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM, 0);
|
||||
lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
if (lbtf_wq == NULL) {
|
||||
printk(KERN_ERR "libertastf: couldn't create workqueue\n");
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -173,6 +173,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
|
||||
if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
|
||||
return;
|
||||
|
||||
if (wcid->def_wcid)
|
||||
wcid = wcid->def_wcid;
|
||||
tid = rcu_dereference(wcid->aggr[tidno]);
|
||||
if (!tid)
|
||||
return;
|
||||
|
||||
@@ -314,21 +314,24 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
||||
kfree(mlink);
|
||||
}
|
||||
|
||||
static void mt76_roc_complete(struct mt76_phy *phy)
|
||||
void mt76_roc_complete(struct mt76_phy *phy)
|
||||
{
|
||||
struct mt76_vif_link *mlink = phy->roc_link;
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
|
||||
if (!phy->roc_vif)
|
||||
return;
|
||||
|
||||
if (mlink)
|
||||
mlink->mvif->roc_phy = NULL;
|
||||
if (phy->main_chandef.chan)
|
||||
if (phy->main_chandef.chan &&
|
||||
!test_bit(MT76_MCU_RESET, &dev->phy.state))
|
||||
mt76_set_channel(phy, &phy->main_chandef, false);
|
||||
mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
|
||||
phy->roc_vif = NULL;
|
||||
phy->roc_link = NULL;
|
||||
ieee80211_remain_on_channel_expired(phy->hw);
|
||||
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
|
||||
ieee80211_remain_on_channel_expired(phy->hw);
|
||||
}
|
||||
|
||||
void mt76_roc_complete_work(struct work_struct *work)
|
||||
@@ -351,6 +354,7 @@ void mt76_abort_roc(struct mt76_phy *phy)
|
||||
mt76_roc_complete(phy);
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_abort_roc);
|
||||
|
||||
int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan, int duration,
|
||||
@@ -368,7 +372,8 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
if (phy->roc_vif || dev->scan.phy == phy) {
|
||||
if (phy->roc_vif || dev->scan.phy == phy ||
|
||||
test_bit(MT76_MCU_RESET, &dev->phy.state)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -185,6 +185,37 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi);
|
||||
|
||||
static void
|
||||
mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
if (!mt76_queue_is_wed_rro(q))
|
||||
return;
|
||||
|
||||
q->magic_cnt = 0;
|
||||
if (mt76_queue_is_wed_rro_ind(q)) {
|
||||
struct mt76_wed_rro_desc *rro_desc;
|
||||
u32 data1 = FIELD_PREP(RRO_IND_DATA1_MAGIC_CNT_MASK,
|
||||
MT_DMA_WED_IND_CMD_CNT - 1);
|
||||
int i;
|
||||
|
||||
rro_desc = (struct mt76_wed_rro_desc *)q->desc;
|
||||
for (i = 0; i < q->ndesc; i++) {
|
||||
struct mt76_wed_rro_ind *cmd;
|
||||
|
||||
cmd = (struct mt76_wed_rro_ind *)&rro_desc[i];
|
||||
cmd->data1 = cpu_to_le32(data1);
|
||||
}
|
||||
} else if (mt76_queue_is_wed_rro_rxdmad_c(q)) {
|
||||
struct mt76_rro_rxdmad_c *dmad = (void *)q->desc;
|
||||
u32 data3 = FIELD_PREP(RRO_RXDMAD_DATA3_MAGIC_CNT_MASK,
|
||||
MT_DMA_MAGIC_CNT - 1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < q->ndesc; i++)
|
||||
dmad[i].data3 = cpu_to_le32(data3);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
@@ -197,13 +228,14 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
q->tail = q->head;
|
||||
}
|
||||
|
||||
void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool reset_idx)
|
||||
void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool reset_idx)
|
||||
{
|
||||
if (!q || !q->ndesc)
|
||||
return;
|
||||
|
||||
if (!mt76_queue_is_wed_rro_ind(q)) {
|
||||
if (!mt76_queue_is_wed_rro_ind(q) &&
|
||||
!mt76_queue_is_wed_rro_rxdmad_c(q)) {
|
||||
int i;
|
||||
|
||||
/* clear descriptors */
|
||||
@@ -211,27 +243,26 @@ void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
|
||||
}
|
||||
|
||||
mt76_dma_queue_magic_cnt_init(dev, q);
|
||||
if (reset_idx) {
|
||||
Q_WRITE(q, cpu_idx, 0);
|
||||
if (mt76_queue_is_emi(q))
|
||||
*q->emi_cpu_idx = 0;
|
||||
else
|
||||
Q_WRITE(q, cpu_idx, 0);
|
||||
Q_WRITE(q, dma_idx, 0);
|
||||
}
|
||||
mt76_dma_sync_idx(dev, q);
|
||||
}
|
||||
|
||||
void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
__mt76_dma_queue_reset(dev, q, true);
|
||||
}
|
||||
|
||||
static int
|
||||
mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
struct mt76_queue_buf *buf, void *data)
|
||||
{
|
||||
struct mt76_queue_entry *entry = &q->entry[q->head];
|
||||
struct mt76_txwi_cache *txwi = NULL;
|
||||
u32 buf1 = 0, ctrl, info = 0;
|
||||
struct mt76_desc *desc;
|
||||
int idx = q->head;
|
||||
u32 buf1 = 0, ctrl;
|
||||
int rx_token;
|
||||
|
||||
if (mt76_queue_is_wed_rro_ind(q)) {
|
||||
@@ -240,6 +271,9 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
rro_desc = (struct mt76_wed_rro_desc *)q->desc;
|
||||
data = &rro_desc[q->head];
|
||||
goto done;
|
||||
} else if (mt76_queue_is_wed_rro_rxdmad_c(q)) {
|
||||
data = &q->desc[q->head];
|
||||
goto done;
|
||||
}
|
||||
|
||||
desc = &q->desc[q->head];
|
||||
@@ -248,7 +282,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32);
|
||||
#endif
|
||||
|
||||
if (mt76_queue_is_wed_rx(q)) {
|
||||
if (mt76_queue_is_wed_rx(q) || mt76_queue_is_wed_rro_data(q)) {
|
||||
txwi = mt76_get_rxwi(dev);
|
||||
if (!txwi)
|
||||
return -ENOMEM;
|
||||
@@ -261,12 +295,26 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
|
||||
buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);
|
||||
ctrl |= MT_DMA_CTL_TO_HOST;
|
||||
|
||||
txwi->qid = q - dev->q_rx;
|
||||
}
|
||||
|
||||
if (mt76_queue_is_wed_rro_msdu_pg(q) &&
|
||||
dev->drv->rx_rro_add_msdu_page) {
|
||||
if (dev->drv->rx_rro_add_msdu_page(dev, q, buf->addr, data))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (q->flags & MT_QFLAG_WED_RRO_EN) {
|
||||
info |= FIELD_PREP(MT_DMA_MAGIC_MASK, q->magic_cnt);
|
||||
if ((q->head + 1) == q->ndesc)
|
||||
q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT;
|
||||
}
|
||||
|
||||
WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr));
|
||||
WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
|
||||
WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
|
||||
WRITE_ONCE(desc->info, 0);
|
||||
WRITE_ONCE(desc->info, cpu_to_le32(info));
|
||||
|
||||
done:
|
||||
entry->dma_addr[0] = buf->addr;
|
||||
@@ -375,7 +423,10 @@ static void
|
||||
mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
wmb();
|
||||
Q_WRITE(q, cpu_idx, q->head);
|
||||
if (mt76_queue_is_emi(q))
|
||||
*q->emi_cpu_idx = cpu_to_le16(q->head);
|
||||
else
|
||||
Q_WRITE(q, cpu_idx, q->head);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -418,16 +469,62 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
|
||||
wake_up(&dev->tx_wait);
|
||||
}
|
||||
|
||||
static void *
|
||||
mt76_dma_get_rxdmad_c_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
int idx, int *len, bool *more)
|
||||
{
|
||||
struct mt76_queue_entry *e = &q->entry[idx];
|
||||
struct mt76_rro_rxdmad_c *dmad = e->buf;
|
||||
u32 data1 = le32_to_cpu(dmad->data1);
|
||||
u32 data2 = le32_to_cpu(dmad->data2);
|
||||
struct mt76_txwi_cache *t;
|
||||
u16 rx_token_id;
|
||||
u8 ind_reason;
|
||||
void *buf;
|
||||
|
||||
rx_token_id = FIELD_GET(RRO_RXDMAD_DATA2_RX_TOKEN_ID_MASK, data2);
|
||||
t = mt76_rx_token_release(dev, rx_token_id);
|
||||
if (!t)
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
q = &dev->q_rx[t->qid];
|
||||
dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr,
|
||||
SKB_WITH_OVERHEAD(q->buf_size),
|
||||
page_pool_get_dma_dir(q->page_pool));
|
||||
|
||||
if (len)
|
||||
*len = FIELD_GET(RRO_RXDMAD_DATA1_SDL0_MASK, data1);
|
||||
if (more)
|
||||
*more = !FIELD_GET(RRO_RXDMAD_DATA1_LS_MASK, data1);
|
||||
|
||||
buf = t->ptr;
|
||||
ind_reason = FIELD_GET(RRO_RXDMAD_DATA2_IND_REASON_MASK, data2);
|
||||
if (ind_reason == MT_DMA_WED_IND_REASON_REPEAT ||
|
||||
ind_reason == MT_DMA_WED_IND_REASON_OLDPKT) {
|
||||
mt76_put_page_pool_buf(buf, false);
|
||||
buf = ERR_PTR(-EAGAIN);
|
||||
}
|
||||
t->ptr = NULL;
|
||||
t->dma_addr = 0;
|
||||
|
||||
mt76_put_rxwi(dev, t);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void *
|
||||
mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
|
||||
int *len, u32 *info, bool *more, bool *drop)
|
||||
int *len, u32 *info, bool *more, bool *drop, bool flush)
|
||||
{
|
||||
struct mt76_queue_entry *e = &q->entry[idx];
|
||||
struct mt76_desc *desc = &q->desc[idx];
|
||||
u32 ctrl, desc_info, buf1;
|
||||
void *buf = e->buf;
|
||||
|
||||
if (mt76_queue_is_wed_rro_ind(q))
|
||||
if (mt76_queue_is_wed_rro_rxdmad_c(q) && !flush)
|
||||
buf = mt76_dma_get_rxdmad_c_buf(dev, q, idx, len, more);
|
||||
|
||||
if (mt76_queue_is_wed_rro(q))
|
||||
goto done;
|
||||
|
||||
ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
|
||||
@@ -482,20 +579,50 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
|
||||
if (!q->queued)
|
||||
return NULL;
|
||||
|
||||
if (mt76_queue_is_wed_rro_data(q))
|
||||
return NULL;
|
||||
if (mt76_queue_is_wed_rro_data(q) || mt76_queue_is_wed_rro_msdu_pg(q))
|
||||
goto done;
|
||||
|
||||
if (!mt76_queue_is_wed_rro_ind(q)) {
|
||||
if (mt76_queue_is_wed_rro_ind(q)) {
|
||||
struct mt76_wed_rro_ind *cmd;
|
||||
u8 magic_cnt;
|
||||
|
||||
if (flush)
|
||||
goto done;
|
||||
|
||||
cmd = q->entry[idx].buf;
|
||||
magic_cnt = FIELD_GET(RRO_IND_DATA1_MAGIC_CNT_MASK,
|
||||
le32_to_cpu(cmd->data1));
|
||||
if (magic_cnt != q->magic_cnt)
|
||||
return NULL;
|
||||
|
||||
if (q->tail == q->ndesc - 1)
|
||||
q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_WED_IND_CMD_CNT;
|
||||
} else if (mt76_queue_is_wed_rro_rxdmad_c(q)) {
|
||||
struct mt76_rro_rxdmad_c *dmad;
|
||||
u16 magic_cnt;
|
||||
|
||||
if (flush)
|
||||
goto done;
|
||||
|
||||
dmad = q->entry[idx].buf;
|
||||
magic_cnt = FIELD_GET(RRO_RXDMAD_DATA3_MAGIC_CNT_MASK,
|
||||
le32_to_cpu(dmad->data3));
|
||||
if (magic_cnt != q->magic_cnt)
|
||||
return NULL;
|
||||
|
||||
if (q->tail == q->ndesc - 1)
|
||||
q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT;
|
||||
} else {
|
||||
if (flush)
|
||||
q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE);
|
||||
else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
done:
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
q->queued--;
|
||||
|
||||
return mt76_dma_get_buf(dev, q, idx, len, info, more, drop);
|
||||
return mt76_dma_get_buf(dev, q, idx, len, info, more, drop, flush);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -646,7 +773,8 @@ mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
void *buf = NULL;
|
||||
int offset;
|
||||
|
||||
if (mt76_queue_is_wed_rro_ind(q))
|
||||
if (mt76_queue_is_wed_rro_ind(q) ||
|
||||
mt76_queue_is_wed_rro_rxdmad_c(q))
|
||||
goto done;
|
||||
|
||||
buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
|
||||
@@ -676,9 +804,6 @@ int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
{
|
||||
int frames;
|
||||
|
||||
if (!q->ndesc)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
frames = mt76_dma_rx_fill_buf(dev, q, allow_direct);
|
||||
spin_unlock_bh(&q->lock);
|
||||
@@ -708,19 +833,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
if (!q->desc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mt76_queue_is_wed_rro_ind(q)) {
|
||||
struct mt76_wed_rro_desc *rro_desc;
|
||||
int i;
|
||||
|
||||
rro_desc = (struct mt76_wed_rro_desc *)q->desc;
|
||||
for (i = 0; i < q->ndesc; i++) {
|
||||
struct mt76_wed_rro_ind *cmd;
|
||||
|
||||
cmd = (struct mt76_wed_rro_ind *)&rro_desc[i];
|
||||
cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1;
|
||||
}
|
||||
}
|
||||
|
||||
mt76_dma_queue_magic_cnt_init(dev, q);
|
||||
size = q->ndesc * sizeof(*q->entry);
|
||||
q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
|
||||
if (!q->entry)
|
||||
@@ -740,7 +853,10 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
return 0;
|
||||
}
|
||||
|
||||
mt76_dma_queue_reset(dev, q);
|
||||
/* HW specific driver is supposed to reset brand-new EMI queues since
|
||||
* it needs to set cpu index pointer.
|
||||
*/
|
||||
mt76_dma_queue_reset(dev, q, !mt76_queue_is_emi(q));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -783,7 +899,8 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
|
||||
if (!q->ndesc)
|
||||
return;
|
||||
|
||||
if (!mt76_queue_is_wed_rro_ind(q)) {
|
||||
if (!mt76_queue_is_wed_rro_ind(q) &&
|
||||
!mt76_queue_is_wed_rro_rxdmad_c(q)) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < q->ndesc; i++)
|
||||
@@ -843,8 +960,9 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
|
||||
bool allow_direct = !mt76_queue_is_wed_rx(q);
|
||||
bool more;
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
|
||||
mt76_queue_is_wed_tx_free(q)) {
|
||||
if ((q->flags & MT_QFLAG_WED_RRO_EN) ||
|
||||
(IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
|
||||
mt76_queue_is_wed_tx_free(q))) {
|
||||
dma_idx = Q_READ(q, dma_idx);
|
||||
check_ddone = true;
|
||||
}
|
||||
@@ -866,6 +984,20 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
|
||||
if (!data)
|
||||
break;
|
||||
|
||||
if (PTR_ERR(data) == -EAGAIN) {
|
||||
done++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mt76_queue_is_wed_rro_ind(q) && dev->drv->rx_rro_ind_process)
|
||||
dev->drv->rx_rro_ind_process(dev, data);
|
||||
|
||||
if (mt76_queue_is_wed_rro(q) &&
|
||||
!mt76_queue_is_wed_rro_rxdmad_c(q)) {
|
||||
done++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drop)
|
||||
goto free_frag;
|
||||
|
||||
@@ -943,6 +1075,15 @@ int mt76_dma_rx_poll(struct napi_struct *napi, int budget)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_dma_rx_poll);
|
||||
|
||||
static void
|
||||
mt76_dma_rx_queue_init(struct mt76_dev *dev, enum mt76_rxq_id qid,
|
||||
int (*poll)(struct napi_struct *napi, int budget))
|
||||
{
|
||||
netif_napi_add(dev->napi_dev, &dev->napi[qid], poll);
|
||||
mt76_dma_rx_fill_buf(dev, &dev->q_rx[qid], false);
|
||||
napi_enable(&dev->napi[qid]);
|
||||
}
|
||||
|
||||
static int
|
||||
mt76_dma_init(struct mt76_dev *dev,
|
||||
int (*poll)(struct napi_struct *napi, int budget))
|
||||
@@ -975,9 +1116,10 @@ mt76_dma_init(struct mt76_dev *dev,
|
||||
init_completion(&dev->mmio.wed_reset_complete);
|
||||
|
||||
mt76_for_each_q_rx(dev, i) {
|
||||
netif_napi_add(dev->napi_dev, &dev->napi[i], poll);
|
||||
mt76_dma_rx_fill_buf(dev, &dev->q_rx[i], false);
|
||||
napi_enable(&dev->napi[i]);
|
||||
if (mt76_queue_is_wed_rro(&dev->q_rx[i]))
|
||||
continue;
|
||||
|
||||
mt76_dma_rx_queue_init(dev, i, poll);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -990,6 +1132,7 @@ static const struct mt76_queue_ops mt76_dma_ops = {
|
||||
.tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw,
|
||||
.tx_queue_skb = mt76_dma_tx_queue_skb,
|
||||
.tx_cleanup = mt76_dma_tx_cleanup,
|
||||
.rx_queue_init = mt76_dma_rx_queue_init,
|
||||
.rx_cleanup = mt76_dma_rx_cleanup,
|
||||
.rx_reset = mt76_dma_rx_reset,
|
||||
.kick = mt76_dma_kick_queue,
|
||||
|
||||
@@ -31,7 +31,12 @@
|
||||
#define MT_DMA_CTL_PN_CHK_FAIL BIT(13)
|
||||
#define MT_DMA_CTL_VER_MASK BIT(7)
|
||||
|
||||
#define MT_DMA_RRO_EN BIT(13)
|
||||
#define MT_DMA_SDP0 GENMASK(15, 0)
|
||||
#define MT_DMA_TOKEN_ID GENMASK(31, 16)
|
||||
#define MT_DMA_MAGIC_MASK GENMASK(31, 28)
|
||||
#define MT_DMA_RRO_EN BIT(13)
|
||||
|
||||
#define MT_DMA_MAGIC_CNT 16
|
||||
|
||||
#define MT_DMA_WED_IND_CMD_CNT 8
|
||||
#define MT_DMA_WED_IND_REASON GENMASK(15, 12)
|
||||
@@ -53,6 +58,21 @@ struct mt76_wed_rro_desc {
|
||||
__le32 buf1;
|
||||
} __packed __aligned(4);
|
||||
|
||||
/* data1 */
|
||||
#define RRO_RXDMAD_DATA1_LS_MASK BIT(30)
|
||||
#define RRO_RXDMAD_DATA1_SDL0_MASK GENMASK(29, 16)
|
||||
/* data2 */
|
||||
#define RRO_RXDMAD_DATA2_RX_TOKEN_ID_MASK GENMASK(31, 16)
|
||||
#define RRO_RXDMAD_DATA2_IND_REASON_MASK GENMASK(15, 12)
|
||||
/* data3 */
|
||||
#define RRO_RXDMAD_DATA3_MAGIC_CNT_MASK GENMASK(31, 28)
|
||||
struct mt76_rro_rxdmad_c {
|
||||
__le32 data0;
|
||||
__le32 data1;
|
||||
__le32 data2;
|
||||
__le32 data3;
|
||||
};
|
||||
|
||||
enum mt76_qsel {
|
||||
MT_QSEL_MGMT,
|
||||
MT_QSEL_HCCA,
|
||||
@@ -81,14 +101,13 @@ void mt76_dma_attach(struct mt76_dev *dev);
|
||||
void mt76_dma_cleanup(struct mt76_dev *dev);
|
||||
int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool allow_direct);
|
||||
void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool reset_idx);
|
||||
void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q);
|
||||
void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool reset_idx);
|
||||
|
||||
static inline void
|
||||
mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
dev->queue_ops->reset_q(dev, q);
|
||||
dev->queue_ops->reset_q(dev, q, true);
|
||||
if (mtk_wed_device_active(&dev->mmio.wed))
|
||||
mt76_wed_dma_setup(dev, q, true);
|
||||
}
|
||||
|
||||
@@ -163,13 +163,16 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
|
||||
return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
mt76_eeprom_override(struct mt76_phy *phy)
|
||||
{
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct device_node *np = dev->dev->of_node;
|
||||
int err;
|
||||
|
||||
of_get_mac_address(np, phy->macaddr);
|
||||
err = of_get_mac_address(np, phy->macaddr);
|
||||
if (err == -EPROBE_DEFER)
|
||||
return err;
|
||||
|
||||
if (!is_valid_ether_addr(phy->macaddr)) {
|
||||
eth_random_addr(phy->macaddr);
|
||||
@@ -177,6 +180,8 @@ mt76_eeprom_override(struct mt76_phy *phy)
|
||||
"Invalid MAC address, using random address %pM\n",
|
||||
phy->macaddr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_eeprom_override);
|
||||
|
||||
|
||||
@@ -824,6 +824,9 @@ static void mt76_reset_phy(struct mt76_phy *phy)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&phy->tx_list);
|
||||
phy->num_sta = 0;
|
||||
phy->chanctx = NULL;
|
||||
mt76_roc_complete(phy);
|
||||
}
|
||||
|
||||
void mt76_reset_device(struct mt76_dev *dev)
|
||||
@@ -844,6 +847,8 @@ void mt76_reset_device(struct mt76_dev *dev)
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
mt76_abort_scan(dev);
|
||||
|
||||
INIT_LIST_HEAD(&dev->wcid_list);
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
dev->vif_mask = 0;
|
||||
@@ -1235,6 +1240,8 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
|
||||
mstat = *((struct mt76_rx_status *)skb->cb);
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
||||
skb->priority = mstat.qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
status->flag = mstat.flag;
|
||||
status->freq = mstat.freq;
|
||||
status->enc_flags = mstat.enc_flags;
|
||||
@@ -2060,3 +2067,55 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
|
||||
mt76_abort_roc(mvif->roc_phy);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_vif_cleanup);
|
||||
|
||||
u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links)
|
||||
{
|
||||
unsigned long usable_links = ieee80211_vif_usable_links(vif);
|
||||
struct {
|
||||
u8 link_id;
|
||||
enum nl80211_band band;
|
||||
} data[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
unsigned int link_id;
|
||||
int i, n_data = 0;
|
||||
u16 sel_links = 0;
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
return 0;
|
||||
|
||||
if (vif->active_links == usable_links)
|
||||
return vif->active_links;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
link_conf = rcu_dereference(vif->link_conf[link_id]);
|
||||
if (WARN_ON_ONCE(!link_conf))
|
||||
continue;
|
||||
|
||||
data[n_data].link_id = link_id;
|
||||
data[n_data].band = link_conf->chanreq.oper.chan->band;
|
||||
n_data++;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
for (i = 0; i < n_data; i++) {
|
||||
int j;
|
||||
|
||||
if (!(BIT(data[i].link_id) & vif->active_links))
|
||||
continue;
|
||||
|
||||
sel_links = BIT(data[i].link_id);
|
||||
for (j = 0; j < n_data; j++) {
|
||||
if (data[i].band != data[j].band) {
|
||||
sel_links |= BIT(data[j].link_id);
|
||||
if (hweight16(sel_links) == max_active_links)
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return sel_links;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_select_links);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define MT_QFLAG_WED BIT(5)
|
||||
#define MT_QFLAG_WED_RRO BIT(6)
|
||||
#define MT_QFLAG_WED_RRO_EN BIT(7)
|
||||
#define MT_QFLAG_EMI_EN BIT(8)
|
||||
|
||||
#define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \
|
||||
FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \
|
||||
@@ -45,6 +46,7 @@
|
||||
#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n)
|
||||
#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n)
|
||||
#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0)
|
||||
#define MT_WED_RRO_Q_RXDMAD_C __MT_WED_RRO_Q(MT76_WED_RRO_Q_RXDMAD_C, 0)
|
||||
|
||||
struct mt76_dev;
|
||||
struct mt76_phy;
|
||||
@@ -71,6 +73,13 @@ enum mt76_wed_type {
|
||||
MT76_WED_RRO_Q_DATA,
|
||||
MT76_WED_RRO_Q_MSDU_PG,
|
||||
MT76_WED_RRO_Q_IND,
|
||||
MT76_WED_RRO_Q_RXDMAD_C,
|
||||
};
|
||||
|
||||
enum mt76_hwrro_mode {
|
||||
MT76_HWRRO_OFF,
|
||||
MT76_HWRRO_V3,
|
||||
MT76_HWRRO_V3_1,
|
||||
};
|
||||
|
||||
struct mt76_bus_ops {
|
||||
@@ -129,6 +138,7 @@ enum mt76_rxq_id {
|
||||
MT_RXQ_TXFREE_BAND1,
|
||||
MT_RXQ_TXFREE_BAND2,
|
||||
MT_RXQ_RRO_IND,
|
||||
MT_RXQ_RRO_RXDMAD_C,
|
||||
__MT_RXQ_MAX
|
||||
};
|
||||
|
||||
@@ -232,6 +242,9 @@ struct mt76_queue {
|
||||
|
||||
u8 buf_offset;
|
||||
u16 flags;
|
||||
u8 magic_cnt;
|
||||
|
||||
__le16 *emi_cpu_idx;
|
||||
|
||||
struct mtk_wed_device *wed;
|
||||
u32 wed_regs;
|
||||
@@ -286,11 +299,15 @@ struct mt76_queue_ops {
|
||||
void (*tx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool flush);
|
||||
|
||||
void (*rx_queue_init)(struct mt76_dev *dev, enum mt76_rxq_id qid,
|
||||
int (*poll)(struct napi_struct *napi, int budget));
|
||||
|
||||
void (*rx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q);
|
||||
|
||||
void (*kick)(struct mt76_dev *dev, struct mt76_queue *q);
|
||||
|
||||
void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q);
|
||||
void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
bool reset_idx);
|
||||
};
|
||||
|
||||
enum mt76_phy_type {
|
||||
@@ -398,15 +415,16 @@ struct mt76_txq {
|
||||
bool aggr;
|
||||
};
|
||||
|
||||
/* data0 */
|
||||
#define RRO_IND_DATA0_IND_REASON_MASK GENMASK(31, 28)
|
||||
#define RRO_IND_DATA0_START_SEQ_MASK GENMASK(27, 16)
|
||||
#define RRO_IND_DATA0_SEQ_ID_MASK GENMASK(11, 0)
|
||||
/* data1 */
|
||||
#define RRO_IND_DATA1_MAGIC_CNT_MASK GENMASK(31, 29)
|
||||
#define RRO_IND_DATA1_IND_COUNT_MASK GENMASK(12, 0)
|
||||
struct mt76_wed_rro_ind {
|
||||
u32 se_id : 12;
|
||||
u32 rsv : 4;
|
||||
u32 start_sn : 12;
|
||||
u32 ind_reason : 4;
|
||||
u32 ind_cnt : 13;
|
||||
u32 win_sz : 3;
|
||||
u32 rsv2 : 13;
|
||||
u32 magic_cnt : 3;
|
||||
__le32 data0;
|
||||
__le32 data1;
|
||||
};
|
||||
|
||||
struct mt76_txwi_cache {
|
||||
@@ -417,6 +435,8 @@ struct mt76_txwi_cache {
|
||||
struct sk_buff *skb;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
u8 qid;
|
||||
};
|
||||
|
||||
struct mt76_rx_tid {
|
||||
@@ -533,6 +553,10 @@ struct mt76_driver_ops {
|
||||
|
||||
void (*rx_poll_complete)(struct mt76_dev *dev, enum mt76_rxq_id q);
|
||||
|
||||
void (*rx_rro_ind_process)(struct mt76_dev *dev, void *data);
|
||||
int (*rx_rro_add_msdu_page)(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
dma_addr_t p, void *data);
|
||||
|
||||
void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta,
|
||||
bool ps);
|
||||
|
||||
@@ -910,6 +934,7 @@ struct mt76_dev {
|
||||
struct mt76_queue q_rx[__MT_RXQ_MAX];
|
||||
const struct mt76_queue_ops *queue_ops;
|
||||
int tx_dma_idx[4];
|
||||
enum mt76_hwrro_mode hwrro_mode;
|
||||
|
||||
struct mt76_worker tx_worker;
|
||||
struct napi_struct tx_napi;
|
||||
@@ -1214,6 +1239,7 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
#define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mphy), __VA_ARGS__)
|
||||
#define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_queue_rx_init(dev, ...) (dev)->mt76.queue_ops->rx_queue_init(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_queue_rx_cleanup(dev, ...) (dev)->mt76.queue_ops->rx_cleanup(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__)
|
||||
#define mt76_queue_reset(dev, ...) (dev)->mt76.queue_ops->reset_q(&((dev)->mt76), __VA_ARGS__)
|
||||
@@ -1268,7 +1294,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
|
||||
s8 *val, int len);
|
||||
|
||||
int mt76_eeprom_init(struct mt76_dev *dev, int len);
|
||||
void mt76_eeprom_override(struct mt76_phy *phy);
|
||||
int mt76_eeprom_override(struct mt76_phy *phy);
|
||||
int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
|
||||
int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
|
||||
const char *cell_name, int len);
|
||||
@@ -1617,6 +1643,7 @@ int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
|
||||
void mt76_scan_work(struct work_struct *work);
|
||||
void mt76_abort_scan(struct mt76_dev *dev);
|
||||
void mt76_roc_complete_work(struct work_struct *work);
|
||||
void mt76_roc_complete(struct mt76_phy *phy);
|
||||
void mt76_abort_roc(struct mt76_phy *phy);
|
||||
struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
|
||||
struct ieee80211_vif *vif);
|
||||
@@ -1782,21 +1809,34 @@ static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q)
|
||||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND;
|
||||
}
|
||||
|
||||
static inline bool mt76_queue_is_wed_rro_rxdmad_c(struct mt76_queue *q)
|
||||
{
|
||||
return mt76_queue_is_wed_rro(q) &&
|
||||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_RXDMAD_C;
|
||||
}
|
||||
|
||||
static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q)
|
||||
{
|
||||
return mt76_queue_is_wed_rro(q) &&
|
||||
(FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA ||
|
||||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG);
|
||||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA;
|
||||
}
|
||||
|
||||
static inline bool mt76_queue_is_wed_rro_msdu_pg(struct mt76_queue *q)
|
||||
{
|
||||
return mt76_queue_is_wed_rro(q) &&
|
||||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) ==
|
||||
MT76_WED_RRO_Q_MSDU_PG;
|
||||
}
|
||||
|
||||
static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
|
||||
{
|
||||
if (!(q->flags & MT_QFLAG_WED))
|
||||
return false;
|
||||
|
||||
return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX ||
|
||||
mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q);
|
||||
return (q->flags & MT_QFLAG_WED) &&
|
||||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX;
|
||||
}
|
||||
|
||||
static inline bool mt76_queue_is_emi(struct mt76_queue *q)
|
||||
{
|
||||
return q->flags & MT_QFLAG_EMI_EN;
|
||||
}
|
||||
|
||||
struct mt76_txwi_cache *
|
||||
@@ -1872,6 +1912,7 @@ mt76_vif_init(struct ieee80211_vif *vif, struct mt76_vif_data *mvif)
|
||||
}
|
||||
|
||||
void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif);
|
||||
u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links);
|
||||
|
||||
static inline struct mt76_vif_link *
|
||||
mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id)
|
||||
|
||||
@@ -182,7 +182,6 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
|
||||
dev->mphy.antenna_mask = 1;
|
||||
|
||||
dev->mphy.chainmask = dev->mphy.antenna_mask;
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
|
||||
return 0;
|
||||
return mt76_eeprom_override(&dev->mphy);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ mt76_wmac_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
error:
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
mt76_free_device(mdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -351,8 +351,6 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
|
||||
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
ETH_ALEN);
|
||||
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
|
||||
return 0;
|
||||
return mt76_eeprom_override(&dev->mphy);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_eeprom_init);
|
||||
|
||||
@@ -570,7 +570,10 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
|
||||
ETH_ALEN);
|
||||
mphy->macaddr[0] |= 2;
|
||||
mphy->macaddr[0] ^= BIT(7);
|
||||
mt76_eeprom_override(mphy);
|
||||
|
||||
ret = mt76_eeprom_override(mphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* second phy can only handle 5 GHz */
|
||||
mphy->cap.has_5ghz = true;
|
||||
|
||||
@@ -294,6 +294,13 @@ enum tx_frag_idx {
|
||||
#define MT_TXP_BUF_LEN GENMASK(11, 0)
|
||||
#define MT_TXP_DMA_ADDR_H GENMASK(15, 12)
|
||||
|
||||
#define MT_TXP0_TOKEN_ID0 GENMASK(14, 0)
|
||||
#define MT_TXP0_TOKEN_ID0_VALID_MASK BIT(15)
|
||||
|
||||
#define MT_TXP1_TID_ADDBA GENMASK(14, 12)
|
||||
#define MT_TXP3_ML0_MASK BIT(15)
|
||||
#define MT_TXP3_DMA_ADDR_H GENMASK(13, 12)
|
||||
|
||||
#define MT_TX_RATE_STBC BIT(14)
|
||||
#define MT_TX_RATE_NSS GENMASK(13, 10)
|
||||
#define MT_TX_RATE_MODE GENMASK(9, 6)
|
||||
|
||||
@@ -1662,6 +1662,31 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (enable && vif->bss_conf.bssid_indicator) {
|
||||
struct {
|
||||
struct {
|
||||
u8 bss_idx;
|
||||
u8 pad[3];
|
||||
} __packed hdr;
|
||||
struct bss_info_uni_mbssid mbssid;
|
||||
} mbssid_req = {
|
||||
.hdr = {
|
||||
.bss_idx = mvif->idx,
|
||||
},
|
||||
.mbssid = {
|
||||
.tag = cpu_to_le16(UNI_BSS_INFO_11V_MBSSID),
|
||||
.len = cpu_to_le16(sizeof(struct bss_info_uni_mbssid)),
|
||||
.max_indicator = vif->bss_conf.bssid_indicator,
|
||||
.mbss_idx = vif->bss_conf.bssid_index,
|
||||
},
|
||||
};
|
||||
|
||||
err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE),
|
||||
&mbssid_req, sizeof(mbssid_req), true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return mt76_connac_mcu_uni_set_chctx(phy, mvif, ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss);
|
||||
|
||||
@@ -332,7 +332,11 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev)
|
||||
|
||||
memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
ETH_ALEN);
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
|
||||
err = mt76_eeprom_override(&dev->mphy);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mt76x02_mac_setaddr(dev, dev->mphy.macaddr);
|
||||
|
||||
mt76x0_set_chip_cap(dev);
|
||||
|
||||
@@ -499,7 +499,9 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev)
|
||||
|
||||
mt76x02_eeprom_parse_hw_cap(dev);
|
||||
mt76x2_eeprom_get_macaddr(dev);
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
ret = mt76_eeprom_override(&dev->mphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev->mphy.macaddr[0] &= ~BIT(1);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -624,13 +624,13 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
|
||||
}
|
||||
|
||||
for (i = 0; i < __MT_MCUQ_MAX; i++)
|
||||
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
|
||||
mt76_queue_reset(dev, dev->mt76.q_mcu[i], true);
|
||||
|
||||
mt76_for_each_q_rx(&dev->mt76, i) {
|
||||
if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i]))
|
||||
continue;
|
||||
|
||||
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
|
||||
mt76_queue_reset(dev, &dev->mt76.q_rx[i], true);
|
||||
}
|
||||
|
||||
mt76_tx_status_check(&dev->mt76, true);
|
||||
|
||||
@@ -284,9 +284,7 @@ int mt7915_eeprom_init(struct mt7915_dev *dev)
|
||||
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
ETH_ALEN);
|
||||
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
|
||||
return 0;
|
||||
return mt76_eeprom_override(&dev->mphy);
|
||||
}
|
||||
|
||||
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
|
||||
|
||||
@@ -50,9 +50,9 @@ enum mt7915_eeprom_field {
|
||||
#define MT_EE_CAL_GROUP_SIZE_7975 (54 * MT_EE_CAL_UNIT + 16)
|
||||
#define MT_EE_CAL_GROUP_SIZE_7976 (94 * MT_EE_CAL_UNIT + 16)
|
||||
#define MT_EE_CAL_GROUP_SIZE_7916_6G (94 * MT_EE_CAL_UNIT + 16)
|
||||
#define MT_EE_CAL_GROUP_SIZE_7981 (144 * MT_EE_CAL_UNIT + 16)
|
||||
#define MT_EE_CAL_DPD_SIZE_V1 (54 * MT_EE_CAL_UNIT)
|
||||
#define MT_EE_CAL_DPD_SIZE_V2 (300 * MT_EE_CAL_UNIT)
|
||||
#define MT_EE_CAL_DPD_SIZE_V2_7981 (102 * MT_EE_CAL_UNIT) /* no 6g dpd data */
|
||||
|
||||
#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0)
|
||||
#define MT_EE_WIFI_CONF0_RX_PATH GENMASK(5, 3)
|
||||
@@ -180,6 +180,8 @@ mt7915_get_cal_group_size(struct mt7915_dev *dev)
|
||||
val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
|
||||
return (val == MT_EE_V2_BAND_SEL_6GHZ) ? MT_EE_CAL_GROUP_SIZE_7916_6G :
|
||||
MT_EE_CAL_GROUP_SIZE_7916;
|
||||
} else if (is_mt7981(&dev->mt76)) {
|
||||
return MT_EE_CAL_GROUP_SIZE_7981;
|
||||
} else if (mt7915_check_adie(dev, false)) {
|
||||
return MT_EE_CAL_GROUP_SIZE_7976;
|
||||
} else {
|
||||
@@ -192,8 +194,6 @@ mt7915_get_cal_dpd_size(struct mt7915_dev *dev)
|
||||
{
|
||||
if (is_mt7915(&dev->mt76))
|
||||
return MT_EE_CAL_DPD_SIZE_V1;
|
||||
else if (is_mt7981(&dev->mt76))
|
||||
return MT_EE_CAL_DPD_SIZE_V2_7981;
|
||||
else
|
||||
return MT_EE_CAL_DPD_SIZE_V2;
|
||||
}
|
||||
|
||||
@@ -702,7 +702,9 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy)
|
||||
mphy->macaddr[0] |= 2;
|
||||
mphy->macaddr[0] ^= BIT(7);
|
||||
}
|
||||
mt76_eeprom_override(mphy);
|
||||
ret = mt76_eeprom_override(mphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* init wiphy according to mphy and phy */
|
||||
mt7915_init_wiphy(phy);
|
||||
|
||||
@@ -3052,30 +3052,15 @@ static int mt7915_dpd_freq_idx(struct mt7915_dev *dev, u16 freq, u8 bw)
|
||||
/* 5G BW160 */
|
||||
5250, 5570, 5815
|
||||
};
|
||||
static const u16 freq_list_v2_7981[] = {
|
||||
/* 5G BW20 */
|
||||
5180, 5200, 5220, 5240,
|
||||
5260, 5280, 5300, 5320,
|
||||
5500, 5520, 5540, 5560,
|
||||
5580, 5600, 5620, 5640,
|
||||
5660, 5680, 5700, 5720,
|
||||
5745, 5765, 5785, 5805,
|
||||
5825, 5845, 5865, 5885,
|
||||
/* 5G BW160 */
|
||||
5250, 5570, 5815
|
||||
};
|
||||
const u16 *freq_list = freq_list_v1;
|
||||
int n_freqs = ARRAY_SIZE(freq_list_v1);
|
||||
int idx;
|
||||
const u16 *freq_list;
|
||||
int idx, n_freqs;
|
||||
|
||||
if (!is_mt7915(&dev->mt76)) {
|
||||
if (is_mt7981(&dev->mt76)) {
|
||||
freq_list = freq_list_v2_7981;
|
||||
n_freqs = ARRAY_SIZE(freq_list_v2_7981);
|
||||
} else {
|
||||
freq_list = freq_list_v2;
|
||||
n_freqs = ARRAY_SIZE(freq_list_v2);
|
||||
}
|
||||
freq_list = freq_list_v2;
|
||||
n_freqs = ARRAY_SIZE(freq_list_v2);
|
||||
} else {
|
||||
freq_list = freq_list_v1;
|
||||
n_freqs = ARRAY_SIZE(freq_list_v1);
|
||||
}
|
||||
|
||||
if (freq < 4000) {
|
||||
|
||||
@@ -189,7 +189,9 @@ static int __mt7921_init_hardware(struct mt792x_dev *dev)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
ret = mt76_eeprom_override(&dev->mphy);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = mt7921_mcu_set_eeprom(dev);
|
||||
if (ret)
|
||||
|
||||
@@ -135,6 +135,8 @@ mt7921_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band,
|
||||
if (is_mt7922(phy->mt76->dev)) {
|
||||
he_cap_elem->phy_cap_info[0] |=
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
|
||||
he_cap_elem->phy_cap_info[4] |=
|
||||
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
|
||||
he_cap_elem->phy_cap_info[8] |=
|
||||
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
|
||||
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
|
||||
|
||||
@@ -21,6 +21,9 @@ static const struct usb_device_id mt7921u_device_table[] = {
|
||||
/* Netgear, Inc. [A8000,AXE3000] */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9060, 0xff, 0xff, 0xff),
|
||||
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||
/* Netgear, Inc. A7500 */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9065, 0xff, 0xff, 0xff),
|
||||
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||
/* TP-Link TXE50UH */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0107, 0xff, 0xff, 0xff),
|
||||
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||
|
||||
@@ -249,7 +249,9 @@ static int __mt7925_init_hardware(struct mt792x_dev *dev)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
ret = mt76_eeprom_override(&dev->mphy);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = mt7925_mcu_set_eeprom(dev);
|
||||
if (ret)
|
||||
|
||||
@@ -1300,7 +1300,6 @@ void mt7925_mac_reset_work(struct work_struct *work)
|
||||
cancel_delayed_work_sync(&dev->mphy.mac_work);
|
||||
cancel_delayed_work_sync(&pm->ps_work);
|
||||
cancel_work_sync(&pm->wake_work);
|
||||
dev->sar_inited = false;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
@@ -1329,6 +1328,10 @@ void mt7925_mac_reset_work(struct work_struct *work)
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7925_vif_connect_iter, NULL);
|
||||
mt76_connac_power_save_sched(&dev->mt76.phy, pm);
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
mt7925_mcu_set_clc(dev, "00", ENVIRON_INDOOR);
|
||||
mt792x_mutex_release(dev);
|
||||
}
|
||||
|
||||
void mt7925_coredump_work(struct work_struct *work)
|
||||
|
||||
@@ -240,6 +240,7 @@ int mt7925_init_mlo_caps(struct mt792x_phy *phy)
|
||||
{
|
||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||
static const u8 ext_capa_sta[] = {
|
||||
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
||||
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||
};
|
||||
static struct wiphy_iftype_ext_capab ext_capab[] = {
|
||||
@@ -310,7 +311,6 @@ void mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy)
|
||||
int __mt7925_start(struct mt792x_phy *phy)
|
||||
{
|
||||
struct mt76_phy *mphy = phy->mt76;
|
||||
struct mt792x_dev *dev = phy->dev;
|
||||
int err;
|
||||
|
||||
err = mt7925_mcu_set_channel_domain(mphy);
|
||||
@@ -321,13 +321,6 @@ int __mt7925_start(struct mt792x_phy *phy)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!dev->sar_inited) {
|
||||
err = mt7925_set_tx_sar_pwr(mphy->hw, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
dev->sar_inited = true;
|
||||
}
|
||||
|
||||
mt792x_mac_reset_counters(phy);
|
||||
set_bit(MT76_STATE_RUNNING, &mphy->state);
|
||||
|
||||
@@ -987,56 +980,6 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7925_mac_sta_add);
|
||||
|
||||
static u16
|
||||
mt7925_mac_select_links(struct mt76_dev *mdev, struct ieee80211_vif *vif)
|
||||
{
|
||||
unsigned long usable_links = ieee80211_vif_usable_links(vif);
|
||||
struct {
|
||||
u8 link_id;
|
||||
enum nl80211_band band;
|
||||
} data[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
u8 link_id, i, j, n_data = 0;
|
||||
u16 sel_links = 0;
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
return 0;
|
||||
|
||||
if (vif->active_links == usable_links)
|
||||
return vif->active_links;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
struct ieee80211_bss_conf *link_conf =
|
||||
rcu_dereference(vif->link_conf[link_id]);
|
||||
|
||||
if (WARN_ON_ONCE(!link_conf))
|
||||
continue;
|
||||
|
||||
data[n_data].link_id = link_id;
|
||||
data[n_data].band = link_conf->chanreq.oper.chan->band;
|
||||
n_data++;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
for (i = 0; i < n_data; i++) {
|
||||
if (!(BIT(data[i].link_id) & vif->active_links))
|
||||
continue;
|
||||
|
||||
sel_links = BIT(data[i].link_id);
|
||||
|
||||
for (j = 0; j < n_data; j++) {
|
||||
if (data[i].band != data[j].band) {
|
||||
sel_links |= BIT(data[j].link_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return sel_links;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif)
|
||||
{
|
||||
@@ -1047,7 +990,7 @@ mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif)
|
||||
struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper;
|
||||
enum nl80211_band band = chandef->chan->band, secondary_band;
|
||||
|
||||
u16 sel_links = mt7925_mac_select_links(mdev, vif);
|
||||
u16 sel_links = mt76_select_links(vif, 2);
|
||||
u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links);
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2)
|
||||
@@ -1731,13 +1674,7 @@ static int mt7925_set_sar_specs(struct ieee80211_hw *hw,
|
||||
int err;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
err = mt7925_mcu_set_clc(dev, dev->mt76.alpha2,
|
||||
dev->country_ie_env);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = mt7925_set_tx_sar_pwr(hw, sar);
|
||||
out:
|
||||
mt792x_mutex_release(dev);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -759,7 +759,6 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name)
|
||||
}
|
||||
}
|
||||
|
||||
ret = mt7925_mcu_set_clc(dev, "00", ENVIRON_INDOOR);
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
@@ -2621,6 +2620,25 @@ mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf
|
||||
qos->qos = link_conf->qos;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7925_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,
|
||||
bool enable)
|
||||
{
|
||||
struct bss_info_uni_mbssid *mbssid;
|
||||
struct tlv *tlv;
|
||||
|
||||
if (!enable && !link_conf->bssid_indicator)
|
||||
return;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_11V_MBSSID,
|
||||
sizeof(*mbssid));
|
||||
|
||||
mbssid = (struct bss_info_uni_mbssid *)tlv;
|
||||
mbssid->max_indicator = link_conf->bssid_indicator;
|
||||
mbssid->mbss_idx = link_conf->bssid_index;
|
||||
mbssid->tx_bss_omac_idx = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,
|
||||
struct mt792x_phy *phy)
|
||||
@@ -2787,8 +2805,10 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
|
||||
mt7925_mcu_bss_color_tlv(skb, link_conf, enable);
|
||||
}
|
||||
|
||||
if (enable)
|
||||
if (enable) {
|
||||
mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx);
|
||||
mt7925_mcu_bss_mbssid_tlv(skb, link_conf, enable);
|
||||
}
|
||||
|
||||
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
|
||||
MCU_UNI_CMD(BSS_INFO_UPDATE), true);
|
||||
@@ -3703,6 +3723,8 @@ out:
|
||||
|
||||
int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy)
|
||||
{
|
||||
struct mt76_dev *mdev = phy->dev;
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(mdev->hw);
|
||||
int err;
|
||||
|
||||
if (phy->cap.has_2ghz) {
|
||||
@@ -3719,7 +3741,7 @@ int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (phy->cap.has_6ghz) {
|
||||
if (phy->cap.has_6ghz && dev->phy.clc_chan_conf) {
|
||||
err = mt7925_mcu_rate_txpower_band(phy,
|
||||
NL80211_BAND_6GHZ);
|
||||
if (err < 0)
|
||||
|
||||
@@ -529,7 +529,7 @@ restore_suspend:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mt7925_pci_resume(struct device *device)
|
||||
static int _mt7925_pci_resume(struct device *device, bool restore)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct mt76_dev *mdev = pci_get_drvdata(pdev);
|
||||
@@ -569,6 +569,9 @@ static int mt7925_pci_resume(struct device *device)
|
||||
napi_schedule(&mdev->tx_napi);
|
||||
local_bh_enable();
|
||||
|
||||
if (restore)
|
||||
goto failed;
|
||||
|
||||
mt76_connac_mcu_set_hif_suspend(mdev, false, false);
|
||||
ret = wait_event_timeout(dev->wait,
|
||||
dev->hif_resumed, 3 * HZ);
|
||||
@@ -585,7 +588,7 @@ static int mt7925_pci_resume(struct device *device)
|
||||
failed:
|
||||
pm->suspended = false;
|
||||
|
||||
if (err < 0)
|
||||
if (err < 0 || restore)
|
||||
mt792x_reset(&dev->mt76);
|
||||
|
||||
return err;
|
||||
@@ -596,7 +599,24 @@ static void mt7925_pci_shutdown(struct pci_dev *pdev)
|
||||
mt7925_pci_remove(pdev);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(mt7925_pm_ops, mt7925_pci_suspend, mt7925_pci_resume);
|
||||
static int mt7925_pci_resume(struct device *device)
|
||||
{
|
||||
return _mt7925_pci_resume(device, false);
|
||||
}
|
||||
|
||||
static int mt7925_pci_restore(struct device *device)
|
||||
{
|
||||
return _mt7925_pci_resume(device, true);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops mt7925_pm_ops = {
|
||||
.suspend = pm_sleep_ptr(mt7925_pci_suspend),
|
||||
.resume = pm_sleep_ptr(mt7925_pci_resume),
|
||||
.freeze = pm_sleep_ptr(mt7925_pci_suspend),
|
||||
.thaw = pm_sleep_ptr(mt7925_pci_resume),
|
||||
.poweroff = pm_sleep_ptr(mt7925_pci_suspend),
|
||||
.restore = pm_sleep_ptr(mt7925_pci_restore),
|
||||
};
|
||||
|
||||
static struct pci_driver mt7925_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
static const struct usb_device_id mt7925u_device_table[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7925, 0xff, 0xff, 0xff),
|
||||
.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },
|
||||
/* Netgear, Inc. A9000 */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9072, 0xff, 0xff, 0xff),
|
||||
.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
@@ -234,7 +234,6 @@ struct mt792x_dev {
|
||||
bool aspm_supported:1;
|
||||
bool hif_idle:1;
|
||||
bool hif_resumed:1;
|
||||
bool sar_inited:1;
|
||||
bool regd_change:1;
|
||||
wait_queue_head_t wait;
|
||||
|
||||
|
||||
@@ -689,8 +689,12 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
|
||||
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
|
||||
ieee80211_hw_set(hw, CONNECTION_MONITOR);
|
||||
ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR);
|
||||
if (is_mt7921(&dev->mt76))
|
||||
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
|
||||
ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID);
|
||||
|
||||
if (is_mt7921(&dev->mt76)) {
|
||||
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
|
||||
}
|
||||
|
||||
if (dev->pm.enable)
|
||||
ieee80211_hw_set(hw, CONNECTION_MONITOR);
|
||||
|
||||
@@ -181,13 +181,13 @@ mt792x_dma_reset(struct mt792x_dev *dev, bool force)
|
||||
|
||||
/* reset hw queues */
|
||||
for (i = 0; i < __MT_TXQ_MAX; i++)
|
||||
mt76_queue_reset(dev, dev->mphy.q_tx[i]);
|
||||
mt76_queue_reset(dev, dev->mphy.q_tx[i], true);
|
||||
|
||||
for (i = 0; i < __MT_MCUQ_MAX; i++)
|
||||
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
|
||||
mt76_queue_reset(dev, dev->mt76.q_mcu[i], true);
|
||||
|
||||
mt76_for_each_q_rx(&dev->mt76, i)
|
||||
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
|
||||
mt76_queue_reset(dev, &dev->mt76.q_rx[i], true);
|
||||
|
||||
mt76_tx_status_check(&dev->mt76, true);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc,
|
||||
ring_base += MT_TXQ_ID(0) * MT_RING_SIZE;
|
||||
idx -= MT_TXQ_ID(0);
|
||||
|
||||
if (phy->mt76->band_idx == MT_BAND2)
|
||||
if (wed == &dev->mt76.mmio.wed_hif2)
|
||||
flags = MT_WED_Q_TX(0);
|
||||
else
|
||||
flags = MT_WED_Q_TX(idx);
|
||||
@@ -83,36 +83,74 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->has_rro) {
|
||||
if (mt7996_has_hwrro(dev)) {
|
||||
/* band0 */
|
||||
RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0,
|
||||
MT7996_RXQ_RRO_BAND0);
|
||||
RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0,
|
||||
MT7996_RXQ_MSDU_PG_BAND0);
|
||||
RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN,
|
||||
MT7996_RXQ_TXFREE0);
|
||||
/* band1 */
|
||||
RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1,
|
||||
MT7996_RXQ_MSDU_PG_BAND1);
|
||||
/* band2 */
|
||||
RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2,
|
||||
MT7996_RXQ_RRO_BAND2);
|
||||
RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2,
|
||||
MT7996_RXQ_MSDU_PG_BAND2);
|
||||
RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI,
|
||||
MT7996_RXQ_TXFREE2);
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3)
|
||||
RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0,
|
||||
MT_INT_RX_DONE_MSDU_PG_BAND0,
|
||||
MT7996_RXQ_MSDU_PG_BAND0);
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0,
|
||||
MT_INT_RX_TXFREE_MAIN, MT7996_RXQ_TXFREE0);
|
||||
/* band1 */
|
||||
RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0,
|
||||
MT_INT_RX_DONE_MSDU_PG_BAND1,
|
||||
MT7996_RXQ_MSDU_PG_BAND1);
|
||||
/* band2 */
|
||||
RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0,
|
||||
MT_INT_RX_DONE_RRO_BAND2,
|
||||
MT7996_RXQ_RRO_BAND2);
|
||||
RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0,
|
||||
MT_INT_RX_DONE_MSDU_PG_BAND2,
|
||||
MT7996_RXQ_MSDU_PG_BAND2);
|
||||
RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0,
|
||||
MT_INT_RX_TXFREE_TRI, MT7996_RXQ_TXFREE2);
|
||||
} else {
|
||||
RXQ_CONFIG(MT_RXQ_RRO_BAND1, WFDMA0,
|
||||
MT_INT_RX_DONE_RRO_BAND1,
|
||||
MT7996_RXQ_RRO_BAND1);
|
||||
}
|
||||
|
||||
RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND,
|
||||
MT7996_RXQ_RRO_IND);
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3)
|
||||
RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0,
|
||||
MT_INT_RX_DONE_RRO_IND,
|
||||
MT7996_RXQ_RRO_IND);
|
||||
else
|
||||
RXQ_CONFIG(MT_RXQ_RRO_RXDMAD_C, WFDMA0,
|
||||
MT_INT_RX_DONE_RRO_RXDMAD_C,
|
||||
MT7996_RXQ_RRO_RXDMAD_C);
|
||||
}
|
||||
|
||||
/* data tx queue */
|
||||
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
|
||||
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
|
||||
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
|
||||
if (dev->hif2) {
|
||||
/* default bn1:ring19 bn2:ring21 */
|
||||
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1,
|
||||
MT7996_TXQ_BAND1);
|
||||
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2,
|
||||
MT7996_TXQ_BAND2);
|
||||
} else {
|
||||
/* single pcie bn0/1:ring18 bn2:ring19 */
|
||||
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1,
|
||||
MT7996_TXQ_BAND1);
|
||||
}
|
||||
} else {
|
||||
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
|
||||
if (dev->hif2) {
|
||||
/* bn0:ring18 bn1:ring21 */
|
||||
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0,
|
||||
MT7996_TXQ_BAND0);
|
||||
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND2,
|
||||
MT7996_TXQ_BAND2);
|
||||
} else {
|
||||
/* single pcie bn0:ring18 bn1:ring19 */
|
||||
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0,
|
||||
MT7996_TXQ_BAND0);
|
||||
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1,
|
||||
MT7996_TXQ_BAND1);
|
||||
}
|
||||
}
|
||||
|
||||
/* mcu tx queue */
|
||||
@@ -166,11 +204,12 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs)
|
||||
|
||||
/* Rx TxFreeDone From MAC Rings */
|
||||
val = is_mt7996(&dev->mt76) ? 4 : 8;
|
||||
if (is_mt7990(&dev->mt76) || (is_mt7996(&dev->mt76) && dev->has_rro))
|
||||
if ((is_mt7996(&dev->mt76) && mt7996_has_hwrro(dev)) ||
|
||||
is_mt7990(&dev->mt76))
|
||||
mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, PREFETCH(val));
|
||||
if (is_mt7990(&dev->mt76) && dev->hif2)
|
||||
mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND1) + ofs, PREFETCH(val));
|
||||
else if (is_mt7996(&dev->mt76) && dev->has_rro)
|
||||
else if (is_mt7996(&dev->mt76) && mt7996_has_hwrro(dev))
|
||||
mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, PREFETCH(val));
|
||||
|
||||
/* Rx Data Rings */
|
||||
@@ -179,7 +218,7 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs)
|
||||
mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(0x10));
|
||||
|
||||
/* Rx RRO Rings */
|
||||
if (dev->has_rro) {
|
||||
if (mt7996_has_hwrro(dev)) {
|
||||
mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_RRO_BAND0) + ofs, PREFETCH(0x10));
|
||||
queue = is_mt7996(&dev->mt76) ? MT_RXQ_RRO_BAND2 : MT_RXQ_RRO_BAND1;
|
||||
mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(0x10));
|
||||
@@ -288,11 +327,14 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset)
|
||||
if (mt7996_band_valid(dev, MT_BAND0))
|
||||
irq_mask |= MT_INT_BAND0_RX_DONE;
|
||||
|
||||
if (mt7996_band_valid(dev, MT_BAND1))
|
||||
if (mt7996_band_valid(dev, MT_BAND1)) {
|
||||
irq_mask |= MT_INT_BAND1_RX_DONE;
|
||||
if (is_mt7992(&dev->mt76) && dev->hif2)
|
||||
irq_mask |= MT_INT_RX_TXFREE_BAND1_EXT;
|
||||
}
|
||||
|
||||
if (mt7996_band_valid(dev, MT_BAND2))
|
||||
irq_mask |= MT_INT_BAND2_RX_DONE;
|
||||
irq_mask |= MT_INT_BAND2_RX_DONE | MT_INT_TX_RX_DONE_EXT;
|
||||
|
||||
if (mtk_wed_device_active(wed) && wed_reset) {
|
||||
u32 wed_irq_mask = irq_mask;
|
||||
@@ -378,13 +420,48 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
|
||||
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
|
||||
|
||||
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
|
||||
MT_WFDMA_HOST_CONFIG_PDMA_BAND |
|
||||
MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
|
||||
MT_WFDMA_HOST_CONFIG_PDMA_BAND);
|
||||
|
||||
mt76_clear(dev, MT_WFDMA_HOST_CONFIG,
|
||||
MT_WFDMA_HOST_CONFIG_BAND0_PCIE1 |
|
||||
MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 |
|
||||
MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
|
||||
|
||||
if (is_mt7996(&dev->mt76))
|
||||
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
|
||||
MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
|
||||
else
|
||||
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
|
||||
MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
|
||||
|
||||
/* AXI read outstanding number */
|
||||
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
|
||||
MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
|
||||
|
||||
if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
|
||||
(dev->hif2->speed == PCIE_SPEED_5_0GT &&
|
||||
dev->hif2->width < PCIE_LNK_X2)) {
|
||||
mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
|
||||
WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
|
||||
FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
|
||||
0x1));
|
||||
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
|
||||
MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
|
||||
FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
|
||||
0x1));
|
||||
} else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
|
||||
(dev->hif2->speed == PCIE_SPEED_8_0GT &&
|
||||
dev->hif2->width < PCIE_LNK_X2)) {
|
||||
mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
|
||||
WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
|
||||
FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
|
||||
0x2));
|
||||
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
|
||||
MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
|
||||
FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
|
||||
0x2));
|
||||
}
|
||||
|
||||
/* WFDMA rx threshold */
|
||||
mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c);
|
||||
mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008);
|
||||
@@ -397,27 +474,58 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
|
||||
* so, redirect pcie0 rx ring3 interrupt to pcie1
|
||||
*/
|
||||
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
|
||||
dev->has_rro)
|
||||
mt7996_has_hwrro(dev)) {
|
||||
u32 intr = is_mt7996(&dev->mt76) ?
|
||||
MT_WFDMA0_RX_INT_SEL_RING6 :
|
||||
MT_WFDMA0_RX_INT_SEL_RING9 |
|
||||
MT_WFDMA0_RX_INT_SEL_RING5;
|
||||
|
||||
mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs,
|
||||
MT_WFDMA0_RX_INT_SEL_RING6);
|
||||
else
|
||||
intr);
|
||||
} else {
|
||||
mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL,
|
||||
MT_WFDMA0_RX_INT_SEL_RING3);
|
||||
}
|
||||
}
|
||||
|
||||
mt7996_dma_start(dev, reset, true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
int mt7996_dma_rro_init(struct mt7996_dev *dev)
|
||||
{
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
u32 irq_mask;
|
||||
int ret;
|
||||
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
|
||||
/* rxdmad_c */
|
||||
mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].flags = MT_WED_RRO_Q_RXDMAD_C;
|
||||
if (mtk_wed_device_active(&mdev->mmio.wed))
|
||||
mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].wed = &mdev->mmio.wed;
|
||||
else
|
||||
mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].flags |= MT_QFLAG_EMI_EN;
|
||||
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C],
|
||||
MT_RXQ_ID(MT_RXQ_RRO_RXDMAD_C),
|
||||
MT7996_RX_RING_SIZE,
|
||||
MT7996_RX_BUF_SIZE,
|
||||
MT_RXQ_RRO_AP_RING_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* We need to set cpu idx pointer before resetting the EMI
|
||||
* queues.
|
||||
*/
|
||||
mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].emi_cpu_idx =
|
||||
&dev->wed_rro.emi_rings_cpu.ptr->ring[0].idx;
|
||||
mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], true);
|
||||
goto start_hw_rro;
|
||||
}
|
||||
|
||||
/* ind cmd */
|
||||
mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND;
|
||||
mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed;
|
||||
if (mtk_wed_device_active(&mdev->mmio.wed) &&
|
||||
mtk_wed_get_rx_capa(&mdev->mmio.wed))
|
||||
mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed;
|
||||
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND],
|
||||
MT_RXQ_ID(MT_RXQ_RRO_IND),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -428,7 +536,9 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
|
||||
/* rx msdu page queue for band0 */
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags =
|
||||
MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN;
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed;
|
||||
if (mtk_wed_device_active(&mdev->mmio.wed) &&
|
||||
mtk_wed_get_rx_capa(&mdev->mmio.wed))
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed;
|
||||
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0],
|
||||
MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -437,11 +547,13 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (mt7996_band_valid(dev, MT_BAND1)) {
|
||||
if (mt7996_band_valid(dev, MT_BAND1) && is_mt7996(&dev->mt76)) {
|
||||
/* rx msdu page queue for band1 */
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags =
|
||||
MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN;
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed;
|
||||
if (mtk_wed_device_active(&mdev->mmio.wed) &&
|
||||
mtk_wed_get_rx_capa(&mdev->mmio.wed))
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed;
|
||||
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1],
|
||||
MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -455,7 +567,9 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
|
||||
/* rx msdu page queue for band2 */
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags =
|
||||
MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN;
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed;
|
||||
if (mtk_wed_device_active(&mdev->mmio.wed) &&
|
||||
mtk_wed_get_rx_capa(&mdev->mmio.wed))
|
||||
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed;
|
||||
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2],
|
||||
MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -465,15 +579,42 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE |
|
||||
MT_INT_TX_DONE_BAND2;
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, irq_mask);
|
||||
mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false);
|
||||
mt7996_irq_enable(dev, irq_mask);
|
||||
start_hw_rro:
|
||||
if (mtk_wed_device_active(&mdev->mmio.wed)) {
|
||||
irq_mask = mdev->mmio.irqmask |
|
||||
MT_INT_TX_DONE_BAND2;
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, irq_mask);
|
||||
mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false);
|
||||
mt7996_irq_enable(dev, irq_mask);
|
||||
} else {
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1,
|
||||
mt76_dma_rx_poll);
|
||||
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2,
|
||||
mt76_dma_rx_poll);
|
||||
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2,
|
||||
mt76_dma_rx_poll);
|
||||
} else {
|
||||
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1,
|
||||
mt76_dma_rx_poll);
|
||||
}
|
||||
|
||||
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll);
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
|
||||
mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C,
|
||||
mt76_dma_rx_poll);
|
||||
} else {
|
||||
mt76_queue_rx_init(dev, MT_RXQ_RRO_IND,
|
||||
mt76_dma_rx_poll);
|
||||
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0,
|
||||
mt76_dma_rx_poll);
|
||||
}
|
||||
mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
|
||||
|
||||
int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
{
|
||||
@@ -560,7 +701,9 @@ int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
return ret;
|
||||
|
||||
/* tx free notify event from WA for band0 */
|
||||
if (mtk_wed_device_active(wed) && !dev->has_rro) {
|
||||
if (mtk_wed_device_active(wed) &&
|
||||
((is_mt7996(&dev->mt76) && !mt7996_has_hwrro(dev)) ||
|
||||
(is_mt7992(&dev->mt76)))) {
|
||||
dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE;
|
||||
dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed;
|
||||
}
|
||||
@@ -615,7 +758,7 @@ int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
/* tx free notify event from WA for mt7996 band2
|
||||
* use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1
|
||||
*/
|
||||
if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) {
|
||||
if (mtk_wed_device_active(wed_hif2) && !mt7996_has_hwrro(dev)) {
|
||||
dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE;
|
||||
dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2;
|
||||
}
|
||||
@@ -630,6 +773,11 @@ int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
} else if (mt7996_band_valid(dev, MT_BAND1)) {
|
||||
/* rx data queue for mt7992 band1 */
|
||||
rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs;
|
||||
if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) {
|
||||
dev->mt76.q_rx[MT_RXQ_BAND1].flags = MT_WED_Q_RX(1);
|
||||
dev->mt76.q_rx[MT_RXQ_BAND1].wed = wed;
|
||||
}
|
||||
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1],
|
||||
MT_RXQ_ID(MT_RXQ_BAND1),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -641,6 +789,12 @@ int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
/* tx free notify event from WA for mt7992 band1 */
|
||||
if (mt7996_has_wa(dev)) {
|
||||
rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs;
|
||||
if (mtk_wed_device_active(wed_hif2)) {
|
||||
dev->mt76.q_rx[MT_RXQ_BAND1_WA].flags =
|
||||
MT_WED_Q_TXFREE;
|
||||
dev->mt76.q_rx[MT_RXQ_BAND1_WA].wed = wed_hif2;
|
||||
}
|
||||
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA],
|
||||
MT_RXQ_ID(MT_RXQ_BAND1_WA),
|
||||
MT7996_RX_MCU_RING_SIZE,
|
||||
@@ -651,12 +805,12 @@ int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) &&
|
||||
dev->has_rro) {
|
||||
if (mt7996_has_hwrro(dev)) {
|
||||
/* rx rro data queue for band0 */
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags =
|
||||
MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN;
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed;
|
||||
if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed))
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed;
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0],
|
||||
MT_RXQ_ID(MT_RXQ_RRO_BAND0),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -665,23 +819,44 @@ int mt7996_dma_init(struct mt7996_dev *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* tx free notify event from WA for band0 */
|
||||
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE;
|
||||
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed;
|
||||
if (is_mt7992(&dev->mt76)) {
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND1].flags =
|
||||
MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN;
|
||||
if (mtk_wed_device_active(wed) &&
|
||||
mtk_wed_get_rx_capa(wed))
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND1].wed = wed;
|
||||
ret = mt76_queue_alloc(dev,
|
||||
&dev->mt76.q_rx[MT_RXQ_RRO_BAND1],
|
||||
MT_RXQ_ID(MT_RXQ_RRO_BAND1),
|
||||
MT7996_RX_RING_SIZE,
|
||||
MT7996_RX_BUF_SIZE,
|
||||
MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + hif1_ofs);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
if (mtk_wed_device_active(wed)) {
|
||||
/* tx free notify event from WA for band0 */
|
||||
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE;
|
||||
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed;
|
||||
}
|
||||
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0],
|
||||
MT_RXQ_ID(MT_RXQ_TXFREE_BAND0),
|
||||
MT7996_RX_MCU_RING_SIZE,
|
||||
MT7996_RX_BUF_SIZE,
|
||||
MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = mt76_queue_alloc(dev,
|
||||
&dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0],
|
||||
MT_RXQ_ID(MT_RXQ_TXFREE_BAND0),
|
||||
MT7996_RX_MCU_RING_SIZE,
|
||||
MT7996_RX_BUF_SIZE,
|
||||
MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mt7996_band_valid(dev, MT_BAND2)) {
|
||||
/* rx rro data queue for band2 */
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags =
|
||||
MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN;
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed;
|
||||
if (mtk_wed_device_active(wed) &&
|
||||
mtk_wed_get_rx_capa(wed))
|
||||
dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed;
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2],
|
||||
MT_RXQ_ID(MT_RXQ_RRO_BAND2),
|
||||
MT7996_RX_RING_SIZE,
|
||||
@@ -752,6 +927,10 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
|
||||
|
||||
mt76_tx_status_check(&dev->mt76, true);
|
||||
|
||||
if (mt7996_has_hwrro(dev) &&
|
||||
!mtk_wed_device_active(&dev->mt76.mmio.wed))
|
||||
mt7996_rro_msdu_page_map_free(dev);
|
||||
|
||||
/* reset wfsys */
|
||||
if (force)
|
||||
mt7996_wfsys_reset(dev);
|
||||
@@ -775,21 +954,32 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
|
||||
}
|
||||
|
||||
for (i = 0; i < __MT_MCUQ_MAX; i++)
|
||||
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
|
||||
mt76_queue_reset(dev, dev->mt76.q_mcu[i], true);
|
||||
|
||||
mt76_for_each_q_rx(&dev->mt76, i) {
|
||||
if (mtk_wed_device_active(&dev->mt76.mmio.wed))
|
||||
if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) ||
|
||||
mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i]))
|
||||
continue;
|
||||
struct mt76_queue *q = &dev->mt76.q_rx[i];
|
||||
|
||||
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
|
||||
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
|
||||
if (mt76_queue_is_wed_rro(q) ||
|
||||
mt76_queue_is_wed_tx_free(q)) {
|
||||
if (force && mt76_queue_is_wed_rro_data(q))
|
||||
mt76_queue_reset(dev, q, false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
mt76_queue_reset(dev, q, true);
|
||||
}
|
||||
|
||||
mt76_tx_status_check(&dev->mt76, true);
|
||||
|
||||
mt76_for_each_q_rx(&dev->mt76, i)
|
||||
mt76_for_each_q_rx(&dev->mt76, i) {
|
||||
if (mtk_wed_device_active(&dev->mt76.mmio.wed) && force &&
|
||||
(mt76_queue_is_wed_rro_ind(&dev->mt76.q_rx[i]) ||
|
||||
mt76_queue_is_wed_rro_msdu_pg(&dev->mt76.q_rx[i])))
|
||||
continue;
|
||||
|
||||
mt76_queue_rx_reset(dev, i);
|
||||
}
|
||||
|
||||
mt7996_dma_enable(dev, !force);
|
||||
}
|
||||
|
||||
@@ -334,9 +334,8 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
|
||||
return ret;
|
||||
|
||||
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN);
|
||||
mt76_eeprom_override(&dev->mphy);
|
||||
|
||||
return 0;
|
||||
return mt76_eeprom_override(&dev->mphy);
|
||||
}
|
||||
|
||||
int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
|
||||
|
||||
@@ -63,6 +63,33 @@ static const struct ieee80211_iface_combination if_comb = {
|
||||
.beacon_int_min_gcd = 100,
|
||||
};
|
||||
|
||||
static const u8 if_types_ext_capa_ap[] = {
|
||||
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
|
||||
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
|
||||
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||
};
|
||||
|
||||
static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = {
|
||||
{
|
||||
.iftype = NL80211_IFTYPE_AP,
|
||||
.extended_capabilities = if_types_ext_capa_ap,
|
||||
.extended_capabilities_mask = if_types_ext_capa_ap,
|
||||
.extended_capabilities_len = sizeof(if_types_ext_capa_ap),
|
||||
.eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP,
|
||||
.mld_capa_and_ops =
|
||||
FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS,
|
||||
MT7996_MAX_RADIOS - 1),
|
||||
}, {
|
||||
.iftype = NL80211_IFTYPE_STATION,
|
||||
.extended_capabilities = if_types_ext_capa_ap,
|
||||
.extended_capabilities_mask = if_types_ext_capa_ap,
|
||||
.extended_capabilities_len = sizeof(if_types_ext_capa_ap),
|
||||
.mld_capa_and_ops =
|
||||
FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS,
|
||||
MT7996_MAX_RADIOS - 1),
|
||||
},
|
||||
};
|
||||
|
||||
static ssize_t mt7996_thermal_temp_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@@ -383,6 +410,7 @@ mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy)
|
||||
|
||||
phy->slottime = 9;
|
||||
phy->beacon_rate = -1;
|
||||
phy->rxfilter = MT_WF_RFCR_DROP_OTHER_UC;
|
||||
|
||||
if (phy->mt76->cap.has_2ghz) {
|
||||
phy->mt76->sband_2g.sband.ht_cap.cap |=
|
||||
@@ -463,8 +491,11 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
|
||||
wiphy->radio = dev->radios;
|
||||
|
||||
wiphy->reg_notifier = mt7996_regd_notifier;
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
|
||||
WIPHY_FLAG_SUPPORTS_MLO;
|
||||
wiphy->mbssid_max_interfaces = 16;
|
||||
wiphy->iftype_ext_capab = iftypes_ext_capa;
|
||||
wiphy->num_iftype_ext_capab = ARRAY_SIZE(iftypes_ext_capa);
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
@@ -575,19 +606,21 @@ void mt7996_mac_init(struct mt7996_dev *dev)
|
||||
}
|
||||
|
||||
/* rro module init */
|
||||
if (is_mt7996(&dev->mt76))
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
|
||||
else
|
||||
if (dev->hif2)
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE,
|
||||
dev->hif2 ? 7 : 0);
|
||||
is_mt7996(&dev->mt76) ? 2 : 7);
|
||||
else
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0);
|
||||
|
||||
if (dev->has_rro) {
|
||||
if (mt7996_has_hwrro(dev)) {
|
||||
u16 timeout;
|
||||
|
||||
timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128;
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout);
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1);
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0);
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE,
|
||||
is_mt7996(&dev->mt76) ? 1 : 2);
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH,
|
||||
!is_mt7996(&dev->mt76));
|
||||
} else {
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
|
||||
mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
|
||||
@@ -634,7 +667,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
|
||||
if (!mt7996_band_valid(dev, band))
|
||||
return 0;
|
||||
|
||||
if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) {
|
||||
if (dev->hif2 &&
|
||||
((is_mt7996(&dev->mt76) && band == MT_BAND2) ||
|
||||
(is_mt7992(&dev->mt76) && band == MT_BAND1))) {
|
||||
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
|
||||
wed = &dev->mt76.mmio.wed_hif2;
|
||||
}
|
||||
@@ -667,17 +702,26 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
|
||||
if (band == MT_BAND2)
|
||||
mphy->macaddr[0] ^= BIT(6);
|
||||
}
|
||||
mt76_eeprom_override(mphy);
|
||||
ret = mt76_eeprom_override(mphy);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* init wiphy according to mphy and phy */
|
||||
mt7996_init_wiphy_band(mphy->hw, phy);
|
||||
ret = mt7996_init_tx_queues(mphy->priv,
|
||||
MT_TXQ_ID(band),
|
||||
MT7996_TX_RING_SIZE,
|
||||
MT_TXQ_RING_BASE(band) + hif1_ofs,
|
||||
wed);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
if (is_mt7996(&dev->mt76) && !dev->hif2 && band == MT_BAND1) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= MT_TXQ_PSD; i++)
|
||||
mphy->q_tx[i] = dev->mt76.phys[MT_BAND0]->q_tx[0];
|
||||
} else {
|
||||
ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band),
|
||||
MT7996_TX_RING_SIZE,
|
||||
MT_TXQ_RING_BASE(band) + hif1_ofs,
|
||||
wed);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = mt76_register_phy(mphy, true, mt76_rates,
|
||||
ARRAY_SIZE(mt76_rates));
|
||||
@@ -685,10 +729,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
|
||||
goto error;
|
||||
|
||||
if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) {
|
||||
u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2;
|
||||
|
||||
mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask);
|
||||
mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask);
|
||||
mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT);
|
||||
mtk_wed_device_start(&dev->mt76.mmio.wed_hif2,
|
||||
MT_INT_TX_RX_DONE_EXT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -724,30 +767,151 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev)
|
||||
{
|
||||
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
|
||||
u32 session_id;
|
||||
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) {
|
||||
wed->wlan.ind_cmd.win_size =
|
||||
ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
|
||||
if (is_mt7996(&dev->mt76))
|
||||
wed->wlan.ind_cmd.particular_sid =
|
||||
MT7996_RRO_MAX_SESSION;
|
||||
else
|
||||
wed->wlan.ind_cmd.particular_sid = 1;
|
||||
wed->wlan.ind_cmd.particular_se_phys =
|
||||
dev->wed_rro.session.phy_addr;
|
||||
wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN;
|
||||
wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL;
|
||||
}
|
||||
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
|
||||
|
||||
if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) {
|
||||
mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00);
|
||||
mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1,
|
||||
MT_RRO_IND_CMD_SIGNATURE_BASE1_EN);
|
||||
} else {
|
||||
mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0);
|
||||
mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, 0);
|
||||
}
|
||||
|
||||
/* particular session configure */
|
||||
/* use max session idx + 1 as particular session id */
|
||||
mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr);
|
||||
|
||||
session_id = is_mt7996(&dev->mt76) ? MT7996_RRO_MAX_SESSION : 1;
|
||||
mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
|
||||
MT_RRO_PARTICULAR_CONFG_EN |
|
||||
FIELD_PREP(MT_RRO_PARTICULAR_SID, session_id));
|
||||
}
|
||||
|
||||
void mt7996_rro_hw_init(struct mt7996_dev *dev)
|
||||
{
|
||||
u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0;
|
||||
int i;
|
||||
|
||||
if (!mt7996_has_hwrro(dev))
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&dev->wed_rro.page_cache);
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.page_map); i++)
|
||||
INIT_LIST_HEAD(&dev->wed_rro.page_map[i]);
|
||||
|
||||
if (!is_mt7996(&dev->mt76)) {
|
||||
reg = MT_RRO_MSDU_PG_SEG_ADDR0;
|
||||
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
|
||||
mt76_clear(dev, MT_RRO_3_0_EMU_CONF,
|
||||
MT_RRO_3_0_EMU_CONF_EN_MASK);
|
||||
mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG,
|
||||
MT_RRO_3_1_GLOBAL_CONFIG_RXDMAD_SEL);
|
||||
if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) {
|
||||
mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG,
|
||||
MT_RRO_3_1_GLOBAL_CONFIG_RX_DIDX_WR_EN |
|
||||
MT_RRO_3_1_GLOBAL_CONFIG_RX_CIDX_RD_EN);
|
||||
mt76_wr(dev, MT_RRO_RX_RING_AP_CIDX_ADDR,
|
||||
dev->wed_rro.emi_rings_cpu.phy_addr >> 4);
|
||||
mt76_wr(dev, MT_RRO_RX_RING_AP_DIDX_ADDR,
|
||||
dev->wed_rro.emi_rings_dma.phy_addr >> 4);
|
||||
}
|
||||
} else {
|
||||
/* set emul 3.0 function */
|
||||
mt76_wr(dev, MT_RRO_3_0_EMU_CONF,
|
||||
MT_RRO_3_0_EMU_CONF_EN_MASK);
|
||||
|
||||
mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0,
|
||||
dev->wed_rro.addr_elem[0].phy_addr);
|
||||
}
|
||||
|
||||
mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG,
|
||||
MT_RRO_3_1_GLOBAL_CONFIG_INTERLEAVE_EN);
|
||||
|
||||
/* setup Msdu page address */
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
|
||||
mt76_wr(dev, reg,
|
||||
dev->wed_rro.msdu_pg[i].phy_addr >> 4);
|
||||
reg += 4;
|
||||
}
|
||||
} else {
|
||||
/* TODO: remove line after WM has set */
|
||||
mt76_clear(dev, WF_RRO_AXI_MST_CFG,
|
||||
WF_RRO_AXI_MST_CFG_DIDX_OK);
|
||||
|
||||
/* setup BA bitmap cache address */
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0,
|
||||
dev->wed_rro.ba_bitmap[0].phy_addr);
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0);
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0,
|
||||
dev->wed_rro.ba_bitmap[1].phy_addr);
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0);
|
||||
|
||||
/* Setup Address element address */
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
|
||||
mt76_wr(dev, reg,
|
||||
dev->wed_rro.addr_elem[i].phy_addr >> 4);
|
||||
reg += 4;
|
||||
}
|
||||
|
||||
/* Setup Address element address - separate address segment
|
||||
* mode.
|
||||
*/
|
||||
mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
|
||||
MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
|
||||
}
|
||||
|
||||
mt7996_rro_hw_init_v3(dev);
|
||||
|
||||
/* interrupt enable */
|
||||
mt76_wr(dev, MT_RRO_HOST_INT_ENA,
|
||||
MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
|
||||
}
|
||||
|
||||
static int mt7996_wed_rro_init(struct mt7996_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
|
||||
u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0;
|
||||
u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, 0xff);
|
||||
struct mt7996_wed_rro_addr *addr;
|
||||
void *ptr;
|
||||
int i;
|
||||
|
||||
if (!dev->has_rro)
|
||||
if (!mt7996_has_hwrro(dev))
|
||||
return 0;
|
||||
|
||||
if (!mtk_wed_device_active(wed))
|
||||
return 0;
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3) {
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) {
|
||||
ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
|
||||
MT7996_RRO_BA_BITMAP_CR_SIZE,
|
||||
&dev->wed_rro.ba_bitmap[i].phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) {
|
||||
ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
|
||||
MT7996_RRO_BA_BITMAP_CR_SIZE,
|
||||
&dev->wed_rro.ba_bitmap[i].phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->wed_rro.ba_bitmap[i].ptr = ptr;
|
||||
dev->wed_rro.ba_bitmap[i].ptr = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
|
||||
@@ -766,12 +930,53 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
|
||||
|
||||
addr = dev->wed_rro.addr_elem[i].ptr;
|
||||
for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) {
|
||||
addr->signature = 0xff;
|
||||
addr->data = cpu_to_le32(val);
|
||||
addr++;
|
||||
}
|
||||
|
||||
wed->wlan.ind_cmd.addr_elem_phys[i] =
|
||||
dev->wed_rro.addr_elem[i].phy_addr;
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
|
||||
mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) {
|
||||
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
|
||||
|
||||
wed->wlan.ind_cmd.addr_elem_phys[i] =
|
||||
dev->wed_rro.addr_elem[i].phy_addr;
|
||||
}
|
||||
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
|
||||
ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
|
||||
MT7996_RRO_MSDU_PG_SIZE_PER_CR,
|
||||
&dev->wed_rro.msdu_pg[i].phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->wed_rro.msdu_pg[i].ptr = ptr;
|
||||
|
||||
memset(dev->wed_rro.msdu_pg[i].ptr, 0,
|
||||
MT7996_RRO_MSDU_PG_SIZE_PER_CR);
|
||||
}
|
||||
|
||||
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
|
||||
ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
|
||||
sizeof(dev->wed_rro.emi_rings_cpu.ptr),
|
||||
&dev->wed_rro.emi_rings_cpu.phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->wed_rro.emi_rings_cpu.ptr = ptr;
|
||||
|
||||
ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
|
||||
sizeof(dev->wed_rro.emi_rings_dma.ptr),
|
||||
&dev->wed_rro.emi_rings_dma.phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->wed_rro.emi_rings_dma.ptr = ptr;
|
||||
}
|
||||
|
||||
ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
|
||||
@@ -784,69 +989,20 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
|
||||
dev->wed_rro.session.ptr = ptr;
|
||||
addr = dev->wed_rro.session.ptr;
|
||||
for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
|
||||
addr->signature = 0xff;
|
||||
addr->data = cpu_to_le32(val);
|
||||
addr++;
|
||||
}
|
||||
|
||||
/* rro hw init */
|
||||
/* TODO: remove line after WM has set */
|
||||
mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK);
|
||||
mt7996_rro_hw_init(dev);
|
||||
|
||||
/* setup BA bitmap cache address */
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0,
|
||||
dev->wed_rro.ba_bitmap[0].phy_addr);
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0);
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0,
|
||||
dev->wed_rro.ba_bitmap[1].phy_addr);
|
||||
mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0);
|
||||
|
||||
/* setup Address element address */
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
|
||||
mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4);
|
||||
reg += 4;
|
||||
}
|
||||
|
||||
/* setup Address element address - separate address segment mode */
|
||||
mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
|
||||
MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
|
||||
|
||||
wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
|
||||
wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION;
|
||||
wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr;
|
||||
wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN;
|
||||
wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL;
|
||||
|
||||
mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00);
|
||||
mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1,
|
||||
MT_RRO_IND_CMD_SIGNATURE_BASE1_EN);
|
||||
|
||||
/* particular session configure */
|
||||
/* use max session idx + 1 as particular session id */
|
||||
mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr);
|
||||
mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
|
||||
MT_RRO_PARTICULAR_CONFG_EN |
|
||||
FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION));
|
||||
|
||||
/* interrupt enable */
|
||||
mt76_wr(dev, MT_RRO_HOST_INT_ENA,
|
||||
MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
|
||||
|
||||
/* rro ind cmd queue init */
|
||||
return mt7996_dma_rro_init(dev);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mt7996_wed_rro_free(struct mt7996_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
int i;
|
||||
|
||||
if (!dev->has_rro)
|
||||
return;
|
||||
|
||||
if (!mtk_wed_device_active(&dev->mt76.mmio.wed))
|
||||
if (!mt7996_has_hwrro(dev))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) {
|
||||
@@ -870,6 +1026,16 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev)
|
||||
dev->wed_rro.addr_elem[i].phy_addr);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
|
||||
if (!dev->wed_rro.msdu_pg[i].ptr)
|
||||
continue;
|
||||
|
||||
dmam_free_coherent(dev->mt76.dma_dev,
|
||||
MT7996_RRO_MSDU_PG_SIZE_PER_CR,
|
||||
dev->wed_rro.msdu_pg[i].ptr,
|
||||
dev->wed_rro.msdu_pg[i].phy_addr);
|
||||
}
|
||||
|
||||
if (!dev->wed_rro.session.ptr)
|
||||
return;
|
||||
|
||||
@@ -878,12 +1044,11 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev)
|
||||
sizeof(struct mt7996_wed_rro_addr),
|
||||
dev->wed_rro.session.ptr,
|
||||
dev->wed_rro.session.phy_addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mt7996_wed_rro_work(struct work_struct *work)
|
||||
{
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, 0xff);
|
||||
struct mt7996_dev *dev;
|
||||
LIST_HEAD(list);
|
||||
|
||||
@@ -920,13 +1085,12 @@ static void mt7996_wed_rro_work(struct work_struct *work)
|
||||
MT7996_RRO_WINDOW_MAX_LEN;
|
||||
reset:
|
||||
elem = ptr + elem_id * sizeof(*elem);
|
||||
elem->signature = 0xff;
|
||||
elem->data |= cpu_to_le32(val);
|
||||
}
|
||||
mt7996_mcu_wed_rro_reset_sessions(dev, e->id);
|
||||
out:
|
||||
kfree(e);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mt7996_variant_type_init(struct mt7996_dev *dev)
|
||||
@@ -1321,7 +1485,6 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
|
||||
eht_cap->has_eht = true;
|
||||
|
||||
eht_cap_elem->mac_cap_info[0] =
|
||||
IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
|
||||
IEEE80211_EHT_MAC_CAP0_OM_CONTROL |
|
||||
u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454,
|
||||
IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK);
|
||||
@@ -1551,6 +1714,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
|
||||
mt7996_mcu_exit(dev);
|
||||
mt7996_tx_token_put(dev);
|
||||
mt7996_dma_cleanup(dev);
|
||||
if (mt7996_has_hwrro(dev) &&
|
||||
!mtk_wed_device_active(&dev->mt76.mmio.wed))
|
||||
mt7996_rro_msdu_page_map_free(dev);
|
||||
tasklet_disable(&dev->mt76.irq_tasklet);
|
||||
|
||||
mt76_free_device(&dev->mt76);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -138,6 +138,28 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_own_mld_idx(u64 mask, bool group_mld)
|
||||
{
|
||||
u8 start = group_mld ? 0 : 16;
|
||||
u8 end = group_mld ? 15 : 63;
|
||||
int idx;
|
||||
|
||||
idx = get_free_idx(mask, start, end);
|
||||
if (idx)
|
||||
return idx - 1;
|
||||
|
||||
/* If the 16-63 range is not available, perform another lookup in the
|
||||
* range 0-15
|
||||
*/
|
||||
if (!group_mld) {
|
||||
idx = get_free_idx(mask, 0, 15);
|
||||
if (idx)
|
||||
return idx - 1;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlink)
|
||||
{
|
||||
@@ -160,112 +182,105 @@ mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlin
|
||||
static int
|
||||
mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
unsigned int link_id, struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
int idx = key->keyidx;
|
||||
unsigned int link_id;
|
||||
unsigned long links;
|
||||
u8 *wcid_keyidx;
|
||||
bool is_bigtk;
|
||||
int err;
|
||||
|
||||
if (key->link_id >= 0)
|
||||
links = BIT(key->link_id);
|
||||
else if (sta && sta->valid_links)
|
||||
links = sta->valid_links;
|
||||
else if (vif->valid_links)
|
||||
links = vif->valid_links;
|
||||
else
|
||||
links = BIT(0);
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
return 0;
|
||||
|
||||
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
u8 *wcid_keyidx;
|
||||
int err;
|
||||
if (!mt7996_vif_link_phy(link))
|
||||
return 0;
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
continue;
|
||||
if (sta) {
|
||||
struct mt7996_sta *msta;
|
||||
|
||||
if (sta) {
|
||||
struct mt7996_sta *msta;
|
||||
msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
msta_link = mt76_dereference(msta->link[link_id],
|
||||
&dev->mt76);
|
||||
if (!msta_link)
|
||||
return 0;
|
||||
|
||||
msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
msta_link = mt76_dereference(msta->link[link_id],
|
||||
&dev->mt76);
|
||||
if (!msta_link)
|
||||
continue;
|
||||
if (!msta_link->wcid.sta)
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
msta_link = &link->msta_link;
|
||||
}
|
||||
wcid_keyidx = &msta_link->wcid.hw_key_idx;
|
||||
|
||||
if (!msta_link->wcid.sta)
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
msta_link = &link->msta_link;
|
||||
is_bigtk = key->keyidx == 6 || key->keyidx == 7;
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
if (is_bigtk) {
|
||||
wcid_keyidx = &msta_link->wcid.hw_key_idx2;
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
|
||||
}
|
||||
wcid_keyidx = &msta_link->wcid.hw_key_idx;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
if (key->keyidx == 6 || key->keyidx == 7) {
|
||||
wcid_keyidx = &msta_link->wcid.hw_key_idx2;
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == SET_KEY && !sta && !link->mt76.cipher) {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
link_conf = link_conf_dereference_protected(vif,
|
||||
link_id);
|
||||
if (!link_conf)
|
||||
link_conf = &vif->bss_conf;
|
||||
|
||||
link->mt76.cipher =
|
||||
mt76_connac_mcu_get_cipher(key->cipher);
|
||||
mt7996_mcu_add_bss_info(link->phy, vif, link_conf,
|
||||
&link->mt76, msta_link, true);
|
||||
}
|
||||
|
||||
if (cmd == SET_KEY) {
|
||||
*wcid_keyidx = idx;
|
||||
} else {
|
||||
if (idx == *wcid_keyidx)
|
||||
*wcid_keyidx = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key);
|
||||
|
||||
if (key->keyidx == 6 || key->keyidx == 7) {
|
||||
err = mt7996_mcu_bcn_prot_enable(dev, link,
|
||||
msta_link, key);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mt7996_mcu_add_key(&dev->mt76, vif, key,
|
||||
MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
|
||||
&msta_link->wcid, cmd);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
link_conf = link_conf_dereference_protected(vif, link_id);
|
||||
if (!link_conf)
|
||||
link_conf = &vif->bss_conf;
|
||||
|
||||
if (cmd == SET_KEY && !sta && !link->mt76.cipher) {
|
||||
link->mt76.cipher =
|
||||
mt76_connac_mcu_get_cipher(key->cipher);
|
||||
mt7996_mcu_add_bss_info(link->phy, vif, link_conf,
|
||||
&link->mt76, msta_link, true);
|
||||
}
|
||||
|
||||
if (cmd == SET_KEY)
|
||||
*wcid_keyidx = idx;
|
||||
else if (idx == *wcid_keyidx)
|
||||
*wcid_keyidx = -1;
|
||||
|
||||
if (cmd != SET_KEY && sta)
|
||||
return 0;
|
||||
|
||||
mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key);
|
||||
|
||||
err = mt7996_mcu_add_key(&dev->mt76, vif, key,
|
||||
MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
|
||||
&msta_link->wcid, cmd);
|
||||
|
||||
/* remove and add beacon in order to enable beacon protection */
|
||||
if (cmd == SET_KEY && is_bigtk && link_conf->enable_beacon) {
|
||||
mt7996_mcu_add_beacon(hw, vif, link_conf, false);
|
||||
mt7996_mcu_add_beacon(hw, vif, link_conf, true);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct mt7996_key_iter_data {
|
||||
enum set_key_cmd cmd;
|
||||
unsigned int link_id;
|
||||
};
|
||||
|
||||
static void
|
||||
mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct ieee80211_key_conf *key,
|
||||
void *data)
|
||||
{
|
||||
struct mt7996_key_iter_data *it = data;
|
||||
|
||||
if (sta)
|
||||
return;
|
||||
|
||||
WARN_ON(mt7996_set_hw_key(hw, SET_KEY, vif, NULL, key));
|
||||
WARN_ON(mt7996_set_hw_key(hw, it->cmd, vif, NULL, it->link_id, key));
|
||||
}
|
||||
|
||||
int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
@@ -278,8 +293,12 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
struct mt7996_phy *phy = mphy->priv;
|
||||
struct mt7996_dev *dev = phy->dev;
|
||||
u8 band_idx = phy->mt76->band_idx;
|
||||
struct mt7996_key_iter_data it = {
|
||||
.cmd = SET_KEY,
|
||||
.link_id = link_conf->link_id,
|
||||
};
|
||||
struct mt76_txq *mtxq;
|
||||
int idx, ret;
|
||||
int mld_idx, idx, ret;
|
||||
|
||||
mlink->idx = __ffs64(~dev->mt76.vif_mask);
|
||||
if (mlink->idx >= mt7996_max_interface_num(dev))
|
||||
@@ -289,6 +308,17 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
if (!dev->mld_idx_mask) { /* first link in the group */
|
||||
mvif->mld_group_idx = get_own_mld_idx(dev->mld_idx_mask, true);
|
||||
mvif->mld_remap_idx = get_free_idx(dev->mld_remap_idx_mask,
|
||||
0, 15);
|
||||
}
|
||||
|
||||
mld_idx = get_own_mld_idx(dev->mld_idx_mask, false);
|
||||
if (mld_idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
link->mld_idx = mld_idx;
|
||||
link->phy = phy;
|
||||
mlink->omac_idx = idx;
|
||||
mlink->band_idx = band_idx;
|
||||
@@ -301,6 +331,11 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
return ret;
|
||||
|
||||
dev->mt76.vif_mask |= BIT_ULL(mlink->idx);
|
||||
if (!dev->mld_idx_mask) {
|
||||
dev->mld_idx_mask |= BIT_ULL(mvif->mld_group_idx);
|
||||
dev->mld_remap_idx_mask |= BIT_ULL(mvif->mld_remap_idx);
|
||||
}
|
||||
dev->mld_idx_mask |= BIT_ULL(link->mld_idx);
|
||||
phy->omac_mask |= BIT_ULL(mlink->omac_idx);
|
||||
|
||||
idx = MT7996_WTBL_RESERVED - mlink->idx;
|
||||
@@ -339,7 +374,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
CONN_STATE_PORT_SECURE, true);
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid);
|
||||
|
||||
ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, NULL);
|
||||
ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
|
||||
|
||||
if (mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED)
|
||||
mvif->mt76.deflink_id = link_conf->link_id;
|
||||
@@ -356,8 +391,14 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
struct mt7996_sta_link *msta_link = &link->msta_link;
|
||||
struct mt7996_phy *phy = mphy->priv;
|
||||
struct mt7996_dev *dev = phy->dev;
|
||||
struct mt7996_key_iter_data it = {
|
||||
.cmd = SET_KEY,
|
||||
.link_id = link_conf->link_id,
|
||||
};
|
||||
int idx = msta_link->wcid.idx;
|
||||
|
||||
ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
|
||||
|
||||
mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL,
|
||||
CONN_STATE_DISCONNECT, false);
|
||||
mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false);
|
||||
@@ -380,7 +421,13 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
||||
}
|
||||
|
||||
dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx);
|
||||
dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx);
|
||||
phy->omac_mask &= ~BIT_ULL(mlink->omac_idx);
|
||||
if (!(dev->mld_idx_mask & ~BIT_ULL(mvif->mld_group_idx))) {
|
||||
/* last link */
|
||||
dev->mld_idx_mask &= ~BIT_ULL(mvif->mld_group_idx);
|
||||
dev->mld_remap_idx_mask &= ~BIT_ULL(mvif->mld_remap_idx);
|
||||
}
|
||||
|
||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||
if (!list_empty(&msta_link->wcid.poll_list))
|
||||
@@ -551,8 +598,9 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
|
||||
int err;
|
||||
unsigned int link_id;
|
||||
unsigned long links;
|
||||
int err = 0;
|
||||
|
||||
/* The hardware does not support per-STA RX GTK, fallback
|
||||
* to software mode for these.
|
||||
@@ -586,11 +634,22 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!mt7996_vif_link_phy(&mvif->deflink))
|
||||
return 0; /* defer until after link add */
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
err = mt7996_set_hw_key(hw, cmd, vif, sta, key);
|
||||
|
||||
if (key->link_id >= 0)
|
||||
links = BIT(key->link_id);
|
||||
else if (sta && sta->valid_links)
|
||||
links = sta->valid_links;
|
||||
else if (vif->valid_links)
|
||||
links = vif->valid_links;
|
||||
else
|
||||
links = BIT(0);
|
||||
|
||||
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
err = mt7996_set_hw_key(hw, cmd, vif, sta, link_id, key);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return err;
|
||||
@@ -850,7 +909,7 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
link->mt76.beacon_rates_idx =
|
||||
mt7996_get_rates_table(phy, info, true, false);
|
||||
|
||||
mt7996_mcu_add_beacon(hw, vif, info);
|
||||
mt7996_mcu_add_beacon(hw, vif, info, info->enable_beacon);
|
||||
}
|
||||
|
||||
if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
|
||||
@@ -878,7 +937,7 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf);
|
||||
mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf, vif->bss_conf.enable_beacon);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
}
|
||||
|
||||
@@ -925,6 +984,7 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
|
||||
msta_link->wcid.sta = 1;
|
||||
msta_link->wcid.idx = idx;
|
||||
msta_link->wcid.link_id = link_id;
|
||||
msta_link->wcid.def_wcid = &msta->deflink.wcid;
|
||||
|
||||
ewma_avg_signal_init(&msta_link->avg_ack_signal);
|
||||
ewma_signal_init(&msta_link->wcid.rssi);
|
||||
@@ -941,18 +1001,9 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
|
||||
struct mt7996_sta_link *msta_link)
|
||||
void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
|
||||
struct mt7996_sta_link *msta_link)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(msta_link->wcid.aggr); i++)
|
||||
mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, i);
|
||||
|
||||
mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||
if (!list_empty(&msta_link->wcid.poll_list))
|
||||
list_del_init(&msta_link->wcid.poll_list);
|
||||
@@ -982,6 +1033,9 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||
if (!msta_link)
|
||||
continue;
|
||||
|
||||
mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
mt7996_mac_sta_deinit_link(dev, msta_link);
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
@@ -1036,16 +1090,17 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||
goto error_unlink;
|
||||
}
|
||||
|
||||
err = mt7996_mac_sta_init_link(dev, link_conf, link_sta, link,
|
||||
link_id);
|
||||
if (err)
|
||||
goto error_unlink;
|
||||
|
||||
mphy = mt76_vif_link_phy(&link->mt76);
|
||||
if (!mphy) {
|
||||
err = -EINVAL;
|
||||
goto error_unlink;
|
||||
}
|
||||
|
||||
err = mt7996_mac_sta_init_link(dev, link_conf, link_sta, link,
|
||||
link_id);
|
||||
if (err)
|
||||
goto error_unlink;
|
||||
|
||||
mphy->num_sta++;
|
||||
}
|
||||
|
||||
@@ -1179,6 +1234,24 @@ mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_set_active_links(struct ieee80211_vif *vif)
|
||||
{
|
||||
u16 active_links;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
return;
|
||||
|
||||
active_links = mt76_select_links(vif, MT7996_MAX_RADIOS);
|
||||
if (hweight16(active_links) < 2)
|
||||
return;
|
||||
|
||||
ieee80211_set_active_links_async(vif, active_links);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, enum ieee80211_sta_state old_state,
|
||||
@@ -1196,16 +1269,18 @@ mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
mt7996_mac_sta_remove(dev, vif, sta);
|
||||
|
||||
if (old_state == IEEE80211_STA_AUTH &&
|
||||
new_state == IEEE80211_STA_ASSOC)
|
||||
new_state == IEEE80211_STA_ASSOC) {
|
||||
mt7996_set_active_links(vif);
|
||||
ev = MT76_STA_EVENT_ASSOC;
|
||||
else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
new_state == IEEE80211_STA_AUTHORIZED)
|
||||
} else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
new_state == IEEE80211_STA_AUTHORIZED) {
|
||||
ev = MT76_STA_EVENT_AUTHORIZE;
|
||||
else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
new_state == IEEE80211_STA_AUTH)
|
||||
} else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
new_state == IEEE80211_STA_AUTH) {
|
||||
ev = MT76_STA_EVENT_DISASSOC;
|
||||
else
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mt7996_mac_sta_event(dev, vif, sta, ev);
|
||||
}
|
||||
@@ -1214,28 +1289,61 @@ static void mt7996_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_control *control,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct ieee80211_sta *sta = control->sta;
|
||||
struct mt7996_sta *msta = sta ? (void *)sta->drv_priv : NULL;
|
||||
struct mt76_phy *mphy = hw->priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct mt7996_vif *mvif = vif ? (void *)vif->drv_priv : NULL;
|
||||
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
|
||||
u8 link_id = u32_get_bits(info->control.flags,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (vif) {
|
||||
struct mt7996_vif *mvif = (void *)vif->drv_priv;
|
||||
/* Use primary link_id if the value from mac80211 is set to
|
||||
* IEEE80211_LINK_UNSPECIFIED.
|
||||
*/
|
||||
if (link_id == IEEE80211_LINK_UNSPECIFIED) {
|
||||
if (msta)
|
||||
link_id = msta->deflink_id;
|
||||
else if (mvif)
|
||||
link_id = mvif->mt76.deflink_id;
|
||||
}
|
||||
|
||||
if (vif && ieee80211_vif_is_mld(vif)) {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
if (msta) {
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
link_sta = rcu_dereference(sta->link[link_id]);
|
||||
if (!link_sta)
|
||||
link_sta = rcu_dereference(sta->link[msta->deflink_id]);
|
||||
|
||||
if (link_sta) {
|
||||
memcpy(hdr->addr1, link_sta->addr, ETH_ALEN);
|
||||
if (ether_addr_equal(sta->addr, hdr->addr3))
|
||||
memcpy(hdr->addr3, link_sta->addr, ETH_ALEN);
|
||||
}
|
||||
}
|
||||
|
||||
link_conf = rcu_dereference(vif->link_conf[link_id]);
|
||||
if (link_conf) {
|
||||
memcpy(hdr->addr2, link_conf->addr, ETH_ALEN);
|
||||
if (ether_addr_equal(vif->addr, hdr->addr3))
|
||||
memcpy(hdr->addr3, link_conf->addr, ETH_ALEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (mvif) {
|
||||
struct mt76_vif_link *mlink = &mvif->deflink.mt76;
|
||||
|
||||
if (link_id < IEEE80211_LINK_UNSPECIFIED)
|
||||
mlink = rcu_dereference(mvif->mt76.link[link_id]);
|
||||
|
||||
if (!mlink) {
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (mlink->wcid)
|
||||
wcid = mlink->wcid;
|
||||
|
||||
@@ -1254,8 +1362,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (control->sta && link_id < IEEE80211_LINK_UNSPECIFIED) {
|
||||
struct mt7996_sta *msta = (void *)control->sta->drv_priv;
|
||||
if (msta && link_id < IEEE80211_LINK_UNSPECIFIED) {
|
||||
struct mt7996_sta_link *msta_link;
|
||||
|
||||
msta_link = rcu_dereference(msta->link[link_id]);
|
||||
@@ -1292,16 +1399,13 @@ static int
|
||||
mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct ieee80211_sta *sta = params->sta;
|
||||
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
struct ieee80211_txq *txq = sta->txq[params->tid];
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u16 tid = params->tid;
|
||||
u16 ssn = params->ssn;
|
||||
struct mt76_txq *mtxq;
|
||||
unsigned int link_id;
|
||||
int ret = 0;
|
||||
|
||||
if (!txq)
|
||||
@@ -1311,59 +1415,42 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
for_each_sta_active_link(vif, sta, link_sta, link_id) {
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
|
||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
||||
if (!msta_link)
|
||||
continue;
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
continue;
|
||||
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
mt76_rx_aggr_start(&dev->mt76, &msta_link->wcid, tid,
|
||||
ssn, params->buf_size);
|
||||
ret = mt7996_mcu_add_rx_ba(dev, params, link, true);
|
||||
break;
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, tid);
|
||||
ret = mt7996_mcu_add_rx_ba(dev, params, link, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
mtxq->aggr = true;
|
||||
mtxq->send_bar = false;
|
||||
ret = mt7996_mcu_add_tx_ba(dev, params, link,
|
||||
msta_link, true);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH:
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
|
||||
mtxq->aggr = false;
|
||||
clear_bit(tid, &msta_link->wcid.ampdu_state);
|
||||
ret = mt7996_mcu_add_tx_ba(dev, params, link,
|
||||
msta_link, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
set_bit(tid, &msta_link->wcid.ampdu_state);
|
||||
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
mtxq->aggr = false;
|
||||
clear_bit(tid, &msta_link->wcid.ampdu_state);
|
||||
ret = mt7996_mcu_add_tx_ba(dev, params, link,
|
||||
msta_link, false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (action == IEEE80211_AMPDU_TX_STOP_CONT)
|
||||
switch (params->action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
/* Since packets belonging to the same TID can be split over
|
||||
* multiple links, store the AMPDU state for reordering in the
|
||||
* primary link
|
||||
*/
|
||||
mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid,
|
||||
ssn, params->buf_size);
|
||||
ret = mt7996_mcu_add_rx_ba(dev, params, vif, true);
|
||||
break;
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid);
|
||||
ret = mt7996_mcu_add_rx_ba(dev, params, vif, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
mtxq->aggr = true;
|
||||
mtxq->send_bar = false;
|
||||
ret = mt7996_mcu_add_tx_ba(dev, params, vif, true);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH:
|
||||
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
|
||||
mtxq->aggr = false;
|
||||
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
|
||||
ret = mt7996_mcu_add_tx_ba(dev, params, vif, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
set_bit(tid, &msta->deflink.wcid.ampdu_state);
|
||||
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
mtxq->aggr = false;
|
||||
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
|
||||
ret = mt7996_mcu_add_tx_ba(dev, params, vif, false);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
@@ -1617,19 +1704,13 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
|
||||
}
|
||||
}
|
||||
|
||||
static void mt7996_link_rate_ctrl_update(void *data, struct ieee80211_sta *sta)
|
||||
static void mt7996_link_rate_ctrl_update(void *data,
|
||||
struct mt7996_sta_link *msta_link)
|
||||
{
|
||||
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
struct mt7996_sta *msta = msta_link->sta;
|
||||
struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
u32 *changed = data;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
msta_link = rcu_dereference(msta->link[msta->deflink_id]);
|
||||
if (!msta_link)
|
||||
goto out;
|
||||
|
||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||
|
||||
msta_link->changed |= *changed;
|
||||
@@ -1637,8 +1718,6 @@ static void mt7996_link_rate_ctrl_update(void *data, struct ieee80211_sta *sta)
|
||||
list_add_tail(&msta_link->rc_list, &dev->sta_rc_list);
|
||||
|
||||
spin_unlock_bh(&dev->mt76.sta_poll_lock);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw,
|
||||
@@ -1646,11 +1725,32 @@ static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
u32 changed)
|
||||
{
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct ieee80211_sta *sta = link_sta->sta;
|
||||
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
|
||||
mt7996_link_rate_ctrl_update(&changed, sta);
|
||||
ieee80211_queue_work(hw, &dev->rc_work);
|
||||
rcu_read_lock();
|
||||
|
||||
msta_link = rcu_dereference(msta->link[link_sta->link_id]);
|
||||
if (msta_link) {
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
|
||||
mt7996_link_rate_ctrl_update(&changed, msta_link);
|
||||
ieee80211_queue_work(hw, &dev->rc_work);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void mt7996_sta_rate_ctrl_update(void *data, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
u32 *changed = data;
|
||||
|
||||
msta_link = rcu_dereference(msta->link[msta->deflink_id]);
|
||||
if (msta_link)
|
||||
mt7996_link_rate_ctrl_update(&changed, msta_link);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1671,7 +1771,7 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
* - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT
|
||||
* then multiple MCS setting (MCS 4,5,6) is not supported.
|
||||
*/
|
||||
ieee80211_iterate_stations_atomic(hw, mt7996_link_rate_ctrl_update,
|
||||
ieee80211_iterate_stations_atomic(hw, mt7996_sta_rate_ctrl_update,
|
||||
&changed);
|
||||
ieee80211_queue_work(hw, &dev->rc_work);
|
||||
|
||||
@@ -2072,9 +2172,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
struct mt76_vif_link *mlink;
|
||||
struct mt7996_phy *phy;
|
||||
|
||||
mlink = rcu_dereference(mvif->mt76.link[msta->deflink_id]);
|
||||
if (!mlink)
|
||||
@@ -2087,12 +2185,9 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
|
||||
if (!msta_link->wcid.sta || msta_link->wcid.idx > MT7996_WTBL_STA)
|
||||
return -EIO;
|
||||
|
||||
link = (struct mt7996_vif_link *)mlink;
|
||||
phy = mt7996_vif_link_phy(link);
|
||||
if (!phy)
|
||||
return -ENODEV;
|
||||
|
||||
if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2)
|
||||
if (dev->hif2 &&
|
||||
((is_mt7996(&dev->mt76) && msta_link->wcid.phy_idx == MT_BAND2) ||
|
||||
(is_mt7992(&dev->mt76) && msta_link->wcid.phy_idx == MT_BAND1)))
|
||||
wed = &dev->mt76.mmio.wed_hif2;
|
||||
|
||||
if (!mtk_wed_device_active(wed))
|
||||
@@ -2105,7 +2200,11 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
|
||||
path->mtk_wdma.queue = 0;
|
||||
path->mtk_wdma.wcid = msta_link->wcid.idx;
|
||||
|
||||
path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed);
|
||||
if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU) &&
|
||||
mtk_wed_is_amsdu_supported(wed))
|
||||
path->mtk_wdma.amsdu = msta_link->wcid.amsdu;
|
||||
else
|
||||
path->mtk_wdma.amsdu = 0;
|
||||
ctx->dev = NULL;
|
||||
|
||||
return 0;
|
||||
@@ -2121,6 +2220,19 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_reconfig_complete(struct ieee80211_hw *hw,
|
||||
enum ieee80211_reconfig_type reconfig_type)
|
||||
{
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct mt7996_phy *phy;
|
||||
|
||||
ieee80211_wake_queues(hw);
|
||||
mt7996_for_each_phy(dev, phy)
|
||||
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
|
||||
MT7996_WATCHDOG_TIME);
|
||||
}
|
||||
|
||||
const struct ieee80211_ops mt7996_ops = {
|
||||
.add_chanctx = mt76_add_chanctx,
|
||||
.remove_chanctx = mt76_remove_chanctx,
|
||||
@@ -2179,4 +2291,5 @@ const struct ieee80211_ops mt7996_ops = {
|
||||
#endif
|
||||
.change_vif_links = mt7996_change_vif_links,
|
||||
.change_sta_links = mt7996_mac_sta_change_links,
|
||||
.reconfig_complete = mt7996_reconfig_complete,
|
||||
};
|
||||
|
||||
@@ -242,6 +242,30 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
|
||||
{
|
||||
mdev->mcu.timeout = 5 * HZ;
|
||||
|
||||
if (!(cmd & __MCU_CMD_FIELD_UNI))
|
||||
return;
|
||||
|
||||
switch (FIELD_GET(__MCU_CMD_FIELD_ID, cmd)) {
|
||||
case MCU_UNI_CMD_THERMAL:
|
||||
case MCU_UNI_CMD_TWT:
|
||||
case MCU_UNI_CMD_GET_MIB_INFO:
|
||||
case MCU_UNI_CMD_STA_REC_UPDATE:
|
||||
case MCU_UNI_CMD_BSS_INFO_UPDATE:
|
||||
mdev->mcu.timeout = 2 * HZ;
|
||||
return;
|
||||
case MCU_UNI_CMD_EFUSE_CTRL:
|
||||
mdev->mcu.timeout = 20 * HZ;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
|
||||
int cmd, int *wait_seq)
|
||||
@@ -255,7 +279,7 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
|
||||
u32 val;
|
||||
u8 seq;
|
||||
|
||||
mdev->mcu.timeout = 20 * HZ;
|
||||
mt7996_mcu_set_timeout(mdev, cmd);
|
||||
|
||||
seq = ++dev->mt76.mcu.msg_seq & 0xf;
|
||||
if (!seq)
|
||||
@@ -660,7 +684,7 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct mt7996_mcu_wed_rro_event *event = (void *)skb->data;
|
||||
|
||||
if (!dev->has_rro)
|
||||
if (!mt7996_has_hwrro(dev))
|
||||
return;
|
||||
|
||||
skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4);
|
||||
@@ -899,17 +923,28 @@ mt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en)
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink)
|
||||
mt7996_mcu_bss_mld_tlv(struct sk_buff *skb,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
struct mt7996_vif_link *link)
|
||||
{
|
||||
struct ieee80211_vif *vif = link_conf->vif;
|
||||
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
|
||||
struct bss_mld_tlv *mld;
|
||||
struct tlv *tlv;
|
||||
|
||||
tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld));
|
||||
|
||||
mld = (struct bss_mld_tlv *)tlv;
|
||||
mld->group_mld_id = 0xff;
|
||||
mld->own_mld_id = mlink->idx;
|
||||
mld->remap_idx = 0xff;
|
||||
mld->own_mld_id = link->mld_idx;
|
||||
mld->link_id = link_conf->link_id;
|
||||
|
||||
if (ieee80211_vif_is_mld(vif)) {
|
||||
mld->group_mld_id = mvif->mld_group_idx;
|
||||
mld->remap_idx = mvif->mld_remap_idx;
|
||||
memcpy(mld->mac_addr, vif->addr, ETH_ALEN);
|
||||
} else {
|
||||
mld->group_mld_id = 0xff;
|
||||
mld->remap_idx = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1108,6 +1143,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
|
||||
goto out;
|
||||
|
||||
if (enable) {
|
||||
struct mt7996_vif_link *link;
|
||||
|
||||
mt7996_mcu_bss_rfch_tlv(skb, phy);
|
||||
mt7996_mcu_bss_bmc_tlv(skb, mlink, phy);
|
||||
mt7996_mcu_bss_ra_tlv(skb, phy);
|
||||
@@ -1118,7 +1155,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
|
||||
mt7996_mcu_bss_he_tlv(skb, vif, link_conf, phy);
|
||||
|
||||
/* this tag is necessary no matter if the vif is MLD */
|
||||
mt7996_mcu_bss_mld_tlv(skb, mlink);
|
||||
link = container_of(mlink, struct mt7996_vif_link, mt76);
|
||||
mt7996_mcu_bss_mld_tlv(skb, link_conf, link);
|
||||
}
|
||||
|
||||
mt7996_mcu_bss_mbssid_tlv(skb, link_conf, enable);
|
||||
@@ -1149,9 +1187,8 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif,
|
||||
static int
|
||||
mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif,
|
||||
struct ieee80211_ampdu_params *params,
|
||||
bool enable, bool tx)
|
||||
struct mt76_wcid *wcid, bool enable, bool tx)
|
||||
{
|
||||
struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv;
|
||||
struct sta_rec_ba_uni *ba;
|
||||
struct sk_buff *skb;
|
||||
struct tlv *tlv;
|
||||
@@ -1170,7 +1207,7 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif,
|
||||
ba->ba_en = enable << params->tid;
|
||||
ba->amsdu = params->amsdu;
|
||||
ba->tid = params->tid;
|
||||
ba->ba_rdd_rro = !tx && enable && dev->has_rro;
|
||||
ba->ba_rdd_rro = !tx && enable && mt7996_has_hwrro(dev);
|
||||
|
||||
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
|
||||
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
|
||||
@@ -1179,20 +1216,67 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif,
|
||||
/** starec & wtbl **/
|
||||
int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
|
||||
struct ieee80211_ampdu_params *params,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link, bool enable)
|
||||
struct ieee80211_vif *vif, bool enable)
|
||||
{
|
||||
if (enable && !params->amsdu)
|
||||
msta_link->wcid.amsdu = false;
|
||||
struct ieee80211_sta *sta = params->sta;
|
||||
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
unsigned int link_id;
|
||||
int ret = 0;
|
||||
|
||||
return mt7996_mcu_sta_ba(dev, &link->mt76, params, enable, true);
|
||||
for_each_sta_active_link(vif, sta, link_sta, link_id) {
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
|
||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
||||
if (!msta_link)
|
||||
continue;
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
continue;
|
||||
|
||||
if (enable && !params->amsdu)
|
||||
msta_link->wcid.amsdu = false;
|
||||
|
||||
ret = mt7996_mcu_sta_ba(dev, &link->mt76, params,
|
||||
&msta_link->wcid, enable, true);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
|
||||
struct ieee80211_ampdu_params *params,
|
||||
struct mt7996_vif_link *link, bool enable)
|
||||
struct ieee80211_vif *vif, bool enable)
|
||||
{
|
||||
return mt7996_mcu_sta_ba(dev, &link->mt76, params, enable, false);
|
||||
struct ieee80211_sta *sta = params->sta;
|
||||
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
unsigned int link_id;
|
||||
int ret = 0;
|
||||
|
||||
for_each_sta_active_link(vif, sta, link_sta, link_id) {
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
|
||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
||||
if (!msta_link)
|
||||
continue;
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
continue;
|
||||
|
||||
ret = mt7996_mcu_sta_ba(dev, &link->mt76, params,
|
||||
&msta_link->wcid, enable, false);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1753,19 +1837,6 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
|
||||
bf->mem_20m = bf->nrow < BF_MAT_ORDER ?
|
||||
matrix[bf->nrow][bf->ncol] : 0;
|
||||
}
|
||||
|
||||
switch (link_sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
bf->mem_total = bf->mem_20m * 2;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
bf->mem_total = bf->mem_20m;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_20:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2265,13 +2336,10 @@ error_unlock:
|
||||
}
|
||||
|
||||
static int
|
||||
mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
mt7996_mcu_add_group(struct mt7996_dev *dev, struct mt7996_vif_link *link,
|
||||
struct mt76_wcid *wcid)
|
||||
{
|
||||
#define MT_STA_BSS_GROUP 1
|
||||
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_sta *msta;
|
||||
struct {
|
||||
u8 __rsv1[4];
|
||||
|
||||
@@ -2286,13 +2354,10 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||
.tag = cpu_to_le16(UNI_VOW_DRR_CTRL),
|
||||
.len = cpu_to_le16(sizeof(req) - 4),
|
||||
.action = cpu_to_le32(MT_STA_BSS_GROUP),
|
||||
.val = cpu_to_le32(mvif->deflink.mt76.idx % 16),
|
||||
.val = cpu_to_le32(link->mt76.idx % 16),
|
||||
.wlan_idx = cpu_to_le16(wcid->idx),
|
||||
};
|
||||
|
||||
msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL;
|
||||
msta_link = msta ? &msta->deflink : &mvif->deflink.msta_link;
|
||||
req.wlan_idx = cpu_to_le16(msta_link->wcid.idx);
|
||||
|
||||
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(VOW), &req,
|
||||
sizeof(req), true);
|
||||
}
|
||||
@@ -2432,7 +2497,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev,
|
||||
}
|
||||
}
|
||||
|
||||
ret = mt7996_mcu_add_group(dev, link_conf->vif, sta);
|
||||
ret = mt7996_mcu_add_group(dev, link, wcid);
|
||||
if (ret) {
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
@@ -2467,41 +2532,58 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
|
||||
enum set_key_cmd cmd)
|
||||
{
|
||||
struct sta_rec_sec_uni *sec;
|
||||
struct sec_key_uni *sec_key;
|
||||
struct tlv *tlv;
|
||||
u8 cipher;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));
|
||||
sec = (struct sta_rec_sec_uni *)tlv;
|
||||
sec->add = cmd;
|
||||
sec->add = 0;
|
||||
sec->n_cipher = 1;
|
||||
sec_key = &sec->key[0];
|
||||
sec_key->wlan_idx = cpu_to_le16(wcid->idx);
|
||||
sec_key->key_id = key->keyidx;
|
||||
|
||||
if (cmd == SET_KEY) {
|
||||
struct sec_key_uni *sec_key;
|
||||
u8 cipher;
|
||||
if (cmd != SET_KEY)
|
||||
return 0;
|
||||
|
||||
cipher = mt76_connac_mcu_get_cipher(key->cipher);
|
||||
if (cipher == MCU_CIPHER_NONE)
|
||||
return -EOPNOTSUPP;
|
||||
cipher = mt76_connac_mcu_get_cipher(key->cipher);
|
||||
if (cipher == MCU_CIPHER_NONE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sec_key = &sec->key[0];
|
||||
sec_key->wlan_idx = cpu_to_le16(wcid->idx);
|
||||
sec_key->mgmt_prot = 0;
|
||||
sec_key->cipher_id = cipher;
|
||||
sec_key->cipher_len = sizeof(*sec_key);
|
||||
sec_key->key_id = key->keyidx;
|
||||
sec_key->key_len = key->keylen;
|
||||
sec_key->need_resp = 0;
|
||||
memcpy(sec_key->key, key->key, key->keylen);
|
||||
sec_key->mgmt_prot = 0;
|
||||
sec_key->cipher_id = cipher;
|
||||
sec_key->cipher_len = sizeof(*sec_key);
|
||||
sec_key->key_len = key->keylen;
|
||||
sec_key->need_resp = 0;
|
||||
memcpy(sec_key->key, key->key, key->keylen);
|
||||
|
||||
if (cipher == MCU_CIPHER_TKIP) {
|
||||
/* Rx/Tx MIC keys are swapped */
|
||||
memcpy(sec_key->key + 16, key->key + 24, 8);
|
||||
memcpy(sec_key->key + 24, key->key + 16, 8);
|
||||
}
|
||||
|
||||
sec->n_cipher = 1;
|
||||
} else {
|
||||
sec->n_cipher = 0;
|
||||
if (cipher == MCU_CIPHER_TKIP) {
|
||||
/* Rx/Tx MIC keys are swapped */
|
||||
memcpy(sec_key->key + 16, key->key + 24, 8);
|
||||
memcpy(sec_key->key + 24, key->key + 16, 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sec_key->key_id != 6 && sec_key->key_id != 7)
|
||||
return 0;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
sec_key->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
sec_key->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
sec_key->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
sec_key->bcn_mode = BP_SW_MODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2519,99 +2601,12 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
|
||||
return PTR_ERR(skb);
|
||||
|
||||
ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
|
||||
}
|
||||
|
||||
static int mt7996_mcu_get_pn(struct mt7996_dev *dev,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link, u8 *pn)
|
||||
{
|
||||
#define TSC_TYPE_BIGTK_PN 2
|
||||
struct sta_rec_pn_info *pn_info;
|
||||
struct sk_buff *skb, *rskb;
|
||||
struct tlv *tlv;
|
||||
int ret;
|
||||
|
||||
skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
|
||||
&msta_link->wcid);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PN_INFO, sizeof(*pn_info));
|
||||
pn_info = (struct sta_rec_pn_info *)tlv;
|
||||
|
||||
pn_info->tsc_type = TSC_TYPE_BIGTK_PN;
|
||||
ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb,
|
||||
MCU_WM_UNI_CMD_QUERY(STA_REC_UPDATE),
|
||||
true, &rskb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
skb_pull(rskb, 4);
|
||||
|
||||
pn_info = (struct sta_rec_pn_info *)rskb->data;
|
||||
if (le16_to_cpu(pn_info->tag) == STA_REC_PN_INFO)
|
||||
memcpy(pn, pn_info->pn, 6);
|
||||
|
||||
dev_kfree_skb(rskb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mt7996_mcu_bcn_prot_tlv *bcn_prot;
|
||||
struct sk_buff *skb;
|
||||
struct tlv *tlv;
|
||||
u8 pn[6] = {};
|
||||
int len = sizeof(struct bss_req_hdr) +
|
||||
sizeof(struct mt7996_mcu_bcn_prot_tlv);
|
||||
int ret;
|
||||
|
||||
skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, len);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BCN_PROT, sizeof(*bcn_prot));
|
||||
|
||||
bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv;
|
||||
|
||||
ret = mt7996_mcu_get_pn(dev, link, msta_link, pn);
|
||||
if (ret) {
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
default:
|
||||
dev_err(dev->mt76.dev, "Not supported Bigtk Cipher\n");
|
||||
dev_kfree_skb(skb);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
pn[0]++;
|
||||
memcpy(bcn_prot->pn, pn, 6);
|
||||
bcn_prot->enable = BP_SW_MODE;
|
||||
memcpy(bcn_prot->key, key->key, WLAN_MAX_KEY_LEN);
|
||||
bcn_prot->key_id = key->keyidx;
|
||||
|
||||
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
|
||||
MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
|
||||
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
|
||||
}
|
||||
|
||||
int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
|
||||
@@ -2752,7 +2747,7 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev,
|
||||
}
|
||||
|
||||
int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf)
|
||||
struct ieee80211_bss_conf *link_conf, bool enabled)
|
||||
{
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf);
|
||||
@@ -2763,7 +2758,6 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct tlv *tlv;
|
||||
struct bss_bcn_content_tlv *bcn;
|
||||
int len, extra_len = 0;
|
||||
bool enabled = link_conf->enable_beacon;
|
||||
|
||||
if (link_conf->nontransmitted)
|
||||
return 0;
|
||||
|
||||
@@ -351,17 +351,6 @@ enum {
|
||||
BP_HW_MODE,
|
||||
};
|
||||
|
||||
struct mt7996_mcu_bcn_prot_tlv {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
u8 pn[6];
|
||||
u8 enable;
|
||||
u8 cipher_id;
|
||||
u8 key[WLAN_MAX_KEY_LEN];
|
||||
u8 key_id;
|
||||
u8 __rsv[3];
|
||||
} __packed;
|
||||
|
||||
struct bss_ra_tlv {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
@@ -481,7 +470,8 @@ struct bss_mld_tlv {
|
||||
u8 own_mld_id;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 remap_idx;
|
||||
u8 __rsv[3];
|
||||
u8 link_id;
|
||||
u8 __rsv[2];
|
||||
} __packed;
|
||||
|
||||
struct sta_rec_ht_uni {
|
||||
@@ -530,6 +520,9 @@ struct sec_key_uni {
|
||||
u8 key_len;
|
||||
u8 need_resp;
|
||||
u8 key[32];
|
||||
u8 pn[6];
|
||||
u8 bcn_mode;
|
||||
u8 _rsv;
|
||||
} __packed;
|
||||
|
||||
struct sta_rec_sec_uni {
|
||||
|
||||
@@ -459,14 +459,15 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
|
||||
struct pci_dev *pci_dev = pdev_ptr;
|
||||
u32 hif1_ofs = 0;
|
||||
u32 hif1_ofs;
|
||||
|
||||
if (!wed_enable)
|
||||
return 0;
|
||||
|
||||
dev->has_rro = true;
|
||||
dev->mt76.hwrro_mode = is_mt7996(&dev->mt76) ? MT76_HWRRO_V3
|
||||
: MT76_HWRRO_V3_1;
|
||||
|
||||
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
|
||||
hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
|
||||
|
||||
if (hif2)
|
||||
wed = &dev->mt76.mmio.wed_hif2;
|
||||
@@ -490,11 +491,18 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_TXQ_RING_BASE(0) +
|
||||
MT7996_TXQ_BAND2 * MT_RING_SIZE;
|
||||
if (dev->has_rro) {
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
|
||||
if (mt7996_has_hwrro(dev)) {
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
|
||||
} else {
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_BAND1_EXT) - 1;
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_MCU_WA_EXT * MT_RING_SIZE;
|
||||
}
|
||||
} else {
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(0) +
|
||||
@@ -504,13 +512,13 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
|
||||
wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG;
|
||||
wed->wlan.wpdma_rx[0] = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) +
|
||||
MT7996_RXQ_BAND0 * MT_RING_SIZE;
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_BAND2) +
|
||||
MT7996_RXQ_BAND2 * MT_RING_SIZE;
|
||||
|
||||
wed->wlan.id = MT7996_DEVICE_ID_2;
|
||||
wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1;
|
||||
} else {
|
||||
wed->wlan.hw_rro = dev->has_rro; /* default on */
|
||||
wed->wlan.hw_rro = mt7996_has_hwrro(dev);
|
||||
wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR;
|
||||
wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR;
|
||||
wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) +
|
||||
@@ -525,9 +533,19 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) +
|
||||
MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE;
|
||||
wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) +
|
||||
MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE;
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) +
|
||||
MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE;
|
||||
} else {
|
||||
wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND1) +
|
||||
MT7996_RXQ_RRO_BAND1 * MT_RING_SIZE;
|
||||
wed->wlan.wpdma_rx[1] = wed->wlan.phy_base + hif1_ofs +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_BAND1) +
|
||||
MT7996_RXQ_BAND1 * MT_RING_SIZE;
|
||||
}
|
||||
|
||||
wed->wlan.wpdma_rx_pg = wed->wlan.phy_base +
|
||||
MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) +
|
||||
MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE;
|
||||
@@ -537,10 +555,14 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE);
|
||||
|
||||
wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1;
|
||||
wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1;
|
||||
|
||||
wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1;
|
||||
wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1;
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1;
|
||||
wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1;
|
||||
} else {
|
||||
wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND1) - 1;
|
||||
wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND1) - 1;
|
||||
}
|
||||
|
||||
wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1;
|
||||
wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1;
|
||||
@@ -548,16 +570,27 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
|
||||
wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1;
|
||||
wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1;
|
||||
if (dev->has_rro) {
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_TXFREE0 * MT_RING_SIZE;
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1;
|
||||
if (is_mt7996(&dev->mt76)) {
|
||||
if (mt7996_has_hwrro(dev)) {
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base +
|
||||
MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_TXFREE0 * MT_RING_SIZE;
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1;
|
||||
} else {
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base +
|
||||
MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1;
|
||||
}
|
||||
} else {
|
||||
wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1;
|
||||
wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
|
||||
MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
|
||||
}
|
||||
dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt;
|
||||
|
||||
if (dev->hif2 && is_mt7992(&dev->mt76))
|
||||
wed->wlan.id = 0x7992;
|
||||
}
|
||||
|
||||
wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE;
|
||||
@@ -576,8 +609,10 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
|
||||
wed->wlan.reset_complete = mt76_wed_reset_complete;
|
||||
}
|
||||
|
||||
if (mtk_wed_device_attach(wed))
|
||||
if (mtk_wed_device_attach(wed)) {
|
||||
dev->mt76.hwrro_mode = MT76_HWRRO_OFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*irq = wed->irq;
|
||||
dev->mt76.dma_dev = wed->dev;
|
||||
@@ -690,12 +725,18 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
|
||||
dev->mt76.mmio.irqmask);
|
||||
if (intr1 & MT_INT_RX_TXFREE_EXT)
|
||||
napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]);
|
||||
|
||||
if (intr1 & MT_INT_RX_DONE_BAND2_EXT)
|
||||
napi_schedule(&dev->mt76.napi[MT_RXQ_BAND2]);
|
||||
|
||||
if (intr1 & MT_INT_RX_TXFREE_BAND1_EXT)
|
||||
napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1_WA]);
|
||||
}
|
||||
|
||||
if (mtk_wed_device_active(wed)) {
|
||||
mtk_wed_device_irq_set_mask(wed, 0);
|
||||
intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask);
|
||||
intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT);
|
||||
intr |= (intr1 & ~MT_INT_TX_RX_DONE_EXT);
|
||||
} else {
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
if (dev->hif2)
|
||||
@@ -781,6 +822,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
|
||||
.rx_skb = mt7996_queue_rx_skb,
|
||||
.rx_check = mt7996_rx_check,
|
||||
.rx_poll_complete = mt7996_rx_poll_complete,
|
||||
.rx_rro_ind_process = mt7996_rro_rx_process,
|
||||
.rx_rro_add_msdu_page = mt7996_rro_msdu_page_add,
|
||||
.update_survey = mt7996_update_channel,
|
||||
.set_channel = mt7996_set_channel,
|
||||
.vif_link_add = mt7996_vif_link_add,
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
#define MT7996_CRIT_TEMP 110
|
||||
#define MT7996_MAX_TEMP 120
|
||||
|
||||
#define MT7996_MAX_HIF_RXD_IN_PG 5
|
||||
#define MT7996_RRO_MSDU_PG_HASH_SIZE 127
|
||||
#define MT7996_RRO_MAX_SESSION 1024
|
||||
#define MT7996_RRO_WINDOW_MAX_LEN 1024
|
||||
#define MT7996_RRO_ADDR_ELEM_LEN 128
|
||||
@@ -128,6 +130,10 @@
|
||||
#define MT7996_RX_MSDU_PAGE_SIZE (128 + \
|
||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
|
||||
/* RRO 3.1 */
|
||||
#define MT7996_RRO_MSDU_PG_CR_CNT 8
|
||||
#define MT7996_RRO_MSDU_PG_SIZE_PER_CR 0x10000
|
||||
|
||||
struct mt7996_vif;
|
||||
struct mt7996_sta;
|
||||
struct mt7996_dfs_pulse;
|
||||
@@ -178,7 +184,7 @@ enum mt7996_rxq_id {
|
||||
MT7996_RXQ_BAND1 = 5, /* for mt7992 */
|
||||
MT7996_RXQ_BAND2 = 5,
|
||||
MT7996_RXQ_RRO_BAND0 = 8,
|
||||
MT7996_RXQ_RRO_BAND1 = 8,/* unused */
|
||||
MT7996_RXQ_RRO_BAND1 = 9,
|
||||
MT7996_RXQ_RRO_BAND2 = 6,
|
||||
MT7996_RXQ_MSDU_PG_BAND0 = 10,
|
||||
MT7996_RXQ_MSDU_PG_BAND1 = 11,
|
||||
@@ -187,6 +193,7 @@ enum mt7996_rxq_id {
|
||||
MT7996_RXQ_TXFREE1 = 9,
|
||||
MT7996_RXQ_TXFREE2 = 7,
|
||||
MT7996_RXQ_RRO_IND = 0,
|
||||
MT7996_RXQ_RRO_RXDMAD_C = 0,
|
||||
MT7990_RXQ_TXFREE0 = 6,
|
||||
MT7990_RXQ_TXFREE1 = 7,
|
||||
};
|
||||
@@ -248,11 +255,16 @@ struct mt7996_vif_link {
|
||||
|
||||
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
|
||||
struct cfg80211_bitrate_mask bitrate_mask;
|
||||
|
||||
u8 mld_idx;
|
||||
};
|
||||
|
||||
struct mt7996_vif {
|
||||
struct mt7996_vif_link deflink; /* must be first */
|
||||
struct mt76_vif_data mt76;
|
||||
|
||||
u8 mld_group_idx;
|
||||
u8 mld_remap_idx;
|
||||
};
|
||||
|
||||
/* crash-dump */
|
||||
@@ -270,15 +282,17 @@ struct mt7996_hif {
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
int irq;
|
||||
|
||||
enum pci_bus_speed speed;
|
||||
enum pcie_link_width width;
|
||||
};
|
||||
|
||||
#define WED_RRO_ADDR_SIGNATURE_MASK GENMASK(31, 24)
|
||||
#define WED_RRO_ADDR_COUNT_MASK GENMASK(14, 4)
|
||||
#define WED_RRO_ADDR_HEAD_HIGH_MASK GENMASK(3, 0)
|
||||
struct mt7996_wed_rro_addr {
|
||||
u32 head_low;
|
||||
u32 head_high : 4;
|
||||
u32 count: 11;
|
||||
u32 oor: 1;
|
||||
u32 rsv : 8;
|
||||
u32 signature : 8;
|
||||
__le32 head_low;
|
||||
__le32 data;
|
||||
};
|
||||
|
||||
struct mt7996_wed_rro_session_id {
|
||||
@@ -286,6 +300,44 @@ struct mt7996_wed_rro_session_id {
|
||||
u16 id;
|
||||
};
|
||||
|
||||
struct mt7996_msdu_page {
|
||||
struct list_head list;
|
||||
|
||||
struct mt76_queue *q;
|
||||
dma_addr_t dma_addr;
|
||||
void *buf;
|
||||
};
|
||||
|
||||
/* data1 */
|
||||
#define RRO_HIF_DATA1_LS_MASK BIT(30)
|
||||
#define RRO_HIF_DATA1_SDL_MASK GENMASK(29, 16)
|
||||
/* data4 */
|
||||
#define RRO_HIF_DATA4_RX_TOKEN_ID_MASK GENMASK(15, 0)
|
||||
struct mt7996_rro_hif {
|
||||
__le32 data0;
|
||||
__le32 data1;
|
||||
__le32 data2;
|
||||
__le32 data3;
|
||||
__le32 data4;
|
||||
__le32 data5;
|
||||
};
|
||||
|
||||
#define MSDU_PAGE_INFO_OWNER_MASK BIT(31)
|
||||
#define MSDU_PAGE_INFO_PG_HIGH_MASK GENMASK(3, 0)
|
||||
struct mt7996_msdu_page_info {
|
||||
struct mt7996_rro_hif rxd[MT7996_MAX_HIF_RXD_IN_PG];
|
||||
__le32 pg_low;
|
||||
__le32 data;
|
||||
};
|
||||
|
||||
#define MT7996_MAX_RRO_RRS_RING 4
|
||||
struct mt7996_rro_queue_regs_emi {
|
||||
struct {
|
||||
__le16 idx;
|
||||
__le16 rsv;
|
||||
} ring[MT7996_MAX_RRO_RRS_RING];
|
||||
};
|
||||
|
||||
struct mt7996_phy {
|
||||
struct mt76_phy *mt76;
|
||||
struct mt7996_dev *dev;
|
||||
@@ -337,6 +389,9 @@ struct mt7996_dev {
|
||||
u32 q_int_mask[MT7996_MAX_QUEUE];
|
||||
u32 q_wfdma_mask;
|
||||
|
||||
u64 mld_idx_mask;
|
||||
u64 mld_remap_idx_mask;
|
||||
|
||||
const struct mt76_bus_ops *bus_ops;
|
||||
struct mt7996_phy phy;
|
||||
|
||||
@@ -377,7 +432,6 @@ struct mt7996_dev {
|
||||
|
||||
bool flash_mode:1;
|
||||
bool has_eht:1;
|
||||
bool has_rro:1;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
@@ -392,10 +446,25 @@ struct mt7996_dev {
|
||||
void *ptr;
|
||||
dma_addr_t phy_addr;
|
||||
} session;
|
||||
struct {
|
||||
void *ptr;
|
||||
dma_addr_t phy_addr;
|
||||
} msdu_pg[MT7996_RRO_MSDU_PG_CR_CNT];
|
||||
struct {
|
||||
struct mt7996_rro_queue_regs_emi *ptr;
|
||||
dma_addr_t phy_addr;
|
||||
} emi_rings_cpu;
|
||||
struct {
|
||||
struct mt7996_rro_queue_regs_emi *ptr;
|
||||
dma_addr_t phy_addr;
|
||||
} emi_rings_dma;
|
||||
|
||||
struct work_struct work;
|
||||
struct list_head poll_list;
|
||||
spinlock_t lock;
|
||||
|
||||
struct list_head page_cache;
|
||||
struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE];
|
||||
} wed_rro;
|
||||
|
||||
bool ibf;
|
||||
@@ -552,6 +621,7 @@ extern struct pci_driver mt7996_hif_driver;
|
||||
|
||||
struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
|
||||
void __iomem *mem_base, u32 device_id);
|
||||
void mt7996_rro_hw_init(struct mt7996_dev *dev);
|
||||
void mt7996_wfsys_reset(struct mt7996_dev *dev);
|
||||
irqreturn_t mt7996_irq_handler(int irq, void *dev_instance);
|
||||
u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link);
|
||||
@@ -604,16 +674,15 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
|
||||
struct mt7996_sta_link *msta_link);
|
||||
int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
|
||||
struct ieee80211_ampdu_params *params,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link, bool enable);
|
||||
struct ieee80211_vif *vif, bool enable);
|
||||
int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
|
||||
struct ieee80211_ampdu_params *params,
|
||||
struct mt7996_vif_link *link, bool enable);
|
||||
struct ieee80211_vif *vif, bool enable);
|
||||
int mt7996_mcu_update_bss_color(struct mt7996_dev *dev,
|
||||
struct mt76_vif_link *mlink,
|
||||
struct cfg80211_he_bss_color *he_bss_color);
|
||||
int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf);
|
||||
struct ieee80211_bss_conf *link_conf, bool enabled);
|
||||
int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
struct mt7996_vif_link *link, u32 changed);
|
||||
@@ -669,6 +738,11 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
|
||||
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
|
||||
int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled);
|
||||
|
||||
static inline bool mt7996_has_hwrro(struct mt7996_dev *dev)
|
||||
{
|
||||
return dev->mt76.hwrro_mode != MT76_HWRRO_OFF;
|
||||
}
|
||||
|
||||
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
|
||||
{
|
||||
return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) +
|
||||
@@ -743,6 +817,8 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link,
|
||||
u8 flowid);
|
||||
void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
|
||||
struct mt7996_sta_link *msta_link);
|
||||
void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_twt_setup *twt);
|
||||
@@ -753,6 +829,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
void mt7996_tx_token_put(struct mt7996_dev *dev);
|
||||
void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb, u32 *info);
|
||||
void mt7996_rro_msdu_page_map_free(struct mt7996_dev *dev);
|
||||
int mt7996_rro_msdu_page_add(struct mt76_dev *mdev, struct mt76_queue *q,
|
||||
dma_addr_t dma_addr, void *data);
|
||||
void mt7996_rro_rx_process(struct mt76_dev *mdev, void *data);
|
||||
bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
|
||||
void mt7996_stats_work(struct work_struct *work);
|
||||
int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
|
||||
@@ -787,8 +867,6 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
|
||||
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
int mt7996_dma_rro_init(struct mt7996_dev *dev);
|
||||
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -87,6 +87,7 @@ static int mt7996_pci_hif2_probe(struct pci_dev *pdev)
|
||||
hif->dev = &pdev->dev;
|
||||
hif->regs = pcim_iomap_table(pdev)[0];
|
||||
hif->irq = pdev->irq;
|
||||
pcie_bandwidth_available(pdev, NULL, &hif->speed, &hif->width);
|
||||
spin_lock_bh(&hif_lock);
|
||||
list_add(&hif->list, &hif_list);
|
||||
spin_unlock_bh(&hif_lock);
|
||||
@@ -137,6 +138,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
|
||||
mdev = &dev->mt76;
|
||||
mt7996_wfsys_reset(dev);
|
||||
hif2 = mt7996_pci_init_hif2(pdev);
|
||||
dev->hif2 = hif2;
|
||||
|
||||
ret = mt7996_mmio_wed_init(dev, pdev, false, &irq);
|
||||
if (ret < 0)
|
||||
@@ -161,7 +163,6 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
|
||||
|
||||
if (hif2) {
|
||||
hif2_dev = container_of(hif2->dev, struct pci_dev, dev);
|
||||
dev->hif2 = hif2;
|
||||
|
||||
ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -88,6 +88,8 @@ enum offs_rev {
|
||||
#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC)
|
||||
#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8)
|
||||
#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12)
|
||||
|
||||
#define MT_RRO_ADDR_ARRAY_BASE0 MT_RRO_TOP(0x30)
|
||||
#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34)
|
||||
#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31)
|
||||
|
||||
@@ -108,6 +110,19 @@ enum offs_rev {
|
||||
|
||||
#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400)
|
||||
|
||||
#define MT_RRO_3_0_EMU_CONF MT_RRO_TOP(0x600)
|
||||
#define MT_RRO_3_0_EMU_CONF_EN_MASK BIT(11)
|
||||
|
||||
#define MT_RRO_3_1_GLOBAL_CONFIG MT_RRO_TOP(0x604)
|
||||
#define MT_RRO_3_1_GLOBAL_CONFIG_RXDMAD_SEL BIT(6)
|
||||
#define MT_RRO_3_1_GLOBAL_CONFIG_RX_CIDX_RD_EN BIT(3)
|
||||
#define MT_RRO_3_1_GLOBAL_CONFIG_RX_DIDX_WR_EN BIT(2)
|
||||
#define MT_RRO_3_1_GLOBAL_CONFIG_INTERLEAVE_EN BIT(0)
|
||||
|
||||
#define MT_RRO_MSDU_PG_SEG_ADDR0 MT_RRO_TOP(0x620)
|
||||
#define MT_RRO_RX_RING_AP_CIDX_ADDR MT_RRO_TOP(0x6f0)
|
||||
#define MT_RRO_RX_RING_AP_DIDX_ADDR MT_RRO_TOP(0x6f4)
|
||||
|
||||
#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50)
|
||||
#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16)
|
||||
#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0)
|
||||
@@ -412,7 +427,9 @@ enum offs_rev {
|
||||
|
||||
#define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154)
|
||||
#define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3)
|
||||
#define MT_WFDMA0_RX_INT_SEL_RING5 BIT(5)
|
||||
#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6)
|
||||
#define MT_WFDMA0_RX_INT_SEL_RING9 BIT(9)
|
||||
|
||||
#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
|
||||
|
||||
@@ -430,6 +447,7 @@ enum offs_rev {
|
||||
#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c)
|
||||
|
||||
#define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0)
|
||||
#define WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK GENMASK(27, 24)
|
||||
#define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18)
|
||||
#define WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE BIT(14)
|
||||
|
||||
@@ -451,6 +469,8 @@ enum offs_rev {
|
||||
|
||||
#define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30)
|
||||
#define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0)
|
||||
#define MT_WFDMA_HOST_CONFIG_BAND0_PCIE1 BIT(20)
|
||||
#define MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 BIT(21)
|
||||
#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22)
|
||||
|
||||
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
|
||||
@@ -459,6 +479,9 @@ enum offs_rev {
|
||||
#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500)
|
||||
#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0)
|
||||
|
||||
#define MT_WFDMA_AXI_R2A_CTRL2 MT_WFDMA_EXT_CSR(0x508)
|
||||
#define MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK GENMASK(31, 28)
|
||||
|
||||
#define MT_PCIE_RECOG_ID 0xd7090
|
||||
#define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0)
|
||||
#define MT_PCIE_RECOG_ID_SEM BIT(31)
|
||||
@@ -492,6 +515,8 @@ enum offs_rev {
|
||||
#define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500)
|
||||
#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40)
|
||||
|
||||
#define MT_RXQ_RRO_AP_RING_BASE MT_RRO_TOP(0x650)
|
||||
|
||||
#define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \
|
||||
MT_MCUQ_ID(q) * 0x4)
|
||||
#define MT_RXQ_EXT_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \
|
||||
@@ -514,7 +539,9 @@ enum offs_rev {
|
||||
#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */
|
||||
#define MT_INT_RX_DONE_WA_TRI BIT(3)
|
||||
#define MT_INT_RX_TXFREE_MAIN BIT(17)
|
||||
#define MT_INT_RX_TXFREE_BAND1 BIT(15)
|
||||
#define MT_INT_RX_TXFREE_TRI BIT(15)
|
||||
#define MT_INT_RX_TXFREE_BAND1_EXT BIT(19) /* for mt7992 two PCIE*/
|
||||
#define MT_INT_RX_TXFREE_BAND0_MT7990 BIT(14)
|
||||
#define MT_INT_RX_TXFREE_BAND1_MT7990 BIT(15)
|
||||
#define MT_INT_RX_DONE_BAND2_EXT BIT(23)
|
||||
@@ -522,9 +549,10 @@ enum offs_rev {
|
||||
#define MT_INT_MCU_CMD BIT(29)
|
||||
|
||||
#define MT_INT_RX_DONE_RRO_BAND0 BIT(16)
|
||||
#define MT_INT_RX_DONE_RRO_BAND1 BIT(16)
|
||||
#define MT_INT_RX_DONE_RRO_BAND1 BIT(17)
|
||||
#define MT_INT_RX_DONE_RRO_BAND2 BIT(14)
|
||||
#define MT_INT_RX_DONE_RRO_IND BIT(11)
|
||||
#define MT_INT_RX_DONE_RRO_RXDMAD_C BIT(11)
|
||||
#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18)
|
||||
#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19)
|
||||
#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23)
|
||||
@@ -552,6 +580,8 @@ enum offs_rev {
|
||||
#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \
|
||||
MT_INT_RX(MT_RXQ_RRO_BAND1) | \
|
||||
MT_INT_RX(MT_RXQ_RRO_BAND2) | \
|
||||
MT_INT_RX(MT_RXQ_RRO_IND) | \
|
||||
MT_INT_RX(MT_RXQ_RRO_RXDMAD_C) | \
|
||||
MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \
|
||||
MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \
|
||||
MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2))
|
||||
|
||||
@@ -16,11 +16,13 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
|
||||
|
||||
clear_bit(MT76_SCANNING, &phy->state);
|
||||
|
||||
if (dev->scan.chan && phy->main_chandef.chan)
|
||||
if (dev->scan.chan && phy->main_chandef.chan &&
|
||||
!test_bit(MT76_MCU_RESET, &dev->phy.state))
|
||||
mt76_set_channel(phy, &phy->main_chandef, false);
|
||||
mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
|
||||
memset(&dev->scan, 0, sizeof(dev->scan));
|
||||
ieee80211_scan_completed(phy->hw, &info);
|
||||
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
|
||||
ieee80211_scan_completed(phy->hw, &info);
|
||||
}
|
||||
|
||||
void mt76_abort_scan(struct mt76_dev *dev)
|
||||
@@ -28,6 +30,7 @@ void mt76_abort_scan(struct mt76_dev *dev)
|
||||
cancel_delayed_work_sync(&dev->scan_work);
|
||||
mt76_scan_complete(dev, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_abort_scan);
|
||||
|
||||
static void
|
||||
mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
|
||||
@@ -112,9 +115,6 @@ void mt76_scan_work(struct work_struct *work)
|
||||
local_bh_enable();
|
||||
|
||||
out:
|
||||
if (!duration)
|
||||
return;
|
||||
|
||||
if (dev->scan.chan)
|
||||
duration = max_t(int, duration,
|
||||
msecs_to_jiffies(req->duration +
|
||||
@@ -139,7 +139,8 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
if (dev->scan.req || phy->roc_vif) {
|
||||
if (dev->scan.req || phy->roc_vif ||
|
||||
test_bit(MT76_MCU_RESET, &dev->phy.state)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -618,7 +618,8 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
|
||||
!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
|
||||
!ieee80211_is_data(hdr->frame_control) &&
|
||||
(!ieee80211_is_bufferable_mmpdu(skb) ||
|
||||
ieee80211_is_deauth(hdr->frame_control)))
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
head == &wcid->tx_offchannel))
|
||||
qid = MT_TXQ_PSD;
|
||||
|
||||
q = phy->q_tx[qid];
|
||||
|
||||
@@ -118,7 +118,7 @@ int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
|
||||
case MT76_WED_Q_TXFREE:
|
||||
/* WED txfree queue needs ring to be initialized before setup */
|
||||
q->flags = 0;
|
||||
mt76_dma_queue_reset(dev, q);
|
||||
mt76_dma_queue_reset(dev, q, true);
|
||||
mt76_dma_rx_fill(dev, q, false);
|
||||
|
||||
ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs);
|
||||
@@ -133,21 +133,21 @@ int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
|
||||
break;
|
||||
case MT76_WED_RRO_Q_DATA:
|
||||
q->flags &= ~MT_QFLAG_WED;
|
||||
__mt76_dma_queue_reset(dev, q, false);
|
||||
mt76_dma_queue_reset(dev, q, false);
|
||||
mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs);
|
||||
q->head = q->ndesc - 1;
|
||||
q->queued = q->head;
|
||||
break;
|
||||
case MT76_WED_RRO_Q_MSDU_PG:
|
||||
q->flags &= ~MT_QFLAG_WED;
|
||||
__mt76_dma_queue_reset(dev, q, false);
|
||||
mt76_dma_queue_reset(dev, q, false);
|
||||
mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs);
|
||||
q->head = q->ndesc - 1;
|
||||
q->queued = q->head;
|
||||
break;
|
||||
case MT76_WED_RRO_Q_IND:
|
||||
q->flags &= ~MT_QFLAG_WED;
|
||||
mt76_dma_queue_reset(dev, q);
|
||||
mt76_dma_queue_reset(dev, q, true);
|
||||
mt76_dma_rx_fill(dev, q, false);
|
||||
mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs);
|
||||
break;
|
||||
|
||||
@@ -1901,6 +1901,27 @@ static void rtl8xxxu_dump_efuse(struct rtl8xxxu_priv *priv)
|
||||
priv->efuse_wifi.raw, EFUSE_MAP_LEN, true);
|
||||
}
|
||||
|
||||
static ssize_t read_file_efuse(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct rtl8xxxu_priv *priv = file_inode(file)->i_private;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
priv->efuse_wifi.raw, EFUSE_MAP_LEN);
|
||||
}
|
||||
|
||||
static const struct debugfs_short_fops fops_efuse = {
|
||||
.read = read_file_efuse,
|
||||
};
|
||||
|
||||
static void rtl8xxxu_debugfs_init(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
struct dentry *phydir;
|
||||
|
||||
phydir = debugfs_create_dir("rtl8xxxu", priv->hw->wiphy->debugfsdir);
|
||||
debugfs_create_file("efuse", 0400, phydir, priv, &fops_efuse);
|
||||
}
|
||||
|
||||
void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
u8 val8;
|
||||
@@ -7815,7 +7836,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
|
||||
untested = 0;
|
||||
break;
|
||||
case 0x2357:
|
||||
if (id->idProduct == 0x0109 || id->idProduct == 0x0135)
|
||||
if (id->idProduct == 0x0109 || id->idProduct == 0x010c ||
|
||||
id->idProduct == 0x0135)
|
||||
untested = 0;
|
||||
break;
|
||||
case 0x0b05:
|
||||
@@ -7974,6 +7996,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
|
||||
}
|
||||
|
||||
rtl8xxxu_init_led(priv);
|
||||
rtl8xxxu_debugfs_init(priv);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -8172,8 +8195,6 @@ static const struct usb_device_id dev_table[] = {
|
||||
.driver_info = (unsigned long)&rtl8192cu_fops},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff),
|
||||
.driver_info = (unsigned long)&rtl8192cu_fops},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8188, 0xff, 0xff, 0xff),
|
||||
.driver_info = (unsigned long)&rtl8192cu_fops},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff),
|
||||
.driver_info = (unsigned long)&rtl8192cu_fops},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff),
|
||||
|
||||
@@ -291,7 +291,6 @@ static const struct usb_device_id rtl8192c_usb_ids[] = {
|
||||
{RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/
|
||||
{RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/
|
||||
{RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/
|
||||
{RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
|
||||
{RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
|
||||
{RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
|
||||
{RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/
|
||||
|
||||
@@ -6,13 +6,17 @@
|
||||
#include "debug.h"
|
||||
#include "led.h"
|
||||
|
||||
static int rtw_led_set_blocking(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
static int rtw_led_set(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct rtw_dev *rtwdev = container_of(led, struct rtw_dev, led_cdev);
|
||||
|
||||
mutex_lock(&rtwdev->mutex);
|
||||
|
||||
rtwdev->chip->ops->led_set(led, brightness);
|
||||
|
||||
mutex_unlock(&rtwdev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,10 +40,7 @@ void rtw_led_init(struct rtw_dev *rtwdev)
|
||||
if (!rtwdev->chip->ops->led_set)
|
||||
return;
|
||||
|
||||
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE)
|
||||
led->brightness_set = rtwdev->chip->ops->led_set;
|
||||
else
|
||||
led->brightness_set_blocking = rtw_led_set_blocking;
|
||||
led->brightness_set_blocking = rtw_led_set;
|
||||
|
||||
snprintf(rtwdev->led_name, sizeof(rtwdev->led_name),
|
||||
"rtw88-%s", dev_name(rtwdev->dev));
|
||||
|
||||
@@ -144,6 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr,
|
||||
|
||||
static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr)
|
||||
{
|
||||
if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) &&
|
||||
!rtw_sdio_is_bus_addr(addr))
|
||||
return false;
|
||||
|
||||
return !rtw_sdio_is_sdio30_supported(rtwdev) ||
|
||||
rtw_sdio_is_bus_addr(addr);
|
||||
}
|
||||
|
||||
@@ -281,6 +281,7 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_hal *hal = &rtwdev->hal;
|
||||
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
|
||||
int i, j;
|
||||
|
||||
hal->entity_pause = false;
|
||||
bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX);
|
||||
@@ -289,6 +290,11 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev)
|
||||
|
||||
INIT_LIST_HEAD(&mgnt->active_list);
|
||||
|
||||
for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) {
|
||||
for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++)
|
||||
mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE;
|
||||
}
|
||||
|
||||
rtw89_config_default_chandef(rtwdev);
|
||||
}
|
||||
|
||||
@@ -353,7 +359,7 @@ static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev,
|
||||
|
||||
const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
|
||||
const char *caller_message,
|
||||
u8 link_index)
|
||||
u8 link_index, bool nullchk)
|
||||
{
|
||||
struct rtw89_hal *hal = &rtwdev->hal;
|
||||
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
|
||||
@@ -400,6 +406,9 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
|
||||
return rtw89_chan_get(rtwdev, chanctx_idx);
|
||||
|
||||
dflt:
|
||||
if (unlikely(nullchk))
|
||||
return NULL;
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
|
||||
"%s (%s): prefetch NULL on link index %u\n",
|
||||
__func__, caller_message ?: "", link_index);
|
||||
|
||||
@@ -180,10 +180,16 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev,
|
||||
|
||||
const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
|
||||
const char *caller_message,
|
||||
u8 link_index);
|
||||
u8 link_index, bool nullchk);
|
||||
|
||||
#define rtw89_mgnt_chan_get(rtwdev, link_index) \
|
||||
__rtw89_mgnt_chan_get(rtwdev, __func__, link_index)
|
||||
__rtw89_mgnt_chan_get(rtwdev, __func__, link_index, false)
|
||||
|
||||
static inline const struct rtw89_chan *
|
||||
rtw89_mgnt_chan_get_or_null(struct rtw89_dev *rtwdev, u8 link_index)
|
||||
{
|
||||
return __rtw89_mgnt_chan_get(rtwdev, NULL, link_index, true);
|
||||
}
|
||||
|
||||
struct rtw89_mcc_links_info {
|
||||
struct rtw89_vif_link *links[NUM_OF_RTW89_MCC_ROLES];
|
||||
|
||||
@@ -93,7 +93,7 @@ static const struct rtw89_btc_fbtc_slot s_def[] = {
|
||||
[CXST_E2G] = __DEF_FBTC_SLOT(5, 0xea5a5a5a, SLOT_MIX),
|
||||
[CXST_E5G] = __DEF_FBTC_SLOT(5, 0xffffffff, SLOT_ISO),
|
||||
[CXST_EBT] = __DEF_FBTC_SLOT(5, 0xe5555555, SLOT_MIX),
|
||||
[CXST_ENULL] = __DEF_FBTC_SLOT(5, 0xaaaaaaaa, SLOT_ISO),
|
||||
[CXST_ENULL] = __DEF_FBTC_SLOT(5, 0x55555555, SLOT_MIX),
|
||||
[CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX),
|
||||
[CXST_W1FDD] = __DEF_FBTC_SLOT(50, 0xffffffff, SLOT_ISO),
|
||||
[CXST_B1FDD] = __DEF_FBTC_SLOT(50, 0xffffdfff, SLOT_ISO),
|
||||
@@ -4153,6 +4153,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
|
||||
s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
|
||||
_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
|
||||
s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
|
||||
_slot_set_dur(btc, CXST_EBT, dur_2);
|
||||
break;
|
||||
case BTC_CXP_OFFE_DEF2:
|
||||
_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
|
||||
@@ -4162,6 +4163,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
|
||||
s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
|
||||
_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
|
||||
s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
|
||||
_slot_set_dur(btc, CXST_EBT, dur_2);
|
||||
break;
|
||||
case BTC_CXP_OFFE_2GBWMIXB:
|
||||
if (a2dp->exist)
|
||||
@@ -4170,6 +4172,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
|
||||
_slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_MIX);
|
||||
_slot_set_le(btc, CXST_EBT, cpu_to_le16(40),
|
||||
s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
|
||||
_slot_set_dur(btc, CXST_EBT, dur_2);
|
||||
break;
|
||||
case BTC_CXP_OFFE_WL: /* for 4-way */
|
||||
_slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_MIX);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/* Copyright(c) 2019-2020 Realtek Corporation
|
||||
*/
|
||||
#include <linux/ip.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include "cam.h"
|
||||
@@ -272,17 +273,18 @@ rtw89_get_6ghz_span(struct rtw89_dev *rtwdev, u32 center_freq)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate)
|
||||
bool rtw89_legacy_rate_to_bitrate(struct rtw89_dev *rtwdev, u8 legacy_rate, u16 *bitrate)
|
||||
{
|
||||
struct ieee80211_rate rate;
|
||||
const struct ieee80211_rate *rate;
|
||||
|
||||
if (unlikely(rpt_rate >= ARRAY_SIZE(rtw89_bitrates))) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rpt rate %d\n", rpt_rate);
|
||||
if (unlikely(legacy_rate >= ARRAY_SIZE(rtw89_bitrates))) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
|
||||
"invalid legacy rate %d\n", legacy_rate);
|
||||
return false;
|
||||
}
|
||||
|
||||
rate = rtw89_bitrates[rpt_rate];
|
||||
*bitrate = rate.bitrate;
|
||||
rate = &rtw89_bitrates[legacy_rate];
|
||||
*bitrate = rate->bitrate;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -697,6 +699,66 @@ static void rtw89_core_tx_update_llc_hdr(struct rtw89_dev *rtwdev,
|
||||
desc_info->hdr_llc_len >>= 1; /* in unit of 2 bytes */
|
||||
}
|
||||
|
||||
u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel)
|
||||
{
|
||||
switch (qsel) {
|
||||
default:
|
||||
rtw89_warn(rtwdev, "Cannot map qsel to dma: %d\n", qsel);
|
||||
fallthrough;
|
||||
case RTW89_TX_QSEL_BE_0:
|
||||
case RTW89_TX_QSEL_BE_1:
|
||||
case RTW89_TX_QSEL_BE_2:
|
||||
case RTW89_TX_QSEL_BE_3:
|
||||
return RTW89_TXCH_ACH0;
|
||||
case RTW89_TX_QSEL_BK_0:
|
||||
case RTW89_TX_QSEL_BK_1:
|
||||
case RTW89_TX_QSEL_BK_2:
|
||||
case RTW89_TX_QSEL_BK_3:
|
||||
return RTW89_TXCH_ACH1;
|
||||
case RTW89_TX_QSEL_VI_0:
|
||||
case RTW89_TX_QSEL_VI_1:
|
||||
case RTW89_TX_QSEL_VI_2:
|
||||
case RTW89_TX_QSEL_VI_3:
|
||||
return RTW89_TXCH_ACH2;
|
||||
case RTW89_TX_QSEL_VO_0:
|
||||
case RTW89_TX_QSEL_VO_1:
|
||||
case RTW89_TX_QSEL_VO_2:
|
||||
case RTW89_TX_QSEL_VO_3:
|
||||
return RTW89_TXCH_ACH3;
|
||||
case RTW89_TX_QSEL_B0_MGMT:
|
||||
return RTW89_TXCH_CH8;
|
||||
case RTW89_TX_QSEL_B0_HI:
|
||||
return RTW89_TXCH_CH9;
|
||||
case RTW89_TX_QSEL_B1_MGMT:
|
||||
return RTW89_TXCH_CH10;
|
||||
case RTW89_TX_QSEL_B1_HI:
|
||||
return RTW89_TXCH_CH11;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_core_get_ch_dma);
|
||||
|
||||
u8 rtw89_core_get_ch_dma_v1(struct rtw89_dev *rtwdev, u8 qsel)
|
||||
{
|
||||
switch (qsel) {
|
||||
default:
|
||||
rtw89_warn(rtwdev, "Cannot map qsel to dma v1: %d\n", qsel);
|
||||
fallthrough;
|
||||
case RTW89_TX_QSEL_BE_0:
|
||||
case RTW89_TX_QSEL_BK_0:
|
||||
return RTW89_TXCH_ACH0;
|
||||
case RTW89_TX_QSEL_VI_0:
|
||||
case RTW89_TX_QSEL_VO_0:
|
||||
return RTW89_TXCH_ACH2;
|
||||
case RTW89_TX_QSEL_B0_MGMT:
|
||||
case RTW89_TX_QSEL_B0_HI:
|
||||
return RTW89_TXCH_CH8;
|
||||
case RTW89_TX_QSEL_B1_MGMT:
|
||||
case RTW89_TX_QSEL_B1_HI:
|
||||
return RTW89_TXCH_CH10;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_core_get_ch_dma_v1);
|
||||
|
||||
static void
|
||||
rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_core_tx_request *tx_req)
|
||||
@@ -710,7 +772,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
|
||||
u8 qsel, ch_dma;
|
||||
|
||||
qsel = rtw89_core_get_qsel_mgmt(rtwdev, tx_req);
|
||||
ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
|
||||
ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel);
|
||||
|
||||
desc_info->qsel = qsel;
|
||||
desc_info->ch_dma = ch_dma;
|
||||
@@ -927,7 +989,7 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev,
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
tid_indicate = rtw89_core_get_tid_indicate(rtwdev, tid);
|
||||
qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : rtw89_core_get_qsel(rtwdev, tid);
|
||||
ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
|
||||
ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel);
|
||||
|
||||
desc_info->ch_dma = ch_dma;
|
||||
desc_info->tid_indicate = tid_indicate;
|
||||
@@ -1073,42 +1135,46 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void rtw89_tx_wait_work(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
{
|
||||
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
|
||||
tx_wait_work.work);
|
||||
|
||||
rtw89_tx_wait_list_clear(rtwdev);
|
||||
}
|
||||
|
||||
void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel)
|
||||
{
|
||||
u8 ch_dma;
|
||||
|
||||
ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
|
||||
ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel);
|
||||
|
||||
rtw89_hci_tx_kick_off(rtwdev, ch_dma);
|
||||
}
|
||||
|
||||
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
int qsel, unsigned int timeout)
|
||||
struct rtw89_tx_wait_info *wait, int qsel,
|
||||
unsigned int timeout)
|
||||
{
|
||||
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
|
||||
struct rtw89_tx_wait_info *wait;
|
||||
unsigned long time_left;
|
||||
int ret = 0;
|
||||
|
||||
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
|
||||
if (!wait) {
|
||||
rtw89_core_tx_kick_off(rtwdev, qsel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_completion(&wait->completion);
|
||||
rcu_assign_pointer(skb_data->wait, wait);
|
||||
lockdep_assert_wiphy(rtwdev->hw->wiphy);
|
||||
|
||||
rtw89_core_tx_kick_off(rtwdev, qsel);
|
||||
time_left = wait_for_completion_timeout(&wait->completion,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (time_left == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
else if (!wait->tx_done)
|
||||
ret = -EAGAIN;
|
||||
|
||||
rcu_assign_pointer(skb_data->wait, NULL);
|
||||
kfree_rcu(wait, rcu_head);
|
||||
if (time_left == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
list_add_tail(&wait->list, &rtwdev->tx_waits);
|
||||
wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->tx_wait_work,
|
||||
RTW89_TX_WAIT_WORK_TIMEOUT);
|
||||
} else {
|
||||
if (!wait->tx_done)
|
||||
ret = -EAGAIN;
|
||||
rtw89_tx_wait_release(wait);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1157,10 +1223,12 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
|
||||
static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link,
|
||||
struct rtw89_sta_link *rtwsta_link,
|
||||
struct sk_buff *skb, int *qsel, bool sw_mld)
|
||||
struct sk_buff *skb, int *qsel, bool sw_mld,
|
||||
struct rtw89_tx_wait_info *wait)
|
||||
{
|
||||
struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
|
||||
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
|
||||
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
|
||||
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
|
||||
struct rtw89_core_tx_request tx_req = {};
|
||||
int ret;
|
||||
@@ -1177,6 +1245,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
|
||||
rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
|
||||
rtw89_core_tx_wake(rtwdev, &tx_req);
|
||||
|
||||
rcu_assign_pointer(skb_data->wait, wait);
|
||||
|
||||
ret = rtw89_hci_tx_write(rtwdev, &tx_req);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
|
||||
@@ -1213,7 +1283,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
}
|
||||
}
|
||||
|
||||
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false);
|
||||
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info)
|
||||
@@ -1835,6 +1906,10 @@ static void rtw89_core_parse_phy_status_ie00(struct rtw89_dev *rtwdev,
|
||||
|
||||
tmp_rpl = le32_get_bits(ie->w0, RTW89_PHY_STS_IE00_W0_RPL);
|
||||
phy_ppdu->rpl_avg = tmp_rpl >> 1;
|
||||
|
||||
if (!phy_ppdu->hdr_2_en)
|
||||
phy_ppdu->rx_path_en =
|
||||
le32_get_bits(ie->w3, RTW89_PHY_STS_IE00_W3_RX_PATH_EN);
|
||||
}
|
||||
|
||||
static void rtw89_core_parse_phy_status_ie00_v2(struct rtw89_dev *rtwdev,
|
||||
@@ -2221,6 +2296,435 @@ static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif_link *rtwvif_link,
|
||||
WRITE_ONCE(rtwvif_link->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp));
|
||||
}
|
||||
|
||||
static u32 rtw89_bcn_calc_min_tbtt(struct rtw89_dev *rtwdev, u32 tbtt1, u32 tbtt2)
|
||||
{
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
u32 close_bcn_intvl_th = bcn_track->close_bcn_intvl_th;
|
||||
u32 tbtt_diff_th = bcn_track->tbtt_diff_th;
|
||||
|
||||
if (tbtt2 > tbtt1)
|
||||
swap(tbtt1, tbtt2);
|
||||
|
||||
if (tbtt1 - tbtt2 > tbtt_diff_th)
|
||||
return tbtt1;
|
||||
else if (tbtt2 > close_bcn_intvl_th)
|
||||
return tbtt2;
|
||||
else if (tbtt1 > close_bcn_intvl_th)
|
||||
return tbtt1;
|
||||
else
|
||||
return tbtt2;
|
||||
}
|
||||
|
||||
static void rtw89_bcn_cfg_tbtt_offset(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
|
||||
u32 offset = bcn_track->tbtt_offset;
|
||||
|
||||
if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) {
|
||||
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
|
||||
const struct rtw89_port_reg *p = mac->port_base;
|
||||
u32 bcnspc, val;
|
||||
|
||||
bcnspc = rtw89_read32_port_mask(rtwdev, rtwvif_link,
|
||||
p->bcn_space, B_AX_BCN_SPACE_MASK);
|
||||
val = bcnspc - (offset / 1024);
|
||||
val = u32_encode_bits(val, B_AX_TBTT_SHIFT_OFST_MAG) |
|
||||
B_AX_TBTT_SHIFT_OFST_SIGN;
|
||||
|
||||
rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift,
|
||||
B_AX_TBTT_SHIFT_OFST_MASK, val);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rtw89_fw_h2c_tbtt_tuning(rtwdev, rtwvif_link, offset);
|
||||
}
|
||||
|
||||
static void rtw89_bcn_update_tbtt_offset(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
u32 *tbtt_us = bcn_stat->tbtt_us;
|
||||
u32 offset = tbtt_us[0];
|
||||
u8 i;
|
||||
|
||||
for (i = 1; i < RTW89_BCN_TRACK_STAT_NR; i++)
|
||||
offset = rtw89_bcn_calc_min_tbtt(rtwdev, tbtt_us[i], offset);
|
||||
|
||||
if (bcn_track->tbtt_offset == offset)
|
||||
return;
|
||||
|
||||
bcn_track->tbtt_offset = offset;
|
||||
rtw89_bcn_cfg_tbtt_offset(rtwdev, rtwvif_link);
|
||||
}
|
||||
|
||||
static int cmp_u16(const void *a, const void *b)
|
||||
{
|
||||
return *(const u16 *)a - *(const u16 *)b;
|
||||
}
|
||||
|
||||
static u16 _rtw89_bcn_calc_drift(u16 tbtt, u16 offset, u16 beacon_int)
|
||||
{
|
||||
if (tbtt < offset)
|
||||
return beacon_int - offset + tbtt;
|
||||
|
||||
return tbtt - offset;
|
||||
}
|
||||
|
||||
static void rtw89_bcn_calc_drift(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
u16 offset_tu = bcn_track->tbtt_offset / 1024;
|
||||
u16 *tbtt_tu = bcn_stat->tbtt_tu;
|
||||
u16 *drift = bcn_stat->drift;
|
||||
u8 i;
|
||||
|
||||
bcn_stat->tbtt_tu_min = U16_MAX;
|
||||
bcn_stat->tbtt_tu_max = 0;
|
||||
for (i = 0; i < RTW89_BCN_TRACK_STAT_NR; i++) {
|
||||
drift[i] = _rtw89_bcn_calc_drift(tbtt_tu[i], offset_tu,
|
||||
bcn_track->beacon_int);
|
||||
|
||||
bcn_stat->tbtt_tu_min = min(bcn_stat->tbtt_tu_min, tbtt_tu[i]);
|
||||
bcn_stat->tbtt_tu_max = max(bcn_stat->tbtt_tu_max, tbtt_tu[i]);
|
||||
}
|
||||
|
||||
sort(drift, RTW89_BCN_TRACK_STAT_NR, sizeof(*drift), cmp_u16, NULL);
|
||||
}
|
||||
|
||||
static void rtw89_bcn_calc_distribution(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
|
||||
u16 lower_bound, upper_bound, outlier_count = 0;
|
||||
u16 *drift = bcn_stat->drift;
|
||||
u16 *bins = bcn_dist->bins;
|
||||
u16 q1, q3, iqr, tmp;
|
||||
u8 i;
|
||||
|
||||
BUILD_BUG_ON(RTW89_BCN_TRACK_STAT_NR % 4 != 0);
|
||||
|
||||
memset(bcn_dist, 0, sizeof(*bcn_dist));
|
||||
|
||||
bcn_dist->min = drift[0];
|
||||
bcn_dist->max = drift[RTW89_BCN_TRACK_STAT_NR - 1];
|
||||
|
||||
tmp = RTW89_BCN_TRACK_STAT_NR / 4;
|
||||
q1 = ((drift[tmp] + drift[tmp - 1]) * RTW89_BCN_TRACK_SCALE_FACTOR) / 2;
|
||||
|
||||
tmp = (RTW89_BCN_TRACK_STAT_NR * 3) / 4;
|
||||
q3 = ((drift[tmp] + drift[tmp - 1]) * RTW89_BCN_TRACK_SCALE_FACTOR) / 2;
|
||||
|
||||
iqr = q3 - q1;
|
||||
tmp = (3 * iqr) / 2;
|
||||
|
||||
if (bcn_dist->min <= 5)
|
||||
lower_bound = bcn_dist->min;
|
||||
else if (q1 > tmp)
|
||||
lower_bound = (q1 - tmp) / RTW89_BCN_TRACK_SCALE_FACTOR;
|
||||
else
|
||||
lower_bound = 0;
|
||||
|
||||
upper_bound = (q3 + tmp) / RTW89_BCN_TRACK_SCALE_FACTOR;
|
||||
|
||||
for (i = 0; i < RTW89_BCN_TRACK_STAT_NR; i++) {
|
||||
u16 tbtt = bcn_stat->tbtt_tu[i];
|
||||
u16 min = bcn_stat->tbtt_tu_min;
|
||||
u8 bin_idx;
|
||||
|
||||
/* histogram */
|
||||
bin_idx = min((tbtt - min) / RTW89_BCN_TRACK_BIN_WIDTH,
|
||||
RTW89_BCN_TRACK_MAX_BIN_NUM - 1);
|
||||
bins[bin_idx]++;
|
||||
|
||||
/* boxplot outlier */
|
||||
if (drift[i] < lower_bound || drift[i] > upper_bound)
|
||||
outlier_count++;
|
||||
}
|
||||
|
||||
bcn_dist->outlier_count = outlier_count;
|
||||
bcn_dist->lower_bound = lower_bound;
|
||||
bcn_dist->upper_bound = upper_bound;
|
||||
}
|
||||
|
||||
static u8 rtw89_bcn_get_coverage(struct rtw89_dev *rtwdev, u16 threshold)
|
||||
{
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
int l = 0, r = RTW89_BCN_TRACK_STAT_NR - 1, m;
|
||||
u16 *drift = bcn_stat->drift;
|
||||
int index = -1;
|
||||
u8 count = 0;
|
||||
|
||||
while (l <= r) {
|
||||
m = l + (r - l) / 2;
|
||||
|
||||
if (drift[m] <= threshold) {
|
||||
index = m;
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m - 1;
|
||||
}
|
||||
}
|
||||
|
||||
count = (index == -1) ? 0 : (index + 1);
|
||||
|
||||
return (count * PERCENT) / RTW89_BCN_TRACK_STAT_NR;
|
||||
}
|
||||
|
||||
static u16 rtw89_bcn_get_histogram_bound(struct rtw89_dev *rtwdev, u8 target)
|
||||
{
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
|
||||
u16 tbtt_tu_max = bcn_stat->tbtt_tu_max;
|
||||
u16 upper, lower = bcn_stat->tbtt_tu_min;
|
||||
u8 i, count = 0;
|
||||
|
||||
for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) {
|
||||
upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1;
|
||||
if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1)
|
||||
upper = max(upper, tbtt_tu_max);
|
||||
|
||||
count += bcn_dist->bins[i];
|
||||
if (count > target)
|
||||
break;
|
||||
|
||||
lower = upper + 1;
|
||||
}
|
||||
|
||||
return upper;
|
||||
}
|
||||
|
||||
static u16 rtw89_bcn_get_rx_time(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_chan *chan)
|
||||
{
|
||||
#define RTW89_SYMBOL_TIME_2GHZ 192
|
||||
#define RTW89_SYMBOL_TIME_5GHZ 20
|
||||
#define RTW89_SYMBOL_TIME_6GHZ 20
|
||||
struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
|
||||
u16 bitrate, val;
|
||||
|
||||
if (!rtw89_legacy_rate_to_bitrate(rtwdev, pkt_stat->beacon_rate, &bitrate))
|
||||
return 0;
|
||||
|
||||
val = (pkt_stat->beacon_len * 8 * RTW89_BCN_TRACK_SCALE_FACTOR) / bitrate;
|
||||
|
||||
switch (chan->band_type) {
|
||||
default:
|
||||
case RTW89_BAND_2G:
|
||||
val += RTW89_SYMBOL_TIME_2GHZ;
|
||||
break;
|
||||
case RTW89_BAND_5G:
|
||||
val += RTW89_SYMBOL_TIME_5GHZ;
|
||||
break;
|
||||
case RTW89_BAND_6G:
|
||||
val += RTW89_SYMBOL_TIME_6GHZ;
|
||||
break;
|
||||
}
|
||||
|
||||
/* convert to millisecond */
|
||||
return DIV_ROUND_UP(val, 1000);
|
||||
}
|
||||
|
||||
static void rtw89_bcn_calc_timeout(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
#define RTW89_BCN_TRACK_EXTEND_TIMEOUT 5
|
||||
#define RTW89_BCN_TRACK_COVERAGE_TH 0 /* unit: TU */
|
||||
#define RTW89_BCN_TRACK_STRONG_RSSI 80
|
||||
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
|
||||
struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
|
||||
u16 outlier_high_bcn_th = bcn_track->outlier_high_bcn_th;
|
||||
u16 outlier_low_bcn_th = bcn_track->outlier_low_bcn_th;
|
||||
u8 rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
|
||||
u16 target_bcn_th = bcn_track->target_bcn_th;
|
||||
u16 low_bcn_th = bcn_track->low_bcn_th;
|
||||
u16 med_bcn_th = bcn_track->med_bcn_th;
|
||||
u16 beacon_int = bcn_track->beacon_int;
|
||||
u16 bcn_timeout;
|
||||
|
||||
if (pkt_stat->beacon_nr < low_bcn_th) {
|
||||
bcn_timeout = (RTW89_BCN_TRACK_TARGET_BCN * beacon_int) / PERCENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bcn_dist->outlier_count >= outlier_high_bcn_th) {
|
||||
bcn_timeout = bcn_dist->max;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pkt_stat->beacon_nr < med_bcn_th) {
|
||||
if (bcn_dist->outlier_count > outlier_low_bcn_th)
|
||||
bcn_timeout = (bcn_dist->max + bcn_dist->upper_bound) / 2;
|
||||
else
|
||||
bcn_timeout = bcn_dist->upper_bound +
|
||||
RTW89_BCN_TRACK_EXTEND_TIMEOUT;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rssi >= RTW89_BCN_TRACK_STRONG_RSSI) {
|
||||
if (rtw89_bcn_get_coverage(rtwdev, RTW89_BCN_TRACK_COVERAGE_TH) >= 90) {
|
||||
/* ideal case */
|
||||
bcn_timeout = 0;
|
||||
} else {
|
||||
u16 offset_tu = bcn_track->tbtt_offset / 1024;
|
||||
u16 upper_bound;
|
||||
|
||||
upper_bound =
|
||||
rtw89_bcn_get_histogram_bound(rtwdev, target_bcn_th);
|
||||
bcn_timeout =
|
||||
_rtw89_bcn_calc_drift(upper_bound, offset_tu, beacon_int);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
bcn_timeout = bcn_stat->drift[target_bcn_th];
|
||||
|
||||
out:
|
||||
bcn_track->bcn_timeout = bcn_timeout + rtw89_bcn_get_rx_time(rtwdev, chan);
|
||||
}
|
||||
|
||||
static void rtw89_bcn_update_timeout(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
rtw89_bcn_calc_drift(rtwdev);
|
||||
rtw89_bcn_calc_distribution(rtwdev);
|
||||
rtw89_bcn_calc_timeout(rtwdev, rtwvif_link);
|
||||
}
|
||||
|
||||
static void rtw89_core_bcn_track(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
struct rtw89_vif_link *rtwvif_link;
|
||||
struct rtw89_vif *rtwvif;
|
||||
unsigned int link_id;
|
||||
|
||||
if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw))
|
||||
return;
|
||||
|
||||
if (!rtwdev->lps_enabled)
|
||||
return;
|
||||
|
||||
if (!bcn_track->is_data_ready)
|
||||
return;
|
||||
|
||||
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
|
||||
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
|
||||
if (!(rtwvif_link->wifi_role == RTW89_WIFI_ROLE_STATION ||
|
||||
rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT))
|
||||
continue;
|
||||
|
||||
rtw89_bcn_update_tbtt_offset(rtwdev, rtwvif_link);
|
||||
rtw89_bcn_update_timeout(rtwdev, rtwvif_link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool rtw89_core_bcn_track_can_lps(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
|
||||
if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw))
|
||||
return true;
|
||||
|
||||
return bcn_track->is_data_ready;
|
||||
}
|
||||
|
||||
static void rtw89_core_bcn_track_assoc(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
#define RTW89_BCN_TRACK_MED_BCN 70
|
||||
#define RTW89_BCN_TRACK_LOW_BCN 30
|
||||
#define RTW89_BCN_TRACK_OUTLIER_HIGH_BCN 30
|
||||
#define RTW89_BCN_TRACK_OUTLIER_LOW_BCN 20
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
u32 period = jiffies_to_msecs(RTW89_TRACK_WORK_PERIOD);
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
u32 beacons_in_period;
|
||||
u32 bcn_intvl_us;
|
||||
u16 beacon_int;
|
||||
u8 dtim;
|
||||
|
||||
rcu_read_lock();
|
||||
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
|
||||
beacon_int = bss_conf->beacon_int;
|
||||
dtim = bss_conf->dtim_period;
|
||||
rcu_read_unlock();
|
||||
|
||||
beacons_in_period = period / beacon_int / dtim;
|
||||
bcn_intvl_us = ieee80211_tu_to_usec(beacon_int);
|
||||
|
||||
bcn_track->low_bcn_th =
|
||||
(beacons_in_period * RTW89_BCN_TRACK_LOW_BCN) / PERCENT;
|
||||
bcn_track->med_bcn_th =
|
||||
(beacons_in_period * RTW89_BCN_TRACK_MED_BCN) / PERCENT;
|
||||
bcn_track->outlier_low_bcn_th =
|
||||
(RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_OUTLIER_LOW_BCN) / PERCENT;
|
||||
bcn_track->outlier_high_bcn_th =
|
||||
(RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_OUTLIER_HIGH_BCN) / PERCENT;
|
||||
bcn_track->target_bcn_th =
|
||||
(RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_TARGET_BCN) / PERCENT;
|
||||
|
||||
bcn_track->close_bcn_intvl_th = ieee80211_tu_to_usec(beacon_int - 3);
|
||||
bcn_track->tbtt_diff_th = (bcn_intvl_us * 85) / PERCENT;
|
||||
bcn_track->beacon_int = beacon_int;
|
||||
bcn_track->dtim = dtim;
|
||||
}
|
||||
|
||||
static void rtw89_core_bcn_track_reset(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
memset(&rtwdev->phystat.bcn_stat, 0, sizeof(rtwdev->phystat.bcn_stat));
|
||||
memset(&rtwdev->bcn_track, 0, sizeof(rtwdev->bcn_track));
|
||||
}
|
||||
|
||||
static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
#define RTW89_APPEND_TSF_2GHZ 384
|
||||
#define RTW89_APPEND_TSF_5GHZ 52
|
||||
#define RTW89_APPEND_TSF_6GHZ 52
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
u32 bcn_intvl_us = ieee80211_tu_to_usec(bss_conf->beacon_int);
|
||||
u64 tsf = le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
u8 wp, num = bcn_stat->num;
|
||||
u16 append;
|
||||
|
||||
if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw))
|
||||
return;
|
||||
|
||||
switch (rx_status->band) {
|
||||
default:
|
||||
case NL80211_BAND_2GHZ:
|
||||
append = RTW89_APPEND_TSF_2GHZ;
|
||||
break;
|
||||
case NL80211_BAND_5GHZ:
|
||||
append = RTW89_APPEND_TSF_5GHZ;
|
||||
break;
|
||||
case NL80211_BAND_6GHZ:
|
||||
append = RTW89_APPEND_TSF_6GHZ;
|
||||
break;
|
||||
}
|
||||
|
||||
wp = bcn_stat->wp;
|
||||
div_u64_rem(tsf - append, bcn_intvl_us, &bcn_stat->tbtt_us[wp]);
|
||||
bcn_stat->tbtt_tu[wp] = bcn_stat->tbtt_us[wp] / 1024;
|
||||
bcn_stat->wp = (wp + 1) % RTW89_BCN_TRACK_STAT_NR;
|
||||
bcn_stat->num = umin(num + 1, RTW89_BCN_TRACK_STAT_NR);
|
||||
bcn_track->is_data_ready = bcn_stat->num == RTW89_BCN_TRACK_STAT_NR;
|
||||
}
|
||||
|
||||
static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
@@ -2237,6 +2741,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
struct rtw89_vif_link *rtwvif_link;
|
||||
const u8 *bssid = iter_data->bssid;
|
||||
const u8 *target_bssid;
|
||||
|
||||
if (rtwdev->scanning &&
|
||||
(ieee80211_is_beacon(hdr->frame_control) ||
|
||||
@@ -2258,7 +2763,10 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ether_addr_equal(bss_conf->bssid, bssid))
|
||||
target_bssid = ieee80211_is_beacon(hdr->frame_control) &&
|
||||
bss_conf->nontransmitted ?
|
||||
bss_conf->transmitter_bssid : bss_conf->bssid;
|
||||
if (!ether_addr_equal(target_bssid, bssid))
|
||||
goto out;
|
||||
|
||||
if (is_mld) {
|
||||
@@ -2272,7 +2780,6 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
||||
rtw89_vif_sync_bcn_tsf(rtwvif_link, hdr, skb->len);
|
||||
rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu);
|
||||
}
|
||||
pkt_stat->beacon_nr++;
|
||||
|
||||
if (phy_ppdu) {
|
||||
ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg);
|
||||
@@ -2280,7 +2787,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
||||
rtwvif_link->bcn_bw_idx = phy_ppdu->bw_idx;
|
||||
}
|
||||
|
||||
pkt_stat->beacon_nr++;
|
||||
pkt_stat->beacon_rate = desc_info->data_rate;
|
||||
pkt_stat->beacon_len = skb->len;
|
||||
|
||||
rtw89_vif_rx_bcn_stat(rtwdev, bss_conf, skb);
|
||||
}
|
||||
|
||||
if (!ether_addr_equal(bss_conf->addr, hdr->addr1))
|
||||
@@ -3226,7 +3737,7 @@ static u32 rtw89_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 tid)
|
||||
u8 qsel, ch_dma;
|
||||
|
||||
qsel = rtw89_core_get_qsel(rtwdev, tid);
|
||||
ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
|
||||
ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel);
|
||||
|
||||
return rtw89_hci_check_and_reclaim_tx_resource(rtwdev, ch_dma);
|
||||
}
|
||||
@@ -3411,6 +3922,7 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
|
||||
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
|
||||
int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1;
|
||||
struct rtw89_sta_link *rtwsta_link;
|
||||
struct rtw89_tx_wait_info *wait;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct rtw89_sta *rtwsta;
|
||||
@@ -3420,6 +3932,12 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
|
||||
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
|
||||
return 0;
|
||||
|
||||
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
|
||||
if (!wait)
|
||||
return -ENOMEM;
|
||||
|
||||
init_completion(&wait->completion);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
|
||||
if (!sta) {
|
||||
@@ -3434,6 +3952,8 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait->skb = skb;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ps)
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
@@ -3441,10 +3961,12 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
|
||||
rtwsta_link = rtwsta->links[rtwvif_link->link_id];
|
||||
if (unlikely(!rtwsta_link)) {
|
||||
ret = -ENOLINK;
|
||||
dev_kfree_skb_any(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true);
|
||||
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true,
|
||||
wait);
|
||||
if (ret) {
|
||||
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
|
||||
dev_kfree_skb_any(skb);
|
||||
@@ -3453,10 +3975,11 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
|
||||
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel,
|
||||
timeout);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
kfree(wait);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -3697,6 +4220,9 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
|
||||
vif->type == NL80211_IFTYPE_P2P_CLIENT))
|
||||
continue;
|
||||
|
||||
if (!rtw89_core_bcn_track_can_lps(rtwdev))
|
||||
continue;
|
||||
|
||||
rtw89_enter_lps(rtwdev, rtwvif, true);
|
||||
}
|
||||
}
|
||||
@@ -3883,6 +4409,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
rtw89_btc_ntfy_wl_sta(rtwdev);
|
||||
}
|
||||
rtw89_mac_bf_monitor_track(rtwdev);
|
||||
rtw89_core_bcn_track(rtwdev);
|
||||
rtw89_phy_stat_track(rtwdev);
|
||||
rtw89_phy_env_monitor_track(rtwdev);
|
||||
rtw89_phy_dig(rtwdev);
|
||||
@@ -4129,8 +4656,10 @@ int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev,
|
||||
|
||||
rtw89_assoc_link_clr(rtwsta_link);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false);
|
||||
rtw89_core_bcn_track_reset(rtwdev);
|
||||
}
|
||||
|
||||
if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
|
||||
rtw89_p2p_noa_once_deinit(rtwvif_link);
|
||||
@@ -4271,6 +4800,7 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev,
|
||||
BTC_ROLE_MSTS_STA_CONN_END);
|
||||
rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta_link->htc_template, chan);
|
||||
rtw89_phy_ul_tb_assoc(rtwdev, rtwvif_link);
|
||||
rtw89_core_bcn_track_assoc(rtwdev, rtwvif_link);
|
||||
|
||||
ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id);
|
||||
if (ret) {
|
||||
@@ -4829,39 +5359,96 @@ void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
}
|
||||
}
|
||||
|
||||
int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
|
||||
struct rtw89_wait_response *
|
||||
rtw89_wait_for_cond_prep(struct rtw89_wait_info *wait, unsigned int cond)
|
||||
{
|
||||
struct completion *cmpl = &wait->completion;
|
||||
unsigned long time_left;
|
||||
struct rtw89_wait_response *prep;
|
||||
unsigned int cur;
|
||||
|
||||
/* use -EPERM _iff_ telling eval side not to make any changes */
|
||||
|
||||
cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond);
|
||||
if (cur != RTW89_WAIT_COND_IDLE)
|
||||
return -EBUSY;
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
time_left = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT);
|
||||
if (time_left == 0) {
|
||||
atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
|
||||
return -ETIMEDOUT;
|
||||
prep = kzalloc(sizeof(*prep), GFP_KERNEL);
|
||||
if (!prep)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init_completion(&prep->completion);
|
||||
|
||||
rcu_assign_pointer(wait->resp, prep);
|
||||
|
||||
return prep;
|
||||
}
|
||||
|
||||
int rtw89_wait_for_cond_eval(struct rtw89_wait_info *wait,
|
||||
struct rtw89_wait_response *prep, int err)
|
||||
{
|
||||
unsigned long time_left;
|
||||
|
||||
if (IS_ERR(prep)) {
|
||||
err = err ?: PTR_ERR(prep);
|
||||
|
||||
/* special error case: no permission to reset anything */
|
||||
if (PTR_ERR(prep) == -EPERM)
|
||||
return err;
|
||||
|
||||
goto reset;
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
time_left = wait_for_completion_timeout(&prep->completion,
|
||||
RTW89_WAIT_FOR_COND_TIMEOUT);
|
||||
if (time_left == 0) {
|
||||
err = -ETIMEDOUT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wait->data = prep->data;
|
||||
|
||||
cleanup:
|
||||
rcu_assign_pointer(wait->resp, NULL);
|
||||
kfree_rcu(prep, rcu_head);
|
||||
|
||||
reset:
|
||||
atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (wait->data.err)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtw89_complete_cond_resp(struct rtw89_wait_response *resp,
|
||||
const struct rtw89_completion_data *data)
|
||||
{
|
||||
resp->data = *data;
|
||||
complete(&resp->completion);
|
||||
}
|
||||
|
||||
void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
|
||||
const struct rtw89_completion_data *data)
|
||||
{
|
||||
struct rtw89_wait_response *resp;
|
||||
unsigned int cur;
|
||||
|
||||
guard(rcu)();
|
||||
|
||||
resp = rcu_dereference(wait->resp);
|
||||
if (!resp)
|
||||
return;
|
||||
|
||||
cur = atomic_cmpxchg(&wait->cond, cond, RTW89_WAIT_COND_IDLE);
|
||||
if (cur != cond)
|
||||
return;
|
||||
|
||||
wait->data = *data;
|
||||
complete(&wait->completion);
|
||||
rtw89_complete_cond_resp(resp, data);
|
||||
}
|
||||
|
||||
void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event)
|
||||
@@ -4908,6 +5495,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rtw89_phy_init_bb_afe(rtwdev);
|
||||
|
||||
ret = rtw89_mac_init(rtwdev);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret);
|
||||
@@ -4952,6 +5541,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
|
||||
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
|
||||
rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable);
|
||||
rtw89_fw_h2c_init_ba_cam(rtwdev);
|
||||
rtw89_tas_fw_timer_enable(rtwdev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4967,6 +5557,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
|
||||
if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
|
||||
return;
|
||||
|
||||
rtw89_tas_fw_timer_enable(rtwdev, false);
|
||||
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_OFF);
|
||||
|
||||
clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
|
||||
@@ -4978,6 +5569,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
|
||||
wiphy_work_cancel(wiphy, &btc->dhcp_notify_work);
|
||||
wiphy_work_cancel(wiphy, &btc->icmp_notify_work);
|
||||
cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
|
||||
wiphy_delayed_work_cancel(wiphy, &rtwdev->tx_wait_work);
|
||||
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work);
|
||||
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work);
|
||||
wiphy_delayed_work_cancel(wiphy, &rtwdev->chanctx_work);
|
||||
@@ -5203,6 +5795,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
|
||||
INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]);
|
||||
}
|
||||
INIT_LIST_HEAD(&rtwdev->scan_info.chan_list);
|
||||
INIT_LIST_HEAD(&rtwdev->tx_waits);
|
||||
INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work);
|
||||
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
|
||||
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
|
||||
@@ -5214,6 +5807,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
|
||||
wiphy_delayed_work_init(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work);
|
||||
wiphy_delayed_work_init(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work);
|
||||
wiphy_delayed_work_init(&rtwdev->mcc_prepare_done_work, rtw89_mcc_prepare_done_work);
|
||||
wiphy_delayed_work_init(&rtwdev->tx_wait_work, rtw89_tx_wait_work);
|
||||
INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work);
|
||||
wiphy_delayed_work_init(&rtwdev->antdiv_work, rtw89_phy_antdiv_work);
|
||||
rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0);
|
||||
@@ -5813,6 +6407,7 @@ int rtw89_core_register(struct rtw89_dev *rtwdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtw89_phy_dm_init_data(rtwdev);
|
||||
rtw89_debugfs_init(rtwdev);
|
||||
|
||||
return 0;
|
||||
@@ -5863,6 +6458,9 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
|
||||
ops->cancel_remain_on_channel = NULL;
|
||||
}
|
||||
|
||||
if (!chip->support_noise)
|
||||
ops->get_survey = NULL;
|
||||
|
||||
driver_data_size = sizeof(struct rtw89_dev) + bus_data_size;
|
||||
hw = ieee80211_alloc_hw(driver_data_size, ops);
|
||||
if (!hw)
|
||||
|
||||
@@ -1011,6 +1011,7 @@ struct rtw89_port_reg {
|
||||
u32 ptcl_dbg;
|
||||
u32 ptcl_dbg_info;
|
||||
u32 bcn_drop_all;
|
||||
u32 bcn_psr_rpt;
|
||||
u32 hiq_win[RTW89_PORT_NUM];
|
||||
};
|
||||
|
||||
@@ -3506,9 +3507,12 @@ struct rtw89_phy_rate_pattern {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
#define RTW89_TX_WAIT_WORK_TIMEOUT msecs_to_jiffies(500)
|
||||
struct rtw89_tx_wait_info {
|
||||
struct rcu_head rcu_head;
|
||||
struct list_head list;
|
||||
struct completion completion;
|
||||
struct sk_buff *skb;
|
||||
bool tx_done;
|
||||
};
|
||||
|
||||
@@ -3759,6 +3763,7 @@ struct rtw89_chip_ops {
|
||||
void (*fill_txdesc_fwcmd)(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_tx_desc_info *desc_info,
|
||||
void *txdesc);
|
||||
u8 (*get_ch_dma)(struct rtw89_dev *rtwdev, u8 qsel);
|
||||
int (*cfg_ctrl_path)(struct rtw89_dev *rtwdev, bool wl);
|
||||
int (*mac_cfg_gnt)(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_mac_ax_coex_gnt *gnt_cfg);
|
||||
@@ -4363,6 +4368,9 @@ struct rtw89_chanctx_listener {
|
||||
(struct rtw89_dev *rtwdev, enum rtw89_chanctx_state state);
|
||||
};
|
||||
|
||||
#define RTW89_NHM_TH_NUM 11
|
||||
#define RTW89_NHM_RPT_NUM 12
|
||||
|
||||
struct rtw89_chip_info {
|
||||
enum rtw89_core_chip_id chip_id;
|
||||
enum rtw89_chip_gen chip_gen;
|
||||
@@ -4397,6 +4405,7 @@ struct rtw89_chip_info {
|
||||
bool support_ant_gain;
|
||||
bool support_tas;
|
||||
bool support_sar_by_ant;
|
||||
bool support_noise;
|
||||
bool ul_tb_waveform_ctrl;
|
||||
bool ul_tb_pwr_diff;
|
||||
bool rx_freq_frome_ie;
|
||||
@@ -4481,6 +4490,8 @@ struct rtw89_chip_info {
|
||||
bool cfo_hw_comp;
|
||||
const struct rtw89_reg_def *dcfo_comp;
|
||||
u8 dcfo_comp_sft;
|
||||
const struct rtw89_reg_def (*nhm_report)[RTW89_NHM_RPT_NUM];
|
||||
const struct rtw89_reg_def (*nhm_th)[RTW89_NHM_TH_NUM];
|
||||
const struct rtw89_imr_info *imr_info;
|
||||
const struct rtw89_imr_table *imr_dmac_table;
|
||||
const struct rtw89_imr_table *imr_cmac_table;
|
||||
@@ -4542,17 +4553,23 @@ struct rtw89_completion_data {
|
||||
u8 buf[RTW89_COMPLETION_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct rtw89_wait_info {
|
||||
atomic_t cond;
|
||||
struct rtw89_wait_response {
|
||||
struct rcu_head rcu_head;
|
||||
struct completion completion;
|
||||
struct rtw89_completion_data data;
|
||||
};
|
||||
|
||||
struct rtw89_wait_info {
|
||||
atomic_t cond;
|
||||
struct rtw89_completion_data data;
|
||||
struct rtw89_wait_response __rcu *resp;
|
||||
};
|
||||
|
||||
#define RTW89_WAIT_FOR_COND_TIMEOUT msecs_to_jiffies(100)
|
||||
|
||||
static inline void rtw89_init_wait(struct rtw89_wait_info *wait)
|
||||
{
|
||||
init_completion(&wait->completion);
|
||||
rcu_assign_pointer(wait->resp, NULL);
|
||||
atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
|
||||
}
|
||||
|
||||
@@ -4622,6 +4639,7 @@ enum rtw89_fw_feature {
|
||||
RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP,
|
||||
RTW89_FW_FEATURE_RFK_NTFY_MCC_V0,
|
||||
RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG,
|
||||
RTW89_FW_FEATURE_BEACON_TRACKING,
|
||||
};
|
||||
|
||||
struct rtw89_fw_suit {
|
||||
@@ -4681,6 +4699,7 @@ struct rtw89_fw_elm_info {
|
||||
struct rtw89_fw_txpwr_track_cfg *txpwr_trk;
|
||||
struct rtw89_phy_rfk_log_fmt *rfk_log_fmt;
|
||||
const struct rtw89_regd_data *regd;
|
||||
const struct rtw89_fw_element_hdr *afe;
|
||||
};
|
||||
|
||||
enum rtw89_fw_mss_dev_type {
|
||||
@@ -5074,9 +5093,36 @@ struct rtw89_pkt_drop_params {
|
||||
struct rtw89_pkt_stat {
|
||||
u16 beacon_nr;
|
||||
u8 beacon_rate;
|
||||
u32 beacon_len;
|
||||
u32 rx_rate_cnt[RTW89_HW_RATE_NR];
|
||||
};
|
||||
|
||||
#define RTW89_BCN_TRACK_STAT_NR 32
|
||||
#define RTW89_BCN_TRACK_SCALE_FACTOR 10
|
||||
#define RTW89_BCN_TRACK_MAX_BIN_NUM 6
|
||||
#define RTW89_BCN_TRACK_BIN_WIDTH 5
|
||||
#define RTW89_BCN_TRACK_TARGET_BCN 80
|
||||
|
||||
struct rtw89_beacon_dist {
|
||||
u16 min;
|
||||
u16 max;
|
||||
u16 outlier_count;
|
||||
u16 lower_bound;
|
||||
u16 upper_bound;
|
||||
u16 bins[RTW89_BCN_TRACK_MAX_BIN_NUM];
|
||||
};
|
||||
|
||||
struct rtw89_beacon_stat {
|
||||
u8 num;
|
||||
u8 wp;
|
||||
u16 tbtt_tu_min;
|
||||
u16 tbtt_tu_max;
|
||||
u16 drift[RTW89_BCN_TRACK_STAT_NR];
|
||||
u32 tbtt_us[RTW89_BCN_TRACK_STAT_NR];
|
||||
u16 tbtt_tu[RTW89_BCN_TRACK_STAT_NR];
|
||||
struct rtw89_beacon_dist bcn_dist;
|
||||
};
|
||||
|
||||
DECLARE_EWMA(thermal, 4, 4);
|
||||
|
||||
struct rtw89_phy_stat {
|
||||
@@ -5085,6 +5131,7 @@ struct rtw89_phy_stat {
|
||||
struct ewma_rssi bcn_rssi;
|
||||
struct rtw89_pkt_stat cur_pkt_stat;
|
||||
struct rtw89_pkt_stat last_pkt_stat;
|
||||
struct rtw89_beacon_stat bcn_stat;
|
||||
};
|
||||
|
||||
enum rtw89_rfk_report_state {
|
||||
@@ -5434,6 +5481,7 @@ enum rtw89_env_racing_lv {
|
||||
struct rtw89_ccx_para_info {
|
||||
enum rtw89_env_racing_lv rac_lv;
|
||||
u16 mntr_time;
|
||||
bool nhm_incld_cca;
|
||||
u8 nhm_manual_th_ofst;
|
||||
u8 nhm_manual_th0;
|
||||
enum rtw89_ifs_clm_application ifs_clm_app;
|
||||
@@ -5467,9 +5515,13 @@ enum rtw89_ccx_edcca_opt_bw_idx {
|
||||
RTW89_CCX_EDCCA_BW20_7 = 7
|
||||
};
|
||||
|
||||
#define RTW89_NHM_TH_NUM 11
|
||||
struct rtw89_nhm_report {
|
||||
struct list_head list;
|
||||
struct ieee80211_channel *channel;
|
||||
u8 noise;
|
||||
};
|
||||
|
||||
#define RTW89_FAHM_TH_NUM 11
|
||||
#define RTW89_NHM_RPT_NUM 12
|
||||
#define RTW89_FAHM_RPT_NUM 12
|
||||
#define RTW89_IFS_CLM_NUM 4
|
||||
struct rtw89_env_monitor_info {
|
||||
@@ -5503,6 +5555,13 @@ struct rtw89_env_monitor_info {
|
||||
u16 ifs_clm_ofdm_fa_permil;
|
||||
u32 ifs_clm_ifs_avg[RTW89_IFS_CLM_NUM];
|
||||
u32 ifs_clm_cca_avg[RTW89_IFS_CLM_NUM];
|
||||
bool nhm_include_cca;
|
||||
u32 nhm_sum;
|
||||
u32 nhm_mntr_time;
|
||||
u16 nhm_result[RTW89_NHM_RPT_NUM];
|
||||
u8 nhm_th[RTW89_NHM_RPT_NUM];
|
||||
struct rtw89_nhm_report *nhm_his[RTW89_BAND_NUM];
|
||||
struct list_head nhm_rpt_list;
|
||||
};
|
||||
|
||||
enum rtw89_ser_rcvy_step {
|
||||
@@ -5715,8 +5774,8 @@ struct rtw89_wow_gtk_info {
|
||||
u8 kck[32];
|
||||
u8 kek[32];
|
||||
u8 tk1[16];
|
||||
u8 txmickey[8];
|
||||
u8 rxmickey[8];
|
||||
u8 txmickey[8];
|
||||
__le32 igtk_keyid;
|
||||
__le64 ipn;
|
||||
u8 igtk[2][32];
|
||||
@@ -5882,6 +5941,24 @@ struct rtw89_mlo_info {
|
||||
struct rtw89_wait_info wait;
|
||||
};
|
||||
|
||||
struct rtw89_beacon_track_info {
|
||||
bool is_data_ready;
|
||||
u32 tbtt_offset; /* in unit of microsecond */
|
||||
u16 bcn_timeout; /* in unit of millisecond */
|
||||
|
||||
/* The following are constant and set at association. */
|
||||
u8 dtim;
|
||||
u16 beacon_int;
|
||||
u16 low_bcn_th;
|
||||
u16 med_bcn_th;
|
||||
u16 high_bcn_th;
|
||||
u16 target_bcn_th;
|
||||
u16 outlier_low_bcn_th;
|
||||
u16 outlier_high_bcn_th;
|
||||
u32 close_bcn_intvl_th;
|
||||
u32 tbtt_diff_th;
|
||||
};
|
||||
|
||||
struct rtw89_dev {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
@@ -5896,6 +5973,7 @@ struct rtw89_dev {
|
||||
const struct rtw89_pci_info *pci_info;
|
||||
const struct rtw89_rfe_parms *rfe_parms;
|
||||
struct rtw89_hal hal;
|
||||
struct rtw89_beacon_track_info bcn_track;
|
||||
struct rtw89_mcc_info mcc;
|
||||
struct rtw89_mlo_info mlo;
|
||||
struct rtw89_mac_info mac;
|
||||
@@ -5925,6 +6003,9 @@ struct rtw89_dev {
|
||||
/* used to protect rpwm */
|
||||
spinlock_t rpwm_lock;
|
||||
|
||||
struct list_head tx_waits;
|
||||
struct wiphy_delayed_work tx_wait_work;
|
||||
|
||||
struct rtw89_cam_info cam_info;
|
||||
|
||||
struct sk_buff_head c2h_queue;
|
||||
@@ -6181,6 +6262,26 @@ rtw89_assoc_link_rcu_dereference(struct rtw89_dev *rtwdev, u8 macid)
|
||||
list_first_entry_or_null(&p->dlink_pool, typeof(*p->links_inst), dlink_schd); \
|
||||
})
|
||||
|
||||
static inline void rtw89_tx_wait_release(struct rtw89_tx_wait_info *wait)
|
||||
{
|
||||
dev_kfree_skb_any(wait->skb);
|
||||
kfree_rcu(wait, rcu_head);
|
||||
}
|
||||
|
||||
static inline void rtw89_tx_wait_list_clear(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_tx_wait_info *wait, *tmp;
|
||||
|
||||
lockdep_assert_wiphy(rtwdev->hw->wiphy);
|
||||
|
||||
list_for_each_entry_safe(wait, tmp, &rtwdev->tx_waits, list) {
|
||||
if (!completion_done(&wait->completion))
|
||||
continue;
|
||||
list_del(&wait->list);
|
||||
rtw89_tx_wait_release(wait);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_core_tx_request *tx_req)
|
||||
{
|
||||
@@ -6190,6 +6291,7 @@ static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev,
|
||||
static inline void rtw89_hci_reset(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
rtwdev->hci.ops->reset(rtwdev);
|
||||
rtw89_tx_wait_list_clear(rtwdev);
|
||||
}
|
||||
|
||||
static inline int rtw89_hci_start(struct rtw89_dev *rtwdev)
|
||||
@@ -6322,9 +6424,13 @@ static inline void rtw89_hci_clear(struct rtw89_dev *rtwdev, struct pci_dev *pde
|
||||
static inline
|
||||
struct rtw89_tx_skb_data *RTW89_TX_SKB_CB(struct sk_buff *skb)
|
||||
{
|
||||
/*
|
||||
* This should be used by/after rtw89_hci_tx_write() and before doing
|
||||
* ieee80211_tx_info_clear_status().
|
||||
*/
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
return (struct rtw89_tx_skb_data *)info->status.status_driver_data;
|
||||
return (struct rtw89_tx_skb_data *)info->driver_data;
|
||||
}
|
||||
|
||||
static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr)
|
||||
@@ -7130,6 +7236,14 @@ void rtw89_chip_fill_txdesc_fwcmd(struct rtw89_dev *rtwdev,
|
||||
chip->ops->fill_txdesc_fwcmd(rtwdev, desc_info, txdesc);
|
||||
}
|
||||
|
||||
static inline
|
||||
u8 rtw89_chip_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel)
|
||||
{
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
|
||||
return chip->ops->get_ch_dma(rtwdev, qsel);
|
||||
}
|
||||
|
||||
static inline
|
||||
void rtw89_chip_mac_cfg_gnt(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_mac_ax_coex_gnt *gnt_cfg)
|
||||
@@ -7258,11 +7372,12 @@ static inline struct sk_buff *rtw89_alloc_skb_for_rx(struct rtw89_dev *rtwdev,
|
||||
return dev_alloc_skb(length);
|
||||
}
|
||||
|
||||
static inline void rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev,
|
||||
static inline bool rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_tx_skb_data *skb_data,
|
||||
bool tx_done)
|
||||
{
|
||||
struct rtw89_tx_wait_info *wait;
|
||||
bool ret = false;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
@@ -7270,11 +7385,14 @@ static inline void rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev,
|
||||
if (!wait)
|
||||
goto out;
|
||||
|
||||
ret = true;
|
||||
wait->tx_done = tx_done;
|
||||
complete(&wait->completion);
|
||||
/* Don't access skb anymore after completion */
|
||||
complete_all(&wait->completion);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev)
|
||||
@@ -7358,7 +7476,8 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
|
||||
struct sk_buff *skb, bool fwdl);
|
||||
void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel);
|
||||
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
int qsel, unsigned int timeout);
|
||||
struct rtw89_tx_wait_info *wait, int qsel,
|
||||
unsigned int timeout);
|
||||
void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_tx_desc_info *desc_info,
|
||||
void *txdesc);
|
||||
@@ -7374,6 +7493,8 @@ void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev,
|
||||
void rtw89_core_fill_txdesc_fwcmd_v2(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_tx_desc_info *desc_info,
|
||||
void *txdesc);
|
||||
u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel);
|
||||
u8 rtw89_core_get_ch_dma_v1(struct rtw89_dev *rtwdev, u8 qsel);
|
||||
void rtw89_core_rx(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_rx_desc_info *desc_info,
|
||||
struct sk_buff *skb);
|
||||
@@ -7454,13 +7575,18 @@ void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc);
|
||||
int rtw89_chip_info_setup(struct rtw89_dev *rtwdev);
|
||||
void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link);
|
||||
bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate);
|
||||
bool rtw89_legacy_rate_to_bitrate(struct rtw89_dev *rtwdev, u8 legacy_rate, u16 *bitrate);
|
||||
int rtw89_regd_setup(struct rtw89_dev *rtwdev);
|
||||
int rtw89_regd_init_hint(struct rtw89_dev *rtwdev);
|
||||
const char *rtw89_regd_get_string(enum rtw89_regulation_type regd);
|
||||
void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_traffic_stats *stats);
|
||||
int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond);
|
||||
struct rtw89_wait_response *
|
||||
rtw89_wait_for_cond_prep(struct rtw89_wait_info *wait, unsigned int cond)
|
||||
__acquires(rtw89_wait);
|
||||
int rtw89_wait_for_cond_eval(struct rtw89_wait_info *wait,
|
||||
struct rtw89_wait_response *prep, int err)
|
||||
__releases(rtw89_wait);
|
||||
void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
|
||||
const struct rtw89_completion_data *data);
|
||||
int rtw89_core_start(struct rtw89_dev *rtwdev);
|
||||
|
||||
@@ -86,6 +86,7 @@ struct rtw89_debugfs {
|
||||
struct rtw89_debugfs_priv stations;
|
||||
struct rtw89_debugfs_priv disable_dm;
|
||||
struct rtw89_debugfs_priv mlo_mode;
|
||||
struct rtw89_debugfs_priv beacon_info;
|
||||
};
|
||||
|
||||
struct rtw89_debugfs_iter_data {
|
||||
@@ -3562,6 +3563,58 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtw89_dbg_trigger_mac_error_ax(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u16 val16;
|
||||
u8 val8;
|
||||
int ret;
|
||||
|
||||
ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val8 = rtw89_read8(rtwdev, R_AX_CMAC_FUNC_EN);
|
||||
rtw89_write8(rtwdev, R_AX_CMAC_FUNC_EN, val8 & ~B_AX_TMAC_EN);
|
||||
mdelay(1);
|
||||
rtw89_write8(rtwdev, R_AX_CMAC_FUNC_EN, val8);
|
||||
|
||||
val16 = rtw89_read16(rtwdev, R_AX_PTCL_IMR0);
|
||||
rtw89_write16(rtwdev, R_AX_PTCL_IMR0, val16 | B_AX_F2PCMD_EMPTY_ERR_INT_EN);
|
||||
rtw89_write16(rtwdev, R_AX_PTCL_IMR0, val16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtw89_dbg_trigger_mac_error_be(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtw89_write32_set(rtwdev, R_BE_CMAC_FW_TRIGGER_IDCT_ISR,
|
||||
B_BE_CMAC_FW_TRIG_IDCT | B_BE_CMAC_FW_ERR_IDCT_IMR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtw89_dbg_trigger_mac_error(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
|
||||
rtw89_leave_ps_mode(rtwdev);
|
||||
|
||||
switch (chip->chip_gen) {
|
||||
case RTW89_CHIP_AX:
|
||||
return rtw89_dbg_trigger_mac_error_ax(rtwdev);
|
||||
case RTW89_CHIP_BE:
|
||||
return rtw89_dbg_trigger_mac_error_be(rtwdev);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
rtw89_debug_priv_fw_crash_get(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_debugfs_priv *debugfs_priv,
|
||||
@@ -3577,6 +3630,7 @@ rtw89_debug_priv_fw_crash_get(struct rtw89_dev *rtwdev,
|
||||
enum rtw89_dbg_crash_simulation_type {
|
||||
RTW89_DBG_SIM_CPU_EXCEPTION = 1,
|
||||
RTW89_DBG_SIM_CTRL_ERROR = 2,
|
||||
RTW89_DBG_SIM_MAC_ERROR = 3,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
@@ -3585,6 +3639,7 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int (*sim)(struct rtw89_dev *rtwdev);
|
||||
bool announce = true;
|
||||
u8 crash_type;
|
||||
int ret;
|
||||
|
||||
@@ -3603,11 +3658,19 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev,
|
||||
case RTW89_DBG_SIM_CTRL_ERROR:
|
||||
sim = rtw89_dbg_trigger_ctrl_error;
|
||||
break;
|
||||
case RTW89_DBG_SIM_MAC_ERROR:
|
||||
sim = rtw89_dbg_trigger_mac_error;
|
||||
|
||||
/* Driver SER flow won't get involved; only FW will. */
|
||||
announce = false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags);
|
||||
if (announce)
|
||||
set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags);
|
||||
|
||||
ret = sim(rtwdev);
|
||||
|
||||
if (ret)
|
||||
@@ -4298,6 +4361,64 @@ rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_debugfs_priv *debugfs_priv,
|
||||
char *buf, size_t bufsz)
|
||||
{
|
||||
struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat;
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
|
||||
struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
|
||||
u16 upper, lower = bcn_stat->tbtt_tu_min;
|
||||
char *p = buf, *end = buf + bufsz;
|
||||
u16 *drift = bcn_stat->drift;
|
||||
u8 bcn_num = bcn_stat->num;
|
||||
u8 count;
|
||||
u8 i;
|
||||
|
||||
p += scnprintf(p, end - p, "[Beacon info]\n");
|
||||
p += scnprintf(p, end - p, "count: %u\n", pkt_stat->beacon_nr);
|
||||
p += scnprintf(p, end - p, "interval: %u\n", bcn_track->beacon_int);
|
||||
p += scnprintf(p, end - p, "dtim: %u\n", bcn_track->dtim);
|
||||
p += scnprintf(p, end - p, "raw rssi: %lu\n",
|
||||
ewma_rssi_read(&rtwdev->phystat.bcn_rssi));
|
||||
p += scnprintf(p, end - p, "hw rate: %u\n", pkt_stat->beacon_rate);
|
||||
p += scnprintf(p, end - p, "length: %u\n", pkt_stat->beacon_len);
|
||||
|
||||
p += scnprintf(p, end - p, "\n[Distribution]\n");
|
||||
p += scnprintf(p, end - p, "tbtt\n");
|
||||
for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) {
|
||||
upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1;
|
||||
if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1)
|
||||
upper = max(upper, bcn_stat->tbtt_tu_max);
|
||||
|
||||
p += scnprintf(p, end - p, "%02u - %02u: %u\n",
|
||||
lower, upper, bcn_dist->bins[i]);
|
||||
|
||||
lower = upper + 1;
|
||||
}
|
||||
|
||||
p += scnprintf(p, end - p, "\ndrift\n");
|
||||
|
||||
for (i = 0; i < bcn_num; i += count) {
|
||||
count = 1;
|
||||
while (i + count < bcn_num && drift[i] == drift[i + count])
|
||||
count++;
|
||||
|
||||
p += scnprintf(p, end - p, "%u: %u\n", drift[i], count);
|
||||
}
|
||||
p += scnprintf(p, end - p, "\nlower bound: %u\n", bcn_dist->lower_bound);
|
||||
p += scnprintf(p, end - p, "upper bound: %u\n", bcn_dist->upper_bound);
|
||||
p += scnprintf(p, end - p, "outlier count: %u\n", bcn_dist->outlier_count);
|
||||
|
||||
p += scnprintf(p, end - p, "\n[Tracking]\n");
|
||||
p += scnprintf(p, end - p, "tbtt offset: %u\n", bcn_track->tbtt_offset);
|
||||
p += scnprintf(p, end - p, "bcn timeout: %u\n", bcn_track->bcn_timeout);
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
#define rtw89_debug_priv_get(name, opts...) \
|
||||
{ \
|
||||
.cb_read = rtw89_debug_priv_ ##name## _get, \
|
||||
@@ -4356,6 +4477,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = {
|
||||
.stations = rtw89_debug_priv_get(stations, RLOCK),
|
||||
.disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK),
|
||||
.mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK),
|
||||
.beacon_info = rtw89_debug_priv_get(beacon_info),
|
||||
};
|
||||
|
||||
#define rtw89_debugfs_add(name, mode, fopname, parent) \
|
||||
@@ -4401,6 +4523,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top
|
||||
rtw89_debugfs_add_r(stations);
|
||||
rtw89_debugfs_add_rw(disable_dm);
|
||||
rtw89_debugfs_add_rw(mlo_mode);
|
||||
rtw89_debugfs_add_r(beacon_info);
|
||||
}
|
||||
|
||||
void rtw89_debugfs_init(struct rtw89_dev *rtwdev)
|
||||
|
||||
@@ -56,6 +56,7 @@ static inline void rtw89_debugfs_deinit(struct rtw89_dev *rtwdev) {}
|
||||
#endif
|
||||
|
||||
#define rtw89_info(rtwdev, a...) dev_info((rtwdev)->dev, ##a)
|
||||
#define rtw89_info_once(rtwdev, a...) dev_info_once((rtwdev)->dev, ##a)
|
||||
#define rtw89_warn(rtwdev, a...) dev_warn((rtwdev)->dev, ##a)
|
||||
#define rtw89_err(rtwdev, a...) dev_err((rtwdev)->dev, ##a)
|
||||
|
||||
|
||||
@@ -830,11 +830,13 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
|
||||
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG),
|
||||
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1),
|
||||
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP),
|
||||
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, BEACON_TRACKING),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 122, 0, BEACON_TRACKING),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG),
|
||||
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1),
|
||||
@@ -846,6 +848,9 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
|
||||
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER),
|
||||
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1),
|
||||
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, BEACON_LOSS_COUNT_V1),
|
||||
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, LPS_DACK_BY_C2H_REG),
|
||||
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, CRASH_TRIGGER_TYPE_1),
|
||||
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING),
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0),
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP),
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD),
|
||||
@@ -864,6 +869,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1),
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG),
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1),
|
||||
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING),
|
||||
};
|
||||
|
||||
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
|
||||
@@ -1280,6 +1286,18 @@ int rtw89_recognize_regd_from_elm(struct rtw89_dev *rtwdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int rtw89_build_afe_pwr_seq_from_elm(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_fw_element_hdr *elm,
|
||||
const union rtw89_fw_element_arg arg)
|
||||
{
|
||||
struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
|
||||
|
||||
elm_info->afe = elm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
|
||||
[RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
|
||||
{ .fw_type = RTW89_FW_BBMCU0 }, NULL},
|
||||
@@ -1365,6 +1383,9 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
|
||||
[RTW89_FW_ELEMENT_ID_REGD] = {
|
||||
rtw89_recognize_regd_from_elm, {}, "REGD",
|
||||
},
|
||||
[RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ] = {
|
||||
rtw89_build_afe_pwr_seq_from_elm, {}, "AFE",
|
||||
},
|
||||
};
|
||||
|
||||
int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
|
||||
@@ -1537,7 +1558,7 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_fw_hdr *fw_hdr;
|
||||
struct sk_buff *skb;
|
||||
u32 truncated;
|
||||
u32 ret = 0;
|
||||
int ret;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
|
||||
if (!skb) {
|
||||
@@ -3990,6 +4011,93 @@ fail:
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be);
|
||||
|
||||
int rtw89_fw_h2c_tbtt_tuning(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link, u32 offset)
|
||||
{
|
||||
struct rtw89_h2c_tbtt_tuning *h2c;
|
||||
u32 len = sizeof(*h2c);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c tbtt tuning\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, len);
|
||||
h2c = (struct rtw89_h2c_tbtt_tuning *)skb->data;
|
||||
|
||||
h2c->w0 = le32_encode_bits(rtwvif_link->phy_idx, RTW89_H2C_TBTT_TUNING_W0_BAND) |
|
||||
le32_encode_bits(rtwvif_link->port, RTW89_H2C_TBTT_TUNING_W0_PORT);
|
||||
h2c->w1 = le32_encode_bits(offset, RTW89_H2C_TBTT_TUNING_W1_SHIFT);
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_PS,
|
||||
H2C_FUNC_TBTT_TUNING, 0, 0,
|
||||
len);
|
||||
|
||||
ret = rtw89_h2c_tx(rtwdev, skb, false);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtw89_fw_h2c_pwr_lvl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
#define RTW89_BCN_TO_VAL_MIN 4
|
||||
#define RTW89_BCN_TO_VAL_MAX 64
|
||||
#define RTW89_DTIM_TO_VAL_MIN 7
|
||||
#define RTW89_DTIM_TO_VAL_MAX 15
|
||||
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
|
||||
struct rtw89_h2c_pwr_lvl *h2c;
|
||||
u32 len = sizeof(*h2c);
|
||||
struct sk_buff *skb;
|
||||
u8 bcn_to_val;
|
||||
int ret;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c pwr lvl\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, len);
|
||||
h2c = (struct rtw89_h2c_pwr_lvl *)skb->data;
|
||||
|
||||
bcn_to_val = clamp_t(u8, bcn_track->bcn_timeout,
|
||||
RTW89_BCN_TO_VAL_MIN, RTW89_BCN_TO_VAL_MAX);
|
||||
|
||||
h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_PWR_LVL_W0_MACID) |
|
||||
le32_encode_bits(bcn_to_val, RTW89_H2C_PWR_LVL_W0_BCN_TO_VAL) |
|
||||
le32_encode_bits(0, RTW89_H2C_PWR_LVL_W0_PS_LVL) |
|
||||
le32_encode_bits(0, RTW89_H2C_PWR_LVL_W0_TRX_LVL) |
|
||||
le32_encode_bits(RTW89_DTIM_TO_VAL_MIN,
|
||||
RTW89_H2C_PWR_LVL_W0_DTIM_TO_VAL);
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_PS,
|
||||
H2C_FUNC_PS_POWER_LEVEL, 0, 0,
|
||||
len);
|
||||
|
||||
ret = rtw89_h2c_tx(rtwdev, skb, false);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link,
|
||||
struct rtw89_sta_link *rtwsta_link,
|
||||
@@ -6580,6 +6688,40 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable)
|
||||
{
|
||||
struct rtw89_h2c_rf_tas *h2c;
|
||||
u32 len = sizeof(*h2c);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c RF TAS\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, len);
|
||||
h2c = (struct rtw89_h2c_rf_tas *)skb->data;
|
||||
|
||||
h2c->enable = cpu_to_le32(enable);
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
|
||||
H2C_FUNC_RFK_TAS_OFFLOAD, 0, 0, len);
|
||||
|
||||
ret = rtw89_h2c_tx(rtwdev, skb, false);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
|
||||
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
|
||||
bool rack, bool dack)
|
||||
@@ -6826,8 +6968,9 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
struct rtw89_fw_info *fw_info = &rtwdev->fw;
|
||||
const u32 *c2h_reg = chip->c2h_regs;
|
||||
u32 ret, timeout;
|
||||
u32 timeout;
|
||||
u8 i, val;
|
||||
int ret;
|
||||
|
||||
info->id = RTW89_FWCMD_C2HREG_FUNC_NULL;
|
||||
|
||||
@@ -6865,7 +7008,7 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_mac_h2c_info *h2c_info,
|
||||
struct rtw89_mac_c2h_info *c2h_info)
|
||||
{
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
if (h2c_info && h2c_info->id != RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE)
|
||||
lockdep_assert_wiphy(rtwdev->hw->wiphy);
|
||||
@@ -7123,7 +7266,6 @@ static void rtw89_pno_scan_add_chan_ax(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pktofld_info *info;
|
||||
u8 probe_count = 0;
|
||||
|
||||
ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK;
|
||||
ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS;
|
||||
ch_info->bw = RTW89_SCAN_WIDTH;
|
||||
ch_info->tx_pkt = true;
|
||||
@@ -7264,7 +7406,6 @@ static void rtw89_pno_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
|
||||
struct rtw89_pktofld_info *info;
|
||||
u8 probe_count = 0, i;
|
||||
|
||||
ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK;
|
||||
ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS;
|
||||
ch_info->bw = RTW89_SCAN_WIDTH;
|
||||
ch_info->tx_null = false;
|
||||
@@ -8585,9 +8726,10 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* not support TKIP yet */
|
||||
h2c->w0 = le32_encode_bits(enable, RTW89_H2C_WOW_GTK_OFLD_W0_EN) |
|
||||
le32_encode_bits(0, RTW89_H2C_WOW_GTK_OFLD_W0_TKIP_EN) |
|
||||
le32_encode_bits(!!memchr_inv(gtk_info->txmickey, 0,
|
||||
sizeof(gtk_info->txmickey)),
|
||||
RTW89_H2C_WOW_GTK_OFLD_W0_TKIP_EN) |
|
||||
le32_encode_bits(gtk_info->igtk_keyid ? 1 : 0,
|
||||
RTW89_H2C_WOW_GTK_OFLD_W0_IEEE80211W_EN) |
|
||||
le32_encode_bits(macid, RTW89_H2C_WOW_GTK_OFLD_W0_MAC_ID) |
|
||||
@@ -8679,19 +8821,30 @@ int rtw89_fw_h2c_wow_request_aoac(struct rtw89_dev *rtwdev)
|
||||
static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
struct rtw89_wait_info *wait, unsigned int cond)
|
||||
{
|
||||
int ret;
|
||||
struct rtw89_wait_response *prep;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_wiphy(rtwdev->hw->wiphy);
|
||||
|
||||
prep = rtw89_wait_for_cond_prep(wait, cond);
|
||||
if (IS_ERR(prep))
|
||||
goto out;
|
||||
|
||||
ret = rtw89_h2c_tx(rtwdev, skb, false);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
|
||||
return 1;
|
||||
if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return rtw89_wait_for_cond(wait, cond);
|
||||
out:
|
||||
return rtw89_wait_for_cond_eval(wait, prep, ret);
|
||||
}
|
||||
|
||||
#define H2C_ADD_MCC_LEN 16
|
||||
|
||||
@@ -1602,6 +1602,28 @@ struct rtw89_h2c_bcn_upd_be {
|
||||
#define RTW89_H2C_BCN_UPD_BE_W7_ECSA_OFST GENMASK(30, 16)
|
||||
#define RTW89_H2C_BCN_UPD_BE_W7_PROTECTION_KEY_ID BIT(31)
|
||||
|
||||
struct rtw89_h2c_tbtt_tuning {
|
||||
__le32 w0;
|
||||
__le32 w1;
|
||||
} __packed;
|
||||
|
||||
#define RTW89_H2C_TBTT_TUNING_W0_BAND GENMASK(3, 0)
|
||||
#define RTW89_H2C_TBTT_TUNING_W0_PORT GENMASK(7, 4)
|
||||
#define RTW89_H2C_TBTT_TUNING_W1_SHIFT GENMASK(31, 0)
|
||||
|
||||
struct rtw89_h2c_pwr_lvl {
|
||||
__le32 w0;
|
||||
__le32 w1;
|
||||
} __packed;
|
||||
|
||||
#define RTW89_H2C_PWR_LVL_W0_MACID GENMASK(7, 0)
|
||||
#define RTW89_H2C_PWR_LVL_W0_BCN_TO_VAL GENMASK(15, 8)
|
||||
#define RTW89_H2C_PWR_LVL_W0_PS_LVL GENMASK(19, 16)
|
||||
#define RTW89_H2C_PWR_LVL_W0_TRX_LVL GENMASK(23, 20)
|
||||
#define RTW89_H2C_PWR_LVL_W0_BCN_TO_LVL GENMASK(27, 24)
|
||||
#define RTW89_H2C_PWR_LVL_W0_DTIM_TO_VAL GENMASK(31, 28)
|
||||
#define RTW89_H2C_PWR_LVL_W1_MACID_EXT GENMASK(7, 0)
|
||||
|
||||
struct rtw89_h2c_role_maintain {
|
||||
__le32 w0;
|
||||
};
|
||||
@@ -3962,6 +3984,7 @@ enum rtw89_fw_element_id {
|
||||
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ = 24,
|
||||
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ = 25,
|
||||
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ = 26,
|
||||
RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ = 27,
|
||||
|
||||
RTW89_FW_ELEMENT_ID_NUM,
|
||||
};
|
||||
@@ -4067,6 +4090,30 @@ struct rtw89_fw_txpwr_track_cfg {
|
||||
BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N) | \
|
||||
BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P))
|
||||
|
||||
enum rtw89_fw_afe_action {
|
||||
RTW89_FW_AFE_ACTION_WRITE = 0,
|
||||
RTW89_FW_AFE_ACTION_DELAY = 1,
|
||||
RTW89_FW_AFE_ACTION_POLL = 2,
|
||||
};
|
||||
|
||||
enum rtw89_fw_afe_cat {
|
||||
RTW89_FW_AFE_CAT_BB = 0,
|
||||
RTW89_FW_AFE_CAT_BB1 = 1,
|
||||
RTW89_FW_AFE_CAT_MAC = 2,
|
||||
RTW89_FW_AFE_CAT_MAC1 = 3,
|
||||
RTW89_FW_AFE_CAT_AFEDIG = 4,
|
||||
RTW89_FW_AFE_CAT_AFEDIG1 = 5,
|
||||
};
|
||||
|
||||
enum rtw89_fw_afe_class {
|
||||
RTW89_FW_AFE_CLASS_P0 = 0,
|
||||
RTW89_FW_AFE_CLASS_P1 = 1,
|
||||
RTW89_FW_AFE_CLASS_P2 = 2,
|
||||
RTW89_FW_AFE_CLASS_P3 = 3,
|
||||
RTW89_FW_AFE_CLASS_P4 = 4,
|
||||
RTW89_FW_AFE_CLASS_CMN = 5,
|
||||
};
|
||||
|
||||
struct rtw89_fw_element_hdr {
|
||||
__le32 id; /* enum rtw89_fw_element_id */
|
||||
__le32 size; /* exclude header size */
|
||||
@@ -4104,6 +4151,17 @@ struct rtw89_fw_element_hdr {
|
||||
u8 rsvd1[3];
|
||||
__le16 offset[];
|
||||
} __packed rfk_log_fmt;
|
||||
struct {
|
||||
u8 rsvd[8];
|
||||
struct rtw89_phy_afe_info {
|
||||
__le32 action; /* enum rtw89_fw_afe_action */
|
||||
__le32 cat; /* enum rtw89_fw_afe_cat */
|
||||
__le32 class; /* enum rtw89_fw_afe_class */
|
||||
__le32 addr;
|
||||
__le32 mask;
|
||||
__le32 val;
|
||||
} __packed infos[];
|
||||
} __packed afe;
|
||||
struct __rtw89_fw_txpwr_element txpwr;
|
||||
struct __rtw89_fw_regd_element regd;
|
||||
} __packed u;
|
||||
@@ -4201,6 +4259,8 @@ enum rtw89_ps_h2c_func {
|
||||
H2C_FUNC_MAC_LPS_PARM = 0x0,
|
||||
H2C_FUNC_P2P_ACT = 0x1,
|
||||
H2C_FUNC_IPS_CFG = 0x3,
|
||||
H2C_FUNC_PS_POWER_LEVEL = 0x7,
|
||||
H2C_FUNC_TBTT_TUNING = 0xA,
|
||||
|
||||
NUM_OF_RTW89_PS_H2C_FUNC,
|
||||
};
|
||||
@@ -4370,6 +4430,7 @@ enum rtw89_rfk_offload_h2c_func {
|
||||
H2C_FUNC_RFK_DACK_OFFLOAD = 0x5,
|
||||
H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6,
|
||||
H2C_FUNC_RFK_PRE_NOTIFY = 0x8,
|
||||
H2C_FUNC_RFK_TAS_OFFLOAD = 0x9,
|
||||
};
|
||||
|
||||
struct rtw89_fw_h2c_rf_get_mccch {
|
||||
@@ -4551,6 +4612,10 @@ struct rtw89_h2c_rf_rxdck_v0 {
|
||||
u8 rxdck_dbg_en;
|
||||
} __packed;
|
||||
|
||||
struct rtw89_h2c_rf_tas {
|
||||
__le32 enable;
|
||||
} __packed;
|
||||
|
||||
struct rtw89_h2c_rf_rxdck {
|
||||
struct rtw89_h2c_rf_rxdck_v0 v0;
|
||||
u8 is_chl_k;
|
||||
@@ -4683,12 +4748,16 @@ struct rtw89_c2h_rfk_report {
|
||||
u8 version;
|
||||
} __packed;
|
||||
|
||||
struct rtw89_c2h_rf_tas_info {
|
||||
struct rtw89_c2h_hdr hdr;
|
||||
struct rtw89_c2h_rf_tas_rpt_log {
|
||||
__le32 cur_idx;
|
||||
__le16 txpwr_history[20];
|
||||
} __packed;
|
||||
|
||||
struct rtw89_c2h_rf_tas_info {
|
||||
struct rtw89_c2h_hdr hdr;
|
||||
struct rtw89_c2h_rf_tas_rpt_log content;
|
||||
} __packed;
|
||||
|
||||
#define RTW89_FW_RSVD_PLE_SIZE 0x800
|
||||
|
||||
#define RTW89_FW_BACKTRACE_INFO_SIZE 8
|
||||
@@ -4750,6 +4819,9 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link);
|
||||
int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link);
|
||||
int rtw89_fw_h2c_tbtt_tuning(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link, u32 offset);
|
||||
int rtw89_fw_h2c_pwr_lvl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
|
||||
int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif,
|
||||
struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr);
|
||||
int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev,
|
||||
@@ -4826,6 +4898,7 @@ int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
|
||||
const struct rtw89_chan *chan);
|
||||
int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
|
||||
const struct rtw89_chan *chan, bool is_chl_k);
|
||||
int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable);
|
||||
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
|
||||
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
|
||||
bool rack, bool dack);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "fw.h"
|
||||
#include "mac.h"
|
||||
#include "pci.h"
|
||||
#include "phy.h"
|
||||
#include "ps.h"
|
||||
#include "reg.h"
|
||||
#include "util.h"
|
||||
@@ -177,7 +178,7 @@ int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_mac_dle_dfi_qempty *qempty)
|
||||
{
|
||||
struct rtw89_mac_dle_dfi_ctrl ctrl;
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
ctrl.type = qempty->dle_type;
|
||||
ctrl.target = DLE_DFI_TYPE_QEMPTY;
|
||||
@@ -985,7 +986,7 @@ static int hfc_upd_ch_info(struct rtw89_dev *rtwdev, u8 ch)
|
||||
struct rtw89_hfc_ch_info *info = param->ch_info;
|
||||
const struct rtw89_hfc_ch_cfg *cfg = param->ch_cfg;
|
||||
u32 val;
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
|
||||
if (ret)
|
||||
@@ -1176,8 +1177,8 @@ int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_e
|
||||
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
u32 dma_ch_mask = chip->dma_ch_mask;
|
||||
int ret = 0;
|
||||
u8 ch;
|
||||
u32 ret = 0;
|
||||
|
||||
if (reset)
|
||||
ret = hfc_reset_param(rtwdev);
|
||||
@@ -1193,7 +1194,7 @@ int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_e
|
||||
if (!en && h2c_en) {
|
||||
mac->hfc_h2c_cfg(rtwdev);
|
||||
mac->hfc_func_en(rtwdev, en, h2c_en);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (ch = RTW89_DMA_ACH0; ch < RTW89_DMA_H2C; ch++) {
|
||||
@@ -2413,7 +2414,7 @@ static int addr_cam_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
|
||||
|
||||
static int scheduler_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
|
||||
{
|
||||
u32 ret;
|
||||
int ret;
|
||||
u32 reg;
|
||||
u32 val;
|
||||
|
||||
@@ -2954,7 +2955,7 @@ static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_mac_h2c_info h2c_info = {};
|
||||
enum rtw89_mac_c2h_type c2h_type;
|
||||
u8 content_len;
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
if (chip->chip_gen == RTW89_CHIP_AX)
|
||||
content_len = 0;
|
||||
@@ -3105,10 +3106,10 @@ int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev)
|
||||
static int rtw89_hw_sch_tx_en_h2c(struct rtw89_dev *rtwdev, u8 band,
|
||||
u16 tx_en_u16, u16 mask_u16)
|
||||
{
|
||||
u32 ret;
|
||||
struct rtw89_mac_c2h_info c2h_info = {0};
|
||||
struct rtw89_mac_h2c_info h2c_info = {0};
|
||||
struct rtw89_h2creg_sch_tx_en *sch_tx_en = &h2c_info.u.sch_tx_en;
|
||||
int ret;
|
||||
|
||||
h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_SCH_TX_EN;
|
||||
h2c_info.content_len = sizeof(*sch_tx_en) - RTW89_H2CREG_HDR_LEN;
|
||||
@@ -4197,6 +4198,7 @@ static const struct rtw89_port_reg rtw89_port_base_ax = {
|
||||
.ptcl_dbg = R_AX_PTCL_DBG,
|
||||
.ptcl_dbg_info = R_AX_PTCL_DBG_INFO,
|
||||
.bcn_drop_all = R_AX_BCN_DROP_ALL0,
|
||||
.bcn_psr_rpt = R_AX_BCN_PSR_RPT_P0,
|
||||
.hiq_win = {R_AX_P0MB_HGQ_WINDOW_CFG_0, R_AX_PORT_HGQ_WINDOW_CFG,
|
||||
R_AX_PORT_HGQ_WINDOW_CFG + 1, R_AX_PORT_HGQ_WINDOW_CFG + 2,
|
||||
R_AX_PORT_HGQ_WINDOW_CFG + 3},
|
||||
@@ -4649,25 +4651,28 @@ static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev,
|
||||
BCN_ERLY_DEF);
|
||||
}
|
||||
|
||||
static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
static void rtw89_mac_port_cfg_bcn_psr_rpt(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
|
||||
const struct rtw89_port_reg *p = mac->port_base;
|
||||
u16 val;
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
u8 bssid_index;
|
||||
u32 reg;
|
||||
|
||||
if (rtwdev->chip->chip_id != RTL8852C)
|
||||
return;
|
||||
rcu_read_lock();
|
||||
|
||||
if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT &&
|
||||
rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION)
|
||||
return;
|
||||
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
|
||||
if (bss_conf->nontransmitted)
|
||||
bssid_index = bss_conf->bssid_index;
|
||||
else
|
||||
bssid_index = 0;
|
||||
|
||||
val = FIELD_PREP(B_AX_TBTT_SHIFT_OFST_MAG, 1) |
|
||||
B_AX_TBTT_SHIFT_OFST_SIGN;
|
||||
rcu_read_unlock();
|
||||
|
||||
rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift,
|
||||
B_AX_TBTT_SHIFT_OFST_MASK, val);
|
||||
reg = rtw89_mac_reg_by_idx(rtwdev, p->bcn_psr_rpt + rtwvif_link->port * 4,
|
||||
rtwvif_link->mac_idx);
|
||||
rtw89_write32_mask(rtwdev, reg, B_AX_BCAID_P0_MASK, bssid_index);
|
||||
}
|
||||
|
||||
void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
|
||||
@@ -4820,13 +4825,13 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvi
|
||||
rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true);
|
||||
rtw89_mac_port_tsf_resync_all(rtwdev);
|
||||
fsleep(BCN_ERLY_SET_DLY);
|
||||
rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif_link);
|
||||
rtw89_mac_port_cfg_bcn_psr_rpt(rtwdev, rtwvif_link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5041,6 +5046,8 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
if (op_chan) {
|
||||
rtw89_mac_enable_aps_bcn_by_chan(rtwdev, op_chan, false);
|
||||
ieee80211_stop_queues(rtwdev->hw);
|
||||
} else {
|
||||
rtw89_phy_nhm_get_result(rtwdev, band, chan);
|
||||
}
|
||||
return;
|
||||
case RTW89_SCAN_END_SCAN_NOTIFY:
|
||||
@@ -5071,6 +5078,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
RTW89_CHANNEL_WIDTH_20);
|
||||
rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx,
|
||||
&new);
|
||||
rtw89_phy_nhm_trigger(rtwdev);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -5235,6 +5243,11 @@ rtw89_mac_c2h_bcn_cnt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
rtw89_mac_c2h_bcn_upd_done(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h,
|
||||
u32 len)
|
||||
@@ -5257,6 +5270,11 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h,
|
||||
rtw89_complete_cond(wait, cond, &data);
|
||||
}
|
||||
|
||||
static void
|
||||
rtw89_mac_c2h_bcn_resend(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
rtw89_mac_c2h_tx_duty_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len)
|
||||
{
|
||||
@@ -5646,7 +5664,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev,
|
||||
[RTW89_MAC_C2H_FUNC_EFUSE_DUMP] = NULL,
|
||||
[RTW89_MAC_C2H_FUNC_READ_RSP] = NULL,
|
||||
[RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP] = rtw89_mac_c2h_pkt_ofld_rsp,
|
||||
[RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL,
|
||||
[RTW89_MAC_C2H_FUNC_BCN_RESEND] = rtw89_mac_c2h_bcn_resend,
|
||||
[RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause,
|
||||
[RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp,
|
||||
[RTW89_MAC_C2H_FUNC_TX_DUTY_RPT] = rtw89_mac_c2h_tx_duty_rpt,
|
||||
@@ -5661,6 +5679,7 @@ void (* const rtw89_mac_c2h_info_handler[])(struct rtw89_dev *rtwdev,
|
||||
[RTW89_MAC_C2H_FUNC_DONE_ACK] = rtw89_mac_c2h_done_ack,
|
||||
[RTW89_MAC_C2H_FUNC_C2H_LOG] = rtw89_mac_c2h_log,
|
||||
[RTW89_MAC_C2H_FUNC_BCN_CNT] = rtw89_mac_c2h_bcn_cnt,
|
||||
[RTW89_MAC_C2H_FUNC_BCN_UPD_DONE] = rtw89_mac_c2h_bcn_upd_done,
|
||||
};
|
||||
|
||||
static
|
||||
@@ -5813,12 +5832,11 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
case RTW89_MAC_C2H_CLASS_ROLE:
|
||||
return;
|
||||
default:
|
||||
rtw89_info(rtwdev, "MAC c2h class %d not support\n", class);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (!handler) {
|
||||
rtw89_info(rtwdev, "MAC c2h class %d func %d not support\n", class,
|
||||
func);
|
||||
rtw89_info_once(rtwdev, "MAC c2h class %d func %d not support\n",
|
||||
class, func);
|
||||
return;
|
||||
}
|
||||
handler(rtwdev, skb, len);
|
||||
@@ -6720,7 +6738,7 @@ int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev,
|
||||
u8 mac_idx = rtwvif_link->mac_idx;
|
||||
u16 set = mac->muedca_ctrl.mask;
|
||||
u32 reg;
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
|
||||
if (ret)
|
||||
@@ -6862,7 +6880,7 @@ int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable)
|
||||
{
|
||||
struct rtw89_mac_h2c_info h2c_info = {};
|
||||
struct rtw89_mac_c2h_info c2h_info = {};
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw))
|
||||
return 0;
|
||||
|
||||
@@ -419,6 +419,7 @@ enum rtw89_mac_c2h_info_func {
|
||||
RTW89_MAC_C2H_FUNC_DONE_ACK,
|
||||
RTW89_MAC_C2H_FUNC_C2H_LOG,
|
||||
RTW89_MAC_C2H_FUNC_BCN_CNT,
|
||||
RTW89_MAC_C2H_FUNC_BCN_UPD_DONE = 0x06,
|
||||
RTW89_MAC_C2H_FUNC_INFO_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -1837,6 +1837,40 @@ static void rtw89_set_rekey_data(struct ieee80211_hw *hw,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rtw89_ops_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct rtw89_dev *rtwdev = hw->priv;
|
||||
struct rtw89_bb_ctx *bb;
|
||||
|
||||
if (idx == 0) {
|
||||
survey->channel = conf->chandef.chan;
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
||||
survey->noise = RTW89_NOISE_DEFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtw89_for_each_active_bb(rtwdev, bb) {
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
struct rtw89_nhm_report *rpt;
|
||||
|
||||
rpt = list_first_entry_or_null(&env->nhm_rpt_list, typeof(*rpt), list);
|
||||
if (!rpt)
|
||||
continue;
|
||||
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
||||
survey->noise = rpt->noise - MAX_RSSI;
|
||||
survey->channel = rpt->channel;
|
||||
list_del_init(&rpt->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void rtw89_ops_rfkill_poll(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rtw89_dev *rtwdev = hw->priv;
|
||||
@@ -1869,6 +1903,7 @@ const struct ieee80211_ops rtw89_ops = {
|
||||
.sta_state = rtw89_ops_sta_state,
|
||||
.set_key = rtw89_ops_set_key,
|
||||
.ampdu_action = rtw89_ops_ampdu_action,
|
||||
.get_survey = rtw89_ops_get_survey,
|
||||
.set_rts_threshold = rtw89_ops_set_rts_threshold,
|
||||
.sta_statistics = rtw89_ops_sta_statistics,
|
||||
.flush = rtw89_ops_flush,
|
||||
|
||||
@@ -56,6 +56,7 @@ static const struct rtw89_port_reg rtw89_port_base_be = {
|
||||
.ptcl_dbg = R_BE_PTCL_DBG,
|
||||
.ptcl_dbg_info = R_BE_PTCL_DBG_INFO,
|
||||
.bcn_drop_all = R_BE_BCN_DROP_ALL0,
|
||||
.bcn_psr_rpt = R_BE_BCN_PSR_RPT_P0,
|
||||
.hiq_win = {R_BE_P0MB_HGQ_WINDOW_CFG_0, R_BE_PORT_HGQ_WINDOW_CFG,
|
||||
R_BE_PORT_HGQ_WINDOW_CFG + 1, R_BE_PORT_HGQ_WINDOW_CFG + 2,
|
||||
R_BE_PORT_HGQ_WINDOW_CFG + 3},
|
||||
|
||||
@@ -134,7 +134,7 @@ static void rtw89_pci_release_fwcmd(struct rtw89_dev *rtwdev,
|
||||
static void rtw89_pci_reclaim_tx_fwcmd(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pci *rtwpci)
|
||||
{
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12];
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[RTW89_TXCH_CH12];
|
||||
u32 cnt;
|
||||
|
||||
cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring);
|
||||
@@ -440,7 +440,7 @@ static int rtw89_pci_poll_rxq_dma(struct rtw89_dev *rtwdev,
|
||||
int countdown = rtwdev->napi_budget_countdown;
|
||||
u32 cnt;
|
||||
|
||||
rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ];
|
||||
rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RXQ];
|
||||
|
||||
cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring);
|
||||
if (!cnt)
|
||||
@@ -464,7 +464,8 @@ static void rtw89_pci_tx_status(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status == RTW89_TX_DONE);
|
||||
if (rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status == RTW89_TX_DONE))
|
||||
return;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
ieee80211_tx_info_clear_status(info);
|
||||
@@ -568,31 +569,52 @@ static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev,
|
||||
rtw89_pci_enqueue_txwd(tx_ring, txwd);
|
||||
}
|
||||
|
||||
static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pci_rpp_fmt *rpp)
|
||||
void rtw89_pci_parse_rpp(struct rtw89_dev *rtwdev, void *_rpp,
|
||||
struct rtw89_pci_rpp_info *rpp_info)
|
||||
{
|
||||
const struct rtw89_pci_rpp_fmt *rpp = _rpp;
|
||||
|
||||
rpp_info->seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ);
|
||||
rpp_info->qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL);
|
||||
rpp_info->tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS);
|
||||
rpp_info->txch = rtw89_chip_get_ch_dma(rtwdev, rpp_info->qsel);
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_parse_rpp);
|
||||
|
||||
void rtw89_pci_parse_rpp_v1(struct rtw89_dev *rtwdev, void *_rpp,
|
||||
struct rtw89_pci_rpp_info *rpp_info)
|
||||
{
|
||||
const struct rtw89_pci_rpp_fmt_v1 *rpp = _rpp;
|
||||
|
||||
rpp_info->seq = le32_get_bits(rpp->w0, RTW89_PCI_RPP_W0_PCIE_SEQ_V1_MASK);
|
||||
rpp_info->qsel = le32_get_bits(rpp->w1, RTW89_PCI_RPP_W1_QSEL_V1_MASK);
|
||||
rpp_info->tx_status = le32_get_bits(rpp->w0, RTW89_PCI_RPP_W0_TX_STATUS_V1_MASK);
|
||||
rpp_info->txch = le32_get_bits(rpp->w0, RTW89_PCI_RPP_W0_DMA_CH_MASK);
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_parse_rpp_v1);
|
||||
|
||||
static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, void *rpp)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_tx_ring *tx_ring;
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
struct rtw89_pci_rpp_info rpp_info = {};
|
||||
struct rtw89_pci_tx_wd_ring *wd_ring;
|
||||
struct rtw89_pci_tx_ring *tx_ring;
|
||||
struct rtw89_pci_tx_wd *txwd;
|
||||
u16 seq;
|
||||
u8 qsel, tx_status, txch;
|
||||
|
||||
seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ);
|
||||
qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL);
|
||||
tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS);
|
||||
txch = rtw89_core_get_ch_dma(rtwdev, qsel);
|
||||
info->parse_rpp(rtwdev, rpp, &rpp_info);
|
||||
|
||||
if (txch == RTW89_TXCH_CH12) {
|
||||
if (rpp_info.txch == RTW89_TXCH_CH12) {
|
||||
rtw89_warn(rtwdev, "should no fwcmd release report\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tx_ring = &rtwpci->tx_rings[txch];
|
||||
tx_ring = &rtwpci->tx.rings[rpp_info.txch];
|
||||
wd_ring = &tx_ring->wd_ring;
|
||||
txwd = &wd_ring->pages[seq];
|
||||
txwd = &wd_ring->pages[rpp_info.seq];
|
||||
|
||||
rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, seq, tx_status);
|
||||
rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, rpp_info.seq,
|
||||
rpp_info.tx_status);
|
||||
}
|
||||
|
||||
static void rtw89_pci_release_pending_txwd_skb(struct rtw89_dev *rtwdev,
|
||||
@@ -617,13 +639,14 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
|
||||
u32 max_cnt)
|
||||
{
|
||||
struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring;
|
||||
struct rtw89_pci_rx_info *rx_info;
|
||||
struct rtw89_pci_rpp_fmt *rpp;
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
struct rtw89_rx_desc_info desc_info = {};
|
||||
struct rtw89_pci_rx_info *rx_info;
|
||||
struct sk_buff *skb;
|
||||
u32 cnt = 0;
|
||||
u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt);
|
||||
void *rpp;
|
||||
u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
|
||||
u32 rpp_size = info->rpp_fmt_size;
|
||||
u32 cnt = 0;
|
||||
u32 skb_idx;
|
||||
u32 offset;
|
||||
int ret;
|
||||
@@ -649,7 +672,7 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
|
||||
/* first segment has RX desc */
|
||||
offset = desc_info.offset + desc_info.rxd_len;
|
||||
for (; offset + rpp_size <= rx_info->len; offset += rpp_size) {
|
||||
rpp = (struct rtw89_pci_rpp_fmt *)(skb->data + offset);
|
||||
rpp = skb->data + offset;
|
||||
rtw89_pci_release_rpp(rtwdev, rpp);
|
||||
}
|
||||
|
||||
@@ -694,7 +717,7 @@ static int rtw89_pci_poll_rpq_dma(struct rtw89_dev *rtwdev,
|
||||
u32 cnt;
|
||||
int work_done;
|
||||
|
||||
rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
|
||||
rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RPQ];
|
||||
|
||||
spin_lock_bh(&rtwpci->trx_lock);
|
||||
|
||||
@@ -724,7 +747,7 @@ static void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RTW89_RXCH_NUM; i++) {
|
||||
rx_ring = &rtwpci->rx_rings[i];
|
||||
rx_ring = &rtwpci->rx.rings[i];
|
||||
bd_ring = &rx_ring->bd_ring;
|
||||
|
||||
reg_idx = rtw89_read32(rtwdev, bd_ring->addr.idx);
|
||||
@@ -797,6 +820,29 @@ void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev,
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2);
|
||||
|
||||
void rtw89_pci_recognize_intrs_v3(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pci *rtwpci,
|
||||
struct rtw89_pci_isrs *isrs)
|
||||
{
|
||||
isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs;
|
||||
isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ?
|
||||
rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0;
|
||||
isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR) & rtwpci->intrs[1];
|
||||
|
||||
/* isrs[0] is not used, so borrow to store RDU status to share common
|
||||
* flow in rtw89_pci_interrupt_threadfn().
|
||||
*/
|
||||
isrs->isrs[0] = isrs->isrs[1] & (B_BE_PCIE_RDU_CH1_INT |
|
||||
B_BE_PCIE_RDU_CH0_INT);
|
||||
|
||||
if (isrs->halt_c2h_isrs)
|
||||
rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs);
|
||||
if (isrs->isrs[1])
|
||||
rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]);
|
||||
rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs);
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v3);
|
||||
|
||||
void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
|
||||
{
|
||||
rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
|
||||
@@ -844,6 +890,21 @@ void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpc
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_disable_intr_v2);
|
||||
|
||||
void rtw89_pci_enable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
|
||||
{
|
||||
rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs);
|
||||
rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]);
|
||||
rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs);
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_enable_intr_v3);
|
||||
|
||||
void rtw89_pci_disable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
|
||||
{
|
||||
rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0);
|
||||
rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_disable_intr_v3);
|
||||
|
||||
static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
@@ -885,7 +946,7 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
|
||||
struct rtw89_dev *rtwdev = dev;
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
const struct rtw89_pci_gen_def *gen_def = info->gen_def;
|
||||
const struct rtw89_pci_isr_def *isr_def = info->isr_def;
|
||||
struct rtw89_pci_isrs isrs;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -893,13 +954,13 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
|
||||
rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs);
|
||||
spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
|
||||
|
||||
if (unlikely(isrs.isrs[0] & gen_def->isr_rdu))
|
||||
if (unlikely(isrs.isrs[0] & isr_def->isr_rdu))
|
||||
rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci);
|
||||
|
||||
if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h))
|
||||
if (unlikely(isrs.halt_c2h_isrs & isr_def->isr_halt_c2h))
|
||||
rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
|
||||
|
||||
if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout))
|
||||
if (unlikely(isrs.halt_c2h_isrs & isr_def->isr_wdt_timeout))
|
||||
rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT);
|
||||
|
||||
if (unlikely(rtwpci->under_recovery))
|
||||
@@ -950,6 +1011,24 @@ exit:
|
||||
return irqret;
|
||||
}
|
||||
|
||||
#define DEF_TXCHADDRS_TYPE3(gen, ch_idx, txch, v...) \
|
||||
[RTW89_TXCH_##ch_idx] = { \
|
||||
.num = R_##gen##_##txch##_TXBD_CFG, \
|
||||
.idx = R_##gen##_##txch##_TXBD_IDX ##v, \
|
||||
.bdram = 0, \
|
||||
.desa_l = 0, \
|
||||
.desa_h = 0, \
|
||||
}
|
||||
|
||||
#define DEF_TXCHADDRS_TYPE3_GRP_BASE(gen, ch_idx, txch, grp, v...) \
|
||||
[RTW89_TXCH_##ch_idx] = { \
|
||||
.num = R_##gen##_##txch##_TXBD_CFG, \
|
||||
.idx = R_##gen##_##txch##_TXBD_IDX ##v, \
|
||||
.bdram = 0, \
|
||||
.desa_l = R_##gen##_##grp##_TXBD_DESA_L, \
|
||||
.desa_h = R_##gen##_##grp##_TXBD_DESA_H, \
|
||||
}
|
||||
|
||||
#define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \
|
||||
[RTW89_TXCH_##ch_idx] = { \
|
||||
.num = R_##gen##_##txch##_TXBD_NUM ##v, \
|
||||
@@ -977,6 +1056,22 @@ exit:
|
||||
.desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \
|
||||
}
|
||||
|
||||
#define DEF_RXCHADDRS_TYPE3(gen, ch_idx, rxch, v...) \
|
||||
[RTW89_RXCH_##ch_idx] = { \
|
||||
.num = R_##gen##_RX_##rxch##_RXBD_CONFIG, \
|
||||
.idx = R_##gen##_##ch_idx##0_RXBD_IDX ##v, \
|
||||
.desa_l = 0, \
|
||||
.desa_h = 0, \
|
||||
}
|
||||
|
||||
#define DEF_RXCHADDRS_TYPE3_GRP_BASE(gen, ch_idx, rxch, grp, v...) \
|
||||
[RTW89_RXCH_##ch_idx] = { \
|
||||
.num = R_##gen##_RX_##rxch##_RXBD_CONFIG, \
|
||||
.idx = R_##gen##_##ch_idx##0_RXBD_IDX ##v, \
|
||||
.desa_l = R_##gen##_##grp##_RXBD_DESA_L, \
|
||||
.desa_h = R_##gen##_##grp##_RXBD_DESA_H, \
|
||||
}
|
||||
|
||||
#define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \
|
||||
[RTW89_RXCH_##ch_idx] = { \
|
||||
.num = R_##gen##_##rxch##_RXBD_NUM ##v, \
|
||||
@@ -1054,8 +1149,36 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = {
|
||||
};
|
||||
EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be);
|
||||
|
||||
const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be_v1 = {
|
||||
.tx = {
|
||||
DEF_TXCHADDRS_TYPE3_GRP_BASE(BE, ACH0, CH0, ACQ, _V1),
|
||||
/* no CH1 */
|
||||
DEF_TXCHADDRS_TYPE3(BE, ACH2, CH2, _V1),
|
||||
/* no CH3 */
|
||||
DEF_TXCHADDRS_TYPE3(BE, ACH4, CH4, _V1),
|
||||
/* no CH5 */
|
||||
DEF_TXCHADDRS_TYPE3(BE, ACH6, CH6, _V1),
|
||||
/* no CH7 */
|
||||
DEF_TXCHADDRS_TYPE3_GRP_BASE(BE, CH8, CH8, NACQ, _V1),
|
||||
/* no CH9 */
|
||||
DEF_TXCHADDRS_TYPE3(BE, CH10, CH10, _V1),
|
||||
/* no CH11 */
|
||||
DEF_TXCHADDRS_TYPE3(BE, CH12, CH12, _V1),
|
||||
},
|
||||
.rx = {
|
||||
DEF_RXCHADDRS_TYPE3_GRP_BASE(BE, RXQ, CH0, HOST0, _V1),
|
||||
DEF_RXCHADDRS_TYPE3(BE, RPQ, CH1, _V1),
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be_v1);
|
||||
|
||||
#undef DEF_TXCHADDRS_TYPE3
|
||||
#undef DEF_TXCHADDRS_TYPE3_GRP_BASE
|
||||
#undef DEF_TXCHADDRS_TYPE2
|
||||
#undef DEF_TXCHADDRS_TYPE1
|
||||
#undef DEF_TXCHADDRS
|
||||
#undef DEF_RXCHADDRS_TYPE3
|
||||
#undef DEF_RXCHADDRS_TYPE3_GRP_BASE
|
||||
#undef DEF_RXCHADDRS
|
||||
|
||||
static int rtw89_pci_get_txch_addrs(struct rtw89_dev *rtwdev,
|
||||
@@ -1101,7 +1224,7 @@ static
|
||||
u32 __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12];
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[RTW89_TXCH_CH12];
|
||||
u32 cnt;
|
||||
|
||||
spin_lock_bh(&rtwpci->trx_lock);
|
||||
@@ -1117,7 +1240,7 @@ u32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev,
|
||||
u8 txch)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch];
|
||||
struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
|
||||
u32 cnt;
|
||||
|
||||
@@ -1134,7 +1257,7 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
|
||||
u8 txch)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch];
|
||||
struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring;
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
u32 bd_cnt, wd_cnt, min_cnt = 0;
|
||||
@@ -1142,7 +1265,7 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
|
||||
enum rtw89_debug_mask debug_mask;
|
||||
u32 cnt;
|
||||
|
||||
rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
|
||||
rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RPQ];
|
||||
|
||||
spin_lock_bh(&rtwpci->trx_lock);
|
||||
bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
|
||||
@@ -1227,7 +1350,7 @@ static void rtw89_pci_tx_bd_ring_update(struct rtw89_dev *rtwdev, struct rtw89_p
|
||||
static void rtw89_pci_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch];
|
||||
|
||||
if (rtwdev->hci.paused) {
|
||||
set_bit(txch, rtwpci->kick_map);
|
||||
@@ -1247,7 +1370,7 @@ static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev)
|
||||
if (!test_and_clear_bit(txch, rtwpci->kick_map))
|
||||
continue;
|
||||
|
||||
tx_ring = &rtwpci->tx_rings[txch];
|
||||
tx_ring = &rtwpci->tx.rings[txch];
|
||||
__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
|
||||
}
|
||||
}
|
||||
@@ -1255,7 +1378,7 @@ static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev)
|
||||
static void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
|
||||
struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch];
|
||||
struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
|
||||
u32 cur_idx, cur_rp;
|
||||
u8 i;
|
||||
@@ -1371,7 +1494,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev = rtwpci->pdev;
|
||||
struct sk_buff *skb = tx_req->skb;
|
||||
struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb);
|
||||
struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
|
||||
bool en_wd_info = desc_info->en_wd_info;
|
||||
u32 txwd_len;
|
||||
u32 txwp_len;
|
||||
@@ -1387,7 +1509,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev,
|
||||
}
|
||||
|
||||
tx_data->dma = dma;
|
||||
rcu_assign_pointer(skb_data->wait, NULL);
|
||||
|
||||
txwp_len = sizeof(*txwp_info);
|
||||
txwd_len = chip->txwd_body_size;
|
||||
@@ -1521,7 +1642,7 @@ static int rtw89_pci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_req
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tx_ring = &rtwpci->tx_rings[txch];
|
||||
tx_ring = &rtwpci->tx.rings[txch];
|
||||
spin_lock_bh(&rtwpci->trx_lock);
|
||||
|
||||
n_avail_txbd = rtw89_pci_get_avail_txbd_num(tx_ring);
|
||||
@@ -1607,6 +1728,41 @@ static void rtw89_pci_init_wp_16sel(struct rtw89_dev *rtwdev)
|
||||
}
|
||||
}
|
||||
|
||||
static u16 rtw89_pci_enc_bd_cfg(struct rtw89_dev *rtwdev, u16 bd_num,
|
||||
u32 dma_offset)
|
||||
{
|
||||
u16 dma_offset_sel;
|
||||
u16 num_sel;
|
||||
|
||||
/* B_BE_TX_NUM_SEL_MASK, B_BE_RX_NUM_SEL_MASK:
|
||||
* 0 -> 0
|
||||
* 1 -> 64 = 2^6
|
||||
* 2 -> 128 = 2^7
|
||||
* ...
|
||||
* 7 -> 4096 = 2^12
|
||||
*/
|
||||
num_sel = ilog2(bd_num) - 5;
|
||||
|
||||
if (hweight16(bd_num) != 1)
|
||||
rtw89_warn(rtwdev, "bd_num %u is not power of 2\n", bd_num);
|
||||
|
||||
/* B_BE_TX_START_OFFSET_MASK, B_BE_RX_START_OFFSET_MASK:
|
||||
* 0 -> 0 = 0 * 2^9
|
||||
* 1 -> 512 = 1 * 2^9
|
||||
* 2 -> 1024 = 2 * 2^9
|
||||
* 3 -> 1536 = 3 * 2^9
|
||||
* ...
|
||||
* 255 -> 130560 = 255 * 2^9
|
||||
*/
|
||||
dma_offset_sel = dma_offset >> 9;
|
||||
|
||||
if (dma_offset % 512)
|
||||
rtw89_warn(rtwdev, "offset %u is not multiple of 512\n", dma_offset);
|
||||
|
||||
return u16_encode_bits(num_sel, B_BE_TX_NUM_SEL_MASK) |
|
||||
u16_encode_bits(dma_offset_sel, B_BE_TX_START_OFFSET_MASK);
|
||||
}
|
||||
|
||||
static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
@@ -1616,10 +1772,12 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||
struct rtw89_pci_rx_ring *rx_ring;
|
||||
struct rtw89_pci_dma_ring *bd_ring;
|
||||
const struct rtw89_pci_bd_ram *bd_ram;
|
||||
dma_addr_t group_dma_base = 0;
|
||||
u16 num_or_offset;
|
||||
u32 addr_desa_l;
|
||||
u32 addr_bdram;
|
||||
u32 addr_num;
|
||||
u32 addr_idx;
|
||||
u32 addr_bdram;
|
||||
u32 addr_desa_l;
|
||||
u32 val32;
|
||||
int i;
|
||||
|
||||
@@ -1627,7 +1785,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||
if (info->tx_dma_ch_mask & BIT(i))
|
||||
continue;
|
||||
|
||||
tx_ring = &rtwpci->tx_rings[i];
|
||||
tx_ring = &rtwpci->tx.rings[i];
|
||||
bd_ring = &tx_ring->bd_ring;
|
||||
bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL;
|
||||
addr_num = bd_ring->addr.num;
|
||||
@@ -1636,7 +1794,18 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||
bd_ring->wp = 0;
|
||||
bd_ring->rp = 0;
|
||||
|
||||
rtw89_write16(rtwdev, addr_num, bd_ring->len);
|
||||
if (info->group_bd_addr) {
|
||||
if (addr_desa_l)
|
||||
group_dma_base = bd_ring->dma;
|
||||
|
||||
num_or_offset =
|
||||
rtw89_pci_enc_bd_cfg(rtwdev, bd_ring->len,
|
||||
bd_ring->dma - group_dma_base);
|
||||
} else {
|
||||
num_or_offset = bd_ring->len;
|
||||
}
|
||||
rtw89_write16(rtwdev, addr_num, num_or_offset);
|
||||
|
||||
if (addr_bdram && bd_ram) {
|
||||
val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) |
|
||||
FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) |
|
||||
@@ -1644,12 +1813,14 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||
|
||||
rtw89_write32(rtwdev, addr_bdram, val32);
|
||||
}
|
||||
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
|
||||
rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma));
|
||||
if (addr_desa_l) {
|
||||
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
|
||||
rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < RTW89_RXCH_NUM; i++) {
|
||||
rx_ring = &rtwpci->rx_rings[i];
|
||||
rx_ring = &rtwpci->rx.rings[i];
|
||||
bd_ring = &rx_ring->bd_ring;
|
||||
addr_num = bd_ring->addr.num;
|
||||
addr_idx = bd_ring->addr.idx;
|
||||
@@ -1663,9 +1834,22 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
|
||||
rx_ring->diliver_desc.ready = false;
|
||||
rx_ring->target_rx_tag = 0;
|
||||
|
||||
rtw89_write16(rtwdev, addr_num, bd_ring->len);
|
||||
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
|
||||
rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma));
|
||||
if (info->group_bd_addr) {
|
||||
if (addr_desa_l)
|
||||
group_dma_base = bd_ring->dma;
|
||||
|
||||
num_or_offset =
|
||||
rtw89_pci_enc_bd_cfg(rtwdev, bd_ring->len,
|
||||
bd_ring->dma - group_dma_base);
|
||||
} else {
|
||||
num_or_offset = bd_ring->len;
|
||||
}
|
||||
rtw89_write16(rtwdev, addr_num, num_or_offset);
|
||||
|
||||
if (addr_desa_l) {
|
||||
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
|
||||
rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma));
|
||||
}
|
||||
|
||||
if (info->rx_ring_eq_is_full)
|
||||
rtw89_write16(rtwdev, addr_idx, bd_ring->wp);
|
||||
@@ -1698,7 +1882,7 @@ void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev)
|
||||
skb_queue_len(&rtwpci->h2c_queue), true);
|
||||
continue;
|
||||
}
|
||||
rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx_rings[txch]);
|
||||
rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx.rings[txch]);
|
||||
}
|
||||
spin_unlock_bh(&rtwpci->trx_lock);
|
||||
}
|
||||
@@ -1774,14 +1958,14 @@ void rtw89_pci_switch_bd_idx_addr(struct rtw89_dev *rtwdev, bool low_power)
|
||||
return;
|
||||
|
||||
for (i = 0; i < RTW89_TXCH_NUM; i++) {
|
||||
tx_ring = &rtwpci->tx_rings[i];
|
||||
tx_ring = &rtwpci->tx.rings[i];
|
||||
tx_ring->bd_ring.addr.idx = low_power ?
|
||||
bd_idx_addr->tx_bd_addrs[i] :
|
||||
dma_addr_set->tx[i].idx;
|
||||
}
|
||||
|
||||
for (i = 0; i < RTW89_RXCH_NUM; i++) {
|
||||
rx_ring = &rtwpci->rx_rings[i];
|
||||
rx_ring = &rtwpci->rx.rings[i];
|
||||
rx_ring->bd_ring.addr.idx = low_power ?
|
||||
bd_idx_addr->rx_bd_addrs[i] :
|
||||
dma_addr_set->rx[i].idx;
|
||||
@@ -2725,7 +2909,7 @@ static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev)
|
||||
|
||||
static int rtw89_pci_poll_dma_all_idle(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
ret = rtw89_pci_poll_txdma_ch_idle_ax(rtwdev);
|
||||
if (ret) {
|
||||
@@ -3211,15 +3395,6 @@ static void rtw89_pci_free_tx_ring(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev,
|
||||
struct rtw89_pci_tx_ring *tx_ring)
|
||||
{
|
||||
int ring_sz;
|
||||
u8 *head;
|
||||
dma_addr_t dma;
|
||||
|
||||
head = tx_ring->bd_ring.head;
|
||||
dma = tx_ring->bd_ring.dma;
|
||||
ring_sz = tx_ring->bd_ring.desc_size * tx_ring->bd_ring.len;
|
||||
dma_free_coherent(&pdev->dev, ring_sz, head, dma);
|
||||
|
||||
tx_ring->bd_ring.head = NULL;
|
||||
}
|
||||
|
||||
@@ -3227,6 +3402,7 @@ static void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_dma_pool *bd_pool = &rtwpci->tx.bd_pool;
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
struct rtw89_pci_tx_ring *tx_ring;
|
||||
int i;
|
||||
@@ -3234,10 +3410,12 @@ static void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev,
|
||||
for (i = 0; i < RTW89_TXCH_NUM; i++) {
|
||||
if (info->tx_dma_ch_mask & BIT(i))
|
||||
continue;
|
||||
tx_ring = &rtwpci->tx_rings[i];
|
||||
tx_ring = &rtwpci->tx.rings[i];
|
||||
rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring);
|
||||
rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring);
|
||||
}
|
||||
|
||||
dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma);
|
||||
}
|
||||
|
||||
static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev,
|
||||
@@ -3248,8 +3426,6 @@ static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev,
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma;
|
||||
u32 buf_sz;
|
||||
u8 *head;
|
||||
int ring_sz = rx_ring->bd_ring.desc_size * rx_ring->bd_ring.len;
|
||||
int i;
|
||||
|
||||
buf_sz = rx_ring->buf_sz;
|
||||
@@ -3265,10 +3441,6 @@ static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev,
|
||||
rx_ring->buf[i] = NULL;
|
||||
}
|
||||
|
||||
head = rx_ring->bd_ring.head;
|
||||
dma = rx_ring->bd_ring.dma;
|
||||
dma_free_coherent(&pdev->dev, ring_sz, head, dma);
|
||||
|
||||
rx_ring->bd_ring.head = NULL;
|
||||
}
|
||||
|
||||
@@ -3276,13 +3448,16 @@ static void rtw89_pci_free_rx_rings(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_dma_pool *bd_pool = &rtwpci->rx.bd_pool;
|
||||
struct rtw89_pci_rx_ring *rx_ring;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RTW89_RXCH_NUM; i++) {
|
||||
rx_ring = &rtwpci->rx_rings[i];
|
||||
rx_ring = &rtwpci->rx.rings[i];
|
||||
rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring);
|
||||
}
|
||||
|
||||
dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma);
|
||||
}
|
||||
|
||||
static void rtw89_pci_free_trx_rings(struct rtw89_dev *rtwdev,
|
||||
@@ -3374,12 +3549,10 @@ static int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev,
|
||||
struct rtw89_pci_tx_ring *tx_ring,
|
||||
u32 desc_size, u32 len,
|
||||
enum rtw89_tx_channel txch)
|
||||
enum rtw89_tx_channel txch,
|
||||
void *head, dma_addr_t dma)
|
||||
{
|
||||
const struct rtw89_pci_ch_dma_addr *txch_addr;
|
||||
int ring_sz = desc_size * len;
|
||||
u8 *head;
|
||||
dma_addr_t dma;
|
||||
int ret;
|
||||
|
||||
ret = rtw89_pci_alloc_tx_wd_ring(rtwdev, pdev, tx_ring, txch);
|
||||
@@ -3394,12 +3567,6 @@ static int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev,
|
||||
goto err_free_wd_ring;
|
||||
}
|
||||
|
||||
head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
|
||||
if (!head) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_wd_ring;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&tx_ring->busy_pages);
|
||||
tx_ring->bd_ring.head = head;
|
||||
tx_ring->bd_ring.dma = dma;
|
||||
@@ -3422,25 +3589,48 @@ static int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_dma_pool *bd_pool = &rtwpci->tx.bd_pool;
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
struct rtw89_pci_tx_ring *tx_ring;
|
||||
u32 desc_size;
|
||||
u32 len;
|
||||
u32 i, tx_allocated;
|
||||
dma_addr_t dma;
|
||||
u32 desc_size;
|
||||
u32 ring_sz;
|
||||
u32 pool_sz;
|
||||
u32 ch_num;
|
||||
void *head;
|
||||
u32 len;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(RTW89_PCI_TXBD_NUM_MAX % 16);
|
||||
|
||||
desc_size = sizeof(struct rtw89_pci_tx_bd_32);
|
||||
len = RTW89_PCI_TXBD_NUM_MAX;
|
||||
ch_num = RTW89_TXCH_NUM - hweight32(info->tx_dma_ch_mask);
|
||||
ring_sz = desc_size * len;
|
||||
pool_sz = ring_sz * ch_num;
|
||||
|
||||
head = dma_alloc_coherent(&pdev->dev, pool_sz, &dma, GFP_KERNEL);
|
||||
if (!head)
|
||||
return -ENOMEM;
|
||||
|
||||
bd_pool->head = head;
|
||||
bd_pool->dma = dma;
|
||||
bd_pool->size = pool_sz;
|
||||
|
||||
for (i = 0; i < RTW89_TXCH_NUM; i++) {
|
||||
if (info->tx_dma_ch_mask & BIT(i))
|
||||
continue;
|
||||
tx_ring = &rtwpci->tx_rings[i];
|
||||
desc_size = sizeof(struct rtw89_pci_tx_bd_32);
|
||||
len = RTW89_PCI_TXBD_NUM_MAX;
|
||||
tx_ring = &rtwpci->tx.rings[i];
|
||||
ret = rtw89_pci_alloc_tx_ring(rtwdev, pdev, tx_ring,
|
||||
desc_size, len, i);
|
||||
desc_size, len, i, head, dma);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to alloc tx ring %d\n", i);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
head += ring_sz;
|
||||
dma += ring_sz;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -3448,24 +3638,24 @@ static int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev,
|
||||
err_free:
|
||||
tx_allocated = i;
|
||||
for (i = 0; i < tx_allocated; i++) {
|
||||
tx_ring = &rtwpci->tx_rings[i];
|
||||
tx_ring = &rtwpci->tx.rings[i];
|
||||
rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring);
|
||||
}
|
||||
|
||||
dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev,
|
||||
struct rtw89_pci_rx_ring *rx_ring,
|
||||
u32 desc_size, u32 len, u32 rxch)
|
||||
u32 desc_size, u32 len, u32 rxch,
|
||||
void *head, dma_addr_t dma)
|
||||
{
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
const struct rtw89_pci_ch_dma_addr *rxch_addr;
|
||||
struct sk_buff *skb;
|
||||
u8 *head;
|
||||
dma_addr_t dma;
|
||||
int ring_sz = desc_size * len;
|
||||
int buf_sz = RTW89_PCI_RX_BUF_SIZE;
|
||||
int i, allocated;
|
||||
int ret;
|
||||
@@ -3476,12 +3666,6 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL);
|
||||
if (!head) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rx_ring->bd_ring.head = head;
|
||||
rx_ring->bd_ring.dma = dma;
|
||||
rx_ring->bd_ring.len = len;
|
||||
@@ -3530,12 +3714,8 @@ err_free:
|
||||
rx_ring->buf[i] = NULL;
|
||||
}
|
||||
|
||||
head = rx_ring->bd_ring.head;
|
||||
dma = rx_ring->bd_ring.dma;
|
||||
dma_free_coherent(&pdev->dev, ring_sz, head, dma);
|
||||
|
||||
rx_ring->bd_ring.head = NULL;
|
||||
err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3543,22 +3723,43 @@ static int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
struct rtw89_pci_dma_pool *bd_pool = &rtwpci->rx.bd_pool;
|
||||
struct rtw89_pci_rx_ring *rx_ring;
|
||||
u32 desc_size;
|
||||
u32 len;
|
||||
int i, rx_allocated;
|
||||
dma_addr_t dma;
|
||||
u32 desc_size;
|
||||
u32 ring_sz;
|
||||
u32 pool_sz;
|
||||
void *head;
|
||||
u32 len;
|
||||
int ret;
|
||||
|
||||
desc_size = sizeof(struct rtw89_pci_rx_bd_32);
|
||||
len = RTW89_PCI_RXBD_NUM_MAX;
|
||||
ring_sz = desc_size * len;
|
||||
pool_sz = ring_sz * RTW89_RXCH_NUM;
|
||||
|
||||
head = dma_alloc_coherent(&pdev->dev, pool_sz, &dma, GFP_KERNEL);
|
||||
if (!head)
|
||||
return -ENOMEM;
|
||||
|
||||
bd_pool->head = head;
|
||||
bd_pool->dma = dma;
|
||||
bd_pool->size = pool_sz;
|
||||
|
||||
for (i = 0; i < RTW89_RXCH_NUM; i++) {
|
||||
rx_ring = &rtwpci->rx_rings[i];
|
||||
desc_size = sizeof(struct rtw89_pci_rx_bd_32);
|
||||
len = RTW89_PCI_RXBD_NUM_MAX;
|
||||
rx_ring = &rtwpci->rx.rings[i];
|
||||
|
||||
ret = rtw89_pci_alloc_rx_ring(rtwdev, pdev, rx_ring,
|
||||
desc_size, len, i);
|
||||
desc_size, len, i,
|
||||
head, dma);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "failed to alloc rx ring %d\n", i);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
head += ring_sz;
|
||||
dma += ring_sz;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -3566,10 +3767,12 @@ static int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev,
|
||||
err_free:
|
||||
rx_allocated = i;
|
||||
for (i = 0; i < rx_allocated; i++) {
|
||||
rx_ring = &rtwpci->rx_rings[i];
|
||||
rx_ring = &rtwpci->rx.rings[i];
|
||||
rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring);
|
||||
}
|
||||
|
||||
dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3776,6 +3979,40 @@ void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev)
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2);
|
||||
|
||||
static void rtw89_pci_recovery_intr_mask_v3(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
|
||||
rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0;
|
||||
rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
|
||||
rtwpci->intrs[0] = 0;
|
||||
rtwpci->intrs[1] = 0;
|
||||
}
|
||||
|
||||
static void rtw89_pci_default_intr_mask_v3(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
|
||||
rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0;
|
||||
rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
|
||||
rtwpci->intrs[0] = 0;
|
||||
rtwpci->intrs[1] = B_BE_PCIE_RDU_CH1_IMR |
|
||||
B_BE_PCIE_RDU_CH0_IMR |
|
||||
B_BE_PCIE_RX_RX0P2_IMR0_V1 |
|
||||
B_BE_PCIE_RX_RPQ0_IMR0_V1;
|
||||
}
|
||||
|
||||
void rtw89_pci_config_intr_mask_v3(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
|
||||
if (rtwpci->under_recovery)
|
||||
rtw89_pci_recovery_intr_mask_v3(rtwdev);
|
||||
else
|
||||
rtw89_pci_default_intr_mask_v3(rtwdev);
|
||||
}
|
||||
EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v3);
|
||||
|
||||
static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
@@ -4158,7 +4395,7 @@ static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev)
|
||||
|
||||
static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
u32 ret;
|
||||
int ret;
|
||||
|
||||
if (rtwdev->chip->chip_id == RTL8852C)
|
||||
return 0;
|
||||
@@ -4172,7 +4409,7 @@ static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev)
|
||||
return ret;
|
||||
|
||||
rtw89_pci_ctrl_dma_all(rtwdev, true);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev,
|
||||
@@ -4228,18 +4465,18 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget)
|
||||
struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi);
|
||||
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
|
||||
const struct rtw89_pci_info *info = rtwdev->pci_info;
|
||||
const struct rtw89_pci_gen_def *gen_def = info->gen_def;
|
||||
const struct rtw89_pci_isr_def *isr_def = info->isr_def;
|
||||
unsigned long flags;
|
||||
int work_done;
|
||||
|
||||
rtwdev->napi_budget_countdown = budget;
|
||||
|
||||
rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data);
|
||||
rtw89_write32(rtwdev, isr_def->isr_clear_rpq.addr, isr_def->isr_clear_rpq.data);
|
||||
work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
|
||||
if (work_done == budget)
|
||||
return budget;
|
||||
|
||||
rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data);
|
||||
rtw89_write32(rtwdev, isr_def->isr_clear_rxq.addr, isr_def->isr_clear_rxq.data);
|
||||
work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
|
||||
if (work_done < budget && napi_complete_done(napi, work_done)) {
|
||||
spin_lock_irqsave(&rtwpci->irq_lock, flags);
|
||||
@@ -4394,14 +4631,17 @@ const struct pci_error_handlers rtw89_pci_err_handler = {
|
||||
};
|
||||
EXPORT_SYMBOL(rtw89_pci_err_handler);
|
||||
|
||||
const struct rtw89_pci_gen_def rtw89_pci_gen_ax = {
|
||||
const struct rtw89_pci_isr_def rtw89_pci_isr_ax = {
|
||||
.isr_rdu = B_AX_RDU_INT,
|
||||
.isr_halt_c2h = B_AX_HALT_C2H_INT_EN,
|
||||
.isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN,
|
||||
.isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT},
|
||||
.isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT |
|
||||
B_AX_RDU_INT},
|
||||
};
|
||||
EXPORT_SYMBOL(rtw89_pci_isr_ax);
|
||||
|
||||
const struct rtw89_pci_gen_def rtw89_pci_gen_ax = {
|
||||
.mac_pre_init = rtw89_pci_ops_mac_pre_init_ax,
|
||||
.mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_ax,
|
||||
.mac_post_init = rtw89_pci_ops_mac_post_init_ax,
|
||||
|
||||
@@ -372,6 +372,14 @@
|
||||
#define B_BE_HS0ISR_IND_INT BIT(0)
|
||||
|
||||
#define R_BE_PCIE_DMA_IMR_0_V1 0x30B8
|
||||
#define B_BE_PCIE_RDU_CH7_IMR BIT(31)
|
||||
#define B_BE_PCIE_RDU_CH6_IMR BIT(30)
|
||||
#define B_BE_PCIE_RDU_CH5_IMR BIT(29)
|
||||
#define B_BE_PCIE_RDU_CH4_IMR BIT(28)
|
||||
#define B_BE_PCIE_RDU_CH3_IMR BIT(27)
|
||||
#define B_BE_PCIE_RDU_CH2_IMR BIT(26)
|
||||
#define B_BE_PCIE_RDU_CH1_IMR BIT(25)
|
||||
#define B_BE_PCIE_RDU_CH0_IMR BIT(24)
|
||||
#define B_BE_PCIE_RX_RX1P1_IMR0_V1 BIT(23)
|
||||
#define B_BE_PCIE_RX_RX0P1_IMR0_V1 BIT(22)
|
||||
#define B_BE_PCIE_RX_ROQ1_IMR0_V1 BIT(21)
|
||||
@@ -397,6 +405,14 @@
|
||||
#define B_BE_PCIE_TX_CH0_IMR0 BIT(0)
|
||||
|
||||
#define R_BE_PCIE_DMA_ISR 0x30BC
|
||||
#define B_BE_PCIE_RDU_CH7_INT BIT(31)
|
||||
#define B_BE_PCIE_RDU_CH6_INT BIT(30)
|
||||
#define B_BE_PCIE_RDU_CH5_INT BIT(29)
|
||||
#define B_BE_PCIE_RDU_CH4_INT BIT(28)
|
||||
#define B_BE_PCIE_RDU_CH3_INT BIT(27)
|
||||
#define B_BE_PCIE_RDU_CH2_INT BIT(26)
|
||||
#define B_BE_PCIE_RDU_CH1_INT BIT(25)
|
||||
#define B_BE_PCIE_RDU_CH0_INT BIT(24)
|
||||
#define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23)
|
||||
#define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22)
|
||||
#define B_BE_PCIE_RX_ROQ1_ISR_V1 BIT(21)
|
||||
@@ -426,9 +442,13 @@
|
||||
#define B_BE_RDU_CH4_INT_IMR_V1 BIT(29)
|
||||
#define B_BE_RDU_CH3_INT_IMR_V1 BIT(28)
|
||||
#define B_BE_RDU_CH2_INT_IMR_V1 BIT(27)
|
||||
#define B_BE_RDU_CH1_INT_EN_V2 BIT(27)
|
||||
#define B_BE_RDU_CH1_INT_IMR_V1 BIT(26)
|
||||
#define B_BE_RDU_CH0_INT_EN_V2 BIT(26)
|
||||
#define B_BE_RDU_CH0_INT_IMR_V1 BIT(25)
|
||||
#define B_BE_RXDMA_STUCK_INT_EN_V2 BIT(25)
|
||||
#define B_BE_RXDMA_STUCK_INT_EN_V1 BIT(24)
|
||||
#define B_BE_TXDMA_STUCK_INT_EN_V2 BIT(24)
|
||||
#define B_BE_TXDMA_STUCK_INT_EN_V1 BIT(23)
|
||||
#define B_BE_TXDMA_CH14_INT_EN_V1 BIT(22)
|
||||
#define B_BE_TXDMA_CH13_INT_EN_V1 BIT(21)
|
||||
@@ -459,9 +479,13 @@
|
||||
#define B_BE_RDU_CH4_INT_V1 BIT(29)
|
||||
#define B_BE_RDU_CH3_INT_V1 BIT(28)
|
||||
#define B_BE_RDU_CH2_INT_V1 BIT(27)
|
||||
#define B_BE_RDU_CH1_INT_V2 BIT(27)
|
||||
#define B_BE_RDU_CH1_INT_V1 BIT(26)
|
||||
#define B_BE_RDU_CH0_INT_V2 BIT(26)
|
||||
#define B_BE_RDU_CH0_INT_V1 BIT(25)
|
||||
#define B_BE_RXDMA_STUCK_INT_V2 BIT(25)
|
||||
#define B_BE_RXDMA_STUCK_INT_V1 BIT(24)
|
||||
#define B_BE_TXDMA_STUCK_INT_V2 BIT(24)
|
||||
#define B_BE_TXDMA_STUCK_INT_V1 BIT(23)
|
||||
#define B_BE_TXDMA_CH14_INT_V1 BIT(22)
|
||||
#define B_BE_TXDMA_CH13_INT_V1 BIT(21)
|
||||
@@ -784,9 +808,25 @@
|
||||
#define R_BE_CH13_TXBD_NUM_V1 0xB04C
|
||||
#define R_BE_CH14_TXBD_NUM_V1 0xB04E
|
||||
|
||||
#define R_BE_CH0_TXBD_CFG 0xB030
|
||||
#define R_BE_CH2_TXBD_CFG 0xB034
|
||||
#define R_BE_CH4_TXBD_CFG 0xB038
|
||||
#define R_BE_CH6_TXBD_CFG 0xB03C
|
||||
#define R_BE_CH8_TXBD_CFG 0xB040
|
||||
#define R_BE_CH10_TXBD_CFG 0xB044
|
||||
#define R_BE_CH12_TXBD_CFG 0xB048
|
||||
#define B_BE_TX_FLAG BIT(14)
|
||||
#define B_BE_TX_START_OFFSET_MASK GENMASK(12, 4)
|
||||
#define B_BE_TX_NUM_SEL_MASK GENMASK(2, 0)
|
||||
|
||||
#define R_BE_RXQ0_RXBD_NUM_V1 0xB050
|
||||
#define R_BE_RPQ0_RXBD_NUM_V1 0xB052
|
||||
|
||||
#define R_BE_RX_CH0_RXBD_CONFIG 0xB050
|
||||
#define R_BE_RX_CH1_RXBD_CONFIG 0xB052
|
||||
#define B_BE_RX_START_OFFSET_MASK GENMASK(11, 4)
|
||||
#define B_BE_RX_NUM_SEL_MASK GENMASK(2, 0)
|
||||
|
||||
#define R_BE_CH0_TXBD_IDX_V1 0xB100
|
||||
#define R_BE_CH1_TXBD_IDX_V1 0xB104
|
||||
#define R_BE_CH2_TXBD_IDX_V1 0xB108
|
||||
@@ -837,11 +877,25 @@
|
||||
#define R_BE_CH14_TXBD_DESA_L_V1 0xB270
|
||||
#define R_BE_CH14_TXBD_DESA_H_V1 0xB274
|
||||
|
||||
#define R_BE_ACQ_TXBD_DESA_L 0xB200
|
||||
#define B_BE_TX_ACQ_DESA_L_MASK GENMASK(31, 3)
|
||||
#define R_BE_ACQ_TXBD_DESA_H 0xB204
|
||||
#define B_BE_TX_ACQ_DESA_H_MASK GENMASK(7, 0)
|
||||
#define R_BE_NACQ_TXBD_DESA_L 0xB240
|
||||
#define B_BE_TX_NACQ_DESA_L_MASK GENMASK(31, 3)
|
||||
#define R_BE_NACQ_TXBD_DESA_H 0xB244
|
||||
#define B_BE_TX_NACQ_DESA_H_MASK GENMASK(7, 0)
|
||||
|
||||
#define R_BE_RXQ0_RXBD_DESA_L_V1 0xB300
|
||||
#define R_BE_RXQ0_RXBD_DESA_H_V1 0xB304
|
||||
#define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308
|
||||
#define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C
|
||||
|
||||
#define R_BE_HOST0_RXBD_DESA_L 0xB300
|
||||
#define B_BE_RX_HOST0_DESA_L_MASK GENMASK(31, 3)
|
||||
#define R_BE_HOST0_RXBD_DESA_H 0xB304
|
||||
#define B_BE_RX_HOST0_DESA_H_MASK GENMASK(7, 0)
|
||||
|
||||
#define R_BE_WP_ADDR_H_SEL0_3_V1 0xB420
|
||||
#define R_BE_WP_ADDR_H_SEL4_7_V1 0xB424
|
||||
#define R_BE_WP_ADDR_H_SEL8_11_V1 0xB428
|
||||
@@ -1249,7 +1303,7 @@ struct rtw89_pci_bd_idx_addr {
|
||||
};
|
||||
|
||||
struct rtw89_pci_ch_dma_addr {
|
||||
u32 num;
|
||||
u32 num; /* also `offset` addr for group_bd_addr design */
|
||||
u32 idx;
|
||||
u32 bdram;
|
||||
u32 desa_l;
|
||||
@@ -1267,13 +1321,15 @@ struct rtw89_pci_bd_ram {
|
||||
u8 min_num;
|
||||
};
|
||||
|
||||
struct rtw89_pci_gen_def {
|
||||
struct rtw89_pci_isr_def {
|
||||
u32 isr_rdu;
|
||||
u32 isr_halt_c2h;
|
||||
u32 isr_wdt_timeout;
|
||||
struct rtw89_reg2_def isr_clear_rpq;
|
||||
struct rtw89_reg2_def isr_clear_rxq;
|
||||
};
|
||||
|
||||
struct rtw89_pci_gen_def {
|
||||
int (*mac_pre_init)(struct rtw89_dev *rtwdev);
|
||||
int (*mac_pre_deinit)(struct rtw89_dev *rtwdev);
|
||||
int (*mac_post_init)(struct rtw89_dev *rtwdev);
|
||||
@@ -1309,8 +1365,16 @@ struct rtw89_pci_ssid_quirk {
|
||||
unsigned long bitmap; /* bitmap of rtw89_quirks */
|
||||
};
|
||||
|
||||
struct rtw89_pci_rpp_info {
|
||||
u16 seq;
|
||||
u8 qsel;
|
||||
u8 tx_status;
|
||||
u8 txch;
|
||||
};
|
||||
|
||||
struct rtw89_pci_info {
|
||||
const struct rtw89_pci_gen_def *gen_def;
|
||||
const struct rtw89_pci_isr_def *isr_def;
|
||||
enum mac_ax_bd_trunc_mode txbd_trunc_mode;
|
||||
enum mac_ax_bd_trunc_mode rxbd_trunc_mode;
|
||||
enum mac_ax_rxbd_mode rxbd_mode;
|
||||
@@ -1328,6 +1392,8 @@ struct rtw89_pci_info {
|
||||
bool rx_ring_eq_is_full;
|
||||
bool check_rx_tag;
|
||||
bool no_rxbd_fs;
|
||||
bool group_bd_addr;
|
||||
u32 rpp_fmt_size;
|
||||
|
||||
u32 init_cfg_reg;
|
||||
u32 txhci_en_bit;
|
||||
@@ -1357,6 +1423,8 @@ struct rtw89_pci_info {
|
||||
u32 (*fill_txaddr_info)(struct rtw89_dev *rtwdev,
|
||||
void *txaddr_info_addr, u32 total_len,
|
||||
dma_addr_t dma, u8 *add_info_nr);
|
||||
void (*parse_rpp)(struct rtw89_dev *rtwdev, void *rpp,
|
||||
struct rtw89_pci_rpp_info *rpp_info);
|
||||
void (*config_intr_mask)(struct rtw89_dev *rtwdev);
|
||||
void (*enable_intr)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void (*disable_intr)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
@@ -1430,6 +1498,19 @@ struct rtw89_pci_rpp_fmt {
|
||||
__le32 dword;
|
||||
} __packed;
|
||||
|
||||
#define RTW89_PCI_RPP_W0_MACID_V1_MASK GENMASK(9, 0)
|
||||
#define RTW89_PCI_RPP_W0_DMA_CH_MASK GENMASK(13, 10)
|
||||
#define RTW89_PCI_RPP_W0_TX_STATUS_V1_MASK GENMASK(16, 14)
|
||||
#define RTW89_PCI_RPP_W0_PCIE_SEQ_V1_MASK GENMASK(31, 17)
|
||||
#define RTW89_PCI_RPP_W1_QSEL_V1_MASK GENMASK(5, 0)
|
||||
#define RTW89_PCI_RPP_W1_TID_IND BIT(6)
|
||||
#define RTW89_PCI_RPP_W1_CHANGE_LINK BIT(7)
|
||||
|
||||
struct rtw89_pci_rpp_fmt_v1 {
|
||||
__le32 w0;
|
||||
__le32 w1;
|
||||
} __packed;
|
||||
|
||||
struct rtw89_pci_rx_bd_32 {
|
||||
__le16 buf_size;
|
||||
__le16 opt;
|
||||
@@ -1468,6 +1549,12 @@ struct rtw89_pci_dma_ring {
|
||||
u32 rp; /* hw idx */
|
||||
};
|
||||
|
||||
struct rtw89_pci_dma_pool {
|
||||
void *head;
|
||||
dma_addr_t dma;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct rtw89_pci_tx_wd_ring {
|
||||
void *head;
|
||||
dma_addr_t dma;
|
||||
@@ -1497,6 +1584,11 @@ struct rtw89_pci_tx_ring {
|
||||
u64 tx_mac_id_drop;
|
||||
};
|
||||
|
||||
struct rtw89_pci_tx_rings {
|
||||
struct rtw89_pci_tx_ring rings[RTW89_TXCH_NUM];
|
||||
struct rtw89_pci_dma_pool bd_pool;
|
||||
};
|
||||
|
||||
struct rtw89_pci_rx_ring {
|
||||
struct rtw89_pci_dma_ring bd_ring;
|
||||
struct sk_buff *buf[RTW89_PCI_RXBD_NUM_MAX];
|
||||
@@ -1506,6 +1598,11 @@ struct rtw89_pci_rx_ring {
|
||||
u32 target_rx_tag:13;
|
||||
};
|
||||
|
||||
struct rtw89_pci_rx_rings {
|
||||
struct rtw89_pci_rx_ring rings[RTW89_RXCH_NUM];
|
||||
struct rtw89_pci_dma_pool bd_pool;
|
||||
};
|
||||
|
||||
struct rtw89_pci_isrs {
|
||||
u32 ind_isrs;
|
||||
u32 halt_c2h_isrs;
|
||||
@@ -1523,8 +1620,8 @@ struct rtw89_pci {
|
||||
bool low_power;
|
||||
bool under_recovery;
|
||||
bool enable_dac;
|
||||
struct rtw89_pci_tx_ring tx_rings[RTW89_TXCH_NUM];
|
||||
struct rtw89_pci_rx_ring rx_rings[RTW89_RXCH_NUM];
|
||||
struct rtw89_pci_tx_rings tx;
|
||||
struct rtw89_pci_rx_rings rx;
|
||||
struct sk_buff_head h2c_queue;
|
||||
struct sk_buff_head h2c_release_queue;
|
||||
DECLARE_BITMAP(kick_map, RTW89_TXCH_NUM);
|
||||
@@ -1537,10 +1634,7 @@ struct rtw89_pci {
|
||||
|
||||
static inline struct rtw89_pci_rx_info *RTW89_PCI_RX_SKB_CB(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct rtw89_pci_tx_data) >
|
||||
sizeof(info->status.status_driver_data));
|
||||
BUILD_BUG_ON(sizeof(struct rtw89_pci_rx_info) > sizeof(skb->cb));
|
||||
|
||||
return (struct rtw89_pci_rx_info *)skb->cb;
|
||||
}
|
||||
@@ -1571,6 +1665,10 @@ static inline struct rtw89_pci_tx_data *RTW89_PCI_TX_SKB_CB(struct sk_buff *skb)
|
||||
{
|
||||
struct rtw89_tx_skb_data *data = RTW89_TX_SKB_CB(skb);
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct rtw89_tx_skb_data) +
|
||||
sizeof(struct rtw89_pci_tx_data) >
|
||||
sizeof_field(struct ieee80211_tx_info, driver_data));
|
||||
|
||||
return (struct rtw89_pci_tx_data *)data->hci_priv;
|
||||
}
|
||||
|
||||
@@ -1626,8 +1724,12 @@ extern const struct pci_error_handlers rtw89_pci_err_handler;
|
||||
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set;
|
||||
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1;
|
||||
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be;
|
||||
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be_v1;
|
||||
extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM];
|
||||
extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM];
|
||||
extern const struct rtw89_pci_isr_def rtw89_pci_isr_ax;
|
||||
extern const struct rtw89_pci_isr_def rtw89_pci_isr_be;
|
||||
extern const struct rtw89_pci_isr_def rtw89_pci_isr_be_v1;
|
||||
extern const struct rtw89_pci_gen_def rtw89_pci_gen_ax;
|
||||
extern const struct rtw89_pci_gen_def rtw89_pci_gen_be;
|
||||
|
||||
@@ -1646,16 +1748,23 @@ u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev,
|
||||
u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev,
|
||||
void *txaddr_info_addr, u32 total_len,
|
||||
dma_addr_t dma, u8 *add_info_nr);
|
||||
void rtw89_pci_parse_rpp(struct rtw89_dev *rtwdev, void *_rpp,
|
||||
struct rtw89_pci_rpp_info *rpp_info);
|
||||
void rtw89_pci_parse_rpp_v1(struct rtw89_dev *rtwdev, void *_rpp,
|
||||
struct rtw89_pci_rpp_info *rpp_info);
|
||||
void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable);
|
||||
void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev);
|
||||
void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev);
|
||||
void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev);
|
||||
void rtw89_pci_config_intr_mask_v3(struct rtw89_dev *rtwdev);
|
||||
void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_enable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_disable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
|
||||
void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pci *rtwpci,
|
||||
struct rtw89_pci_isrs *isrs);
|
||||
@@ -1665,6 +1774,9 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
|
||||
void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pci *rtwpci,
|
||||
struct rtw89_pci_isrs *isrs);
|
||||
void rtw89_pci_recognize_intrs_v3(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_pci *rtwpci,
|
||||
struct rtw89_pci_isrs *isrs);
|
||||
|
||||
static inline
|
||||
u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev,
|
||||
|
||||
@@ -175,10 +175,10 @@ static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev)
|
||||
rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1,
|
||||
B_BE_CLR_RXQ0_IDX | B_BE_CLR_RPQ0_IDX);
|
||||
|
||||
rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ];
|
||||
rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RXQ];
|
||||
rtw89_write16(rtwdev, R_BE_RXQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1);
|
||||
|
||||
rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
|
||||
rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RPQ];
|
||||
rtw89_write16(rtwdev, R_BE_RPQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1);
|
||||
}
|
||||
|
||||
@@ -665,13 +665,25 @@ static int __maybe_unused rtw89_pci_resume_be(struct device *dev)
|
||||
SIMPLE_DEV_PM_OPS(rtw89_pm_ops_be, rtw89_pci_suspend_be, rtw89_pci_resume_be);
|
||||
EXPORT_SYMBOL(rtw89_pm_ops_be);
|
||||
|
||||
const struct rtw89_pci_gen_def rtw89_pci_gen_be = {
|
||||
const struct rtw89_pci_isr_def rtw89_pci_isr_be = {
|
||||
.isr_rdu = B_BE_RDU_CH1_INT_V1 | B_BE_RDU_CH0_INT_V1,
|
||||
.isr_halt_c2h = B_BE_HALT_C2H_INT,
|
||||
.isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT,
|
||||
.isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1},
|
||||
.isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1},
|
||||
};
|
||||
EXPORT_SYMBOL(rtw89_pci_isr_be);
|
||||
|
||||
const struct rtw89_pci_isr_def rtw89_pci_isr_be_v1 = {
|
||||
.isr_rdu = B_BE_PCIE_RDU_CH1_INT | B_BE_PCIE_RDU_CH0_INT,
|
||||
.isr_halt_c2h = B_BE_HALT_C2H_INT,
|
||||
.isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT,
|
||||
.isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1},
|
||||
.isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1},
|
||||
};
|
||||
EXPORT_SYMBOL(rtw89_pci_isr_be_v1);
|
||||
|
||||
const struct rtw89_pci_gen_def rtw89_pci_gen_be = {
|
||||
.mac_pre_init = rtw89_pci_ops_mac_pre_init_be,
|
||||
.mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be,
|
||||
.mac_post_init = rtw89_pci_ops_mac_post_init_be,
|
||||
|
||||
@@ -1702,6 +1702,91 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
|
||||
rtw89_phy_bb_reset(rtwdev);
|
||||
}
|
||||
|
||||
void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
|
||||
const struct rtw89_fw_element_hdr *afe_elm = elm_info->afe;
|
||||
const struct rtw89_phy_afe_info *info;
|
||||
u32 action, cat, class;
|
||||
u32 addr, mask, val;
|
||||
u32 poll, rpt;
|
||||
u32 n, i;
|
||||
|
||||
if (!afe_elm)
|
||||
return;
|
||||
|
||||
n = le32_to_cpu(afe_elm->size) / sizeof(*info);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
info = &afe_elm->u.afe.infos[i];
|
||||
|
||||
class = le32_to_cpu(info->class);
|
||||
switch (class) {
|
||||
case RTW89_FW_AFE_CLASS_P0:
|
||||
case RTW89_FW_AFE_CLASS_P1:
|
||||
case RTW89_FW_AFE_CLASS_CMN:
|
||||
/* Currently support two paths */
|
||||
break;
|
||||
case RTW89_FW_AFE_CLASS_P2:
|
||||
case RTW89_FW_AFE_CLASS_P3:
|
||||
case RTW89_FW_AFE_CLASS_P4:
|
||||
default:
|
||||
rtw89_warn(rtwdev, "unexpected AFE class %u\n", class);
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = le32_to_cpu(info->addr);
|
||||
mask = le32_to_cpu(info->mask);
|
||||
val = le32_to_cpu(info->val);
|
||||
cat = le32_to_cpu(info->cat);
|
||||
action = le32_to_cpu(info->action);
|
||||
|
||||
switch (action) {
|
||||
case RTW89_FW_AFE_ACTION_WRITE:
|
||||
switch (cat) {
|
||||
case RTW89_FW_AFE_CAT_MAC:
|
||||
case RTW89_FW_AFE_CAT_MAC1:
|
||||
rtw89_write32_mask(rtwdev, addr, mask, val);
|
||||
break;
|
||||
case RTW89_FW_AFE_CAT_AFEDIG:
|
||||
case RTW89_FW_AFE_CAT_AFEDIG1:
|
||||
rtw89_write32_mask(rtwdev, addr, mask, val);
|
||||
break;
|
||||
case RTW89_FW_AFE_CAT_BB:
|
||||
rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_0);
|
||||
break;
|
||||
case RTW89_FW_AFE_CAT_BB1:
|
||||
rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1);
|
||||
break;
|
||||
default:
|
||||
rtw89_warn(rtwdev,
|
||||
"unexpected AFE writing action %u\n", action);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RTW89_FW_AFE_ACTION_POLL:
|
||||
for (poll = 0; poll <= 10; poll++) {
|
||||
/*
|
||||
* For CAT_BB, AFE reads register with mcu_offset 0,
|
||||
* so both CAT_MAC and CAT_BB use the same method.
|
||||
*/
|
||||
rpt = rtw89_read32_mask(rtwdev, addr, mask);
|
||||
if (rpt == val)
|
||||
goto poll_done;
|
||||
|
||||
fsleep(1);
|
||||
}
|
||||
rtw89_warn(rtwdev, "failed to poll AFE cat=%u addr=0x%x mask=0x%x\n",
|
||||
cat, addr, mask);
|
||||
poll_done:
|
||||
break;
|
||||
case RTW89_FW_AFE_ACTION_DELAY:
|
||||
fsleep(addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
rtw89_phy_write32(rtwdev, 0x8080, 0x4);
|
||||
@@ -2943,7 +3028,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
|
||||
}
|
||||
|
||||
if (mode == RTW89_RA_RPT_MODE_LEGACY) {
|
||||
valid = rtw89_ra_report_to_bitrate(rtwdev, rate, &legacy_bitrate);
|
||||
valid = rtw89_legacy_rate_to_bitrate(rtwdev, rate, &legacy_bitrate);
|
||||
if (!valid)
|
||||
return;
|
||||
}
|
||||
@@ -3087,6 +3172,34 @@ void (* const rtw89_phy_c2h_dm_handler[])(struct rtw89_dev *rtwdev,
|
||||
[RTW89_PHY_C2H_DM_FUNC_FW_SCAN] = rtw89_phy_c2h_fw_scan_rpt,
|
||||
};
|
||||
|
||||
static
|
||||
void rtw89_phy_c2h_rfk_tas_pwr(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_c2h_rf_tas_rpt_log *content)
|
||||
{
|
||||
const enum rtw89_sar_sources src = rtwdev->sar.src;
|
||||
struct rtw89_tas_info *tas = &rtwdev->tas;
|
||||
u64 linear = 0;
|
||||
u32 i, cur_idx;
|
||||
s16 txpwr;
|
||||
|
||||
if (!tas->enable || src == RTW89_SAR_SOURCE_NONE)
|
||||
return;
|
||||
|
||||
cur_idx = le32_to_cpu(content->cur_idx);
|
||||
for (i = 0; i < cur_idx; i++) {
|
||||
txpwr = le16_to_cpu(content->txpwr_history[i]);
|
||||
linear += rtw89_db_quarter_to_linear(txpwr);
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_SAR,
|
||||
"tas: index: %u, txpwr: %d\n", i, txpwr);
|
||||
}
|
||||
|
||||
if (cur_idx == 0)
|
||||
tas->instant_txpwr = rtw89_db_to_linear(0);
|
||||
else
|
||||
tas->instant_txpwr = DIV_ROUND_DOWN_ULL(linear, cur_idx);
|
||||
}
|
||||
|
||||
static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
|
||||
enum rtw89_phy_c2h_rfk_log_func func,
|
||||
void *content, u16 len)
|
||||
@@ -3338,6 +3451,13 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
|
||||
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[1] = %*ph\n",
|
||||
(int)sizeof(txgapk->power_d[1]), txgapk->power_d[1]);
|
||||
return;
|
||||
case RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR:
|
||||
if (len != sizeof(struct rtw89_c2h_rf_tas_rpt_log))
|
||||
goto out;
|
||||
|
||||
rtw89_phy_c2h_rfk_tas_pwr(rtwdev, content);
|
||||
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -3390,9 +3510,6 @@ static void rtw89_phy_c2h_rfk_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
|
||||
u16 chunk_len;
|
||||
bool handled;
|
||||
|
||||
if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK))
|
||||
return;
|
||||
|
||||
log_ptr += sizeof(*c2h_hdr);
|
||||
len -= sizeof(*c2h_hdr);
|
||||
|
||||
@@ -3469,6 +3586,13 @@ rtw89_phy_c2h_rfk_log_txgapk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK, "TXGAPK");
|
||||
}
|
||||
|
||||
static void
|
||||
rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
|
||||
{
|
||||
rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR, "TAS");
|
||||
}
|
||||
|
||||
static
|
||||
void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
|
||||
struct sk_buff *c2h, u32 len) = {
|
||||
@@ -3478,6 +3602,7 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
|
||||
[RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK] = rtw89_phy_c2h_rfk_log_rxdck,
|
||||
[RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI] = rtw89_phy_c2h_rfk_log_tssi,
|
||||
[RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk,
|
||||
[RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr,
|
||||
};
|
||||
|
||||
static
|
||||
@@ -3540,39 +3665,19 @@ rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u3
|
||||
}
|
||||
|
||||
static void
|
||||
rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
|
||||
rtw89_phy_c2h_rfk_report_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
|
||||
{
|
||||
const struct rtw89_c2h_rf_tas_info *rf_tas =
|
||||
const struct rtw89_c2h_rf_tas_info *report =
|
||||
(const struct rtw89_c2h_rf_tas_info *)c2h->data;
|
||||
const enum rtw89_sar_sources src = rtwdev->sar.src;
|
||||
struct rtw89_tas_info *tas = &rtwdev->tas;
|
||||
u64 linear = 0;
|
||||
u32 i, cur_idx;
|
||||
s16 txpwr;
|
||||
|
||||
if (!tas->enable || src == RTW89_SAR_SOURCE_NONE)
|
||||
return;
|
||||
|
||||
cur_idx = le32_to_cpu(rf_tas->cur_idx);
|
||||
for (i = 0; i < cur_idx; i++) {
|
||||
txpwr = (s16)le16_to_cpu(rf_tas->txpwr_history[i]);
|
||||
linear += rtw89_db_quarter_to_linear(txpwr);
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_SAR,
|
||||
"tas: index: %u, txpwr: %d\n", i, txpwr);
|
||||
}
|
||||
|
||||
if (cur_idx == 0)
|
||||
tas->instant_txpwr = rtw89_db_to_linear(0);
|
||||
else
|
||||
tas->instant_txpwr = DIV_ROUND_DOWN_ULL(linear, cur_idx);
|
||||
rtw89_phy_c2h_rfk_tas_pwr(rtwdev, &report->content);
|
||||
}
|
||||
|
||||
static
|
||||
void (* const rtw89_phy_c2h_rfk_report_handler[])(struct rtw89_dev *rtwdev,
|
||||
struct sk_buff *c2h, u32 len) = {
|
||||
[RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE] = rtw89_phy_c2h_rfk_report_state,
|
||||
[RTW89_PHY_C2H_RFK_LOG_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr,
|
||||
[RTW89_PHY_C2H_RFK_REPORT_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_report_tas_pwr,
|
||||
};
|
||||
|
||||
bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func)
|
||||
@@ -3626,12 +3731,11 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
|
||||
handler = rtw89_phy_c2h_dm_handler[func];
|
||||
break;
|
||||
default:
|
||||
rtw89_info(rtwdev, "PHY c2h class %d not support\n", class);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (!handler) {
|
||||
rtw89_info(rtwdev, "PHY c2h class %d func %d not support\n", class,
|
||||
func);
|
||||
rtw89_info_once(rtwdev, "PHY c2h class %d func %d not support\n",
|
||||
class, func);
|
||||
return;
|
||||
}
|
||||
handler(rtwdev, skb, len);
|
||||
@@ -5497,6 +5601,34 @@ static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev,
|
||||
i + 1, env->ifs_clm_th_l[i], env->ifs_clm_th_h[i]);
|
||||
}
|
||||
|
||||
static void __rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
const struct rtw89_ccx_regs *ccx = phy->ccx;
|
||||
|
||||
env->nhm_include_cca = false;
|
||||
env->nhm_mntr_time = 0;
|
||||
env->nhm_sum = 0;
|
||||
|
||||
rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_config, ccx->nhm_en_mask, bb->phy_idx);
|
||||
rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_method, ccx->nhm_pwr_method_msk,
|
||||
bb->phy_idx);
|
||||
}
|
||||
|
||||
void rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
struct rtw89_bb_ctx *bb;
|
||||
|
||||
if (!chip->support_noise)
|
||||
return;
|
||||
|
||||
rtw89_for_each_active_bb(rtwdev, bb)
|
||||
__rtw89_phy_nhm_setting_init(rtwdev, bb);
|
||||
}
|
||||
|
||||
static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
@@ -5558,7 +5690,7 @@ static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev,
|
||||
}
|
||||
|
||||
static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb)
|
||||
struct rtw89_bb_ctx *bb, u8 sel)
|
||||
{
|
||||
const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
@@ -5568,10 +5700,17 @@ static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev,
|
||||
bb->phy_idx);
|
||||
rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 0,
|
||||
bb->phy_idx);
|
||||
if (sel & RTW89_PHY_ENV_MON_NHM)
|
||||
rtw89_phy_write32_idx_clr(rtwdev, ccx->nhm_config,
|
||||
ccx->nhm_en_mask, bb->phy_idx);
|
||||
|
||||
rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_clm_cnt_clear_mask, 1,
|
||||
bb->phy_idx);
|
||||
rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 1,
|
||||
bb->phy_idx);
|
||||
if (sel & RTW89_PHY_ENV_MON_NHM)
|
||||
rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_config,
|
||||
ccx->nhm_en_mask, bb->phy_idx);
|
||||
|
||||
env->ccx_ongoing = true;
|
||||
}
|
||||
@@ -5642,6 +5781,125 @@ static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev,
|
||||
env->ifs_clm_cca_avg[i]);
|
||||
}
|
||||
|
||||
static u8 rtw89_nhm_weighted_avg(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
u8 nhm_weight[RTW89_NHM_RPT_NUM];
|
||||
u32 nhm_weighted_sum = 0;
|
||||
u8 weight_zero;
|
||||
u8 i;
|
||||
|
||||
if (env->nhm_sum == 0)
|
||||
return 0;
|
||||
|
||||
weight_zero = clamp_t(u16, env->nhm_th[0] - RTW89_NHM_WEIGHT_OFFSET, 0, U8_MAX);
|
||||
|
||||
for (i = 0; i < RTW89_NHM_RPT_NUM; i++) {
|
||||
if (i == 0)
|
||||
nhm_weight[i] = weight_zero;
|
||||
else if (i == (RTW89_NHM_RPT_NUM - 1))
|
||||
nhm_weight[i] = env->nhm_th[i - 1] + RTW89_NHM_WEIGHT_OFFSET;
|
||||
else
|
||||
nhm_weight[i] = (env->nhm_th[i - 1] + env->nhm_th[i]) / 2;
|
||||
}
|
||||
|
||||
if (rtwdev->chip->chip_id == RTL8852A || rtwdev->chip->chip_id == RTL8852B ||
|
||||
rtwdev->chip->chip_id == RTL8852C) {
|
||||
if (env->nhm_th[RTW89_NHM_TH_NUM - 1] == RTW89_NHM_WA_TH) {
|
||||
nhm_weight[RTW89_NHM_RPT_NUM - 1] =
|
||||
env->nhm_th[RTW89_NHM_TH_NUM - 2] +
|
||||
RTW89_NHM_WEIGHT_OFFSET;
|
||||
nhm_weight[RTW89_NHM_RPT_NUM - 2] =
|
||||
nhm_weight[RTW89_NHM_RPT_NUM - 1];
|
||||
}
|
||||
|
||||
env->nhm_result[0] += env->nhm_result[RTW89_NHM_RPT_NUM - 1];
|
||||
env->nhm_result[RTW89_NHM_RPT_NUM - 1] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < RTW89_NHM_RPT_NUM; i++)
|
||||
nhm_weighted_sum += env->nhm_result[i] * nhm_weight[i];
|
||||
|
||||
return (nhm_weighted_sum / env->nhm_sum) >> RTW89_NHM_TH_FACTOR;
|
||||
}
|
||||
|
||||
static void __rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb, enum rtw89_band hw_band,
|
||||
u16 ch_hw_value)
|
||||
{
|
||||
const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
const struct rtw89_ccx_regs *ccx = phy->ccx;
|
||||
struct ieee80211_supported_band *sband;
|
||||
const struct rtw89_reg_def *nhm_rpt;
|
||||
enum nl80211_band band;
|
||||
u32 sum = 0;
|
||||
u8 chan_idx;
|
||||
u8 nhm_pwr;
|
||||
u8 i;
|
||||
|
||||
if (!rtw89_phy_read32_idx(rtwdev, ccx->nhm, ccx->nhm_ready, bb->phy_idx)) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "[NHM] Get NHM report Fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < RTW89_NHM_RPT_NUM; i++) {
|
||||
nhm_rpt = &(*chip->nhm_report)[i];
|
||||
|
||||
env->nhm_result[i] =
|
||||
rtw89_phy_read32_idx(rtwdev, nhm_rpt->addr,
|
||||
nhm_rpt->mask, bb->phy_idx);
|
||||
sum += env->nhm_result[i];
|
||||
}
|
||||
env->nhm_sum = sum;
|
||||
nhm_pwr = rtw89_nhm_weighted_avg(rtwdev, bb);
|
||||
|
||||
if (!ch_hw_value)
|
||||
return;
|
||||
|
||||
band = rtw89_hw_to_nl80211_band(hw_band);
|
||||
sband = rtwdev->hw->wiphy->bands[band];
|
||||
if (!sband)
|
||||
return;
|
||||
|
||||
for (chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) {
|
||||
struct ieee80211_channel *channel;
|
||||
struct rtw89_nhm_report *rpt;
|
||||
struct list_head *nhm_list;
|
||||
|
||||
channel = &sband->channels[chan_idx];
|
||||
if (channel->hw_value != ch_hw_value)
|
||||
continue;
|
||||
|
||||
rpt = &env->nhm_his[hw_band][chan_idx];
|
||||
nhm_list = &env->nhm_rpt_list;
|
||||
|
||||
rpt->channel = channel;
|
||||
rpt->noise = nhm_pwr;
|
||||
|
||||
if (list_empty(&rpt->list))
|
||||
list_add_tail(&rpt->list, nhm_list);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "[NHM] channel not found\n");
|
||||
}
|
||||
|
||||
void rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev, enum rtw89_band hw_band,
|
||||
u16 ch_hw_value)
|
||||
{
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
struct rtw89_bb_ctx *bb;
|
||||
|
||||
if (!chip->support_noise)
|
||||
return;
|
||||
|
||||
rtw89_for_each_active_bb(rtwdev, bb)
|
||||
__rtw89_phy_nhm_get_result(rtwdev, bb, hw_band, ch_hw_value);
|
||||
}
|
||||
|
||||
static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
@@ -5742,6 +6000,107 @@ static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rtw89_phy_nhm_th_update(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
static const u8 nhm_th_11k[RTW89_NHM_RPT_NUM] = {
|
||||
18, 21, 24, 27, 30, 35, 40, 45, 50, 55, 60, 0
|
||||
};
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
const struct rtw89_reg_def *nhm_th;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < RTW89_NHM_RPT_NUM; i++)
|
||||
env->nhm_th[i] = nhm_th_11k[i] << RTW89_NHM_TH_FACTOR;
|
||||
|
||||
if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
|
||||
chip->chip_id == RTL8852C)
|
||||
env->nhm_th[RTW89_NHM_TH_NUM - 1] = RTW89_NHM_WA_TH;
|
||||
|
||||
for (i = 0; i < RTW89_NHM_TH_NUM; i++) {
|
||||
nhm_th = &(*chip->nhm_th)[i];
|
||||
|
||||
rtw89_phy_write32_idx(rtwdev, nhm_th->addr, nhm_th->mask,
|
||||
env->nhm_th[i], bb->phy_idx);
|
||||
}
|
||||
}
|
||||
|
||||
static int rtw89_phy_nhm_set(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb,
|
||||
struct rtw89_ccx_para_info *para)
|
||||
{
|
||||
const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
const struct rtw89_ccx_regs *ccx = phy->ccx;
|
||||
u32 unit_idx = 0;
|
||||
u32 period = 0;
|
||||
|
||||
if (para->mntr_time == 0) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
|
||||
"[NHM] MNTR_TIME is 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rtw89_phy_ccx_racing_ctrl(rtwdev, bb, para->rac_lv))
|
||||
return -EINVAL;
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
|
||||
"[NHM]nhm_incld_cca=%d, mntr_time=%d ms\n",
|
||||
para->nhm_incld_cca, para->mntr_time);
|
||||
|
||||
if (para->mntr_time != env->nhm_mntr_time) {
|
||||
rtw89_phy_ccx_ms_to_period_unit(rtwdev, para->mntr_time,
|
||||
&period, &unit_idx);
|
||||
rtw89_phy_write32_idx(rtwdev, ccx->nhm_config,
|
||||
ccx->nhm_period_mask, period, bb->phy_idx);
|
||||
rtw89_phy_write32_idx(rtwdev, ccx->nhm_config,
|
||||
ccx->nhm_unit_mask, period, bb->phy_idx);
|
||||
|
||||
env->nhm_mntr_time = para->mntr_time;
|
||||
env->ccx_period = period;
|
||||
env->ccx_unit_idx = unit_idx;
|
||||
}
|
||||
|
||||
if (para->nhm_incld_cca != env->nhm_include_cca) {
|
||||
rtw89_phy_write32_idx(rtwdev, ccx->nhm_config,
|
||||
ccx->nhm_include_cca_mask, para->nhm_incld_cca,
|
||||
bb->phy_idx);
|
||||
|
||||
env->nhm_include_cca = para->nhm_incld_cca;
|
||||
}
|
||||
|
||||
rtw89_phy_nhm_th_update(rtwdev, bb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
struct rtw89_ccx_para_info para = {
|
||||
.mntr_time = RTW89_NHM_MNTR_TIME,
|
||||
.rac_lv = RTW89_RAC_LV_1,
|
||||
.nhm_incld_cca = true,
|
||||
};
|
||||
|
||||
rtw89_phy_ccx_racing_release(rtwdev, bb);
|
||||
|
||||
rtw89_phy_nhm_set(rtwdev, bb, ¶);
|
||||
rtw89_phy_ccx_trigger(rtwdev, bb, RTW89_PHY_ENV_MON_NHM);
|
||||
}
|
||||
|
||||
void rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
struct rtw89_bb_ctx *bb;
|
||||
|
||||
if (!chip->support_noise)
|
||||
return;
|
||||
|
||||
rtw89_for_each_active_bb(rtwdev, bb)
|
||||
__rtw89_phy_nhm_trigger(rtwdev, bb);
|
||||
}
|
||||
|
||||
static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_bb_ctx *bb,
|
||||
struct rtw89_ccx_para_info *para)
|
||||
@@ -5816,7 +6175,7 @@ static void __rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev,
|
||||
if (rtw89_phy_ifs_clm_set(rtwdev, bb, ¶) == 0)
|
||||
chk_result |= RTW89_PHY_ENV_MON_IFS_CLM;
|
||||
if (chk_result)
|
||||
rtw89_phy_ccx_trigger(rtwdev, bb);
|
||||
rtw89_phy_ccx_trigger(rtwdev, bb, chk_result);
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
|
||||
"get_result=0x%x, chk_result:0x%x\n",
|
||||
@@ -5930,8 +6289,6 @@ static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev,
|
||||
val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF) |
|
||||
BIT(RTW89_PHYSTS_IE01_CMN_OFDM);
|
||||
} else if (i >= RTW89_CCK_PKT) {
|
||||
val |= BIT(RTW89_PHYSTS_IE09_FTR_0);
|
||||
|
||||
val &= ~(GENMASK(RTW89_PHYSTS_IE07_CMN_EXT_PATH_D,
|
||||
RTW89_PHYSTS_IE04_CMN_EXT_PATH_A));
|
||||
|
||||
@@ -6910,6 +7267,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
|
||||
rtw89_chip_bb_sethw(rtwdev);
|
||||
|
||||
rtw89_phy_env_monitor_init(rtwdev);
|
||||
rtw89_phy_nhm_setting_init(rtwdev);
|
||||
rtw89_physts_parsing_init(rtwdev);
|
||||
rtw89_phy_dig_init(rtwdev);
|
||||
rtw89_phy_cfo_init(rtwdev);
|
||||
@@ -6935,6 +7293,43 @@ void rtw89_phy_dm_reinit(struct rtw89_dev *rtwdev)
|
||||
rtw89_physts_parsing_init(rtwdev);
|
||||
}
|
||||
|
||||
static void __rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
|
||||
{
|
||||
struct rtw89_env_monitor_info *env = &bb->env_monitor;
|
||||
const struct rtw89_chip_info *chip = rtwdev->chip;
|
||||
struct ieee80211_supported_band *sband;
|
||||
enum rtw89_band hw_band;
|
||||
enum nl80211_band band;
|
||||
u8 idx;
|
||||
|
||||
if (!chip->support_noise)
|
||||
return;
|
||||
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
sband = rtwdev->hw->wiphy->bands[band];
|
||||
if (!sband)
|
||||
continue;
|
||||
|
||||
hw_band = rtw89_nl80211_to_hw_band(band);
|
||||
env->nhm_his[hw_band] =
|
||||
devm_kcalloc(rtwdev->dev, sband->n_channels,
|
||||
sizeof(*env->nhm_his[0]), GFP_KERNEL);
|
||||
|
||||
for (idx = 0; idx < sband->n_channels; idx++)
|
||||
INIT_LIST_HEAD(&env->nhm_his[hw_band][idx].list);
|
||||
|
||||
INIT_LIST_HEAD(&env->nhm_rpt_list);
|
||||
}
|
||||
}
|
||||
|
||||
void rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_bb_ctx *bb;
|
||||
|
||||
rtw89_for_each_capab_bb(rtwdev, bb)
|
||||
__rtw89_phy_dm_init_data(rtwdev, bb);
|
||||
}
|
||||
|
||||
void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif_link *rtwvif_link)
|
||||
{
|
||||
@@ -7590,6 +7985,15 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
|
||||
.ifs_total_addr = R_IFSCNT,
|
||||
.ifs_cnt_done_mask = B_IFSCNT_DONE_MSK,
|
||||
.ifs_total_mask = B_IFSCNT_TOTAL_CNT_MSK,
|
||||
.nhm = R_NHM_AX,
|
||||
.nhm_ready = B_NHM_READY_MSK,
|
||||
.nhm_config = R_NHM_CFG,
|
||||
.nhm_period_mask = B_NHM_PERIOD_MSK,
|
||||
.nhm_unit_mask = B_NHM_COUNTER_MSK,
|
||||
.nhm_include_cca_mask = B_NHM_INCLUDE_CCA_MSK,
|
||||
.nhm_en_mask = B_NHM_EN_MSK,
|
||||
.nhm_method = R_NHM_TH9,
|
||||
.nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK,
|
||||
};
|
||||
|
||||
static const struct rtw89_physts_regs rtw89_physts_regs_ax = {
|
||||
|
||||
@@ -149,13 +149,14 @@ enum rtw89_phy_c2h_rfk_log_func {
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK = 3,
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI = 4,
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5,
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR = 9,
|
||||
|
||||
RTW89_PHY_C2H_RFK_LOG_FUNC_NUM,
|
||||
};
|
||||
|
||||
enum rtw89_phy_c2h_rfk_report_func {
|
||||
RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE = 0,
|
||||
RTW89_PHY_C2H_RFK_LOG_TAS_PWR = 6,
|
||||
RTW89_PHY_C2H_RFK_REPORT_FUNC_TAS_PWR = 6,
|
||||
};
|
||||
|
||||
enum rtw89_phy_c2h_dm_func {
|
||||
@@ -188,6 +189,12 @@ enum rtw89_env_monitor_result_level {
|
||||
RTW89_PHY_ENV_MON_EDCCA_CLM = BIT(4),
|
||||
};
|
||||
|
||||
#define RTW89_NHM_WEIGHT_OFFSET 2
|
||||
#define RTW89_NHM_WA_TH (109 << 1)
|
||||
#define RTW89_NOISE_DEFAULT -96
|
||||
#define RTW89_NHM_MNTR_TIME 40
|
||||
#define RTW89_NHM_TH_FACTOR 1
|
||||
|
||||
#define CCX_US_BASE_RATIO 4
|
||||
enum rtw89_ccx_unit {
|
||||
RTW89_CCX_4_US = 0,
|
||||
@@ -428,6 +435,15 @@ struct rtw89_ccx_regs {
|
||||
u32 ifs_total_addr;
|
||||
u32 ifs_cnt_done_mask;
|
||||
u32 ifs_total_mask;
|
||||
u32 nhm;
|
||||
u32 nhm_ready;
|
||||
u32 nhm_config;
|
||||
u32 nhm_period_mask;
|
||||
u32 nhm_unit_mask;
|
||||
u32 nhm_include_cca_mask;
|
||||
u32 nhm_en_mask;
|
||||
u32 nhm_method;
|
||||
u32 nhm_pwr_method_msk;
|
||||
};
|
||||
|
||||
struct rtw89_physts_regs {
|
||||
@@ -814,6 +830,7 @@ bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
|
||||
bool rtw89_phy_write_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
|
||||
u32 addr, u32 mask, u32 data);
|
||||
void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev);
|
||||
void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev);
|
||||
void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio);
|
||||
void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_reg2_def *reg,
|
||||
@@ -821,6 +838,7 @@ void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev,
|
||||
void *extra_data);
|
||||
void rtw89_phy_dm_init(struct rtw89_dev *rtwdev);
|
||||
void rtw89_phy_dm_reinit(struct rtw89_dev *rtwdev);
|
||||
void rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev);
|
||||
void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
|
||||
u32 data, enum rtw89_phy_idx phy_idx);
|
||||
void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
|
||||
@@ -1038,5 +1056,9 @@ enum rtw89_rf_path rtw89_phy_get_syn_sel(struct rtw89_dev *rtwdev,
|
||||
u8 rtw89_rfk_chan_lookup(struct rtw89_dev *rtwdev,
|
||||
const struct rtw89_rfk_chan_desc *desc, u8 desc_nr,
|
||||
const struct rtw89_chan *target_chan);
|
||||
void rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev);
|
||||
void rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev, enum rtw89_band hw_band,
|
||||
u16 ch_hw_value);
|
||||
void rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user