diff mbox

[V4,05/10] dmaengine: qcom_hidma: make pending_tre_count atomic

Message ID 1475115167-5898-6-git-send-email-okaya@codeaurora.org (mailing list archive)
State Changes Requested
Headers show

Commit Message

Sinan Kaya Sept. 29, 2016, 2:12 a.m. UTC
Getting ready for the MSI interrupts. The pending_tre_count is used
in the interrupt handler to make sure all outstanding requests are
serviced.

Making it atomic so that it can be updated from multiple contexts.

Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
---
 drivers/dma/qcom/hidma.h     |  2 +-
 drivers/dma/qcom/hidma_dbg.c |  3 ++-
 drivers/dma/qcom/hidma_ll.c  | 13 ++++++-------
 3 files changed, 9 insertions(+), 9 deletions(-)

Comments

Vinod Koul Oct. 1, 2016, 6:19 a.m. UTC | #1
On Wed, Sep 28, 2016 at 10:12:42PM -0400, Sinan Kaya wrote:
> Getting ready for the MSI interrupts. The pending_tre_count is used
> in the interrupt handler to make sure all outstanding requests are
> serviced.
> 
> Making it atomic so that it can be updated from multiple contexts.

How is it multiple contexts? It's either existing context of MSI, not both!

> 
> Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
> ---
>  drivers/dma/qcom/hidma.h     |  2 +-
>  drivers/dma/qcom/hidma_dbg.c |  3 ++-
>  drivers/dma/qcom/hidma_ll.c  | 13 ++++++-------
>  3 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h
> index e52e207..3f2ddd4 100644
> --- a/drivers/dma/qcom/hidma.h
> +++ b/drivers/dma/qcom/hidma.h
> @@ -58,7 +58,7 @@ struct hidma_lldev {
>  	void __iomem *evca;		/* Event Channel address          */
>  	struct hidma_tre
>  		**pending_tre_list;	/* Pointers to pending TREs	  */
> -	s32 pending_tre_count;		/* Number of TREs pending	  */
> +	atomic_t pending_tre_count;	/* Number of TREs pending	  */
>  
>  	void *tre_ring;			/* TRE ring			  */
>  	dma_addr_t tre_dma;		/* TRE ring to be shared with HW  */
> diff --git a/drivers/dma/qcom/hidma_dbg.c b/drivers/dma/qcom/hidma_dbg.c
> index fa827e5..87db285 100644
> --- a/drivers/dma/qcom/hidma_dbg.c
> +++ b/drivers/dma/qcom/hidma_dbg.c
> @@ -74,7 +74,8 @@ static void hidma_ll_devstats(struct seq_file *s, void *llhndl)
>  	seq_printf(s, "tre_ring_handle=%pap\n", &lldev->tre_dma);
>  	seq_printf(s, "tre_ring_size = 0x%x\n", lldev->tre_ring_size);
>  	seq_printf(s, "tre_processed_off = 0x%x\n", lldev->tre_processed_off);
> -	seq_printf(s, "pending_tre_count=%d\n", lldev->pending_tre_count);
> +	seq_printf(s, "pending_tre_count=%d\n",
> +			atomic_read(&lldev->pending_tre_count));
>  	seq_printf(s, "evca=%p\n", lldev->evca);
>  	seq_printf(s, "evre_ring=%p\n", lldev->evre_ring);
>  	seq_printf(s, "evre_ring_handle=%pap\n", &lldev->evre_dma);
> diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c
> index 3224f24..29fef4f 100644
> --- a/drivers/dma/qcom/hidma_ll.c
> +++ b/drivers/dma/qcom/hidma_ll.c
> @@ -218,10 +218,9 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator,
>  	 * Keep track of pending TREs that SW is expecting to receive
>  	 * from HW. We got one now. Decrement our counter.
>  	 */
> -	lldev->pending_tre_count--;
> -	if (lldev->pending_tre_count < 0) {
> +	if (atomic_dec_return(&lldev->pending_tre_count) < 0) {
>  		dev_warn(lldev->dev, "tre count mismatch on completion");
> -		lldev->pending_tre_count = 0;
> +		atomic_set(&lldev->pending_tre_count, 0);
>  	}
>  
>  	spin_unlock_irqrestore(&lldev->lock, flags);
> @@ -321,7 +320,7 @@ void hidma_cleanup_pending_tre(struct hidma_lldev *lldev, u8 err_info,
>  	u32 tre_read_off;
>  
>  	tre_iterator = lldev->tre_processed_off;
> -	while (lldev->pending_tre_count) {
> +	while (atomic_read(&lldev->pending_tre_count)) {
>  		if (hidma_post_completed(lldev, tre_iterator, err_info,
>  					 err_code))
>  			break;
> @@ -548,7 +547,7 @@ void hidma_ll_queue_request(struct hidma_lldev *lldev, u32 tre_ch)
>  	tre->err_code = 0;
>  	tre->err_info = 0;
>  	tre->queued = 1;
> -	lldev->pending_tre_count++;
> +	atomic_inc(&lldev->pending_tre_count);
>  	lldev->tre_write_offset = (lldev->tre_write_offset + HIDMA_TRE_SIZE)
>  					% lldev->tre_ring_size;
>  	spin_unlock_irqrestore(&lldev->lock, flags);
> @@ -654,7 +653,7 @@ int hidma_ll_setup(struct hidma_lldev *lldev)
>  	u32 val;
>  	u32 nr_tres = lldev->nr_tres;
>  
> -	lldev->pending_tre_count = 0;
> +	atomic_set(&lldev->pending_tre_count, 0);
>  	lldev->tre_processed_off = 0;
>  	lldev->evre_processed_off = 0;
>  	lldev->tre_write_offset = 0;
> @@ -816,7 +815,7 @@ int hidma_ll_uninit(struct hidma_lldev *lldev)
>  	tasklet_kill(&lldev->task);
>  	memset(lldev->trepool, 0, required_bytes);
>  	lldev->trepool = NULL;
> -	lldev->pending_tre_count = 0;
> +	atomic_set(&lldev->pending_tre_count, 0);
>  	lldev->tre_write_offset = 0;
>  
>  	rc = hidma_ll_reset(lldev);
> -- 
> 1.9.1
>
Sinan Kaya Oct. 1, 2016, 3:19 p.m. UTC | #2
On 10/1/2016 2:19 AM, Vinod Koul wrote:
>> Making it atomic so that it can be updated from multiple contexts.
> How is it multiple contexts? It's either existing context of MSI, not both!
> 

I was trying to mean multiple processor contexts here. The driver allocates 11
MSI interrupts. Each MSI interrupt can be assigned to a different CPU. Then, 
we have a race condition for common variables as they share the same interrupt
handler with a different cause bit. 

I will put the above description into the commit text.
Vinod Koul Oct. 3, 2016, 3:39 a.m. UTC | #3
On Sat, Oct 01, 2016 at 11:19:43AM -0400, Sinan Kaya wrote:
> On 10/1/2016 2:19 AM, Vinod Koul wrote:
> >> Making it atomic so that it can be updated from multiple contexts.
> > How is it multiple contexts? It's either existing context of MSI, not both!
> > 
> 
> I was trying to mean multiple processor contexts here. The driver allocates 11
> MSI interrupts. Each MSI interrupt can be assigned to a different CPU. Then, 
> we have a race condition for common variables as they share the same interrupt
> handler with a different cause bit. 
> 
> I will put the above description into the commit text.

Sounds better :)
diff mbox

Patch

diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h
index e52e207..3f2ddd4 100644
--- a/drivers/dma/qcom/hidma.h
+++ b/drivers/dma/qcom/hidma.h
@@ -58,7 +58,7 @@  struct hidma_lldev {
 	void __iomem *evca;		/* Event Channel address          */
 	struct hidma_tre
 		**pending_tre_list;	/* Pointers to pending TREs	  */
-	s32 pending_tre_count;		/* Number of TREs pending	  */
+	atomic_t pending_tre_count;	/* Number of TREs pending	  */
 
 	void *tre_ring;			/* TRE ring			  */
 	dma_addr_t tre_dma;		/* TRE ring to be shared with HW  */
diff --git a/drivers/dma/qcom/hidma_dbg.c b/drivers/dma/qcom/hidma_dbg.c
index fa827e5..87db285 100644
--- a/drivers/dma/qcom/hidma_dbg.c
+++ b/drivers/dma/qcom/hidma_dbg.c
@@ -74,7 +74,8 @@  static void hidma_ll_devstats(struct seq_file *s, void *llhndl)
 	seq_printf(s, "tre_ring_handle=%pap\n", &lldev->tre_dma);
 	seq_printf(s, "tre_ring_size = 0x%x\n", lldev->tre_ring_size);
 	seq_printf(s, "tre_processed_off = 0x%x\n", lldev->tre_processed_off);
-	seq_printf(s, "pending_tre_count=%d\n", lldev->pending_tre_count);
+	seq_printf(s, "pending_tre_count=%d\n",
+			atomic_read(&lldev->pending_tre_count));
 	seq_printf(s, "evca=%p\n", lldev->evca);
 	seq_printf(s, "evre_ring=%p\n", lldev->evre_ring);
 	seq_printf(s, "evre_ring_handle=%pap\n", &lldev->evre_dma);
diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c
index 3224f24..29fef4f 100644
--- a/drivers/dma/qcom/hidma_ll.c
+++ b/drivers/dma/qcom/hidma_ll.c
@@ -218,10 +218,9 @@  static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator,
 	 * Keep track of pending TREs that SW is expecting to receive
 	 * from HW. We got one now. Decrement our counter.
 	 */
-	lldev->pending_tre_count--;
-	if (lldev->pending_tre_count < 0) {
+	if (atomic_dec_return(&lldev->pending_tre_count) < 0) {
 		dev_warn(lldev->dev, "tre count mismatch on completion");
-		lldev->pending_tre_count = 0;
+		atomic_set(&lldev->pending_tre_count, 0);
 	}
 
 	spin_unlock_irqrestore(&lldev->lock, flags);
@@ -321,7 +320,7 @@  void hidma_cleanup_pending_tre(struct hidma_lldev *lldev, u8 err_info,
 	u32 tre_read_off;
 
 	tre_iterator = lldev->tre_processed_off;
-	while (lldev->pending_tre_count) {
+	while (atomic_read(&lldev->pending_tre_count)) {
 		if (hidma_post_completed(lldev, tre_iterator, err_info,
 					 err_code))
 			break;
@@ -548,7 +547,7 @@  void hidma_ll_queue_request(struct hidma_lldev *lldev, u32 tre_ch)
 	tre->err_code = 0;
 	tre->err_info = 0;
 	tre->queued = 1;
-	lldev->pending_tre_count++;
+	atomic_inc(&lldev->pending_tre_count);
 	lldev->tre_write_offset = (lldev->tre_write_offset + HIDMA_TRE_SIZE)
 					% lldev->tre_ring_size;
 	spin_unlock_irqrestore(&lldev->lock, flags);
@@ -654,7 +653,7 @@  int hidma_ll_setup(struct hidma_lldev *lldev)
 	u32 val;
 	u32 nr_tres = lldev->nr_tres;
 
-	lldev->pending_tre_count = 0;
+	atomic_set(&lldev->pending_tre_count, 0);
 	lldev->tre_processed_off = 0;
 	lldev->evre_processed_off = 0;
 	lldev->tre_write_offset = 0;
@@ -816,7 +815,7 @@  int hidma_ll_uninit(struct hidma_lldev *lldev)
 	tasklet_kill(&lldev->task);
 	memset(lldev->trepool, 0, required_bytes);
 	lldev->trepool = NULL;
-	lldev->pending_tre_count = 0;
+	atomic_set(&lldev->pending_tre_count, 0);
 	lldev->tre_write_offset = 0;
 
 	rc = hidma_ll_reset(lldev);