From 081fb3a4be26d71743221ea4ad3326257b51dbc0 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 10:58:09 +0800 Subject: [PATCH 01/17] BACKPORT: FROMLIST: wifi: ath12k: refactor PCI window register access Currently offset of PCI window register address is defined as 0x310c which is same across existing chips. However QCC2072 has a different offset 0x3278. In order to make the window selection logic work for QCC2072 as well, change to initialize this parameter per device at the probe time. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-1-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/pci.c | 16 +++++++++++++--- drivers/net/wireless/ath/ath12k/pci.h | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index c729d5526c753..21a3d8e254576 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -175,8 +175,8 @@ static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset) if (window != ab_pci->register_window) { iowrite32(WINDOW_ENABLE_BIT | window, - ab->mem + WINDOW_REG_ADDRESS); - ioread32(ab->mem + WINDOW_REG_ADDRESS); + ab->mem + ab_pci->window_reg_addr); + ioread32(ab->mem + ab_pci->window_reg_addr); ab_pci->register_window = window; } } @@ -193,7 +193,7 @@ static void ath12k_pci_select_static_window(struct ath12k_pci *ab_pci) ab_pci->register_window = window; spin_unlock_bh(&ab_pci->window_lock); - iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); + iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + ab_pci->window_reg_addr); } static u32 ath12k_pci_get_window_start(struct ath12k_base *ab, @@ -1593,6 +1593,11 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab->static_window_map = true; ab_pci->pci_ops = &ath12k_pci_ops_qcn9274; ab->hal_rx_ops = &hal_rx_qcn9274_ops; + /* + * init window reg addr before reading hardware version + * as it will be used there + */ + ab_pci->window_reg_addr = WINDOW_REG_ADDRESS; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); ab->target_mem_mode = ath12k_core_get_memory_mode(ab); @@ -1617,6 +1622,11 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab->static_window_map = false; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; ab->hal_rx_ops = &hal_rx_wcn7850_ops; + /* + * init window reg addr before reading hardware version + * as it will be used there + */ + ab_pci->window_reg_addr = WINDOW_REG_ADDRESS; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index d1ec8aad7f6c3..541fba4373348 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -119,6 +119,8 @@ struct ath12k_pci { const struct ath12k_pci_ops *pci_ops; u32 qmi_instance; u64 dma_mask; + + u32 window_reg_addr; }; static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab) From 67d64f1cb3eb83d91f1697c5b91de57ae20b3c9c Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 11:04:30 +0800 Subject: [PATCH 02/17] BACKPORT: FROMLIST: wifi: ath12k: refactor REO CMD ring handling The entry of REO CMD ring of existing chips has a 64 bit TLV header, hence below functions take a 64 bit TLV assumption by default reo_init_cmd_ring reo_cmd_encode_hdr However this is not the case for QCC2072 of which the TLV is 32 bit, meaning above functions don't work for it. Rename/refactor above functions to prepare for QCC2072 support: Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-2-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/hal.c | 44 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 3 ++ drivers/net/wireless/ath/ath12k/hal_rx.c | 44 +++++++++++------------- 3 files changed, 67 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 6406fcf5d69fd..9a76e7d1ade50 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1030,6 +1030,26 @@ static u32 ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } +static void ath12k_hal_qcn9274_reo_init_cmd_ring(void *entry, int cmd_num) +{ + struct hal_reo_get_queue_stats *desc; + struct hal_tlv_64_hdr *tlv = entry; + + desc = (struct hal_reo_get_queue_stats *)tlv->value; + desc->cmd.info0 = le32_encode_bits(cmd_num, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); +} + +static void *ath12k_hal_qcn9274_reo_cmd_encode_hdr(void *reo_desc, + u64 tag, u64 len) +{ + struct hal_tlv_64_hdr *tlv = reo_desc; + + tlv->tl = le64_encode_bits(tag, HAL_TLV_HDR_TAG) | + le64_encode_bits(len, HAL_TLV_HDR_LEN); + + return tlv->value; +} + static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) { return sizeof(struct hal_rx_desc_qcn9274_compact); @@ -1089,6 +1109,8 @@ const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { const struct hal_ops hal_qcn9274_ops = { .create_srng_config = ath12k_hal_srng_create_config_qcn9274, .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, + .reo_init_cmd_ring = ath12k_hal_qcn9274_reo_init_cmd_ring, + .reo_cmd_encode_hdr = ath12k_hal_qcn9274_reo_cmd_encode_hdr, .rxdma_ring_wmask_rx_mpdu_start = ath12k_hal_qcn9274_rx_mpdu_start_wmask_get, .rxdma_ring_wmask_rx_msdu_end = ath12k_hal_qcn9274_rx_msdu_end_wmask_get, .get_hal_rx_compact_ops = ath12k_hal_qcn9274_get_hal_rx_compact_ops, @@ -1512,6 +1534,26 @@ static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) return 0; } +static void ath12k_hal_wcn7850_reo_init_cmd_ring(void *entry, int cmd_num) +{ + struct hal_reo_get_queue_stats *desc; + struct hal_tlv_64_hdr *tlv = entry; + + desc = (struct hal_reo_get_queue_stats *)tlv->value; + desc->cmd.info0 = le32_encode_bits(cmd_num, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); +} + +static void *ath12k_hal_wcn7850_reo_cmd_encode_hdr(void *reo_desc, + u64 tag, u64 len) +{ + struct hal_tlv_64_hdr *tlv = reo_desc; + + tlv->tl = le64_encode_bits(tag, HAL_TLV_HDR_TAG) | + le64_encode_bits(len, HAL_TLV_HDR_LEN); + + return tlv->value; +} + const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, @@ -1556,6 +1598,8 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { const struct hal_ops hal_wcn7850_ops = { .create_srng_config = ath12k_hal_srng_create_config_wcn7850, .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, + .reo_init_cmd_ring = ath12k_hal_wcn7850_reo_init_cmd_ring, + .reo_cmd_encode_hdr = ath12k_hal_wcn7850_reo_cmd_encode_hdr, .rxdma_ring_wmask_rx_mpdu_start = NULL, .rxdma_ring_wmask_rx_msdu_end = NULL, .get_hal_rx_compact_ops = NULL, diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index efe00e1679986..de423004a9a5a 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1106,6 +1106,9 @@ struct hal_ops { u16 (*rxdma_ring_wmask_rx_mpdu_start)(void); u32 (*rxdma_ring_wmask_rx_msdu_end)(void); const struct hal_rx_ops *(*get_hal_rx_compact_ops)(void); + void (*reo_init_cmd_ring)(void *entry, int cmd_num); + void *(*reo_cmd_encode_hdr)(void *reo_desc, + u64 tag, u64 len); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 669096278fdd4..6b384144ba97d 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -21,15 +21,15 @@ static void ath12k_hal_reo_set_desc_hdr(struct hal_desc_header *hdr, hdr->info0 |= le32_encode_bits(magic, HAL_DESC_HDR_INFO0_DBG_RESERVED); } -static int ath12k_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv, +static int ath12k_hal_reo_cmd_queue_stats(struct ath12k_base *ab, + struct hal_tlv_64_hdr *tlv, struct ath12k_hal_reo_cmd *cmd) { struct hal_reo_get_queue_stats *desc; - tlv->tl = le64_encode_bits(HAL_REO_GET_QUEUE_STATS, HAL_TLV_HDR_TAG) | - le64_encode_bits(sizeof(*desc), HAL_TLV_HDR_LEN); - - desc = (struct hal_reo_get_queue_stats *)tlv->value; + desc = ab->hw_params->hal_ops->reo_cmd_encode_hdr(tlv, + HAL_REO_GET_QUEUE_STATS, + sizeof(*desc)); memset_startat(desc, 0, queue_addr_lo); desc->cmd.info0 &= ~cpu_to_le32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED); @@ -45,10 +45,11 @@ static int ath12k_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv, return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); } -static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, +static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_base *ab, struct hal_tlv_64_hdr *tlv, struct ath12k_hal_reo_cmd *cmd) { + struct ath12k_hal *hal = &ab->hal; struct hal_reo_flush_cache *desc; u8 avail_slot = ffz(hal->avail_blk_resource); @@ -59,10 +60,9 @@ static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, hal->current_blk_index = avail_slot; } - tlv->tl = le64_encode_bits(HAL_REO_FLUSH_CACHE, HAL_TLV_HDR_TAG) | - le64_encode_bits(sizeof(*desc), HAL_TLV_HDR_LEN); - - desc = (struct hal_reo_flush_cache *)tlv->value; + desc = ab->hw_params->hal_ops->reo_cmd_encode_hdr(tlv, + HAL_REO_FLUSH_CACHE, + sizeof(*desc)); memset_startat(desc, 0, cache_addr_lo); desc->cmd.info0 &= ~cpu_to_le32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED); @@ -95,15 +95,15 @@ static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); } -static int ath12k_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv, +static int ath12k_hal_reo_cmd_update_rx_queue(struct ath12k_base *ab, + struct hal_tlv_64_hdr *tlv, struct ath12k_hal_reo_cmd *cmd) { struct hal_reo_update_rx_queue *desc; - tlv->tl = le64_encode_bits(HAL_REO_UPDATE_RX_REO_QUEUE, HAL_TLV_HDR_TAG) | - le64_encode_bits(sizeof(*desc), HAL_TLV_HDR_LEN); - - desc = (struct hal_reo_update_rx_queue *)tlv->value; + desc = ab->hw_params->hal_ops->reo_cmd_encode_hdr(tlv, + HAL_REO_UPDATE_RX_REO_QUEUE, + sizeof(*desc)); memset_startat(desc, 0, queue_addr_lo); desc->cmd.info0 &= ~cpu_to_le32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED); @@ -238,13 +238,13 @@ int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng, switch (type) { case HAL_REO_CMD_GET_QUEUE_STATS: - ret = ath12k_hal_reo_cmd_queue_stats(reo_desc, cmd); + ret = ath12k_hal_reo_cmd_queue_stats(ab, reo_desc, cmd); break; case HAL_REO_CMD_FLUSH_CACHE: - ret = ath12k_hal_reo_cmd_flush_cache(&ab->hal, reo_desc, cmd); + ret = ath12k_hal_reo_cmd_flush_cache(ab, reo_desc, cmd); break; case HAL_REO_CMD_UPDATE_RX_QUEUE: - ret = ath12k_hal_reo_cmd_update_rx_queue(reo_desc, cmd); + ret = ath12k_hal_reo_cmd_update_rx_queue(ab, reo_desc, cmd); break; case HAL_REO_CMD_FLUSH_QUEUE: case HAL_REO_CMD_UNBLOCK_CACHE: @@ -878,8 +878,6 @@ void ath12k_hal_reo_init_cmd_ring(struct ath12k_base *ab, struct hal_srng *srng) { struct hal_srng_params params; - struct hal_tlv_64_hdr *tlv; - struct hal_reo_get_queue_stats *desc; int i, cmd_num = 1; int entry_size; u8 *entry; @@ -891,11 +889,9 @@ void ath12k_hal_reo_init_cmd_ring(struct ath12k_base *ab, entry = (u8 *)params.ring_base_vaddr; for (i = 0; i < params.num_entries; i++) { - tlv = (struct hal_tlv_64_hdr *)entry; - desc = (struct hal_reo_get_queue_stats *)tlv->value; - desc->cmd.info0 = le32_encode_bits(cmd_num++, - HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); + ab->hw_params->hal_ops->reo_init_cmd_ring(entry, cmd_num); entry += entry_size; + cmd_num++; } } From 4d465c83138905d3267d119098275aae95fc10f8 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 5 Dec 2025 14:07:03 +0800 Subject: [PATCH 03/17] BACKPORT: FROMLIST: wifi: ath12k: refactor REO status ring handling The entry of REO status ring of existing chips has a 64 bit TLV header, however this is not the case for QCC2072 of which the TLV is 32 bit. Refactor above functions to prepare for QCC2072 support, this is done by removing TLV length assumption and offloading TLV decoding work to a newly added callback _reo_status_dec_tlv_hdr. This way each chip can register its own handler hence can do the work accordingly. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-3-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/dp_rx.c | 3 ++- drivers/net/wireless/ath/ath12k/hal.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 5e5c14a70316d..c8d9515cba866 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -4359,6 +4359,7 @@ void ath12k_dp_rx_process_reo_status(struct ath12k_base *ab) bool found = false; u16 tag; struct hal_reo_status reo_status; + void *desc; srng = &ab->hal.srng_list[dp->reo_status_ring.ring_id]; @@ -4369,7 +4370,7 @@ void ath12k_dp_rx_process_reo_status(struct ath12k_base *ab) ath12k_hal_srng_access_begin(ab, srng); while ((hdr = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { - tag = le64_get_bits(hdr->tl, HAL_SRNG_TLV_HDR_TAG); + tag = ab->hw_params->hal_ops->reo_status_decode_hdr(hdr, &desc); switch (tag) { case HAL_REO_GET_QUEUE_STATS_STATUS: diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 9a76e7d1ade50..b3f446b570c4f 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1050,6 +1050,17 @@ static void *ath12k_hal_qcn9274_reo_cmd_encode_hdr(void *reo_desc, return tlv->value; } +static u16 ath12k_hal_qcn9274_reo_status_decode_hdr(void *reo_desc, void **desc) +{ + struct hal_tlv_64_hdr *tlv = reo_desc; + u16 tag; + + tag = le64_get_bits(tlv->tl, HAL_SRNG_TLV_HDR_TAG); + *desc = tlv->value; + + return tag; +} + static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) { return sizeof(struct hal_rx_desc_qcn9274_compact); @@ -1111,6 +1122,7 @@ const struct hal_ops hal_qcn9274_ops = { .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, .reo_init_cmd_ring = ath12k_hal_qcn9274_reo_init_cmd_ring, .reo_cmd_encode_hdr = ath12k_hal_qcn9274_reo_cmd_encode_hdr, + .reo_status_decode_hdr = ath12k_hal_qcn9274_reo_status_decode_hdr, .rxdma_ring_wmask_rx_mpdu_start = ath12k_hal_qcn9274_rx_mpdu_start_wmask_get, .rxdma_ring_wmask_rx_msdu_end = ath12k_hal_qcn9274_rx_msdu_end_wmask_get, .get_hal_rx_compact_ops = ath12k_hal_qcn9274_get_hal_rx_compact_ops, @@ -1554,6 +1566,17 @@ static void *ath12k_hal_wcn7850_reo_cmd_encode_hdr(void *reo_desc, return tlv->value; } +static u16 ath12k_hal_wcn7850_reo_status_decode_hdr(void *reo_desc, void **desc) +{ + struct hal_tlv_64_hdr *tlv = reo_desc; + u16 tag; + + tag = le64_get_bits(tlv->tl, HAL_SRNG_TLV_HDR_TAG); + *desc = tlv->value; + + return tag; +} + const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, @@ -1600,6 +1623,7 @@ const struct hal_ops hal_wcn7850_ops = { .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, .reo_init_cmd_ring = ath12k_hal_wcn7850_reo_init_cmd_ring, .reo_cmd_encode_hdr = ath12k_hal_wcn7850_reo_cmd_encode_hdr, + .reo_status_decode_hdr = ath12k_hal_wcn7850_reo_status_decode_hdr, .rxdma_ring_wmask_rx_mpdu_start = NULL, .rxdma_ring_wmask_rx_msdu_end = NULL, .get_hal_rx_compact_ops = NULL, diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index de423004a9a5a..d84f71280d0ed 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1109,6 +1109,7 @@ struct hal_ops { void (*reo_init_cmd_ring)(void *entry, int cmd_num); void *(*reo_cmd_encode_hdr)(void *reo_desc, u64 tag, u64 len); + u16 (*reo_status_decode_hdr)(void *reo_desc, void **desc); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; From 4eae5bf25b9dfc250fa2584ed194807c5658b1b0 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 12 Nov 2025 09:28:21 +0800 Subject: [PATCH 04/17] BACKPORT: FROMLIST: wifi: ath12k: fix preferred hardware mode calculation For single pdev device like WCN7850/QCC2072, preferred_hw_mode is initialized to WMI_HOST_HW_MODE_SINGLE. Later when firmware sends supported modes to host, each mode is compared with the initial one and if the priority of the new mode is higher, update the parameter and store mode capability. For WCN7850, this does not result in issue, as one of the supported mode indeed has a higher priority. However the only available mode of QCC2072 at this stage is WMI_HOST_HW_MODE_SINGLE, which fails the comparison, hence mode capability is not stored. Subsequently driver initialization fails. Fix it by accepting a mode with the same priority. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-4-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ff6b3d4ea8208..f14c7e9146047 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4487,7 +4487,7 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, pref = soc->wmi_ab.preferred_hw_mode; - if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) { + if (ath12k_hw_mode_pri_map[mode] <= ath12k_hw_mode_pri_map[pref]) { svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps; soc->wmi_ab.preferred_hw_mode = mode; } From 2f4f350002b8cd9d1a45900a4b602573a766f71d Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 12 Nov 2025 09:41:22 +0800 Subject: [PATCH 05/17] BACKPORT: FROMLIST: wifi: ath12k: refactor 320 MHz bandwidth support parsing For single pdev device, 320 MHz bandwidth support is reported only in capability of WMI_HOST_HW_MODE_SINGLE mode, hence commit d4e244c85e45 ("wifi: ath12k: enable 320 MHz bandwidth for 6 GHz band in EHT PHY capability for WCN7850") relaxed the condition check in ath12k_wmi_tlv_mac_phy_caps_ext() to allow SINGLE mode getting parsed in ath12k_wmi_tlv_mac_phy_caps_ext_parse(). Since SINGLE mode is not assumed to be preferred, the function returns unconditionally after parsing 320 MHz support. This works for WCN7850 because it prefers another mode indeed, while it breaks QCC2072 since it prefers SINGLE mode. Due to the unconditional return, the subsequent EHT parsing is skipped. Consequently EHT related features are disabled. Refactor it by moving 320 MHz parsing to ath12k_wmi_tlv_mac_phy_caps_ext(), before the mode checking. This makes the code more straightforward, and work for both WCN7850 and QCC2072. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-5-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/wmi.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index f14c7e9146047..8ab0c2813d727 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4956,19 +4956,10 @@ ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, const struct ath12k_wmi_caps_ext_params *caps, struct ath12k_pdev *pdev) { - struct ath12k_band_cap *cap_band; - u32 bands, support_320mhz; + u32 bands; int i; if (ab->hw_params->single_pdev_only) { - if (caps->hw_mode_id == WMI_HOST_HW_MODE_SINGLE) { - support_320mhz = le32_to_cpu(caps->eht_cap_phy_info_5ghz[0]) & - IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; - cap_band = &pdev->cap.band[NL80211_BAND_6GHZ]; - cap_band->eht_cap_phy_info[0] |= support_320mhz; - return 0; - } - for (i = 0; i < ab->fw_pdev_count; i++) { struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; @@ -5021,14 +5012,22 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, void *data) { const struct ath12k_wmi_caps_ext_params *caps = ptr; + struct ath12k_band_cap *cap_band; + u32 support_320mhz; int i = 0, ret; if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT) return -EPROTO; if (ab->hw_params->single_pdev_only) { - if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id) && - caps->hw_mode_id != WMI_HOST_HW_MODE_SINGLE) + if (caps->hw_mode_id == WMI_HOST_HW_MODE_SINGLE) { + support_320mhz = le32_to_cpu(caps->eht_cap_phy_info_5ghz[0]) & + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + cap_band = &ab->pdevs[0].cap.band[NL80211_BAND_6GHZ]; + cap_band->eht_cap_phy_info[0] |= support_320mhz; + } + + if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id)) return 0; } else { for (i = 0; i < ab->num_radios; i++) { From bd699cefdd9f0b8eb4f9ce306125529fc919fafc Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:32:39 +0800 Subject: [PATCH 06/17] BACKPORT: FROMLIST: wifi: ath12k: fix mac phy capability parsing Currently ath12k_pull_mac_phy_cap_svc_ready_ext() assumes only one band supported in each phy, hence it skips 5 GHz band if 2 GHz band support is detected. This does not work for device which gets only one phy but has both bands supported, such as QCC2072. Change to check each band individually to fix this issue. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-6-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/wmi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 8ab0c2813d727..cb7c22ddbe752 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -493,6 +493,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, struct ath12k_band_cap *cap_band; struct ath12k_pdev_cap *pdev_cap = &pdev->cap; struct ath12k_fw_pdev *fw_pdev; + u32 supported_bands; u32 phy_map; u32 hw_idx, phy_idx = 0; int i; @@ -516,14 +517,19 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, return -EINVAL; mac_caps = wmi_mac_phy_caps + phy_idx; + supported_bands = le32_to_cpu(mac_caps->supported_bands); + + if (!(supported_bands & WMI_HOST_WLAN_2GHZ_CAP) && + !(supported_bands & WMI_HOST_WLAN_5GHZ_CAP)) + return -EINVAL; pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); pdev->hw_link_id = ath12k_wmi_mac_phy_get_hw_link_id(mac_caps); - pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); + pdev_cap->supported_bands |= supported_bands; pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; - fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); + fw_pdev->supported_bands = supported_bands; fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); ab->fw_pdev_count++; @@ -532,10 +538,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, * band to band for a single radio, need to see how this should be * handled. */ - if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2GHZ_CAP) { + if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) { pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_2g); pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_2g); - } else if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5GHZ_CAP) { + } + + if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { pdev_cap->vht_cap = le32_to_cpu(mac_caps->vht_cap_info_5g); pdev_cap->vht_mcs = le32_to_cpu(mac_caps->vht_supp_mcs_5g); pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); @@ -545,8 +553,6 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, WMI_NSS_RATIO_EN_DIS_GET(mac_caps->nss_ratio); pdev_cap->nss_ratio_info = WMI_NSS_RATIO_INFO_GET(mac_caps->nss_ratio); - } else { - return -EINVAL; } /* tx/rx chainmask reported from fw depends on the actual hw chains used, @@ -562,7 +568,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, pdev_cap->rx_chain_mask_shift = find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32); - if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2GHZ_CAP) { + if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) { cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; cap_band->phy_id = le32_to_cpu(mac_caps->phy_id); cap_band->max_bw_supported = le32_to_cpu(mac_caps->max_bw_supported_2g); @@ -582,7 +588,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, le32_to_cpu(mac_caps->he_ppet2g.ppet16_ppet8_ru3_ru0[i]); } - if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5GHZ_CAP) { + if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; cap_band->phy_id = le32_to_cpu(mac_caps->phy_id); cap_band->max_bw_supported = From 6e2eb1865c427ab8b13b29d0160ff1ed289821c9 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:34:39 +0800 Subject: [PATCH 07/17] BACKPORT: FROMLIST: wifi: ath12k: add hardware registers for QCC2072 Add hardware registers and populate hw_regs field in ath12k_wifi7_hw_ver_map for QCC2072. Note for some registers not defined and not used by QCC2072, a magic value is assigned. Also populate other fields to be the same with WCN7850. Among them, however, QCC2072 requires different HAL ops and descriptor size, both will be updated in upcoming patches. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-7-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 87 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hw.h | 2 + 3 files changed, 90 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3d1956966a485..c21832454d689 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -155,6 +155,7 @@ enum ath12k_hw_rev { ATH12K_HW_QCN9274_HW20, ATH12K_HW_WCN7850_HW20, ATH12K_HW_IPQ5332_HW10, + ATH12K_HW_QCC2072_HW10, }; enum ath12k_firmware_mode { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 6791ae1d64e50..6ee2e2220cc49 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1278,6 +1278,93 @@ static const struct ath12k_hw_regs wcn7850_regs = { .gcc_gcc_pcie_hot_rst = 0x1e40304, }; +static const struct ath12k_hw_regs qcc2072_regs = { + /* SW2TCL(x) R0 ring configuration address */ + .hal_tcl1_ring_id = 0x00000920, + .hal_tcl1_ring_misc = 0x00000928, + .hal_tcl1_ring_tp_addr_lsb = 0x00000934, + .hal_tcl1_ring_tp_addr_msb = 0x00000938, + .hal_tcl1_ring_consumer_int_setup_ix0 = 0x00000948, + .hal_tcl1_ring_consumer_int_setup_ix1 = 0x0000094c, + .hal_tcl1_ring_msi1_base_lsb = 0x00000960, + .hal_tcl1_ring_msi1_base_msb = 0x00000964, + .hal_tcl1_ring_msi1_data = 0x00000968, + .hal_tcl_ring_base_lsb = 0x00000b70, + .hal_tcl1_ring_base_lsb = 0x00000918, + .hal_tcl1_ring_base_msb = 0x0000091c, + .hal_tcl2_ring_base_lsb = 0x00000990, + + /* TCL STATUS ring address */ + .hal_tcl_status_ring_base_lsb = 0x00000d50, + + .hal_wbm_idle_ring_base_lsb = 0x00000d3c, + .hal_wbm_idle_ring_misc_addr = 0x00000d4c, + .hal_wbm_r0_idle_list_cntl_addr = 0x00000240, + .hal_wbm_r0_idle_list_size_addr = 0x00000244, + .hal_wbm_scattered_ring_base_lsb = 0x00000250, + .hal_wbm_scattered_ring_base_msb = 0x00000254, + .hal_wbm_scattered_desc_head_info_ix0 = 0x00000260, + .hal_wbm_scattered_desc_head_info_ix1 = 0x00000264, + .hal_wbm_scattered_desc_tail_info_ix0 = 0x00000270, + .hal_wbm_scattered_desc_tail_info_ix1 = 0x00000274, + .hal_wbm_scattered_desc_ptr_hp_addr = 0x00000027c, + + .hal_wbm_sw_release_ring_base_lsb = 0x0000037c, + .hal_wbm_sw1_release_ring_base_lsb = ATH12K_HW_REG_UNDEFINED, + .hal_wbm0_release_ring_base_lsb = 0x00000e08, + .hal_wbm1_release_ring_base_lsb = 0x00000e80, + + /* PCIe base address */ + .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac, + .pcie_pcs_osc_dtct_config_base = 0x01e0d45c, + + /* PPE release ring address */ + .hal_ppe_rel_ring_base = 0x0000046c, + + /* REO DEST ring address */ + .hal_reo2_ring_base = 0x00000578, + .hal_reo1_misc_ctrl_addr = 0x00000ba0, + .hal_reo1_sw_cookie_cfg0 = 0x0000006c, + .hal_reo1_sw_cookie_cfg1 = 0x00000070, + .hal_reo1_qdesc_lut_base0 = ATH12K_HW_REG_UNDEFINED, + .hal_reo1_qdesc_lut_base1 = ATH12K_HW_REG_UNDEFINED, + .hal_reo1_ring_base_lsb = 0x00000500, + .hal_reo1_ring_base_msb = 0x00000504, + .hal_reo1_ring_id = 0x00000508, + .hal_reo1_ring_misc = 0x00000510, + .hal_reo1_ring_hp_addr_lsb = 0x00000514, + .hal_reo1_ring_hp_addr_msb = 0x00000518, + .hal_reo1_ring_producer_int_setup = 0x00000524, + .hal_reo1_ring_msi1_base_lsb = 0x00000548, + .hal_reo1_ring_msi1_base_msb = 0x0000054c, + .hal_reo1_ring_msi1_data = 0x00000550, + .hal_reo1_aging_thres_ix0 = 0x00000b2c, + .hal_reo1_aging_thres_ix1 = 0x00000b30, + .hal_reo1_aging_thres_ix2 = 0x00000b34, + .hal_reo1_aging_thres_ix3 = 0x00000b38, + + /* REO Exception ring address */ + .hal_reo2_sw0_ring_base = 0x000008c0, + + /* REO Reinject ring address */ + .hal_sw2reo_ring_base = 0x00000320, + .hal_sw2reo1_ring_base = 0x00000398, + + /* REO cmd ring address */ + .hal_reo_cmd_ring_base = 0x000002a8, + + /* REO status ring address */ + .hal_reo_status_ring_base = 0x00000aa0, + + /* CE base address */ + .hal_umac_ce0_src_reg_base = 0x01b80000, + .hal_umac_ce0_dest_reg_base = 0x01b81000, + .hal_umac_ce1_src_reg_base = 0x01b82000, + .hal_umac_ce1_dest_reg_base = 0x01b83000, + + .gcc_gcc_pcie_hot_rst = 0x1e65304, +}; + static const struct ath12k_hw_hal_params ath12k_hw_hal_params_qcn9274 = { .rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM, .wbm2sw_cc_enable = HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW0_EN | diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 8ce11c3e6d5c2..c83c89703a64e 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -285,6 +285,8 @@ enum ath12k_bd_ie_type { ATH12K_BD_IE_REGDB = 1, }; +#define ATH12K_HW_REG_UNDEFINED 0xdeadbeaf + struct ath12k_hw_regs { u32 hal_tcl1_ring_id; u32 hal_tcl1_ring_misc; From c3a3928edb370baa7ce5f804895531e96cf4c564 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:36:23 +0800 Subject: [PATCH 08/17] BACKPORT: FROMLIST: wifi: ath12k: add hardware parameters for QCC2072 Add hardware parameters for QCC2072, these parameters are directly taken from WCN7850, with exceptions to hardware name, revision, firmware directory, iova_mask and RFKILL parameter set. Compared to WCN7850, QCC2072 doesn't require aligned IOVA when transmitting packets, hence iova_mask is set to zero. Besides, WCN7850 has a dedicated GPIO for RFKILL purpose, however QCC2072 has it coupled with WLAN_EN pin. For QCC2072, host is not allowed to send any RFKILL configuration info to firmware, or firmware crashes. Hence those parameters are all cleared to skip configuring command. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-8-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/hw.c | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 6ee2e2220cc49..96d7f134cdf0e 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1740,6 +1740,96 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .dp_primary_link_only = true, }, + { + .name = "qcc2072 hw1.0", + .hw_rev = ATH12K_HW_QCC2072_HW10, + + .fw = { + .dir = "QCC2072/hw1.0", + .board_size = 256 * 1024, + .cal_offset = 256 * 1024, + .m3_loader = ath12k_m3_fw_loader_driver, + }, + + .max_radios = 1, + .single_pdev_only = true, + .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850, + .internal_sleep_clock = true, + + .hw_ops = &wcn7850_ops, + .ring_mask = &ath12k_hw_ring_mask_wcn7850, + .regs = &qcc2072_regs, + + .host_ce_config = ath12k_host_ce_config_wcn7850, + .ce_count = 9, + .target_ce_config = ath12k_target_ce_config_wlan_wcn7850, + .target_ce_count = 9, + .svc_to_ce_map = ath12k_target_service_to_ce_map_wlan_wcn7850, + .svc_to_ce_map_len = 14, + + .hal_params = &ath12k_hw_hal_params_wcn7850, + + .rxdma1_enable = false, + .num_rxdma_per_pdev = 2, + .num_rxdma_dst_ring = 1, + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), + .supports_monitor = false, + + .idle_ps = true, + .download_calib = false, + .supports_suspend = true, + .tcl_ring_retry = false, + .reoq_lut_support = false, + .supports_shadow_regs = true, + + .num_tcl_banks = 7, + .max_tx_ring = 3, + + .mhi_config = &ath12k_mhi_config_wcn7850, + + .wmi_init = ath12k_wmi_init_wcn7850, + + .hal_ops = &hal_wcn7850_ops, + + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) | + BIT(CNSS_PCIE_PERST_NO_PULL_V01), + + .rfkill_pin = 0, + .rfkill_cfg = 0, + .rfkill_on_level = 0, + + .rddm_size = 0x780000, + + .def_num_link = 2, + .max_mlo_peer = 32, + + .otp_board_id_register = 0, + + .supports_sta_ps = true, + + .acpi_guid = &wcn7850_uuid, + .supports_dynamic_smps_6ghz = false, + + .iova_mask = 0, + + .supports_aspm = true, + + .ce_ie_addr = NULL, + .ce_remap = NULL, + .bdf_addr_offset = 0, + + .current_cc_support = true, + + .dp_primary_link_only = true, + }, + }; int ath12k_hw_init(struct ath12k_base *ab) From 33e6df2351353c219af5682e8a045d784a830c4e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:46:04 +0800 Subject: [PATCH 09/17] BACKPORT: FROMLIST: wifi: ath12k: advertise standard ELF image format for QCC2072 Firmware (amss.bin) of QCC2072 is a standard ELF image, however those of other chips are not. MHI subsystem supports both format, but by default takes it as non-standard. Flag this to MHI subsystem to avoid firmware loading failure. Also refine hardware parameter dereferencing by defining a new local pointer. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-9-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/hw.c | 5 +++++ drivers/net/wireless/ath/ath12k/hw.h | 1 + drivers/net/wireless/ath/ath12k/mhi.c | 10 ++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 96d7f134cdf0e..f2eaef1ec0f7a 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1411,6 +1411,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .std_elf_img = false, }, .max_radios = 1, .single_pdev_only = false, @@ -1497,6 +1498,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 256 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .std_elf_img = false, }, .max_radios = 1, @@ -1585,6 +1587,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .std_elf_img = false, }, .max_radios = 2, .single_pdev_only = false, @@ -1670,6 +1673,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_remoteproc, + .std_elf_img = false, }, .max_radios = 1, .single_pdev_only = false, @@ -1749,6 +1753,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 256 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .std_elf_img = true, }, .max_radios = 1, diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index c83c89703a64e..4eab0b5542215 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -147,6 +147,7 @@ struct ath12k_hw_params { size_t board_size; size_t cal_offset; enum ath12k_m3_fw_loaders m3_loader; + bool std_elf_img:1; } fw; u8 max_radios; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index 08f44baf182a5..53e31d36be7b3 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -317,6 +317,7 @@ static void ath12k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, int ath12k_mhi_register(struct ath12k_pci *ab_pci) { struct ath12k_base *ab = ab_pci->ab; + const struct ath12k_hw_params *hw_params = ab->hw_params; struct mhi_controller *mhi_ctrl; unsigned int board_id; int ret; @@ -331,11 +332,12 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) mhi_ctrl->cntrl_dev = ab->dev; mhi_ctrl->regs = ab->mem; mhi_ctrl->reg_len = ab->mem_len; - mhi_ctrl->rddm_size = ab->hw_params->rddm_size; + mhi_ctrl->rddm_size = hw_params->rddm_size; + mhi_ctrl->standard_elf_image = hw_params->fw.std_elf_img; - if (ab->hw_params->otp_board_id_register) { + if (hw_params->otp_board_id_register) { board_id = - ath12k_pci_read32(ab, ab->hw_params->otp_board_id_register); + ath12k_pci_read32(ab, hw_params->otp_board_id_register); board_id = u32_get_bits(board_id, OTP_BOARD_ID_MASK); if (!board_id || (board_id == OTP_INVALID_BOARD_ID)) { @@ -392,7 +394,7 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) mhi_ctrl->read_reg = ath12k_mhi_op_read_reg; mhi_ctrl->write_reg = ath12k_mhi_op_write_reg; - ret = mhi_register_controller(mhi_ctrl, ab->hw_params->mhi_config); + ret = mhi_register_controller(mhi_ctrl, hw_params->mhi_config); if (ret) { ath12k_err(ab, "failed to register to mhi bus, err = %d\n", ret); goto free_controller; From 2168e96be5e84fa453bbcc7abac4e98f6f03e9c9 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:47:45 +0800 Subject: [PATCH 10/17] BACKPORT: FROMLIST: wifi: ath12k: support LPASS_SHARED target memory type QCC2072 requires a new type of QMI target memory named LPASS_SHARED_V01, add support for it. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-10-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/qmi.c | 1 + drivers/net/wireless/ath/ath12k/qmi.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 36325e62aa242..cb504461ef90f 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2609,6 +2609,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) case M3_DUMP_REGION_TYPE: case PAGEABLE_MEM_REGION_TYPE: case CALDB_MEM_REGION_TYPE: + case LPASS_SHARED_V01_REGION_TYPE: ret = ath12k_qmi_alloc_chunk(ab, chunk); if (ret) goto err; diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 4767d9a2e309e..9c795f33dce66 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -175,6 +175,7 @@ enum ath12k_qmi_target_mem { CALDB_MEM_REGION_TYPE = 0x4, MLO_GLOBAL_MEM_REGION_TYPE = 0x8, PAGEABLE_MEM_REGION_TYPE = 0x9, + LPASS_SHARED_V01_REGION_TYPE = 0xb, }; enum qmi_wlanfw_host_build_type { From c7f7a3dfbc8089e03c6f4ca37a001546ad7b6d0e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 18 Dec 2025 19:31:54 +0800 Subject: [PATCH 11/17] BACKPORT: FROMLIST: wifi: ath12k: support downloading auxiliary ucode image for QCC2072 QCC2072 requires another firmware image named aux_ucode.bin, add support to download it. Add a new hardware parameter download_aux_ucode to make sure other chips are not affected. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-11-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/core.h | 2 + drivers/net/wireless/ath/ath12k/fw.c | 8 ++ drivers/net/wireless/ath/ath12k/fw.h | 1 + drivers/net/wireless/ath/ath12k/hw.c | 7 +- drivers/net/wireless/ath/ath12k/hw.h | 2 + drivers/net/wireless/ath/ath12k/qmi.c | 179 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/qmi.h | 15 +++ 7 files changed, 212 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index c21832454d689..9fa7b4d265d88 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1190,6 +1190,8 @@ struct ath12k_base { size_t amss_dualmac_len; const u8 *m3_data; size_t m3_len; + const u8 *aux_uc_data; + size_t aux_uc_len; DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); bool fw_features_valid; diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c index 5ac497f80cad8..2cf30d637c6ad 100644 --- a/drivers/net/wireless/ath/ath12k/fw.c +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -121,6 +121,14 @@ static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, ab->fw.m3_data = data; ab->fw.m3_len = ie_len; break; + case ATH12K_FW_IE_AUX_UC_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found aux_uc image ie (%zd B)\n", + ie_len); + + ab->fw.aux_uc_data = data; + ab->fw.aux_uc_len = ie_len; + break; case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE: ath12k_dbg(ab, ATH12K_DBG_BOOT, "found dualmac fw image ie (%zd B)\n", diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index 7afaefed5086f..c854d88d8f7bd 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -15,6 +15,7 @@ enum ath12k_fw_ie_type { ATH12K_FW_IE_AMSS_IMAGE = 2, ATH12K_FW_IE_M3_IMAGE = 3, ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4, + ATH12K_FW_IE_AUX_UC_IMAGE = 5, }; enum ath12k_fw_features { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index f2eaef1ec0f7a..7e5142fa9fcbb 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1412,6 +1412,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, .std_elf_img = false, + .download_aux_ucode = false, }, .max_radios = 1, .single_pdev_only = false, @@ -1499,6 +1500,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .cal_offset = 256 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, .std_elf_img = false, + .download_aux_ucode = false, }, .max_radios = 1, @@ -1588,6 +1590,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, .std_elf_img = false, + .download_aux_ucode = false, }, .max_radios = 2, .single_pdev_only = false, @@ -1754,6 +1757,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .cal_offset = 256 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, .std_elf_img = true, + .download_aux_ucode = true, }, .max_radios = 1, @@ -1804,7 +1808,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_ops = &hal_wcn7850_ops, .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) | - BIT(CNSS_PCIE_PERST_NO_PULL_V01), + BIT(CNSS_PCIE_PERST_NO_PULL_V01) | + BIT(CNSS_AUX_UC_SUPPORT_V01), .rfkill_pin = 0, .rfkill_cfg = 0, diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 4eab0b5542215..b1d2aebe59734 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -78,6 +78,7 @@ #define ATH12K_DEFAULT_CAL_FILE "caldata.bin" #define ATH12K_AMSS_FILE "amss.bin" #define ATH12K_M3_FILE "m3.bin" +#define ATH12K_AUX_UC_FILE "aux_ucode.bin" #define ATH12K_REGDB_FILE_NAME "regdb.bin" #define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128 @@ -148,6 +149,7 @@ struct ath12k_hw_params { size_t cal_offset; enum ath12k_m3_fw_loaders m3_loader; bool std_elf_img:1; + bool download_aux_ucode:1; } fw; u8 max_radios; diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index cb504461ef90f..51fe936cc56ba 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1623,6 +1623,47 @@ static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { }, }; +static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, size), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_aux_uc_info_resp_msg_v01, resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, @@ -3234,6 +3275,130 @@ int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) return ret; } +static void ath12k_qmi_aux_uc_free(struct ath12k_base *ab) +{ + struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem; + + if (!aux_uc_mem->vaddr) + return; + + dma_free_coherent(ab->dev, aux_uc_mem->total_size, + aux_uc_mem->vaddr, aux_uc_mem->paddr); + aux_uc_mem->vaddr = NULL; + aux_uc_mem->total_size = 0; + aux_uc_mem->size = 0; +} + +static int ath12k_qmi_aux_uc_load(struct ath12k_base *ab) +{ + struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem; + const struct firmware *fw = NULL; + const void *aux_uc_data; + char path[100]; + size_t aux_uc_len; + int ret; + + if (ab->fw.aux_uc_data && ab->fw.aux_uc_len > 0) { + /* firmware-N.bin had a aux_uc firmware file so use that */ + aux_uc_data = ab->fw.aux_uc_data; + aux_uc_len = ab->fw.aux_uc_len; + } else { + /* No aux_uc file in firmware-N.bin so try to request old + * separate aux_ucode.bin. + */ + fw = ath12k_core_firmware_request(ab, ATH12K_AUX_UC_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath12k_core_create_firmware_path(ab, ATH12K_AUX_UC_FILE, + path, sizeof(path)); + ath12k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } + + aux_uc_data = fw->data; + aux_uc_len = fw->size; + } + + /* In recovery/resume cases, AUX_UC buffer is not freed, try to reuse that */ + if (aux_uc_mem->vaddr) { + if (aux_uc_mem->total_size >= aux_uc_len) + goto copy; + + /* Old buffer is too small, free and reallocate */ + ath12k_qmi_aux_uc_free(ab); + } + + aux_uc_mem->vaddr = dma_alloc_coherent(ab->dev, aux_uc_len, + &aux_uc_mem->paddr, GFP_KERNEL); + if (!aux_uc_mem->vaddr) { + ret = -ENOMEM; + goto out; + } + + aux_uc_mem->total_size = aux_uc_len; + +copy: + memcpy(aux_uc_mem->vaddr, aux_uc_data, aux_uc_len); + aux_uc_mem->size = aux_uc_len; + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static noinline_for_stack +int ath12k_qmi_wlanfw_aux_uc_info_send(struct ath12k_base *ab) +{ + struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem; + struct qmi_wlanfw_aux_uc_info_req_msg_v01 req = {}; + struct qmi_wlanfw_aux_uc_info_resp_msg_v01 resp = {}; + struct qmi_txn txn; + int ret = 0; + + ret = ath12k_qmi_aux_uc_load(ab); + if (ret) { + ath12k_err(ab, "failed to load aux_uc firmware: %d", ret); + return ret; + } + + req.addr = aux_uc_mem->paddr; + req.size = aux_uc_mem->size; + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_aux_uc_info_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, + QMI_WLANFW_AUX_UC_INFO_REQ_V01, + QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN, + qmi_wlanfw_aux_uc_info_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath12k_warn(ab, "qmi failed to send AUX_UC information request, err = %d\n", + ret); + goto out; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) { + ath12k_warn(ab, "qmi failed AUX_UC information request %d\n", ret); + goto out; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath12k_warn(ab, "qmi AUX_UC info request failed, result: %d, err: %d\n", + resp.resp.result, resp.resp.error); + ret = -EINVAL; + goto out; + } +out: + return ret; +} + static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, u32 mode) { @@ -3582,6 +3747,7 @@ static noinline_for_stack int ath12k_qmi_event_mem_request(struct ath12k_qmi *qmi) { struct ath12k_base *ab = qmi->ab; + const struct ath12k_hw_params *hw_params = ab->hw_params; int ret; ret = ath12k_qmi_respond_fw_mem_request(ab); @@ -3598,6 +3764,7 @@ static noinline_for_stack int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi) { struct ath12k_base *ab = qmi->ab; + const struct ath12k_hw_params *hw_params = ab->hw_params; int ret; ret = ath12k_qmi_request_target_cap(ab); @@ -3618,7 +3785,7 @@ int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi) return ret; } - if (ab->hw_params->download_calib) { + if (hw_params->download_calib) { ret = ath12k_qmi_load_bdf_qmi(ab, ATH12K_QMI_BDF_TYPE_CALIBRATION); if (ret < 0) ath12k_warn(ab, "qmi failed to load calibrated data :%d\n", ret); @@ -3630,6 +3797,14 @@ int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi) return ret; } + if (hw_params->fw.download_aux_ucode) { + ret = ath12k_qmi_wlanfw_aux_uc_info_send(ab); + if (ret < 0) { + ath12k_warn(ab, "qmi failed to send aux_uc info req: %d\n", ret); + return ret; + } + } + return ret; } @@ -3903,6 +4078,7 @@ void ath12k_qmi_deinit_service(struct ath12k_base *ab) qmi_handle_release(&ab->qmi.handle); cancel_work_sync(&ab->qmi.event_work); destroy_workqueue(ab->qmi.event_wq); + ath12k_qmi_aux_uc_free(ab); ath12k_qmi_m3_free(ab); ath12k_qmi_free_target_mem_chunk(ab); ab->qmi.ab = NULL; @@ -3911,5 +4087,6 @@ void ath12k_qmi_deinit_service(struct ath12k_base *ab) void ath12k_qmi_free_resource(struct ath12k_base *ab) { ath12k_qmi_free_target_mem_chunk(ab); + ath12k_qmi_aux_uc_free(ab); ath12k_qmi_m3_free(ab); } diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 9c795f33dce66..1894c025a49f1 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -151,6 +151,7 @@ struct ath12k_qmi { u8 num_radios; struct target_info target; struct m3_mem_region m3_mem; + struct m3_mem_region aux_uc_mem; unsigned int service_ins_id; struct dev_mem_info dev_mem[ATH12K_QMI_WLFW_MAX_DEV_MEM_NUM_V01]; }; @@ -200,6 +201,7 @@ enum ath12k_qmi_cnss_feature { CNSS_FEATURE_MIN_ENUM_VAL_V01 = INT_MIN, CNSS_QDSS_CFG_MISS_V01 = 3, CNSS_PCIE_PERST_NO_PULL_V01 = 4, + CNSS_AUX_UC_SUPPORT_V01 = 6, CNSS_MAX_FEATURE_V01 = 64, CNSS_FEATURE_MAX_ENUM_VAL_V01 = INT_MAX, }; @@ -538,6 +540,19 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +#define QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +#define QMI_WLANFW_AUX_UC_INFO_RESP_MSG_V01_MAX_MSG_LEN 7 +#define QMI_WLANFW_AUX_UC_INFO_REQ_V01 0x005A + +struct qmi_wlanfw_aux_uc_info_req_msg_v01 { + u64 addr; + u32 size; +}; + +struct qmi_wlanfw_aux_uc_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + #define QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN 11 #define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN 7 #define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN 803 From 4a039011fe3e4fc90cbc35acb0ba569650a58b7f Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 12 Nov 2025 10:57:49 +0800 Subject: [PATCH 12/17] BACKPORT: FROMLIST: wifi: ath12k: add HAL descriptor and ops for QCC2072 QCC2072 has different HAL descriptors hence require different HAL handling, compared to other chips. Add support for this. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-12-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/hal.c | 505 +++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hal.h | 2 + drivers/net/wireless/ath/ath12k/hal_desc.h | 25 + drivers/net/wireless/ath/ath12k/hw.c | 2 +- drivers/net/wireless/ath/ath12k/rx_desc.h | 17 + 5 files changed, 550 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index b3f446b570c4f..0fecb5ff10ac4 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1629,6 +1629,511 @@ const struct hal_ops hal_wcn7850_ops = { .get_hal_rx_compact_ops = NULL, }; +static bool ath12k_hw_qcc2072_rx_desc_get_first_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_FIRST_MSDU); +} + +static bool ath12k_hw_qcc2072_rx_desc_get_last_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_LAST_MSDU); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc) +{ + return (u8)le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_L3_HDR_PADDING); +} + +static bool ath12k_hw_qcc2072_rx_desc_encrypt_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_ENCRYPT_INFO_VALID); +} + +static u32 ath12k_hw_qcc2072_rx_desc_get_encrypt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.mpdu_start.info2, + RX_MPDU_START_INFO2_ENC_TYPE); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_decap_type(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info11, + RX_MSDU_END_INFO11_DECAP_FORMAT); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info11, + RX_MSDU_END_INFO11_MESH_CTRL_PRESENT); +} + +static bool ath12k_hw_qcc2072_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_CTRL_VALID); +} + +static bool ath12k_hw_qcc2072_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_FCTRL_VALID); +} + +static u16 ath12k_hw_qcc2072_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc) +{ + return (u16)le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_NUM); +} + +static u16 ath12k_hw_qcc2072_rx_desc_get_msdu_len(struct hal_rx_desc *desc) +{ + return (u16)le32_get_bits(desc->u.qcc2072.msdu_end.info10, + RX_MSDU_END_INFO10_MSDU_LENGTH); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_SGI); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_RATE_MCS); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_RECV_BW); +} + +static u32 ath12k_hw_qcc2072_rx_desc_get_msdu_freq(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcc2072.msdu_end.phy_meta_data); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_PKT_TYPE); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) +{ + return (u8)le32_get_bits(desc->u.qcc2072.mpdu_start.info2, + RX_MPDU_START_INFO2_TID); +} + +static u16 ath12k_hw_qcc2072_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcc2072.mpdu_start.sw_peer_id); +} + +static void ath12k_hw_qcc2072_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc, + struct hal_rx_desc *ldesc) +{ + memcpy(&fdesc->u.qcc2072.msdu_end, &ldesc->u.qcc2072.msdu_end, + sizeof(struct rx_msdu_end_qcn9274)); +} + +static u32 ath12k_hw_qcc2072_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.mpdu_start_tag, + HAL_TLV_HDR_TAG); +} + +static u32 ath12k_hw_qcc2072_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcc2072.mpdu_start.phy_ppdu_id); +} + +static void ath12k_hw_qcc2072_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len) +{ + u32 info = __le32_to_cpu(desc->u.qcc2072.msdu_end.info10); + + info &= ~RX_MSDU_END_INFO10_MSDU_LENGTH; + info |= u32_encode_bits(len, RX_MSDU_END_INFO10_MSDU_LENGTH); + + desc->u.qcc2072.msdu_end.info10 = __cpu_to_le32(info); +} + +static u8 *ath12k_hw_qcc2072_rx_desc_get_msdu_payload(struct hal_rx_desc *desc) +{ + return &desc->u.qcc2072.msdu_payload[0]; +} + +static u32 ath12k_hw_qcc2072_rx_desc_get_mpdu_start_offset(void) +{ + return offsetof(struct hal_rx_desc_qcc2072, mpdu_start_tag); +} + +static u32 ath12k_hw_qcc2072_rx_desc_get_msdu_end_offset(void) +{ + return offsetof(struct hal_rx_desc_qcc2072, msdu_end_tag); +} + +static bool ath12k_hw_qcc2072_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcc2072.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR2_VALID; +} + +static u8 *ath12k_hw_qcc2072_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) +{ + return desc->u.qcc2072.mpdu_start.addr2; +} + +static bool ath12k_hw_qcc2072_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcc2072.msdu_end.info13) & + RX_MSDU_END_INFO13_MCAST_BCAST; +} + +static void ath12k_hw_qcc2072_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, + struct ieee80211_hdr *hdr) +{ + hdr->frame_control = desc->u.qcc2072.mpdu_start.frame_ctrl; + hdr->duration_id = desc->u.qcc2072.mpdu_start.duration; + ether_addr_copy(hdr->addr1, desc->u.qcc2072.mpdu_start.addr1); + ether_addr_copy(hdr->addr2, desc->u.qcc2072.mpdu_start.addr2); + ether_addr_copy(hdr->addr3, desc->u.qcc2072.mpdu_start.addr3); + if (__le32_to_cpu(desc->u.qcc2072.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR4_VALID) { + ether_addr_copy(hdr->addr4, desc->u.qcc2072.mpdu_start.addr4); + } + hdr->seq_ctrl = desc->u.qcc2072.mpdu_start.seq_ctrl; +} + +static void ath12k_hw_qcc2072_rx_desc_get_crypto_hdr(struct hal_rx_desc *desc, + u8 *crypto_hdr, + enum hal_encrypt_type enctype) +{ + unsigned int key_id; + + switch (enctype) { + case HAL_ENCRYPT_TYPE_OPEN: + return; + case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: + case HAL_ENCRYPT_TYPE_TKIP_MIC: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[1] = 0; + crypto_hdr[2] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcc2072.mpdu_start.pn[0]); + break; + case HAL_ENCRYPT_TYPE_CCMP_128: + case HAL_ENCRYPT_TYPE_CCMP_256: + case HAL_ENCRYPT_TYPE_GCMP_128: + case HAL_ENCRYPT_TYPE_AES_GCMP_256: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[1] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[2] = 0; + break; + case HAL_ENCRYPT_TYPE_WEP_40: + case HAL_ENCRYPT_TYPE_WEP_104: + case HAL_ENCRYPT_TYPE_WEP_128: + case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: + case HAL_ENCRYPT_TYPE_WAPI: + return; + } + key_id = u32_get_bits(__le32_to_cpu(desc->u.qcc2072.mpdu_start.info5), + RX_MPDU_START_INFO5_KEY_ID); + crypto_hdr[3] = (u8)(0x20 | (key_id << 6)); + crypto_hdr[4] = HAL_RX_MPDU_INFO_PN_GET_BYTE3(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[5] = HAL_RX_MPDU_INFO_PN_GET_BYTE4(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[6] = HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcc2072.mpdu_start.pn[1]); + crypto_hdr[7] = HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcc2072.mpdu_start.pn[1]); +} + +static int ath12k_hal_srng_create_config_qcc2072(struct ath12k_base *ab) +{ + struct ath12k_hal *hal = &ab->hal; + struct hal_srng_config *s; + + hal->srng_config = kmemdup(hw_srng_config_template, + sizeof(hw_srng_config_template), + GFP_KERNEL); + if (!hal->srng_config) + return -ENOMEM; + + s = &hal->srng_config[HAL_REO_DST]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP; + s->reg_size[0] = HAL_REO2_RING_BASE_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab); + s->reg_size[1] = HAL_REO2_RING_HP - HAL_REO1_RING_HP; + + s = &hal->srng_config[HAL_REO_EXCEPTION]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_SW0_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_SW0_RING_HP; + + s = &hal->srng_config[HAL_REO_REINJECT]; + s->max_rings = 1; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP; + + s = &hal->srng_config[HAL_REO_CMD]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP; + s->entry_size = (sizeof(struct hal_tlv_hdr) + + sizeof(struct hal_reo_get_queue_stats_qcc2072)) >> 2, + + s = &hal->srng_config[HAL_REO_STATUS]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP; + s->entry_size = (sizeof(struct hal_tlv_hdr) + + sizeof(struct hal_reo_get_queue_stats_status_qcc2072)) >> 2, + + s = &hal->srng_config[HAL_TCL_DATA]; + s->max_rings = 5; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP; + s->reg_size[0] = HAL_TCL2_RING_BASE_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab); + s->reg_size[1] = HAL_TCL2_RING_HP - HAL_TCL1_RING_HP; + + s = &hal->srng_config[HAL_TCL_CMD]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP; + + s = &hal->srng_config[HAL_TCL_STATUS]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP; + + s = &hal->srng_config[HAL_CE_SRC]; + s->max_rings = 12; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP; + s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab); + s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab); + + s = &hal->srng_config[HAL_CE_DST]; + s->max_rings = 12; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP; + s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab); + s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab); + + s = &hal->srng_config[HAL_CE_DST_STATUS]; + s->max_rings = 12; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + + HAL_CE_DST_STATUS_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP; + s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab); + s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab); + + s = &hal->srng_config[HAL_WBM_IDLE_LINK]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_HP; + + s = &hal->srng_config[HAL_SW2WBM_RELEASE]; + s->max_rings = 1; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + + HAL_WBM_SW_RELEASE_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_SW_RELEASE_RING_HP; + + s = &hal->srng_config[HAL_WBM2SW_RELEASE]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_HP; + s->reg_size[0] = HAL_WBM1_RELEASE_RING_BASE_LSB(ab) - + HAL_WBM0_RELEASE_RING_BASE_LSB(ab); + s->reg_size[1] = HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP; + + s = &hal->srng_config[HAL_RXDMA_BUF]; + s->max_rings = 2; + s->mac_type = ATH12K_HAL_SRNG_PMAC; + + s = &hal->srng_config[HAL_RXDMA_DST]; + s->max_rings = 1; + s->entry_size = sizeof(struct hal_reo_entrance_ring) >> 2; + + /* below rings are not used */ + s = &hal->srng_config[HAL_RXDMA_DIR_BUF]; + s->max_rings = 0; + + s = &hal->srng_config[HAL_PPE2TCL]; + s->max_rings = 0; + + s = &hal->srng_config[HAL_PPE_RELEASE]; + s->max_rings = 0; + + s = &hal->srng_config[HAL_TX_MONITOR_BUF]; + s->max_rings = 0; + + s = &hal->srng_config[HAL_TX_MONITOR_DST]; + s->max_rings = 0; + + s = &hal->srng_config[HAL_PPE2TCL]; + s->max_rings = 0; + + return 0; +} + +static void ath12k_hal_qcc2072_reo_init_cmd_ring(void *entry, int cmd_num) +{ + struct hal_reo_get_queue_stats *desc; + struct hal_tlv_hdr *tlv = entry; + + desc = (struct hal_reo_get_queue_stats *)tlv->value; + desc->cmd.info0 = le32_encode_bits(cmd_num, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); +} + +static void *ath12k_hal_qcc2072_reo_cmd_encode_hdr(void *reo_desc, + u64 tag, u64 len) +{ + struct hal_tlv_hdr *tlv = reo_desc; + + tlv->tl = le32_encode_bits((u32)tag, HAL_TLV_HDR_TAG) | + le32_encode_bits((u32)len, HAL_TLV_HDR_LEN); + + return tlv->value; +} + +static u16 ath12k_hal_qcc2072_reo_status_decode_hdr(void *reo_desc, void **desc) +{ + struct hal_tlv_hdr *tlv = reo_desc; + u16 tag; + + tag = (u16)le32_get_bits(tlv->tl, HAL_SRNG_TLV_HDR_TAG); + /* actual desc starts after tlv32_padding */ + *desc = tlv->value + sizeof(u32); + + return tag; +} + +static bool ath12k_hw_qcc2072_dp_rx_h_msdu_done(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.msdu_end.info14, + RX_MSDU_END_INFO14_MSDU_DONE); +} + +static bool ath12k_hw_qcc2072_dp_rx_h_l4_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.msdu_end.info13, + RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcc2072_dp_rx_h_ip_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.msdu_end.info13, + RX_MSDU_END_INFO13_IP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcc2072_dp_rx_h_is_decrypted(struct hal_rx_desc *desc) +{ + return (le32_get_bits(desc->u.qcc2072.msdu_end.info14, + RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE) == + RX_DESC_DECRYPT_STATUS_CODE_OK); +} + +static u32 ath12k_hw_qcc2072_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) +{ + u32 info = __le32_to_cpu(desc->u.qcc2072.msdu_end.info13); + u32 errmap = 0; + + if (info & RX_MSDU_END_INFO13_FCS_ERR) + errmap |= HAL_RX_MPDU_ERR_FCS; + + if (info & RX_MSDU_END_INFO13_DECRYPT_ERR) + errmap |= HAL_RX_MPDU_ERR_DECRYPT; + + if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR) + errmap |= HAL_RX_MPDU_ERR_TKIP_MIC; + + if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR) + errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR; + + if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR) + errmap |= HAL_RX_MPDU_ERR_OVERFLOW; + + if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MSDU_LEN; + + if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MPDU_LEN; + + return errmap; +} + +static u32 ath12k_hw_qcc2072_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcc2072); +} + +static u8 ath12k_hw_qcc2072_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + +const struct hal_rx_ops hal_rx_qcc2072_ops = { + .rx_desc_get_first_msdu = ath12k_hw_qcc2072_rx_desc_get_first_msdu, + .rx_desc_get_last_msdu = ath12k_hw_qcc2072_rx_desc_get_last_msdu, + .rx_desc_get_l3_pad_bytes = ath12k_hw_qcc2072_rx_desc_get_l3_pad_bytes, + .rx_desc_encrypt_valid = ath12k_hw_qcc2072_rx_desc_encrypt_valid, + .rx_desc_get_encrypt_type = ath12k_hw_qcc2072_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath12k_hw_qcc2072_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath12k_hw_qcc2072_rx_desc_get_mesh_ctl, + .rx_desc_get_mpdu_seq_ctl_vld = ath12k_hw_qcc2072_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath12k_hw_qcc2072_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath12k_hw_qcc2072_rx_desc_get_mpdu_start_seq_no, + .rx_desc_get_msdu_len = ath12k_hw_qcc2072_rx_desc_get_msdu_len, + .rx_desc_get_msdu_sgi = ath12k_hw_qcc2072_rx_desc_get_msdu_sgi, + .rx_desc_get_msdu_rate_mcs = ath12k_hw_qcc2072_rx_desc_get_msdu_rate_mcs, + .rx_desc_get_msdu_rx_bw = ath12k_hw_qcc2072_rx_desc_get_msdu_rx_bw, + .rx_desc_get_msdu_freq = ath12k_hw_qcc2072_rx_desc_get_msdu_freq, + .rx_desc_get_msdu_pkt_type = ath12k_hw_qcc2072_rx_desc_get_msdu_pkt_type, + .rx_desc_get_msdu_nss = ath12k_hw_qcc2072_rx_desc_get_msdu_nss, + .rx_desc_get_mpdu_tid = ath12k_hw_qcc2072_rx_desc_get_mpdu_tid, + .rx_desc_get_mpdu_peer_id = ath12k_hw_qcc2072_rx_desc_get_mpdu_peer_id, + .rx_desc_copy_end_tlv = ath12k_hw_qcc2072_rx_desc_copy_end_tlv, + .rx_desc_get_mpdu_start_tag = ath12k_hw_qcc2072_rx_desc_get_mpdu_start_tag, + .rx_desc_get_mpdu_ppdu_id = ath12k_hw_qcc2072_rx_desc_get_mpdu_ppdu_id, + .rx_desc_set_msdu_len = ath12k_hw_qcc2072_rx_desc_set_msdu_len, + .rx_desc_get_msdu_payload = ath12k_hw_qcc2072_rx_desc_get_msdu_payload, + .rx_desc_get_mpdu_start_offset = ath12k_hw_qcc2072_rx_desc_get_mpdu_start_offset, + .rx_desc_get_msdu_end_offset = ath12k_hw_qcc2072_rx_desc_get_msdu_end_offset, + .rx_desc_mac_addr2_valid = ath12k_hw_qcc2072_rx_desc_mac_addr2_valid, + .rx_desc_mpdu_start_addr2 = ath12k_hw_qcc2072_rx_desc_mpdu_start_addr2, + .rx_desc_is_da_mcbc = ath12k_hw_qcc2072_rx_desc_is_da_mcbc, + .rx_desc_get_dot11_hdr = ath12k_hw_qcc2072_rx_desc_get_dot11_hdr, + .rx_desc_get_crypto_header = ath12k_hw_qcc2072_rx_desc_get_crypto_hdr, + .dp_rx_h_msdu_done = ath12k_hw_qcc2072_dp_rx_h_msdu_done, + .dp_rx_h_l4_cksum_fail = ath12k_hw_qcc2072_dp_rx_h_l4_cksum_fail, + .dp_rx_h_ip_cksum_fail = ath12k_hw_qcc2072_dp_rx_h_ip_cksum_fail, + .dp_rx_h_is_decrypted = ath12k_hw_qcc2072_dp_rx_h_is_decrypted, + .dp_rx_h_mpdu_err = ath12k_hw_qcc2072_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcc2072_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_qcc2072_rx_desc_get_msdu_src_link, +}; + +const struct hal_ops hal_qcc2072_ops = { + .create_srng_config = ath12k_hal_srng_create_config_qcc2072, + .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, + .reo_init_cmd_ring = ath12k_hal_qcc2072_reo_init_cmd_ring, + .reo_cmd_encode_hdr = ath12k_hal_qcc2072_reo_cmd_encode_hdr, + .reo_status_decode_hdr = ath12k_hal_qcc2072_reo_status_decode_hdr, + .rxdma_ring_wmask_rx_mpdu_start = NULL, + .rxdma_ring_wmask_rx_msdu_end = NULL, + .get_hal_rx_compact_ops = NULL, +}; static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) { struct ath12k_hal *hal = &ab->hal; diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index d84f71280d0ed..d8af9dc1155a1 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1115,10 +1115,12 @@ struct hal_ops { extern const struct hal_ops hal_qcn9274_ops; extern const struct hal_ops hal_wcn7850_ops; +extern const struct hal_ops hal_qcc2072_ops; extern const struct hal_rx_ops hal_rx_qcn9274_ops; extern const struct hal_rx_ops hal_rx_qcn9274_compact_ops; extern const struct hal_rx_ops hal_rx_wcn7850_ops; +extern const struct hal_rx_ops hal_rx_qcc2072_ops; u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 13ddac4a94125..2e321a913c4af 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -1207,6 +1207,13 @@ struct hal_reo_get_queue_stats { * Hole_count */ +struct hal_reo_get_queue_stats_qcc2072 { + struct hal_reo_cmd_hdr cmd; + __le32 queue_addr_lo; + __le32 info0; + __le32 rsvd0[6]; +} __packed; + #define HAL_REO_FLUSH_QUEUE_INFO0_DESC_ADDR_HI GENMASK(7, 0) #define HAL_REO_FLUSH_QUEUE_INFO0_BLOCK_DESC_ADDR BIT(8) #define HAL_REO_FLUSH_QUEUE_INFO0_BLOCK_RESRC_IDX GENMASK(10, 9) @@ -2728,6 +2735,24 @@ struct hal_reo_get_queue_stats_status { * entries into this Ring has looped around the ring. */ +struct hal_reo_get_queue_stats_status_qcc2072 { + __le32 tlv32_padding; + struct hal_reo_status_hdr hdr; + __le32 info0; + __le32 pn[4]; + __le32 last_rx_enqueue_timestamp; + __le32 last_rx_dequeue_timestamp; + __le32 rx_bitmap[9]; + __le32 info1; + __le32 info2; + __le32 info3; + __le32 num_mpdu_frames; + __le32 num_msdu_frames; + __le32 total_bytes; + __le32 info4; + __le32 info5; +} __packed; + #define HAL_REO_STATUS_LOOP_CNT GENMASK(31, 28) #define HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED BIT(0) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 7e5142fa9fcbb..d3ebd859219e9 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1805,7 +1805,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .wmi_init = ath12k_wmi_init_wcn7850, - .hal_ops = &hal_wcn7850_ops, + .hal_ops = &hal_qcc2072_ops, .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) | BIT(CNSS_PCIE_PERST_NO_PULL_V01) | diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index 6c600473b4021..8090f89254c39 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -1528,11 +1528,28 @@ struct hal_rx_desc_wcn7850 { u8 msdu_payload[]; }; +struct rx_pkt_hdr_tlv_qcc2072 { + __le32 tag; + __le64 phy_ppdu_id; + u8 rx_pkt_hdr[HAL_RX_BE_PKT_HDR_TLV_LEN]; +}; + +struct hal_rx_desc_qcc2072 { + __le32 msdu_end_tag; + struct rx_msdu_end_qcn9274 msdu_end; + u8 rx_padding0[RX_BE_PADDING0_BYTES]; + __le32 mpdu_start_tag; + struct rx_mpdu_start_qcn9274 mpdu_start; + struct rx_pkt_hdr_tlv_qcc2072 pkt_hdr_tlv; + u8 msdu_payload[]; +}; + struct hal_rx_desc { union { struct hal_rx_desc_qcn9274 qcn9274; struct hal_rx_desc_qcn9274_compact qcn9274_compact; struct hal_rx_desc_wcn7850 wcn7850; + struct hal_rx_desc_qcc2072 qcc2072; } u; } __packed; From 5c48fbd8af44a063480ae12cd681de62a7bf91fb Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:52:13 +0800 Subject: [PATCH 13/17] BACKPORT: FROMLIST: wifi: ath12k: add hardware ops support for QCC2072 Due to HAL descriptors, QCC2027 has different offsets of MPDU start tag and MSDU end tag, compared with other chips. Hence add new hardware ops structure for QCC2072. All ops are directly taken from WCN7850, with the exception to rxdma_ring_sel_config, which needs a new function ath12k_dp_rxdma_ring_sel_config_qcc2072() to handle the difference mentioned above. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-13-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/dp_rx.c | 42 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/dp_rx.h | 1 + drivers/net/wireless/ath/ath12k/hal.c | 11 +++++++ drivers/net/wireless/ath/ath12k/hal_rx.h | 2 ++ drivers/net/wireless/ath/ath12k/hw.c | 11 ++++++- 5 files changed, 66 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index c8d9515cba866..c0896459f40e7 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -4545,6 +4545,48 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) return ret; } +int ath12k_dp_rxdma_ring_sel_config_qcc2072(struct ath12k_base *ab) +{ + struct ath12k_dp *dp = &ab->dp; + struct htt_rx_ring_tlv_filter tlv_filter = {}; + u32 ring_id; + int ret = 0; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; + int i; + + ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; + + tlv_filter.rx_filter = HTT_RX_TLV_FLAGS_RXDMA_RING; + tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BAR; + tlv_filter.pkt_filter_flags3 = HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_MCAST | + HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_UCAST | + HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA; + tlv_filter.offset_valid = true; + tlv_filter.rx_packet_offset = hal_rx_desc_sz; + + tlv_filter.rx_header_offset = offsetof(struct hal_rx_desc_qcc2072, pkt_hdr_tlv); + + tlv_filter.rx_mpdu_start_offset = + ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(); + tlv_filter.rx_msdu_end_offset = + ath12k_hal_rx_desc_get_msdu_end_offset_qcc2072(); + + /* TODO: Selectively subscribe to required qwords within msdu_end + * and mpdu_start and setup the mask in below msg + * and modify the rx_desc struct + */ + + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { + ring_id = dp->rx_mac_buf_ring[i].ring_id; + ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, i, + HAL_RXDMA_BUF, + DP_RXDMA_REFILL_RING_SIZE, + &tlv_filter); + } + + return ret; +} + int ath12k_dp_rx_htt_setup(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index 69d0a36a91d88..053b2f69abe36 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -170,6 +170,7 @@ u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab, void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info); int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab); int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab); +int ath12k_dp_rxdma_ring_sel_config_qcc2072(struct ath12k_base *ab); int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len, int (*iter)(struct ath12k_base *ar, u16 tag, u16 len, diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 0fecb5ff10ac4..b2549f5245fee 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -2134,6 +2134,17 @@ const struct hal_ops hal_qcc2072_ops = { .rxdma_ring_wmask_rx_msdu_end = NULL, .get_hal_rx_compact_ops = NULL, }; + +u32 ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(void) +{ + return offsetof(struct hal_rx_desc_qcc2072, mpdu_start_tag); +} + +u32 ath12k_hal_rx_desc_get_msdu_end_offset_qcc2072(void) +{ + return offsetof(struct hal_rx_desc_qcc2072, msdu_end_tag); +} + static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) { struct ath12k_hal *hal = &ab->hal; diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index d1ad7747b82c4..e1f8a7cd5f2c9 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -1168,4 +1168,6 @@ void ath12k_hal_rx_msdu_list_get(struct ath12k *ar, struct hal_rx_msdu_list *msdu_list, u16 *num_msdus); +u32 ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(void); +u32 ath12k_hal_rx_desc_get_msdu_end_offset_qcc2072(void); #endif diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index d3ebd859219e9..d144b69b33e20 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -147,6 +147,15 @@ static const struct ath12k_hw_ops wcn7850_ops = { .is_frame_link_agnostic = ath12k_is_frame_link_agnostic_wcn7850, }; +static const struct ath12k_hw_ops qcc2072_ops = { + .get_hw_mac_from_pdev_id = ath12k_hw_qcn9274_mac_from_pdev_id, + .mac_id_to_pdev_id = ath12k_hw_mac_id_to_pdev_id_wcn7850, + .mac_id_to_srng_id = ath12k_hw_mac_id_to_srng_id_wcn7850, + .rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_qcc2072, + .get_ring_selector = ath12k_hw_get_ring_selector_wcn7850, + .dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_wcn7850, +}; + #define ATH12K_TX_RING_MASK_0 0x1 #define ATH12K_TX_RING_MASK_1 0x2 #define ATH12K_TX_RING_MASK_2 0x4 @@ -1765,7 +1774,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850, .internal_sleep_clock = true, - .hw_ops = &wcn7850_ops, + .hw_ops = &qcc2072_ops, .ring_mask = &ath12k_hw_ring_mask_wcn7850, .regs = &qcc2072_regs, From 46cb219acd4259aada65ccc26b29e62302235381 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:53:38 +0800 Subject: [PATCH 14/17] BACKPORT: FROMLIST: wifi: ath12k: limit number of channels per WMI command Currently the number of channels can be sent in a single WMI command is calculated based on the maximum message length of the target, this results in WMI exchange hang for QCC2072 as its firmware can not support those many channels in a single command. Add a limit to avoid this issue. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-16-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/wmi.c | 3 ++- drivers/net/wireless/ath/ath12k/wmi.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index cb7c22ddbe752..42131b57345db 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2897,7 +2897,8 @@ int ath12k_wmi_send_scan_chan_list_cmd(struct ath12k *ar, max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / sizeof(*chan_info); - num_send_chans = min(arg->nallchans, max_chan_limit); + num_send_chans = min3(arg->nallchans, max_chan_limit, + ATH12K_WMI_MAX_NUM_CHAN_PER_CMD); arg->nallchans -= num_send_chans; len += sizeof(*chan_info) * num_send_chans; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index a8c3190e8ad95..0912e6472f4c4 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -6310,6 +6310,9 @@ struct ath12k_wmi_rssi_dbm_conv_info_arg { s8 min_nf_dbm; }; +/* each WMI cmd can hold 58 channel entries at most */ +#define ATH12K_WMI_MAX_NUM_CHAN_PER_CMD 58 + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, From 72e5595a8e6398a3329562d0963ae25b9972ae06 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 13 Nov 2025 13:55:35 +0800 Subject: [PATCH 15/17] BACKPORT: FROMLIST: wifi: ath12k: send peer meta data version to firmware Peer meta data version is currently not delivered to firmware, resulting in QCC2072 data path issues. Parse it from service ready ext2 event and send to firmware in WMI init command. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-17-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/wmi.c | 9 +++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 42131b57345db..8ffbdc40b054a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -298,6 +298,11 @@ void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, config->num_multicast_filter_entries = 0x20; config->num_wow_filters = 0x16; config->num_keep_alive_pattern = 0; + + if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) + config->peer_metadata_ver = ATH12K_PEER_METADATA_V1A; + else + config->peer_metadata_ver = ab->wmi_ab.dp_peer_meta_data_ver; } #define PRIMAP(_hw_mode_) \ @@ -5515,6 +5520,10 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, ret); return ret; } + + ab->wmi_ab.dp_peer_meta_data_ver = + u32_get_bits(parse->arg.target_cap_flags, + WMI_TARGET_CAP_FLAGS_RX_PEER_METADATA_VERSION); break; case WMI_TAG_ARRAY_STRUCT: diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 0912e6472f4c4..29f8b9e6facaa 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2781,6 +2781,8 @@ enum wmi_channel_width { #define WMI_EHT_MCS_NSS_10_11 GENMASK(11, 8) #define WMI_EHT_MCS_NSS_12_13 GENMASK(15, 12) +#define WMI_TARGET_CAP_FLAGS_RX_PEER_METADATA_VERSION GENMASK(1, 0) + struct wmi_service_ready_ext2_event { __le32 reg_db_version; __le32 hw_min_max_tx_power_2ghz; @@ -5218,6 +5220,8 @@ struct ath12k_wmi_base { struct ath12k_svc_ext_info svc_ext_info; u32 sbs_lower_band_end_freq; struct ath12k_hw_mode_info hw_mode_info; + + u8 dp_peer_meta_data_ver; }; struct wmi_pdev_set_bios_interface_cmd { From 265dd3fa1e5adeff25d6a1e82cb626997ab80381 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Thu, 18 Dec 2025 17:47:41 +0800 Subject: [PATCH 16/17] BACKPORT: FROMLIST: wifi: ath12k: fix PCIE_LOCAL_REG_QRTR_NODE_ID definition for QCC2072 The definition of PCIE_LOCAL_REG_QRTR_NODE_ID in QCC2072 is incorrect, which causes the QMI connection to fail when ATH12K_FW_FEATURE_MULTI_QRTR_ID is enabled. To resolve this issue, move it to the hardware register table. Note IPQ5332 is not affected as it is not PCIe based device. Tested-on: QCC2072 hw1.0 PCI CI_WLAN.COL.1.0-01668.1-QCACOLSWPL_V1_TO_SILICONZ-9 Signed-off-by: Miaoqing Pan Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-18-87928cf8e547@oss.qualcomm.com/ --- drivers/net/wireless/ath/ath12k/hw.c | 8 ++++++++ drivers/net/wireless/ath/ath12k/hw.h | 2 ++ drivers/net/wireless/ath/ath12k/pci.c | 3 +-- drivers/net/wireless/ath/ath12k/pci.h | 5 +++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index d144b69b33e20..cfeda87b31b93 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -1017,6 +1017,8 @@ static const struct ath12k_hw_regs qcn9274_v1_regs = { .hal_umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e38338, + + .qrtr_node_id = 0x1e03164, }; static const struct ath12k_hw_regs qcn9274_v2_regs = { @@ -1110,6 +1112,8 @@ static const struct ath12k_hw_regs qcn9274_v2_regs = { .hal_umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e38338, + + .qrtr_node_id = 0x1e03164, }; static const struct ath12k_hw_regs ipq5332_regs = { @@ -1285,6 +1289,8 @@ static const struct ath12k_hw_regs wcn7850_regs = { .hal_umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e40304, + + .qrtr_node_id = 0x1e03164, }; static const struct ath12k_hw_regs qcc2072_regs = { @@ -1372,6 +1378,8 @@ static const struct ath12k_hw_regs qcc2072_regs = { .hal_umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e65304, + + .qrtr_node_id = 0x1e03300, }; static const struct ath12k_hw_hal_params ath12k_hw_hal_params_qcn9274 = { diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index b1d2aebe59734..84e0e3c6b5d25 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -368,6 +368,8 @@ struct ath12k_hw_regs { u32 hal_reo_status_ring_base; u32 gcc_gcc_pcie_hot_rst; + + u32 qrtr_node_id; }; static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 21a3d8e254576..407025e2bb824 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -41,7 +41,6 @@ #define QCN9274_DEVICE_ID 0x1109 #define WCN7850_DEVICE_ID 0x1107 -#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164 #define DOMAIN_NUMBER_MASK GENMASK(7, 4) #define BUS_NUMBER_MASK GENMASK(3, 0) @@ -947,7 +946,7 @@ static void ath12k_pci_update_qrtr_node_id(struct ath12k_base *ab) * writes to the given register, it is available for firmware when the QMI service * is spawned. */ - reg = PCIE_LOCAL_REG_QRTR_NODE_ID & WINDOW_RANGE_MASK; + reg = PCIE_LOCAL_REG_QRTR_NODE_ID(ab) & WINDOW_RANGE_MASK; ath12k_pci_write32(ab, reg, ab_pci->qmi_instance); ath12k_dbg(ab, ATH12K_DBG_PCI, "pci reg 0x%x instance 0x%x read val 0x%x\n", diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 541fba4373348..8b0e47a95df8f 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -58,6 +58,11 @@ #define QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB 0x1E20338 #define OTP_BOARD_ID_MASK GENMASK(15, 0) +#define PCIE_LOCAL_REG_QRTR_NODE_ID(ab) \ + ((ab)->hw_params->regs->qrtr_node_id) +#define DOMAIN_NUMBER_MASK GENMASK(7, 4) +#define BUS_NUMBER_MASK GENMASK(3, 0) + #define PCI_BAR_WINDOW0_BASE 0x1E00000 #define PCI_BAR_WINDOW0_END 0x1E7FFFC #define PCI_SOC_RANGE_MASK 0x3FFF From 0997338382310e833e64b27cdd698c27b8224741 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 18 Dec 2025 17:50:12 +0800 Subject: [PATCH 17/17] BACKPORT: FROMLIST: wifi: ath12k: enable QCC2072 support Add QCC2072's PCI device ID to the table such that it can be probed, also populate some parameters when probing. Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0-01560-QCACOLSWPL_V1_TO_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Signed-off-by: Baochen Qiang Link: https://lore.kernel.org/linux-wireless/20251218-ath12k-support-qcc2072-v1-19-87928cf8e547@oss.qualcomm.com/ Signed-off-by: Miaoqing Pan --- drivers/net/wireless/ath/ath12k/pci.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 407025e2bb824..f0493ac56b94c 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -23,6 +23,7 @@ #define WINDOW_ENABLE_BIT 0x40000000 #define WINDOW_REG_ADDRESS 0x310c +#define WINDOW_REG_ADDRESS_QCC2072 0x3278 #define WINDOW_VALUE_MASK GENMASK(24, 19) #define WINDOW_START 0x80000 #define WINDOW_RANGE_MASK GENMASK(18, 0) @@ -40,6 +41,7 @@ #define QCN9274_DEVICE_ID 0x1109 #define WCN7850_DEVICE_ID 0x1107 +#define QCC2072_DEVICE_ID 0x1112 #define DOMAIN_NUMBER_MASK GENMASK(7, 4) #define BUS_NUMBER_MASK GENMASK(3, 0) @@ -47,6 +49,7 @@ static const struct pci_device_id ath12k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, + { PCI_VDEVICE(QCOM, QCC2072_DEVICE_ID) }, {} }; @@ -159,6 +162,11 @@ static const struct ath12k_pci_ops ath12k_pci_ops_wcn7850 = { .release = ath12k_pci_bus_release, }; +static const struct ath12k_pci_ops ath12k_pci_ops_qcc2027 = { + .wakeup = ath12k_pci_bus_wake_up, + .release = ath12k_pci_bus_release, +}; + static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset) { struct ath12k_base *ab = ab_pci->ab; @@ -1641,6 +1649,16 @@ static int ath12k_pci_probe(struct pci_dev *pdev, goto err_pci_free_region; } break; + case QCC2072_DEVICE_ID: + ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD; + ab_pci->msi_config = &ath12k_msi_config[0]; + ab->static_window_map = false; + ab_pci->pci_ops = &ath12k_pci_ops_qcc2027; + ab_pci->window_reg_addr = WINDOW_REG_ADDRESS_QCC2072; + ab->hal_rx_ops = &hal_rx_qcc2072_ops; + /* there is only one version till now */ + ab->hw_rev = ATH12K_HW_QCC2072_HW10; + break; default: dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",