Path: blob/main/sys/contrib/dev/athk/ath11k/hal.c
105221 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.4* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.5*/6#if defined(__FreeBSD__)7#include <asm/io.h>8#endif9#include <linux/dma-mapping.h>10#include <linux/export.h>11#include "hal_tx.h"12#include "debug.h"13#include "hal_desc.h"14#include "hif.h"1516static const struct hal_srng_config hw_srng_config_template[] = {17/* TODO: max_rings can populated by querying HW capabilities */18{ /* REO_DST */19.start_ring_id = HAL_SRNG_RING_ID_REO2SW1,20.max_rings = 4,21.entry_size = sizeof(struct hal_reo_dest_ring) >> 2,22.lmac_ring = false,23.ring_dir = HAL_SRNG_DIR_DST,24.max_size = HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE,25},26{ /* REO_EXCEPTION */27/* Designating REO2TCL ring as exception ring. This ring is28* similar to other REO2SW rings though it is named as REO2TCL.29* Any of theREO2SW rings can be used as exception ring.30*/31.start_ring_id = HAL_SRNG_RING_ID_REO2TCL,32.max_rings = 1,33.entry_size = sizeof(struct hal_reo_dest_ring) >> 2,34.lmac_ring = false,35.ring_dir = HAL_SRNG_DIR_DST,36.max_size = HAL_REO_REO2TCL_RING_BASE_MSB_RING_SIZE,37},38{ /* REO_REINJECT */39.start_ring_id = HAL_SRNG_RING_ID_SW2REO,40.max_rings = 1,41.entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,42.lmac_ring = false,43.ring_dir = HAL_SRNG_DIR_SRC,44.max_size = HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE,45},46{ /* REO_CMD */47.start_ring_id = HAL_SRNG_RING_ID_REO_CMD,48.max_rings = 1,49.entry_size = (sizeof(struct hal_tlv_hdr) +50sizeof(struct hal_reo_get_queue_stats)) >> 2,51.lmac_ring = false,52.ring_dir = HAL_SRNG_DIR_SRC,53.max_size = HAL_REO_CMD_RING_BASE_MSB_RING_SIZE,54},55{ /* REO_STATUS */56.start_ring_id = HAL_SRNG_RING_ID_REO_STATUS,57.max_rings = 1,58.entry_size = (sizeof(struct hal_tlv_hdr) +59sizeof(struct hal_reo_get_queue_stats_status)) >> 2,60.lmac_ring = false,61.ring_dir = HAL_SRNG_DIR_DST,62.max_size = HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE,63},64{ /* TCL_DATA */65.start_ring_id = HAL_SRNG_RING_ID_SW2TCL1,66.max_rings = 3,67.entry_size = (sizeof(struct hal_tlv_hdr) +68sizeof(struct hal_tcl_data_cmd)) >> 2,69.lmac_ring = false,70.ring_dir = HAL_SRNG_DIR_SRC,71.max_size = HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE,72},73{ /* TCL_CMD */74.start_ring_id = HAL_SRNG_RING_ID_SW2TCL_CMD,75.max_rings = 1,76.entry_size = (sizeof(struct hal_tlv_hdr) +77sizeof(struct hal_tcl_gse_cmd)) >> 2,78.lmac_ring = false,79.ring_dir = HAL_SRNG_DIR_SRC,80.max_size = HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE,81},82{ /* TCL_STATUS */83.start_ring_id = HAL_SRNG_RING_ID_TCL_STATUS,84.max_rings = 1,85.entry_size = (sizeof(struct hal_tlv_hdr) +86sizeof(struct hal_tcl_status_ring)) >> 2,87.lmac_ring = false,88.ring_dir = HAL_SRNG_DIR_DST,89.max_size = HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE,90},91{ /* CE_SRC */92.start_ring_id = HAL_SRNG_RING_ID_CE0_SRC,93.max_rings = 12,94.entry_size = sizeof(struct hal_ce_srng_src_desc) >> 2,95.lmac_ring = false,96.ring_dir = HAL_SRNG_DIR_SRC,97.max_size = HAL_CE_SRC_RING_BASE_MSB_RING_SIZE,98},99{ /* CE_DST */100.start_ring_id = HAL_SRNG_RING_ID_CE0_DST,101.max_rings = 12,102.entry_size = sizeof(struct hal_ce_srng_dest_desc) >> 2,103.lmac_ring = false,104.ring_dir = HAL_SRNG_DIR_SRC,105.max_size = HAL_CE_DST_RING_BASE_MSB_RING_SIZE,106},107{ /* CE_DST_STATUS */108.start_ring_id = HAL_SRNG_RING_ID_CE0_DST_STATUS,109.max_rings = 12,110.entry_size = sizeof(struct hal_ce_srng_dst_status_desc) >> 2,111.lmac_ring = false,112.ring_dir = HAL_SRNG_DIR_DST,113.max_size = HAL_CE_DST_STATUS_RING_BASE_MSB_RING_SIZE,114},115{ /* WBM_IDLE_LINK */116.start_ring_id = HAL_SRNG_RING_ID_WBM_IDLE_LINK,117.max_rings = 1,118.entry_size = sizeof(struct hal_wbm_link_desc) >> 2,119.lmac_ring = false,120.ring_dir = HAL_SRNG_DIR_SRC,121.max_size = HAL_WBM_IDLE_LINK_RING_BASE_MSB_RING_SIZE,122},123{ /* SW2WBM_RELEASE */124.start_ring_id = HAL_SRNG_RING_ID_WBM_SW_RELEASE,125.max_rings = 1,126.entry_size = sizeof(struct hal_wbm_release_ring) >> 2,127.lmac_ring = false,128.ring_dir = HAL_SRNG_DIR_SRC,129.max_size = HAL_SW2WBM_RELEASE_RING_BASE_MSB_RING_SIZE,130},131{ /* WBM2SW_RELEASE */132.start_ring_id = HAL_SRNG_RING_ID_WBM2SW0_RELEASE,133.max_rings = 5,134.entry_size = sizeof(struct hal_wbm_release_ring) >> 2,135.lmac_ring = false,136.ring_dir = HAL_SRNG_DIR_DST,137.max_size = HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE,138},139{ /* RXDMA_BUF */140.start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF,141.max_rings = 2,142.entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,143.lmac_ring = true,144.ring_dir = HAL_SRNG_DIR_SRC,145.max_size = HAL_RXDMA_RING_MAX_SIZE,146},147{ /* RXDMA_DST */148.start_ring_id = HAL_SRNG_RING_ID_WMAC1_RXDMA2SW0,149.max_rings = 1,150.entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,151.lmac_ring = true,152.ring_dir = HAL_SRNG_DIR_DST,153.max_size = HAL_RXDMA_RING_MAX_SIZE,154},155{ /* RXDMA_MONITOR_BUF */156.start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA2_BUF,157.max_rings = 1,158.entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,159.lmac_ring = true,160.ring_dir = HAL_SRNG_DIR_SRC,161.max_size = HAL_RXDMA_RING_MAX_SIZE,162},163{ /* RXDMA_MONITOR_STATUS */164.start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_STATBUF,165.max_rings = 1,166.entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,167.lmac_ring = true,168.ring_dir = HAL_SRNG_DIR_SRC,169.max_size = HAL_RXDMA_RING_MAX_SIZE,170},171{ /* RXDMA_MONITOR_DST */172.start_ring_id = HAL_SRNG_RING_ID_WMAC1_RXDMA2SW1,173.max_rings = 1,174.entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,175.lmac_ring = true,176.ring_dir = HAL_SRNG_DIR_DST,177.max_size = HAL_RXDMA_RING_MAX_SIZE,178},179{ /* RXDMA_MONITOR_DESC */180.start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_DESC,181.max_rings = 1,182.entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,183.lmac_ring = true,184.ring_dir = HAL_SRNG_DIR_SRC,185.max_size = HAL_RXDMA_RING_MAX_SIZE,186},187{ /* RXDMA DIR BUF */188.start_ring_id = HAL_SRNG_RING_ID_RXDMA_DIR_BUF,189.max_rings = 1,190.entry_size = 8 >> 2, /* TODO: Define the struct */191.lmac_ring = true,192.ring_dir = HAL_SRNG_DIR_SRC,193.max_size = HAL_RXDMA_RING_MAX_SIZE,194},195};196197static int ath11k_hal_alloc_cont_rdp(struct ath11k_base *ab)198{199struct ath11k_hal *hal = &ab->hal;200size_t size;201202size = sizeof(u32) * HAL_SRNG_RING_ID_MAX;203hal->rdp.vaddr = dma_alloc_coherent(ab->dev, size, &hal->rdp.paddr,204GFP_KERNEL);205if (!hal->rdp.vaddr)206return -ENOMEM;207208return 0;209}210211static void ath11k_hal_free_cont_rdp(struct ath11k_base *ab)212{213struct ath11k_hal *hal = &ab->hal;214size_t size;215216if (!hal->rdp.vaddr)217return;218219size = sizeof(u32) * HAL_SRNG_RING_ID_MAX;220dma_free_coherent(ab->dev, size,221hal->rdp.vaddr, hal->rdp.paddr);222hal->rdp.vaddr = NULL;223}224225static int ath11k_hal_alloc_cont_wrp(struct ath11k_base *ab)226{227struct ath11k_hal *hal = &ab->hal;228size_t size;229230size = sizeof(u32) * HAL_SRNG_NUM_LMAC_RINGS;231hal->wrp.vaddr = dma_alloc_coherent(ab->dev, size, &hal->wrp.paddr,232GFP_KERNEL);233if (!hal->wrp.vaddr)234return -ENOMEM;235236return 0;237}238239static void ath11k_hal_free_cont_wrp(struct ath11k_base *ab)240{241struct ath11k_hal *hal = &ab->hal;242size_t size;243244if (!hal->wrp.vaddr)245return;246247size = sizeof(u32) * HAL_SRNG_NUM_LMAC_RINGS;248dma_free_coherent(ab->dev, size,249hal->wrp.vaddr, hal->wrp.paddr);250hal->wrp.vaddr = NULL;251}252253static void ath11k_hal_ce_dst_setup(struct ath11k_base *ab,254struct hal_srng *srng, int ring_num)255{256struct hal_srng_config *srng_config = &ab->hal.srng_config[HAL_CE_DST];257u32 addr;258u32 val;259260addr = HAL_CE_DST_RING_CTRL +261srng_config->reg_start[HAL_SRNG_REG_GRP_R0] +262ring_num * srng_config->reg_size[HAL_SRNG_REG_GRP_R0];263264val = ath11k_hif_read32(ab, addr);265val &= ~HAL_CE_DST_R0_DEST_CTRL_MAX_LEN;266val |= FIELD_PREP(HAL_CE_DST_R0_DEST_CTRL_MAX_LEN,267srng->u.dst_ring.max_buffer_length);268ath11k_hif_write32(ab, addr, val);269}270271static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab,272struct hal_srng *srng)273{274struct ath11k_hal *hal = &ab->hal;275u32 val;276u64 hp_addr;277u32 reg_base;278279reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];280281if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) {282ath11k_hif_write32(ab, reg_base +283HAL_REO1_RING_MSI1_BASE_LSB_OFFSET(ab),284srng->msi_addr);285286val = FIELD_PREP(HAL_REO1_RING_MSI1_BASE_MSB_ADDR,287((u64)srng->msi_addr >>288HAL_ADDR_MSB_REG_SHIFT)) |289HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE;290ath11k_hif_write32(ab, reg_base +291HAL_REO1_RING_MSI1_BASE_MSB_OFFSET(ab), val);292293ath11k_hif_write32(ab,294reg_base + HAL_REO1_RING_MSI1_DATA_OFFSET(ab),295srng->msi_data);296}297298ath11k_hif_write32(ab, reg_base, srng->ring_base_paddr);299300val = FIELD_PREP(HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB,301((u64)srng->ring_base_paddr >>302HAL_ADDR_MSB_REG_SHIFT)) |303FIELD_PREP(HAL_REO1_RING_BASE_MSB_RING_SIZE,304(srng->entry_size * srng->num_entries));305ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_BASE_MSB_OFFSET(ab), val);306307val = FIELD_PREP(HAL_REO1_RING_ID_RING_ID, srng->ring_id) |308FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size);309ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_ID_OFFSET(ab), val);310311/* interrupt setup */312val = FIELD_PREP(HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD,313(srng->intr_timer_thres_us >> 3));314315val |= FIELD_PREP(HAL_REO1_RING_PRDR_INT_SETUP_BATCH_COUNTER_THOLD,316(srng->intr_batch_cntr_thres_entries *317srng->entry_size));318319ath11k_hif_write32(ab,320reg_base + HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET(ab),321val);322323hp_addr = hal->rdp.paddr +324((unsigned long)srng->u.dst_ring.hp_addr -325(unsigned long)hal->rdp.vaddr);326ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_LSB_OFFSET(ab),327hp_addr & HAL_ADDR_LSB_REG_MASK);328ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_MSB_OFFSET(ab),329hp_addr >> HAL_ADDR_MSB_REG_SHIFT);330331/* Initialize head and tail pointers to indicate ring is empty */332reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];333ath11k_hif_write32(ab, reg_base, 0);334ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET(ab), 0);335*srng->u.dst_ring.hp_addr = 0;336337reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];338val = 0;339if (srng->flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)340val |= HAL_REO1_RING_MISC_DATA_TLV_SWAP;341if (srng->flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)342val |= HAL_REO1_RING_MISC_HOST_FW_SWAP;343if (srng->flags & HAL_SRNG_FLAGS_MSI_SWAP)344val |= HAL_REO1_RING_MISC_MSI_SWAP;345val |= HAL_REO1_RING_MISC_SRNG_ENABLE;346347ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_MISC_OFFSET(ab), val);348}349350static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab,351struct hal_srng *srng)352{353struct ath11k_hal *hal = &ab->hal;354u32 val;355u64 tp_addr;356u32 reg_base;357358reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];359360if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) {361ath11k_hif_write32(ab, reg_base +362HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(ab),363srng->msi_addr);364365val = FIELD_PREP(HAL_TCL1_RING_MSI1_BASE_MSB_ADDR,366((u64)srng->msi_addr >>367HAL_ADDR_MSB_REG_SHIFT)) |368HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE;369ath11k_hif_write32(ab, reg_base +370HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(ab),371val);372373ath11k_hif_write32(ab, reg_base +374HAL_TCL1_RING_MSI1_DATA_OFFSET(ab),375srng->msi_data);376}377378ath11k_hif_write32(ab, reg_base, srng->ring_base_paddr);379380val = FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB,381((u64)srng->ring_base_paddr >>382HAL_ADDR_MSB_REG_SHIFT)) |383FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE,384(srng->entry_size * srng->num_entries));385ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(ab), val);386387val = FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size);388ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET(ab), val);389390if (srng->ring_id == HAL_SRNG_RING_ID_WBM_IDLE_LINK) {391ath11k_hif_write32(ab, reg_base, (u32)srng->ring_base_paddr);392val = FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB,393((u64)srng->ring_base_paddr >>394HAL_ADDR_MSB_REG_SHIFT)) |395FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE,396(srng->entry_size * srng->num_entries));397ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(ab), val);398}399400/* interrupt setup */401/* NOTE: IPQ8074 v2 requires the interrupt timer threshold in the402* unit of 8 usecs instead of 1 usec (as required by v1).403*/404val = FIELD_PREP(HAL_TCL1_RING_CONSR_INT_SETUP_IX0_INTR_TMR_THOLD,405srng->intr_timer_thres_us);406407val |= FIELD_PREP(HAL_TCL1_RING_CONSR_INT_SETUP_IX0_BATCH_COUNTER_THOLD,408(srng->intr_batch_cntr_thres_entries *409srng->entry_size));410411ath11k_hif_write32(ab,412reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(ab),413val);414415val = 0;416if (srng->flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) {417val |= FIELD_PREP(HAL_TCL1_RING_CONSR_INT_SETUP_IX1_LOW_THOLD,418srng->u.src_ring.low_threshold);419}420ath11k_hif_write32(ab,421reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(ab),422val);423424if (srng->ring_id != HAL_SRNG_RING_ID_WBM_IDLE_LINK) {425tp_addr = hal->rdp.paddr +426((unsigned long)srng->u.src_ring.tp_addr -427(unsigned long)hal->rdp.vaddr);428ath11k_hif_write32(ab,429reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(ab),430tp_addr & HAL_ADDR_LSB_REG_MASK);431ath11k_hif_write32(ab,432reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(ab),433tp_addr >> HAL_ADDR_MSB_REG_SHIFT);434}435436/* Initialize head and tail pointers to indicate ring is empty */437reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];438ath11k_hif_write32(ab, reg_base, 0);439ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_TP_OFFSET, 0);440*srng->u.src_ring.tp_addr = 0;441442reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];443val = 0;444if (srng->flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)445val |= HAL_TCL1_RING_MISC_DATA_TLV_SWAP;446if (srng->flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)447val |= HAL_TCL1_RING_MISC_HOST_FW_SWAP;448if (srng->flags & HAL_SRNG_FLAGS_MSI_SWAP)449val |= HAL_TCL1_RING_MISC_MSI_SWAP;450451/* Loop count is not used for SRC rings */452val |= HAL_TCL1_RING_MISC_MSI_LOOPCNT_DISABLE;453454val |= HAL_TCL1_RING_MISC_SRNG_ENABLE;455456ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET(ab), val);457}458459static void ath11k_hal_srng_hw_init(struct ath11k_base *ab,460struct hal_srng *srng)461{462if (srng->ring_dir == HAL_SRNG_DIR_SRC)463ath11k_hal_srng_src_hw_init(ab, srng);464else465ath11k_hal_srng_dst_hw_init(ab, srng);466}467468static int ath11k_hal_srng_get_ring_id(struct ath11k_base *ab,469enum hal_ring_type type,470int ring_num, int mac_id)471{472struct hal_srng_config *srng_config = &ab->hal.srng_config[type];473int ring_id;474475if (ring_num >= srng_config->max_rings) {476ath11k_warn(ab, "invalid ring number :%d\n", ring_num);477return -EINVAL;478}479480ring_id = srng_config->start_ring_id + ring_num;481if (srng_config->lmac_ring)482ring_id += mac_id * HAL_SRNG_RINGS_PER_LMAC;483484if (WARN_ON(ring_id >= HAL_SRNG_RING_ID_MAX))485return -EINVAL;486487return ring_id;488}489490int ath11k_hal_srng_get_entrysize(struct ath11k_base *ab, u32 ring_type)491{492struct hal_srng_config *srng_config;493494if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES))495return -EINVAL;496497srng_config = &ab->hal.srng_config[ring_type];498499return (srng_config->entry_size << 2);500}501502int ath11k_hal_srng_get_max_entries(struct ath11k_base *ab, u32 ring_type)503{504struct hal_srng_config *srng_config;505506if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES))507return -EINVAL;508509srng_config = &ab->hal.srng_config[ring_type];510511return (srng_config->max_size / srng_config->entry_size);512}513514void ath11k_hal_srng_get_params(struct ath11k_base *ab, struct hal_srng *srng,515struct hal_srng_params *params)516{517params->ring_base_paddr = srng->ring_base_paddr;518params->ring_base_vaddr = srng->ring_base_vaddr;519params->num_entries = srng->num_entries;520params->intr_timer_thres_us = srng->intr_timer_thres_us;521params->intr_batch_cntr_thres_entries =522srng->intr_batch_cntr_thres_entries;523params->low_threshold = srng->u.src_ring.low_threshold;524params->msi_addr = srng->msi_addr;525params->msi_data = srng->msi_data;526params->flags = srng->flags;527}528529dma_addr_t ath11k_hal_srng_get_hp_addr(struct ath11k_base *ab,530struct hal_srng *srng)531{532if (!(srng->flags & HAL_SRNG_FLAGS_LMAC_RING))533return 0;534535if (srng->ring_dir == HAL_SRNG_DIR_SRC)536return ab->hal.wrp.paddr +537((unsigned long)srng->u.src_ring.hp_addr -538(unsigned long)ab->hal.wrp.vaddr);539else540return ab->hal.rdp.paddr +541((unsigned long)srng->u.dst_ring.hp_addr -542(unsigned long)ab->hal.rdp.vaddr);543}544545dma_addr_t ath11k_hal_srng_get_tp_addr(struct ath11k_base *ab,546struct hal_srng *srng)547{548if (!(srng->flags & HAL_SRNG_FLAGS_LMAC_RING))549return 0;550551if (srng->ring_dir == HAL_SRNG_DIR_SRC)552return ab->hal.rdp.paddr +553((unsigned long)srng->u.src_ring.tp_addr -554(unsigned long)ab->hal.rdp.vaddr);555else556return ab->hal.wrp.paddr +557((unsigned long)srng->u.dst_ring.tp_addr -558(unsigned long)ab->hal.wrp.vaddr);559}560561u32 ath11k_hal_ce_get_desc_size(enum hal_ce_desc type)562{563switch (type) {564case HAL_CE_DESC_SRC:565return sizeof(struct hal_ce_srng_src_desc);566case HAL_CE_DESC_DST:567return sizeof(struct hal_ce_srng_dest_desc);568case HAL_CE_DESC_DST_STATUS:569return sizeof(struct hal_ce_srng_dst_status_desc);570}571572return 0;573}574575void ath11k_hal_ce_src_set_desc(void *buf, dma_addr_t paddr, u32 len, u32 id,576u8 byte_swap_data)577{578struct hal_ce_srng_src_desc *desc = buf;579580desc->buffer_addr_low = paddr & HAL_ADDR_LSB_REG_MASK;581desc->buffer_addr_info =582FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_ADDR_HI,583((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT)) |584FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_BYTE_SWAP,585byte_swap_data) |586FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_GATHER, 0) |587FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_LEN, len);588desc->meta_info = FIELD_PREP(HAL_CE_SRC_DESC_META_INFO_DATA, id);589}590591void ath11k_hal_ce_dst_set_desc(void *buf, dma_addr_t paddr)592{593struct hal_ce_srng_dest_desc *desc = buf;594595desc->buffer_addr_low = paddr & HAL_ADDR_LSB_REG_MASK;596desc->buffer_addr_info =597FIELD_PREP(HAL_CE_DEST_DESC_ADDR_INFO_ADDR_HI,598((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT));599}600601u32 ath11k_hal_ce_dst_status_get_length(void *buf)602{603struct hal_ce_srng_dst_status_desc *desc = buf;604u32 len;605606len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, desc->flags);607desc->flags &= ~HAL_CE_DST_STATUS_DESC_FLAGS_LEN;608609return len;610}611612void ath11k_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc, u32 cookie,613dma_addr_t paddr)614{615desc->buf_addr_info.info0 = FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,616(paddr & HAL_ADDR_LSB_REG_MASK));617desc->buf_addr_info.info1 = FIELD_PREP(BUFFER_ADDR_INFO1_ADDR,618((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT)) |619FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR, 1) |620FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, cookie);621}622623u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng)624{625lockdep_assert_held(&srng->lock);626627if (srng->u.dst_ring.tp != srng->u.dst_ring.cached_hp)628return (srng->ring_base_vaddr + srng->u.dst_ring.tp);629630return NULL;631}632633static u32 *ath11k_hal_srng_dst_peek_with_dma(struct ath11k_base *ab,634struct hal_srng *srng, dma_addr_t *paddr)635{636lockdep_assert_held(&srng->lock);637638if (srng->u.dst_ring.tp != srng->u.dst_ring.cached_hp) {639*paddr = srng->ring_base_paddr +640sizeof(*srng->ring_base_vaddr) * srng->u.dst_ring.tp;641return srng->ring_base_vaddr + srng->u.dst_ring.tp;642}643644return NULL;645}646647static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab,648struct hal_srng *srng)649{650dma_addr_t desc_paddr;651u32 *desc;652653/* prefetch only if desc is available */654desc = ath11k_hal_srng_dst_peek_with_dma(ab, srng, &desc_paddr);655if (likely(desc)) {656dma_sync_single_for_cpu(ab->dev, desc_paddr,657(srng->entry_size * sizeof(u32)),658DMA_FROM_DEVICE);659prefetch(desc);660}661}662663u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab,664struct hal_srng *srng)665{666u32 *desc;667668lockdep_assert_held(&srng->lock);669670if (srng->u.dst_ring.tp == srng->u.dst_ring.cached_hp)671return NULL;672673desc = srng->ring_base_vaddr + srng->u.dst_ring.tp;674675srng->u.dst_ring.tp += srng->entry_size;676677/* wrap around to start of ring*/678if (srng->u.dst_ring.tp == srng->ring_size)679srng->u.dst_ring.tp = 0;680681/* Try to prefetch the next descriptor in the ring */682if (srng->flags & HAL_SRNG_FLAGS_CACHED)683ath11k_hal_srng_prefetch_desc(ab, srng);684685return desc;686}687688int ath11k_hal_srng_dst_num_free(struct ath11k_base *ab, struct hal_srng *srng,689bool sync_hw_ptr)690{691u32 tp, hp;692693lockdep_assert_held(&srng->lock);694695tp = srng->u.dst_ring.tp;696697if (sync_hw_ptr) {698hp = *srng->u.dst_ring.hp_addr;699srng->u.dst_ring.cached_hp = hp;700} else {701hp = srng->u.dst_ring.cached_hp;702}703704if (hp >= tp)705return (hp - tp) / srng->entry_size;706else707return (srng->ring_size - tp + hp) / srng->entry_size;708}709710/* Returns number of available entries in src ring */711int ath11k_hal_srng_src_num_free(struct ath11k_base *ab, struct hal_srng *srng,712bool sync_hw_ptr)713{714u32 tp, hp;715716lockdep_assert_held(&srng->lock);717718hp = srng->u.src_ring.hp;719720if (sync_hw_ptr) {721tp = *srng->u.src_ring.tp_addr;722srng->u.src_ring.cached_tp = tp;723} else {724tp = srng->u.src_ring.cached_tp;725}726727if (tp > hp)728return ((tp - hp) / srng->entry_size) - 1;729else730return ((srng->ring_size - hp + tp) / srng->entry_size) - 1;731}732733u32 *ath11k_hal_srng_src_get_next_entry(struct ath11k_base *ab,734struct hal_srng *srng)735{736u32 *desc;737u32 next_hp;738739lockdep_assert_held(&srng->lock);740741/* TODO: Using % is expensive, but we have to do this since size of some742* SRNG rings is not power of 2 (due to descriptor sizes). Need to see743* if separate function is defined for rings having power of 2 ring size744* (TCL2SW, REO2SW, SW2RXDMA and CE rings) so that we can avoid the745* overhead of % by using mask (with &).746*/747next_hp = (srng->u.src_ring.hp + srng->entry_size) % srng->ring_size;748749if (next_hp == srng->u.src_ring.cached_tp)750return NULL;751752desc = srng->ring_base_vaddr + srng->u.src_ring.hp;753srng->u.src_ring.hp = next_hp;754755/* TODO: Reap functionality is not used by all rings. If particular756* ring does not use reap functionality, we need not update reap_hp757* with next_hp pointer. Need to make sure a separate function is used758* before doing any optimization by removing below code updating759* reap_hp.760*/761srng->u.src_ring.reap_hp = next_hp;762763return desc;764}765766u32 *ath11k_hal_srng_src_reap_next(struct ath11k_base *ab,767struct hal_srng *srng)768{769u32 *desc;770u32 next_reap_hp;771772lockdep_assert_held(&srng->lock);773774next_reap_hp = (srng->u.src_ring.reap_hp + srng->entry_size) %775srng->ring_size;776777if (next_reap_hp == srng->u.src_ring.cached_tp)778return NULL;779780desc = srng->ring_base_vaddr + next_reap_hp;781srng->u.src_ring.reap_hp = next_reap_hp;782783return desc;784}785786u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab,787struct hal_srng *srng)788{789u32 *desc;790791lockdep_assert_held(&srng->lock);792793if (srng->u.src_ring.hp == srng->u.src_ring.reap_hp)794return NULL;795796desc = srng->ring_base_vaddr + srng->u.src_ring.hp;797srng->u.src_ring.hp = (srng->u.src_ring.hp + srng->entry_size) %798srng->ring_size;799800return desc;801}802803u32 *ath11k_hal_srng_src_next_peek(struct ath11k_base *ab, struct hal_srng *srng)804{805u32 next_hp;806807lockdep_assert_held(&srng->lock);808809next_hp = (srng->u.src_ring.hp + srng->entry_size) % srng->ring_size;810811if (next_hp != srng->u.src_ring.cached_tp)812return srng->ring_base_vaddr + next_hp;813814return NULL;815}816817u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng)818{819lockdep_assert_held(&srng->lock);820821if (((srng->u.src_ring.hp + srng->entry_size) % srng->ring_size) ==822srng->u.src_ring.cached_tp)823return NULL;824825return srng->ring_base_vaddr + srng->u.src_ring.hp;826}827828void ath11k_hal_srng_access_begin(struct ath11k_base *ab, struct hal_srng *srng)829{830u32 hp;831832lockdep_assert_held(&srng->lock);833834if (srng->ring_dir == HAL_SRNG_DIR_SRC) {835srng->u.src_ring.cached_tp =836*(volatile u32 *)srng->u.src_ring.tp_addr;837} else {838hp = READ_ONCE(*srng->u.dst_ring.hp_addr);839840if (hp != srng->u.dst_ring.cached_hp) {841srng->u.dst_ring.cached_hp = hp;842/* Make sure descriptor is read after the head843* pointer.844*/845dma_rmb();846}847848/* Try to prefetch the next descriptor in the ring */849if (srng->flags & HAL_SRNG_FLAGS_CACHED)850ath11k_hal_srng_prefetch_desc(ab, srng);851}852}853854/* Update cached ring head/tail pointers to HW. ath11k_hal_srng_access_begin()855* should have been called before this.856*/857void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng)858{859lockdep_assert_held(&srng->lock);860861if (srng->flags & HAL_SRNG_FLAGS_LMAC_RING) {862/* For LMAC rings, ring pointer updates are done through FW and863* hence written to a shared memory location that is read by FW864*/865if (srng->ring_dir == HAL_SRNG_DIR_SRC) {866srng->u.src_ring.last_tp =867*(volatile u32 *)srng->u.src_ring.tp_addr;868/* Make sure descriptor is written before updating the869* head pointer.870*/871dma_wmb();872WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp);873} else {874srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr;875/* Make sure descriptor is read before updating the876* tail pointer.877*/878dma_mb();879WRITE_ONCE(*srng->u.dst_ring.tp_addr, srng->u.dst_ring.tp);880}881} else {882if (srng->ring_dir == HAL_SRNG_DIR_SRC) {883srng->u.src_ring.last_tp =884*(volatile u32 *)srng->u.src_ring.tp_addr;885/* Assume implementation use an MMIO write accessor886* which has the required wmb() so that the descriptor887* is written before the updating the head pointer.888*/889ath11k_hif_write32(ab,890(unsigned long)srng->u.src_ring.hp_addr -891(unsigned long)ab->mem,892srng->u.src_ring.hp);893} else {894srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr;895/* Make sure descriptor is read before updating the896* tail pointer.897*/898mb();899ath11k_hif_write32(ab,900(unsigned long)srng->u.dst_ring.tp_addr -901(unsigned long)ab->mem,902srng->u.dst_ring.tp);903}904}905906srng->timestamp = jiffies;907}908909void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,910struct hal_wbm_idle_scatter_list *sbuf,911u32 nsbufs, u32 tot_link_desc,912u32 end_offset)913{914struct ath11k_buffer_addr *link_addr;915int i;916u32 reg_scatter_buf_sz = HAL_WBM_IDLE_SCATTER_BUF_SIZE / 64;917918#if defined(__linux__)919link_addr = (void *)sbuf[0].vaddr + HAL_WBM_IDLE_SCATTER_BUF_SIZE;920#elif defined(__FreeBSD__)921link_addr = (void *)((uintptr_t)sbuf[0].vaddr + HAL_WBM_IDLE_SCATTER_BUF_SIZE);922#endif923924for (i = 1; i < nsbufs; i++) {925link_addr->info0 = sbuf[i].paddr & HAL_ADDR_LSB_REG_MASK;926link_addr->info1 = FIELD_PREP(927HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,928(u64)sbuf[i].paddr >> HAL_ADDR_MSB_REG_SHIFT) |929FIELD_PREP(930HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG,931BASE_ADDR_MATCH_TAG_VAL);932933#if defined(__linux__)934link_addr = (void *)sbuf[i].vaddr +935HAL_WBM_IDLE_SCATTER_BUF_SIZE;936#elif defined(__FreeBSD__)937link_addr = (void *)((uintptr_t)sbuf[i].vaddr +938HAL_WBM_IDLE_SCATTER_BUF_SIZE);939#endif940}941942ath11k_hif_write32(ab,943HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR,944FIELD_PREP(HAL_WBM_SCATTER_BUFFER_SIZE, reg_scatter_buf_sz) |945FIELD_PREP(HAL_WBM_LINK_DESC_IDLE_LIST_MODE, 0x1));946ath11k_hif_write32(ab,947HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_R0_IDLE_LIST_SIZE_ADDR,948FIELD_PREP(HAL_WBM_SCATTER_RING_SIZE_OF_IDLE_LINK_DESC_LIST,949reg_scatter_buf_sz * nsbufs));950ath11k_hif_write32(ab,951HAL_SEQ_WCSS_UMAC_WBM_REG +952HAL_WBM_SCATTERED_RING_BASE_LSB,953FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,954sbuf[0].paddr & HAL_ADDR_LSB_REG_MASK));955ath11k_hif_write32(ab,956HAL_SEQ_WCSS_UMAC_WBM_REG +957HAL_WBM_SCATTERED_RING_BASE_MSB,958FIELD_PREP(959HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,960(u64)sbuf[0].paddr >> HAL_ADDR_MSB_REG_SHIFT) |961FIELD_PREP(962HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG,963BASE_ADDR_MATCH_TAG_VAL));964965/* Setup head and tail pointers for the idle list */966ath11k_hif_write32(ab,967HAL_SEQ_WCSS_UMAC_WBM_REG +968HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0,969FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,970sbuf[nsbufs - 1].paddr));971ath11k_hif_write32(ab,972HAL_SEQ_WCSS_UMAC_WBM_REG +973HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX1,974FIELD_PREP(975HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,976((u64)sbuf[nsbufs - 1].paddr >>977HAL_ADDR_MSB_REG_SHIFT)) |978FIELD_PREP(HAL_WBM_SCATTERED_DESC_HEAD_P_OFFSET_IX1,979(end_offset >> 2)));980ath11k_hif_write32(ab,981HAL_SEQ_WCSS_UMAC_WBM_REG +982HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0,983FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,984sbuf[0].paddr));985986ath11k_hif_write32(ab,987HAL_SEQ_WCSS_UMAC_WBM_REG +988HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX0,989FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,990sbuf[0].paddr));991ath11k_hif_write32(ab,992HAL_SEQ_WCSS_UMAC_WBM_REG +993HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX1,994FIELD_PREP(995HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,996((u64)sbuf[0].paddr >> HAL_ADDR_MSB_REG_SHIFT)) |997FIELD_PREP(HAL_WBM_SCATTERED_DESC_TAIL_P_OFFSET_IX1,9980));999ath11k_hif_write32(ab,1000HAL_SEQ_WCSS_UMAC_WBM_REG +1001HAL_WBM_SCATTERED_DESC_PTR_HP_ADDR,10022 * tot_link_desc);10031004/* Enable the SRNG */1005ath11k_hif_write32(ab,1006HAL_SEQ_WCSS_UMAC_WBM_REG +1007HAL_WBM_IDLE_LINK_RING_MISC_ADDR(ab), 0x40);1008}10091010int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,1011int ring_num, int mac_id,1012struct hal_srng_params *params)1013{1014struct ath11k_hal *hal = &ab->hal;1015struct hal_srng_config *srng_config = &ab->hal.srng_config[type];1016struct hal_srng *srng;1017int ring_id;1018u32 lmac_idx;1019int i;1020u32 reg_base;10211022ring_id = ath11k_hal_srng_get_ring_id(ab, type, ring_num, mac_id);1023if (ring_id < 0)1024return ring_id;10251026srng = &hal->srng_list[ring_id];10271028srng->ring_id = ring_id;1029srng->ring_dir = srng_config->ring_dir;1030srng->ring_base_paddr = params->ring_base_paddr;1031srng->ring_base_vaddr = params->ring_base_vaddr;1032srng->entry_size = srng_config->entry_size;1033srng->num_entries = params->num_entries;1034srng->ring_size = srng->entry_size * srng->num_entries;1035srng->intr_batch_cntr_thres_entries =1036params->intr_batch_cntr_thres_entries;1037srng->intr_timer_thres_us = params->intr_timer_thres_us;1038srng->flags = params->flags;1039srng->msi_addr = params->msi_addr;1040srng->msi_data = params->msi_data;1041srng->initialized = 1;1042spin_lock_init(&srng->lock);1043lockdep_set_class(&srng->lock, hal->srng_key + ring_id);10441045for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) {1046srng->hwreg_base[i] = srng_config->reg_start[i] +1047(ring_num * srng_config->reg_size[i]);1048}10491050memset(srng->ring_base_vaddr, 0,1051(srng->entry_size * srng->num_entries) << 2);10521053/* TODO: Add comments on these swap configurations */1054if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))1055srng->flags |= HAL_SRNG_FLAGS_MSI_SWAP | HAL_SRNG_FLAGS_DATA_TLV_SWAP |1056HAL_SRNG_FLAGS_RING_PTR_SWAP;10571058reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];10591060if (srng->ring_dir == HAL_SRNG_DIR_SRC) {1061srng->u.src_ring.hp = 0;1062srng->u.src_ring.cached_tp = 0;1063srng->u.src_ring.reap_hp = srng->ring_size - srng->entry_size;1064srng->u.src_ring.tp_addr = (void *)(hal->rdp.vaddr + ring_id);1065srng->u.src_ring.low_threshold = params->low_threshold *1066srng->entry_size;1067if (srng_config->lmac_ring) {1068lmac_idx = ring_id - HAL_SRNG_RING_ID_LMAC1_ID_START;1069srng->u.src_ring.hp_addr = (void *)(hal->wrp.vaddr +1070lmac_idx);1071srng->flags |= HAL_SRNG_FLAGS_LMAC_RING;1072} else {1073if (!ab->hw_params.supports_shadow_regs)1074srng->u.src_ring.hp_addr =1075(u32 *)((unsigned long)ab->mem + reg_base);1076else1077ath11k_dbg(ab, ATH11K_DBG_HAL,1078"type %d ring_num %d reg_base 0x%x shadow 0x%lx\n",1079type, ring_num,1080reg_base,1081(unsigned long)srng->u.src_ring.hp_addr -1082(unsigned long)ab->mem);1083}1084} else {1085/* During initialization loop count in all the descriptors1086* will be set to zero, and HW will set it to 1 on completing1087* descriptor update in first loop, and increments it by 1 on1088* subsequent loops (loop count wraps around after reaching1089* 0xffff). The 'loop_cnt' in SW ring state is the expected1090* loop count in descriptors updated by HW (to be processed1091* by SW).1092*/1093srng->u.dst_ring.loop_cnt = 1;1094srng->u.dst_ring.tp = 0;1095srng->u.dst_ring.cached_hp = 0;1096srng->u.dst_ring.hp_addr = (void *)(hal->rdp.vaddr + ring_id);1097if (srng_config->lmac_ring) {1098/* For LMAC rings, tail pointer updates will be done1099* through FW by writing to a shared memory location1100*/1101lmac_idx = ring_id - HAL_SRNG_RING_ID_LMAC1_ID_START;1102srng->u.dst_ring.tp_addr = (void *)(hal->wrp.vaddr +1103lmac_idx);1104srng->flags |= HAL_SRNG_FLAGS_LMAC_RING;1105} else {1106if (!ab->hw_params.supports_shadow_regs)1107srng->u.dst_ring.tp_addr =1108(u32 *)((unsigned long)ab->mem + reg_base +1109(HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab)));1110else1111ath11k_dbg(ab, ATH11K_DBG_HAL,1112"type %d ring_num %d target_reg 0x%x shadow 0x%lx\n",1113type, ring_num,1114reg_base + (HAL_REO1_RING_TP(ab) -1115HAL_REO1_RING_HP(ab)),1116(unsigned long)srng->u.dst_ring.tp_addr -1117(unsigned long)ab->mem);1118}1119}11201121if (srng_config->lmac_ring)1122return ring_id;11231124ath11k_hal_srng_hw_init(ab, srng);11251126if (type == HAL_CE_DST) {1127srng->u.dst_ring.max_buffer_length = params->max_buffer_len;1128ath11k_hal_ce_dst_setup(ab, srng, ring_num);1129}11301131return ring_id;1132}11331134static void ath11k_hal_srng_update_hp_tp_addr(struct ath11k_base *ab,1135int shadow_cfg_idx,1136enum hal_ring_type ring_type,1137int ring_num)1138{1139struct hal_srng *srng;1140struct ath11k_hal *hal = &ab->hal;1141int ring_id;1142struct hal_srng_config *srng_config = &hal->srng_config[ring_type];11431144ring_id = ath11k_hal_srng_get_ring_id(ab, ring_type, ring_num, 0);1145if (ring_id < 0)1146return;11471148srng = &hal->srng_list[ring_id];11491150if (srng_config->ring_dir == HAL_SRNG_DIR_DST)1151srng->u.dst_ring.tp_addr = (u32 *)(HAL_SHADOW_REG(ab, shadow_cfg_idx) +1152(unsigned long)ab->mem);1153else1154srng->u.src_ring.hp_addr = (u32 *)(HAL_SHADOW_REG(ab, shadow_cfg_idx) +1155(unsigned long)ab->mem);1156}11571158int ath11k_hal_srng_update_shadow_config(struct ath11k_base *ab,1159enum hal_ring_type ring_type,1160int ring_num)1161{1162struct ath11k_hal *hal = &ab->hal;1163struct hal_srng_config *srng_config = &hal->srng_config[ring_type];1164int shadow_cfg_idx = hal->num_shadow_reg_configured;1165u32 target_reg;11661167if (shadow_cfg_idx >= HAL_SHADOW_NUM_REGS)1168return -EINVAL;11691170hal->num_shadow_reg_configured++;11711172target_reg = srng_config->reg_start[HAL_HP_OFFSET_IN_REG_START];1173target_reg += srng_config->reg_size[HAL_HP_OFFSET_IN_REG_START] *1174ring_num;11751176/* For destination ring, shadow the TP */1177if (srng_config->ring_dir == HAL_SRNG_DIR_DST)1178target_reg += HAL_OFFSET_FROM_HP_TO_TP;11791180hal->shadow_reg_addr[shadow_cfg_idx] = target_reg;11811182/* update hp/tp addr to hal structure*/1183ath11k_hal_srng_update_hp_tp_addr(ab, shadow_cfg_idx, ring_type,1184ring_num);11851186ath11k_dbg(ab, ATH11K_DBG_HAL,1187"update shadow config target_reg %x shadow reg 0x%x shadow_idx 0x%x ring_type %d ring num %d",1188target_reg,1189HAL_SHADOW_REG(ab, shadow_cfg_idx),1190shadow_cfg_idx,1191ring_type, ring_num);11921193return 0;1194}11951196void ath11k_hal_srng_shadow_config(struct ath11k_base *ab)1197{1198struct ath11k_hal *hal = &ab->hal;1199int ring_type, ring_num;12001201/* update all the non-CE srngs. */1202for (ring_type = 0; ring_type < HAL_MAX_RING_TYPES; ring_type++) {1203struct hal_srng_config *srng_config = &hal->srng_config[ring_type];12041205if (ring_type == HAL_CE_SRC ||1206ring_type == HAL_CE_DST ||1207ring_type == HAL_CE_DST_STATUS)1208continue;12091210if (srng_config->lmac_ring)1211continue;12121213for (ring_num = 0; ring_num < srng_config->max_rings; ring_num++)1214ath11k_hal_srng_update_shadow_config(ab, ring_type, ring_num);1215}1216}12171218void ath11k_hal_srng_get_shadow_config(struct ath11k_base *ab,1219u32 **cfg, u32 *len)1220{1221struct ath11k_hal *hal = &ab->hal;12221223*len = hal->num_shadow_reg_configured;1224*cfg = hal->shadow_reg_addr;1225}12261227void ath11k_hal_srng_shadow_update_hp_tp(struct ath11k_base *ab,1228struct hal_srng *srng)1229{1230lockdep_assert_held(&srng->lock);12311232/* check whether the ring is empty. Update the shadow1233* HP only when then ring isn't empty.1234*/1235if (srng->ring_dir == HAL_SRNG_DIR_SRC &&1236*srng->u.src_ring.tp_addr != srng->u.src_ring.hp)1237ath11k_hal_srng_access_end(ab, srng);1238}12391240static int ath11k_hal_srng_create_config(struct ath11k_base *ab)1241{1242struct ath11k_hal *hal = &ab->hal;1243struct hal_srng_config *s;12441245hal->srng_config = kmemdup(hw_srng_config_template,1246sizeof(hw_srng_config_template),1247GFP_KERNEL);1248if (!hal->srng_config)1249return -ENOMEM;12501251s = &hal->srng_config[HAL_REO_DST];1252s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB(ab);1253s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP(ab);1254s->reg_size[0] = HAL_REO2_RING_BASE_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab);1255s->reg_size[1] = HAL_REO2_RING_HP(ab) - HAL_REO1_RING_HP(ab);12561257s = &hal->srng_config[HAL_REO_EXCEPTION];1258s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB(ab);1259s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP(ab);12601261s = &hal->srng_config[HAL_REO_REINJECT];1262s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB(ab);1263s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP(ab);12641265s = &hal->srng_config[HAL_REO_CMD];1266s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB(ab);1267s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP(ab);12681269s = &hal->srng_config[HAL_REO_STATUS];1270s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB(ab);1271s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP(ab);12721273s = &hal->srng_config[HAL_TCL_DATA];1274s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB(ab);1275s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP;1276s->reg_size[0] = HAL_TCL2_RING_BASE_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab);1277s->reg_size[1] = HAL_TCL2_RING_HP - HAL_TCL1_RING_HP;12781279s = &hal->srng_config[HAL_TCL_CMD];1280s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB(ab);1281s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP;12821283s = &hal->srng_config[HAL_TCL_STATUS];1284s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB(ab);1285s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP;12861287s = &hal->srng_config[HAL_CE_SRC];1288s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB +1289ATH11K_CE_OFFSET(ab);1290s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP +1291ATH11K_CE_OFFSET(ab);1292s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) -1293HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab);1294s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) -1295HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab);12961297s = &hal->srng_config[HAL_CE_DST];1298s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB +1299ATH11K_CE_OFFSET(ab);1300s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP +1301ATH11K_CE_OFFSET(ab);1302s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -1303HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);1304s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -1305HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);13061307s = &hal->srng_config[HAL_CE_DST_STATUS];1308s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) +1309HAL_CE_DST_STATUS_RING_BASE_LSB + ATH11K_CE_OFFSET(ab);1310s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP +1311ATH11K_CE_OFFSET(ab);1312s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -1313HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);1314s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -1315HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);13161317s = &hal->srng_config[HAL_WBM_IDLE_LINK];1318s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_BASE_LSB(ab);1319s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_HP;13201321s = &hal->srng_config[HAL_SW2WBM_RELEASE];1322s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_RELEASE_RING_BASE_LSB(ab);1323s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_RELEASE_RING_HP;13241325s = &hal->srng_config[HAL_WBM2SW_RELEASE];1326s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_BASE_LSB(ab);1327s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_HP;1328s->reg_size[0] = HAL_WBM1_RELEASE_RING_BASE_LSB(ab) -1329HAL_WBM0_RELEASE_RING_BASE_LSB(ab);1330s->reg_size[1] = HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP;13311332return 0;1333}13341335static void ath11k_hal_register_srng_key(struct ath11k_base *ab)1336{1337#if defined(__linux__)1338struct ath11k_hal *hal = &ab->hal;1339u32 ring_id;13401341for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++)1342lockdep_register_key(hal->srng_key + ring_id);1343#endif1344}13451346static void ath11k_hal_unregister_srng_key(struct ath11k_base *ab)1347{1348#if defined(__linux__)1349struct ath11k_hal *hal = &ab->hal;1350u32 ring_id;13511352for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++)1353lockdep_unregister_key(hal->srng_key + ring_id);1354#endif1355}13561357int ath11k_hal_srng_init(struct ath11k_base *ab)1358{1359struct ath11k_hal *hal = &ab->hal;1360int ret;13611362memset(hal, 0, sizeof(*hal));13631364ret = ath11k_hal_srng_create_config(ab);1365if (ret)1366goto err_hal;13671368ret = ath11k_hal_alloc_cont_rdp(ab);1369if (ret)1370goto err_hal;13711372ret = ath11k_hal_alloc_cont_wrp(ab);1373if (ret)1374goto err_free_cont_rdp;13751376ath11k_hal_register_srng_key(ab);13771378return 0;13791380err_free_cont_rdp:1381ath11k_hal_free_cont_rdp(ab);13821383err_hal:1384return ret;1385}1386EXPORT_SYMBOL(ath11k_hal_srng_init);13871388void ath11k_hal_srng_deinit(struct ath11k_base *ab)1389{1390struct ath11k_hal *hal = &ab->hal;1391int i;13921393for (i = 0; i < HAL_SRNG_RING_ID_MAX; i++)1394ab->hal.srng_list[i].initialized = 0;13951396ath11k_hal_unregister_srng_key(ab);1397ath11k_hal_free_cont_rdp(ab);1398ath11k_hal_free_cont_wrp(ab);1399kfree(hal->srng_config);1400hal->srng_config = NULL;1401}1402EXPORT_SYMBOL(ath11k_hal_srng_deinit);14031404void ath11k_hal_srng_clear(struct ath11k_base *ab)1405{1406/* No need to memset rdp and wrp memory since each individual1407* segment would get cleared in ath11k_hal_srng_src_hw_init()1408* and ath11k_hal_srng_dst_hw_init().1409*/1410memset(ab->hal.srng_list, 0,1411sizeof(ab->hal.srng_list));1412memset(ab->hal.shadow_reg_addr, 0,1413sizeof(ab->hal.shadow_reg_addr));1414ab->hal.avail_blk_resource = 0;1415ab->hal.current_blk_index = 0;1416ab->hal.num_shadow_reg_configured = 0;1417}1418EXPORT_SYMBOL(ath11k_hal_srng_clear);14191420void ath11k_hal_dump_srng_stats(struct ath11k_base *ab)1421{1422struct hal_srng *srng;1423struct ath11k_ext_irq_grp *irq_grp;1424struct ath11k_ce_pipe *ce_pipe;1425int i;14261427ath11k_err(ab, "Last interrupt received for each CE:\n");1428for (i = 0; i < ab->hw_params.ce_count; i++) {1429ce_pipe = &ab->ce.ce_pipe[i];14301431if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)1432continue;14331434#if defined(__linux__)1435ath11k_err(ab, "CE_id %d pipe_num %d %ums before\n",1436i, ce_pipe->pipe_num,1437jiffies_to_msecs(jiffies - ce_pipe->timestamp));1438#elif defined(__FreeBSD__)1439ath11k_err(ab, "CE_id %d pipe_num %d %jums before\n",1440i, ce_pipe->pipe_num,1441(uintmax_t)jiffies_to_msecs(jiffies - ce_pipe->timestamp));1442#endif1443}14441445ath11k_err(ab, "\nLast interrupt received for each group:\n");1446for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {1447irq_grp = &ab->ext_irq_grp[i];1448#if defined(__linux__)1449ath11k_err(ab, "group_id %d %ums before\n",1450irq_grp->grp_id,1451jiffies_to_msecs(jiffies - irq_grp->timestamp));1452#elif defined(__FreeBSD__)1453ath11k_err(ab, "group_id %d %jums before\n",1454irq_grp->grp_id,1455(uintmax_t)jiffies_to_msecs(jiffies - irq_grp->timestamp));1456#endif1457}14581459for (i = 0; i < HAL_SRNG_RING_ID_MAX; i++) {1460srng = &ab->hal.srng_list[i];14611462if (!srng->initialized)1463continue;14641465if (srng->ring_dir == HAL_SRNG_DIR_SRC)1466ath11k_err(ab,1467#if defined(__linux__)1468"src srng id %u hp %u, reap_hp %u, cur tp %u, cached tp %u last tp %u napi processed before %ums\n",1469#elif defined(__FreeBSD__)1470"src srng id %u hp %u, reap_hp %u, cur tp %u, cached tp %u last tp %u napi processed before %jums\n",1471#endif1472srng->ring_id, srng->u.src_ring.hp,1473srng->u.src_ring.reap_hp,1474*srng->u.src_ring.tp_addr, srng->u.src_ring.cached_tp,1475srng->u.src_ring.last_tp,1476#if defined(__linux__)1477jiffies_to_msecs(jiffies - srng->timestamp));1478#elif defined(__FreeBSD__)1479(uintmax_t)jiffies_to_msecs(jiffies - srng->timestamp));1480#endif1481else if (srng->ring_dir == HAL_SRNG_DIR_DST)1482ath11k_err(ab,1483#if defined(__linux__)1484"dst srng id %u tp %u, cur hp %u, cached hp %u last hp %u napi processed before %ums\n",1485#elif defined(__FreeBSD__)1486"dst srng id %u tp %u, cur hp %u, cached hp %u last hp %u napi processed before %jums\n",1487#endif1488srng->ring_id, srng->u.dst_ring.tp,1489*srng->u.dst_ring.hp_addr,1490srng->u.dst_ring.cached_hp,1491srng->u.dst_ring.last_hp,1492#if defined(__linux__)1493jiffies_to_msecs(jiffies - srng->timestamp));1494#elif defined(__FreeBSD__)1495(uintmax_t)jiffies_to_msecs(jiffies - srng->timestamp));1496#endif1497}1498}149915001501