Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for v5.11. Major changes:

ath11k

* suspend support for QCA6390 PCI devices

* support TXOP duration based RTS threshold

* mesh: add support for 256 bitmap in blockack frames in 11ax
This commit is contained in:
Kalle Valo 2020-12-12 06:51:34 +02:00
commit 7ab250385e
40 changed files with 1033 additions and 131 deletions

View File

@ -1350,7 +1350,8 @@ out:
static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
const char *boardname,
const char *fallback_boardname,
const char *fallback_boardname1,
const char *fallback_boardname2,
const char *filename)
{
size_t len, magic_len;
@ -1399,8 +1400,11 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
ret = ath10k_core_search_bd(ar, boardname, data, len);
/* if we didn't find it and have a fallback name, try that */
if (ret == -ENOENT && fallback_boardname)
ret = ath10k_core_search_bd(ar, fallback_boardname, data, len);
if (ret == -ENOENT && fallback_boardname1)
ret = ath10k_core_search_bd(ar, fallback_boardname1, data, len);
if (ret == -ENOENT && fallback_boardname2)
ret = ath10k_core_search_bd(ar, fallback_boardname2, data, len);
if (ret == -ENOENT) {
ath10k_err(ar,
@ -1420,7 +1424,8 @@ err:
}
static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
size_t name_len, bool with_variant)
size_t name_len, bool with_variant,
bool with_chip_id)
{
/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };
@ -1439,7 +1444,7 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
}
if (ar->id.qmi_ids_valid) {
if (with_variant && ar->id.bdf_ext[0] != '\0')
if (with_chip_id)
scnprintf(name, name_len,
"bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s",
ath10k_bus_str(ar->hif.bus),
@ -1483,21 +1488,36 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,
int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
{
char boardname[100], fallback_boardname[100];
char boardname[100], fallback_boardname1[100], fallback_boardname2[100];
int ret;
if (bd_ie_type == ATH10K_BD_IE_BOARD) {
/* With variant and chip id */
ret = ath10k_core_create_board_name(ar, boardname,
sizeof(boardname), true);
sizeof(boardname), true,
true);
if (ret) {
ath10k_err(ar, "failed to create board name: %d", ret);
return ret;
}
ret = ath10k_core_create_board_name(ar, fallback_boardname,
sizeof(boardname), false);
/* Without variant and only chip-id */
ret = ath10k_core_create_board_name(ar, fallback_boardname1,
sizeof(boardname), false,
true);
if (ret) {
ath10k_err(ar, "failed to create fallback board name: %d", ret);
ath10k_err(ar, "failed to create 1st fallback board name: %d",
ret);
return ret;
}
/* Without variant and without chip-id */
ret = ath10k_core_create_board_name(ar, fallback_boardname2,
sizeof(boardname), false,
false);
if (ret) {
ath10k_err(ar, "failed to create 2nd fallback board name: %d",
ret);
return ret;
}
} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {
@ -1511,7 +1531,8 @@ int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
ar->bd_api = 2;
ret = ath10k_core_fetch_board_data_api_n(ar, boardname,
fallback_boardname,
fallback_boardname1,
fallback_boardname2,
ATH10K_BOARD_API2_FILE);
if (!ret)
goto success;
@ -2273,6 +2294,17 @@ static int ath10k_init_hw_params(struct ath10k *ar)
return 0;
}
void ath10k_core_start_recovery(struct ath10k *ar)
{
if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) {
ath10k_warn(ar, "already restarting\n");
return;
}
queue_work(ar->workqueue, &ar->restart_work);
}
EXPORT_SYMBOL(ath10k_core_start_recovery);
static void ath10k_core_restart(struct work_struct *work)
{
struct ath10k *ar = container_of(work, struct ath10k, restart_work);

View File

@ -865,6 +865,9 @@ enum ath10k_dev_flags {
/* Per Station statistics service */
ATH10K_FLAG_PEER_STATS,
/* Indicates that ath10k device is during recovery process and not complete */
ATH10K_FLAG_RESTARTING,
};
enum ath10k_cal_mode {
@ -1320,6 +1323,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
const struct ath10k_fw_components *fw_components);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
void ath10k_core_stop(struct ath10k *ar);
void ath10k_core_start_recovery(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar,
const struct ath10k_bus_params *bus_params);
void ath10k_core_unregister(struct ath10k *ar);

View File

@ -583,7 +583,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
ret = ath10k_debug_fw_assert(ar);
} else if (!strcmp(buf, "hw-restart")) {
ath10k_info(ar, "user requested hw restart\n");
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
ret = 0;
} else {
ret = -EINVAL;
@ -2005,7 +2005,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
}
} else {
ath10k_info(ar, "restarting firmware due to btcoex change");
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
}
if (val)
@ -2136,7 +2136,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file,
ath10k_info(ar, "restarting firmware due to Peer stats change");
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
ret = count;
exit:

View File

@ -7932,6 +7932,7 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
ath10k_info(ar, "device successfully recovered\n");
ar->state = ATH10K_STATE_ON;
ieee80211_wake_queues(ar->hw);
clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags);
}
mutex_unlock(&ar->conf_mutex);

View File

@ -1774,7 +1774,7 @@ static void ath10k_pci_fw_dump_work(struct work_struct *work)
mutex_unlock(&ar->dump_mutex);
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
}
static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)

View File

@ -561,7 +561,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH);
ret = -ENOMEM;
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
ath10k_warn(ar, "exceeds length, start recovery\n");
goto err;
@ -960,7 +960,7 @@ static int ath10k_sdio_mbox_read_int_status(struct ath10k *ar,
ret = ath10k_sdio_read(ar, MBOX_HOST_INT_STATUS_ADDRESS,
irq_proc_reg, sizeof(*irq_proc_reg));
if (ret) {
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
ath10k_warn(ar, "read int status fail, start recovery\n");
goto out;
}
@ -2237,7 +2237,7 @@ static bool ath10k_sdio_is_fast_dump_supported(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio hi_option_flag2 %x\n", param);
return param & HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW;
return !!(param & HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW);
}
static void ath10k_sdio_dump_registers(struct ath10k *ar,
@ -2501,7 +2501,7 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
ath10k_sdio_enable_intrs(ar);
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
}
static int ath10k_sdio_probe(struct sdio_func *func,

View File

@ -1305,7 +1305,7 @@ int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
switch (type) {
case ATH10K_QMI_EVENT_FW_READY_IND:
if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
break;
}

View File

@ -1937,7 +1937,7 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
if (ret == -EAGAIN) {
ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n",
cmd_id);
queue_work(ar->workqueue, &ar->restart_work);
ath10k_core_start_recovery(ar);
}
return ret;

View File

@ -16,7 +16,8 @@ ath11k-y += core.o \
ce.o \
peer.o \
dbring.o \
hw.o
hw.o \
wow.o
ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o

View File

@ -747,6 +747,13 @@ static int ath11k_ahb_remove(struct platform_device *pdev)
struct ath11k_base *ab = platform_get_drvdata(pdev);
unsigned long left;
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath11k_ahb_power_down(ab);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
}
reinit_completion(&ab->driver_recovery);
if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
@ -760,8 +767,8 @@ static int ath11k_ahb_remove(struct platform_device *pdev)
cancel_work_sync(&ab->restart_work);
ath11k_core_deinit(ab);
qmi_fail:
ath11k_ahb_free_irq(ab);
ath11k_hal_srng_deinit(ab);
ath11k_ce_free_pipes(ab);
ath11k_core_free(ab);

View File

@ -195,7 +195,7 @@ static bool ath11k_ce_need_shadow_fix(int ce_id)
return false;
}
static void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab)
void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab)
{
int i;

View File

@ -190,4 +190,6 @@ int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
int ath11k_ce_attr_attach(struct ath11k_base *ab);
void ath11k_ce_get_shadow_config(struct ath11k_base *ab,
u32 **shadow_cfg, u32 *shadow_cfg_len);
void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab);
#endif

View File

@ -13,6 +13,7 @@
#include "dp_rx.h"
#include "debug.h"
#include "hif.h"
#include "wow.h"
unsigned int ath11k_debug_mask;
EXPORT_SYMBOL(ath11k_debug_mask);
@ -51,7 +52,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074,
.svc_to_ce_map_len = 21,
.single_pdev_only = false,
.needs_band_to_mac = true,
.rxdma1_enable = true,
.num_rxmda_per_pdev = 1,
.rx_mac_buf_ring = false,
@ -67,6 +67,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = false,
.idle_ps = false,
.cold_boot_calib = true,
.supports_suspend = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@ -89,7 +90,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018,
.svc_to_ce_map_len = 19,
.single_pdev_only = false,
.needs_band_to_mac = true,
.rxdma1_enable = true,
.num_rxmda_per_pdev = 1,
.rx_mac_buf_ring = false,
@ -105,6 +105,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = false,
.idle_ps = false,
.cold_boot_calib = true,
.supports_suspend = false,
},
{
.name = "qca6390 hw2.0",
@ -127,7 +128,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
.svc_to_ce_map_len = 14,
.single_pdev_only = true,
.needs_band_to_mac = false,
.rxdma1_enable = false,
.num_rxmda_per_pdev = 2,
.rx_mac_buf_ring = true,
@ -142,9 +142,91 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = true,
.idle_ps = true,
.cold_boot_calib = false,
.supports_suspend = true,
},
};
int ath11k_core_suspend(struct ath11k_base *ab)
{
int ret;
if (!ab->hw_params.supports_suspend)
return -EOPNOTSUPP;
/* TODO: there can frames in queues so for now add delay as a hack.
* Need to implement to handle and remove this delay.
*/
msleep(500);
ret = ath11k_dp_rx_pktlog_stop(ab, true);
if (ret) {
ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
ret);
return ret;
}
ret = ath11k_wow_enable(ab);
if (ret) {
ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret);
return ret;
}
ret = ath11k_dp_rx_pktlog_stop(ab, false);
if (ret) {
ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
ret);
return ret;
}
ath11k_ce_stop_shadow_timers(ab);
ath11k_dp_stop_shadow_timers(ab);
ath11k_hif_irq_disable(ab);
ath11k_hif_ce_irq_disable(ab);
ret = ath11k_hif_suspend(ab);
if (!ret) {
ath11k_warn(ab, "failed to suspend hif: %d\n", ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(ath11k_core_suspend);
int ath11k_core_resume(struct ath11k_base *ab)
{
int ret;
if (!ab->hw_params.supports_suspend)
return -EOPNOTSUPP;
ret = ath11k_hif_resume(ab);
if (ret) {
ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret);
return ret;
}
ath11k_hif_ce_irq_enable(ab);
ath11k_hif_irq_enable(ab);
ret = ath11k_dp_rx_pktlog_start(ab);
if (ret) {
ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",
ret);
return ret;
}
ret = ath11k_wow_wakeup(ab);
if (ret) {
ath11k_warn(ab, "failed to wakeup wow during resume: %d\n", ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(ath11k_core_resume);
int ath11k_core_check_dt(struct ath11k_base *ab)
{
size_t max_len = sizeof(ab->qmi.target.bdf_ext);
@ -646,6 +728,15 @@ static int ath11k_core_start(struct ath11k_base *ab,
goto err_reo_cleanup;
}
/* put hardware to DBS mode */
if (ab->hw_params.single_pdev_only) {
ret = ath11k_wmi_set_hw_mode(ab, WMI_HOST_HW_MODE_DBS);
if (ret) {
ath11k_err(ab, "failed to send dbs mode: %d\n", ret);
goto err_hif_stop;
}
}
ret = ath11k_dp_tx_htt_h2t_ver_req_msg(ab);
if (ret) {
ath11k_err(ab, "failed to send htt version request message: %d\n",
@ -962,6 +1053,9 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
init_waitqueue_head(&ab->qmi.cold_boot_waitq);
INIT_WORK(&ab->restart_work, ath11k_core_restart);
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
init_completion(&ab->htc_suspend);
init_completion(&ab->wow.wakeup_completed);
ab->dev = dev;
ab->bus_params = *bus_params;
ab->hif.bus = bus;

View File

@ -185,6 +185,8 @@ enum ath11k_dev_flags {
ATH11K_FLAG_RECOVERY,
ATH11K_FLAG_UNREGISTERING,
ATH11K_FLAG_REGISTERED,
ATH11K_FLAG_QMI_FAIL,
ATH11K_FLAG_HTC_SUSPEND_COMPLETE,
};
enum ath11k_monitor_flags {
@ -464,6 +466,7 @@ struct ath11k {
struct ieee80211_sband_iftype_data
iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
} mac;
unsigned long dev_flags;
unsigned int filter_flags;
unsigned long monitor_flags;
@ -670,6 +673,10 @@ struct ath11k_base {
const struct ath11k_hif_ops *ops;
} hif;
struct {
struct completion wakeup_completed;
} wow;
struct ath11k_ce ce;
struct timer_list rx_replenish_retry;
struct ath11k_hal hal;
@ -731,6 +738,9 @@ struct ath11k_base {
u32 num_db_cap;
struct timer_list mon_reap_timer;
struct completion htc_suspend;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
@ -887,6 +897,8 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
int ath11k_core_check_dt(struct ath11k_base *ath11k);
void ath11k_core_halt(struct ath11k *ar);
int ath11k_core_resume(struct ath11k_base *ab);
int ath11k_core_suspend(struct ath11k_base *ab);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);

View File

@ -867,6 +867,7 @@ void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
debugfs_remove_recursive(ab->debugfs_ath11k);
ab->debugfs_ath11k = NULL;
}
EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
{

View File

@ -304,7 +304,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
return 0;
}
static void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab)
void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab)
{
int i;

View File

@ -40,6 +40,7 @@ struct dp_rx_tid {
#define DP_REO_DESC_FREE_THRESHOLD 64
#define DP_REO_DESC_FREE_TIMEOUT_MS 1000
#define DP_MON_PURGE_TIMEOUT_MS 100
#define DP_MON_SERVICE_BUDGET 128
struct dp_reo_cache_flush_elem {
@ -1640,5 +1641,6 @@ void ath11k_dp_shadow_stop_timer(struct ath11k_base *ab,
void ath11k_dp_shadow_init_timer(struct ath11k_base *ab,
struct ath11k_hp_update_timer *update_timer,
u32 interval, u32 ring_id);
void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab);
#endif

View File

@ -274,6 +274,28 @@ static void ath11k_dp_service_mon_ring(struct timer_list *t)
msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
}
static int ath11k_dp_purge_mon_ring(struct ath11k_base *ab)
{
int i, reaped = 0;
unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS);
do {
for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++)
reaped += ath11k_dp_rx_process_mon_rings(ab, i,
NULL,
DP_MON_SERVICE_BUDGET);
/* nothing more to reap */
if (reaped < DP_MON_SERVICE_BUDGET)
return 0;
} while (time_before(jiffies, timeout));
ath11k_warn(ab, "dp mon ring purge timeout");
return -ETIMEDOUT;
}
/* Returns number of Rx buffers replenished */
int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id,
struct dp_rxdma_ring *rx_ring,
@ -5026,3 +5048,29 @@ int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar)
ath11k_dp_mon_link_free(ar);
return 0;
}
int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab)
{
/* start reap timer */
mod_timer(&ab->mon_reap_timer,
jiffies + msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
return 0;
}
int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer)
{
int ret;
if (stop_timer)
del_timer_sync(&ab->mon_reap_timer);
/* reap all the monitor related rings */
ret = ath11k_dp_purge_mon_ring(ab);
if (ret) {
ath11k_warn(ab, "failed to purge dp mon ring: %d\n", ret);
return ret;
}
return 0;
}

View File

@ -91,4 +91,7 @@ int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar);
int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar);
int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id);
int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab);
int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer);
#endif /* ATH11K_DP_RX_H */

View File

@ -17,6 +17,8 @@ struct ath11k_hif_ops {
void (*stop)(struct ath11k_base *sc);
int (*power_up)(struct ath11k_base *sc);
void (*power_down)(struct ath11k_base *sc);
int (*suspend)(struct ath11k_base *ab);
int (*resume)(struct ath11k_base *ab);
int (*map_service_to_pipe)(struct ath11k_base *sc, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe);
int (*get_user_msi_vector)(struct ath11k_base *ab, char *user_name,
@ -24,8 +26,22 @@ struct ath11k_hif_ops {
u32 *base_vector);
void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo,
u32 *msi_addr_hi);
void (*ce_irq_enable)(struct ath11k_base *ab);
void (*ce_irq_disable)(struct ath11k_base *ab);
};
static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
{
if (ab->hif.ops->ce_irq_enable)
ab->hif.ops->ce_irq_enable(ab);
}
static inline void ath11k_hif_ce_irq_disable(struct ath11k_base *ab)
{
if (ab->hif.ops->ce_irq_disable)
ab->hif.ops->ce_irq_disable(ab);
}
static inline int ath11k_hif_start(struct ath11k_base *sc)
{
return sc->hif.ops->start(sc);
@ -56,6 +72,22 @@ static inline void ath11k_hif_power_down(struct ath11k_base *sc)
sc->hif.ops->power_down(sc);
}
static inline int ath11k_hif_suspend(struct ath11k_base *ab)
{
if (ab->hif.ops->suspend)
return ab->hif.ops->suspend(ab);
return 0;
}
static inline int ath11k_hif_resume(struct ath11k_base *ab)
{
if (ab->hif.ops->resume)
return ab->hif.ops->resume(ab);
return 0;
}
static inline u32 ath11k_hif_read32(struct ath11k_base *sc, u32 address)
{
return sc->hif.ops->read32(sc, address);

View File

@ -60,9 +60,11 @@ static void ath11k_htc_prepare_tx_skb(struct ath11k_htc_ep *ep,
memset(hdr, 0, sizeof(*hdr));
hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) |
FIELD_PREP(HTC_HDR_PAYLOADLEN,
(skb->len - sizeof(*hdr))) |
FIELD_PREP(HTC_HDR_FLAGS,
ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE);
(skb->len - sizeof(*hdr)));
if (ep->tx_credit_flow_enabled)
hdr->htc_info |= FIELD_PREP(HTC_HDR_FLAGS,
ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE);
spin_lock_bh(&ep->htc->tx_lock);
hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++);
@ -231,6 +233,18 @@ static int ath11k_htc_process_trailer(struct ath11k_htc *htc,
return status;
}
static void ath11k_htc_suspend_complete(struct ath11k_base *ab, bool ack)
{
ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot suspend complete %d\n", ack);
if (ack)
set_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
else
clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
complete(&ab->htc_suspend);
}
void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
struct sk_buff *skb)
{
@ -328,8 +342,17 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
complete(&htc->ctl_resp);
break;
case ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE:
ath11k_htc_suspend_complete(ab, true);
break;
case ATH11K_HTC_MSG_NACK_SUSPEND:
ath11k_htc_suspend_complete(ab, false);
break;
case ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID:
break;
default:
ath11k_warn(ab, "ignoring unsolicited htc ep0 event\n");
ath11k_warn(ab, "ignoring unsolicited htc ep0 event %ld\n",
FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id));
break;
}
goto out;

View File

@ -65,7 +65,9 @@ enum ath11k_htc_msg_id {
ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID = 3,
ATH11K_HTC_MSG_SETUP_COMPLETE_ID = 4,
ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID = 5,
ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE = 6
ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE = 6,
ATH11K_HTC_MSG_NACK_SUSPEND = 7,
ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID = 8,
};
enum ath11k_htc_version {
@ -221,10 +223,6 @@ enum ath11k_htc_ep_id {
ATH11K_HTC_EP_COUNT,
};
struct ath11k_htc_ops {
void (*target_send_suspend_complete)(struct ath11k_base *ar);
};
struct ath11k_htc_ep_ops {
void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *);
void (*ep_rx_complete)(struct ath11k_base *, struct sk_buff *);
@ -284,8 +282,6 @@ struct ath11k_htc {
/* protects endpoints */
spinlock_t tx_lock;
struct ath11k_htc_ops htc_ops;
u8 control_resp_buffer[ATH11K_HTC_MAX_CTRL_MSG_LEN];
int control_resp_len;

View File

@ -143,12 +143,6 @@ struct ath11k_hw_params {
bool single_pdev_only;
/* For example on QCA6390 struct
* wmi_init_cmd_param::band_to_mac_config needs to be false as the
* firmware creates the mapping.
*/
bool needs_band_to_mac;
bool rxdma1_enable;
int num_rxmda_per_pdev;
bool rx_mac_buf_ring;
@ -162,6 +156,7 @@ struct ath11k_hw_params {
bool supports_shadow_regs;
bool idle_ps;
bool cold_boot_calib;
bool supports_suspend;
};
struct ath11k_hw_ops {

View File

@ -1925,20 +1925,6 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret)
ath11k_warn(ar->ab, "failed to update bcn template: %d\n",
ret);
if (vif->bss_conf.he_support) {
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
WMI_VDEV_PARAM_BA_MODE,
WMI_BA_MODE_BUFFER_SIZE_256);
if (ret)
ath11k_warn(ar->ab,
"failed to set BA BUFFER SIZE 256 for vdev: %d\n",
arvif->vdev_id);
else
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
"Set BA BUFFER SIZE 256 for VDEV: %d\n",
arvif->vdev_id);
}
}
if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
@ -1969,9 +1955,33 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
ether_addr_copy(arvif->bssid, info->bssid);
if (changed & BSS_CHANGED_BEACON_ENABLED)
if (changed & BSS_CHANGED_BEACON_ENABLED) {
ath11k_control_beaconing(arvif, info);
if (arvif->is_up && vif->bss_conf.he_support &&
vif->bss_conf.he_oper.params) {
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
WMI_VDEV_PARAM_BA_MODE,
WMI_BA_MODE_BUFFER_SIZE_256);
if (ret)
ath11k_warn(ar->ab,
"failed to set BA BUFFER SIZE 256 for vdev: %d\n",
arvif->vdev_id);
param_id = WMI_VDEV_PARAM_HEOPS_0_31;
param_value = vif->bss_conf.he_oper.params;
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
"he oper param: %x set for VDEV: %d\n",
param_value, arvif->vdev_id);
if (ret)
ath11k_warn(ar->ab, "Failed to set he oper params %x for VDEV %d: %i\n",
param_value, arvif->vdev_id, ret);
}
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
u32 cts_prot;
@ -4136,6 +4146,10 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
&tlv_filter);
}
if (enable && !ar->ab->hw_params.rxdma1_enable)
mod_timer(&ar->ab->mon_reap_timer, jiffies +
msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
return ret;
}
@ -4615,13 +4629,13 @@ err_peer_del:
if (ret) {
ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
arvif->vdev_id, vif->addr);
return ret;
goto err;
}
ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id,
vif->addr);
if (ret)
return ret;
goto err;
ar->num_peers--;
}

View File

@ -190,6 +190,15 @@ static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)
static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
enum mhi_callback cb)
{
struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);
switch (cb) {
case MHI_CB_SYS_ERROR:
ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
break;
default:
break;
}
}
static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,
@ -214,7 +223,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
struct mhi_controller *mhi_ctrl;
int ret;
mhi_ctrl = kzalloc(sizeof(*mhi_ctrl), GFP_KERNEL);
mhi_ctrl = mhi_alloc_controller();
if (!mhi_ctrl)
return -ENOMEM;
@ -230,7 +239,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
ret = ath11k_mhi_get_msi(ab_pci);
if (ret) {
ath11k_err(ab, "failed to get msi for mhi\n");
kfree(mhi_ctrl);
mhi_free_controller(mhi_ctrl);
return ret;
}
@ -248,7 +257,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
ret = mhi_register_controller(mhi_ctrl, &ath11k_mhi_config);
if (ret) {
ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
kfree(mhi_ctrl);
mhi_free_controller(mhi_ctrl);
return ret;
}
@ -261,6 +270,7 @@ void ath11k_mhi_unregister(struct ath11k_pci *ab_pci)
mhi_unregister_controller(mhi_ctrl);
kfree(mhi_ctrl->irq);
mhi_free_controller(mhi_ctrl);
}
static char *ath11k_mhi_state_to_str(enum ath11k_mhi_state mhi_state)
@ -409,8 +419,10 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci,
ret = 0;
break;
case ATH11K_MHI_SUSPEND:
ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
break;
case ATH11K_MHI_RESUME:
ret = mhi_pm_resume(ab_pci->mhi_ctrl);
break;
case ATH11K_MHI_TRIGGER_RDDM:
ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl);
@ -461,3 +473,12 @@ void ath11k_mhi_stop(struct ath11k_pci *ab_pci)
ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT);
}
void ath11k_mhi_suspend(struct ath11k_pci *ab_pci)
{
ath11k_mhi_set_state(ab_pci, ATH11K_MHI_SUSPEND);
}
void ath11k_mhi_resume(struct ath11k_pci *ab_pci)
{
ath11k_mhi_set_state(ab_pci, ATH11K_MHI_RESUME);
}

View File

@ -36,4 +36,7 @@ void ath11k_mhi_unregister(struct ath11k_pci *ar_pci);
void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab);
void ath11k_mhi_clear_vector(struct ath11k_base *ab);
void ath11k_mhi_suspend(struct ath11k_pci *ar_pci);
void ath11k_mhi_resume(struct ath11k_pci *ar_pci);
#endif

View File

@ -126,6 +126,7 @@ static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offse
if (window != ab_pci->register_window) {
iowrite32(WINDOW_ENABLE_BIT | window,
ab->mem + WINDOW_REG_ADDRESS);
ioread32(ab->mem + WINDOW_REG_ADDRESS);
ab_pci->register_window = window;
}
}
@ -239,15 +240,137 @@ static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
}
static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
u32 offset, u32 value, u32 mask)
{
u32 v;
int i;
v = ath11k_pci_read32(ab, offset);
if ((v & mask) == value)
return 0;
for (i = 0; i < 10; i++) {
ath11k_pci_write32(ab, offset, (v & ~mask) | value);
v = ath11k_pci_read32(ab, offset);
if ((v & mask) == value)
return 0;
mdelay(2);
}
ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
offset, v & mask, value);
return -ETIMEDOUT;
}
static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
{
int ret;
ret = ath11k_pci_set_link_reg(ab,
PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG,
PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
if (!ret) {
ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
return ret;
}
ret = ath11k_pci_set_link_reg(ab,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
if (!ret) {
ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
return ret;
}
ret = ath11k_pci_set_link_reg(ab,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
if (!ret) {
ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
return ret;
}
ret = ath11k_pci_set_link_reg(ab,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL,
PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
if (!ret) {
ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
return ret;
}
return 0;
}
static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
{
u32 val;
int i;
val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
/* PCIE link seems very unstable after the Hot Reset*/
for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
if (val == 0xffffffff)
mdelay(5);
ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
}
ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10;
ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
mdelay(5);
}
static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
{
/* This is a WAR for PCIE Hotreset.
* When target receive Hotreset, but will set the interrupt.
* So when download SBL again, SBL will open Interrupt and
* receive it, and crash immediately.
*/
ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
}
static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
{
u32 val;
val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
}
static void ath11k_pci_force_wake(struct ath11k_base *ab)
{
ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
mdelay(5);
}
static void ath11k_pci_sw_reset(struct ath11k_base *ab)
static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
{
ath11k_pci_soc_global_reset(ab);
if (power_on) {
ath11k_pci_enable_ltssm(ab);
ath11k_pci_clear_all_intrs(ab);
ath11k_pci_set_wlaon_pwr_ctrl(ab);
ath11k_pci_fix_l1ss(ab);
}
ath11k_mhi_clear_vector(ab);
ath11k_pci_soc_global_reset(ab);
ath11k_mhi_set_mhictrl_reset(ab);
@ -264,13 +387,18 @@ int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
u32 *msi_addr_hi)
{
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
struct pci_dev *pci_dev = to_pci_dev(ab->dev);
pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
msi_addr_lo);
pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
msi_addr_hi);
if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
msi_addr_hi);
} else {
*msi_addr_hi = 0;
}
}
int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
@ -658,6 +786,8 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
}
ab_pci->msi_ep_base_data = msi_desc->msg.data;
if (msi_desc->msi_attrib.is_64)
set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
@ -763,7 +893,7 @@ static int ath11k_pci_power_up(struct ath11k_base *ab)
ab_pci->register_window = 0;
clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
ath11k_pci_sw_reset(ab_pci->ab);
ath11k_pci_sw_reset(ab_pci->ab, true);
ret = ath11k_mhi_start(ab_pci);
if (ret) {
@ -778,10 +908,28 @@ static void ath11k_pci_power_down(struct ath11k_base *ab)
{
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
ath11k_pci_force_wake(ab_pci->ab);
ath11k_mhi_stop(ab_pci);
clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
ath11k_pci_force_wake(ab_pci->ab);
ath11k_pci_sw_reset(ab_pci->ab);
ath11k_pci_sw_reset(ab_pci->ab, false);
}
static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
{
struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
ath11k_mhi_suspend(ar_pci);
return 0;
}
static int ath11k_pci_hif_resume(struct ath11k_base *ab)
{
struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
ath11k_mhi_resume(ar_pci);
return 0;
}
static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
@ -798,11 +946,16 @@ static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
}
}
static void ath11k_pci_stop(struct ath11k_base *ab)
static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
{
ath11k_pci_ce_irqs_disable(ab);
ath11k_pci_sync_ce_irqs(ab);
ath11k_pci_kill_tasklets(ab);
}
static void ath11k_pci_stop(struct ath11k_base *ab)
{
ath11k_pci_ce_irq_disable_sync(ab);
ath11k_ce_cleanup_pipes(ab);
}
@ -818,6 +971,16 @@ static int ath11k_pci_start(struct ath11k_base *ab)
return 0;
}
static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
{
ath11k_pci_ce_irqs_enable(ab);
}
static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
{
ath11k_pci_ce_irq_disable_sync(ab);
}
static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
{
@ -868,11 +1031,15 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.write32 = ath11k_pci_write32,
.power_down = ath11k_pci_power_down,
.power_up = ath11k_pci_power_up,
.suspend = ath11k_pci_hif_suspend,
.resume = ath11k_pci_hif_resume,
.irq_enable = ath11k_pci_ext_irq_enable,
.irq_disable = ath11k_pci_ext_irq_disable,
.get_msi_address = ath11k_pci_get_msi_address,
.get_user_msi_vector = ath11k_get_user_msi_assignment,
.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
};
static int ath11k_pci_probe(struct pci_dev *pdev,
@ -1007,10 +1174,18 @@ static void ath11k_pci_remove(struct pci_dev *pdev)
struct ath11k_base *ab = pci_get_drvdata(pdev);
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath11k_pci_power_down(ab);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
}
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
ath11k_core_deinit(ab);
qmi_fail:
ath11k_mhi_unregister(ab_pci);
ath11k_pci_free_irq(ab);
@ -1029,12 +1204,43 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
ath11k_pci_power_down(ab);
}
static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
{
struct ath11k_base *ab = dev_get_drvdata(dev);
int ret;
ret = ath11k_core_suspend(ab);
if (ret)
ath11k_warn(ab, "failed to suspend core: %d\n", ret);
return ret;
}
static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
{
struct ath11k_base *ab = dev_get_drvdata(dev);
int ret;
ret = ath11k_core_resume(ab);
if (ret)
ath11k_warn(ab, "failed to resume core: %d\n", ret);
return ret;
}
static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
ath11k_pci_pm_suspend,
ath11k_pci_pm_resume);
static struct pci_driver ath11k_pci_driver = {
.name = "ath11k_pci",
.id_table = ath11k_pci_id_table,
.probe = ath11k_pci_probe,
.remove = ath11k_pci_remove,
.shutdown = ath11k_pci_shutdown,
#ifdef CONFIG_PM
.driver.pm = &ath11k_pci_pm_ops,
#endif
};
static int ath11k_pci_init(void)
@ -1059,3 +1265,8 @@ module_exit(ath11k_pci_exit);
MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
/* QCA639x 2.0 firmware files */
MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);

View File

@ -24,6 +24,30 @@
/* register used for handshake mechanism to validate UMAC is awake */
#define PCIE_SOC_WAKE_PCIE_LOCAL_REG 0x3004
#define PCIE_PCIE_PARF_LTSSM 0x1e081b0
#define PARM_LTSSM_VALUE 0x111
#define GCC_GCC_PCIE_HOT_RST 0x1e402bc
#define GCC_GCC_PCIE_HOT_RST_VAL 0x10
#define PCIE_PCIE_INT_ALL_CLEAR 0x1e08228
#define PCIE_SMLH_REQ_RST_LINK_DOWN 0x2
#define PCIE_INT_CLEAR_ALL 0xffffffff
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG 0x01e0c0ac
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL 0x10
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK 0xffffffff
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG 0x01e0c628
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL 0x02
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG 0x01e0c62c
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL 0x52
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG 0x01e0c634
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL 0xff
#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK 0x000000ff
#define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c
#define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4
struct ath11k_msi_user {
char *name;
int num_vectors;
@ -38,6 +62,7 @@ struct ath11k_msi_config {
enum ath11k_pci_flags {
ATH11K_PCI_FLAG_INIT_DONE,
ATH11K_PCI_FLAG_IS_MSI_64,
};
struct ath11k_pci {

View File

@ -2421,7 +2421,7 @@ ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
return 0;
}
static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
static int ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
{
struct ath11k_base *ab = qmi->ab;
int ret;
@ -2429,17 +2429,19 @@ static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
ret = ath11k_qmi_fw_ind_register_send(ab);
if (ret < 0) {
ath11k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret);
return;
return ret;
}
ret = ath11k_qmi_host_cap_send(ab);
if (ret < 0) {
ath11k_warn(ab, "qmi failed to send host cap QMI:%d\n", ret);
return;
return ret;
}
return ret;
}
static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
static int ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
{
struct ath11k_base *ab = qmi->ab;
int ret;
@ -2447,11 +2449,13 @@ static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
ret = ath11k_qmi_respond_fw_mem_request(ab);
if (ret < 0) {
ath11k_warn(ab, "qmi failed to respond fw mem req:%d\n", ret);
return;
return ret;
}
return ret;
}
static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
{
struct ath11k_base *ab = qmi->ab;
int ret;
@ -2459,7 +2463,7 @@ static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
ret = ath11k_qmi_request_target_cap(ab);
if (ret < 0) {
ath11k_warn(ab, "qmi failed to req target capabilities:%d\n", ret);
return;
return ret;
}
if (ab->bus_params.fixed_bdf_addr)
@ -2468,14 +2472,16 @@ static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
ret = ath11k_qmi_load_bdf_qmi(ab);
if (ret < 0) {
ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret);
return;
return ret;
}
ret = ath11k_qmi_wlanfw_m3_info_send(ab);
if (ret < 0) {
ath11k_warn(ab, "qmi failed to send m3 info req:%d\n", ret);
return;
return ret;
}
return ret;
}
static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
@ -2615,7 +2621,7 @@ static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw qmi service connected\n");
ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_ARRIVE, NULL);
return 0;
return ret;
}
static void ath11k_qmi_ops_del_server(struct qmi_handle *qmi_hdl,
@ -2639,6 +2645,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
event_work);
struct ath11k_qmi_driver_event *event;
struct ath11k_base *ab = qmi->ab;
int ret;
spin_lock(&qmi->event_lock);
while (!list_empty(&qmi->event_list)) {
@ -2652,19 +2659,26 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
switch (event->type) {
case ATH11K_QMI_EVENT_SERVER_ARRIVE:
ath11k_qmi_event_server_arrive(qmi);
ret = ath11k_qmi_event_server_arrive(qmi);
if (ret < 0)
set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
break;
case ATH11K_QMI_EVENT_SERVER_EXIT:
set_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
set_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
break;
case ATH11K_QMI_EVENT_REQUEST_MEM:
ath11k_qmi_event_mem_request(qmi);
ret = ath11k_qmi_event_mem_request(qmi);
if (ret < 0)
set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
break;
case ATH11K_QMI_EVENT_FW_MEM_READY:
ath11k_qmi_event_load_bdf(qmi);
ret = ath11k_qmi_event_load_bdf(qmi);
if (ret < 0)
set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
break;
case ATH11K_QMI_EVENT_FW_READY:
clear_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
ath11k_hal_dump_srng_stats(ab);
queue_work(ab->workqueue, &ab->restart_work);
@ -2742,4 +2756,5 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab)
ath11k_qmi_m3_free(ab);
ath11k_qmi_free_target_mem_chunk(ab);
}
EXPORT_SYMBOL(ath11k_qmi_deinit_service);

View File

@ -1688,7 +1688,8 @@ int ath11k_wmi_vdev_install_key(struct ath11k *ar,
static inline void
ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
struct peer_assoc_params *param)
struct peer_assoc_params *param,
bool hw_crypto_disabled)
{
cmd->peer_flags = 0;
@ -1742,7 +1743,8 @@ ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
cmd->peer_flags |= WMI_PEER_AUTH;
if (param->need_ptk_4_way) {
cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
cmd->peer_flags &= ~WMI_PEER_AUTH;
if (!hw_crypto_disabled)
cmd->peer_flags &= ~WMI_PEER_AUTH;
}
if (param->need_gtk_2_way)
cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
@ -1809,7 +1811,9 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar,
cmd->peer_new_assoc = param->peer_new_assoc;
cmd->peer_associd = param->peer_associd;
ath11k_wmi_copy_peer_flags(cmd, param);
ath11k_wmi_copy_peer_flags(cmd, param,
test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED,
&ar->ab->dev_flags));
ether_addr_copy(cmd->peer_macaddr.addr, param->peer_mac);
@ -2209,37 +2213,6 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
}
}
len = params->num_hint_s_ssid * sizeof(struct hint_short_ssid);
tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len);
ptr += TLV_HDR_SIZE;
if (params->num_hint_s_ssid) {
s_ssid = ptr;
for (i = 0; i < params->num_hint_s_ssid; ++i) {
s_ssid->freq_flags = params->hint_s_ssid[i].freq_flags;
s_ssid->short_ssid = params->hint_s_ssid[i].short_ssid;
s_ssid++;
}
}
ptr += len;
len = params->num_hint_bssid * sizeof(struct hint_bssid);
tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len);
ptr += TLV_HDR_SIZE;
if (params->num_hint_bssid) {
hint_bssid = ptr;
for (i = 0; i < params->num_hint_bssid; ++i) {
hint_bssid->freq_flags =
params->hint_bssid[i].freq_flags;
ether_addr_copy(&params->hint_bssid[i].bssid.addr[0],
&hint_bssid->bssid.addr[0]);
hint_bssid++;
}
}
ret = ath11k_wmi_cmd_send(wmi, skb,
WMI_START_SCAN_CMDID);
if (ret) {
@ -3475,6 +3448,35 @@ int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab)
return 0;
}
int ath11k_wmi_set_hw_mode(struct ath11k_base *ab,
enum wmi_host_hw_mode_config_type mode)
{
struct wmi_pdev_set_hw_mode_cmd_param *cmd;
struct sk_buff *skb;
struct ath11k_wmi_base *wmi_ab = &ab->wmi_ab;
int len;
int ret;
len = sizeof(*cmd);
skb = ath11k_wmi_alloc_skb(wmi_ab, len);
cmd = (struct wmi_pdev_set_hw_mode_cmd_param *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SET_HW_MODE_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->pdev_id = WMI_PDEV_ID_SOC;
cmd->hw_mode_index = mode;
ret = ath11k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_HW_MODE_CMDID);
if (ret) {
ath11k_warn(ab, "failed to send WMI_PDEV_SET_HW_MODE_CMDID\n");
dev_kfree_skb(skb);
}
return ret;
}
int ath11k_wmi_cmd_init(struct ath11k_base *ab)
{
struct ath11k_wmi_base *wmi_sc = &ab->wmi_ab;
@ -3493,10 +3495,11 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab)
init_param.hw_mode_id = wmi_sc->preferred_hw_mode;
init_param.mem_chunks = wmi_sc->mem_chunks;
if (ab->hw_params.needs_band_to_mac) {
init_param.num_band_to_mac = ab->num_radios;
ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac);
}
if (ab->hw_params.single_pdev_only)
init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
init_param.num_band_to_mac = ab->num_radios;
ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac);
return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param);
}
@ -6697,6 +6700,59 @@ static void ath11k_probe_resp_tx_status_event(struct ath11k_base *ab,
kfree(tb);
}
static int ath11k_wmi_tlv_wow_wakeup_host_parse(struct ath11k_base *ab,
u16 tag, u16 len,
const void *ptr, void *data)
{
struct wmi_wow_ev_arg *ev = data;
const char *wow_pg_fault;
int wow_pg_len;
switch (tag) {
case WMI_TAG_WOW_EVENT_INFO:
memcpy(ev, ptr, sizeof(*ev));
ath11k_dbg(ab, ATH11K_DBG_WMI, "wow wakeup host reason %d %s\n",
ev->wake_reason, wow_reason(ev->wake_reason));
break;
case WMI_TAG_ARRAY_BYTE:
if (ev && ev->wake_reason == WOW_REASON_PAGE_FAULT) {
wow_pg_fault = ptr;
/* the first 4 bytes are length */
wow_pg_len = *(int *)wow_pg_fault;
wow_pg_fault += sizeof(int);
ath11k_dbg(ab, ATH11K_DBG_WMI, "wow data_len = %d\n",
wow_pg_len);
ath11k_dbg_dump(ab, ATH11K_DBG_WMI,
"wow_event_info_type packet present",
"wow_pg_fault ",
wow_pg_fault,
wow_pg_len);
}
break;
default:
break;
}
return 0;
}
static void ath11k_wmi_event_wow_wakeup_host(struct ath11k_base *ab, struct sk_buff *skb)
{
struct wmi_wow_ev_arg ev = { };
int ret;
ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
ath11k_wmi_tlv_wow_wakeup_host_parse,
&ev);
if (ret) {
ath11k_warn(ab, "failed to parse wmi wow tlv: %d\n", ret);
return;
}
complete(&ab->wow.wakeup_completed);
}
static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
@ -6804,6 +6860,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
case WMI_VDEV_DELETE_RESP_EVENTID:
ath11k_vdev_delete_resp_event(ab, skb);
break;
case WMI_WOW_WAKEUP_HOST_EVENTID:
ath11k_wmi_event_wow_wakeup_host(ab, skb);
break;
/* TODO: Add remaining events */
default:
ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
@ -7018,3 +7077,46 @@ void ath11k_wmi_detach(struct ath11k_base *ab)
ath11k_wmi_free_dbring_caps(ab);
}
int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar)
{
struct wmi_wow_host_wakeup_ind *cmd;
struct sk_buff *skb;
size_t len;
len = sizeof(*cmd);
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_wow_host_wakeup_ind *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
WMI_TAG_WOW_HOSTWAKEUP_FROM_SLEEP_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow host wakeup ind\n");
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
}
int ath11k_wmi_wow_enable(struct ath11k *ar)
{
struct wmi_wow_enable_cmd *cmd;
struct sk_buff *skb;
int len;
len = sizeof(*cmd);
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;
cmd = (struct wmi_wow_enable_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_WOW_ENABLE_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->enable = 1;
cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED;
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow enable\n");
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID);
}

View File

@ -1037,7 +1037,7 @@ enum wmi_tlv_vdev_param {
WMI_VDEV_PARAM_PROTOTYPE = 0x8000,
WMI_VDEV_PARAM_BSS_COLOR,
WMI_VDEV_PARAM_SET_HEMU_MODE,
WMI_VDEV_PARAM_TX_OFDMA_CPLEN,
WMI_VDEV_PARAM_HEOPS_0_31 = 0x8003,
};
enum wmi_tlv_peer_flags {
@ -5044,6 +5044,169 @@ struct ath11k_wmi_base {
struct ath11k_targ_cap *targ_cap;
};
/* WOW structures */
enum wmi_wow_wakeup_event {
WOW_BMISS_EVENT = 0,
WOW_BETTER_AP_EVENT,
WOW_DEAUTH_RECVD_EVENT,
WOW_MAGIC_PKT_RECVD_EVENT,
WOW_GTK_ERR_EVENT,
WOW_FOURWAY_HSHAKE_EVENT,
WOW_EAPOL_RECVD_EVENT,
WOW_NLO_DETECTED_EVENT,
WOW_DISASSOC_RECVD_EVENT,
WOW_PATTERN_MATCH_EVENT,
WOW_CSA_IE_EVENT,
WOW_PROBE_REQ_WPS_IE_EVENT,
WOW_AUTH_REQ_EVENT,
WOW_ASSOC_REQ_EVENT,
WOW_HTT_EVENT,
WOW_RA_MATCH_EVENT,
WOW_HOST_AUTO_SHUTDOWN_EVENT,
WOW_IOAC_MAGIC_EVENT,
WOW_IOAC_SHORT_EVENT,
WOW_IOAC_EXTEND_EVENT,
WOW_IOAC_TIMER_EVENT,
WOW_DFS_PHYERR_RADAR_EVENT,
WOW_BEACON_EVENT,
WOW_CLIENT_KICKOUT_EVENT,
WOW_EVENT_MAX,
};
enum wmi_wow_interface_cfg {
WOW_IFACE_PAUSE_ENABLED,
WOW_IFACE_PAUSE_DISABLED
};
#define C2S(x) case x: return #x
static inline const char *wow_wakeup_event(enum wmi_wow_wakeup_event ev)
{
switch (ev) {
C2S(WOW_BMISS_EVENT);
C2S(WOW_BETTER_AP_EVENT);
C2S(WOW_DEAUTH_RECVD_EVENT);
C2S(WOW_MAGIC_PKT_RECVD_EVENT);
C2S(WOW_GTK_ERR_EVENT);
C2S(WOW_FOURWAY_HSHAKE_EVENT);
C2S(WOW_EAPOL_RECVD_EVENT);
C2S(WOW_NLO_DETECTED_EVENT);
C2S(WOW_DISASSOC_RECVD_EVENT);
C2S(WOW_PATTERN_MATCH_EVENT);
C2S(WOW_CSA_IE_EVENT);
C2S(WOW_PROBE_REQ_WPS_IE_EVENT);
C2S(WOW_AUTH_REQ_EVENT);
C2S(WOW_ASSOC_REQ_EVENT);
C2S(WOW_HTT_EVENT);
C2S(WOW_RA_MATCH_EVENT);
C2S(WOW_HOST_AUTO_SHUTDOWN_EVENT);
C2S(WOW_IOAC_MAGIC_EVENT);
C2S(WOW_IOAC_SHORT_EVENT);
C2S(WOW_IOAC_EXTEND_EVENT);
C2S(WOW_IOAC_TIMER_EVENT);
C2S(WOW_DFS_PHYERR_RADAR_EVENT);
C2S(WOW_BEACON_EVENT);
C2S(WOW_CLIENT_KICKOUT_EVENT);
C2S(WOW_EVENT_MAX);
default:
return NULL;
}
}
enum wmi_wow_wake_reason {
WOW_REASON_UNSPECIFIED = -1,
WOW_REASON_NLOD = 0,
WOW_REASON_AP_ASSOC_LOST,
WOW_REASON_LOW_RSSI,
WOW_REASON_DEAUTH_RECVD,
WOW_REASON_DISASSOC_RECVD,
WOW_REASON_GTK_HS_ERR,
WOW_REASON_EAP_REQ,
WOW_REASON_FOURWAY_HS_RECV,
WOW_REASON_TIMER_INTR_RECV,
WOW_REASON_PATTERN_MATCH_FOUND,
WOW_REASON_RECV_MAGIC_PATTERN,
WOW_REASON_P2P_DISC,
WOW_REASON_WLAN_HB,
WOW_REASON_CSA_EVENT,
WOW_REASON_PROBE_REQ_WPS_IE_RECV,
WOW_REASON_AUTH_REQ_RECV,
WOW_REASON_ASSOC_REQ_RECV,
WOW_REASON_HTT_EVENT,
WOW_REASON_RA_MATCH,
WOW_REASON_HOST_AUTO_SHUTDOWN,
WOW_REASON_IOAC_MAGIC_EVENT,
WOW_REASON_IOAC_SHORT_EVENT,
WOW_REASON_IOAC_EXTEND_EVENT,
WOW_REASON_IOAC_TIMER_EVENT,
WOW_REASON_ROAM_HO,
WOW_REASON_DFS_PHYERR_RADADR_EVENT,
WOW_REASON_BEACON_RECV,
WOW_REASON_CLIENT_KICKOUT_EVENT,
WOW_REASON_PAGE_FAULT = 0x3a,
WOW_REASON_DEBUG_TEST = 0xFF,
};
static inline const char *wow_reason(enum wmi_wow_wake_reason reason)
{
switch (reason) {
C2S(WOW_REASON_UNSPECIFIED);
C2S(WOW_REASON_NLOD);
C2S(WOW_REASON_AP_ASSOC_LOST);
C2S(WOW_REASON_LOW_RSSI);
C2S(WOW_REASON_DEAUTH_RECVD);
C2S(WOW_REASON_DISASSOC_RECVD);
C2S(WOW_REASON_GTK_HS_ERR);
C2S(WOW_REASON_EAP_REQ);
C2S(WOW_REASON_FOURWAY_HS_RECV);
C2S(WOW_REASON_TIMER_INTR_RECV);
C2S(WOW_REASON_PATTERN_MATCH_FOUND);
C2S(WOW_REASON_RECV_MAGIC_PATTERN);
C2S(WOW_REASON_P2P_DISC);
C2S(WOW_REASON_WLAN_HB);
C2S(WOW_REASON_CSA_EVENT);
C2S(WOW_REASON_PROBE_REQ_WPS_IE_RECV);
C2S(WOW_REASON_AUTH_REQ_RECV);
C2S(WOW_REASON_ASSOC_REQ_RECV);
C2S(WOW_REASON_HTT_EVENT);
C2S(WOW_REASON_RA_MATCH);
C2S(WOW_REASON_HOST_AUTO_SHUTDOWN);
C2S(WOW_REASON_IOAC_MAGIC_EVENT);
C2S(WOW_REASON_IOAC_SHORT_EVENT);
C2S(WOW_REASON_IOAC_EXTEND_EVENT);
C2S(WOW_REASON_IOAC_TIMER_EVENT);
C2S(WOW_REASON_ROAM_HO);
C2S(WOW_REASON_DFS_PHYERR_RADADR_EVENT);
C2S(WOW_REASON_BEACON_RECV);
C2S(WOW_REASON_CLIENT_KICKOUT_EVENT);
C2S(WOW_REASON_PAGE_FAULT);
C2S(WOW_REASON_DEBUG_TEST);
default:
return NULL;
}
}
#undef C2S
struct wmi_wow_enable_cmd {
u32 tlv_header;
u32 enable;
u32 pause_iface_config;
u32 flags;
} __packed;
struct wmi_wow_host_wakeup_ind {
u32 tlv_header;
u32 reserved;
} __packed;
struct wmi_wow_ev_arg {
u32 vdev_id;
u32 flag;
enum wmi_wow_wake_reason wake_reason;
u32 data_len;
};
int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
u32 cmd_id);
struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
@ -5171,4 +5334,9 @@ int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval,
bool unsol_bcast_probe_resp_enabled);
int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id,
struct sk_buff *tmpl);
int ath11k_wmi_set_hw_mode(struct ath11k_base *ab,
enum wmi_host_hw_mode_config_type mode);
int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar);
int ath11k_wmi_wow_enable(struct ath11k *ar);
#endif

View File

@ -0,0 +1,73 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
*/
#include <linux/delay.h>
#include "mac.h"
#include "core.h"
#include "hif.h"
#include "debug.h"
#include "wmi.h"
#include "wow.h"
int ath11k_wow_enable(struct ath11k_base *ab)
{
struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
int i, ret;
clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
for (i = 0; i < ATH11K_WOW_RETRY_NUM; i++) {
reinit_completion(&ab->htc_suspend);
ret = ath11k_wmi_wow_enable(ar);
if (ret) {
ath11k_warn(ab, "failed to issue wow enable: %d\n", ret);
return ret;
}
ret = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);
if (ret == 0) {
ath11k_warn(ab,
"timed out while waiting for htc suspend completion\n");
return -ETIMEDOUT;
}
if (test_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags))
/* success, suspend complete received */
return 0;
ath11k_warn(ab, "htc suspend not complete, retrying (try %d)\n",
i);
msleep(ATH11K_WOW_RETRY_WAIT_MS);
}
ath11k_warn(ab, "htc suspend not complete, failing after %d tries\n", i);
return -ETIMEDOUT;
}
int ath11k_wow_wakeup(struct ath11k_base *ab)
{
struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
int ret;
reinit_completion(&ab->wow.wakeup_completed);
ret = ath11k_wmi_wow_host_wakeup_ind(ar);
if (ret) {
ath11k_warn(ab, "failed to send wow wakeup indication: %d\n",
ret);
return ret;
}
ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
if (ret == 0) {
ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
return -ETIMEDOUT;
}
return 0;
}

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
*/
#define ATH11K_WOW_RETRY_NUM 3
#define ATH11K_WOW_RETRY_WAIT_MS 200
int ath11k_wow_enable(struct ath11k_base *ab);
int ath11k_wow_wakeup(struct ath11k_base *ab);

View File

@ -433,6 +433,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
case NL80211_IFTYPE_STATION:
if (ah->assoc)
rfilt |= AR5K_RX_FILTER_BEACON;
break;
default:
break;
}

View File

@ -189,7 +189,7 @@ static ssize_t read_file_phy_err(struct file *file, char __user *user_buf,
{
#define PHY_ERR(s, p) \
len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \
rxstats->phy_err_stats[p]);
rxstats->phy_err_stats[p])
struct ath_rx_stats *rxstats = file->private_data;
char *buf;

View File

@ -26,7 +26,7 @@ static struct ath_dfs_pool_stats dfs_pool_stats = { 0 };
#define ATH9K_DFS_STAT(s, p) \
len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
sc->debug.stats.dfs_stats.p);
sc->debug.stats.dfs_stats.p)
#define ATH9K_DFS_POOL_STAT(s, p) \
len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
dfs_pool_stats.p);

View File

@ -297,7 +297,12 @@ static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv,
tx_hdr.data_type = ATH9K_HTC_NORMAL;
}
if (ieee80211_is_data_qos(hdr->frame_control)) {
/* Transmit all frames that should not be reordered relative
* to each other using the same priority. For other QoS data
* frames extract the priority from the header.
*/
if (!(tx_info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) &&
ieee80211_is_data_qos(hdr->frame_control)) {
qc = ieee80211_get_qos_ctl(hdr);
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}

View File

@ -45,7 +45,7 @@
#include "cmd.h"
#define ADD(buf, off, max, fmt, args...) \
off += scnprintf(&buf[off], max - off, fmt, ##args);
off += scnprintf(&buf[off], max - off, fmt, ##args)
struct carl9170_debugfs_fops {
@ -818,7 +818,7 @@ void carl9170_debugfs_register(struct ar9170 *ar)
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \
ar->debug_dir, ar, \
&carl_debugfs_##name ## _ops.fops);
&carl_debugfs_##name ## _ops.fops)
DEBUGFS_ADD(usb_tx_anch_urbs);
DEBUGFS_ADD(usb_rx_pool_urbs);

View File

@ -840,6 +840,7 @@ static bool carl9170_tx_rts_check(struct ar9170 *ar,
case CARL9170_ERP_RTS:
if (likely(!multi))
return true;
break;
default:
break;

View File

@ -2570,7 +2570,7 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_SCAN_IND_FAILED:
case WCN36XX_HAL_SCAN_IND_DEQUEUED:
scan_info.aborted = true;
/* fall through */
fallthrough;
case WCN36XX_HAL_SCAN_IND_COMPLETED:
mutex_lock(&wcn->scan_lock);
wcn->scan_req = NULL;