mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 20:24:02 -04:00
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user