diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml index a52cb8a0d409..0cb065265df4 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml @@ -92,6 +92,22 @@ properties: ieee80211-freq-limit: true + nvmem-cells: + minItems: 1 + maxItems: 3 + description: + References to nvmem cells for MAC address and/or calibration data. + Supported cell names are mac-address, calibration, and pre-calibration. + + nvmem-cell-names: + minItems: 1 + maxItems: 3 + items: + enum: + - mac-address + - calibration + - pre-calibration + qcom,calibration-data: $ref: /schemas/types.yaml#/definitions/uint8-array description: diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index bbca275a8289..08fd6795ed9e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -5136,6 +5136,15 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab, err: kfree(svc_rdy_ext.mac_phy_caps); + + /* + * During TLV iteration the WMI_TAG_SOC_HAL_REG_CAPABILITIES + * handler may have allocated ab->reg_info_store, so free it + * on error to avoid a memory leak + */ + kfree(ab->reg_info_store); + ab->reg_info_store = NULL; + ath11k_wmi_free_dbring_caps(ab); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index a98fc6e0699d..4718da494aab 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -928,15 +928,6 @@ struct ath12k_wsi_info { u32 hw_link_id_base; }; -struct ath12k_dp_profile_params { - u32 tx_comp_ring_size; - u32 rxdma_monitor_buf_ring_size; - u32 rxdma_monitor_dst_ring_size; - u32 num_pool_tx_desc; - u32 rx_desc_count; - u32 rx_release_ring_size; -}; - struct ath12k_mem_profile_based_param { u32 num_vdevs; u32 max_client_single; diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index d54995b7adb2..12791e267d1a 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -1071,6 +1071,20 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file, [HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET] = "PN err", [HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED] = "Desc blocked"}; + static const char *wbm_rx_drop[WBM_ERR_DROP_MAX] = { + [WBM_ERR_DROP_GET_SW_DESC] = "SW desc error", + [WBM_ERR_DROP_DESC_PARSE] = "Desc parse error", + [WBM_ERR_DROP_INV_HW_ID] = "Invalid hw id", + [WBM_ERR_DROP_NULL_PRTNR_DP] = "Null Partner dp", + [WBM_ERR_DROP_NULL_PROC_DP] = "Process Null Partner dp", + [WBM_ERR_DROP_NULL_PDEV] = "Null Pdev", + [WBM_ERR_DROP_NULL_AR] = "Null ar", + [WBM_ERR_DROP_CAC_RUNNING] = "CAC Running", + [WBM_ERR_DROP_SG] = "Scatter Gather", + [WBM_ERR_DROP_INV_NWIFI_HDR] = "Invalid NWifi Hdr len", + [WBM_ERR_DROP_REO_GENERIC] = "REO Generic", + [WBM_ERR_DROP_RXDMA_GENERIC] = "RXDMA Generic"}; + static const char *wbm_rel_src[HAL_WBM_REL_SRC_MODULE_MAX] = { [HAL_WBM_REL_SRC_MODULE_TQM] = "TQM", [HAL_WBM_REL_SRC_MODULE_RXDMA] = "Rxdma", @@ -1095,13 +1109,32 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file, for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++) len += scnprintf(buf + len, size - len, "%s: %u\n", - rxdma_err[i], device_stats->rxdma_error[i]); + rxdma_err[i], device_stats->wbm_err.rxdma_error[i]); len += scnprintf(buf + len, size - len, "\nREO errors:\n"); for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++) len += scnprintf(buf + len, size - len, "%s: %u\n", - reo_err[i], device_stats->reo_error[i]); + reo_err[i], device_stats->wbm_err.reo_error[i]); + + len += scnprintf(buf + len, size - len, "\nWBM Rx Drop Count:\n"); + for (i = 0; i < WBM_ERR_DROP_MAX; i++) + len += scnprintf(buf + len, size - len, "%s: %u\n", + wbm_rx_drop[i], device_stats->wbm_err.drop[i]); + + len += scnprintf(buf + len, size - len, "\nREO sent to stack:\n"); + for (i = 0; i < DP_REO_DST_RING_MAX; i++) { + len += scnprintf(buf + len, size - len, "ring%d:", i); + for (j = 0; j < ab->ag->num_devices; j++) + len += scnprintf(buf + len, size - len, + "\t%d:%u", j, + device_stats->sent_to_stack[i][j]); + len += scnprintf(buf + len, size - len, "\n"); + } + + len += scnprintf(buf + len, size - len, + "\nWBM SW desc fallback (HW CC not done): %u\n", + device_stats->wbm_err.sw_desc_fallback); len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n"); @@ -1117,6 +1150,11 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file, len += scnprintf(buf + len, size - len, "ring%d: %u\n", i, device_stats->tx_err.desc_na[i]); + len += scnprintf(buf + len, size - len, "\nTX Descriptor Pool Alloc Failures:\n"); + for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) + len += scnprintf(buf + len, size - len, "pool%d: %u\n", + i, device_stats->tx_err.txbuf_na[i]); + len += scnprintf(buf + len, size - len, "\nMisc Transmit Failures: %d\n", atomic_read(&device_stats->tx_err.misc_fail)); @@ -1181,7 +1219,7 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file, len += scnprintf(buf + len, size - len, "\nREO Rx Received:\n"); for (i = 0; i < DP_REO_DST_RING_MAX; i++) { - len += scnprintf(buf + len, size - len, "Ring%d:", i + 1); + len += scnprintf(buf + len, size - len, "ring%d:", i); for (j = 0; j < ab->ag->num_devices; j++) { len += scnprintf(buf + len, size - len, @@ -1215,8 +1253,40 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file, return ret; } +static ssize_t +ath12k_debugfs_write_device_dp_stats(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath12k_base *ab = file->private_data; + struct ath12k_dp *dp = ath12k_ab_to_dp(ab); + struct ath12k_device_dp_stats *device_stats = &dp->device_stats; + char buf[20] = {}; + int ret; + + /* filter partial writes and invalid commands */ + if (*ppos != 0 || count >= sizeof(buf) || count == 0) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + if (ret < 0) + return ret; + + /* drop the possible '\n' from the end */ + if (buf[*ppos - 1] == '\n') + buf[*ppos - 1] = '\0'; + + if (!strcmp(buf, "reset")) { + memset(device_stats, 0, sizeof(*device_stats)); + return count; + } + + return -EINVAL; +} + static const struct file_operations fops_device_dp_stats = { .read = ath12k_debugfs_dump_device_dp_stats, + .write = ath12k_debugfs_write_device_dp_stats, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -1227,7 +1297,7 @@ void ath12k_debugfs_pdev_create(struct ath12k_base *ab) debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab, &fops_simulate_fw_crash); - debugfs_create_file("device_dp_stats", 0400, ab->debugfs_soc, ab, + debugfs_create_file("device_dp_stats", 0600, ab->debugfs_soc, ab, &fops_device_dp_stats); } diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index ef9601152f81..83f9edfabf69 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -439,6 +439,7 @@ static void ath12k_dp_srng_common_cleanup(struct ath12k_base *ab) static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) { + const struct ath12k_dp_profile_params *dp_params = &ab->profile_param->dp_params; struct ath12k_dp *dp = ath12k_ab_to_dp(ab); const struct ath12k_hal_tcl_to_wbm_rbm_map *map; struct hal_srng *srng; @@ -469,7 +470,7 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_comp_ring, HAL_WBM2SW_RELEASE, tx_comp_ring_num, 0, - DP_TX_COMP_RING_SIZE(ab)); + ath12k_dp_tx_comp_ring_size(dp_params)); if (ret) { ath12k_warn(ab, "failed to set up tcl_comp ring (%d) :%d\n", tx_comp_ring_num, ret); @@ -487,7 +488,7 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rx_rel_ring, HAL_WBM2SW_RELEASE, HAL_WBM2SW_REL_ERR_RING_NUM, 0, - DP_RX_RELEASE_RING_SIZE(ab)); + ath12k_dp_rx_release_ring_size(dp_params)); if (ret) { ath12k_warn(ab, "failed to set up rx_rel ring :%d\n", ret); goto err; @@ -966,14 +967,15 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif) static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) { - struct ath12k_rx_desc_info *desc_info; + const struct ath12k_dp_profile_params *dp_params = &ab->profile_param->dp_params; + u32 pool_id, tx_spt_page, tx_spt_pages_per_pool, num_rx_spt_pages; struct ath12k_tx_desc_info *tx_desc_info, *tmp1; struct ath12k_dp *dp = ath12k_ab_to_dp(ab); + struct ath12k_rx_desc_info *desc_info; struct ath12k_skb_cb *skb_cb; struct sk_buff *skb; struct ath12k *ar; int i, j; - u32 pool_id, tx_spt_page; if (!dp->spt_info) return; @@ -981,8 +983,10 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) /* RX Descriptor cleanup */ spin_lock_bh(&dp->rx_desc_lock); + num_rx_spt_pages = ath12k_dp_num_rx_spt_pages(dp_params); + if (dp->rxbaddr) { - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES(ab); i++) { + for (i = 0; i < num_rx_spt_pages; i++) { if (!dp->rxbaddr[i]) continue; @@ -998,10 +1002,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) if (!skb) continue; - dma_unmap_single(ab->dev, - ATH12K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); + if (!ATH12K_SKB_RXCB(skb)->unmapped) + dma_unmap_single(ab->dev, + ATH12K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); dev_kfree_skb_any(skb); } @@ -1055,12 +1060,13 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) } if (dp->txbaddr) { + tx_spt_pages_per_pool = ath12k_dp_tx_spt_pages_per_pool(dp_params); + for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { spin_lock_bh(&dp->tx_desc_lock[pool_id]); - for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL(ab); i++) { - tx_spt_page = i + pool_id * - ATH12K_TX_SPT_PAGES_PER_POOL(ab); + for (i = 0; i < tx_spt_pages_per_pool; i++) { + tx_spt_page = i + pool_id * tx_spt_pages_per_pool; if (!dp->txbaddr[tx_spt_page]) continue; @@ -1154,14 +1160,16 @@ static void *ath12k_dp_cc_get_desc_addr_ptr(struct ath12k_dp *dp, struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_dp *dp, u32 cookie) { + const struct ath12k_dp_profile_params *dp_params; struct ath12k_rx_desc_info **desc_addr_ptr; u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); + dp_params = &dp->ab->profile_param->dp_params; - start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET(dp->ab); - end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES(dp->ab); + start_ppt_idx = dp->rx_ppt_base + ath12k_dp_rx_spt_page_offset(dp_params); + end_ppt_idx = start_ppt_idx + ath12k_dp_num_rx_spt_pages(dp_params); if (ppt_idx < start_ppt_idx || ppt_idx >= end_ppt_idx || @@ -1178,15 +1186,16 @@ EXPORT_SYMBOL(ath12k_dp_get_rx_desc); struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_dp *dp, u32 cookie) { + const struct ath12k_dp_profile_params *dp_params; struct ath12k_tx_desc_info **desc_addr_ptr; u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); + dp_params = &dp->ab->profile_param->dp_params; start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET; - end_ppt_idx = start_ppt_idx + - (ATH12K_TX_SPT_PAGES_PER_POOL(dp->ab) * ATH12K_HW_MAX_QUEUES); + end_ppt_idx = start_ppt_idx + ath12k_dp_num_tx_spt_pages(dp_params); if (ppt_idx < start_ppt_idx || ppt_idx >= end_ppt_idx || @@ -1201,12 +1210,13 @@ EXPORT_SYMBOL(ath12k_dp_get_tx_desc); static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) { - struct ath12k_dp *dp = ath12k_ab_to_dp(ab); + const struct ath12k_dp_profile_params *dp_params = &ab->profile_param->dp_params; + u32 num_rx_spt_pages = ath12k_dp_num_rx_spt_pages(dp_params); struct ath12k_rx_desc_info *rx_descs, **rx_desc_addr; struct ath12k_tx_desc_info *tx_descs, **tx_desc_addr; - u32 num_rx_spt_pages = ATH12K_NUM_RX_SPT_PAGES(ab); - u32 i, j, pool_id, tx_spt_page; - u32 ppt_idx, cookie_ppt_idx; + u32 i, j, pool_id, tx_spt_page, tx_spt_pages_per_pool; + u32 ppt_idx, cookie_ppt_idx, rx_spt_page_offset; + struct ath12k_dp *dp = ath12k_ab_to_dp(ab); spin_lock_bh(&dp->rx_desc_lock); @@ -1218,9 +1228,9 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - /* First ATH12K_NUM_RX_SPT_PAGES(ab) of allocated SPT pages are used for - * RX - */ + rx_spt_page_offset = ath12k_dp_rx_spt_page_offset(dp_params); + + /* First num_rx_spt_pages of allocated SPT pages are used for RX */ for (i = 0; i < num_rx_spt_pages; i++) { rx_descs = kzalloc_objs(*rx_descs, ATH12K_MAX_SPT_ENTRIES, GFP_ATOMIC); @@ -1230,7 +1240,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET(ab) + i; + ppt_idx = rx_spt_page_offset + i; cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; dp->rxbaddr[i] = &rx_descs[0]; @@ -1249,14 +1259,17 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) spin_unlock_bh(&dp->rx_desc_lock); dp->txbaddr = kzalloc_objs(struct ath12k_tx_desc_info *, - ATH12K_NUM_TX_SPT_PAGES(ab), GFP_ATOMIC); + ath12k_dp_num_tx_spt_pages(dp_params), + GFP_ATOMIC); if (!dp->txbaddr) return -ENOMEM; + tx_spt_pages_per_pool = ath12k_dp_tx_spt_pages_per_pool(dp_params); + for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { spin_lock_bh(&dp->tx_desc_lock[pool_id]); - for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL(ab); i++) { + for (i = 0; i < tx_spt_pages_per_pool; i++) { tx_descs = kzalloc_objs(*tx_descs, ATH12K_MAX_SPT_ENTRIES, GFP_ATOMIC); @@ -1267,8 +1280,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - tx_spt_page = i + pool_id * - ATH12K_TX_SPT_PAGES_PER_POOL(ab); + tx_spt_page = i + pool_id * tx_spt_pages_per_pool; ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; dp->txbaddr[tx_spt_page] = &tx_descs[0]; @@ -1294,6 +1306,7 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab, struct ath12k_dp *dp, enum ath12k_dp_desc_type type) { + const struct ath12k_dp_profile_params *dp_params = &ab->profile_param->dp_params; u32 cmem_base; int i, start, end; @@ -1302,12 +1315,12 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab, switch (type) { case ATH12K_DP_TX_DESC: start = ATH12K_TX_SPT_PAGE_OFFSET; - end = start + ATH12K_NUM_TX_SPT_PAGES(ab); + end = start + ath12k_dp_num_tx_spt_pages(dp_params); break; case ATH12K_DP_RX_DESC: cmem_base += ATH12K_PPT_ADDR_OFFSET(dp->rx_ppt_base); - start = ATH12K_RX_SPT_PAGE_OFFSET(ab); - end = start + ATH12K_NUM_RX_SPT_PAGES(ab); + start = ath12k_dp_rx_spt_page_offset(dp_params); + end = start + ath12k_dp_num_rx_spt_pages(dp_params); break; default: ath12k_err(ab, "invalid descriptor type %d in cmem init\n", type); @@ -1337,7 +1350,10 @@ void ath12k_dp_partner_cc_init(struct ath12k_base *ab) static u32 ath12k_dp_get_num_spt_pages(struct ath12k_base *ab) { - return ATH12K_NUM_RX_SPT_PAGES(ab) + ATH12K_NUM_TX_SPT_PAGES(ab); + const struct ath12k_dp_profile_params *dp_params = &ab->profile_param->dp_params; + + return ath12k_dp_num_rx_spt_pages(dp_params) + + ath12k_dp_num_tx_spt_pages(dp_params); } static int ath12k_dp_cc_init(struct ath12k_base *ab) @@ -1365,7 +1381,8 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) return -ENOMEM; } - dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES(ab); + dp->rx_ppt_base = ab->device_id * + ath12k_dp_num_rx_spt_pages(&ab->profile_param->dp_params); for (i = 0; i < dp->num_spt_pages; i++) { dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev, @@ -1465,6 +1482,7 @@ static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab) static int ath12k_dp_setup(struct ath12k_base *ab) { + const struct ath12k_dp_profile_params *dp_params; struct ath12k_dp *dp; struct hal_srng *srng = NULL; size_t size = 0; @@ -1474,6 +1492,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab) dp = ath12k_ab_to_dp(ab); dp->ab = ab; + dp_params = &ab->profile_param->dp_params; INIT_LIST_HEAD(&dp->reo_cmd_list); INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list); @@ -1528,7 +1547,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab) goto fail_dp_bank_profiles_cleanup; size = ab->hal.hal_wbm_release_ring_tx_size * - DP_TX_COMP_RING_SIZE(ab); + ath12k_dp_tx_comp_ring_size(dp_params); ret = ath12k_dp_reoq_lut_setup(ab); if (ret) { @@ -1540,7 +1559,8 @@ static int ath12k_dp_setup(struct ath12k_base *ab) dp->tx_ring[i].tcl_data_ring_id = i; dp->tx_ring[i].tx_status_head = 0; - dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE(ab) - 1; + dp->tx_ring[i].tx_status_tail = + ath12k_dp_tx_comp_ring_size(dp_params) - 1; dp->tx_ring[i].tx_status = kmalloc(size, GFP_KERNEL); if (!dp->tx_ring[i].tx_status) { ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index bef0f2ba0560..c53eac20b989 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -7,6 +7,7 @@ #ifndef ATH12K_DP_H #define ATH12K_DP_H +#include "dp_stats.h" #include "hw.h" #include "dp_htt.h" #include "dp_cmn.h" @@ -23,6 +24,15 @@ struct ath12k_ext_irq_grp; struct ath12k_dp_rx_tid; struct ath12k_dp_rx_tid_rxq; +struct ath12k_dp_profile_params { + u32 tx_comp_ring_size; + u32 rxdma_monitor_buf_ring_size; + u32 rxdma_monitor_dst_ring_size; + u32 num_pool_tx_desc; + u32 rx_desc_count; + u32 rx_release_ring_size; +}; + #define DP_MON_PURGE_TIMEOUT_MS 100 #define DP_MON_SERVICE_BUDGET 128 @@ -52,7 +62,7 @@ struct dp_rxdma_ring { int bufs_max; }; -#define ATH12K_TX_COMPL_NEXT(ab, x) (((x) + 1) % DP_TX_COMP_RING_SIZE(ab)) +#define ATH12K_TX_COMPL_NEXT(ring_size, x) (((x) + 1) % (ring_size)) struct dp_tx_ring { u8 tcl_data_ring_id; @@ -192,16 +202,11 @@ struct ath12k_pdev_dp { #define DP_WBM_RELEASE_RING_SIZE 64 #define DP_TCL_DATA_RING_SIZE 512 -#define DP_TX_COMP_RING_SIZE(ab) \ - ((ab)->profile_param->dp_params.tx_comp_ring_size) -#define DP_TX_IDR_SIZE(ab) DP_TX_COMP_RING_SIZE(ab) #define DP_TCL_CMD_RING_SIZE 32 #define DP_TCL_STATUS_RING_SIZE 32 #define DP_REO_DST_RING_MAX 8 #define DP_REO_DST_RING_SIZE 2048 #define DP_REO_REINJECT_RING_SIZE 32 -#define DP_RX_RELEASE_RING_SIZE(ab) \ - ((ab)->profile_param->dp_params.rx_release_ring_size) #define DP_REO_EXCEPTION_RING_SIZE 128 #define DP_REO_CMD_RING_SIZE 256 #define DP_REO_STATUS_RING_SIZE 2048 @@ -210,10 +215,6 @@ struct ath12k_pdev_dp { #define DP_RXDMA_REFILL_RING_SIZE 2048 #define DP_RXDMA_ERR_DST_RING_SIZE 1024 #define DP_RXDMA_MON_STATUS_RING_SIZE 1024 -#define DP_RXDMA_MONITOR_BUF_RING_SIZE(ab) \ - ((ab)->profile_param->dp_params.rxdma_monitor_buf_ring_size) -#define DP_RXDMA_MONITOR_DST_RING_SIZE(ab) \ - ((ab)->profile_param->dp_params.rxdma_monitor_dst_ring_size) #define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096 #define DP_TX_MONITOR_BUF_RING_SIZE 4096 #define DP_TX_MONITOR_DEST_RING_SIZE 2048 @@ -247,12 +248,6 @@ struct ath12k_pdev_dp { #define ATH12K_SHADOW_DP_TIMER_INTERVAL 20 #define ATH12K_SHADOW_CTRL_TIMER_INTERVAL 10 -#define ATH12K_NUM_POOL_TX_DESC(ab) \ - ((ab)->profile_param->dp_params.num_pool_tx_desc) -/* TODO: revisit this count during testing */ -#define ATH12K_RX_DESC_COUNT(ab) \ - ((ab)->profile_param->dp_params.rx_desc_count) - #define ATH12K_PAGE_SIZE PAGE_SIZE /* Total 1024 entries in PPT, i.e 4K/4 considering 4K aligned @@ -263,21 +258,7 @@ struct ath12k_pdev_dp { /* Total 512 entries in a SPT, i.e 4K Page/8 */ #define ATH12K_MAX_SPT_ENTRIES 512 -#define ATH12K_NUM_RX_SPT_PAGES(ab) ((ATH12K_RX_DESC_COUNT(ab)) / \ - ATH12K_MAX_SPT_ENTRIES) - -#define ATH12K_TX_SPT_PAGES_PER_POOL(ab) (ATH12K_NUM_POOL_TX_DESC(ab) / \ - ATH12K_MAX_SPT_ENTRIES) -#define ATH12K_NUM_TX_SPT_PAGES(ab) (ATH12K_TX_SPT_PAGES_PER_POOL(ab) * \ - ATH12K_HW_MAX_QUEUES) - #define ATH12K_TX_SPT_PAGE_OFFSET 0 -#define ATH12K_RX_SPT_PAGE_OFFSET(ab) ATH12K_NUM_TX_SPT_PAGES(ab) - -/* The SPT pages are divided for RX and TX, first block for RX - * and remaining for TX - */ -#define ATH12K_NUM_TX_SPT_PAGE_START(ab) ATH12K_NUM_RX_SPT_PAGES(ab) #define ATH12K_DP_RX_DESC_MAGIC 0xBABABABA @@ -429,19 +410,27 @@ struct ath12k_dp_arch_ops { struct ath12k_device_dp_tx_err_stats { /* TCL Ring Descriptor unavailable */ u32 desc_na[DP_TCL_NUM_RING_MAX]; + /* TX descriptor pool exhausted (per pool_id / traffic class) */ + u32 txbuf_na[ATH12K_HW_MAX_QUEUES]; /* Other failures during dp_tx due to mem allocation failure * idr unavailable etc. */ atomic_t misc_fail; }; +struct ath12k_device_dp_rx_wbm_err_stats { + u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; + u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX]; + u32 drop[WBM_ERR_DROP_MAX]; + u32 sw_desc_fallback; +}; + struct ath12k_device_dp_stats { u32 err_ring_pkts; u32 invalid_rbm; - u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; - u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX]; u32 hal_reo_error[DP_REO_DST_RING_MAX]; struct ath12k_device_dp_tx_err_stats tx_err; + struct ath12k_device_dp_rx_wbm_err_stats wbm_err; u32 reo_rx[DP_REO_DST_RING_MAX][ATH12K_MAX_DEVICES]; u32 rx_wbm_rel_source[HAL_WBM_REL_SRC_MODULE_MAX][ATH12K_MAX_DEVICES]; u32 tqm_rel_reason[MAX_TQM_RELEASE_REASON]; @@ -450,6 +439,7 @@ struct ath12k_device_dp_stats { u32 tx_enqueued[DP_TCL_NUM_RING_MAX]; u32 tx_completed[DP_TCL_NUM_RING_MAX]; u32 reo_excep_msdu_buf_type; + u32 sent_to_stack[DP_REO_DST_RING_MAX][ATH12K_MAX_DEVICES]; }; struct ath12k_dp { @@ -680,6 +670,66 @@ ath12k_dp_to_pdev_dp(struct ath12k_dp *dp, u8 pdev_idx) return rcu_dereference(dp->dp_pdevs[pdev_idx]); } +static inline u32 +ath12k_dp_tx_comp_ring_size(const struct ath12k_dp_profile_params *p) +{ + return p->tx_comp_ring_size; +} + +static inline u32 +ath12k_dp_rxdma_monitor_buf_ring_size(const struct ath12k_dp_profile_params *p) +{ + return p->rxdma_monitor_buf_ring_size; +} + +static inline u32 +ath12k_dp_rxdma_monitor_dst_ring_size(const struct ath12k_dp_profile_params *p) +{ + return p->rxdma_monitor_dst_ring_size; +} + +static inline u32 +ath12k_dp_num_pool_tx_desc(const struct ath12k_dp_profile_params *p) +{ + return p->num_pool_tx_desc; +} + +static inline u32 +ath12k_dp_tx_spt_pages_per_pool(const struct ath12k_dp_profile_params *p) +{ + return ath12k_dp_num_pool_tx_desc(p) / ATH12K_MAX_SPT_ENTRIES; +} + +static inline u32 +ath12k_dp_num_tx_spt_pages(const struct ath12k_dp_profile_params *p) +{ + return ath12k_dp_tx_spt_pages_per_pool(p) * ATH12K_HW_MAX_QUEUES; +} + +static inline u32 +ath12k_dp_rx_spt_page_offset(const struct ath12k_dp_profile_params *p) +{ + return ath12k_dp_num_tx_spt_pages(p); +} + +static inline u32 +ath12k_dp_rx_desc_count(const struct ath12k_dp_profile_params *p) +{ + return p->rx_desc_count; +} + +static inline u32 +ath12k_dp_num_rx_spt_pages(const struct ath12k_dp_profile_params *p) +{ + return ath12k_dp_rx_desc_count(p) / ATH12K_MAX_SPT_ENTRIES; +} + +static inline u32 +ath12k_dp_rx_release_ring_size(const struct ath12k_dp_profile_params *p) +{ + return p->rx_release_ring_size; +} + void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif); void ath12k_dp_partner_cc_init(struct ath12k_base *ab); int ath12k_dp_pdev_alloc(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 1faf1896d0ab..709507d44d8e 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -81,24 +81,23 @@ fail_alloc_skb: } EXPORT_SYMBOL(ath12k_dp_rx_alloc_mon_status_buf); -u32 ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id) +bool ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id) { - u32 ret = 0; - if ((*ppdu_id < msdu_ppdu_id) && ((msdu_ppdu_id - *ppdu_id) < DP_NOT_PPDU_ID_WRAP_AROUND)) { /* Hold on mon dest ring, and reap mon status ring. */ *ppdu_id = msdu_ppdu_id; - ret = msdu_ppdu_id; - } else if ((*ppdu_id > msdu_ppdu_id) && - ((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) { + return true; + } + if ((*ppdu_id > msdu_ppdu_id) && + ((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) { /* PPDU ID has exceeded the maximum value and will * restart from 0. */ *ppdu_id = msdu_ppdu_id; - ret = msdu_ppdu_id; + return true; } - return ret; + return false; } EXPORT_SYMBOL(ath12k_dp_mon_comp_ppduid); diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h index 162cdcaa57a7..f352655eae9d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.h +++ b/drivers/net/wireless/ath/ath12k/dp_mon.h @@ -100,7 +100,7 @@ struct sk_buff *ath12k_dp_rx_alloc_mon_status_buf(struct ath12k_base *ab, struct dp_rxdma_mon_ring *rx_ring, int *buf_id); -u32 ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id); +bool ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id); int ath12k_dp_mon_parse_status_buf(struct ath12k_pdev_dp *dp_pdev, struct ath12k_mon_data *pmon, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 41ac0a4072ae..cfaf26ae2720 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -330,16 +330,20 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) { struct ath12k_pdev_dp *dp = &ar->dp; struct ath12k_base *ab = ar->ab; + u32 monitor_dst_ring_size; + u32 mac_id = dp->mac_id; int i; int ret; - u32 mac_id = dp->mac_id; + + monitor_dst_ring_size = + ath12k_dp_rxdma_monitor_dst_ring_size(&ab->profile_param->dp_params); for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { ret = ath12k_dp_srng_setup(ar->ab, &dp->rxdma_mon_dst_ring[i], HAL_RXDMA_MONITOR_DST, 0, mac_id + i, - DP_RXDMA_MONITOR_DST_RING_SIZE(ab)); + monitor_dst_ring_size); if (ret) { ath12k_warn(ar->ab, "failed to setup HAL_RXDMA_MONITOR_DST\n"); @@ -1200,27 +1204,6 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu } EXPORT_SYMBOL(ath12k_dp_rx_h_undecap); -struct ath12k_dp_link_peer * -ath12k_dp_rx_h_find_link_peer(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, - struct hal_rx_desc_data *rx_info) -{ - struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - struct ath12k_dp_link_peer *peer = NULL; - struct ath12k_dp *dp = dp_pdev->dp; - - lockdep_assert_held(&dp->dp_lock); - - peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id); - - if (peer) - return peer; - - if (rx_info->addr2_present) - peer = ath12k_dp_link_peer_find_by_addr(dp, rx_info->addr2); - - return peer; -} - static void ath12k_dp_rx_h_rate(struct ath12k_pdev_dp *dp_pdev, struct hal_rx_desc_data *rx_info) { @@ -1704,6 +1687,8 @@ int ath12k_dp_rx_htt_setup(struct ath12k_base *ab) int ath12k_dp_rx_alloc(struct ath12k_base *ab) { + const struct ath12k_dp_profile_params *dp_params = &ab->profile_param->dp_params; + u32 monitor_buf_ring_size = ath12k_dp_rxdma_monitor_buf_ring_size(dp_params); struct ath12k_dp *dp = ath12k_ab_to_dp(ab); struct dp_srng *srng; int i, ret; @@ -1748,7 +1733,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring, HAL_RXDMA_MONITOR_BUF, 0, 0, - DP_RXDMA_MONITOR_BUF_RING_SIZE(ab)); + monitor_buf_ring_size); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index 0660db070e92..82700474548a 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -237,9 +237,6 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab, struct hal_rx_desc *desc); -struct ath12k_dp_link_peer * -ath12k_dp_rx_h_find_link_peer(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, - struct hal_rx_desc_data *rx_info); u8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab, struct hal_rx_desc *desc); u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab, diff --git a/drivers/net/wireless/ath/ath12k/dp_stats.h b/drivers/net/wireless/ath/ath12k/dp_stats.h new file mode 100644 index 000000000000..1a05256dbf74 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/dp_stats.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef ATH12K_DP_STATS_H +#define ATH12K_DP_STATS_H + +enum ath12k_wbm_err_drop_reason { + WBM_ERR_DROP_GET_SW_DESC, + WBM_ERR_DROP_DESC_PARSE, + WBM_ERR_DROP_INV_HW_ID, + WBM_ERR_DROP_NULL_PRTNR_DP, + WBM_ERR_DROP_NULL_PROC_DP, + WBM_ERR_DROP_NULL_PDEV, + WBM_ERR_DROP_NULL_AR, + WBM_ERR_DROP_CAC_RUNNING, + WBM_ERR_DROP_SG, + WBM_ERR_DROP_INV_NWIFI_HDR, + WBM_ERR_DROP_REO_GENERIC, + WBM_ERR_DROP_RXDMA_GENERIC, + WBM_ERR_DROP_MAX, +}; + +#endif /* ATH12K_DP_STATS_H */ diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index e790de5737db..1e652dc0d247 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -166,6 +166,7 @@ struct ath12k_hw_params { u8 max_radios; bool single_pdev_only:1; u32 qmi_service_ins_id; + u32 qmi_max_chunk_size; bool internal_sleep_clock:1; const struct ath12k_hw_ops *hw_ops; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d4116ba0da08..196b807210de 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9739,6 +9739,7 @@ static int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable) static int ath12k_mac_start(struct ath12k *ar) { + const struct ath12k_dp_profile_params *dp_params; struct ath12k_hw *ah = ar->ah; struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev = ar->pdev; @@ -9747,6 +9748,8 @@ static int ath12k_mac_start(struct ath12k *ar) lockdep_assert_held(&ah->hw_mutex); lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + dp_params = &ab->profile_param->dp_params; + ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1, pdev->pdev_id); @@ -9795,7 +9798,7 @@ static int ath12k_mac_start(struct ath12k *ar) if (ab->hw_params->supports_cong_ctrl_max_msdus) { ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_SET_CONG_CTRL_MAX_MSDUS, - ATH12K_NUM_POOL_TX_DESC(ab), + ath12k_dp_num_pool_tx_desc(dp_params), pdev->pdev_id); if (ret) { ath12k_err(ab, diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 50082505c882..817bd820623d 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -14,11 +14,11 @@ #include #include #include +#include #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 #define HOST_CSTATE_BIT 0x04 #define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08 -#define ATH12K_QMI_MAX_CHUNK_SIZE 2097152 static const struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { { @@ -2584,46 +2584,63 @@ static void ath12k_qmi_free_mlo_mem_chunk(struct ath12k_base *ab, mlo_chunk->v.ioaddr = NULL; } else if (mlo_chunk->v.addr) { dma_free_coherent(ab->dev, - mlo_chunk->size, - mlo_chunk->v.addr, - mlo_chunk->paddr); + mlo_chunk->total_size, + mlo_chunk->vaddr_unaligned, + mlo_chunk->paddr_unaligned); + mlo_chunk->vaddr_unaligned = NULL; mlo_chunk->v.addr = NULL; } mlo_chunk->paddr = 0; + mlo_chunk->paddr_unaligned = 0; mlo_chunk->size = 0; - if (fixed_mem) + mlo_chunk->total_size = 0; + + if (fixed_mem) { chunk->v.ioaddr = NULL; - else + } else { chunk->v.addr = NULL; + chunk->vaddr_unaligned = NULL; + } chunk->paddr = 0; + chunk->paddr_unaligned = 0; chunk->size = 0; + chunk->total_size = 0; } static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab) { struct ath12k_hw_group *ag = ab->ag; + struct target_mem_chunk *chunk; int i, mlo_idx; for (i = 0, mlo_idx = 0; i < ab->qmi.mem_seg_count; i++) { - if (ab->qmi.target_mem[i].type == MLO_GLOBAL_MEM_REGION_TYPE) { + chunk = &ab->qmi.target_mem[i]; + + if (chunk->type == MLO_GLOBAL_MEM_REGION_TYPE) { ath12k_qmi_free_mlo_mem_chunk(ab, - &ab->qmi.target_mem[i], + chunk, mlo_idx++); } else { if (test_bit(ATH12K_FLAG_FIXED_MEM_REGION, &ab->dev_flags) && - ab->qmi.target_mem[i].v.ioaddr) { - iounmap(ab->qmi.target_mem[i].v.ioaddr); - ab->qmi.target_mem[i].v.ioaddr = NULL; + chunk->v.ioaddr) { + iounmap(chunk->v.ioaddr); + chunk->v.ioaddr = NULL; } else { - if (!ab->qmi.target_mem[i].v.addr) + if (!chunk->v.addr) continue; dma_free_coherent(ab->dev, - ab->qmi.target_mem[i].prev_size, - ab->qmi.target_mem[i].v.addr, - ab->qmi.target_mem[i].paddr); - ab->qmi.target_mem[i].v.addr = NULL; + chunk->total_size, + chunk->vaddr_unaligned, + chunk->paddr_unaligned); + chunk->vaddr_unaligned = NULL; + chunk->v.addr = NULL; } + + chunk->paddr = 0; + chunk->paddr_unaligned = 0; + chunk->size = 0; + chunk->total_size = 0; } } @@ -2636,6 +2653,10 @@ static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab) static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab, struct target_mem_chunk *chunk) { + dma_addr_t paddr; + size_t size; + void *vaddr; + /* Firmware reloads in recovery/resume. * In such cases, no need to allocate memory for FW again. */ @@ -2645,29 +2666,56 @@ static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab, goto this_chunk_done; /* cannot reuse the existing chunk */ - dma_free_coherent(ab->dev, chunk->prev_size, - chunk->v.addr, chunk->paddr); + dma_free_coherent(ab->dev, chunk->total_size, + chunk->vaddr_unaligned, chunk->paddr_unaligned); chunk->v.addr = NULL; + chunk->vaddr_unaligned = NULL; + chunk->paddr_unaligned = 0; + chunk->total_size = 0; } - chunk->v.addr = dma_alloc_coherent(ab->dev, - chunk->size, - &chunk->paddr, + /* + * Each unaligned chunk costs the firmware extra TLB entries when + * mapping it, and too many unaligned chunks exhaust the TLB and + * crash the firmware, so align the base to 64 KB. The DMA + * allocator only guarantees page alignment, but a natural + * allocation is often already 64 KB aligned. Try the exact size + * first and keep it when it happens to be aligned; only fall back + * to over-allocating and rounding up when it is not. + */ + size = chunk->size; + vaddr = dma_alloc_coherent(ab->dev, size, &paddr, + GFP_KERNEL | __GFP_NOWARN); + if (vaddr && !IS_ALIGNED(paddr, SZ_64K)) { + dma_free_coherent(ab->dev, size, vaddr, paddr); + + size = chunk->size + SZ_64K - PAGE_SIZE; + vaddr = dma_alloc_coherent(ab->dev, size, &paddr, GFP_KERNEL | __GFP_NOWARN); - if (!chunk->v.addr) { - if (chunk->size > ATH12K_QMI_MAX_CHUNK_SIZE) { + } + + if (!vaddr) { + if (chunk->size > ab->hw_params->qmi_max_chunk_size) { ab->qmi.target_mem_delayed = true; ath12k_warn(ab, - "qmi dma allocation failed (%u B type %u), will try later with small size\n", - chunk->size, + "qmi dma allocation failed (%zu B type %u), will try later with small size\n", + size, chunk->type); ath12k_qmi_free_target_mem_chunk(ab); return -EAGAIN; } - ath12k_warn(ab, "memory allocation failure for %u size: %u\n", - chunk->type, chunk->size); + ath12k_warn(ab, "memory allocation failure for %u size: %zu\n", + chunk->type, size); return -ENOMEM; } + + chunk->vaddr_unaligned = vaddr; + chunk->paddr_unaligned = paddr; + chunk->total_size = size; + + chunk->paddr = ALIGN(paddr, SZ_64K); + chunk->v.addr = (u8 *)vaddr + (chunk->paddr - paddr); + chunk->prev_type = chunk->type; chunk->prev_size = chunk->size; this_chunk_done: diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 6da10f3cb597..1b1c88906f1e 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -100,6 +100,10 @@ struct target_mem_chunk { void __iomem *ioaddr; void *addr; } v; + + dma_addr_t paddr_unaligned; + void *vaddr_unaligned; + u32 total_size; }; struct target_info { diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c index ded7d56cd79b..1e29c13ad66d 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c @@ -2675,6 +2675,8 @@ ath12k_wifi7_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id, if (pmon->mon_last_linkdesc_paddr == paddr) { pmon->rx_mon_stats.dup_mon_linkdesc_cnt++; spin_unlock_bh(&pmon->mon_lock); + kfree_skb_list(*head_msdu); + *head_msdu = NULL; return rx_bufs_used; } @@ -2718,7 +2720,6 @@ ath12k_wifi7_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id, i, (unsigned long)rxcb->paddr, (unsigned long)msdu_list.paddr[i]); drop_mpdu = true; - continue; } if (!rxcb->unmapped) { dma_unmap_single(ar->ab->dev, rxcb->paddr, @@ -2801,7 +2802,7 @@ next_msdu: if (last) last->next = NULL; - *tail_msdu = msdu; + *tail_msdu = last; if (msdu_cnt == 0) *npackets = 1; @@ -2826,7 +2827,6 @@ ath12k_wifi7_dp_rx_mon_dest_process(struct ath12k *ar, int mac_id, struct ath12k_base *ab = ar->ab; struct ath12k_dp *dp = ath12k_ab_to_dp(ab); void *ring_entry, *mon_dst_srng; - struct dp_mon_mpdu *tmp_mpdu; LIST_HEAD(rx_desc_used_list); struct hal_srng *srng; @@ -2892,18 +2892,16 @@ ath12k_wifi7_dp_rx_mon_dest_process(struct ath12k *ar, int mac_id, } if (head_msdu && tail_msdu) { - tmp_mpdu = kzalloc_obj(*tmp_mpdu, GFP_ATOMIC); - if (!tmp_mpdu) - break; + struct dp_mon_mpdu tmp_mpdu = { + .head = head_msdu, + .tail = tail_msdu, + .err_bitmap = pmon->err_bitmap, + .decap_format = pmon->decap_format, + }; - tmp_mpdu->head = head_msdu; - tmp_mpdu->tail = tail_msdu; - tmp_mpdu->err_bitmap = pmon->err_bitmap; - tmp_mpdu->decap_format = pmon->decap_format; - ath12k_wifi7_dp_mon_rx_deliver(&ar->dp, tmp_mpdu, + ath12k_wifi7_dp_mon_rx_deliver(&ar->dp, &tmp_mpdu, &pmon->mon_ppdu_info, napi); rx_mon_stats->dest_mpdu_done++; - kfree(tmp_mpdu); } ring_entry = ath12k_hal_srng_dst_get_next_entry(ar->ab, diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c index 8b722ee0ad8f..a32c804403e8 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c @@ -12,6 +12,15 @@ #include "hal_wcn7850.h" #include "hal_qcc2072.h" +static void +ath12k_wifi7_dp_rx_wbm_err_free_skb(struct ath12k_dp *dp, + struct sk_buff *msdu, + enum ath12k_wbm_err_drop_reason drop_reason) +{ + dp->device_stats.wbm_err.drop[drop_reason]++; + dev_kfree_skb_any(msdu); +} + static u16 ath12k_wifi7_dp_rx_get_peer_id(struct ath12k_dp *dp, enum ath12k_peer_metadata_version ver, __le32 peer_metadata) @@ -642,7 +651,10 @@ ath12k_wifi7_dp_rx_process_received_packets(struct ath12k_dp *dp, dev_kfree_skb_any(msdu); continue; } - + if (likely(ring_id < DP_REO_DST_RING_MAX)) + dp->device_stats.sent_to_stack[ring_id][partner_dp->device_id]++; + else + WARN_ON_ONCE(1); ath12k_dp_rx_deliver_msdu(dp_pdev, napi, msdu, &rx_info); } @@ -1614,6 +1626,7 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev, /* First buffer will be freed by the caller, so deduct it's length */ msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - hal_rx_desc_sz); ath12k_wifi7_dp_rx_null_q_desc_sg_drop(dp, msdu_len, msdu_list); + dp->device_stats.wbm_err.drop[WBM_ERR_DROP_SG]++; return -EINVAL; } @@ -1649,8 +1662,10 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev, skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); } - if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu, rx_info))) + if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu, rx_info))) { + dp->device_stats.wbm_err.drop[WBM_ERR_DROP_INV_NWIFI_HDR]++; return -EINVAL; + } ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info); @@ -1763,7 +1778,10 @@ static bool ath12k_wifi7_dp_rx_h_rxdma_err(struct ath12k_pdev_dp *dp_pdev, struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); bool drop = false; - dp->device_stats.rxdma_error[rxcb->err_code]++; + if (likely(rxcb->err_code < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX)) + dp->device_stats.wbm_err.rxdma_error[rxcb->err_code]++; + else + WARN_ON_ONCE(1); switch (rxcb->err_code) { case HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR: @@ -1780,6 +1798,7 @@ static bool ath12k_wifi7_dp_rx_h_rxdma_err(struct ath12k_pdev_dp *dp_pdev, /* TODO: Review other rxdma error code to check if anything is * worth reporting to mac80211 */ + dp->device_stats.wbm_err.drop[WBM_ERR_DROP_RXDMA_GENERIC]++; drop = true; break; } @@ -1796,7 +1815,10 @@ static bool ath12k_wifi7_dp_rx_h_reo_err(struct ath12k_pdev_dp *dp_pdev, struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); bool drop = false; - dp->device_stats.reo_error[rxcb->err_code]++; + if (likely(rxcb->err_code < HAL_REO_DEST_RING_ERROR_CODE_MAX)) + dp->device_stats.wbm_err.reo_error[rxcb->err_code]++; + else + WARN_ON_ONCE(1); switch (rxcb->err_code) { case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO: @@ -1813,6 +1835,7 @@ static bool ath12k_wifi7_dp_rx_h_reo_err(struct ath12k_pdev_dp *dp_pdev, /* TODO: Review other errors and process them to mac80211 * as appropriate. */ + dp->device_stats.wbm_err.drop[WBM_ERR_DROP_REO_GENERIC]++; drop = true; break; } @@ -1935,6 +1958,7 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp, ret = ath12k_wifi7_hal_wbm_desc_parse_err(dp, rx_desc, &err_info); if (ret) { + dp->device_stats.wbm_err.drop[WBM_ERR_DROP_DESC_PARSE]++; ath12k_warn(ab, "failed to parse rx error in wbm_rel ring desc %d\n", ret); continue; @@ -1944,8 +1968,10 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp, /* retry manual desc retrieval if hw cc is not done */ if (!desc_info) { + dp->device_stats.wbm_err.sw_desc_fallback++; desc_info = ath12k_dp_get_rx_desc(dp, err_info.cookie); if (!desc_info) { + dp->device_stats.wbm_err.drop[WBM_ERR_DROP_GET_SW_DESC]++; ath12k_warn(ab, "Invalid cookie in DP WBM rx error descriptor retrieval: 0x%x\n", err_info.cookie); continue; @@ -1961,7 +1987,8 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp, device_id = desc_info->device_id; partner_dp = ath12k_dp_hw_grp_to_dp(dp_hw_grp, device_id); if (unlikely(!partner_dp)) { - dev_kfree_skb_any(msdu); + ath12k_wifi7_dp_rx_wbm_err_free_skb(dp, msdu, + WBM_ERR_DROP_NULL_PRTNR_DP); /* In any case continuation bit is set * in the previous record, cleanup scatter_msdu_list @@ -2007,7 +2034,8 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp, hw_link_id = ath12k_dp_rx_get_msdu_src_link(partner_dp->hal, msdu_data); if (hw_link_id >= ATH12K_GROUP_MAX_RADIO) { - dev_kfree_skb_any(msdu); + ath12k_wifi7_dp_rx_wbm_err_free_skb(dp, msdu, + WBM_ERR_DROP_INV_HW_ID); /* In any case continuation bit is set * in the previous record, cleanup scatter_msdu_list @@ -2068,7 +2096,8 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp, ath12k_dbg(ab, ATH12K_DBG_DATA, "Unable to process WBM error msdu due to invalid hw link id %d device id %d\n", hw_link_id, device_id); - dev_kfree_skb_any(msdu); + ath12k_wifi7_dp_rx_wbm_err_free_skb(dp, msdu, + WBM_ERR_DROP_NULL_PROC_DP); continue; } @@ -2077,18 +2106,21 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp, dp_pdev = ath12k_dp_to_pdev_dp(partner_dp, pdev_idx); if (!dp_pdev) { - dev_kfree_skb_any(msdu); + ath12k_wifi7_dp_rx_wbm_err_free_skb(dp, msdu, + WBM_ERR_DROP_NULL_PDEV); continue; } ar = ath12k_pdev_dp_to_ar(dp_pdev); if (!ar || !rcu_dereference(ar->ab->pdevs_active[pdev_idx])) { - dev_kfree_skb_any(msdu); + ath12k_wifi7_dp_rx_wbm_err_free_skb(dp, msdu, + WBM_ERR_DROP_NULL_AR); continue; } if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) { - dev_kfree_skb_any(msdu); + ath12k_wifi7_dp_rx_wbm_err_free_skb(dp, msdu, + WBM_ERR_DROP_CAC_RUNNING); continue; } diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c index 7c12dba4cc51..41abf1865702 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c @@ -167,8 +167,10 @@ tcl_ring_sel: tx_ring = &dp->tx_ring[ti.ring_id]; tx_desc = ath12k_dp_tx_assign_buffer(dp, pool_id); - if (!tx_desc) + if (!tx_desc) { + dp->device_stats.tx_err.txbuf_na[pool_id]++; return -ENOMEM; + } dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, arvif->link_id); @@ -582,18 +584,19 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_dp *dp, void *desc, { struct htt_tx_wbm_completion *status_desc; struct ath12k_dp_htt_wbm_tx_status ts = {}; - enum hal_wbm_htt_tx_comp_status wbm_status; + enum hal_wbm_htt_tx_comp_status htt_status; u16 peer_id; status_desc = desc; - wbm_status = le32_get_bits(status_desc->info0, + htt_status = le32_get_bits(status_desc->info0, HTT_TX_WBM_COMP_INFO0_STATUS); - dp->device_stats.fw_tx_status[wbm_status]++; + if (likely(htt_status < MAX_FW_TX_STATUS)) + dp->device_stats.fw_tx_status[htt_status]++; - switch (wbm_status) { + switch (htt_status) { case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK: - ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); + ts.acked = true; ts.ack_rssi = le32_get_bits(status_desc->info2, HTT_TX_WBM_COMP_INFO2_ACK_RSSI); @@ -615,7 +618,7 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_dp *dp, void *desc, */ break; default: - ath12k_warn(dp->ab, "Unknown htt wbm tx status %d\n", wbm_status); + ath12k_warn(dp->ab, "Unknown htt tx status %d\n", htt_status); break; } } @@ -929,12 +932,14 @@ void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id) u64 desc_va; enum hal_wbm_rel_src_module buf_rel_source; enum hal_wbm_tqm_rel_reason rel_status; + u32 ring_size; spin_lock_bh(&status_ring->lock); + ring_size = ath12k_dp_tx_comp_ring_size(&ab->profile_param->dp_params); ath12k_hal_srng_access_begin(ab, status_ring); - while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) != + while (ATH12K_TX_COMPL_NEXT(ring_size, tx_ring->tx_status_head) != tx_ring->tx_status_tail) { desc = ath12k_hal_srng_dst_get_next_entry(ab, status_ring); if (!desc) @@ -943,11 +948,11 @@ void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id) memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], desc, sizeof(*desc)); tx_ring->tx_status_head = - ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head); + ATH12K_TX_COMPL_NEXT(ring_size, tx_ring->tx_status_head); } if (ath12k_hal_srng_dst_peek(ab, status_ring) && - (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) == + (ATH12K_TX_COMPL_NEXT(ring_size, tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { /* TODO: Process pending tx_status messages when kfifo_is_full() */ ath12k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); @@ -957,13 +962,13 @@ void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id) spin_unlock_bh(&status_ring->lock); - while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail) != + while (ATH12K_TX_COMPL_NEXT(ring_size, tx_ring->tx_status_tail) != tx_ring->tx_status_head) { struct hal_wbm_completion_ring_tx *tx_status; u32 desc_id; tx_ring->tx_status_tail = - ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail); + ATH12K_TX_COMPL_NEXT(ring_size, tx_ring->tx_status_tail); tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; ath12k_wifi7_dp_tx_status_parse(dp, tx_status, &ts); @@ -991,11 +996,17 @@ void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id) /* Find the HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE value */ buf_rel_source = le32_get_bits(tx_status->info0, HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE); - dp->device_stats.tx_wbm_rel_source[buf_rel_source]++; + if (likely(buf_rel_source < HAL_WBM_REL_SRC_MODULE_MAX)) + dp->device_stats.tx_wbm_rel_source[buf_rel_source]++; + else + WARN_ON_ONCE(1); rel_status = le32_get_bits(tx_status->info0, HAL_WBM_COMPL_TX_INFO0_TQM_RELEASE_REASON); - dp->device_stats.tqm_rel_reason[rel_status]++; + if (likely(rel_status < MAX_TQM_RELEASE_REASON)) + dp->device_stats.tqm_rel_reason[rel_status]++; + else + WARN_ON_ONCE(1); /* Release descriptor as soon as extracting necessary info * to reduce contention diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c index 49c693289709..60e7a36097f1 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c @@ -329,7 +329,10 @@ int ath12k_wifi7_hal_desc_reo_parse_err(struct ath12k_dp *dp, HAL_REO_DEST_RING_INFO0_PUSH_REASON); err_code = le32_get_bits(desc->info0, HAL_REO_DEST_RING_INFO0_ERROR_CODE); - dp->device_stats.reo_error[err_code]++; + if (likely(err_code < HAL_REO_DEST_RING_ERROR_CODE_MAX)) + dp->device_stats.wbm_err.reo_error[err_code]++; + else + WARN_ON_ONCE(1); if (push_reason != HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED && push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c index ae8df80928b0..aec7c652808c 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "../debug.h" #include "../core.h" @@ -369,6 +370,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .max_radios = 1, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274, + .qmi_max_chunk_size = SZ_2M, .internal_sleep_clock = false, .hw_ops = &qcn9274_ops, @@ -461,6 +463,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .max_radios = 1, .single_pdev_only = true, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850, + .qmi_max_chunk_size = SZ_512K, .internal_sleep_clock = true, .hw_ops = &wcn7850_ops, @@ -553,6 +556,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .max_radios = 2, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274, + .qmi_max_chunk_size = SZ_2M, .internal_sleep_clock = false, .hw_ops = &qcn9274_ops, @@ -643,6 +647,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .max_radios = 1, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ5332, + .qmi_max_chunk_size = SZ_2M, .internal_sleep_clock = false, .hw_ops = &qcn9274_ops, @@ -729,6 +734,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .max_radios = 1, .single_pdev_only = true, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850, + .qmi_max_chunk_size = SZ_512K, .internal_sleep_clock = true, .hw_ops = &qcc2072_ops, @@ -822,6 +828,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .max_radios = 1, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ5332, + .qmi_max_chunk_size = SZ_2M, .internal_sleep_clock = false, .hw_ops = &qcn9274_ops,