mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
Quite a bunch more work, of note:
- iwlwifi: new FW version support
- mt76:
- mt7928 support
- mt7925 NAN support
- mt7996 AP powersave improvements
- rtw89:
- LED support
- RTL8922DE support
- dual-BT coex for RTL8922D
- ath12k: AHB platform MultiPD support
- cfg80211: pre-assign cookies for operations
- mac80211: AQL support for multicast
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmp0efQACgkQ10qiO8sP
aACLlQ//RIWyRR5ss0/CFHKOasGxbffdlEbByQLpj2lM5z1X1rZEs3+JyHUM3ulf
AqZmlU5vVtiNSgGwcL/2+E1BdUQdWLhnqkjAGHtKDh9LT06eix4e2VMLLqY9WdQ+
E5l1hSfrKck7f1C+orhRhKWbGzWJ5kVuIIARTcPPMMi9VnCzVJ6vuREFgwX8i7j5
xFiLGJSaynL9zQoKSaXhcEpyIMVox/lD1BY3HLuVm9ldJD5+KtLb3vkKgf52DbI6
Cx3znqDfpOzfb3VHnoCWn6GVNTAtZGNA+NM9+RWFIHAe2jIbRfgG7tgDiemC9NJ9
HrmgIMR8uLHc0EPCripsckzENmaAgv6opSb2RAJL7blZ/hSzVulDg+ejVCe87FN6
3joldI2Rwpp90kFLLqm3JV8yrE97mZXPzA7zqt+uvEuHOTRrfskKIk6nDifsnhcn
pK/y9CpqpHyLbvynPS/BPQSyazO+f4GVq7J8mxZXqvV9q9i8g40qjCmp7jKiNCH9
4rWooGTwFRmVcfmnfc0XK/xMC/FrQ7C6grl+YFudP6FxJ1MOyLqApkthO6W4pGIr
spH1s4eaHYdM1l9kOlMfnGtLXF/RBFDX5pSnKRnkZYGklZJxUtrOj1hFc4c0lF0I
lKf2KWf223eFTnSeMe77UozS/C3cDQFBmegdsKzNJaFKsP4mWuc=
=L5q1
-----END PGP SIGNATURE-----
Merge tag 'wireless-next-2026-08-06' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says:
====================
Quite a bunch more work, of note:
- iwlwifi: new FW version support
- mt76:
- mt7928 support
- mt7925 NAN support
- mt7996 AP powersave improvements
- rtw89:
- LED support
- RTL8922DE support
- dual-BT coex for RTL8922D
- ath12k: AHB platform MultiPD support
- cfg80211: pre-assign cookies for operations
- mac80211: AQL support for multicast
* tag 'wireless-next-2026-08-06' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (403 commits)
wifi: nxpwifi: bound uAP association event IEs to the event buffer
wifi: nxpwifi: detach sync command buffer on interrupted wait
wifi: brcmfmac: Fix memory leak in brcmf_sdio_read_control()
wifi: rsi: Fix types to appease CFI
wifi: mac80211: skip default WMM setup for AP_VLAN links
wifi: nxpwifi: fix multiple static analysis errors and warnings
wifi: morsemicro: MM81X should be invisible and selected by its users
wifi: nxp: NXPWIFI should be invisible and selected by its users
wifi: cfg80211: stop PMSR before P2P and NAN teardown
wifi: mac80211: disconnect on CSA to channel 0
wifi: brcmfmac: fix P2P action frame handling without device vif
wifi: brcmfmac: Set DMA direction for msgbuf packet IDs
wifi: brcmfmac: validate msgbuf flowring IDs before use
wifi: mac80211: fix RCU usage in peer probing
wifi: mac80211: fix RCU dereference in throughput estimate
wifi: wilc1000: validate monitor transmit frame headers
wifi: mac80211: skip unused probe response countdown offsets
wifi: zd1211rw: reject secondary interfaces to prevent conflicts
wifi: nl80211: clean up color-change beacon data on errors
wifi: mac80211: send TWT teardown to peer after setup TX failure
...
====================
Link: https://patch.msgid.link/20260806121304.190084-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
4fa4977a0d
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -161,14 +161,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
|
||||
|
|
@ -942,6 +934,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 {
|
||||
|
|
@ -1150,7 +1143,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.
|
||||
|
|
|
|||
|
|
@ -1044,6 +1044,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;
|
||||
|
||||
|
|
@ -3034,20 +3039,14 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy,
|
|||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration,
|
||||
u64 *cookie, const u8 *rx_addr)
|
||||
u64 cookie, const u8 *rx_addr)
|
||||
{
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
u32 id;
|
||||
|
||||
/* TODO: if already pending or ongoing remain-on-channel,
|
||||
* return -EBUSY */
|
||||
id = ++vif->last_roc_id;
|
||||
if (id == 0) {
|
||||
/* Do not use 0 as the cookie value */
|
||||
id = ++vif->last_roc_id;
|
||||
}
|
||||
*cookie = id;
|
||||
vif->last_roc_id = cookie;
|
||||
|
||||
return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
chan->center_freq, duration);
|
||||
|
|
@ -3106,6 +3105,7 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
|
|||
|
||||
static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
|
||||
u32 id,
|
||||
u64 cookie,
|
||||
u32 freq,
|
||||
u32 wait,
|
||||
const u8 *buf,
|
||||
|
|
@ -3138,6 +3138,7 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
|
|||
|
||||
INIT_LIST_HEAD(&mgmt_buf->list);
|
||||
mgmt_buf->id = id;
|
||||
mgmt_buf->cookie = cookie;
|
||||
mgmt_buf->freq = freq;
|
||||
mgmt_buf->wait = wait;
|
||||
mgmt_buf->len = len;
|
||||
|
|
@ -3190,7 +3191,7 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
|
|||
}
|
||||
|
||||
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
|
||||
struct cfg80211_mgmt_tx_params *params, u64 cookie)
|
||||
{
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
|
|
@ -3222,7 +3223,6 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
* Send Probe Response frame in GO mode using a separate WMI
|
||||
* command to allow the target to fill in the generic IEs.
|
||||
*/
|
||||
*cookie = 0; /* TX status not supported */
|
||||
return ath6kl_send_go_probe_resp(vif, buf, len, freq);
|
||||
}
|
||||
|
||||
|
|
@ -3235,16 +3235,15 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
id = vif->send_action_id++;
|
||||
}
|
||||
|
||||
*cookie = id;
|
||||
|
||||
/* AP mode Power saving processing */
|
||||
if (vif->nw_type == AP_NETWORK) {
|
||||
queued = ath6kl_mgmt_powersave_ap(vif, id, freq, wait, buf, len,
|
||||
&more_data, no_cck);
|
||||
queued = ath6kl_mgmt_powersave_ap(vif, id, cookie, freq, wait,
|
||||
buf, len, &more_data, no_cck);
|
||||
if (queued)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ar->wmi->last_mgmt_tx_cookie = cookie;
|
||||
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, freq,
|
||||
wait, buf, len, no_cck);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ struct ath6kl_mgmt_buff {
|
|||
u32 freq;
|
||||
u32 wait;
|
||||
u32 id;
|
||||
u64 cookie;
|
||||
bool no_cck;
|
||||
size_t len;
|
||||
u8 buf[];
|
||||
|
|
@ -631,8 +632,8 @@ struct ath6kl_vif {
|
|||
struct cfg80211_scan_request *scan_req;
|
||||
enum sme_state sme_state;
|
||||
int reconnect_flag;
|
||||
u32 last_roc_id;
|
||||
u32 last_cancel_roc_id;
|
||||
u64 last_roc_id;
|
||||
u64 last_cancel_roc_id;
|
||||
u32 send_action_id;
|
||||
bool probe_req_report;
|
||||
u16 assoc_bss_beacon_int;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -898,6 +898,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
|
|||
spin_unlock_bh(&conn->psq_lock);
|
||||
|
||||
conn->sta_flags |= STA_PS_POLLED;
|
||||
ar->wmi->last_mgmt_tx_cookie = mgmt_buf->cookie;
|
||||
ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
mgmt_buf->id, mgmt_buf->freq,
|
||||
mgmt_buf->wait, mgmt_buf->buf,
|
||||
|
|
|
|||
|
|
@ -1469,6 +1469,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
|
|||
spin_unlock_bh(&conn->psq_lock);
|
||||
idx = vif->fw_vif_idx;
|
||||
|
||||
ar->wmi->last_mgmt_tx_cookie = mgmt->cookie;
|
||||
ath6kl_wmi_send_mgmt_cmd(ar->wmi,
|
||||
idx,
|
||||
mgmt->id,
|
||||
|
|
|
|||
|
|
@ -596,7 +596,7 @@ static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len,
|
|||
ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
|
||||
id, ev->ack_status);
|
||||
if (wmi->last_mgmt_tx_frame) {
|
||||
cfg80211_mgmt_tx_status(&vif->wdev, id,
|
||||
cfg80211_mgmt_tx_status(&vif->wdev, wmi->last_mgmt_tx_cookie,
|
||||
wmi->last_mgmt_tx_frame,
|
||||
wmi->last_mgmt_tx_frame_len,
|
||||
!!ev->ack_status, GFP_ATOMIC);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ struct wmi {
|
|||
|
||||
u8 *last_mgmt_tx_frame;
|
||||
size_t last_mgmt_tx_frame_len;
|
||||
u64 last_mgmt_tx_cookie;
|
||||
u8 saved_pwr_mode;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1432,7 +1432,7 @@ static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx,
|
|||
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie)
|
||||
u64 cookie)
|
||||
{
|
||||
const u8 *buf = params->buf;
|
||||
size_t len = params->len;
|
||||
|
|
@ -1488,8 +1488,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
*/
|
||||
tx_status = (rc == 0);
|
||||
rc = (rc == -EAGAIN) ? 0 : rc;
|
||||
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
|
||||
tx_status, GFP_KERNEL);
|
||||
cfg80211_mgmt_tx_status(wdev, cookie, buf, len, tx_status, GFP_KERNEL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1735,7 +1734,7 @@ static int wil_remain_on_channel(struct wiphy *wiphy,
|
|||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration,
|
||||
u64 *cookie, const u8 *rx_addr)
|
||||
u64 cookie, const u8 *rx_addr)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
|
|
@ -2381,7 +2380,7 @@ void wil_probe_client_flush(struct wil6210_vif *vif)
|
|||
|
||||
static int wil_cfg80211_probe_peer(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
const u8 *peer, u64 *cookie)
|
||||
const u8 *peer, u64 cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wil6210_vif *vif = ndev_to_vif(dev);
|
||||
|
|
@ -2399,13 +2398,12 @@ static int wil_cfg80211_probe_peer(struct wiphy *wiphy,
|
|||
return -ENOMEM;
|
||||
|
||||
req->cid = cid;
|
||||
req->cookie = cid;
|
||||
req->cookie = cookie;
|
||||
|
||||
mutex_lock(&vif->probe_client_mutex);
|
||||
list_add_tail(&req->list, &vif->probe_client_pending);
|
||||
mutex_unlock(&vif->probe_client_mutex);
|
||||
|
||||
*cookie = req->cookie;
|
||||
queue_work(wil->wq_service, &vif->probe_client_worker);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -985,7 +985,7 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
|||
params.buf = frame;
|
||||
params.len = len;
|
||||
|
||||
rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL);
|
||||
rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, 0);
|
||||
|
||||
kfree(frame);
|
||||
wil_info(wil, "-> %d\n", rc);
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ int wil_p2p_search(struct wil6210_vif *vif,
|
|||
|
||||
int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
||||
unsigned int duration, struct ieee80211_channel *chan,
|
||||
u64 *cookie)
|
||||
u64 cookie)
|
||||
{
|
||||
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
|
|
@ -144,7 +144,7 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
|||
}
|
||||
|
||||
memcpy(&p2p->listen_chan, chan, sizeof(*chan));
|
||||
*cookie = ++p2p->cookie;
|
||||
p2p->cookie = cookie;
|
||||
p2p->listen_duration = duration;
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
|
|
@ -166,7 +166,7 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
|||
if (vif->mid == 0)
|
||||
wil->radio_wdev = wdev;
|
||||
|
||||
cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
|
||||
cfg80211_ready_on_channel(wdev, cookie, chan, duration,
|
||||
GFP_KERNEL);
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -1301,7 +1301,7 @@ int wil_p2p_search(struct wil6210_vif *vif,
|
|||
struct cfg80211_scan_request *request);
|
||||
int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
||||
unsigned int duration, struct ieee80211_channel *chan,
|
||||
u64 *cookie);
|
||||
u64 cookie);
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_vif *vif);
|
||||
int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie);
|
||||
void wil_p2p_listen_expired(struct work_struct *work);
|
||||
|
|
@ -1317,7 +1317,7 @@ int wmi_stop_discovery(struct wil6210_vif *vif);
|
|||
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie);
|
||||
u64 cookie);
|
||||
void wil_cfg80211_ap_recovery(struct wil6210_priv *wil);
|
||||
int wil_cfg80211_iface_combinations_from_fw(
|
||||
struct wil6210_priv *wil,
|
||||
|
|
|
|||
|
|
@ -5554,7 +5554,7 @@ brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
|||
|
||||
int
|
||||
brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
|
||||
struct cfg80211_mgmt_tx_params *params, u64 cookie)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
struct ieee80211_channel *chan = params->chan;
|
||||
|
|
@ -5573,8 +5573,6 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
*cookie = 0;
|
||||
|
||||
mgmt = (const struct ieee80211_mgmt *)buf;
|
||||
|
||||
if (!ieee80211_is_mgmt(mgmt->frame_control)) {
|
||||
|
|
@ -5605,7 +5603,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
BRCMF_VNDR_IE_PRBRSP_FLAG,
|
||||
&buf[ie_offset],
|
||||
ie_len);
|
||||
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
|
||||
cfg80211_mgmt_tx_status(wdev, cookie, buf, len, true,
|
||||
GFP_KERNEL);
|
||||
} else if (ieee80211_is_action(mgmt->frame_control)) {
|
||||
if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
|
||||
|
|
@ -5621,7 +5619,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
}
|
||||
action_frame = &af_params->action_frame;
|
||||
/* Add the packet Id */
|
||||
action_frame->packet_id = cpu_to_le32(*cookie);
|
||||
action_frame->packet_id = cpu_to_le32(cookie);
|
||||
/* Add BSSID */
|
||||
memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
|
||||
memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
|
||||
|
|
@ -5649,12 +5647,12 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
le16_to_cpu(action_frame->len));
|
||||
|
||||
brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, channel=%d\n",
|
||||
*cookie, le16_to_cpu(action_frame->len),
|
||||
cookie, le16_to_cpu(action_frame->len),
|
||||
le32_to_cpu(af_params->channel));
|
||||
|
||||
ack = brcmf_p2p_send_action_frame(vif->ifp, af_params);
|
||||
|
||||
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
|
||||
cfg80211_mgmt_tx_status(wdev, cookie, buf, len, ack,
|
||||
GFP_KERNEL);
|
||||
free:
|
||||
kfree(af_params);
|
||||
|
|
|
|||
|
|
@ -497,6 +497,6 @@ void brcmf_cfg80211_free_vif(struct net_device *ndev);
|
|||
|
||||
int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags);
|
||||
int brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie);
|
||||
struct cfg80211_mgmt_tx_params *params, u64 cookie);
|
||||
|
||||
#endif /* BRCMFMAC_CFG80211_H */
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ static int brcmf_cyw_activate_events(struct brcmf_if *ifp)
|
|||
|
||||
static
|
||||
int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
|
||||
struct cfg80211_mgmt_tx_params *params, u64 cookie)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
struct ieee80211_channel *chan = params->chan;
|
||||
|
|
@ -123,7 +123,6 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
if (!ieee80211_is_auth(mgmt->frame_control))
|
||||
return brcmf_cfg80211_mgmt_tx(wiphy, wdev, params, cookie);
|
||||
|
||||
*cookie = 0;
|
||||
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
|
||||
|
||||
reinit_completion(&vif->mgmt_tx);
|
||||
|
|
@ -155,7 +154,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
|
||||
memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN);
|
||||
memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
|
||||
mf_params->packet_id = cpu_to_le32(*cookie);
|
||||
mf_params->packet_id = cpu_to_le32(cookie);
|
||||
memcpy(mf_params->data, &buf[DOT11_MGMT_HDR_LEN],
|
||||
le16_to_cpu(mf_params->len));
|
||||
|
||||
|
|
@ -187,8 +186,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
}
|
||||
|
||||
tx_status:
|
||||
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
|
||||
GFP_KERNEL);
|
||||
cfg80211_mgmt_tx_status(wdev, cookie, buf, len, ack, GFP_KERNEL);
|
||||
free:
|
||||
kfree(mf_params);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ brcmf_msgbuf_init_pktids(u32 nr_array_entries,
|
|||
}
|
||||
pktids->array = array;
|
||||
pktids->array_size = nr_array_entries;
|
||||
pktids->direction = direction;
|
||||
|
||||
return pktids;
|
||||
}
|
||||
|
|
@ -560,6 +561,28 @@ brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)
|
|||
brcmf_flowring_delete(msgbuf->flow, flowid);
|
||||
}
|
||||
|
||||
static bool brcmf_msgbuf_get_flowid(struct brcmf_msgbuf *msgbuf,
|
||||
u16 flow_ring_id, u16 *flowid)
|
||||
{
|
||||
u32 id = flow_ring_id;
|
||||
|
||||
if (id < BRCMF_H2D_MSGRING_FLOWRING_IDSTART) {
|
||||
bphy_err(msgbuf->drvr, "invalid flowring id %u\n",
|
||||
flow_ring_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
id -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;
|
||||
if (id >= msgbuf->max_flowrings) {
|
||||
bphy_err(msgbuf->drvr, "invalid flowring id %u\n",
|
||||
flow_ring_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
*flowid = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static struct brcmf_msgbuf_work_item *
|
||||
brcmf_msgbuf_dequeue_work(struct brcmf_msgbuf *msgbuf)
|
||||
|
|
@ -880,17 +903,23 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
|
|||
struct msgbuf_tx_status *tx_status;
|
||||
u32 idx;
|
||||
struct sk_buff *skb;
|
||||
u16 flow_ring_id;
|
||||
u16 flowid;
|
||||
|
||||
tx_status = (struct msgbuf_tx_status *)buf;
|
||||
idx = le32_to_cpu(tx_status->msg.request_id) - 1;
|
||||
flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id);
|
||||
flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;
|
||||
flow_ring_id = le16_to_cpu(tx_status->compl_hdr.flow_ring_id);
|
||||
skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
|
||||
msgbuf->tx_pktids, idx);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
if (!brcmf_msgbuf_get_flowid(msgbuf, flow_ring_id, &flowid)) {
|
||||
brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),
|
||||
skb, false);
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(flowid, msgbuf->txstatus_done_map);
|
||||
commonring = msgbuf->flowrings[flowid];
|
||||
atomic_dec(&commonring->outstanding_tx);
|
||||
|
|
@ -1237,13 +1266,16 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,
|
|||
struct msgbuf_flowring_create_resp *flowring_create_resp;
|
||||
u16 status;
|
||||
u16 flowid;
|
||||
u16 flow_ring_id;
|
||||
|
||||
flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf;
|
||||
|
||||
flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id);
|
||||
flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;
|
||||
flow_ring_id = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id);
|
||||
status = le16_to_cpu(flowring_create_resp->compl_hdr.status);
|
||||
|
||||
if (!brcmf_msgbuf_get_flowid(msgbuf, flow_ring_id, &flowid))
|
||||
return;
|
||||
|
||||
if (status) {
|
||||
bphy_err(drvr, "Flowring creation failed, code %d\n", status);
|
||||
brcmf_msgbuf_remove_flowring(msgbuf, flowid);
|
||||
|
|
@ -1266,13 +1298,16 @@ brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf,
|
|||
struct msgbuf_flowring_delete_resp *flowring_delete_resp;
|
||||
u16 status;
|
||||
u16 flowid;
|
||||
u16 flow_ring_id;
|
||||
|
||||
flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf;
|
||||
|
||||
flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id);
|
||||
flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART;
|
||||
flow_ring_id = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id);
|
||||
status = le16_to_cpu(flowring_delete_resp->compl_hdr.status);
|
||||
|
||||
if (!brcmf_msgbuf_get_flowid(msgbuf, flow_ring_id, &flowid))
|
||||
return;
|
||||
|
||||
if (status) {
|
||||
bphy_err(drvr, "Flowring deletion failed, code %d\n", status);
|
||||
brcmf_flowring_delete(msgbuf->flow, flowid);
|
||||
|
|
|
|||
|
|
@ -979,10 +979,8 @@ brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
|
|||
p2p->cfg->d11inf.encchspec(&ch);
|
||||
err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
|
||||
ch.chspec, (u16)duration);
|
||||
if (!err) {
|
||||
if (!err)
|
||||
set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);
|
||||
p2p->remain_on_channel_cookie++;
|
||||
}
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1000,7 +998,7 @@ brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
|
|||
*/
|
||||
int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *channel,
|
||||
unsigned int duration, u64 *cookie,
|
||||
unsigned int duration, u64 cookie,
|
||||
const u8 *rx_addr)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
|
|
@ -1020,8 +1018,8 @@ int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
goto exit;
|
||||
|
||||
memcpy(&p2p->remain_on_channel, channel, sizeof(*channel));
|
||||
*cookie = p2p->remain_on_channel_cookie;
|
||||
cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
|
||||
p2p->remain_on_channel_cookie = cookie;
|
||||
cfg80211_ready_on_channel(wdev, cookie, channel, duration, GFP_KERNEL);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
|
|
@ -1309,6 +1307,9 @@ static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg)
|
|||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
|
||||
if (!vif)
|
||||
vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
|
||||
|
||||
err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val,
|
||||
sizeof(s32));
|
||||
if (err)
|
||||
|
|
@ -1847,6 +1848,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_if *ifp,
|
|||
/* validate channel and p2p ies */
|
||||
if (config_af_params.search_channel &&
|
||||
IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&
|
||||
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif &&
|
||||
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {
|
||||
afx_hdl = &p2p->afx_hdl;
|
||||
afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
|
|||
struct brcmf_cfg80211_vif *vif);
|
||||
int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *channel,
|
||||
unsigned int duration, u64 *cookie,
|
||||
unsigned int duration, u64 cookie,
|
||||
const u8 *rx_addr);
|
||||
int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *e,
|
||||
|
|
|
|||
|
|
@ -1827,17 +1827,18 @@ brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
|
|||
if (bus->rxctl) {
|
||||
brcmf_err("last control frame is being processed.\n");
|
||||
spin_unlock_bh(&bus->rxctl_lock);
|
||||
vfree(buf);
|
||||
goto done;
|
||||
}
|
||||
bus->rxctl = buf + doff;
|
||||
bus->rxctl_orig = buf;
|
||||
bus->rxlen = len - doff;
|
||||
spin_unlock_bh(&bus->rxctl_lock);
|
||||
buf = NULL;
|
||||
|
||||
done:
|
||||
/* Awake any waiters */
|
||||
brcmf_sdio_dcmd_resp_wake(bus);
|
||||
vfree(buf);
|
||||
}
|
||||
|
||||
/* Pad read to blocksize for efficiency */
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "fw/api/txq.h"
|
||||
|
||||
/* Highest firmware core release supported */
|
||||
#define IWL_BZ_UCODE_CORE_MAX 106
|
||||
#define IWL_BZ_UCODE_CORE_MAX 107
|
||||
|
||||
/* Lowest firmware core release supported */
|
||||
#define IWL_BZ_UCODE_CORE_MIN 102
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include "fw/api/txq.h"
|
||||
|
||||
/* Highest firmware core release supported */
|
||||
#define IWL_DR_UCODE_CORE_MAX 106
|
||||
#define IWL_DR_UCODE_CORE_MAX 107
|
||||
|
||||
/* Lowest firmware core release supported */
|
||||
#define IWL_DR_UCODE_CORE_MIN 102
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "fw/api/txq.h"
|
||||
|
||||
/* Highest firmware core release supported */
|
||||
#define IWL_SC_UCODE_CORE_MAX 106
|
||||
#define IWL_SC_UCODE_CORE_MAX 107
|
||||
|
||||
/* Lowest firmware core release supported */
|
||||
#define IWL_SC_UCODE_CORE_MIN 102
|
||||
|
|
|
|||
|
|
@ -1511,10 +1511,10 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
|||
priv->workqueue = NULL;
|
||||
out_uninit_drv:
|
||||
iwl_uninit_drv(priv);
|
||||
out_free_eeprom_blob:
|
||||
kfree(priv->eeprom_blob);
|
||||
out_free_eeprom:
|
||||
kfree(priv->nvm_data);
|
||||
out_free_eeprom_blob:
|
||||
kfree(priv->eeprom_blob);
|
||||
out_leave_trans:
|
||||
iwl_trans_op_mode_leave(priv->trans);
|
||||
out_free_hw:
|
||||
|
|
|
|||
|
|
@ -604,8 +604,10 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
|||
}
|
||||
|
||||
ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
iwlagn_dealloc_agg_txq(priv, txq_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_bh(&priv->sta_lock);
|
||||
tid_data = &priv->tid_data[sta_id][tid];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2019-2025 Intel Corporation
|
||||
* Copyright (C) 2019-2026 Intel Corporation
|
||||
*/
|
||||
#include <linux/uuid.h>
|
||||
#include "iwl-drv.h"
|
||||
|
|
@ -181,6 +181,7 @@ static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt)
|
|||
|
||||
fwrt->dsm_revision = ACPI_DSM_REV;
|
||||
fwrt->dsm_source = BIOS_SOURCE_ACPI;
|
||||
fwrt->dsm_values[DSM_FUNC_QUERY] = (u32)query_func_val;
|
||||
|
||||
IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
|
||||
(u32)query_func_val);
|
||||
|
|
@ -246,7 +247,7 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
|
|||
BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS);
|
||||
BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS);
|
||||
|
||||
if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func))
|
||||
if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
|
||||
|
|
@ -1193,6 +1194,8 @@ int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
|
|||
|
||||
*value = wifi_pkg->package.elements[1].integer.value &
|
||||
IWL_ACPI_WBEM_REV0_MASK;
|
||||
fwrt->wbem_source = BIOS_SOURCE_ACPI;
|
||||
fwrt->wbem_revision = tbl_rev;
|
||||
IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n");
|
||||
ret = 0;
|
||||
out_free:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2023, 2025 Intel Corporation
|
||||
* Copyright (C) 2018-2023, 2025-2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_acpi__
|
||||
#define __iwl_fw_acpi__
|
||||
|
|
@ -111,9 +111,6 @@
|
|||
#define ACPI_PPAG_WIFI_DATA_SIZE_V3 ((ACPI_PPAG_NUM_CHAINS * \
|
||||
ACPI_PPAG_NUM_BANDS_V3) + 2)
|
||||
|
||||
#define IWL_SAR_ENABLE_MSK BIT(0)
|
||||
#define IWL_REDUCE_POWER_FLAGS_POS 1
|
||||
|
||||
/* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */
|
||||
#define UEFI_WIFI_GUID_UNLOCKED 0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -46,6 +46,11 @@ enum iwl_regulatory_and_nvm_subcmd_ids {
|
|||
*/
|
||||
MCC_ALLOWED_AP_TYPE_CMD = 0x5,
|
||||
|
||||
/**
|
||||
* @LARI_CONFIG_EXTENSION: &struct iwl_lari_config_extension_cmd
|
||||
*/
|
||||
LARI_CONFIG_EXTENSION = 0x8,
|
||||
|
||||
/**
|
||||
* @PNVM_INIT_COMPLETE_NTFY: &struct iwl_pnvm_init_complete_ntfy
|
||||
*/
|
||||
|
|
@ -433,7 +438,10 @@ struct iwl_mcc_chub_notif {
|
|||
__le16 mcc;
|
||||
u8 source_id;
|
||||
u8 reserved1;
|
||||
} __packed; /* LAR_MCC_NOTIFY_S */
|
||||
} __packed;
|
||||
/* LAR_MCC_NOTIFY_S_VER_1
|
||||
* LAR_MCC_NOTIFY_S_VER_2
|
||||
*/
|
||||
|
||||
enum iwl_mcc_update_status {
|
||||
MCC_RESP_NEW_CHAN_PROFILE,
|
||||
|
|
@ -541,6 +549,27 @@ struct iwl_bios_config_hdr {
|
|||
u8 reserved[2];
|
||||
} __packed; /* BIOS_CONFIG_HDR_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_lari_config_extension_cmd - extend LARI configuration
|
||||
*
|
||||
* LARI_CONFIG_CHANGE's version must remain stable for frozen firmware.
|
||||
* Because the driver might not know this version but still load that
|
||||
* frozen FW and then send some default old version of LARI, causing the FW to
|
||||
* assert about the bad size of it. To handle this, we do the following:
|
||||
* 1. For newer firmware: increase the LARI_CONFIG_CHANGE version to support the
|
||||
* new firmware API with extra UHB bits.
|
||||
* 2. For frozen firmware: add a special alternative API that doesn't require
|
||||
* modifying the frozen LARI_CONFIG_CHANGE's version.
|
||||
* @dsm_table_hdr: BIOS DSM table source and revision
|
||||
* @oem_uhb_allow_extension_bitmap: extension bitmap for OEM UHB config
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_lari_config_extension_cmd {
|
||||
struct iwl_bios_config_hdr dsm_table_hdr;
|
||||
__le32 oem_uhb_allow_extension_bitmap;
|
||||
__le32 reserved[10];
|
||||
} __packed; /* LARI_CONFIG_EXTENSION_CMD_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct bios_value_u32 - BIOS configuration.
|
||||
* @hdr: bios config header
|
||||
|
|
@ -689,6 +718,14 @@ struct iwl_lari_config_change_cmd_v8 {
|
|||
* get the data from the BIOS.
|
||||
* @oem_unii9_enable: UNII-9 enablement as read from the BIOS
|
||||
* @bios_hdr: bios config header
|
||||
* @oem_uhb_allow_extension_bitmap: DSM Function 4 data as an extension of UHB
|
||||
* enabled MCC sets
|
||||
* @bios_wcpe_hdr: puncturing config header
|
||||
* @wcpe_bitmap: bitmap of puncturing enablement per MCC
|
||||
* @bios_wbem_hdr: 320 MHz per-MCC WBEM config header
|
||||
* @reserved: reserved
|
||||
* @oem_supported_dsm_bitmap: DSM function 0 bitmap describing supported
|
||||
* DSM function indices
|
||||
*/
|
||||
struct iwl_lari_config_change_cmd {
|
||||
__le32 config_bitmap;
|
||||
|
|
@ -706,9 +743,19 @@ struct iwl_lari_config_change_cmd {
|
|||
__le32 oem_unii9_enable;
|
||||
/* since version 13 */
|
||||
struct iwl_bios_config_hdr bios_hdr;
|
||||
/* All the below are since version 14 */
|
||||
__le32 oem_uhb_allow_extension_bitmap;
|
||||
struct iwl_bios_config_hdr bios_wcpe_hdr;
|
||||
__le32 wcpe_bitmap;
|
||||
struct iwl_bios_config_hdr bios_wbem_hdr;
|
||||
__le32 reserved[10];
|
||||
/* since version 15 */
|
||||
__le32 oem_supported_dsm_bitmap;
|
||||
} __packed;
|
||||
/* LARI_CHANGE_CONF_CMD_S_VER_12
|
||||
* LARI_CHANGE_CONF_CMD_S_VER_13
|
||||
* LARI_CHANGE_CONF_CMD_S_VER_14
|
||||
* LARI_CHANGE_CONF_CMD_S_VER_15
|
||||
*/
|
||||
|
||||
/* Activate UNII-1 (5.2GHz) for World Wide */
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt)
|
|||
void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
struct iwl_pc_data *pc_data;
|
||||
u8 count;
|
||||
u32 count;
|
||||
|
||||
if (!iwl_trans_device_enabled(fwrt->trans)) {
|
||||
IWL_ERR(fwrt,
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ struct iwl_fw_ini_error_dump_register {
|
|||
* struct iwl_fw_ini_dump_cfg_name - configuration name
|
||||
* @image_type: image type the configuration is related to
|
||||
* @cfg_name_len: length of the configuration name
|
||||
* @cfg_name: name of the configuraiton
|
||||
* @cfg_name: name of the configuration
|
||||
*/
|
||||
struct iwl_fw_ini_dump_cfg_name {
|
||||
__le32 image_type;
|
||||
|
|
|
|||
|
|
@ -448,8 +448,9 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
|
|||
* @IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT: external FSEQ image support
|
||||
* @IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT: FW reset handshake is needed
|
||||
* during assert handling even if the dump isn't split
|
||||
* @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of
|
||||
* handling raw DSM table data.
|
||||
* @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware can handle raw DSM
|
||||
* table data. For LARI_CONFIG_CHANGE command version 13 and above, this
|
||||
* capability is obsolete since raw DSM values are accepted by default.
|
||||
* @IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT: Supports NAN synchronization
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
|
||||
|
|
|
|||
|
|
@ -205,6 +205,12 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
|
|||
IWL_DEBUG_FW(trans,
|
||||
"Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
|
||||
tlv_len);
|
||||
if (tlv_len < sizeof(*tlv_sku_id)) {
|
||||
IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
|
||||
tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
|
||||
le32_to_cpu(tlv_sku_id->data[0]),
|
||||
le32_to_cpu(tlv_sku_id->data[1]),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Intel Corporation
|
||||
* Copyright (C) 2023-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __fw_regulatory_h__
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#define BIOS_GEO_MIN_PROFILE_NUM 3
|
||||
|
||||
#define IWL_SAR_ENABLE_MSK BIT(0)
|
||||
#define IWL_REDUCE_POWER_FLAGS_POS 1
|
||||
|
||||
/* PPAG gain value bounds in 1/8 dBm */
|
||||
#define IWL_PPAG_MIN_LB -16
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_runtime_h__
|
||||
#define __iwl_fw_runtime_h__
|
||||
|
|
@ -144,6 +144,11 @@ struct iwl_txf_iter_data {
|
|||
* @tpc_enabled: TPC enabled
|
||||
* @dsm_source: one of &enum bios_source. UEFI, ACPI or NONE
|
||||
* @dsm_revision: the revision of the DSM table
|
||||
* @wbem_source: one of &enum bios_source for the WBEM table
|
||||
* @wbem_revision: the revision of the WBEM table
|
||||
* @puncturing_source: one of &enum bios_source for the puncturing table
|
||||
* @puncturing_revision: the revision of the puncturing table
|
||||
* @bios_puncturing: per-country puncturing enablement bitmap from BIOS
|
||||
*/
|
||||
struct iwl_fw_runtime {
|
||||
struct iwl_trans *trans;
|
||||
|
|
@ -226,6 +231,12 @@ struct iwl_fw_runtime {
|
|||
u32 dsm_funcs_valid;
|
||||
u32 dsm_values[DSM_FUNC_NUM_FUNCS];
|
||||
#endif
|
||||
|
||||
enum bios_source wbem_source;
|
||||
u8 wbem_revision;
|
||||
enum bios_source puncturing_source;
|
||||
u8 puncturing_revision;
|
||||
u32 bios_puncturing;
|
||||
};
|
||||
|
||||
void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright(c) 2021-2025 Intel Corporation
|
||||
* Copyright(c) 2021-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "iwl-drv.h"
|
||||
|
|
@ -248,6 +248,12 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
|
|||
IWL_DEBUG_FW(trans,
|
||||
"Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
|
||||
tlv_len);
|
||||
if (tlv_len < sizeof(*tlv_sku_id)) {
|
||||
IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
|
||||
tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
|
||||
le32_to_cpu(tlv_sku_id->data[0]),
|
||||
le32_to_cpu(tlv_sku_id->data[1]),
|
||||
|
|
@ -884,6 +890,8 @@ int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
|
|||
goto out;
|
||||
}
|
||||
*value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK;
|
||||
fwrt->wbem_source = BIOS_SOURCE_UEFI;
|
||||
fwrt->wbem_revision = data->revision;
|
||||
IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n");
|
||||
out:
|
||||
kfree(data);
|
||||
|
|
@ -919,7 +927,7 @@ static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt)
|
|||
*/
|
||||
fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
|
||||
|
||||
for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
|
||||
for (int func = 0; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
|
||||
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
|
||||
IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n",
|
||||
func, fwrt->dsm_funcs_valid);
|
||||
|
|
@ -970,29 +978,29 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
|
|||
int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
struct uefi_cnv_var_puncturing_data *data;
|
||||
/* default value is not enabled if there is any issue in reading
|
||||
* uefi variable or revision is not supported
|
||||
*/
|
||||
int puncturing = 0;
|
||||
int ret = 0;
|
||||
|
||||
data = iwl_uefi_get_verified_variable(fwrt->trans,
|
||||
IWL_UEFI_PUNCTURING_NAME,
|
||||
"UefiCnvWlanPuncturing",
|
||||
sizeof(*data), NULL);
|
||||
if (IS_ERR(data))
|
||||
return puncturing;
|
||||
return -EINVAL;
|
||||
|
||||
if (data->revision != IWL_UEFI_PUNCTURING_REVISION) {
|
||||
IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PUNCTURING rev:%d\n",
|
||||
data->revision);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
puncturing = data->puncturing & IWL_UEFI_PUNCTURING_REV0_MASK;
|
||||
fwrt->puncturing_source = BIOS_SOURCE_UEFI;
|
||||
fwrt->puncturing_revision = data->revision;
|
||||
fwrt->bios_puncturing = data->puncturing;
|
||||
IWL_DEBUG_RADIO(fwrt, "Loaded puncturing bits from UEFI: %d\n",
|
||||
puncturing);
|
||||
fwrt->bios_puncturing);
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
return puncturing;
|
||||
return ret;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_uefi_get_puncturing);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright(c) 2021-2025 Intel Corporation
|
||||
* Copyright(c) 2021-2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_fw_uefi__
|
||||
#define __iwl_fw_uefi__
|
||||
|
|
@ -275,8 +275,6 @@ enum iwl_uefi_cnv_puncturing_flags {
|
|||
IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK = BIT(1),
|
||||
};
|
||||
|
||||
#define IWL_UEFI_PUNCTURING_REV0_MASK (IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK | \
|
||||
IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK)
|
||||
/**
|
||||
* struct uefi_cnv_var_puncturing_data - controlling channel
|
||||
* puncturing for few countries.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
#include <linux/firmware.h>
|
||||
#include "iwl-drv.h"
|
||||
|
|
@ -611,6 +611,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
|
|||
cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH))
|
||||
return 0;
|
||||
|
||||
if (!fw_mon_cfg->req_size)
|
||||
return -EIO;
|
||||
|
||||
num_frags = le32_to_cpu(fw_mon_cfg->max_frags_num);
|
||||
if (fwrt->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
|
||||
if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
|
||||
|
|
@ -621,6 +624,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (!num_frags)
|
||||
return -EIO;
|
||||
|
||||
remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size),
|
||||
PAGE_SIZE);
|
||||
num_frags = min_t(u32, num_frags, BUF_ALLOC_MAX_NUM_FRAGS);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,18 @@ enum iwl_reg_capa_flags_v5 {
|
|||
REG_CAPA_V5_11BN_DISABLED = BIT(17),
|
||||
}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4, 5 */
|
||||
|
||||
/**
|
||||
* enum iwl_reg_capa_flags_v6 - global capability flags,
|
||||
* applicable from MCC response version 10 onwards.
|
||||
* Response v6 includes all members of iwl_reg_capa_flags_v5; only v6-specific
|
||||
* additions are listed here.
|
||||
* @REG_CAPA_V6_EHT_PUNCTURING_ENABLED: EHT puncturing is enabled for this
|
||||
* regulatory domain.
|
||||
*/
|
||||
enum iwl_reg_capa_flags_v6 {
|
||||
REG_CAPA_V6_EHT_PUNCTURING_ENABLED = BIT(18),
|
||||
}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_6 */
|
||||
|
||||
/*
|
||||
* API v2 for reg_capa_flags is relevant from version 6 and onwards of the
|
||||
* MCC update command response.
|
||||
|
|
@ -236,6 +248,11 @@ enum iwl_reg_capa_flags_v5 {
|
|||
*/
|
||||
#define REG_CAPA_V4_RESP_VER 8
|
||||
|
||||
/* API v6 for reg_capa_flags is relevant from version 10 and onwards of the
|
||||
* MCC update command response.
|
||||
*/
|
||||
#define REG_CAPA_V6_RESP_VER 10
|
||||
|
||||
static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level,
|
||||
int chan, u32 flags)
|
||||
{
|
||||
|
|
@ -697,7 +714,8 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = {
|
|||
.mac.mac_cap = {
|
||||
[0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP |
|
||||
IEEE80211_UHR_MAC_CAP0_DPS_SUPP,
|
||||
[1] = IEEE80211_UHR_MAC_CAP1_DUO_SUPP,
|
||||
[1] = IEEE80211_UHR_MAC_CAP1_DUO_SUPP |
|
||||
IEEE80211_UHR_MAC_CAP1_DBE_SUPP,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1687,6 +1705,13 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver)
|
|||
{
|
||||
struct iwl_reg_capa reg_capa = {};
|
||||
|
||||
if (resp_ver >= REG_CAPA_V6_RESP_VER) {
|
||||
if (flags & REG_CAPA_V6_EHT_PUNCTURING_ENABLED)
|
||||
reg_capa.puncturing_status = IWL_PUNCTURING_STATUS_ENABLED;
|
||||
else
|
||||
reg_capa.puncturing_status = IWL_PUNCTURING_STATUS_DISABLED;
|
||||
}
|
||||
|
||||
if (resp_ver >= REG_CAPA_V4_RESP_VER) {
|
||||
reg_capa.allow_40mhz = true;
|
||||
reg_capa.allow_80mhz = flags & REG_CAPA_V5_80MHZ_ALLOWED;
|
||||
|
|
@ -1713,7 +1738,8 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver)
|
|||
struct ieee80211_regdomain *
|
||||
iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
|
||||
int num_of_ch, __le32 *channels, u16 fw_mcc,
|
||||
u16 geo_info, u32 cap, u8 resp_ver)
|
||||
u16 geo_info, u32 cap, u8 resp_ver,
|
||||
enum iwl_puncturing_status *puncturing_status)
|
||||
{
|
||||
const struct iwl_rf_cfg *cfg = trans->cfg;
|
||||
struct device *dev = trans->dev;
|
||||
|
|
@ -1776,6 +1802,9 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
|
|||
/* parse regulatory capability flags */
|
||||
reg_capa = iwl_get_reg_capa(cap, resp_ver);
|
||||
|
||||
if (puncturing_status)
|
||||
*puncturing_status = reg_capa.puncturing_status;
|
||||
|
||||
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
|
||||
enum nl80211_band band =
|
||||
iwl_nl80211_band_from_channel_idx(ch_idx);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2005-2015, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2005-2015, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
#ifndef __iwl_nvm_parse_h__
|
||||
|
|
@ -21,6 +21,19 @@ enum iwl_nvm_sbands_flags {
|
|||
IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_puncturing_status - EHT puncturing status from MCC capabilities
|
||||
* @IWL_PUNCTURING_STATUS_UNKNOWN: puncturing status is not provided by FW
|
||||
* or is not initialized yet
|
||||
* @IWL_PUNCTURING_STATUS_ENABLED: puncturing is enabled for the current MCC
|
||||
* @IWL_PUNCTURING_STATUS_DISABLED: puncturing is disabled for the current MCC
|
||||
*/
|
||||
enum iwl_puncturing_status {
|
||||
IWL_PUNCTURING_STATUS_UNKNOWN,
|
||||
IWL_PUNCTURING_STATUS_ENABLED,
|
||||
IWL_PUNCTURING_STATUS_DISABLED,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_reg_capa - struct for global regulatory capabilities, Used for
|
||||
* handling the different APIs of reg_capa_flags.
|
||||
|
|
@ -36,6 +49,8 @@ enum iwl_nvm_sbands_flags {
|
|||
* @disable_11ax: 11ax is forbidden for this regulatory domain.
|
||||
* @disable_11be: 11be is forbidden for this regulatory domain.
|
||||
* @disable_11bn: UHR/11bn is not allowed for this regulatory domain
|
||||
* @puncturing_status: EHT puncturing status for the current MCC.
|
||||
* See &enum iwl_puncturing_status.
|
||||
*/
|
||||
struct iwl_reg_capa {
|
||||
bool allow_40mhz;
|
||||
|
|
@ -45,6 +60,7 @@ struct iwl_reg_capa {
|
|||
bool disable_11ax;
|
||||
bool disable_11be;
|
||||
bool disable_11bn;
|
||||
enum iwl_puncturing_status puncturing_status;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -131,11 +147,13 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
* @geo_info: geo info value
|
||||
* @cap: capability
|
||||
* @resp_ver: FW response version
|
||||
* @puncturing_status: FW puncturing status for current MCC, when available
|
||||
*/
|
||||
struct ieee80211_regdomain *
|
||||
iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
|
||||
int num_of_ch, __le32 *channels, u16 fw_mcc,
|
||||
u16 geo_info, u32 cap, u8 resp_ver);
|
||||
u16 geo_info, u32 cap, u8 resp_ver,
|
||||
enum iwl_puncturing_status *puncturing_status);
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_section - describes an NVM section in memory.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2021-2024 Intel Corporation
|
||||
* Copyright (C) 2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
|
@ -457,7 +458,7 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev,
|
|||
notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF];
|
||||
q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF];
|
||||
q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF];
|
||||
ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr, q_sz);
|
||||
ret = iwl_mei_write_cyclic_buf(cldev, notif_q, q_head, hdr, q_sz);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -1040,11 +1041,14 @@ static void iwl_mei_read_from_q(const u8 *q_head, u32 q_sz,
|
|||
u32 rd = *_rd;
|
||||
|
||||
if (rd + len <= q_sz) {
|
||||
memcpy(buf, q_head + rd, len);
|
||||
if (buf)
|
||||
memcpy(buf, q_head + rd, len);
|
||||
rd += len;
|
||||
} else {
|
||||
memcpy(buf, q_head + rd, q_sz - rd);
|
||||
memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd));
|
||||
if (buf) {
|
||||
memcpy(buf, q_head + rd, q_sz - rd);
|
||||
memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd));
|
||||
}
|
||||
rd = len - (q_sz - rd);
|
||||
}
|
||||
|
||||
|
|
@ -1085,24 +1089,29 @@ static void iwl_mei_handle_sap_data(struct mei_cl_device *cldev,
|
|||
break;
|
||||
}
|
||||
|
||||
valid_rx_sz -= len;
|
||||
|
||||
if (len < sizeof(*ethhdr)) {
|
||||
dev_err(&cldev->dev,
|
||||
"Data len is smaller than an ethernet header? len = %d\n",
|
||||
len);
|
||||
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
valid_rx_sz -= len;
|
||||
|
||||
if (le16_to_cpu(hdr.type) != SAP_MSG_DATA_PACKET) {
|
||||
dev_err(&cldev->dev, "Unsupported Rx data: type %d, len %d\n",
|
||||
le16_to_cpu(hdr.type), len);
|
||||
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We need enough room for the WiFi header + SNAP + IV */
|
||||
skb = netdev_alloc_skb(netdev, len + QOS_HDR_IV_SNAP_LEN);
|
||||
if (!skb)
|
||||
if (!skb) {
|
||||
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
skb_reserve(skb, QOS_HDR_IV_SNAP_LEN);
|
||||
ethhdr = skb_push(skb, sizeof(*ethhdr));
|
||||
|
|
@ -1147,6 +1156,11 @@ static void iwl_mei_handle_sap_rx_cmd(struct mei_cl_device *cldev,
|
|||
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, hdr, sizeof(*hdr));
|
||||
valid_rx_sz -= sizeof(*hdr);
|
||||
len = le16_to_cpu(hdr->len);
|
||||
if (len + sizeof(*hdr) > PAGE_SIZE) {
|
||||
dev_err(&cldev->dev,
|
||||
"SAP message is too big: %u\n", len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid_rx_sz < len)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -200,11 +200,11 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
struct iwl_mld_baid_data *baid_data;
|
||||
struct iwl_mld_reorder_buffer *buffer;
|
||||
struct iwl_mld_reorder_buf_entry *entries;
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
struct iwl_mld_link_sta *mld_link_sta;
|
||||
u32 reorder = le32_to_cpu(desc->reorder_data);
|
||||
bool amsdu, last_subframe, is_old_sn, is_dup;
|
||||
u8 tid = ieee80211_get_tid(hdr);
|
||||
struct iwl_mld_sta *mld_sta;
|
||||
u8 baid;
|
||||
u16 nssn, sn;
|
||||
u32 sta_mask = 0;
|
||||
|
|
@ -228,10 +228,13 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
/* no sta yet */
|
||||
if (WARN_ONCE(!sta,
|
||||
"Got valid BAID without a valid station assigned\n"))
|
||||
if (IWL_FW_CHECK(mld, !sta,
|
||||
"Got valid BAID without a valid station assigned - %d\n",
|
||||
baid))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
|
||||
/* not a data packet */
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
is_multicast_ether_addr(hdr->addr1))
|
||||
|
|
|
|||
|
|
@ -59,6 +59,30 @@ struct iwl_mld_suspend_key_iter_data {
|
|||
__le32 bigtk_cipher;
|
||||
};
|
||||
|
||||
struct iwl_mld_wake_pkt_iter_data {
|
||||
bool multicast;
|
||||
u32 ivlen;
|
||||
u32 icvlen;
|
||||
};
|
||||
|
||||
static void
|
||||
iwl_mld_wake_pkt_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key, void *_data)
|
||||
{
|
||||
struct iwl_mld_wake_pkt_iter_data *data = _data;
|
||||
bool is_group_key = !sta;
|
||||
|
||||
/* ignore anything that is not a PTK / GTK */
|
||||
if (key->keyidx > 3)
|
||||
return;
|
||||
if (is_group_key != data->multicast)
|
||||
return;
|
||||
|
||||
data->ivlen = key->iv_len;
|
||||
data->icvlen = key->icv_len;
|
||||
}
|
||||
|
||||
struct iwl_mld_mcast_key_data {
|
||||
u8 key[WOWLAN_KEY_MAX_SIZE];
|
||||
u8 len;
|
||||
|
|
@ -573,18 +597,42 @@ iwl_mld_convert_wowlan_notif_v5(const struct iwl_wowlan_info_notif_v5 *notif_v5,
|
|||
}
|
||||
}
|
||||
|
||||
static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld,
|
||||
u32 len,
|
||||
u32 expected_len,
|
||||
u8 num_mlo_keys,
|
||||
static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld, u32 len,
|
||||
const void *notif_data,
|
||||
int version)
|
||||
{
|
||||
u32 len_with_mlo_keys;
|
||||
u32 expected_len;
|
||||
u8 num_mlo_keys;
|
||||
|
||||
if (IWL_FW_CHECK(mld, len < expected_len,
|
||||
"Invalid wowlan_info_notif v%d (expected=%u got=%u)\n",
|
||||
version, expected_len, len))
|
||||
/* Extract num_mlo_keys from the void pointer based on version */
|
||||
if (version == 5) {
|
||||
const struct iwl_wowlan_info_notif_v5 *notif_v5 = notif_data;
|
||||
|
||||
expected_len = sizeof(*notif_v5);
|
||||
|
||||
if (IWL_FW_CHECK(mld, len < expected_len,
|
||||
"Invalid wowlan_info_notif v5 (expected=%u got=%u)\n",
|
||||
expected_len, len))
|
||||
return false;
|
||||
|
||||
num_mlo_keys = notif_v5->num_mlo_link_keys;
|
||||
} else if (version == 6) {
|
||||
const struct iwl_wowlan_info_notif *notif = notif_data;
|
||||
|
||||
expected_len = sizeof(*notif);
|
||||
|
||||
if (IWL_FW_CHECK(mld, len < expected_len,
|
||||
"Invalid wowlan_info_notif v6 (expected=%u got=%u)\n",
|
||||
expected_len, len))
|
||||
return false;
|
||||
|
||||
num_mlo_keys = notif->num_mlo_link_keys;
|
||||
} else {
|
||||
IWL_WARN(mld, "Unsupported wowlan_info_notif version %d\n",
|
||||
version);
|
||||
return false;
|
||||
}
|
||||
|
||||
len_with_mlo_keys = expected_len +
|
||||
(num_mlo_keys * sizeof(struct iwl_wowlan_mlo_gtk));
|
||||
|
|
@ -616,16 +664,14 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
|
|||
|
||||
if (wowlan_info_ver == 5) {
|
||||
/* v5 format - validate before conversion */
|
||||
const struct iwl_wowlan_info_notif_v5 *notif_v5 = (void *)pkt->data;
|
||||
const struct iwl_wowlan_info_notif_v5 *_notif =
|
||||
(void *)pkt->data;
|
||||
|
||||
if (!iwl_mld_validate_wowlan_notif_size(mld, len,
|
||||
sizeof(*notif_v5),
|
||||
notif_v5->num_mlo_link_keys,
|
||||
5))
|
||||
if (!iwl_mld_validate_wowlan_notif_size(mld, len, _notif, 5))
|
||||
return true;
|
||||
|
||||
converted_notif = kzalloc_flex(*converted_notif, mlo_gtks,
|
||||
notif_v5->num_mlo_link_keys,
|
||||
_notif->num_mlo_link_keys,
|
||||
GFP_ATOMIC);
|
||||
if (!converted_notif) {
|
||||
IWL_ERR(mld,
|
||||
|
|
@ -633,15 +679,12 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
|
|||
return true;
|
||||
}
|
||||
|
||||
iwl_mld_convert_wowlan_notif_v5(notif_v5,
|
||||
converted_notif);
|
||||
iwl_mld_convert_wowlan_notif_v5(_notif, converted_notif);
|
||||
notif = converted_notif;
|
||||
} else if (wowlan_info_ver == 6) {
|
||||
notif = (void *)pkt->data;
|
||||
if (!iwl_mld_validate_wowlan_notif_size(mld, len,
|
||||
sizeof(*notif),
|
||||
notif->num_mlo_link_keys,
|
||||
6))
|
||||
|
||||
if (!iwl_mld_validate_wowlan_notif_size(mld, len, notif, 6))
|
||||
return true;
|
||||
} else {
|
||||
/* smaller versions are not supported */
|
||||
|
|
@ -686,7 +729,7 @@ iwl_mld_handle_wake_pkt_notif(struct iwl_mld *mld,
|
|||
{
|
||||
const struct iwl_wowlan_wake_pkt_notif *notif = (void *)pkt->data;
|
||||
u32 actual_size, len = iwl_rx_packet_payload_len(pkt);
|
||||
u32 expected_size = le32_to_cpu(notif->wake_packet_length);
|
||||
u32 expected_size;
|
||||
|
||||
if (IWL_FW_CHECK(mld, len < sizeof(*notif),
|
||||
"Invalid WoWLAN wake packet notification (expected size=%zu got=%u)\n",
|
||||
|
|
@ -699,6 +742,7 @@ iwl_mld_handle_wake_pkt_notif(struct iwl_mld *mld,
|
|||
wowlan_status->wakeup_reasons))
|
||||
return true;
|
||||
|
||||
expected_size = le32_to_cpu(notif->wake_packet_length);
|
||||
actual_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif,
|
||||
wake_packet);
|
||||
|
||||
|
|
@ -723,11 +767,17 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
|
|||
struct cfg80211_wowlan_wakeup *wakeup,
|
||||
struct sk_buff **_pkt)
|
||||
{
|
||||
int pkt_bufsize = wowlan_status->wake_packet_bufsize;
|
||||
int expected_pktlen = wowlan_status->wake_packet_length;
|
||||
u32 pkt_bufsize = wowlan_status->wake_packet_bufsize;
|
||||
u32 expected_pktlen = wowlan_status->wake_packet_length;
|
||||
const u8 *pktdata = wowlan_status->wake_packet;
|
||||
const struct ieee80211_hdr *hdr = (const void *)pktdata;
|
||||
int truncated = expected_pktlen - pkt_bufsize;
|
||||
u32 truncated;
|
||||
|
||||
if (IWL_FW_CHECK(mld, pkt_bufsize < sizeof(*hdr),
|
||||
"pkt_bufsize is too short: %u\n", pkt_bufsize))
|
||||
return;
|
||||
|
||||
truncated = expected_pktlen - pkt_bufsize;
|
||||
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
|
@ -738,9 +788,18 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
|
|||
if (!pkt)
|
||||
return;
|
||||
|
||||
skb_put_data(pkt, pktdata, hdrlen);
|
||||
pktdata += hdrlen;
|
||||
pkt_bufsize -= hdrlen;
|
||||
if (ieee80211_has_protected(hdr->frame_control)) {
|
||||
struct iwl_mld_wake_pkt_iter_data iter_data = {
|
||||
.multicast =
|
||||
is_multicast_ether_addr(hdr->addr1),
|
||||
};
|
||||
|
||||
ieee80211_iter_keys(mld->hw, vif,
|
||||
iwl_mld_wake_pkt_key_iter,
|
||||
&iter_data);
|
||||
ivlen = iter_data.ivlen;
|
||||
icvlen += iter_data.icvlen;
|
||||
}
|
||||
|
||||
/* if truncated, FCS/ICV is (partially) gone */
|
||||
if (truncated >= icvlen) {
|
||||
|
|
@ -751,6 +810,13 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
|
|||
truncated = 0;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mld, pkt_bufsize <= hdrlen + ivlen + icvlen,
|
||||
"pkt_bufsize is too small %u\n", pkt_bufsize))
|
||||
return;
|
||||
|
||||
skb_put_data(pkt, pktdata, hdrlen);
|
||||
pktdata += hdrlen;
|
||||
pkt_bufsize -= hdrlen;
|
||||
pkt_bufsize -= ivlen + icvlen;
|
||||
pktdata += ivlen;
|
||||
|
||||
|
|
@ -772,6 +838,11 @@ iwl_mld_set_wake_packet(struct iwl_mld *mld,
|
|||
fcslen -= truncated;
|
||||
truncated = 0;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mld, pkt_bufsize <= fcslen,
|
||||
"pkt_bufsize is too small %u\n", pkt_bufsize))
|
||||
return;
|
||||
|
||||
pkt_bufsize -= fcslen;
|
||||
wakeup->packet = wowlan_status->wake_packet;
|
||||
wakeup->packet_present_len = pkt_bufsize;
|
||||
|
|
@ -1449,8 +1520,16 @@ static bool iwl_mld_handle_d3_notif(struct iwl_notif_wait_data *notif_wait,
|
|||
}
|
||||
case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {
|
||||
struct iwl_d3_end_notif *notif = (void *)pkt->data;
|
||||
u32 len = iwl_rx_packet_payload_len(pkt);
|
||||
|
||||
if (IWL_FW_CHECK(mld, len < sizeof(*notif),
|
||||
"Invalid D3_END notification (expected=%zu got=%u)\n",
|
||||
sizeof(*notif), len)) {
|
||||
resume_data->notif_handling_err = true;
|
||||
} else {
|
||||
resume_data->d3_end_flags = le32_to_cpu(notif->flags);
|
||||
}
|
||||
|
||||
resume_data->d3_end_flags = le32_to_cpu(notif->flags);
|
||||
resume_data->notifs_received |= IWL_D3_NOTIF_D3_END_NOTIF;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2140,6 +2219,9 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld)
|
|||
ret = iwl_mld_wait_d3_notif(mld, &resume_data, true);
|
||||
if (ret) {
|
||||
IWL_ERR(mld, "Couldn't get the d3 notifs %d\n", ret);
|
||||
|
||||
if (bss_vif->cfg.assoc)
|
||||
ieee80211_resume_disconnect(bss_vif);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -459,3 +459,24 @@ void iwl_mld_ftm_restart_cleanup(struct iwl_mld *mld)
|
|||
mld->ftm_initiator.req, GFP_KERNEL);
|
||||
iwl_mld_ftm_reset(mld);
|
||||
}
|
||||
|
||||
void iwl_mld_ftm_abort(struct iwl_mld *mld, struct cfg80211_pmsr_request *req)
|
||||
{
|
||||
struct iwl_tof_range_abort_cmd cmd = {
|
||||
.request_id = req->cookie,
|
||||
};
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
if (req != mld->ftm_initiator.req)
|
||||
return;
|
||||
|
||||
if (iwl_mld_send_cmd_pdu(mld, WIDE_ID(LOCATION_GROUP,
|
||||
TOF_RANGE_ABORT_CMD),
|
||||
&cmd))
|
||||
IWL_ERR(mld, "failed to abort FTM process\n");
|
||||
|
||||
iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_FTM_REQ,
|
||||
mld->ftm_initiator.req->cookie);
|
||||
iwl_mld_ftm_reset(mld);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,5 +25,6 @@ int iwl_mld_ftm_start(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
|||
void iwl_mld_handle_ftm_resp_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
void iwl_mld_ftm_restart_cleanup(struct iwl_mld *mld);
|
||||
void iwl_mld_ftm_abort(struct iwl_mld *mld, struct cfg80211_pmsr_request *req);
|
||||
|
||||
#endif /* __iwl_mld_ftm_initiator_h__ */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_hcmd_h__
|
||||
#define __iwl_mld_hcmd_h__
|
||||
|
|
@ -42,7 +42,12 @@ __iwl_mld_send_cmd_with_flags_pdu(struct iwl_mld *mld, u32 id,
|
|||
|
||||
#define _iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, len, \
|
||||
ignored...) \
|
||||
__iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, len)
|
||||
({ \
|
||||
BUILD_BUG_ON(__builtin_constant_p(len) && \
|
||||
(u16)(len) > IWL_MAX_CMD_PAYLOAD_SIZE); \
|
||||
__iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, \
|
||||
data, len); \
|
||||
})
|
||||
#define iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, len...) \
|
||||
_iwl_mld_send_cmd_with_flags_pdu(mld, id, flags, data, ##len, \
|
||||
sizeof(*(data)))
|
||||
|
|
|
|||
|
|
@ -543,8 +543,7 @@ iwl_mld_mac80211_tx(struct ieee80211_hw *hw,
|
|||
iwl_mld_tx_skb(mld, skb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mld_restart_cleanup(struct iwl_mld *mld)
|
||||
void iwl_mld_restart_cleanup(struct iwl_mld *mld)
|
||||
{
|
||||
iwl_cleanup_mld(mld);
|
||||
|
||||
|
|
@ -1281,11 +1280,13 @@ void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
iwl_mld_tlc_update_phy(mld, vif, link);
|
||||
|
||||
/* in the non-MLO case, remove/re-add the link to clean up FW state.
|
||||
* In MLO, it'll be done in drv_change_vif_link
|
||||
* In MLO, it'll be done in drv_change_vif_link.
|
||||
* Do not do so during restart or in case the device is dead.
|
||||
*/
|
||||
if (!ieee80211_vif_is_mld(vif) && !mld_vif->ap_sta &&
|
||||
!WARN_ON_ONCE(vif->cfg.assoc) &&
|
||||
vif->type != NL80211_IFTYPE_AP && !mld->fw_status.in_hw_restart) {
|
||||
vif->type != NL80211_IFTYPE_AP && !mld->fw_status.in_hw_restart &&
|
||||
!iwl_trans_is_dead(mld->trans)) {
|
||||
iwl_mld_remove_link(mld, link);
|
||||
iwl_mld_add_link(mld, link);
|
||||
}
|
||||
|
|
@ -2853,6 +2854,15 @@ static int iwl_mld_start_pmsr(struct ieee80211_hw *hw,
|
|||
return iwl_mld_ftm_start(mld, vif, request);
|
||||
}
|
||||
|
||||
static void iwl_mld_abort_pmsr(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_pmsr_request *request)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
|
||||
iwl_mld_ftm_abort(mld, request);
|
||||
}
|
||||
|
||||
static enum ieee80211_neg_ttlm_res
|
||||
iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm)
|
||||
|
|
@ -2974,6 +2984,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = {
|
|||
.prep_add_interface = iwl_mld_prep_add_interface,
|
||||
.set_hw_timestamp = iwl_mld_set_hw_timestamp,
|
||||
.start_pmsr = iwl_mld_start_pmsr,
|
||||
.abort_pmsr = iwl_mld_abort_pmsr,
|
||||
.can_neg_ttlm = iwl_mld_can_neg_ttlm,
|
||||
.start_nan = iwl_mld_start_nan,
|
||||
.stop_nan = iwl_mld_stop_nan,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_mld_mac80211_h__
|
||||
#define __iwl_mld_mac80211_h__
|
||||
|
|
@ -9,5 +10,6 @@
|
|||
|
||||
int iwl_mld_register_hw(struct iwl_mld *mld);
|
||||
void iwl_mld_recalc_multicast_filter(struct iwl_mld *mld);
|
||||
void iwl_mld_restart_cleanup(struct iwl_mld *mld);
|
||||
|
||||
#endif /* __iwl_mld_mac80211_h__ */
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
|
|||
struct iwl_mcc_update_resp_v8 *resp;
|
||||
u8 resp_ver = iwl_fw_lookup_notif_ver(mld->fw, IWL_ALWAYS_LONG_GROUP,
|
||||
MCC_UPDATE_CMD, 0);
|
||||
enum iwl_puncturing_status puncturing_status;
|
||||
u16 mcc;
|
||||
|
||||
IWL_DEBUG_LAR(mld, "Getting regdomain data for %s from FW\n", alpha2);
|
||||
|
||||
|
|
@ -116,12 +118,13 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
|
|||
}
|
||||
IWL_DEBUG_LAR(mld, "MCC update response version: %d\n", resp_ver);
|
||||
|
||||
mcc = le16_to_cpu(resp->mcc);
|
||||
regd = iwl_parse_nvm_mcc_info(mld->trans,
|
||||
__le32_to_cpu(resp->n_channels),
|
||||
resp->channels,
|
||||
__le16_to_cpu(resp->mcc),
|
||||
resp->channels, mcc,
|
||||
__le16_to_cpu(resp->geo_info),
|
||||
le32_to_cpu(resp->cap), resp_ver);
|
||||
le32_to_cpu(resp->cap), resp_ver,
|
||||
&puncturing_status);
|
||||
|
||||
if (IS_ERR(regd)) {
|
||||
IWL_DEBUG_LAR(mld, "Could not get parse update from FW %ld\n",
|
||||
|
|
@ -135,18 +138,25 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
|
|||
|
||||
mld->mcc_src = resp->source_id;
|
||||
|
||||
if (puncturing_status == IWL_PUNCTURING_STATUS_ENABLED)
|
||||
__clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING,
|
||||
mld->hw->flags);
|
||||
else if (puncturing_status == IWL_PUNCTURING_STATUS_DISABLED)
|
||||
ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
|
||||
|
||||
if (resp_ver >= 10)
|
||||
goto out;
|
||||
|
||||
/* FM follows BIOS/MCC policy, WH disallows puncturing only in US/CA. */
|
||||
if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM) {
|
||||
if (!iwl_puncturing_is_allowed_in_bios(mld->bios_enable_puncturing,
|
||||
le16_to_cpu(resp->mcc)))
|
||||
if (!iwl_puncturing_is_allowed_in_bios(mld->fwrt.bios_puncturing,
|
||||
mcc))
|
||||
ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
|
||||
else
|
||||
__clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING,
|
||||
mld->hw->flags);
|
||||
} else if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) ==
|
||||
IWL_CFG_RF_TYPE_WH) {
|
||||
u16 mcc = le16_to_cpu(resp->mcc);
|
||||
|
||||
IWL_CFG_RF_TYPE_WH) {
|
||||
if (mcc == IWL_MCC_US || mcc == IWL_MCC_CANADA)
|
||||
ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ static const struct iwl_hcmd_names iwl_mld_reg_and_nvm_names[] = {
|
|||
HCMD_NAME(TAS_CONFIG),
|
||||
HCMD_NAME(SAR_OFFSET_MAPPING_TABLE_CMD),
|
||||
HCMD_NAME(MCC_ALLOWED_AP_TYPE_CMD),
|
||||
HCMD_NAME(PNVM_INIT_COMPLETE_NTFY),
|
||||
};
|
||||
|
||||
/* Please keep this array *SORTED* by hex value.
|
||||
|
|
@ -418,8 +419,6 @@ iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
iwl_mld_construct_fw_runtime(mld, trans, fw, dbgfs_dir);
|
||||
|
||||
iwl_mld_get_bios_tables(mld);
|
||||
iwl_uefi_get_sgom_table(trans, &mld->fwrt);
|
||||
mld->bios_enable_puncturing = iwl_uefi_get_puncturing(&mld->fwrt);
|
||||
|
||||
iwl_mld_hw_set_regulatory(mld);
|
||||
|
||||
|
|
@ -446,6 +445,8 @@ iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
/* wiphy memory is about to be freed, we should cancel any pending work */
|
||||
wiphy_work_cancel(mld->wiphy, &mld->async_handlers_wk);
|
||||
wiphy_unlock(mld->wiphy);
|
||||
rtnl_unlock();
|
||||
goto err;
|
||||
|
|
@ -511,6 +512,7 @@ iwl_op_mode_mld_stop(struct iwl_op_mode *op_mode)
|
|||
iwl_mld_thermal_exit(mld);
|
||||
|
||||
wiphy_lock(mld->wiphy);
|
||||
wiphy_work_cancel(mld->wiphy, &mld->async_handlers_wk);
|
||||
iwl_mld_low_latency_stop(mld);
|
||||
iwl_mld_deinit_time_sync(mld);
|
||||
wiphy_unlock(mld->wiphy);
|
||||
|
|
@ -745,6 +747,7 @@ static void iwl_mld_device_powered_off(struct iwl_op_mode *op_mode)
|
|||
|
||||
wiphy_lock(mld->wiphy);
|
||||
iwl_mld_stop_fw(mld);
|
||||
iwl_mld_restart_cleanup(mld);
|
||||
mld->fw_status.in_d3 = false;
|
||||
wiphy_unlock(mld->wiphy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@
|
|||
* @debug_max_sleep: maximum sleep time in D3 (for debug purposes)
|
||||
* @led: the led device
|
||||
* @mcc_src: the source id of the MCC, comes from the firmware
|
||||
* @bios_enable_puncturing: is puncturing enabled by bios
|
||||
* @fw_id_to_ba: maps a fw (BA) id to a corresponding Block Ack session data.
|
||||
* @num_rx_ba_sessions: tracks the number of active Rx Block Ack (BA) sessions.
|
||||
* the driver ensures that new BA sessions are blocked once the maximum
|
||||
|
|
@ -279,7 +278,6 @@ struct iwl_mld {
|
|||
struct led_classdev led;
|
||||
#endif
|
||||
enum iwl_mcc_source mcc_src;
|
||||
bool bios_enable_puncturing;
|
||||
|
||||
struct iwl_mld_baid_data __rcu *fw_id_to_ba[IWL_MAX_BAID];
|
||||
u8 num_rx_ba_sessions;
|
||||
|
|
|
|||
|
|
@ -298,7 +298,8 @@ CMD_VERSIONS(channel_survey_notif,
|
|||
CMD_VERSIONS(mfuart_notif,
|
||||
CMD_VER_ENTRY(2, iwl_mfuart_load_notif))
|
||||
CMD_VERSIONS(update_mcc,
|
||||
CMD_VER_ENTRY(1, iwl_mcc_chub_notif))
|
||||
CMD_VER_ENTRY(1, iwl_mcc_chub_notif)
|
||||
CMD_VER_ENTRY(2, iwl_mcc_chub_notif))
|
||||
CMD_VERSIONS(session_prot_notif,
|
||||
CMD_VER_ENTRY(3, iwl_session_prot_notif))
|
||||
CMD_VERSIONS(missed_beacon_notif,
|
||||
|
|
@ -517,7 +518,7 @@ iwl_mld_notif_is_valid(struct iwl_mld *mld, struct iwl_rx_packet *pkt,
|
|||
handler->cmd_id, notif_ver,
|
||||
handler->sizes[handler->n_sizes - 1].ver);
|
||||
|
||||
return size < handler->sizes[handler->n_sizes - 1].size;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct iwl_async_handler_entry {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,26 @@
|
|||
#include "mld.h"
|
||||
#include "hcmd.h"
|
||||
|
||||
static ssize_t iwl_mld_get_lari_config_cmd_size(u8 cmd_ver)
|
||||
{
|
||||
switch (cmd_ver) {
|
||||
case 15:
|
||||
return sizeof(struct iwl_lari_config_change_cmd);
|
||||
case 14:
|
||||
return offsetof(struct iwl_lari_config_change_cmd,
|
||||
oem_supported_dsm_bitmap);
|
||||
case 13:
|
||||
return offsetof(struct iwl_lari_config_change_cmd,
|
||||
oem_uhb_allow_extension_bitmap);
|
||||
case 12:
|
||||
return offsetof(struct iwl_lari_config_change_cmd,
|
||||
oem_11bn_allow_bitmap);
|
||||
default:
|
||||
WARN(true, "unsupported version: %d", cmd_ver);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_mld_get_bios_tables(struct iwl_mld *mld)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -67,6 +87,9 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld)
|
|||
iwl_uefi_get_uneb_table(mld->trans, &mld->fwrt);
|
||||
|
||||
iwl_bios_get_phy_filters(&mld->fwrt);
|
||||
|
||||
iwl_uefi_get_sgom_table(mld->trans, &mld->fwrt);
|
||||
iwl_uefi_get_puncturing(&mld->fwrt);
|
||||
}
|
||||
|
||||
static int iwl_mld_geo_sar_init(struct iwl_mld *mld)
|
||||
|
|
@ -325,11 +348,23 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
struct iwl_lari_config_change_cmd cmd = {
|
||||
.config_bitmap = iwl_mld_get_lari_config_bitmap(fwrt),
|
||||
};
|
||||
bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
|
||||
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), 12);
|
||||
/*
|
||||
* For LARI_CONFIG_CHANGE command version 13 and above, firmware accepts
|
||||
* raw DSM values by default and this TLV is no longer needed.
|
||||
*/
|
||||
bool has_raw_dsm_capa = cmd_ver >= 13 ||
|
||||
fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
|
||||
ssize_t cmd_len = iwl_mld_get_lari_config_cmd_size(cmd_ver);
|
||||
int ret;
|
||||
u32 value;
|
||||
|
||||
if (cmd_len < 0)
|
||||
return;
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
|
|
@ -371,8 +406,11 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
}
|
||||
|
||||
ret = iwl_bios_get_wbem(fwrt, &value);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
cmd.oem_320mhz_allow_bitmap = cpu_to_le32(value);
|
||||
cmd.bios_wbem_hdr.table_source = fwrt->wbem_source;
|
||||
cmd.bios_wbem_hdr.table_revision = fwrt->wbem_revision;
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
|
||||
if (!ret)
|
||||
|
|
@ -386,8 +424,21 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
if (!ret)
|
||||
cmd.oem_unii9_enable = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &value);
|
||||
if (!ret)
|
||||
cmd.oem_uhb_allow_extension_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_QUERY, &value);
|
||||
if (!ret)
|
||||
cmd.oem_supported_dsm_bitmap = cpu_to_le32(value);
|
||||
|
||||
cmd.bios_wcpe_hdr.table_source = fwrt->puncturing_source;
|
||||
cmd.bios_wcpe_hdr.table_revision = fwrt->puncturing_revision;
|
||||
cmd.wcpe_bitmap = cpu_to_le32(fwrt->bios_puncturing);
|
||||
|
||||
if (!cmd.config_bitmap &&
|
||||
!cmd.oem_uhb_allow_bitmap &&
|
||||
!cmd.oem_uhb_allow_extension_bitmap &&
|
||||
!cmd.oem_11ax_allow_bitmap &&
|
||||
!cmd.oem_unii4_allow_bitmap &&
|
||||
!cmd.chan_state_active_bitmap &&
|
||||
|
|
@ -396,7 +447,9 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
!cmd.oem_320mhz_allow_bitmap &&
|
||||
!cmd.oem_11be_allow_bitmap &&
|
||||
!cmd.oem_11bn_allow_bitmap &&
|
||||
!cmd.oem_unii9_enable)
|
||||
!cmd.oem_unii9_enable &&
|
||||
!cmd.wcpe_bitmap &&
|
||||
!cmd.oem_supported_dsm_bitmap)
|
||||
return;
|
||||
|
||||
cmd.bios_hdr.table_source = fwrt->dsm_source;
|
||||
|
|
@ -414,6 +467,9 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
"sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_uhb_allow_bitmap),
|
||||
le32_to_cpu(cmd.force_disable_channels_bitmap));
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, oem_uhb_allow_extension_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_uhb_allow_extension_bitmap));
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.edt_bitmap),
|
||||
|
|
@ -427,22 +483,16 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, oem_unii9_enable=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_unii9_enable));
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, wcpe_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.wcpe_bitmap));
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, oem_supported_dsm_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_supported_dsm_bitmap));
|
||||
|
||||
if (iwl_fw_lookup_cmd_ver(mld->fw,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), 12) == 12) {
|
||||
int cmd_size = offsetof(typeof(cmd), oem_11bn_allow_bitmap);
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE),
|
||||
&cmd, cmd_size);
|
||||
} else {
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE),
|
||||
&cmd);
|
||||
}
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), &cmd, cmd_len);
|
||||
if (ret)
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"Failed to send LARI_CONFIG_CHANGE (%d)\n",
|
||||
|
|
@ -488,6 +538,8 @@ void iwl_mld_init_ap_type_tables(struct iwl_mld *mld)
|
|||
if (ret)
|
||||
IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n",
|
||||
ret);
|
||||
else
|
||||
IWL_DEBUG_RADIO(mld, "MCC_ALLOWED_AP_TYPE_CMD sent to FW\n");
|
||||
}
|
||||
|
||||
void iwl_mld_init_tas(struct iwl_mld *mld)
|
||||
|
|
|
|||
|
|
@ -1681,7 +1681,8 @@ iwl_mld_scan_send_abort_cmd_status(struct iwl_mld *mld, int uid, u32 *status)
|
|||
static int
|
||||
iwl_mld_scan_abort(struct iwl_mld *mld, int type, int uid, bool *wait)
|
||||
{
|
||||
enum iwl_umac_scan_abort_status status;
|
||||
enum iwl_umac_scan_abort_status status =
|
||||
IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND;
|
||||
int ret;
|
||||
|
||||
*wait = true;
|
||||
|
|
|
|||
|
|
@ -355,10 +355,9 @@ static void iwl_mld_fill_pkt_ext(struct iwl_mld *mld,
|
|||
|
||||
for (int i = 0; i < MAX_HE_SUPP_NSS; i++) {
|
||||
for (int bw = 0;
|
||||
bw < ARRAY_SIZE(*pkt_ext->pkt_ext_qam_th[i]);
|
||||
bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);
|
||||
bw++) {
|
||||
u8 *qam_th =
|
||||
&pkt_ext->pkt_ext_qam_th[i][bw][0];
|
||||
u8 *qam_th = pkt_ext->pkt_ext_qam_th[i][bw];
|
||||
|
||||
IWL_DEBUG_HT(mld,
|
||||
"PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n",
|
||||
|
|
|
|||
|
|
@ -1517,12 +1517,48 @@ static int iwl_mvm_fill_lari_config(struct iwl_fw_runtime *fwrt,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mvm_send_lari_cfg_extension(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_fw_runtime *fwrt = &mvm->fwrt;
|
||||
struct iwl_lari_config_extension_cmd cmd = {};
|
||||
u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_EXTENSION);
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
if (iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) < 1)
|
||||
return;
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &value);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
cmd.dsm_table_hdr.table_source = fwrt->dsm_source;
|
||||
cmd.dsm_table_hdr.table_revision = fwrt->dsm_revision;
|
||||
cmd.oem_uhb_allow_extension_bitmap = cpu_to_le32(value);
|
||||
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"sending LARI_CONFIG_EXTENSION, oem_uhb_allow_extension_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_uhb_allow_extension_bitmap));
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
|
||||
if (ret < 0)
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"Failed to send LARI_CONFIG_EXTENSION (%d)\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_lari_config_change_cmd cmd;
|
||||
size_t cmd_size;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* LARI_CONFIG_CHANGE triggers a profile update, so send
|
||||
* LARI_CONFIG_EXTENSION first to make sure its data is applied
|
||||
* in the same update.
|
||||
*/
|
||||
iwl_mvm_send_lari_cfg_extension(mvm);
|
||||
ret = iwl_mvm_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size);
|
||||
if (!ret) {
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm,
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
|
|||
resp->channels,
|
||||
__le16_to_cpu(resp->mcc),
|
||||
__le16_to_cpu(resp->geo_info),
|
||||
le32_to_cpu(resp->cap), resp_ver);
|
||||
le32_to_cpu(resp->cap), resp_ver, NULL);
|
||||
/* Store the return source id */
|
||||
src_id = resp->source_id;
|
||||
if (IS_ERR_OR_NULL(regd)) {
|
||||
|
|
@ -1127,7 +1127,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
|
|||
RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
|
||||
}
|
||||
|
||||
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
||||
void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
||||
{
|
||||
iwl_mvm_stop_device(mvm);
|
||||
|
||||
|
|
@ -2350,10 +2350,9 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm,
|
|||
int bw;
|
||||
|
||||
for (bw = 0;
|
||||
bw < ARRAY_SIZE(*pkt_ext->pkt_ext_qam_th[i]);
|
||||
bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]);
|
||||
bw++) {
|
||||
u8 *qam_th =
|
||||
&pkt_ext->pkt_ext_qam_th[i][bw][0];
|
||||
u8 *qam_th = pkt_ext->pkt_ext_qam_th[i][bw];
|
||||
|
||||
IWL_DEBUG_HT(mvm,
|
||||
"PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n",
|
||||
|
|
|
|||
|
|
@ -1657,6 +1657,7 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
|
|||
u8 iwl_mvm_rate_idx_to_fw_idx(const struct iwl_fw *fw, int rate_idx);
|
||||
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
|
||||
bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm);
|
||||
|
||||
static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
|
||||
{
|
||||
|
|
@ -1672,14 +1673,24 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm);
|
|||
/* Tx / Host Commands */
|
||||
int iwl_mvm_send_cmd(struct iwl_mvm *mvm,
|
||||
struct iwl_host_cmd *cmd);
|
||||
int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
|
||||
u32 flags, u16 len, const void *data);
|
||||
int _iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
|
||||
u32 flags, u16 len, const void *data);
|
||||
#define iwl_mvm_send_cmd_pdu(mvm, id, flags, len, data) ({ \
|
||||
BUILD_BUG_ON(__builtin_constant_p(len) && \
|
||||
(u16)(len) > IWL_MAX_CMD_PAYLOAD_SIZE); \
|
||||
_iwl_mvm_send_cmd_pdu(mvm, id, flags, len, data); \
|
||||
})
|
||||
int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm,
|
||||
struct iwl_host_cmd *cmd,
|
||||
u32 *status);
|
||||
int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id,
|
||||
u16 len, const void *data,
|
||||
u32 *status);
|
||||
int _iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id,
|
||||
u16 len, const void *data,
|
||||
u32 *status);
|
||||
#define iwl_mvm_send_cmd_pdu_status(mvm, id, len, data, status) ({ \
|
||||
BUILD_BUG_ON(__builtin_constant_p(len) && \
|
||||
(u16)(len) > IWL_MAX_CMD_PAYLOAD_SIZE); \
|
||||
_iwl_mvm_send_cmd_pdu_status(mvm, id, len, data, status); \
|
||||
})
|
||||
int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
struct ieee80211_sta *sta);
|
||||
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb);
|
||||
|
|
@ -2392,14 +2403,12 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
|
|||
bool sync,
|
||||
const void *data, u32 size);
|
||||
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
|
||||
struct ieee80211_vif *iwl_mvm_get_vif_by_macid(struct iwl_mvm *mvm, u32 macid);
|
||||
bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm);
|
||||
|
||||
#define MVM_TCM_PERIOD_MSEC 500
|
||||
#define MVM_TCM_PERIOD (HZ * MVM_TCM_PERIOD_MSEC / 1000)
|
||||
#define MVM_LL_PERIOD (10 * HZ)
|
||||
void iwl_mvm_tcm_work(struct work_struct *work);
|
||||
void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel);
|
||||
void iwl_mvm_resume_tcm(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm,
|
|||
if (notif->type != cpu_to_le32(IWL_DP_MON_NOTIF_TYPE_EXT_CCA))
|
||||
return;
|
||||
|
||||
/* FIXME: should fetch the link and not the vif */
|
||||
vif = iwl_mvm_get_vif_by_macid(mvm, notif->link_id);
|
||||
/* mac_id = link_id since we don't support MLO */
|
||||
vif = iwl_mvm_rcu_dereference_vif_id(mvm, notif->link_id, false);
|
||||
if (!vif || vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
|
|
@ -707,6 +707,7 @@ static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = {
|
|||
HCMD_NAME(NVM_ACCESS_COMPLETE),
|
||||
HCMD_NAME(NVM_GET_INFO),
|
||||
HCMD_NAME(TAS_CONFIG),
|
||||
HCMD_NAME(LARI_CONFIG_EXTENSION),
|
||||
};
|
||||
|
||||
/* Please keep this array *SORTED* by hex value.
|
||||
|
|
@ -954,7 +955,7 @@ static void iwl_mvm_frob_txf_key_iter(struct ieee80211_hw *hw,
|
|||
}
|
||||
match++;
|
||||
if (match == keylen) {
|
||||
memset(txf->buf + i - keylen, 0xAA, keylen);
|
||||
memset(txf->buf + i + 1 - keylen, 0xAA, keylen);
|
||||
match = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1535,6 +1536,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)
|
|||
iwl_fw_cancel_timestamp(&mvm->fwrt);
|
||||
|
||||
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
|
||||
mvm->sf_state = SF_UNINIT;
|
||||
|
||||
iwl_mvm_pause_tcm(mvm, false);
|
||||
|
||||
|
|
@ -2090,7 +2092,7 @@ static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode)
|
|||
|
||||
mutex_lock(&mvm->mutex);
|
||||
clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
|
||||
iwl_mvm_stop_device(mvm);
|
||||
iwl_mvm_restart_cleanup(mvm);
|
||||
mvm->fast_resume = false;
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
* Copyright (C) 2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __TIME_SYNC_H__
|
||||
#define __TIME_SYNC_H__
|
||||
|
|
@ -19,6 +20,9 @@ int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, const u8 *addr,
|
|||
static inline
|
||||
bool iwl_mvm_time_sync_frame(struct iwl_mvm *mvm, struct sk_buff *skb, u8 *addr)
|
||||
{
|
||||
if (!mvm->time_sync.active)
|
||||
return false;
|
||||
|
||||
if (ether_addr_equal(mvm->time_sync.peer_addr, addr) &&
|
||||
(ieee80211_is_timing_measurement(skb) || ieee80211_is_ftm(skb))) {
|
||||
skb_queue_tail(&mvm->time_sync.frame_list, skb);
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
|
||||
u32 flags, u16 len, const void *data)
|
||||
int _iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,
|
||||
u32 flags, u16 len, const void *data)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = id,
|
||||
|
|
@ -137,8 +137,8 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
|
|||
/*
|
||||
* We assume that the caller set the status to the sucess value
|
||||
*/
|
||||
int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,
|
||||
const void *data, u32 *status)
|
||||
int _iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,
|
||||
const void *data, u32 *status)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = id,
|
||||
|
|
@ -689,36 +689,6 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
|
|||
return bss_iter_data.vif;
|
||||
}
|
||||
|
||||
struct iwl_bss_find_iter_data {
|
||||
struct ieee80211_vif *vif;
|
||||
u32 macid;
|
||||
};
|
||||
|
||||
static void iwl_mvm_bss_find_iface_iterator(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_bss_find_iter_data *data = _data;
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
if (mvmvif->id == data->macid)
|
||||
data->vif = vif;
|
||||
}
|
||||
|
||||
struct ieee80211_vif *iwl_mvm_get_vif_by_macid(struct iwl_mvm *mvm, u32 macid)
|
||||
{
|
||||
struct iwl_bss_find_iter_data data = {
|
||||
.macid = macid,
|
||||
};
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_bss_find_iface_iterator, &data);
|
||||
|
||||
return data.vif;
|
||||
}
|
||||
|
||||
struct iwl_sta_iter_data {
|
||||
bool assoc;
|
||||
};
|
||||
|
|
@ -1055,7 +1025,7 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
|
|||
/*
|
||||
* If the current load isn't low we need to force re-evaluation
|
||||
* in the TCM period, so that we can return to low load if there
|
||||
* was no traffic at all (and thus iwl_mvm_recalc_tcm didn't get
|
||||
* was no traffic at all (and thus iwl_mvm_tcm_work() didn't get
|
||||
* triggered by traffic).
|
||||
*/
|
||||
if (load != IWL_MVM_TRAFFIC_LOW)
|
||||
|
|
@ -1081,8 +1051,11 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)
|
||||
void iwl_mvm_tcm_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm,
|
||||
tcm.work);
|
||||
unsigned long ts = jiffies;
|
||||
bool handle_uapsd =
|
||||
time_after(ts, mvm->tcm.uapsd_nonagg_ts +
|
||||
|
|
@ -1119,15 +1092,6 @@ void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)
|
|||
iwl_mvm_tcm_results(mvm);
|
||||
}
|
||||
|
||||
void iwl_mvm_tcm_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm,
|
||||
tcm.work);
|
||||
|
||||
iwl_mvm_recalc_tcm(mvm);
|
||||
}
|
||||
|
||||
void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel)
|
||||
{
|
||||
spin_lock_bh(&mvm->tcm.lock);
|
||||
|
|
|
|||
|
|
@ -548,6 +548,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0xD340, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x6E70, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
{IWL_PCI_DEVICE(0xD240, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9327, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
#endif /* CONFIG_IWLMVM || CONFIG_IWLMLD */
|
||||
|
||||
{0}
|
||||
|
|
|
|||
|
|
@ -773,6 +773,8 @@ int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
|
||||
tfd = iwl_txq_gen2_build_tfd(trans, txq, dev_cmd, skb, out_meta);
|
||||
if (!tfd) {
|
||||
txq->entries[idx].skb = NULL;
|
||||
txq->entries[idx].cmd = NULL;
|
||||
spin_unlock(&txq->lock);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2003-2014, 2018-2021, 2023-2025 Intel Corporation
|
||||
* Copyright (C) 2003-2014, 2018-2021, 2023-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -1149,10 +1149,17 @@ bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
|||
unsigned int wdg_timeout)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id];
|
||||
struct iwl_txq *txq;
|
||||
int fifo = -1;
|
||||
bool scd_bug = false;
|
||||
|
||||
if (WARN_ONCE(txq_id < 0 ||
|
||||
txq_id >= trans->mac_cfg->base->num_of_queues,
|
||||
"queue %d out of range", txq_id))
|
||||
return false;
|
||||
|
||||
txq = trans_pcie->txqs.txq[txq_id];
|
||||
|
||||
if (test_and_set_bit(txq_id, trans_pcie->txqs.queue_used))
|
||||
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
|
|||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
|
||||
struct cfg80211_mgmt_tx_params *params, u64 cookie)
|
||||
{
|
||||
const u8 *buf = params->buf;
|
||||
size_t len = params->len;
|
||||
|
|
@ -259,14 +259,13 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
tx_info->pkt_len = pkt_len;
|
||||
|
||||
mwifiex_form_mgmt_frame(skb, buf, len);
|
||||
*cookie = get_random_u32() | 1;
|
||||
|
||||
if (ieee80211_is_action(mgmt->frame_control))
|
||||
skb = mwifiex_clone_skb_for_tx_status(priv,
|
||||
skb,
|
||||
MWIFIEX_BUF_FLAG_ACTION_TX_STATUS, cookie);
|
||||
MWIFIEX_BUF_FLAG_ACTION_TX_STATUS, &cookie);
|
||||
else
|
||||
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
|
||||
cfg80211_mgmt_tx_status(wdev, cookie, buf, len, true,
|
||||
GFP_ATOMIC);
|
||||
|
||||
mwifiex_queue_tx_pkt(priv, skb);
|
||||
|
|
@ -304,13 +303,13 @@ static int
|
|||
mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration, u64 *cookie,
|
||||
unsigned int duration, u64 cookie,
|
||||
const u8 *rx_addr)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
|
||||
int ret;
|
||||
|
||||
if (!chan || !cookie) {
|
||||
if (!chan) {
|
||||
mwifiex_dbg(priv->adapter, ERROR, "Invalid parameter for ROC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -326,15 +325,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
|
|||
duration);
|
||||
|
||||
if (!ret) {
|
||||
*cookie = get_random_u32() | 1;
|
||||
priv->roc_cfg.cookie = *cookie;
|
||||
priv->roc_cfg.cookie = cookie;
|
||||
priv->roc_cfg.chan = *chan;
|
||||
|
||||
cfg80211_ready_on_channel(wdev, *cookie, chan,
|
||||
cfg80211_ready_on_channel(wdev, cookie, chan,
|
||||
duration, GFP_ATOMIC);
|
||||
|
||||
mwifiex_dbg(priv->adapter, INFO,
|
||||
"info: ROC, cookie = 0x%llx\n", *cookie);
|
||||
"info: ROC, cookie = 0x%llx\n", cookie);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -4560,7 +4558,7 @@ mwifiex_cfg80211_disassociate(struct wiphy *wiphy,
|
|||
static int
|
||||
mwifiex_cfg80211_probe_peer(struct wiphy *wiphy,
|
||||
struct net_device *dev, const u8 *peer,
|
||||
u64 *cookie)
|
||||
u64 cookie)
|
||||
{
|
||||
/* hostapd looks for NL80211_CMD_PROBE_CLIENT support; otherwise,
|
||||
* it requires monitor-mode support (which mwifiex doesn't support).
|
||||
|
|
|
|||
|
|
@ -1550,7 +1550,7 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter)
|
|||
|
||||
adapter->workqueue =
|
||||
alloc_workqueue("MWIFIEX_WORK_QUEUE",
|
||||
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
if (!adapter->workqueue)
|
||||
goto err_kmalloc;
|
||||
|
||||
|
|
@ -1716,7 +1716,7 @@ mwifiex_add_card(void *card, struct completion *fw_done,
|
|||
|
||||
adapter->workqueue =
|
||||
alloc_workqueue("MWIFIEX_WORK_QUEUE",
|
||||
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
|
||||
if (!adapter->workqueue)
|
||||
goto err_kmalloc;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,18 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
|
|||
mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",
|
||||
status);
|
||||
mwifiex_cancel_all_pending_cmd(adapter);
|
||||
|
||||
/* The command response path writes through cmd_node->data_buf.
|
||||
* On an interrupted wait, the caller can return and release a
|
||||
* stack-allocated data_buf before a late firmware response is
|
||||
* processed. Detach the caller-owned buffer from the current
|
||||
* command so a late response cannot corrupt freed stack memory.
|
||||
*/
|
||||
spin_lock_bh(&adapter->mwifiex_cmd_lock);
|
||||
if (adapter->curr_cmd == cmd_queued)
|
||||
adapter->curr_cmd->data_buf = NULL;
|
||||
spin_unlock_bh(&adapter->mwifiex_cmd_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,68 +186,74 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
|
|||
int n_vifs,
|
||||
enum ieee80211_chanctx_switch_mode mode)
|
||||
{
|
||||
struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv;
|
||||
struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv;
|
||||
struct ieee80211_chanctx_conf *conf = vifs->new_ctx;
|
||||
struct mt76_phy *old_phy = old_ctx->phy;
|
||||
struct mt76_phy *phy = hw->priv;
|
||||
struct ieee80211_vif_chanctx_switch *v;
|
||||
struct mt76_chanctx *old_ctx, *new_ctx;
|
||||
struct mt76_phy *old_phy, *phy = hw->priv;
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct mt76_vif_link *mlink;
|
||||
bool update_chan;
|
||||
bool need_update[__MT_MAX_BAND] = {};
|
||||
int i, ret = 0;
|
||||
|
||||
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
|
||||
phy = new_ctx->phy = dev->band_phys[conf->def.chan->band];
|
||||
else
|
||||
phy = new_ctx->phy;
|
||||
if (!phy)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
v = &vifs[i];
|
||||
new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv;
|
||||
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
|
||||
phy = new_ctx->phy = dev->band_phys[v->new_ctx->def.chan->band];
|
||||
else
|
||||
phy = new_ctx->phy;
|
||||
|
||||
update_chan = phy->chanctx != new_ctx;
|
||||
if (update_chan) {
|
||||
if (dev->scan.phy == phy)
|
||||
mt76_abort_scan(dev);
|
||||
if (!phy)
|
||||
return -EINVAL;
|
||||
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
if (need_update[phy->band_idx])
|
||||
continue;
|
||||
|
||||
if (phy->chanctx != new_ctx) {
|
||||
if (dev->scan.phy == phy)
|
||||
mt76_abort_scan(dev);
|
||||
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
need_update[phy->band_idx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
|
||||
phy != old_phy && old_phy->chanctx == old_ctx)
|
||||
old_phy->chanctx = NULL;
|
||||
|
||||
if (update_chan)
|
||||
ret = mt76_phy_update_channel(phy, vifs->new_ctx);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (old_phy == phy)
|
||||
goto skip_link_replace;
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
|
||||
v = &vifs[i];
|
||||
old_ctx = (struct mt76_chanctx *)v->old_ctx->drv_priv;
|
||||
old_phy = old_ctx->phy;
|
||||
|
||||
new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv;
|
||||
phy = new_ctx->phy;
|
||||
|
||||
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && old_phy->chanctx &&
|
||||
old_phy->chanctx == old_ctx && phy != old_phy)
|
||||
old_phy->chanctx = NULL;
|
||||
|
||||
if (need_update[phy->band_idx]) {
|
||||
ret = mt76_phy_update_channel(phy, v->new_ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
need_update[phy->band_idx] = false;
|
||||
}
|
||||
|
||||
mlink = mt76_vif_conf_link(dev, v->vif, v->link_conf);
|
||||
if (!mlink)
|
||||
continue;
|
||||
|
||||
dev->drv->vif_link_remove(old_phy, vifs[i].vif,
|
||||
vifs[i].link_conf, mlink);
|
||||
if (old_phy != phy) {
|
||||
dev->drv->vif_link_remove(old_phy, v->vif, v->link_conf,
|
||||
mlink);
|
||||
|
||||
ret = dev->drv->vif_link_add(phy, vifs[i].vif,
|
||||
vifs[i].link_conf, mlink);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = dev->drv->vif_link_add(phy, v->vif, v->link_conf,
|
||||
mlink);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
skip_link_replace:
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
|
||||
if (!mlink)
|
||||
continue;
|
||||
|
||||
mlink->ctx = vifs->new_ctx;
|
||||
mlink->ctx = v->new_ctx;
|
||||
if (mlink->beacon_mon_interval)
|
||||
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,18 @@ mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
}
|
||||
}
|
||||
|
||||
/* A hung bus (e.g. after a PCIe AER error) reads 0xffffffff from every
|
||||
* register, so clamp an out-of-range index to the fallback to keep it from
|
||||
* corrupting q->head/q->tail.
|
||||
*/
|
||||
static int
|
||||
mt76_dma_read_dma_idx(struct mt76_queue *q, int fallback)
|
||||
{
|
||||
u32 idx = Q_READ(q, dma_idx);
|
||||
|
||||
return idx < q->ndesc ? idx : fallback;
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
|
||||
{
|
||||
|
|
@ -201,7 +213,8 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
}
|
||||
|
||||
Q_WRITE(q, desc_base, q->desc_dma);
|
||||
q->head = Q_READ(q, dma_idx);
|
||||
|
||||
q->head = mt76_dma_read_dma_idx(q, 0);
|
||||
q->tail = q->head;
|
||||
}
|
||||
|
||||
|
|
@ -419,7 +432,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
|
|||
if (flush)
|
||||
last = -1;
|
||||
else
|
||||
last = Q_READ(q, dma_idx);
|
||||
last = mt76_dma_read_dma_idx(q, -1);
|
||||
|
||||
while (q->queued > 0 && q->tail != last) {
|
||||
mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
|
||||
|
|
@ -432,7 +445,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
|
|||
}
|
||||
|
||||
if (!flush && q->tail == last)
|
||||
last = Q_READ(q, dma_idx);
|
||||
last = mt76_dma_read_dma_idx(q, -1);
|
||||
}
|
||||
spin_unlock_bh(&q->cleanup_lock);
|
||||
|
||||
|
|
@ -534,8 +547,13 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
|
|||
t->ptr = NULL;
|
||||
|
||||
mt76_put_rxwi(dev, t);
|
||||
if (drop)
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
/* the WO MCU owns the RX path only on WED v2, on newer
|
||||
* versions this buf1 bit carries no drop information
|
||||
*/
|
||||
if (drop && dev->mmio.wed.version == 2)
|
||||
*drop |= !!(buf1 & MT_DMA_CTL_WO_DROP);
|
||||
#endif
|
||||
} else {
|
||||
dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],
|
||||
SKB_WITH_OVERHEAD(q->buf_size),
|
||||
|
|
@ -595,6 +613,15 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
|
|||
q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE);
|
||||
else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE)))
|
||||
return NULL;
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
/* on WED v3 the M_DONE bit signals that WED is done reading
|
||||
* the txfree descriptor; WED v2 does not set it
|
||||
*/
|
||||
else if (dev->mmio.wed.version > 2 &&
|
||||
mt76_queue_is_wed_tx_free(q) &&
|
||||
!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_M_DONE)))
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
done:
|
||||
q->tail = (q->tail + 1) % q->ndesc;
|
||||
|
|
@ -625,8 +652,8 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
|
|||
buf.len = skb->len;
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL);
|
||||
mt76_dma_kick_queue(dev, q);
|
||||
if (mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL) >= 0)
|
||||
mt76_dma_kick_queue(dev, q);
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
return 0;
|
||||
|
|
@ -977,23 +1004,24 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
|
|||
struct sk_buff *skb;
|
||||
unsigned char *data;
|
||||
bool check_ddone = false;
|
||||
bool allow_direct = !mt76_queue_is_wed_rx(q);
|
||||
bool allow_direct = !mt76_queue_is_wed_rx(q) &&
|
||||
!mt76_queue_is_wed_rro_rxdmad_c(q);
|
||||
bool more;
|
||||
|
||||
if ((q->flags & MT_QFLAG_WED_RRO_EN) ||
|
||||
(IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
|
||||
mt76_queue_is_wed_tx_free(q))) {
|
||||
dma_idx = Q_READ(q, dma_idx);
|
||||
dma_idx = mt76_dma_read_dma_idx(q, q->tail);
|
||||
check_ddone = true;
|
||||
}
|
||||
|
||||
while (done < budget) {
|
||||
bool drop = false;
|
||||
u32 info;
|
||||
u32 info = 0;
|
||||
|
||||
if (check_ddone) {
|
||||
if (q->tail == dma_idx)
|
||||
dma_idx = Q_READ(q, dma_idx);
|
||||
dma_idx = mt76_dma_read_dma_idx(q, q->tail);
|
||||
|
||||
if (q->tail == dma_idx)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@
|
|||
#ifndef __MT76_DMA_H
|
||||
#define __MT76_DMA_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define DMA_DUMMY_DATA ((void *)~0)
|
||||
|
||||
#define MT_RING_SIZE 0x10
|
||||
|
||||
#define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0)
|
||||
#define MT_DMA_CTL_LAST_SEC1 BIT(14)
|
||||
#define MT_DMA_CTL_BURST BIT(15)
|
||||
#define MT_DMA_CTL_M_DONE BIT(15)
|
||||
#define MT_DMA_CTL_SD_LEN0 GENMASK(29, 16)
|
||||
#define MT_DMA_CTL_LAST_SEC0 BIT(30)
|
||||
#define MT_DMA_CTL_DMA_DONE BIT(31)
|
||||
|
|
@ -46,73 +48,75 @@
|
|||
#define MT_FCE_INFO_LEN 4
|
||||
#define MT_RX_RXWI_LEN 32
|
||||
|
||||
static inline bool
|
||||
mt76_dma_handle_read(struct mt76_queue *q, u32 offset, u32 *val)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
|
||||
if (q->flags & MT_QFLAG_WED) {
|
||||
*val = mtk_wed_device_reg_read(q->wed, q->wed_regs + offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_MT76_NPU)
|
||||
if (q->flags & MT_QFLAG_NPU) {
|
||||
struct airoha_npu *npu;
|
||||
|
||||
*val = 0;
|
||||
rcu_read_lock();
|
||||
npu = rcu_dereference(q->dev->mmio.npu);
|
||||
if (npu)
|
||||
regmap_read(npu->regmap, q->wed_regs + offset, val);
|
||||
rcu_read_unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
mt76_dma_handle_write(struct mt76_queue *q, u32 offset, u32 val)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
|
||||
if (q->flags & MT_QFLAG_WED) {
|
||||
mtk_wed_device_reg_write(q->wed, q->wed_regs + offset, val);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_MT76_NPU)
|
||||
if (q->flags & MT_QFLAG_NPU) {
|
||||
struct airoha_npu *npu;
|
||||
|
||||
rcu_read_lock();
|
||||
npu = rcu_dereference(q->dev->mmio.npu);
|
||||
if (npu)
|
||||
regmap_write(npu->regmap, q->wed_regs + offset, val);
|
||||
rcu_read_unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define Q_READ(_q, _field) ({ \
|
||||
u32 _offset = offsetof(struct mt76_queue_regs, _field); \
|
||||
u32 _val; \
|
||||
if ((_q)->flags & MT_QFLAG_WED) \
|
||||
_val = mtk_wed_device_reg_read((_q)->wed, \
|
||||
((_q)->wed_regs + \
|
||||
_offset)); \
|
||||
else \
|
||||
if (!mt76_dma_handle_read(_q, _offset, &_val)) \
|
||||
_val = readl(&(_q)->regs->_field); \
|
||||
_val; \
|
||||
})
|
||||
|
||||
#define Q_WRITE(_q, _field, _val) do { \
|
||||
u32 _offset = offsetof(struct mt76_queue_regs, _field); \
|
||||
if ((_q)->flags & MT_QFLAG_WED) \
|
||||
mtk_wed_device_reg_write((_q)->wed, \
|
||||
((_q)->wed_regs + _offset), \
|
||||
_val); \
|
||||
else \
|
||||
if (!mt76_dma_handle_write(_q, _offset, _val)) \
|
||||
writel(_val, &(_q)->regs->_field); \
|
||||
} while (0)
|
||||
|
||||
#elif IS_ENABLED(CONFIG_MT76_NPU)
|
||||
|
||||
#define Q_READ(_q, _field) ({ \
|
||||
u32 _offset = offsetof(struct mt76_queue_regs, _field); \
|
||||
u32 _val = 0; \
|
||||
if ((_q)->flags & MT_QFLAG_NPU) { \
|
||||
struct airoha_npu *npu; \
|
||||
\
|
||||
rcu_read_lock(); \
|
||||
npu = rcu_dereference(q->dev->mmio.npu); \
|
||||
if (npu) \
|
||||
regmap_read(npu->regmap, \
|
||||
((_q)->wed_regs + _offset), &_val); \
|
||||
rcu_read_unlock(); \
|
||||
} else { \
|
||||
_val = readl(&(_q)->regs->_field); \
|
||||
} \
|
||||
_val; \
|
||||
})
|
||||
|
||||
#define Q_WRITE(_q, _field, _val) do { \
|
||||
u32 _offset = offsetof(struct mt76_queue_regs, _field); \
|
||||
if ((_q)->flags & MT_QFLAG_NPU) { \
|
||||
struct airoha_npu *npu; \
|
||||
\
|
||||
rcu_read_lock(); \
|
||||
npu = rcu_dereference(q->dev->mmio.npu); \
|
||||
if (npu) \
|
||||
regmap_write(npu->regmap, \
|
||||
((_q)->wed_regs + _offset), _val); \
|
||||
rcu_read_unlock(); \
|
||||
} else { \
|
||||
writel(_val, &(_q)->regs->_field); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define Q_READ(_q, _field) readl(&(_q)->regs->_field)
|
||||
#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field)
|
||||
|
||||
#endif
|
||||
|
||||
struct mt76_desc {
|
||||
__le32 buf0;
|
||||
__le32 ctrl;
|
||||
|
|
|
|||
|
|
@ -439,8 +439,9 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
|
|||
SET_IEEE80211_DEV(hw, dev->dev);
|
||||
SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
|
||||
|
||||
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
|
||||
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
|
||||
wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
|
||||
if (!phy->no_active_monitor)
|
||||
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
|
||||
WIPHY_FLAG_SUPPORTS_TDLS |
|
||||
WIPHY_FLAG_AP_UAPSD;
|
||||
|
|
@ -681,6 +682,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
|
|||
dev = hw->priv;
|
||||
dev->hw = hw;
|
||||
dev->dev = pdev;
|
||||
dev->init_wiphy = NULL;
|
||||
dev->drv = drv_ops;
|
||||
dev->dma_dev = pdev;
|
||||
|
||||
|
|
@ -779,6 +781,12 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
|
|||
mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
|
||||
mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
|
||||
|
||||
if (dev->init_wiphy) {
|
||||
ret = dev->init_wiphy(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
|
||||
ret = mt76_led_init(phy);
|
||||
if (ret)
|
||||
|
|
@ -886,6 +894,7 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
|
|||
struct sk_buff *skb = phy->rx_amsdu[q].head;
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct mt76_queue *rxq = &dev->q_rx[q];
|
||||
|
||||
phy->rx_amsdu[q].head = NULL;
|
||||
phy->rx_amsdu[q].tail = NULL;
|
||||
|
|
@ -914,6 +923,13 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* RRO 3.0 data queue skbs are processed and completed in the context
|
||||
* of the indicator queue NAPI, which only polls its own skb list
|
||||
*/
|
||||
if (mt76_queue_is_wed_rro_data(rxq) && dev->hwrro_mode == MT76_HWRRO_V3)
|
||||
q = MT_RXQ_RRO_IND;
|
||||
|
||||
__skb_queue_tail(&dev->rx_skb[q], skb);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,15 +78,19 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
|
|||
unsigned long expires;
|
||||
int ret, seq;
|
||||
|
||||
if (mt76_is_sdio(dev))
|
||||
if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung))
|
||||
return -EIO;
|
||||
|
||||
if (ret_skb)
|
||||
*ret_skb = NULL;
|
||||
|
||||
mutex_lock(&dev->mcu.mutex);
|
||||
|
||||
if ((mt76_is_mmio(dev) && atomic_read(&dev->bus_hung)) ||
|
||||
(mt76_is_sdio(dev) && test_bit(MT76_RESET, &dev->phy.state) &&
|
||||
atomic_read(&dev->bus_hung))) {
|
||||
orig_skb = skb;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev->mcu_ops->mcu_skb_prepare_msg) {
|
||||
orig_skb = skb;
|
||||
ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq);
|
||||
|
|
|
|||
|
|
@ -35,9 +35,16 @@ static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset,
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ALIGN(len, 4); i += 4)
|
||||
for (i = 0; i + 4 <= len; i += 4)
|
||||
writel(get_unaligned_le32(data + i),
|
||||
dev->mmio.regs + offset + i);
|
||||
|
||||
if (i < len) {
|
||||
u8 tmp[4] = {};
|
||||
|
||||
memcpy(tmp, data + i, len - i);
|
||||
writel(get_unaligned_le32(tmp), dev->mmio.regs + offset + i);
|
||||
}
|
||||
}
|
||||
|
||||
static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
|
||||
|
|
@ -45,9 +52,16 @@ static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset,
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ALIGN(len, 4); i += 4)
|
||||
for (i = 0; i + 4 <= len; i += 4)
|
||||
put_unaligned_le32(readl(dev->mmio.regs + offset + i),
|
||||
data + i);
|
||||
|
||||
if (i < len) {
|
||||
u8 tmp[4];
|
||||
|
||||
put_unaligned_le32(readl(dev->mmio.regs + offset + i), tmp);
|
||||
memcpy(data + i, tmp, len - i);
|
||||
}
|
||||
}
|
||||
|
||||
static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
|
||||
|
|
|
|||
|
|
@ -539,6 +539,7 @@ struct mt76_hw_cap {
|
|||
#define MT_DRV_HW_MGMT_TXQ BIT(4)
|
||||
#define MT_DRV_AMSDU_OFFLOAD BIT(5)
|
||||
#define MT_DRV_IGNORE_TXS_FAILED BIT(6)
|
||||
#define MT_DRV_HW_PS_BUFFERING BIT(7)
|
||||
|
||||
struct mt76_driver_ops {
|
||||
u32 drv_flags;
|
||||
|
|
@ -672,6 +673,7 @@ struct mt76_usb {
|
|||
|
||||
u8 out_ep[__MT_EP_OUT_MAX];
|
||||
u8 in_ep[__MT_EP_IN_MAX];
|
||||
void (*ctrl_timeout)(struct mt76_dev *dev, int err);
|
||||
bool sg_en;
|
||||
|
||||
struct mt76u_mcu {
|
||||
|
|
@ -871,6 +873,7 @@ struct mt76_phy {
|
|||
struct cfg80211_chan_def main_chandef;
|
||||
bool offchannel;
|
||||
bool radar_enabled;
|
||||
bool no_active_monitor;
|
||||
|
||||
struct delayed_work roc_work;
|
||||
struct ieee80211_vif *roc_vif;
|
||||
|
|
@ -940,6 +943,9 @@ struct mt76_dev {
|
|||
const struct mt76_bus_ops *bus;
|
||||
const struct mt76_driver_ops *drv;
|
||||
const struct mt76_mcu_ops *mcu_ops;
|
||||
|
||||
/* Optional callback to finalize wiphy state before registration. */
|
||||
int (*init_wiphy)(struct mt76_dev *dev);
|
||||
struct device *dev;
|
||||
struct device *dma_dev;
|
||||
|
||||
|
|
@ -1537,6 +1543,8 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
|
|||
u16 tids, int nframes,
|
||||
enum ieee80211_frame_release_type reason,
|
||||
bool more_data);
|
||||
void mt76_sta_ps_transition(struct mt76_dev *dev, struct mt76_wcid *wcid,
|
||||
bool ps);
|
||||
bool mt76_has_tx_pending(struct mt76_phy *phy);
|
||||
int mt76_update_channel(struct mt76_phy *phy);
|
||||
void mt76_update_survey(struct mt76_phy *phy);
|
||||
|
|
@ -2124,6 +2132,9 @@ mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id)
|
|||
if (!link_id)
|
||||
return mlink;
|
||||
|
||||
if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
|
||||
return NULL;
|
||||
|
||||
return mt76_dereference(mvif->link[link_id], dev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BCN));
|
||||
if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) {
|
||||
dev->beacon_check = MT7603_WATCHDOG_TIMEOUT;
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +64,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BMC));
|
||||
if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) {
|
||||
dev->beacon_check = MT7603_WATCHDOG_TIMEOUT;
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
|
|||
|
||||
val = le32_to_cpu(txd[1]);
|
||||
idx = FIELD_GET(MT_TXD1_WLAN_IDX, val);
|
||||
skb->priority = FIELD_GET(MT_TXD1_TID, val);
|
||||
|
||||
if (idx >= MT7603_WTBL_STA - 1)
|
||||
goto free;
|
||||
|
|
@ -72,6 +71,7 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
|
|||
hwq = MT_TX_HW_QUEUE_MGMT;
|
||||
}
|
||||
|
||||
skb->priority = tid;
|
||||
ieee80211_sta_set_buffered(sta, tid, true);
|
||||
|
||||
val = le32_to_cpu(txd[0]);
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ static int mt7603_check_eeprom(struct mt76_dev *dev)
|
|||
case 0x7628:
|
||||
case 0x7603:
|
||||
case 0x7600:
|
||||
case 0x7592:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -235,16 +235,17 @@ void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
|||
sta->smps = enabled;
|
||||
}
|
||||
|
||||
void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled)
|
||||
static void
|
||||
__mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled, bool filter)
|
||||
{
|
||||
int idx = sta->wcid.idx;
|
||||
u32 addr;
|
||||
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
lockdep_assert_held(&dev->ps_lock);
|
||||
|
||||
if (sta->ps == enabled)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
mt76_wr(dev, MT_PSE_RTA,
|
||||
FIELD_PREP(MT_PSE_RTA_TAG_ID, idx) |
|
||||
|
|
@ -255,7 +256,7 @@ void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
|||
|
||||
mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000);
|
||||
|
||||
if (enabled)
|
||||
if (enabled && filter)
|
||||
mt7603_filter_tx(dev, sta->vif->idx, idx, false);
|
||||
|
||||
addr = mt7603_wtbl1_addr(idx);
|
||||
|
|
@ -264,8 +265,34 @@ void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
|||
enabled * MT_WTBL1_W3_POWER_SAVE);
|
||||
mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
|
||||
sta->ps = enabled;
|
||||
}
|
||||
|
||||
out:
|
||||
void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled)
|
||||
{
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
__mt7603_wtbl_set_ps(dev, sta, enabled, enabled);
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
}
|
||||
|
||||
void mt7603_wtbl_sta_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool ps)
|
||||
{
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
sta->ps_sleeping = ps;
|
||||
__mt7603_wtbl_set_ps(dev, sta, ps, ps);
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
}
|
||||
|
||||
void mt7603_wtbl_restore_ps(struct mt7603_dev *dev, struct mt7603_sta *sta)
|
||||
{
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
/*
|
||||
* Frames that are already queued for the station belong to the service
|
||||
* period that has just been served, so unlike on a sleep transition
|
||||
* they must not be pulled back into the PS queue.
|
||||
*/
|
||||
if (sta->ps_sleeping)
|
||||
__mt7603_wtbl_set_ps(dev, sta, true, false);
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
}
|
||||
|
||||
|
|
@ -1816,6 +1843,39 @@ mt7603_false_cca_check(struct mt7603_dev *dev)
|
|||
mt7603_adjust_sensitivity(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Releasing buffered frames turns off the PSE redirect for a station, since
|
||||
* the released frames would otherwise be looped back into the driver PS queue
|
||||
* again. mac80211 never tells us when the service period is over, so hardware
|
||||
* buffering has to be re-armed here for every station that is still known to
|
||||
* be asleep. Waiting for the PSD queue to drain makes sure that the released
|
||||
* frames have already passed the redirect stage.
|
||||
*/
|
||||
static void
|
||||
mt7603_mac_ps_check(struct mt7603_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dev->mphy.q_tx[MT_TXQ_PSD]->queued)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < MT7603_WTBL_STA; i++) {
|
||||
struct mt76_wcid *wcid = mt76_wcid_ptr(dev, i);
|
||||
struct mt7603_sta *msta;
|
||||
|
||||
if (!wcid || !wcid->sta)
|
||||
continue;
|
||||
|
||||
msta = container_of(wcid, struct mt7603_sta, wcid);
|
||||
if (msta->ps || !msta->ps_sleeping)
|
||||
continue;
|
||||
|
||||
mt7603_wtbl_restore_ps(dev, msta);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void mt7603_mac_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7603_dev *dev = container_of(work, struct mt7603_dev,
|
||||
|
|
@ -1830,6 +1890,7 @@ void mt7603_mac_work(struct work_struct *work)
|
|||
dev->mphy.mac_work_count++;
|
||||
mt76_update_survey(&dev->mphy);
|
||||
mt7603_edcca_check(dev);
|
||||
mt7603_mac_ps_check(dev);
|
||||
|
||||
for (i = 0, idx = 0; i < 2; i++) {
|
||||
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
|
|||
struct sk_buff_head list;
|
||||
|
||||
mt76_stop_tx_queues(&dev->mphy, sta, true);
|
||||
mt7603_wtbl_set_ps(dev, msta, ps);
|
||||
mt7603_wtbl_sta_ps(dev, msta, ps);
|
||||
if (ps)
|
||||
return;
|
||||
|
||||
|
|
@ -423,13 +423,33 @@ mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
|
|||
mt7603_ps_tx_list(dev, &list);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_ps_set_more_data(struct sk_buff *skb)
|
||||
static struct ieee80211_hdr *
|
||||
mt7603_ps_skb_hdr(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
return (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE];
|
||||
}
|
||||
|
||||
hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE];
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
/*
|
||||
* Buffered frames can be recycled into the PS queue by mt7603_filter_tx(), so
|
||||
* both bits have to be assigned, not just set.
|
||||
*/
|
||||
static void
|
||||
mt7603_ps_set_flags(struct sk_buff *skb, bool more_data, bool eosp)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = mt7603_ps_skb_hdr(skb);
|
||||
|
||||
if (more_data)
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
else
|
||||
hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
return;
|
||||
|
||||
if (eosp)
|
||||
*ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_EOSP;
|
||||
else
|
||||
*ieee80211_get_qos_ctl(hdr) &= ~IEEE80211_QOS_CTL_EOSP;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -442,7 +462,12 @@ mt7603_release_buffered_frames(struct ieee80211_hw *hw,
|
|||
struct mt7603_dev *dev = hw->priv;
|
||||
struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
|
||||
struct sk_buff_head list;
|
||||
struct sk_buff *skb, *tmp;
|
||||
struct sk_buff *skb, *tmp, *last;
|
||||
bool eosp_null, uapsd;
|
||||
unsigned long drained;
|
||||
u16 pending = 0;
|
||||
u8 last_tid;
|
||||
int i;
|
||||
|
||||
__skb_queue_head_init(&list);
|
||||
|
||||
|
|
@ -458,20 +483,58 @@ mt7603_release_buffered_frames(struct ieee80211_hw *hw,
|
|||
|
||||
skb_set_queue_mapping(skb, MT_TXQ_PSD);
|
||||
__skb_unlink(skb, &msta->psq);
|
||||
mt7603_ps_set_more_data(skb);
|
||||
__skb_queue_tail(&list, skb);
|
||||
nframes--;
|
||||
}
|
||||
|
||||
skb_queue_walk(&msta->psq, skb)
|
||||
pending |= BIT(skb->priority);
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
|
||||
if (!skb_queue_empty(&list))
|
||||
ieee80211_sta_eosp(sta);
|
||||
/*
|
||||
* Without this, mac80211 keeps the TIM bit set for the station and
|
||||
* keeps routing every service period to the driver, even though there
|
||||
* is nothing left to release.
|
||||
*/
|
||||
drained = tids & ~pending;
|
||||
for_each_set_bit(i, &drained, IEEE80211_NUM_TIDS)
|
||||
ieee80211_sta_set_buffered(sta, i, false);
|
||||
|
||||
last = skb_peek_tail(&list);
|
||||
if (!last) {
|
||||
mt76_release_buffered_frames(hw, sta, tids, nframes, reason,
|
||||
more_data);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* End the service period here instead of passing the remaining frame
|
||||
* budget on to mt76_release_buffered_frames(), which would signal the
|
||||
* end of the same service period a second time.
|
||||
*/
|
||||
uapsd = reason == IEEE80211_FRAME_RELEASE_UAPSD;
|
||||
more_data |= !!(pending & tids);
|
||||
|
||||
skb_queue_walk(&list, skb)
|
||||
mt7603_ps_set_flags(skb, skb != last || more_data,
|
||||
skb == last && uapsd);
|
||||
|
||||
/*
|
||||
* EOSP lives in the QoS control field, so a bufferable MMPDU cannot
|
||||
* terminate a U-APSD service period on its own. In that case mac80211
|
||||
* has to append a QoS-Null frame, which ends the SP through its tx
|
||||
* status.
|
||||
*/
|
||||
eosp_null = uapsd &&
|
||||
!ieee80211_is_data_qos(mt7603_ps_skb_hdr(last)->frame_control);
|
||||
last_tid = __fls(tids);
|
||||
|
||||
mt7603_ps_tx_list(dev, &list);
|
||||
|
||||
if (nframes)
|
||||
mt76_release_buffered_frames(hw, sta, tids, nframes, reason,
|
||||
more_data);
|
||||
if (eosp_null)
|
||||
ieee80211_send_eosp_nullfunc(sta, last_tid);
|
||||
else
|
||||
ieee80211_sta_eosp(sta);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ struct mt7603_sta {
|
|||
u8 smps;
|
||||
|
||||
u8 ps;
|
||||
u8 ps_sleeping;
|
||||
};
|
||||
|
||||
struct mt7603_vif {
|
||||
|
|
@ -229,6 +230,9 @@ int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid,
|
|||
struct ieee80211_key_conf *key);
|
||||
void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled);
|
||||
void mt7603_wtbl_sta_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool ps);
|
||||
void mt7603_wtbl_restore_ps(struct mt7603_dev *dev, struct mt7603_sta *sta);
|
||||
void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled);
|
||||
void mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort);
|
||||
|
|
|
|||
|
|
@ -1239,11 +1239,12 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
|
|||
cancel_delayed_work_sync(&dev->pm.ps_work);
|
||||
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
|
||||
|
||||
cancel_delayed_work_sync(&phy->scan_work);
|
||||
cancel_delayed_work_sync(&phy->mt76->mac_work);
|
||||
|
||||
mt7615_mutex_acquire(dev);
|
||||
|
||||
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
cancel_delayed_work_sync(&phy->scan_work);
|
||||
cancel_delayed_work_sync(&phy->mt76->mac_work);
|
||||
|
||||
set_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
|
||||
ieee80211_iterate_active_interfaces(hw,
|
||||
|
|
|
|||
|
|
@ -68,10 +68,11 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
int pid, id;
|
||||
u8 *txwi = (u8 *)txwi_ptr;
|
||||
struct mt76_txwi_cache *t;
|
||||
struct mt7615_sta *msta;
|
||||
struct mt7615_sta *msta = NULL;
|
||||
void *txp;
|
||||
|
||||
msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL;
|
||||
if (wcid && wcid->sta)
|
||||
msta = container_of(wcid, struct mt7615_sta, wcid);
|
||||
if (!wcid)
|
||||
wcid = &dev->mt76.global_wcid;
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user