All of lore.kernel.org
 help / color / mirror / Atom feed
From: Javi Merino <javi.merino@arm.com>
To: Jassi Brar <jassisinghbrar@gmail.com>
Cc: Jassi Brar <jaswinder.singh@linaro.org>,
	Kukjin Kim <kgene.kim@samsung.com>,
	Boojin Kim <boojin.kim@samsung.com>,
	"vinod.koul@intel.com" <vinod.koul@intel.com>,
	linux-samsung-soc <linux-samsung-soc@vger.kernel.org>,
	Thomas Abraham <thomas.abraham@linaro.org>,
	"linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2] ARM: pl330: Fix a race condition
Date: Fri, 09 Dec 2011 19:50:08 +0000	[thread overview]
Message-ID: <4EE26670.1060005@arm.com> (raw)
In-Reply-To: <CABb+yY2-1B65-UqRofj72zVuZUUk5c6pkqNGs15ZLnkrVheRDQ@mail.gmail.com>

On 09/12/11 16:50, Jassi Brar wrote:
> What do you think about ...
> 
> diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
> index f407a6b..3a51cdd 100644
> --- a/arch/arm/common/pl330.c
> +++ b/arch/arm/common/pl330.c
> @@ -1546,7 +1546,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
> 
>  		/* Start the next */
>  	case PL330_OP_START:
> -		if (!_thrd_active(thrd) && !_start(thrd))
> +		if (_state(thrd) == PL330_STATE_STOPPED && !_start(thrd))

Reintroduces the race condition, but you shorten the window:

  * pl330_submit_req()
  * pl330_chan_ctrl(PL330_OP_START)
  * pl330_submit_req()
  * pl330_chan_ctrl():spin_lock_irqsave()
  * Transfer 1 finishes, interrupt raised (but pl330_update() is not
    called as interrupts are disabled)
  * _state(thrd) is PL330_STATE_STOPPED , _start() reissues the first
    transaction.
  * pl330_chan_ctrl():spin_lock_irqrestore()
  * pl330_update() called for the first transaction, but it is running
    again!

What about properly tracking what we have sent to the DMA?  Something
like the following (warning *ugly* and untested code ahead, may eat your
kitten):

diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index f407a6b..3652c4b 100644
--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -303,6 +303,7 @@ struct pl330_thread {
 	struct _pl330_req req[2];
 	/* Index of the last submitted request */
 	unsigned lstenq;
+	int req_running;
 };

 enum pl330_dmac_state {
@@ -836,31 +837,6 @@ static inline u32 _state(struct pl330_thread *thrd)
 	}
 }

-/* If the request 'req' of thread 'thrd' is currently active */
-static inline bool _req_active(struct pl330_thread *thrd,
-		struct _pl330_req *req)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	u32 buf = req->mc_bus, pc = readl(regs + CPC(thrd->id));
-
-	if (IS_FREE(req))
-		return false;
-
-	return (pc >= buf && pc <= buf + req->mc_len) ? true : false;
-}
-
-/* Returns 0 if the thread is inactive, ID of active req + 1 otherwise */
-static inline unsigned _thrd_active(struct pl330_thread *thrd)
-{
-	if (_req_active(thrd, &thrd->req[0]))
-		return 1; /* First req active */
-
-	if (_req_active(thrd, &thrd->req[1]))
-		return 2; /* Second req active */
-
-	return 0;
-}
-
 static void _stop(struct pl330_thread *thrd)
 {
 	void __iomem *regs = thrd->dmac->pinfo->base;
@@ -897,11 +873,13 @@ static bool _trigger(struct pl330_thread *thrd)
 	if (_state(thrd) != PL330_STATE_STOPPED)
 		return true;

-	if (!IS_FREE(&thrd->req[1 - thrd->lstenq]))
+	if (!IS_FREE(&thrd->req[1 - thrd->lstenq])) {
 		req = &thrd->req[1 - thrd->lstenq];
-	else if (!IS_FREE(&thrd->req[thrd->lstenq]))
+		thrd->req_running = 2 - thrd->lstenq;
+	} else if (!IS_FREE(&thrd->req[thrd->lstenq])) {
 		req = &thrd->req[thrd->lstenq];
-	else
+		thrd->req_running = 1 + thrd->lstenq;
+	} else
 		req = NULL;

 	/* Return if no request */
@@ -1384,6 +1362,7 @@ static void pl330_dotask(unsigned long data)
 			thrd->req[1].r = NULL;
 			MARK_FREE(&thrd->req[0]);
 			MARK_FREE(&thrd->req[1]);
+			thrd->req_running = 0;

 			/* Clear the reset flag */
 			pl330->dmac_tbd.reset_chan &= ~(1 << i);
@@ -1461,7 +1440,7 @@ int pl330_update(const struct pl330_info *pi)

 			thrd = &pl330->channels[id];

-			active = _thrd_active(thrd);
+			active = thrd->req_running;
 			if (!active) /* Aborted */
 				continue;

@@ -1469,6 +1448,7 @@ int pl330_update(const struct pl330_info *pi)

 			rqdone = &thrd->req[active];
 			MARK_FREE(rqdone);
+			thrd->req_running = 0;

 			/* Get going again ASAP */
 			_start(thrd);
@@ -1527,10 +1507,11 @@ int pl330_chan_ctrl(void *ch_id, enum
pl330_chan_op op)
 		thrd->req[1].r = NULL;
 		MARK_FREE(&thrd->req[0]);
 		MARK_FREE(&thrd->req[1]);
+		thrd->req_running = 0;
 		break;

 	case PL330_OP_ABORT:
-		active = _thrd_active(thrd);
+		active = thrd->req_running;

 		/* Make sure the channel is stopped */
 		_stop(thrd);
@@ -1543,10 +1524,11 @@ int pl330_chan_ctrl(void *ch_id, enum
pl330_chan_op op)

 		thrd->req[active].r = NULL;
 		MARK_FREE(&thrd->req[active]);
+		thrd->req_running = 0;

 		/* Start the next */
 	case PL330_OP_START:
-		if (!_thrd_active(thrd) && !_start(thrd))
+		if (!thrd->req_running && !_start(thrd))
 			ret = -EIO;
 		break;

@@ -1587,7 +1569,7 @@ int pl330_chan_status(void *ch_id, struct
pl330_chanstatus *pstatus)
 	else
 		pstatus->faulting = false;

-	active = _thrd_active(thrd);
+	active = thrd->req_running;

 	if (!active) {
 		/* Indicate that the thread is not running */
@@ -1662,6 +1644,7 @@ void *pl330_request_channel(const struct
pl330_info *pi)
 				MARK_FREE(&thrd->req[0]);
 				thrd->req[1].r = NULL;
 				MARK_FREE(&thrd->req[1]);
+				thrd->req_running = 0;
 				break;
 			}
 		}
@@ -1775,6 +1758,8 @@ static inline void _reset_thread(struct
pl330_thread *thrd)
 				+ pi->mcbufsz / 2;
 	thrd->req[1].r = NULL;
 	MARK_FREE(&thrd->req[1]);
+
+	thrd->req_running = 0;
 }

 static int dmac_alloc_threads(struct pl330_dmac *pl330)



> [Sorry I don't have any pl330 platform handy]

It's all right, I can do the testing.  However, I'd like that somebody
with an exynos could test whatever patch we come up with in the end.  I
don't want to break that platform again O:-)

WARNING: multiple messages have this Message-ID (diff)
From: javi.merino@arm.com (Javi Merino)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2] ARM: pl330: Fix a race condition
Date: Fri, 09 Dec 2011 19:50:08 +0000	[thread overview]
Message-ID: <4EE26670.1060005@arm.com> (raw)
In-Reply-To: <CABb+yY2-1B65-UqRofj72zVuZUUk5c6pkqNGs15ZLnkrVheRDQ@mail.gmail.com>

On 09/12/11 16:50, Jassi Brar wrote:
> What do you think about ...
> 
> diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
> index f407a6b..3a51cdd 100644
> --- a/arch/arm/common/pl330.c
> +++ b/arch/arm/common/pl330.c
> @@ -1546,7 +1546,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
> 
>  		/* Start the next */
>  	case PL330_OP_START:
> -		if (!_thrd_active(thrd) && !_start(thrd))
> +		if (_state(thrd) == PL330_STATE_STOPPED && !_start(thrd))

Reintroduces the race condition, but you shorten the window:

  * pl330_submit_req()
  * pl330_chan_ctrl(PL330_OP_START)
  * pl330_submit_req()
  * pl330_chan_ctrl():spin_lock_irqsave()
  * Transfer 1 finishes, interrupt raised (but pl330_update() is not
    called as interrupts are disabled)
  * _state(thrd) is PL330_STATE_STOPPED , _start() reissues the first
    transaction.
  * pl330_chan_ctrl():spin_lock_irqrestore()
  * pl330_update() called for the first transaction, but it is running
    again!

What about properly tracking what we have sent to the DMA?  Something
like the following (warning *ugly* and untested code ahead, may eat your
kitten):

diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index f407a6b..3652c4b 100644
--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -303,6 +303,7 @@ struct pl330_thread {
 	struct _pl330_req req[2];
 	/* Index of the last submitted request */
 	unsigned lstenq;
+	int req_running;
 };

 enum pl330_dmac_state {
@@ -836,31 +837,6 @@ static inline u32 _state(struct pl330_thread *thrd)
 	}
 }

-/* If the request 'req' of thread 'thrd' is currently active */
-static inline bool _req_active(struct pl330_thread *thrd,
-		struct _pl330_req *req)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	u32 buf = req->mc_bus, pc = readl(regs + CPC(thrd->id));
-
-	if (IS_FREE(req))
-		return false;
-
-	return (pc >= buf && pc <= buf + req->mc_len) ? true : false;
-}
-
-/* Returns 0 if the thread is inactive, ID of active req + 1 otherwise */
-static inline unsigned _thrd_active(struct pl330_thread *thrd)
-{
-	if (_req_active(thrd, &thrd->req[0]))
-		return 1; /* First req active */
-
-	if (_req_active(thrd, &thrd->req[1]))
-		return 2; /* Second req active */
-
-	return 0;
-}
-
 static void _stop(struct pl330_thread *thrd)
 {
 	void __iomem *regs = thrd->dmac->pinfo->base;
@@ -897,11 +873,13 @@ static bool _trigger(struct pl330_thread *thrd)
 	if (_state(thrd) != PL330_STATE_STOPPED)
 		return true;

-	if (!IS_FREE(&thrd->req[1 - thrd->lstenq]))
+	if (!IS_FREE(&thrd->req[1 - thrd->lstenq])) {
 		req = &thrd->req[1 - thrd->lstenq];
-	else if (!IS_FREE(&thrd->req[thrd->lstenq]))
+		thrd->req_running = 2 - thrd->lstenq;
+	} else if (!IS_FREE(&thrd->req[thrd->lstenq])) {
 		req = &thrd->req[thrd->lstenq];
-	else
+		thrd->req_running = 1 + thrd->lstenq;
+	} else
 		req = NULL;

 	/* Return if no request */
@@ -1384,6 +1362,7 @@ static void pl330_dotask(unsigned long data)
 			thrd->req[1].r = NULL;
 			MARK_FREE(&thrd->req[0]);
 			MARK_FREE(&thrd->req[1]);
+			thrd->req_running = 0;

 			/* Clear the reset flag */
 			pl330->dmac_tbd.reset_chan &= ~(1 << i);
@@ -1461,7 +1440,7 @@ int pl330_update(const struct pl330_info *pi)

 			thrd = &pl330->channels[id];

-			active = _thrd_active(thrd);
+			active = thrd->req_running;
 			if (!active) /* Aborted */
 				continue;

@@ -1469,6 +1448,7 @@ int pl330_update(const struct pl330_info *pi)

 			rqdone = &thrd->req[active];
 			MARK_FREE(rqdone);
+			thrd->req_running = 0;

 			/* Get going again ASAP */
 			_start(thrd);
@@ -1527,10 +1507,11 @@ int pl330_chan_ctrl(void *ch_id, enum
pl330_chan_op op)
 		thrd->req[1].r = NULL;
 		MARK_FREE(&thrd->req[0]);
 		MARK_FREE(&thrd->req[1]);
+		thrd->req_running = 0;
 		break;

 	case PL330_OP_ABORT:
-		active = _thrd_active(thrd);
+		active = thrd->req_running;

 		/* Make sure the channel is stopped */
 		_stop(thrd);
@@ -1543,10 +1524,11 @@ int pl330_chan_ctrl(void *ch_id, enum
pl330_chan_op op)

 		thrd->req[active].r = NULL;
 		MARK_FREE(&thrd->req[active]);
+		thrd->req_running = 0;

 		/* Start the next */
 	case PL330_OP_START:
-		if (!_thrd_active(thrd) && !_start(thrd))
+		if (!thrd->req_running && !_start(thrd))
 			ret = -EIO;
 		break;

@@ -1587,7 +1569,7 @@ int pl330_chan_status(void *ch_id, struct
pl330_chanstatus *pstatus)
 	else
 		pstatus->faulting = false;

-	active = _thrd_active(thrd);
+	active = thrd->req_running;

 	if (!active) {
 		/* Indicate that the thread is not running */
@@ -1662,6 +1644,7 @@ void *pl330_request_channel(const struct
pl330_info *pi)
 				MARK_FREE(&thrd->req[0]);
 				thrd->req[1].r = NULL;
 				MARK_FREE(&thrd->req[1]);
+				thrd->req_running = 0;
 				break;
 			}
 		}
@@ -1775,6 +1758,8 @@ static inline void _reset_thread(struct
pl330_thread *thrd)
 				+ pi->mcbufsz / 2;
 	thrd->req[1].r = NULL;
 	MARK_FREE(&thrd->req[1]);
+
+	thrd->req_running = 0;
 }

 static int dmac_alloc_threads(struct pl330_dmac *pl330)



> [Sorry I don't have any pl330 platform handy]

It's all right, I can do the testing.  However, I'd like that somebody
with an exynos could test whatever patch we come up with in the end.  I
don't want to break that platform again O:-)

  reply	other threads:[~2011-12-09 19:50 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-19 17:11 [PATCH] ARM: pl330: Fix a race condition Javi Merino
2011-09-19 18:07 ` Jassi Brar
2011-09-20 13:36   ` Javi Merino
2011-10-05 12:57     ` Javi Merino
2011-10-06  9:10       ` [PATCH v2] " Javi Merino
2011-11-05 19:05         ` Thomas Abraham
2011-11-05 19:05           ` Thomas Abraham
2011-11-07 10:48           ` Javi Merino
2011-11-07 10:48             ` Javi Merino
2011-11-07 11:03             ` Thomas Abraham
2011-11-07 11:03               ` Thomas Abraham
2011-11-28  8:23             ` Boojin Kim
2011-11-28  8:23               ` Boojin Kim
2011-11-28 16:36               ` Javi Merino
2011-11-28 16:36                 ` Javi Merino
2011-11-29  3:41                 ` Boojin Kim
2011-11-29  3:41                   ` Boojin Kim
2011-11-29  9:53                   ` Javi Merino
2011-11-29  9:53                     ` Javi Merino
2011-11-29 10:37                     ` Jassi Brar
2011-11-29 10:37                       ` Jassi Brar
2011-12-07  7:52                       ` Kukjin Kim
2011-12-07  7:52                         ` Kukjin Kim
2011-12-07 10:01                         ` Javi Merino
2011-12-07 10:01                           ` Javi Merino
2011-12-07 20:54                           ` Javi Merino
2011-12-07 20:54                             ` Javi Merino
2011-12-09 11:58                             ` Javi Merino
2011-12-09 11:58                               ` Javi Merino
2011-12-09 13:04                               ` Jassi Brar
2011-12-09 13:04                                 ` Jassi Brar
2011-12-09 13:41                                 ` Javi Merino
2011-12-09 13:41                                   ` Javi Merino
2011-12-09 14:15                                   ` Jassi Brar
2011-12-09 14:15                                     ` Jassi Brar
2011-12-09 14:52                                     ` Javi Merino
2011-12-09 14:52                                       ` Javi Merino
2011-12-09 16:50                                       ` Jassi Brar
2011-12-09 16:50                                         ` Jassi Brar
2011-12-09 19:50                                         ` Javi Merino [this message]
2011-12-09 19:50                                           ` Javi Merino
2011-12-11 10:51                                           ` Jassi Brar
2011-12-11 10:51                                             ` Jassi Brar
2011-12-11 15:09                                             ` Javi Merino
2011-12-11 15:09                                               ` Javi Merino
2011-12-11 17:10                                               ` Jassi Brar
2011-12-11 17:10                                                 ` Jassi Brar
2011-12-11 17:42                                                 ` Javi Merino
2011-12-11 17:42                                                   ` Javi Merino
2011-12-11 19:27                                                   ` [PATCH] ARM: PL330: Fix driver freeze Javi Merino
2011-12-11 19:27                                                     ` Javi Merino
2011-12-15 17:48                                                     ` Javi Merino
2011-12-15 17:48                                                       ` Javi Merino
2011-12-16  9:01                                                       ` Tushar Behera
2011-12-16  9:01                                                         ` Tushar Behera
2011-12-16  6:27                                                     ` Jassi Brar
2011-12-16  6:27                                                       ` Jassi Brar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EE26670.1060005@arm.com \
    --to=javi.merino@arm.com \
    --cc=boojin.kim@samsung.com \
    --cc=jassisinghbrar@gmail.com \
    --cc=jaswinder.singh@linaro.org \
    --cc=kgene.kim@samsung.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=thomas.abraham@linaro.org \
    --cc=vinod.koul@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.