diff --git a/drivers/soc/qcom/sps/bam.c b/drivers/soc/qcom/sps/bam.c index 1fa340a18eb1..e605cbcaa204 100644 --- a/drivers/soc/qcom/sps/bam.c +++ b/drivers/soc/qcom/sps/bam.c @@ -948,6 +948,17 @@ int bam_init(void *base, u32 ee, return 0; } +/** + * Set BAM global interrupt + */ +void bam_set_global_irq(void *base, u32 ee, u32 irq_mask, bool en) +{ + if (en) + bam_write_reg_field(base, IRQ_SRCS_MSK_EE, ee, BAM_IRQ, 1); + else + bam_write_reg_field(base, IRQ_SRCS_MSK_EE, ee, BAM_IRQ, 0); +} + /** * Set BAM global execution environment * diff --git a/drivers/soc/qcom/sps/bam.h b/drivers/soc/qcom/sps/bam.h index 4305251689c9..74e474d23090 100644 --- a/drivers/soc/qcom/sps/bam.h +++ b/drivers/soc/qcom/sps/bam.h @@ -185,6 +185,21 @@ void bam_output_register_content(void *base, u32 ee); u32 bam_check_irq_source(void *base, u32 ee, u32 mask, enum sps_callback_case *cb_case); +/** + * Set BAM global interrupts + * + * This function initializes a BAM device. + * + * @base - BAM virtual base address. + * + * @ee - BAM execution environment index + * + * @mask - error interrupts mask + * + * @en - Enable or Disable interrupt + * + */ +void bam_set_global_irq(void *base, u32 ee, u32 mask, bool en); /** * Initialize a BAM pipe diff --git a/drivers/soc/qcom/sps/sps.c b/drivers/soc/qcom/sps/sps.c index d94b4f5b073f..77b479a25af4 100644 --- a/drivers/soc/qcom/sps/sps.c +++ b/drivers/soc/qcom/sps/sps.c @@ -2427,6 +2427,58 @@ int sps_bam_process_irq(unsigned long dev) } EXPORT_SYMBOL(sps_bam_process_irq); +/* + * Enable all IRQs of a BAM + */ +int sps_bam_enable_irqs(unsigned long dev) +{ + struct sps_bam *bam; + + if (!dev) { + SPS_ERR(sps, "sps: BAM handle is NULL\n"); + return SPS_ERROR; + } + + bam = sps_h2bam(dev); + if (bam == NULL) { + SPS_ERR(sps, "sps: BAM is not found by handle\n"); + return SPS_ERROR; + } + + SPS_DBG1(bam, "sps: BAM: %pa\n", BAM_ID(bam)); + + sps_bam_enable_all_irqs(bam); + + return 0; +} +EXPORT_SYMBOL(sps_bam_enable_irqs); + +/* + * Disable all IRQs of a BAM + */ +int sps_bam_disable_irqs(unsigned long dev) +{ + struct sps_bam *bam; + + if (!dev) { + SPS_ERR(sps, "sps: BAM handle is NULL\n"); + return SPS_ERROR; + } + + bam = sps_h2bam(dev); + if (bam == NULL) { + SPS_ERR(sps, "sps: BAM is not found by handle\n"); + return SPS_ERROR; + } + + SPS_DBG1(bam, "sps: BAM: %pa\n", BAM_ID(bam)); + + sps_bam_disable_all_irqs(bam); + + return 0; +} +EXPORT_SYMBOL(sps_bam_disable_irqs); + /* * Get address info of a BAM */ diff --git a/drivers/soc/qcom/sps/sps_bam.c b/drivers/soc/qcom/sps/sps_bam.c index 87d0b40278e9..0365be601156 100644 --- a/drivers/soc/qcom/sps/sps_bam.c +++ b/drivers/soc/qcom/sps/sps_bam.c @@ -125,6 +125,13 @@ int sps_bam_check_irq(struct sps_bam *dev) spin_lock_irqsave(&dev->isr_lock, flags); + if (dev->no_serve_irq) { + SPS_ERR(dev, "sps:IRQ from BAM %pa can't be currently served\n", + BAM_ID(dev)); + spin_unlock_irqrestore(&dev->isr_lock, flags); + return ret; + } + polling: /* Get BAM interrupt source(s) */ if ((dev->state & BAM_STATE_MTI) == 0) { @@ -581,6 +588,7 @@ int sps_bam_device_init(struct sps_bam *dev) dev->state = 0; dev->pipe_active_mask = 0; dev->pipe_remote_mask = 0; + dev->no_serve_irq = false; INIT_LIST_HEAD(&dev->pipes_q); spin_lock_init(&dev->isr_lock); @@ -1324,6 +1332,73 @@ int sps_bam_pipe_set_params(struct sps_bam *dev, u32 pipe_index, u32 options) return 0; } +/** + * Enable all IRQs of a BAM and its pipes. + * + */ +void sps_bam_enable_all_irqs(struct sps_bam *dev) +{ + struct sps_pipe *pipe; + u32 irq_mask; + unsigned long flags = 0; + + spin_lock_irqsave(&dev->isr_lock, flags); + /* Enable global interrupt */ + irq_mask = BAM_IRQ_ALL; + bam_set_global_irq(&dev->base, dev->props.ee, irq_mask, true); + + /* Enable all pipe interrupts */ + pipe = list_first_entry(&dev->pipes_q, struct sps_pipe, list); + + list_for_each_entry(pipe, &dev->pipes_q, list) { + /* Check this pipe's bit in the source mask */ + if (BAM_PIPE_IS_ASSIGNED(pipe) + && (!pipe->disconnecting)) { + bam_pipe_set_irq(&dev->base, pipe->pipe_index, BAM_ENABLE, + pipe->irq_mask, dev->props.ee); + } + } + + // Write memory barrier + wmb(); + dev->no_serve_irq = false; + + spin_unlock_irqrestore(&dev->isr_lock, flags); +} + +/** + * Disable all IRQs of a BAM and its pipes. + * + */ +void sps_bam_disable_all_irqs(struct sps_bam *dev) +{ + struct sps_pipe *pipe; + unsigned long flags = 0; + + spin_lock_irqsave(&dev->isr_lock, flags); + + /* Disable global interrupt */ + bam_set_global_irq(&dev->base, dev->props.ee, 0, false); + + /* Disable all pipe interrupts */ + pipe = list_first_entry(&dev->pipes_q, struct sps_pipe, list); + + list_for_each_entry(pipe, &dev->pipes_q, list) { + /* Check this pipe's bit in the source mask */ + if (BAM_PIPE_IS_ASSIGNED(pipe) + && (!pipe->disconnecting)) { + bam_pipe_set_irq(&dev->base, pipe->pipe_index, BAM_DISABLE, + 0, dev->props.ee); + } + } + + // Write memory barrier + wmb(); + dev->no_serve_irq = true; + + spin_unlock_irqrestore(&dev->isr_lock, flags); +} + /** * Enable a BAM pipe * diff --git a/drivers/soc/qcom/sps/sps_bam.h b/drivers/soc/qcom/sps/sps_bam.h index d687f0334f68..71411fc1accc 100644 --- a/drivers/soc/qcom/sps/sps_bam.h +++ b/drivers/soc/qcom/sps/sps_bam.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2011-2019, 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ /* * Function and data structure declarations for SPS BAM handling. @@ -220,6 +221,9 @@ struct sps_bam { /* Desc cache pointers */ u8 *desc_cache_pointers[BAM_MAX_PIPES]; + + /* ISR behavior */ + bool no_serve_irq; }; /** @@ -584,6 +588,24 @@ int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index, */ int sps_bam_check_irq(struct sps_bam *dev); +/* + * sps_bam_enable_all_irqs - Enable all IRQs of a BAM + * @dev - pointer to BAM device descriptor + * + * This function enables all irqs of a BAM and its pipes. + * + */ +void sps_bam_enable_all_irqs(struct sps_bam *dev); + +/* + * sps_bam_disable_all_irqs - Disable all IRQs of a BAM + * @dev - pointer to BAM device descriptor + * + * This function disables all irqs of a BAM and its pipes. + * + */ +void sps_bam_disable_all_irqs(struct sps_bam *dev); + /* * sps_bam_pipe_pending_desc - checking pending descriptor. * @dev: BAM device handle diff --git a/include/linux/msm-sps.h b/include/linux/msm-sps.h index b6ff335f95d1..429546a85959 100644 --- a/include/linux/msm-sps.h +++ b/include/linux/msm-sps.h @@ -1408,6 +1408,26 @@ int sps_pipe_pending_desc(unsigned long dev, u32 pipe, bool *pending); */ int sps_bam_process_irq(unsigned long dev); +/* + * sps_bam_enable_irqs - enable IRQs of a BAM. + * @dev: BAM device handle + * + * This function enables all IRQs of a BAM. + * + * Return: 0 on success, negative value on error + */ +int sps_bam_enable_irqs(unsigned long dev); + +/* + * sps_bam_disable_irqs - disable IRQs of a BAM. + * @dev: BAM device handle + * + * This function disables all IRQs of a BAM. + * + * Return: 0 on success, negative value on error + */ +int sps_bam_disable_irqs(unsigned long dev); + /* * sps_get_bam_addr - get address info of a BAM. * @dev: BAM device handle @@ -1620,6 +1640,16 @@ static inline int sps_bam_process_irq(unsigned long dev) return -EPERM; } +static inline int sps_bam_enable_irqs(unsigned long dev) +{ + return -EPERM; +} + +static inline int sps_bam_disable_irqs(unsigned long dev) +{ + return -EPERM; +} + static inline int sps_get_bam_addr(unsigned long dev, phys_addr_t *base, u32 *size) {