/* * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HAL_GENERIC_API_H_ #define _HAL_GENERIC_API_H_ #include #define SRNG_ENABLE_BIT 0x40 #define SRNG_IDLE_STATE_BIT 0x80 /** * hal_get_radiotap_he_gi_ltf() - Convert HE ltf and GI value * from stats enum to radiotap enum * @he_gi: HE GI value used in stats * @he_ltf: HE LTF value used in stats * * Return: void */ static inline void hal_get_radiotap_he_gi_ltf(uint16_t *he_gi, uint16_t *he_ltf) { switch (*he_gi) { case HE_GI_0_8: *he_gi = HE_GI_RADIOTAP_0_8; break; case HE_GI_1_6: *he_gi = HE_GI_RADIOTAP_1_6; break; case HE_GI_3_2: *he_gi = HE_GI_RADIOTAP_3_2; break; default: *he_gi = HE_GI_RADIOTAP_RESERVED; } switch (*he_ltf) { case HE_LTF_1_X: *he_ltf = HE_LTF_RADIOTAP_1_X; break; case HE_LTF_2_X: *he_ltf = HE_LTF_RADIOTAP_2_X; break; case HE_LTF_4_X: *he_ltf = HE_LTF_RADIOTAP_4_X; break; default: *he_ltf = HE_LTF_RADIOTAP_UNKNOWN; } } /* channel number to freq conversion */ #define CHANNEL_NUM_14 14 #define CHANNEL_NUM_15 15 #define CHANNEL_NUM_27 27 #define CHANNEL_NUM_35 35 #define CHANNEL_NUM_182 182 #define CHANNEL_NUM_197 197 #define CHANNEL_FREQ_2484 2484 #define CHANNEL_FREQ_2407 2407 #define CHANNEL_FREQ_2512 2512 #define CHANNEL_FREQ_5000 5000 #define CHANNEL_FREQ_5950 5950 #define CHANNEL_FREQ_4000 4000 #define CHANNEL_FREQ_5150 5150 #define CHANNEL_FREQ_5920 5920 #define CHANNEL_FREQ_5935 5935 #define FREQ_MULTIPLIER_CONST_5MHZ 5 #define FREQ_MULTIPLIER_CONST_20MHZ 20 /** * hal_rx_radiotap_num_to_freq() - Get frequency from chan number * @chan_num: Input channel number * @center_freq: Input Channel Center frequency * * Return - Channel frequency in Mhz */ static inline uint16_t hal_rx_radiotap_num_to_freq(uint16_t chan_num, qdf_freq_t center_freq) { if (center_freq > CHANNEL_FREQ_5920 && center_freq < CHANNEL_FREQ_5950) return CHANNEL_FREQ_5935; if (center_freq < CHANNEL_FREQ_5950) { if (chan_num == CHANNEL_NUM_14) return CHANNEL_FREQ_2484; if (chan_num < CHANNEL_NUM_14) return CHANNEL_FREQ_2407 + (chan_num * FREQ_MULTIPLIER_CONST_5MHZ); if (chan_num < CHANNEL_NUM_27) return CHANNEL_FREQ_2512 + ((chan_num - CHANNEL_NUM_15) * FREQ_MULTIPLIER_CONST_20MHZ); if (chan_num > CHANNEL_NUM_182 && chan_num < CHANNEL_NUM_197) return ((chan_num * FREQ_MULTIPLIER_CONST_5MHZ) + CHANNEL_FREQ_4000); return CHANNEL_FREQ_5000 + (chan_num * FREQ_MULTIPLIER_CONST_5MHZ); } else { return CHANNEL_FREQ_5950 + (chan_num * FREQ_MULTIPLIER_CONST_5MHZ); } } /** * hal_get_hw_hptp_generic() - Get HW head and tail pointer value for any ring * @hal_soc: Opaque HAL SOC handle * @hal_ring_hdl: Source ring pointer * @headp: Head Pointer * @tailp: Tail Pointer * @ring: Ring type * * Return: Update tail pointer and head pointer in arguments. */ static inline void hal_get_hw_hptp_generic(struct hal_soc *hal_soc, hal_ring_handle_t hal_ring_hdl, uint32_t *headp, uint32_t *tailp, uint8_t ring) { struct hal_srng *srng = (struct hal_srng *)hal_ring_hdl; struct hal_hw_srng_config *ring_config; enum hal_ring_type ring_type = (enum hal_ring_type)ring; if (!hal_soc || !srng) { QDF_TRACE(QDF_MODULE_ID_HAL, QDF_TRACE_LEVEL_ERROR, "%s: Context is Null", __func__); return; } ring_config = HAL_SRNG_CONFIG(hal_soc, ring_type); if (!ring_config->lmac_ring) { if (srng->ring_dir == HAL_SRNG_SRC_RING) { *headp = SRNG_SRC_REG_READ(srng, HP); *tailp = SRNG_SRC_REG_READ(srng, TP); } else { *headp = SRNG_DST_REG_READ(srng, HP); *tailp = SRNG_DST_REG_READ(srng, TP); } } } #ifdef DP_UMAC_HW_RESET_SUPPORT /** * hal_srng_src_hw_write_cons_prefetch_timer() - Write cons prefetch timer reg * @srng: srng handle * @value: value to set * * Return: None */ static inline void hal_srng_src_hw_write_cons_prefetch_timer(struct hal_srng *srng, uint32_t value) { SRNG_SRC_REG_WRITE(srng, CONSUMER_PREFETCH_TIMER, value); } /** * hal_srng_hw_disable_generic() - Private function to disable SRNG * source ring HW * @hal: HAL SOC handle * @srng: SRNG ring pointer */ static inline void hal_srng_hw_disable_generic(struct hal_soc *hal, struct hal_srng *srng) { uint32_t reg_val = 0; struct hal_hw_srng_config *ring_config = HAL_SRNG_CONFIG(hal, srng->ring_type); if (ring_config->lmac_ring) return; if (srng->ring_dir == HAL_SRNG_DST_RING) { reg_val = SRNG_DST_REG_READ(srng, MISC) & ~(SRNG_ENABLE_BIT); SRNG_DST_REG_WRITE(srng, MISC, reg_val); } else { reg_val = SRNG_SRC_REG_READ(srng, MISC) & ~(SRNG_ENABLE_BIT); SRNG_SRC_REG_WRITE(srng, MISC, reg_val); srng->prefetch_timer = SRNG_SRC_REG_READ(srng, CONSUMER_PREFETCH_TIMER); hal_srng_src_hw_write_cons_prefetch_timer(srng, 0); } } #else static inline void hal_srng_hw_disable_generic(struct hal_soc *hal, struct hal_srng *srng) { } static inline void hal_srng_src_hw_write_cons_prefetch_timer(struct hal_srng *srng, uint32_t value) { } #endif #ifndef WLAN_SOFTUMAC_SUPPORT #if defined(WBM_IDLE_LSB_WRITE_CONFIRM_WAR) /** * hal_wbm_idle_lsb_write_confirm() - Check and update WBM_IDLE_LINK ring LSB * @srng: srng handle * * Return: None */ static void hal_wbm_idle_lsb_write_confirm(struct hal_srng *srng) { if (srng->ring_id == HAL_SRNG_WBM_IDLE_LINK) { while (SRNG_SRC_REG_READ(srng, BASE_LSB) != ((unsigned int)srng->ring_base_paddr & 0xffffffff)) SRNG_SRC_REG_WRITE(srng, BASE_LSB, srng->ring_base_paddr & 0xffffffff); } } #else static void hal_wbm_idle_lsb_write_confirm(struct hal_srng *srng) { } #endif /** * hal_srng_src_hw_init_generic() - Private function to initialize SRNG * source ring HW * @hal: HAL SOC handle * @srng: SRNG ring pointer * @idle_check: Check if ring is idle * @idx: ring index */ static inline void hal_srng_src_hw_init_generic(struct hal_soc *hal, struct hal_srng *srng, bool idle_check, uint32_t idx) { uint32_t reg_val = 0; uint64_t tp_addr = 0; hal_debug("hw_init srng %d", srng->ring_id); if (idle_check) { reg_val = SRNG_SRC_REG_READ(srng, MISC); if (!(reg_val & SRNG_IDLE_STATE_BIT)) { hal_err("ring_id %d not in idle state", srng->ring_id); qdf_assert_always(0); } hal_srng_src_hw_write_cons_prefetch_timer(srng, srng->prefetch_timer); } else { reg_val = SRNG_SRC_REG_READ(srng, MISC) & ~(SRNG_ENABLE_BIT); SRNG_SRC_REG_WRITE(srng, MISC, reg_val); } reg_val = 0; if (srng->flags & HAL_SRNG_MSI_INTR) { SRNG_SRC_REG_WRITE(srng, MSI1_BASE_LSB, srng->msi_addr & 0xffffffff); reg_val = SRNG_SM(SRNG_SRC_FLD(MSI1_BASE_MSB, ADDR), (uint64_t)(srng->msi_addr) >> 32) | SRNG_SM(SRNG_SRC_FLD(MSI1_BASE_MSB, MSI1_ENABLE), 1); SRNG_SRC_REG_WRITE(srng, MSI1_BASE_MSB, reg_val); SRNG_SRC_REG_WRITE(srng, MSI1_DATA, qdf_cpu_to_le32(srng->msi_data)); } SRNG_SRC_REG_WRITE(srng, BASE_LSB, srng->ring_base_paddr & 0xffffffff); hal_wbm_idle_lsb_write_confirm(srng); reg_val = SRNG_SM(SRNG_SRC_FLD(BASE_MSB, RING_BASE_ADDR_MSB), ((uint64_t)(srng->ring_base_paddr) >> 32)) | SRNG_SM(SRNG_SRC_FLD(BASE_MSB, RING_SIZE), srng->entry_size * srng->num_entries); SRNG_SRC_REG_WRITE(srng, BASE_MSB, reg_val); reg_val = SRNG_SM(SRNG_SRC_FLD(ID, ENTRY_SIZE), srng->entry_size); SRNG_SRC_REG_WRITE(srng, ID, reg_val); /** * Interrupt setup: * Default interrupt mode is 'pulse'. Need to setup SW_INTERRUPT_MODE * if level mode is required */ reg_val = 0; /* * WAR - Hawkeye v1 has a hardware bug which requires timer value to be * programmed in terms of 1us resolution instead of 8us resolution as * given in MLD. */ if (srng->intr_timer_thres_us) { reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX0, INTERRUPT_TIMER_THRESHOLD), srng->intr_timer_thres_us >> 3); /* For HK v2 this should be (srng->intr_timer_thres_us >> 3) */ } if (srng->intr_batch_cntr_thres_entries) { reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX0, BATCH_COUNTER_THRESHOLD), srng->intr_batch_cntr_thres_entries * srng->entry_size); } SRNG_SRC_REG_WRITE(srng, CONSUMER_INT_SETUP_IX0, reg_val); reg_val = 0; if (srng->flags & HAL_SRNG_LOW_THRES_INTR_ENABLE) { reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX1, LOW_THRESHOLD), srng->u.src_ring.low_threshold); } SRNG_SRC_REG_WRITE(srng, CONSUMER_INT_SETUP_IX1, reg_val); /* As per HW team, TP_ADDR and HP_ADDR for Idle link ring should * remain 0 to avoid some WBM stability issues. Remote head/tail * pointers are not required since this ring is completely managed * by WBM HW */ reg_val = 0; if (srng->ring_id != HAL_SRNG_WBM_IDLE_LINK) { tp_addr = (uint64_t)(hal->shadow_rdptr_mem_paddr + ((unsigned long)(srng->u.src_ring.tp_addr) - (unsigned long)(hal->shadow_rdptr_mem_vaddr))); SRNG_SRC_REG_WRITE(srng, TP_ADDR_LSB, tp_addr & 0xffffffff); SRNG_SRC_REG_WRITE(srng, TP_ADDR_MSB, tp_addr >> 32); } else { reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, RING_ID_DISABLE), 1); } /* Initilaize head and tail pointers to indicate ring is empty */ SRNG_SRC_REG_WRITE(srng, HP, idx * srng->entry_size); SRNG_SRC_REG_WRITE(srng, TP, idx * srng->entry_size); *srng->u.src_ring.tp_addr = idx * srng->entry_size; srng->u.src_ring.hp = idx * srng->entry_size; reg_val |= ((srng->flags & HAL_SRNG_DATA_TLV_SWAP) ? SRNG_SM(SRNG_SRC_FLD(MISC, DATA_TLV_SWAP_BIT), 1) : 0) | ((srng->flags & HAL_SRNG_RING_PTR_SWAP) ? SRNG_SM(SRNG_SRC_FLD(MISC, HOST_FW_SWAP_BIT), 1) : 0) | ((srng->flags & HAL_SRNG_MSI_SWAP) ? SRNG_SM(SRNG_SRC_FLD(MISC, MSI_SWAP_BIT), 1) : 0); /* Loop count is not used for SRC rings */ reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, LOOPCNT_DISABLE), 1); /* * reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, SRNG_ENABLE), 1); * todo: update fw_api and replace with above line * (when SRNG_ENABLE field for the MISC register is available in fw_api) * (WCSS_UMAC_CE_0_SRC_WFSS_CE_CHANNEL_SRC_R0_SRC_RING_MISC) */ reg_val |= SRNG_ENABLE_BIT; SRNG_SRC_REG_WRITE(srng, MISC, reg_val); } #ifdef WLAN_FEATURE_NEAR_FULL_IRQ /** * hal_srng_dst_msi2_setup() - Configure MSI2 register for a SRNG * @srng: SRNG handle * * Return: None */ static inline void hal_srng_dst_msi2_setup(struct hal_srng *srng) { uint32_t reg_val = 0; if (srng->u.dst_ring.nf_irq_support) { SRNG_DST_REG_WRITE(srng, MSI2_BASE_LSB, srng->msi2_addr & 0xffffffff); reg_val = SRNG_SM(SRNG_DST_FLD(MSI2_BASE_MSB, ADDR), (uint64_t)(srng->msi2_addr) >> 32) | SRNG_SM(SRNG_DST_FLD(MSI2_BASE_MSB, MSI2_ENABLE), 1); SRNG_DST_REG_WRITE(srng, MSI2_BASE_MSB, reg_val); SRNG_DST_REG_WRITE(srng, MSI2_DATA, qdf_cpu_to_le32(srng->msi2_data)); } } /** * hal_srng_dst_near_full_int_setup() - Configure near-full params for SRNG * @srng: SRNG handle * * Return: None */ static inline void hal_srng_dst_near_full_int_setup(struct hal_srng *srng) { uint32_t reg_val = 0; if (srng->u.dst_ring.nf_irq_support) { if (srng->intr_timer_thres_us) { reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT2_SETUP, INTERRUPT2_TIMER_THRESHOLD), srng->intr_timer_thres_us >> 3); } reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT2_SETUP, HIGH_THRESHOLD), srng->u.dst_ring.high_thresh * srng->entry_size); } SRNG_DST_REG_WRITE(srng, PRODUCER_INT2_SETUP, reg_val); } #else static inline void hal_srng_dst_msi2_setup(struct hal_srng *srng) { } static inline void hal_srng_dst_near_full_int_setup(struct hal_srng *srng) { } #endif /** * hal_srng_dst_hw_init_generic() - Private function to initialize SRNG * destination ring HW * @hal: HAL SOC handle * @srng: SRNG ring pointer * @idle_check: Check if ring is idle * @idx: Ring index */ static inline void hal_srng_dst_hw_init_generic(struct hal_soc *hal, struct hal_srng *srng, bool idle_check, uint32_t idx) { uint32_t reg_val = 0; uint64_t hp_addr = 0; hal_debug("hw_init srng %d", srng->ring_id); if (idle_check) { reg_val = SRNG_DST_REG_READ(srng, MISC); if (!(reg_val & SRNG_IDLE_STATE_BIT)) { hal_err("ring_id %d not in idle state", srng->ring_id); qdf_assert_always(0); } } else { reg_val = SRNG_DST_REG_READ(srng, MISC) & ~(SRNG_ENABLE_BIT); SRNG_DST_REG_WRITE(srng, MISC, reg_val); } reg_val = 0; if (srng->flags & HAL_SRNG_MSI_INTR) { SRNG_DST_REG_WRITE(srng, MSI1_BASE_LSB, srng->msi_addr & 0xffffffff); reg_val = SRNG_SM(SRNG_DST_FLD(MSI1_BASE_MSB, ADDR), (uint64_t)(srng->msi_addr) >> 32) | SRNG_SM(SRNG_DST_FLD(MSI1_BASE_MSB, MSI1_ENABLE), 1); SRNG_DST_REG_WRITE(srng, MSI1_BASE_MSB, reg_val); SRNG_DST_REG_WRITE(srng, MSI1_DATA, qdf_cpu_to_le32(srng->msi_data)); hal_srng_dst_msi2_setup(srng); } SRNG_DST_REG_WRITE(srng, BASE_LSB, srng->ring_base_paddr & 0xffffffff); reg_val = SRNG_SM(SRNG_DST_FLD(BASE_MSB, RING_BASE_ADDR_MSB), ((uint64_t)(srng->ring_base_paddr) >> 32)) | SRNG_SM(SRNG_DST_FLD(BASE_MSB, RING_SIZE), srng->entry_size * srng->num_entries); SRNG_DST_REG_WRITE(srng, BASE_MSB, reg_val); reg_val = SRNG_SM(SRNG_DST_FLD(ID, RING_ID), srng->ring_id) | SRNG_SM(SRNG_DST_FLD(ID, ENTRY_SIZE), srng->entry_size); SRNG_DST_REG_WRITE(srng, ID, reg_val); /** * Interrupt setup: * Default interrupt mode is 'pulse'. Need to setup SW_INTERRUPT_MODE * if level mode is required */ reg_val = 0; if (srng->intr_timer_thres_us) { reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT_SETUP, INTERRUPT_TIMER_THRESHOLD), srng->intr_timer_thres_us >> 3); } if (srng->intr_batch_cntr_thres_entries) { reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT_SETUP, BATCH_COUNTER_THRESHOLD), srng->intr_batch_cntr_thres_entries * srng->entry_size); } SRNG_DST_REG_WRITE(srng, PRODUCER_INT_SETUP, reg_val); /** * Near-Full Interrupt setup: * Default interrupt mode is 'pulse'. Need to setup SW_INTERRUPT_MODE * if level mode is required */ hal_srng_dst_near_full_int_setup(srng); hp_addr = (uint64_t)(hal->shadow_rdptr_mem_paddr + ((unsigned long)(srng->u.dst_ring.hp_addr) - (unsigned long)(hal->shadow_rdptr_mem_vaddr))); SRNG_DST_REG_WRITE(srng, HP_ADDR_LSB, hp_addr & 0xffffffff); SRNG_DST_REG_WRITE(srng, HP_ADDR_MSB, hp_addr >> 32); /* Initilaize head and tail pointers to indicate ring is empty */ SRNG_DST_REG_WRITE(srng, HP, idx * srng->entry_size); SRNG_DST_REG_WRITE(srng, TP, idx * srng->entry_size); *srng->u.dst_ring.hp_addr = idx * srng->entry_size; srng->u.dst_ring.tp = idx * srng->entry_size; reg_val = ((srng->flags & HAL_SRNG_DATA_TLV_SWAP) ? SRNG_SM(SRNG_DST_FLD(MISC, DATA_TLV_SWAP_BIT), 1) : 0) | ((srng->flags & HAL_SRNG_RING_PTR_SWAP) ? SRNG_SM(SRNG_DST_FLD(MISC, HOST_FW_SWAP_BIT), 1) : 0) | ((srng->flags & HAL_SRNG_MSI_SWAP) ? SRNG_SM(SRNG_DST_FLD(MISC, MSI_SWAP_BIT), 1) : 0); /* * reg_val |= SRNG_SM(SRNG_SRC_FLD(MISC, SRNG_ENABLE), 1); * todo: update fw_api and replace with above line * (when SRNG_ENABLE field for the MISC register is available in fw_api) * (WCSS_UMAC_CE_0_SRC_WFSS_CE_CHANNEL_SRC_R0_SRC_RING_MISC) */ reg_val |= SRNG_ENABLE_BIT; SRNG_DST_REG_WRITE(srng, MISC, reg_val); } /** * hal_srng_hw_reg_offset_init_generic() - Initialize the HW srng reg offset * @hal_soc: HAL Soc handle * * Return: None */ static inline void hal_srng_hw_reg_offset_init_generic(struct hal_soc *hal_soc) { int32_t *hw_reg_offset = hal_soc->hal_hw_reg_offset; /* dst */ hw_reg_offset[DST_HP] = REG_OFFSET(DST, HP); hw_reg_offset[DST_TP] = REG_OFFSET(DST, TP); hw_reg_offset[DST_ID] = REG_OFFSET(DST, ID); hw_reg_offset[DST_MISC] = REG_OFFSET(DST, MISC); hw_reg_offset[DST_HP_ADDR_LSB] = REG_OFFSET(DST, HP_ADDR_LSB); hw_reg_offset[DST_HP_ADDR_MSB] = REG_OFFSET(DST, HP_ADDR_MSB); hw_reg_offset[DST_MSI1_BASE_LSB] = REG_OFFSET(DST, MSI1_BASE_LSB); hw_reg_offset[DST_MSI1_BASE_MSB] = REG_OFFSET(DST, MSI1_BASE_MSB); hw_reg_offset[DST_MSI1_DATA] = REG_OFFSET(DST, MSI1_DATA); hw_reg_offset[DST_BASE_LSB] = REG_OFFSET(DST, BASE_LSB); hw_reg_offset[DST_BASE_MSB] = REG_OFFSET(DST, BASE_MSB); hw_reg_offset[DST_PRODUCER_INT_SETUP] = REG_OFFSET(DST, PRODUCER_INT_SETUP); /* src */ hw_reg_offset[SRC_HP] = REG_OFFSET(SRC, HP); hw_reg_offset[SRC_TP] = REG_OFFSET(SRC, TP); hw_reg_offset[SRC_ID] = REG_OFFSET(SRC, ID); hw_reg_offset[SRC_MISC] = REG_OFFSET(SRC, MISC); hw_reg_offset[SRC_TP_ADDR_LSB] = REG_OFFSET(SRC, TP_ADDR_LSB); hw_reg_offset[SRC_TP_ADDR_MSB] = REG_OFFSET(SRC, TP_ADDR_MSB); hw_reg_offset[SRC_MSI1_BASE_LSB] = REG_OFFSET(SRC, MSI1_BASE_LSB); hw_reg_offset[SRC_MSI1_BASE_MSB] = REG_OFFSET(SRC, MSI1_BASE_MSB); hw_reg_offset[SRC_MSI1_DATA] = REG_OFFSET(SRC, MSI1_DATA); hw_reg_offset[SRC_BASE_LSB] = REG_OFFSET(SRC, BASE_LSB); hw_reg_offset[SRC_BASE_MSB] = REG_OFFSET(SRC, BASE_MSB); hw_reg_offset[SRC_CONSUMER_INT_SETUP_IX0] = REG_OFFSET(SRC, CONSUMER_INT_SETUP_IX0); hw_reg_offset[SRC_CONSUMER_INT_SETUP_IX1] = REG_OFFSET(SRC, CONSUMER_INT_SETUP_IX1); #ifdef DP_UMAC_HW_RESET_SUPPORT hw_reg_offset[SRC_CONSUMER_PREFETCH_TIMER] = REG_OFFSET(SRC, CONSUMER_PREFETCH_TIMER); #endif } #else static inline void hal_srng_src_hw_init_generic(struct hal_soc *hal, struct hal_srng *srng, bool idle_check, uint32_t idx) {} static inline void hal_srng_dst_hw_init_generic(struct hal_soc *hal, struct hal_srng *srng, bool idle_check, uint32_t idx) {} #endif #ifdef FEATURE_DIRECT_LINK /** * hal_srng_set_msi_config() - Set the MSI config and enable the SRNG * @ring_hdl: srng handle * @params: ring parameters * * Return: QDF status */ static inline QDF_STATUS hal_srng_set_msi_config(hal_ring_handle_t ring_hdl, void *params) { struct hal_srng *srng = (struct hal_srng *)ring_hdl; struct hal_srng_params *ring_params = (struct hal_srng_params *)params; uint32_t reg_val; srng->intr_timer_thres_us = ring_params->intr_timer_thres_us; srng->intr_batch_cntr_thres_entries = ring_params->intr_batch_cntr_thres_entries; srng->msi_addr = ring_params->msi_addr; srng->msi_data = ring_params->msi_data; if (!srng->msi_addr && !srng->msi_data) { if (srng->ring_dir == HAL_SRNG_SRC_RING) SRNG_SRC_REG_WRITE(srng, MSI1_BASE_MSB, 0); else SRNG_DST_REG_WRITE(srng, MSI1_BASE_MSB, 0); return QDF_STATUS_SUCCESS; } if (srng->ring_dir == HAL_SRNG_SRC_RING) { reg_val = 0; SRNG_SRC_REG_WRITE(srng, MSI1_BASE_LSB, srng->msi_addr & 0xffffffff); reg_val = SRNG_SM(SRNG_SRC_FLD(MSI1_BASE_MSB, ADDR), (uint64_t)(srng->msi_addr) >> 32) | SRNG_SM(SRNG_SRC_FLD(MSI1_BASE_MSB, MSI1_ENABLE), 1); SRNG_SRC_REG_WRITE(srng, MSI1_BASE_MSB, reg_val); SRNG_SRC_REG_WRITE(srng, MSI1_DATA, qdf_cpu_to_le32(srng->msi_data)); reg_val = 0; if (srng->intr_timer_thres_us) { reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX0, INTERRUPT_TIMER_THRESHOLD), srng->intr_timer_thres_us); } if (srng->intr_batch_cntr_thres_entries) { reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX0, BATCH_COUNTER_THRESHOLD), srng->intr_batch_cntr_thres_entries * srng->entry_size); } SRNG_SRC_REG_WRITE(srng, CONSUMER_INT_SETUP_IX0, reg_val); } else { reg_val = 0; SRNG_DST_REG_WRITE(srng, MSI1_BASE_LSB, srng->msi_addr & 0xffffffff); reg_val = SRNG_SM(SRNG_DST_FLD(MSI1_BASE_MSB, ADDR), (uint64_t)(srng->msi_addr) >> 32) | SRNG_SM(SRNG_DST_FLD(MSI1_BASE_MSB, MSI1_ENABLE), 1); SRNG_DST_REG_WRITE(srng, MSI1_BASE_MSB, reg_val); SRNG_DST_REG_WRITE(srng, MSI1_DATA, qdf_cpu_to_le32(srng->msi_data)); reg_val = 0; if (srng->intr_timer_thres_us) { reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT_SETUP, INTERRUPT_TIMER_THRESHOLD), srng->intr_timer_thres_us >> 3); } if (srng->intr_batch_cntr_thres_entries) { reg_val |= SRNG_SM(SRNG_DST_FLD(PRODUCER_INT_SETUP, BATCH_COUNTER_THRESHOLD), srng->intr_batch_cntr_thres_entries * srng->entry_size); } SRNG_DST_REG_WRITE(srng, PRODUCER_INT_SETUP, reg_val); } return QDF_STATUS_SUCCESS; } #else static inline QDF_STATUS hal_srng_set_msi_config(hal_ring_handle_t ring_hdl, void *params) { return QDF_STATUS_E_NOSUPPORT; } #endif #endif /* HAL_GENERIC_API_H_ */