Merge tag 'ath-next-20260803' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath

Jeff Johnson says:
==================
ath.git patches for v7.3 (PR #2)

For ath12k, add MultiPD support for AHB platforms. Other than that, just an
assortment of cleanups and minor bug fixes across ath6kl, ath10k, ath11k,
and ath12k.
==================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg
2026-08-06 14:00:02 +02:00
23 changed files with 553 additions and 123 deletions

View File

@@ -6,6 +6,7 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -1475,11 +1476,15 @@ static void ath10k_msa_dump_memory(struct ath10k *ar,
hdr->length = cpu_to_le32(ar->msa.mem_size);
if (current_region->len < ar->msa.mem_size) {
memcpy(buf, ar->msa.vaddr, current_region->len);
memcpy_fromio(buf,
(const void __iomem __force *)ar->msa.vaddr,
current_region->len);
ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",
current_region->len, ar->msa.mem_size);
} else {
memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);
memcpy_fromio(buf,
(const void __iomem __force *)ar->msa.vaddr,
ar->msa.mem_size);
}
}

View File

@@ -156,6 +156,14 @@ static void ath10k_tm_event_segmented(struct ath10k *ar, u32 cmd_id, struct sk_b
cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
}
static bool ath10k_tm_is_utf_event(u32 cmd_id)
{
return cmd_id == WMI_10X_PDEV_UTF_EVENTID ||
cmd_id == WMI_10_2_PDEV_UTF_EVENTID ||
cmd_id == WMI_10_4_PDEV_UTF_EVENTID ||
cmd_id == WMI_TLV_PDEV_UTF_EVENTID;
}
/* Returns true if callee consumes the skb and the skb should be discarded.
* Returns false if skb is not used. Does not sleep.
*/
@@ -182,6 +190,12 @@ bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
*/
consumed = true;
if (!ath10k_tm_is_utf_event(cmd_id)) {
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
"testmode drop non-utf event cmd_id %u\n", cmd_id);
goto out;
}
if (ar->testmode.expected_seq != ATH10K_FTM_SEG_NONE)
ath10k_tm_event_segmented(ar, cmd_id, skb);
else

View File

@@ -431,36 +431,44 @@ static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
}
static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
static void ath11k_ahb_free_ext_irq_grp(struct ath11k_base *ab,
struct ath11k_ext_irq_grp *irq_grp)
{
int i, j;
int j;
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
for (j = 0; j < irq_grp->num_irq; j++)
free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
for (j = 0; j < irq_grp->num_irq; j++)
free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
netif_napi_del(&irq_grp->napi);
free_netdev(irq_grp->napi_ndev);
}
netif_napi_del(&irq_grp->napi);
free_netdev(irq_grp->napi_ndev);
}
static void ath11k_ahb_free_irq(struct ath11k_base *ab)
static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
{
int irq_idx;
int i;
if (ab->hw_params.hybrid_bus_type)
return ath11k_pcic_free_irq(ab);
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++)
ath11k_ahb_free_ext_irq_grp(ab, &ab->ext_irq_grp[i]);
}
for (i = 0; i < ab->hw_params.ce_count; i++) {
static void ath11k_ahb_free_ce_irqs(struct ath11k_base *ab, int max_idx)
{
int irq_idx, i;
for (i = 0; i < max_idx; i++) {
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
continue;
irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
}
}
static void ath11k_ahb_free_irq(struct ath11k_base *ab)
{
if (ab->hw_params.hybrid_bus_type)
return ath11k_pcic_free_irq(ab);
ath11k_ahb_free_ce_irqs(ab, ab->hw_params.ce_count);
ath11k_ahb_free_ext_irq(ab);
}
@@ -524,20 +532,25 @@ static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
{
struct ath11k_hw_params *hw = &ab->hw_params;
struct ath11k_ext_irq_grp *irq_grp;
int i, j;
int irq;
int ret;
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
u32 num_irq = 0;
irq_grp = &ab->ext_irq_grp[i];
irq_grp->ab = ab;
irq_grp->grp_id = i;
irq_grp->napi_ndev = alloc_netdev_dummy(0);
if (!irq_grp->napi_ndev)
return -ENOMEM;
if (!irq_grp->napi_ndev) {
ret = -ENOMEM;
irq_grp->num_irq = 0;
goto err_request_irq;
}
netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,
ath11k_ahb_ext_grp_napi_poll);
@@ -585,14 +598,11 @@ static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
}
}
}
irq_grp->num_irq = num_irq;
for (j = 0; j < irq_grp->num_irq; j++) {
for (j = 0; j < num_irq; j++) {
int irq_idx = irq_grp->irqs[j];
irq = platform_get_irq_byname(ab->pdev,
irq_name[irq_idx]);
ab->irq_num[irq_idx] = irq;
irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
IRQF_TRIGGER_RISING,
@@ -600,11 +610,24 @@ static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
if (ret) {
ath11k_err(ab, "failed request_irq for %d\n",
irq);
irq_grp->num_irq = j;
ath11k_ahb_free_ext_irq_grp(ab, irq_grp);
goto err_request_irq;
}
ab->irq_num[irq_idx] = irq;
}
irq_grp->num_irq = num_irq;
}
return 0;
err_request_irq:
for (i--; i >= 0; i--) {
irq_grp = &ab->ext_irq_grp[i];
ath11k_ahb_free_ext_irq_grp(ab, irq_grp);
}
return ret;
}
static int ath11k_ahb_config_irq(struct ath11k_base *ab)
@@ -629,16 +652,24 @@ static int ath11k_ahb_config_irq(struct ath11k_base *ab)
ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
IRQF_TRIGGER_RISING, irq_name[irq_idx],
ce_pipe);
if (ret)
if (ret) {
ath11k_err(ab, "failed request_irq for %d\n", irq);
ath11k_ahb_free_ce_irqs(ab, i);
return ret;
}
ab->irq_num[irq_idx] = irq;
}
/* Configure external interrupts */
ret = ath11k_ahb_config_ext_irq(ab);
if (ret) {
ath11k_err(ab, "failed to configure ext irq: %d\n", ret);
ath11k_ahb_free_ce_irqs(ab, ab->hw_params.ce_count);
return ret;
}
return ret;
return 0;
}
static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,

View File

@@ -159,6 +159,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
.min_len = sizeof(struct ath11k_wmi_p2p_noa_info) },
[WMI_TAG_P2P_NOA_EVENT] = {
.min_len = sizeof(struct wmi_p2p_noa_event) },
[WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT] = {
.min_len = sizeof(struct wmi_pdev_csa_switch_ev) },
};
#define PRIMAP(_hw_mode_) \
@@ -262,6 +264,13 @@ const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,
return tb;
}
static u32 ath11k_wmi_tlv_data_len(const void *data)
{
const struct wmi_tlv *tlv = (const struct wmi_tlv *)data - 1;
return FIELD_GET(WMI_TLV_LEN, tlv->header);
}
static int ath11k_wmi_cmd_send_nowait(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
u32 cmd_id)
{
@@ -4800,14 +4809,16 @@ static int ath11k_wmi_tlv_mac_phy_caps_parse(struct ath11k_base *soc,
if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id)
return -ENOBUFS;
len = min_t(u16, len, sizeof(struct wmi_mac_phy_capabilities));
if (!svc_rdy_ext->n_mac_phy_caps) {
svc_rdy_ext->mac_phy_caps = kcalloc(svc_rdy_ext->tot_phy_id,
len, GFP_ATOMIC);
svc_rdy_ext->mac_phy_caps =
kzalloc_objs(*svc_rdy_ext->mac_phy_caps,
svc_rdy_ext->tot_phy_id,
GFP_ATOMIC);
if (!svc_rdy_ext->mac_phy_caps)
return -ENOMEM;
}
len = min_t(u16, len, sizeof(struct wmi_mac_phy_capabilities));
memcpy(svc_rdy_ext->mac_phy_caps + svc_rdy_ext->n_mac_phy_caps, ptr, len);
svc_rdy_ext->n_mac_phy_caps++;
return 0;
@@ -5124,6 +5135,7 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab,
return 0;
err:
kfree(svc_rdy_ext.mac_phy_caps);
ath11k_wmi_free_dbring_caps(ab);
return ret;
}
@@ -8359,15 +8371,23 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab,
const struct wmi_pdev_csa_switch_ev *ev,
const u32 *vdev_ids)
{
int i;
u32 vdev_ids_len = ath11k_wmi_tlv_data_len(vdev_ids);
u32 num_vdevs = ev->num_vdevs;
struct ath11k_vif *arvif;
int i;
/* Finish CSA once the switch count becomes NULL */
if (ev->current_switch_count)
return;
if (num_vdevs > vdev_ids_len / sizeof(*vdev_ids)) {
ath11k_warn(ab, "csa switch count num_vdevs %u exceeds tlv array length %u\n",
num_vdevs, vdev_ids_len);
return;
}
rcu_read_lock();
for (i = 0; i < ev->num_vdevs; i++) {
for (i = 0; i < num_vdevs; i++) {
arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);
if (!arvif) {

View File

@@ -25,6 +25,22 @@ static const char ath12k_userpd_irq[][9] = {"spawn",
"ready",
"stop-ack"};
/*
* Multi-UserPD Architecture:
*
* One Q6 RootPD (managed by separate rproc driver) supports multiple
* ath12k UserPDs. Each UserPD represents a WiFi radio instance.
*
* Lifecycle:
* - RootPD boots when first UserPD probes
* - All UserPDs share RootPD's SSR notifier
*
* Locking:
* - ath12k_rproc_info_lock: Protects g_rproc_info allocation/free
*/
static struct ath12k_ahb_rproc_info *g_rproc_info;
static DEFINE_MUTEX(ath12k_rproc_info_lock);
static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"misc-pulse1",
"misc-latch",
@@ -704,7 +720,7 @@ static int ath12k_ahb_map_service_to_pipe(struct ath12k_base *ab, u16 service_id
return 0;
}
static const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
.start = ath12k_ahb_start,
.stop = ath12k_ahb_stop,
.read32 = ath12k_ahb_read32,
@@ -715,6 +731,7 @@ static const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
.power_up = ath12k_ahb_power_up,
.power_down = ath12k_ahb_power_down,
};
EXPORT_SYMBOL(ath12k_ahb_hif_ops);
static irqreturn_t ath12k_userpd_irq_handler(int irq, void *data)
{
@@ -785,44 +802,85 @@ static int ath12k_ahb_config_rproc_irq(struct ath12k_base *ab)
static int ath12k_ahb_root_pd_state_notifier(struct notifier_block *nb,
const unsigned long event, void *data)
{
struct ath12k_ahb *ab_ahb = container_of(nb, struct ath12k_ahb, root_pd_nb);
struct ath12k_base *ab = ab_ahb->ab;
struct ath12k_ahb_rproc_info *rproc_info =
container_of(nb, struct ath12k_ahb_rproc_info, root_pd_nb);
if (event == ATH12K_RPROC_AFTER_POWERUP) {
ath12k_dbg(ab, ATH12K_DBG_AHB, "Root PD is UP\n");
complete(&ab_ahb->rootpd_ready);
ath12k_generic_dbg(ATH12K_DBG_AHB, "Root PD is UP\n");
complete(&rproc_info->rootpd_ready);
}
return 0;
}
static int ath12k_ahb_register_rproc_notifier(struct ath12k_base *ab)
static int ath12k_ahb_register_rproc_notifier(void)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
int ret;
ab_ahb->root_pd_nb.notifier_call = ath12k_ahb_root_pd_state_notifier;
init_completion(&ab_ahb->rootpd_ready);
lockdep_assert_held(&ath12k_rproc_info_lock);
ab_ahb->root_pd_notifier = qcom_register_ssr_notifier(ab_ahb->tgt_rproc->name,
&ab_ahb->root_pd_nb);
if (IS_ERR(ab_ahb->root_pd_notifier))
return PTR_ERR(ab_ahb->root_pd_notifier);
if (g_rproc_info->root_pd_notifier)
return 0;
g_rproc_info->root_pd_nb.notifier_call = ath12k_ahb_root_pd_state_notifier;
g_rproc_info->root_pd_notifier =
qcom_register_ssr_notifier(g_rproc_info->tgt_rproc->name,
&g_rproc_info->root_pd_nb);
if (IS_ERR(g_rproc_info->root_pd_notifier)) {
ret = PTR_ERR(g_rproc_info->root_pd_notifier);
g_rproc_info->root_pd_notifier = NULL;
return ret;
}
return 0;
}
static void ath12k_ahb_unregister_rproc_notifier(struct ath12k_base *ab)
static void ath12k_ahb_unregister_rproc_notifier(void)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
lockdep_assert_held(&ath12k_rproc_info_lock);
if (!ab_ahb->root_pd_notifier) {
ath12k_err(ab, "Rproc notifier not registered\n");
if (!g_rproc_info->root_pd_notifier)
return;
}
qcom_unregister_ssr_notifier(ab_ahb->root_pd_notifier,
&ab_ahb->root_pd_nb);
ab_ahb->root_pd_notifier = NULL;
qcom_unregister_ssr_notifier(g_rproc_info->root_pd_notifier,
&g_rproc_info->root_pd_nb);
g_rproc_info->root_pd_notifier = NULL;
}
static void ath12k_ahb_cleanup_userpd(struct ath12k_base *ab)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
lockdep_assert_held(&ath12k_rproc_info_lock);
if (!rproc_info)
return;
rproc_info->userpd[ab_ahb->userpd_id - 1] = NULL;
rproc_info->num_userpd--;
ab_ahb->rproc_info = NULL;
}
static struct ath12k_ahb_rproc_info *ath12k_ahb_rproc_info_alloc(struct ath12k_base *ab)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
struct ath12k_ahb_rproc_info *rproc_info;
lockdep_assert_held(&ath12k_rproc_info_lock);
rproc_info = kzalloc_obj(*rproc_info, GFP_KERNEL);
if (!rproc_info)
return NULL;
rproc_info->rootpd_booted_by_driver = false;
rproc_info->userpd[ab_ahb->userpd_id - 1] = ab_ahb;
rproc_info->num_userpd = 1;
init_completion(&rproc_info->rootpd_ready);
ab_ahb->rproc_info = rproc_info;
return rproc_info;
}
static int ath12k_ahb_get_rproc(struct ath12k_base *ab)
@@ -831,37 +889,69 @@ static int ath12k_ahb_get_rproc(struct ath12k_base *ab)
struct device *dev = ab->dev;
struct device_node *np;
struct rproc *prproc;
int ret;
lockdep_assert_held(&ath12k_rproc_info_lock);
if (ab_ahb->userpd_id > ATH12K_MAX_DEVICES)
return -ENOSPC;
if (g_rproc_info) {
if (g_rproc_info->num_userpd >= ATH12K_MAX_DEVICES) {
ath12k_err(ab, "Max UserPD limit reached\n");
return -ENOSPC;
}
g_rproc_info->userpd[ab_ahb->userpd_id - 1] = ab_ahb;
g_rproc_info->num_userpd++;
ab_ahb->rproc_info = g_rproc_info;
return 0;
}
g_rproc_info = ath12k_ahb_rproc_info_alloc(ab);
if (!g_rproc_info)
return -ENOMEM;
np = of_parse_phandle(dev->of_node, "qcom,rproc", 0);
if (!np) {
ath12k_err(ab, "failed to get q6_rproc handle\n");
return -ENOENT;
ret = -ENOENT;
goto err_free_rproc_info;
}
prproc = rproc_get_by_phandle(np->phandle);
of_node_put(np);
if (!prproc)
return dev_err_probe(&ab->pdev->dev, -EPROBE_DEFER,
"failed to get rproc\n");
ab_ahb->tgt_rproc = prproc;
if (!prproc) {
ret = dev_err_probe(&ab->pdev->dev, -EPROBE_DEFER,
"failed to get rproc\n");
goto err_free_rproc_info;
}
g_rproc_info->tgt_rproc = prproc;
return 0;
err_free_rproc_info:
ab_ahb->rproc_info = NULL;
kfree(g_rproc_info);
g_rproc_info = NULL;
return ret;
}
static int ath12k_ahb_boot_root_pd(struct ath12k_base *ab)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
unsigned long time_left;
int ret;
ret = rproc_boot(ab_ahb->tgt_rproc);
lockdep_assert_held(&ath12k_rproc_info_lock);
reinit_completion(&g_rproc_info->rootpd_ready);
ret = rproc_boot(g_rproc_info->tgt_rproc);
if (ret < 0) {
ath12k_err(ab, "RootPD boot failed\n");
return ret;
}
time_left = wait_for_completion_timeout(&ab_ahb->rootpd_ready,
time_left = wait_for_completion_timeout(&g_rproc_info->rootpd_ready,
ATH12K_ROOTPD_READY_TIMEOUT);
if (!time_left) {
ath12k_err(ab, "RootPD ready wait timed out\n");
@@ -873,44 +963,74 @@ static int ath12k_ahb_boot_root_pd(struct ath12k_base *ab)
static int ath12k_ahb_configure_rproc(struct ath12k_base *ab)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
int ret;
ret = ath12k_ahb_get_rproc(ab);
if (ret < 0)
return ret;
mutex_lock(&ath12k_rproc_info_lock);
ret = ath12k_ahb_register_rproc_notifier(ab);
ret = ath12k_ahb_get_rproc(ab);
if (ret < 0) {
mutex_unlock(&ath12k_rproc_info_lock);
return ret;
}
ret = ath12k_ahb_register_rproc_notifier();
if (ret < 0) {
ret = dev_err_probe(&ab->pdev->dev, ret,
"failed to register rproc notifier\n");
goto err_put_rproc;
goto err_cleanup_userpd;
}
if (ab_ahb->tgt_rproc->state != RPROC_RUNNING) {
if (g_rproc_info->tgt_rproc->state != RPROC_RUNNING) {
ret = ath12k_ahb_boot_root_pd(ab);
if (ret < 0) {
ath12k_err(ab, "failed to boot the remote processor Q6\n");
goto err_unreg_notifier;
}
g_rproc_info->rootpd_booted_by_driver = true;
}
return ath12k_ahb_config_rproc_irq(ab);
mutex_unlock(&ath12k_rproc_info_lock);
return 0;
err_unreg_notifier:
ath12k_ahb_unregister_rproc_notifier(ab);
ath12k_ahb_unregister_rproc_notifier();
err_put_rproc:
rproc_put(ab_ahb->tgt_rproc);
err_cleanup_userpd:
ath12k_ahb_cleanup_userpd(ab);
if (g_rproc_info && !g_rproc_info->num_userpd) {
rproc_put(g_rproc_info->tgt_rproc);
kfree(g_rproc_info);
g_rproc_info = NULL;
}
mutex_unlock(&ath12k_rproc_info_lock);
return ret;
}
static void ath12k_ahb_deconfigure_rproc(struct ath12k_base *ab)
{
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
ath12k_ahb_unregister_rproc_notifier(ab);
rproc_put(ab_ahb->tgt_rproc);
lockdep_assert_held(&ath12k_rproc_info_lock);
if (!rproc_info || !g_rproc_info)
return;
ath12k_ahb_cleanup_userpd(ab);
if (!g_rproc_info->num_userpd) {
ath12k_ahb_unregister_rproc_notifier();
if (g_rproc_info->rootpd_booted_by_driver &&
g_rproc_info->tgt_rproc->state == RPROC_RUNNING)
rproc_shutdown(g_rproc_info->tgt_rproc);
rproc_put(g_rproc_info->tgt_rproc);
kfree(g_rproc_info);
g_rproc_info = NULL;
}
}
static int ath12k_ahb_resource_init(struct ath12k_base *ab)
@@ -1038,7 +1158,6 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
ab_ahb = ath12k_ab_to_ahb(ab);
ab_ahb->ab = ab;
ab->hif.ops = &ath12k_ahb_hif_ops;
ab->pdev = pdev;
platform_set_drvdata(pdev, ab);
@@ -1094,6 +1213,10 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
if (ret)
goto err_ce_free;
ret = ath12k_ahb_config_rproc_irq(ab);
if (ret)
goto err_rproc_deconfigure;
ret = ath12k_ahb_config_irq(ab);
if (ret) {
ath12k_err(ab, "failed to configure irq: %d\n", ret);
@@ -1121,7 +1244,9 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
ab_ahb->device_family_ops->arch_deinit(ab);
err_rproc_deconfigure:
mutex_lock(&ath12k_rproc_info_lock);
ath12k_ahb_deconfigure_rproc(ab);
mutex_unlock(&ath12k_rproc_info_lock);
err_ce_free:
ath12k_ce_free_pipes(ab);
@@ -1163,7 +1288,9 @@ static void ath12k_ahb_free_resources(struct ath12k_base *ab)
ath12k_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
ath12k_ahb_resource_deinit(ab);
mutex_lock(&ath12k_rproc_info_lock);
ath12k_ahb_deconfigure_rproc(ab);
mutex_unlock(&ath12k_rproc_info_lock);
ab_ahb->device_family_ops->arch_deinit(ab);
ath12k_core_free(ab);
platform_set_drvdata(pdev, NULL);

View File

@@ -30,6 +30,24 @@
#define ATH12K_USERPD_ID_MASK GENMASK(10, 8)
#define ATH12K_USERPD_FW_NAME_LEN 35
enum ath12k_ahb_userpd_id {
ATH12K_AHB_USERPD_ID_0 = 1,
ATH12K_AHB_USERPD_ID_1,
ATH12K_AHB_USERPD_ID_2,
};
struct ath12k_ahb_userpd_map {
phys_addr_t io_start;
const char *node_name;
u32 upd_id;
};
struct ath12k_ahb_desc {
enum ath12k_hw_rev hw_rev;
bool auth_enabled;
const struct ath12k_hif_ops *ops;
};
enum ath12k_ahb_smp2p_msg_id {
ATH12K_AHB_POWER_SAVE_ENTER = 1,
ATH12K_AHB_POWER_SAVE_EXIT,
@@ -43,6 +61,7 @@ enum ath12k_ahb_userpd_irq {
};
struct ath12k_base;
extern const struct ath12k_hif_ops ath12k_ahb_hif_ops;
struct ath12k_ahb_device_family_ops {
int (*probe)(struct platform_device *pdev);
@@ -50,13 +69,19 @@ struct ath12k_ahb_device_family_ops {
void (*arch_deinit)(struct ath12k_base *ab);
};
struct ath12k_ahb {
struct ath12k_base *ab;
struct ath12k_ahb_rproc_info {
struct rproc *tgt_rproc;
struct clk *xo_clk;
struct completion rootpd_ready;
struct notifier_block root_pd_nb;
void *root_pd_notifier;
struct completion rootpd_ready;
u8 num_userpd;
bool rootpd_booted_by_driver;
struct ath12k_ahb *userpd[ATH12K_MAX_DEVICES];
};
struct ath12k_ahb {
struct ath12k_base *ab;
struct clk *xo_clk;
struct qcom_smem_state *spawn_state;
struct qcom_smem_state *stop_state;
struct completion userpd_spawned;
@@ -69,6 +94,7 @@ struct ath12k_ahb {
const struct ath12k_ahb_ops *ahb_ops;
const struct ath12k_ahb_device_family_ops *device_family_ops;
bool scm_auth_enabled;
struct ath12k_ahb_rproc_info *rproc_info;
};
struct ath12k_ahb_driver {

View File

@@ -23,6 +23,7 @@
#include "wow.h"
#include "dp_cmn.h"
#include "peer.h"
#include "qmi.h"
unsigned int ath12k_debug_mask;
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
@@ -52,6 +53,7 @@ ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = {
.rxdma_monitor_dst_ring_size = 8192,
.num_pool_tx_desc = 32768,
.rx_desc_count = 12288,
.rx_release_ring_size = 16384,
},
},
[ATH12K_QMI_MEMORY_MODE_LOW_512_M] = {
@@ -65,6 +67,7 @@ ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = {
.rxdma_monitor_dst_ring_size = 512,
.num_pool_tx_desc = 16384,
.rx_desc_count = 6144,
.rx_release_ring_size = 8192,
},
},
};
@@ -794,7 +797,7 @@ static int ath12k_core_soc_create(struct ath12k_base *ab)
int ret;
if (ath12k_ftm_mode) {
ab->fw_mode = ATH12K_FIRMWARE_MODE_FTM;
ab->fw_mode = ATH12K_QMI_FIRMWARE_MODE_FTM;
ath12k_info(ab, "Booting in ftm mode\n");
}
@@ -1188,7 +1191,7 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
}
static int ath12k_core_start_firmware(struct ath12k_base *ab,
enum ath12k_firmware_mode mode)
enum ath12k_qmi_firmware_mode mode)
{
int ret;

View File

@@ -160,14 +160,6 @@ enum ath12k_hw_rev {
ATH12K_HW_IPQ5424_HW10,
};
enum ath12k_firmware_mode {
/* the default mode, standard 802.11 functionality */
ATH12K_FIRMWARE_MODE_NORMAL,
/* factory tests etc */
ATH12K_FIRMWARE_MODE_FTM,
};
#define ATH12K_IRQ_NUM_MAX 57
#define ATH12K_EXT_IRQ_NUM_MAX 16
#define ATH12K_MAX_TCL_RING_NUM 3
@@ -939,6 +931,7 @@ struct ath12k_dp_profile_params {
u32 rxdma_monitor_dst_ring_size;
u32 num_pool_tx_desc;
u32 rx_desc_count;
u32 rx_release_ring_size;
};
struct ath12k_mem_profile_based_param {
@@ -1147,7 +1140,7 @@ struct ath12k_base {
struct ath12k_hw_group *ag;
struct ath12k_wsi_info wsi_info;
enum ath12k_firmware_mode fw_mode;
enum ath12k_qmi_firmware_mode fw_mode;
struct ath12k_ftm_event_obj ftm_event_obj;
bool hw_group_ref;

View File

@@ -487,7 +487,7 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab)
ret = ath12k_dp_srng_setup(ab, &dp->rx_rel_ring, HAL_WBM2SW_RELEASE,
HAL_WBM2SW_REL_ERR_RING_NUM, 0,
DP_RX_RELEASE_RING_SIZE);
DP_RX_RELEASE_RING_SIZE(ab));
if (ret) {
ath12k_warn(ab, "failed to set up rx_rel ring :%d\n", ret);
goto err;

View File

@@ -200,7 +200,8 @@ struct ath12k_pdev_dp {
#define DP_REO_DST_RING_MAX 8
#define DP_REO_DST_RING_SIZE 2048
#define DP_REO_REINJECT_RING_SIZE 32
#define DP_RX_RELEASE_RING_SIZE 1024
#define DP_RX_RELEASE_RING_SIZE(ab) \
((ab)->profile_param->dp_params.rx_release_ring_size)
#define DP_REO_EXCEPTION_RING_SIZE 128
#define DP_REO_CMD_RING_SIZE 256
#define DP_REO_STATUS_RING_SIZE 2048

View File

@@ -82,6 +82,52 @@ enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher)
}
EXPORT_SYMBOL(ath12k_dp_tx_get_encrypt_type);
u8 ath12k_dp_tx_crypto_iv_len(enum hal_encrypt_type enc_type)
{
switch (enc_type) {
case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
case HAL_ENCRYPT_TYPE_TKIP_MIC:
return IEEE80211_TKIP_IV_LEN;
case HAL_ENCRYPT_TYPE_CCMP_128:
return IEEE80211_CCMP_HDR_LEN;
case HAL_ENCRYPT_TYPE_CCMP_256:
return IEEE80211_CCMP_256_HDR_LEN;
case HAL_ENCRYPT_TYPE_GCMP_128:
case HAL_ENCRYPT_TYPE_AES_GCMP_256:
return IEEE80211_GCMP_HDR_LEN;
case HAL_ENCRYPT_TYPE_WEP_40:
case HAL_ENCRYPT_TYPE_WEP_104:
case HAL_ENCRYPT_TYPE_WEP_128:
return IEEE80211_WEP_IV_LEN;
default:
return 0;
}
}
EXPORT_SYMBOL(ath12k_dp_tx_crypto_iv_len);
u8 ath12k_dp_tx_crypto_icv_len(enum hal_encrypt_type enc_type)
{
switch (enc_type) {
case HAL_ENCRYPT_TYPE_CCMP_128:
return IEEE80211_CCMP_MIC_LEN;
case HAL_ENCRYPT_TYPE_CCMP_256:
return IEEE80211_CCMP_256_MIC_LEN;
case HAL_ENCRYPT_TYPE_GCMP_128:
case HAL_ENCRYPT_TYPE_AES_GCMP_256:
return IEEE80211_GCMP_MIC_LEN;
case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
case HAL_ENCRYPT_TYPE_TKIP_MIC:
return IEEE80211_TKIP_ICV_LEN;
case HAL_ENCRYPT_TYPE_WEP_40:
case HAL_ENCRYPT_TYPE_WEP_104:
case HAL_ENCRYPT_TYPE_WEP_128:
return IEEE80211_WEP_ICV_LEN;
default:
return 0;
}
}
EXPORT_SYMBOL(ath12k_dp_tx_crypto_icv_len);
void ath12k_dp_tx_release_txbuf(struct ath12k_dp *dp,
struct ath12k_tx_desc_info *tx_desc,
u8 pool_id)

View File

@@ -19,6 +19,8 @@ enum hal_tcl_encap_type
ath12k_dp_tx_get_encap_type(struct ath12k_base *ab, struct sk_buff *skb);
void ath12k_dp_tx_encap_nwifi(struct sk_buff *skb);
u8 ath12k_dp_tx_get_tid(struct sk_buff *skb);
u8 ath12k_dp_tx_crypto_iv_len(enum hal_encrypt_type enc_type);
u8 ath12k_dp_tx_crypto_icv_len(enum hal_encrypt_type enc_type);
void *ath12k_dp_metadata_align_skb(struct sk_buff *skb, u8 tail_len);
int ath12k_dp_tx_align_payload(struct ath12k_dp *dp, struct sk_buff **pskb);
void ath12k_dp_tx_release_txbuf(struct ath12k_dp *dp,

View File

@@ -100,7 +100,6 @@ struct ieee80211_rx_status;
#define ATH12K_REGDB_FILE_NAME "regdb.bin"
#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128
#define ATH12K_IPQ5332_USERPD_ID 1
enum ath12k_hw_rate_cck {
ATH12K_HW_RATE_CCK_LP_11M = 0,

View File

@@ -859,7 +859,7 @@ struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
return NULL;
for (i = 0; i < ab->num_radios; i++) {
if (ab->fw_mode == ATH12K_FIRMWARE_MODE_FTM)
if (ab->fw_mode == ATH12K_QMI_FIRMWARE_MODE_FTM)
pdev = &ab->pdevs[i];
else
pdev = rcu_dereference(ab->pdevs_active[i]);

View File

@@ -17,6 +17,7 @@
#include "mhi.h"
#include "debug.h"
#include "hal.h"
#include "qmi.h"
#define ATH12K_PCI_BAR_NUM 0
#define ATH12K_PCI_DMA_MASK 36
@@ -1555,7 +1556,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
ab_pci->ab = ab;
ab_pci->pdev = pdev;
ab->hif.ops = &ath12k_pci_hif_ops;
ab->fw_mode = ATH12K_FIRMWARE_MODE_NORMAL;
ab->fw_mode = ATH12K_QMI_FIRMWARE_MODE_NORMAL;
pci_set_drvdata(pdev, ab);
spin_lock_init(&ab_pci->window_lock);

View File

@@ -3431,7 +3431,7 @@ int ath12k_qmi_wlanfw_aux_uc_info_send(struct ath12k_base *ab)
}
static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
u32 mode)
enum ath12k_qmi_firmware_mode mode)
{
struct qmi_wlanfw_wlan_mode_req_msg_v01 req = {};
struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp = {};
@@ -3460,7 +3460,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS));
if (ret < 0) {
if (mode == ATH12K_FIRMWARE_MODE_OFF && ret == -ENETRESET) {
if (mode == ATH12K_QMI_FIRMWARE_MODE_OFF && ret == -ENETRESET) {
ath12k_warn(ab, "WLFW service is dis-connected\n");
return 0;
}
@@ -3623,7 +3623,7 @@ void ath12k_qmi_firmware_stop(struct ath12k_base *ab)
clear_bit(ATH12K_FLAG_QMI_FW_READY_COMPLETE, &ab->dev_flags);
ret = ath12k_qmi_wlanfw_mode_send(ab, ATH12K_FIRMWARE_MODE_OFF);
ret = ath12k_qmi_wlanfw_mode_send(ab, ATH12K_QMI_FIRMWARE_MODE_OFF);
if (ret < 0) {
ath12k_warn(ab, "qmi failed to send wlan mode off\n");
return;
@@ -3631,7 +3631,7 @@ void ath12k_qmi_firmware_stop(struct ath12k_base *ab)
}
int ath12k_qmi_firmware_start(struct ath12k_base *ab,
u32 mode)
enum ath12k_qmi_firmware_mode mode)
{
int ret;

View File

@@ -32,7 +32,6 @@
#define QMI_WLFW_FW_READY_IND_V01 0x0038
#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
#define ATH12K_FIRMWARE_MODE_OFF 4
#define ATH12K_BOARD_ID_DEFAULT 0xFF
@@ -602,6 +601,17 @@ enum ath12k_qmi_mem_mode {
ATH12K_QMI_MEMORY_MODE_LOW_512_M,
};
enum ath12k_qmi_firmware_mode {
/* the default mode, standard 802.11 functionality */
ATH12K_QMI_FIRMWARE_MODE_NORMAL,
/* factory tests etc */
ATH12K_QMI_FIRMWARE_MODE_FTM,
/* firmware offline; values 2-3 reserved by firmware ABI */
ATH12K_QMI_FIRMWARE_MODE_OFF = 4,
};
static inline void ath12k_qmi_set_event_block(struct ath12k_qmi *qmi, bool block)
{
lockdep_assert_held(&qmi->event_lock);
@@ -617,7 +627,7 @@ static inline bool ath12k_qmi_get_event_block(struct ath12k_qmi *qmi)
}
int ath12k_qmi_firmware_start(struct ath12k_base *ab,
u32 mode);
enum ath12k_qmi_firmware_mode mode);
void ath12k_qmi_firmware_stop(struct ath12k_base *ab);
void ath12k_qmi_deinit_service(struct ath12k_base *ab);
int ath12k_qmi_init_service(struct ath12k_base *ab);

View File

@@ -15,44 +15,100 @@
#include "dp.h"
#include "core.h"
/*
* Node name to UserPD ID mapping
*
* The io_start field is used for additional validation when the reg
* property is present in the device tree. If io_start is 0, only
* node_name matching is performed.
*
* For platforms where not all WiFi nodes have a 'reg' property, set
* io_start to 0 for those entries. The driver will match purely by
* node name in such cases.
*/
static const struct ath12k_ahb_userpd_map ath12k_wifi7_ahb_userpd_map[] = {
{ .io_start = 0x0c000000, .node_name = "wifi", .upd_id = ATH12K_AHB_USERPD_ID_0 },
};
static const struct ath12k_ahb_desc ath12k_wifi7_ahb_desc[] = {
[ATH12K_HW_IPQ5332_HW10] = {
.hw_rev = ATH12K_HW_IPQ5332_HW10,
.auth_enabled = true,
.ops = &ath12k_ahb_hif_ops,
},
[ATH12K_HW_IPQ5424_HW10] = {
.hw_rev = ATH12K_HW_IPQ5424_HW10,
.auth_enabled = false,
.ops = &ath12k_ahb_hif_ops,
},
};
static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
{ .compatible = "qcom,ipq5332-wifi",
.data = (void *)ATH12K_HW_IPQ5332_HW10,
.data = (void *)&ath12k_wifi7_ahb_desc[ATH12K_HW_IPQ5332_HW10],
},
{ .compatible = "qcom,ipq5424-wifi",
.data = (void *)ATH12K_HW_IPQ5424_HW10,
.data = (void *)&ath12k_wifi7_ahb_desc[ATH12K_HW_IPQ5424_HW10],
},
{ }
};
MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match);
/*
* ath12k_wifi7_ahb_get_userpd_id - Resolve UserPD ID from DT properties
* @ab: ath12k base structure
*
* Returns: UserPD ID (1-based) on success, 0 on failure
*
* Resolution logic:
* 1. If reg property exist in DT, get userpd_id from io_start
* 2. If reg property is absent, get userpd_id from DT node name
* 3. Return 0 if no match found (probe will fail)
*/
static u32 ath12k_wifi7_ahb_get_userpd_id(struct ath12k_base *ab)
{
const struct ath12k_ahb_userpd_map *map;
struct resource *res;
size_t i;
res = platform_get_resource(ab->pdev, IORESOURCE_MEM, 0);
for (i = 0; i < ARRAY_SIZE(ath12k_wifi7_ahb_userpd_map); i++) {
map = &ath12k_wifi7_ahb_userpd_map[i];
if (res) {
if (map->io_start && map->io_start == res->start)
return map->upd_id;
} else if (map->node_name &&
of_node_name_eq(ab->dev->of_node, map->node_name)) {
return map->upd_id;
}
}
return 0;
}
static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
{
const struct ath12k_ahb_desc *desc;
struct ath12k_ahb *ab_ahb;
enum ath12k_hw_rev hw_rev;
struct ath12k_base *ab;
int ret;
ab = platform_get_drvdata(pdev);
ab_ahb = ath12k_ab_to_ahb(ab);
hw_rev = (enum ath12k_hw_rev)(kernel_ulong_t)of_device_get_match_data(&pdev->dev);
switch (hw_rev) {
case ATH12K_HW_IPQ5332_HW10:
ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
ab_ahb->scm_auth_enabled = true;
break;
case ATH12K_HW_IPQ5424_HW10:
ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
ab_ahb->scm_auth_enabled = false;
break;
default:
desc = of_device_get_match_data(&pdev->dev);
if (!desc)
return -EOPNOTSUPP;
}
ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
ab->hw_rev = hw_rev;
ab->hw_rev = desc->hw_rev;
ab->hif.ops = desc->ops;
ab_ahb->scm_auth_enabled = desc->auth_enabled;
ab_ahb->userpd_id = ath12k_wifi7_ahb_get_userpd_id(ab);
if (!ab_ahb->userpd_id)
return -EOPNOTSUPP;
ret = ath12k_wifi7_hw_init(ab);
if (ret) {

View File

@@ -13,6 +13,49 @@
#include "hal.h"
#include "hal_tx.h"
/*
* Convert an encrypted EAPOL frame from native-WiFi format to
* the layout expected by the firmware RAW encrypt pipeline:
*
* [802.11 hdr][IV (zeroed)][LLC/SNAP][EAPOL payload][ICV (zeroed)]
*
* mac80211 delivers the frame as [802.11 hdr][LLC/SNAP][EAPOL payload].
* The MAC header length is read from the unmodified skb and is safe because
* ieee80211_hdrlen() only inspects the 2-byte frame_control field.
* pskb_expand_head() is used to grow both head (for the IV) and tail
* (for the ICV) in a single call and allocation.
*/
static int
ath12k_wifi7_dp_tx_encap_eapol(struct sk_buff *skb,
struct hal_tx_info *ti,
struct ath12k_skb_cb *skb_cb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
enum hal_encrypt_type enc_type =
ath12k_dp_tx_get_encrypt_type(skb_cb->cipher);
u16 mac_hdr_len = ieee80211_hdrlen(hdr->frame_control);
u8 iv_len = ath12k_dp_tx_crypto_iv_len(enc_type);
u8 icv_len = ath12k_dp_tx_crypto_icv_len(enc_type);
if (pskb_expand_head(skb, iv_len, icv_len, GFP_ATOMIC))
return -ENOMEM;
if (iv_len) {
skb_push(skb, iv_len);
memmove(skb->data, skb->data + iv_len, mac_hdr_len);
memset(skb->data + mac_hdr_len, 0, iv_len);
}
if (icv_len)
memset(skb_put(skb, icv_len), 0, icv_len);
ti->flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
ti->encap_type = HAL_TCL_ENCAP_TYPE_RAW;
ti->encrypt_type = enc_type;
return 0;
}
static void
ath12k_wifi7_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
struct hal_tx_msdu_ext_desc *tcl_ext_cmd,
@@ -91,6 +134,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
u32 iova_mask = dp->hw_params->iova_mask;
bool is_diff_encap = false;
bool is_null_frame = false;
bool eapol_encap_done = false;
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
return -ESHUTDOWN;
@@ -211,9 +255,27 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
is_null_frame = ieee80211_is_nullfunc(hdr->frame_control);
if (ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
if (skb->protocol == cpu_to_be16(ETH_P_PAE) || is_null_frame)
if ((skb->protocol == cpu_to_be16(ETH_P_PAE) &&
!(skb_cb->flags & ATH12K_SKB_CIPHER_SET)) || is_null_frame)
is_diff_encap = true;
if (skb->protocol == cpu_to_be16(ETH_P_PAE) &&
(skb_cb->flags & ATH12K_SKB_CIPHER_SET)) {
if (!eapol_encap_done) {
ret = ath12k_wifi7_dp_tx_encap_eapol(skb, &ti,
skb_cb);
if (ret)
goto fail_remove_tx_buf;
hdr = (void *)skb->data;
eapol_encap_done = true;
} else {
ti.flags0 |= u32_encode_bits(1,
HAL_TCL_DATA_CMD_INFO2_TO_FW);
ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
ti.encrypt_type =
ath12k_dp_tx_get_encrypt_type(skb_cb->cipher);
}
}
/* Firmware expects msdu ext descriptor for nwifi/raw packets
* received in ETH mode. Without this, observed tx fail for
* Multicast packets in ETH mode.

View File

@@ -1032,6 +1032,9 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
continue;
tmp_ar = tmp_arvif->ar;
if (unlikely(test_bit(ATH12K_FLAG_CRASH_FLUSH, &tmp_ar->ab->dev_flags)))
continue;
tmp_dp = ath12k_ab_to_dp(tmp_ar->ab);
tmp_dp_pdev = ath12k_dp_to_pdev_dp(tmp_dp,
tmp_ar->pdev_idx);

View File

@@ -207,6 +207,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
.min_len = sizeof(struct wmi_per_chain_rssi_stat_params) },
[WMI_TAG_OBSS_COLOR_COLLISION_EVT] = {
.min_len = sizeof(struct wmi_obss_color_collision_event) },
[WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT] = {
.min_len = sizeof(struct ath12k_wmi_pdev_csa_event) },
};
__le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
@@ -374,6 +376,13 @@ ath12k_wmi_tlv_parse(struct ath12k_base *ab, struct sk_buff *skb)
return tb;
}
static u32 ath12k_wmi_tlv_data_len(const void *data)
{
const struct wmi_tlv *tlv = (const struct wmi_tlv *)data - 1;
return le32_get_bits(tlv->header, WMI_TLV_LEN);
}
static int ath12k_wmi_cmd_send_nowait(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
u32 cmd_id)
{
@@ -4765,14 +4774,16 @@ static int ath12k_wmi_mac_phy_caps_parse(struct ath12k_base *soc,
if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id)
return -ENOBUFS;
len = min_t(u16, len, sizeof(struct ath12k_wmi_mac_phy_caps_params));
if (!svc_rdy_ext->n_mac_phy_caps) {
svc_rdy_ext->mac_phy_caps = kzalloc((svc_rdy_ext->tot_phy_id) * len,
GFP_ATOMIC);
svc_rdy_ext->mac_phy_caps =
kzalloc_objs(*svc_rdy_ext->mac_phy_caps,
svc_rdy_ext->tot_phy_id,
GFP_ATOMIC);
if (!svc_rdy_ext->mac_phy_caps)
return -ENOMEM;
}
len = min_t(u16, len, sizeof(struct ath12k_wmi_mac_phy_caps_params));
memcpy(svc_rdy_ext->mac_phy_caps + svc_rdy_ext->n_mac_phy_caps, ptr, len);
svc_rdy_ext->n_mac_phy_caps++;
return 0;
@@ -9075,12 +9086,19 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
const u32 *vdev_ids)
{
u32 current_switch_count = le32_to_cpu(ev->current_switch_count);
u32 vdev_ids_len = ath12k_wmi_tlv_data_len(vdev_ids);
u32 num_vdevs = le32_to_cpu(ev->num_vdevs);
struct ieee80211_bss_conf *conf;
struct ath12k_link_vif *arvif;
struct ath12k_vif *ahvif;
int i;
if (num_vdevs > vdev_ids_len / sizeof(*vdev_ids)) {
ath12k_warn(ab, "csa switch count num_vdevs %u exceeds tlv array length %u\n",
num_vdevs, vdev_ids_len);
return;
}
rcu_read_lock();
for (i = 0; i < num_vdevs; i++) {
arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);
@@ -9970,6 +9988,7 @@ static void ath12k_wmi_process_tpc_stats(struct ath12k_base *ab,
void *ptr = skb->data;
struct ath12k *ar;
u16 tlv_tag;
u16 tlv_len;
u32 event_count;
int ret;
@@ -9985,6 +10004,7 @@ static void ath12k_wmi_process_tpc_stats(struct ath12k_base *ab,
tlv = (struct wmi_tlv *)ptr;
tlv_tag = le32_get_bits(tlv->header, WMI_TLV_TAG);
tlv_len = le32_get_bits(tlv->header, WMI_TLV_LEN);
ptr += sizeof(*tlv);
if (tlv_tag != WMI_TAG_HALPHY_CTRL_PATH_EVENT_FIXED_PARAM) {
@@ -9992,6 +10012,12 @@ static void ath12k_wmi_process_tpc_stats(struct ath12k_base *ab,
return;
}
if (tlv_len < sizeof(*fixed_param)) {
ath12k_warn(ab, "TPC stats fixed param tlv len %u too short\n",
tlv_len);
return;
}
fixed_param = (struct ath12k_wmi_pdev_tpc_stats_event_fixed_params *)ptr;
rcu_read_lock();
ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(fixed_param->pdev_id) + 1);

View File

@@ -754,6 +754,11 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
assoc_resp_ie_offset;
if (assoc_req_len < assoc_req_ie_offset)
assoc_req_len = assoc_req_ie_offset;
if (assoc_resp_len < assoc_resp_ie_offset)
assoc_resp_len = assoc_resp_ie_offset;
assoc_req_len -= assoc_req_ie_offset;
assoc_resp_len -= assoc_resp_ie_offset;

View File

@@ -1570,7 +1570,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
if (status)
return status;
return status;
return 0;
}
int ath6kl_init_hw_params(struct ath6kl *ar)