Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-11 Thread Jassi Brar
On Sat, Dec 10, 2011 at 1:20 AM, Javi Merino javi.mer...@arm.com wrote:

 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;
 

Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-11 Thread Javi Merino
On 11/12/11 10:51, Jassi Brar wrote:
 On Sat, Dec 10, 2011 at 1:20 AM, Javi Merino javi.mer...@arm.com wrote:

 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):

 Yeah, this is like I said 'marker' method. Though we can clean it up a bit.
 1) Pack req_running and lstenq together. Make lsteng return invalid value
 should there be no buff programmed, otherwise 0 or 1.

This can lead to starvation.  If lstenq is -1 when the DMA hasn't been
programmed yet, in _trigger() you don't know which buffer is the
oldest, so you may end up always starting the new buffer and
forgetting about the other one.  lstenq as it is right now prevents that.

 2) Try to merge req_running modification as part of MARK_FREE.

Yes, I thought about that, but I didn't want to code a proper solution
and then receive a no, we shouldn't go down this road.

I'll clean it up and send a proper patch.

Cheers,
Javi

-- IMPORTANT NOTICE: The contents of this email and any attachments are 
confidential and may also be privileged. If you are not the intended recipient, 
please notify the sender immediately and do not disclose the contents to any 
other person, use it for any purpose, or store or copy the information in any 
medium.  Thank you.

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-11 Thread Jassi Brar
On 11 December 2011 20:39, Javi Merino javi.mer...@arm.com wrote:

 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):

 Yeah, this is like I said 'marker' method. Though we can clean it up a bit.
 1) Pack req_running and lstenq together. Make lsteng return invalid value
 should there be no buff programmed, otherwise 0 or 1.

 This can lead to starvation.  If lstenq is -1 when the DMA hasn't been
 programmed yet, in _trigger() you don't know which buffer is the
 oldest, so you may end up always starting the new buffer and
 forgetting about the other one.  lstenq as it is right now prevents that.

Sorry I don't understand. If lstenq is -1 that means there's no req programmed
so trigger need not do anything. I didn't say we don't need to do anything else.
Though it's just an idea I haven't implemented and it may not work out.
Just please give it a try if you can. Thanks.
--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-11 Thread Javi Merino
On 11/12/11 17:10, Jassi Brar wrote:
 On 11 December 2011 20:39, Javi Merino javi.mer...@arm.com wrote:

 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):

 Yeah, this is like I said 'marker' method. Though we can clean it up a bit.
 1) Pack req_running and lstenq together. Make lsteng return invalid value
 should there be no buff programmed, otherwise 0 or 1.

 This can lead to starvation.  If lstenq is -1 when the DMA hasn't been
 programmed yet, in _trigger() you don't know which buffer is the
 oldest, so you may end up always starting the new buffer and
 forgetting about the other one.  lstenq as it is right now prevents that.

 Sorry I don't understand. If lstenq is -1 that means there's no req programmed
 so trigger need not do anything. I didn't say we don't need to do anything 
 else.

Currently lstenq tracks the last request that pl330_submit_req() has
enqueued.  I think we should add a req_running (or any other name) that
tracks what _trigger() has sent to the DMA.  If we pack them together we
lose some information and I don't see a way of packing them safely.

 Though it's just an idea I haven't implemented and it may not work out.

I was trying to implement it and got stuck in _trigger() thinking ok,
so which buffer am I supposed to trigger now...

 Just please give it a try if you can. Thanks.

I have a patch that seems to be working.  Let me test it a little bit
more and I'll send it to the list.

Cheers,
Javi

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-09 Thread Javi Merino
On 07/12/11 20:54, Javi Merino wrote:
 On 07/12/11 10:01, Javi Merino wrote:
 On 07/12/11 07:52, Kukjin Kim wrote:
 Jassi Brar wrote:
 On 29 November 2011 15:23, Javi Merino javi.mer...@arm.com wrote:
 On Samsung's Exynos4 platform, while testing audio playback with
 i2s
 interface, the above change causes the playback to freeze. The
 _thrd_active(thrd) call always returns '1' and hence _start(thrd)
 is
 not getting called.

 Your patch makes the memcpy operation on dmatest.c and net DMA be
 frozen too
 as well as Samsung audio playback.

 Javi, could you please check if you too get the memcpy failure with
 dmatest ?

 Ok, I think I've just reproduced it in my end with the kernel's dmatest
 module.  After the first transaction it looks like the dma test wasn't
 able to issue any more transactions.  I'll have a look at it tomorrow
 and try to answer my own questions ;)

The problem is that pl330_submit_req() always puts the request in buffer 0 if
both buffers are free.

If you submit a transaction, it finishes and there's nothing else to run,
pl330_update() calls _start() but there is nothing to send.  This is all
right.  Then, if another transaction is submitted, pl330_submit_req() will
put it in buffer 0 again.  This time, the PC of the DMA is in the last
instruction of buffer 0 (the DMAEND of the *previous* transaction that
finished long ago) so _thrd_active() thinks that this buffer is active,
which makes pl330_chan_ctrl() not start the transaction and hence, the DMA
freezes.

I believe something like the following should fix it:

--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -1301,7 +1301,7 @@ int pl330_submit_req(void *ch_id, struct pl330_req *r)
goto xfer_exit;
}
 
-   idx = IS_FREE(thrd-req[0]) ? 0 : 1;
+   idx = IS_FREE(thrd-req[1 - thrd-lstenq]) ? 1 - thrd-lstenq : 
thrd-lstenq;
 
xs.ccr = ccr;
xs.r = r;


I have only tested this with a single-channel single-thread dma test.
I'll send a proper patch to the list once I've done more testing.

Cheers,
Javi

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-09 Thread Jassi Brar
Hi Javi,

On 9 December 2011 17:28, Javi Merino javi.mer...@arm.com wrote:

 Javi, could you please check if you too get the memcpy failure with
 dmatest ?

 Ok, I think I've just reproduced it in my end with the kernel's dmatest
 module.  After the first transaction it looks like the dma test wasn't
 able to issue any more transactions.  I'll have a look at it tomorrow
 and try to answer my own questions ;)

 The problem is that pl330_submit_req() always puts the request in buffer 0 if
 both buffers are free.

There should be nothing wrong in that.
It is but natural to prefer 0 if both 0 and 1 are available.

 If you submit a transaction, it finishes and there's nothing else to run,
 pl330_update() calls _start() but there is nothing to send.  This is all
 right.  Then, if another transaction is submitted, pl330_submit_req() will
 put it in buffer 0 again.  This time, the PC of the DMA is in the last
 instruction of buffer 0 (the DMAEND of the *previous* transaction that
 finished long ago) so _thrd_active() thinks that this buffer is active,

Many thanks for the in-depth analysis.

Though before the PC check, the IS_FREE() should return true since
pl330_update() does MARK_FREE()

Could you please check if the client's callback function called
successfully for the
first submitted transfer ?

Then we can decide upon one of the following 2 options (I *think*
either should fix the issue)

diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index 97912fa..f550d46 100644
--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -846,7 +846,7 @@ static inline bool _req_active(struct pl330_thread *thrd,
if (IS_FREE(req))
return false;

-   return (pc = buf  pc = buf + req-mc_len) ? true : false;
+   return (pc = buf  pc  buf + req-mc_len) ? true : false;
 }

--OR--

diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index 97912fa..ad85a75 100644
--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -233,7 +233,7 @@
} while (0)

 /* If the _pl330_req is available to the client */
-#define IS_FREE(req)   (*((u8 *)((req)-mc_cpu)) == CMD_DMAEND)
+#define IS_FREE(req)   ((req)-mc_len == 0)

 /* Use this _only_ to wait on transient states */
 #define UNTIL(t, s)while (!(_state(t)  (s))) cpu_relax();


Thanks.
--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-09 Thread Jassi Brar
On Fri, Dec 9, 2011 at 8:22 PM, Javi Merino javi.mer...@arm.com wrote:

 I think the best solution would be to revert
 ee3f615819404a9438b2dd01b7a39f276d2737f2 and go back to my original
 patch (in the beginning of this thread):

 http://article.gmane.org/gmane.linux.ports.arm.kernel/133110

 What do you think?

Well, we have to resort to that if we can't find something simpler.

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))
ret = -EIO;
break;

Thanks
-jassi

[Sorry I don't have any pl330 platform handy]
--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-12-09 Thread Javi Merino
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;

Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-29 Thread Javi Merino
On 29/11/11 03:41, Boojin Kim wrote:
 Javi Merino wrote:
 
 

 On Samsung's Exynos4 platform, while testing audio playback with
 i2s
 interface, the above change causes the playback to freeze. The
 _thrd_active(thrd) call always returns '1' and hence _start(thrd)
 is
 not getting called.

 If _thrd_active(thrd) returns '1', that means there is an active
 transfer still running or, if it has finished, you haven't called
 pl330_update() to acknowledge that.  pl330_update() calls _start()
 as
 soon as it can.

 drivers/dma/pl330.c registers the irq handler in pl330_probe(), so
 when
 the transaction finishes, pl330_update() should clear it and call
 _start().  If there is any outstanding transaction, it should start
 straight away. If there isn't, it would mark the channel as free,
 so
 _thrd_active() should return '0'.  If _thrd_active() is still '1',
 then
 something has gone wrong in the way.

 Does this shed some light?


 Your patch makes the memcpy operation on dmatest.c and net DMA be
 frozen too
 as well as Samsung audio playback.

 Is the IRQ correctly registered in drivers/dma/pl330.c:pl330_probe()?
 Do you get interrupts when the transfer finish?
 Sure. IRQ works well.

Ok, so can you check if pl330_update() is correctly marking the request
as free?  Do you know if there is another request in the queue when that
happens?

Thomas, you said in a previous email that _thrd_active() always returned
'1'.  Was that after a request in req[0] finished?
  - If so, can you check that MARK_FREE was actually called for that
request in pl330_update()?
  - If it was after a request in req[1] finished and there was a
request already waiting in req[0], can you debug why _start()
didn't activate it.

Cheers,
Javi

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-29 Thread Jassi Brar
On 29 November 2011 15:23, Javi Merino javi.mer...@arm.com wrote:
 On Samsung's Exynos4 platform, while testing audio playback with
 i2s
 interface, the above change causes the playback to freeze. The
 _thrd_active(thrd) call always returns '1' and hence _start(thrd)
 is
 not getting called.

 If _thrd_active(thrd) returns '1', that means there is an active
 transfer still running or, if it has finished, you haven't called
 pl330_update() to acknowledge that.  pl330_update() calls _start()
 as
 soon as it can.

 drivers/dma/pl330.c registers the irq handler in pl330_probe(), so
 when
 the transaction finishes, pl330_update() should clear it and call
 _start().  If there is any outstanding transaction, it should start
 straight away. If there isn't, it would mark the channel as free,
 so
 _thrd_active() should return '0'.  If _thrd_active() is still '1',
 then
 something has gone wrong in the way.

 Does this shed some light?


 Your patch makes the memcpy operation on dmatest.c and net DMA be
 frozen too
 as well as Samsung audio playback.

 Is the IRQ correctly registered in drivers/dma/pl330.c:pl330_probe()?
 Do you get interrupts when the transfer finish?
 Sure. IRQ works well.

 Ok, so can you check if pl330_update() is correctly marking the request
 as free?  Do you know if there is another request in the queue when that
 happens?

 Thomas, you said in a previous email that _thrd_active() always returned
 '1'.  Was that after a request in req[0] finished?
  - If so, can you check that MARK_FREE was actually called for that
    request in pl330_update()?
  - If it was after a request in req[1] finished and there was a
    request already waiting in req[0], can you debug why _start()
    didn't activate it.

Javi, could you please check if you too get the memcpy failure with dmatest ?
Thanks.
--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-28 Thread Boojin Kim
Javi Merino wrote:

  On Samsung's Exynos4 platform, while testing audio playback with i2s
  interface, the above change causes the playback to freeze. The
  _thrd_active(thrd) call always returns '1' and hence _start(thrd) is
  not getting called.

 If _thrd_active(thrd) returns '1', that means there is an active
 transfer still running or, if it has finished, you haven't called
 pl330_update() to acknowledge that.  pl330_update() calls _start() as
 soon as it can.

 drivers/dma/pl330.c registers the irq handler in pl330_probe(), so
 when
 the transaction finishes, pl330_update() should clear it and call
 _start().  If there is any outstanding transaction, it should start
 straight away. If there isn't, it would mark the channel as free, so
 _thrd_active() should return '0'.  If _thrd_active() is still '1', then
 something has gone wrong in the way.

 Does this shed some light?


Your patch makes the memcpy operation on dmatest.c and net DMA be frozen too
as well as Samsung audio playback.
With our patch, common DMA memcpy sequence may be changed.
I think..
it's needed to find the other way not to bring these side effects.

 Cheers,
 Javi

 --
 To unsubscribe from this list: send the line unsubscribe linux-
 samsung-soc in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-28 Thread Javi Merino
On 28/11/11 08:23, Boojin Kim wrote:
 Javi Merino wrote:
 
 On Samsung's Exynos4 platform, while testing audio playback with i2s
 interface, the above change causes the playback to freeze. The
 _thrd_active(thrd) call always returns '1' and hence _start(thrd) is
 not getting called.

 If _thrd_active(thrd) returns '1', that means there is an active
 transfer still running or, if it has finished, you haven't called
 pl330_update() to acknowledge that.  pl330_update() calls _start() as
 soon as it can.

 drivers/dma/pl330.c registers the irq handler in pl330_probe(), so
 when
 the transaction finishes, pl330_update() should clear it and call
 _start().  If there is any outstanding transaction, it should start
 straight away. If there isn't, it would mark the channel as free, so
 _thrd_active() should return '0'.  If _thrd_active() is still '1', then
 something has gone wrong in the way.

 Does this shed some light?

 
 Your patch makes the memcpy operation on dmatest.c and net DMA be frozen too
 as well as Samsung audio playback.

Is the IRQ correctly registered in drivers/dma/pl330.c:pl330_probe()?
Do you get interrupts when the transfer finish?

The only way I can think of that
ee3f615819404a9438b2dd01b7a39f276d2737f2 can break break something is
that you aren't calling pl330_update() at all.

 With our patch, common DMA memcpy sequence may be changed.

Which one is our patch?  I'm sorry, I'm not subscribed to any of the
lists so I may have missed something.

Cheers,
Javi

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-28 Thread Boojin Kim
Javi Merino wrote:


 
  On Samsung's Exynos4 platform, while testing audio playback with
 i2s
  interface, the above change causes the playback to freeze. The
  _thrd_active(thrd) call always returns '1' and hence _start(thrd)
 is
  not getting called.
 
  If _thrd_active(thrd) returns '1', that means there is an active
  transfer still running or, if it has finished, you haven't called
  pl330_update() to acknowledge that.  pl330_update() calls _start()
 as
  soon as it can.
 
  drivers/dma/pl330.c registers the irq handler in pl330_probe(), so
  when
  the transaction finishes, pl330_update() should clear it and call
  _start().  If there is any outstanding transaction, it should start
  straight away. If there isn't, it would mark the channel as free,
 so
  _thrd_active() should return '0'.  If _thrd_active() is still '1',
 then
  something has gone wrong in the way.
 
  Does this shed some light?
 
 
  Your patch makes the memcpy operation on dmatest.c and net DMA be
 frozen too
  as well as Samsung audio playback.

 Is the IRQ correctly registered in drivers/dma/pl330.c:pl330_probe()?
 Do you get interrupts when the transfer finish?
Sure. IRQ works well.


 The only way I can think of that
 ee3f615819404a9438b2dd01b7a39f276d2737f2 can break break something is
 that you aren't calling pl330_update() at all.

  With our patch, common DMA memcpy sequence may be changed.

 Which one is our patch?  I'm sorry, I'm not subscribed to any of the
 lists so I may have missed something.

Sorry to make you confused.
I mean.. With your patch, common DMA memcpy sequence may be changed.
Your patch brings the side effect that freezes dma transmits.


 Cheers,
 Javi


 ___
 linux-arm-kernel mailing list
 linux-arm-ker...@lists.infradead.org
 http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-07 Thread Javi Merino
On 05/11/11 19:05, Thomas Abraham wrote:
 Hi Javi,
 
 On 6 October 2011 05:10, Javi Merino javi.mer...@arm.com wrote:
 If two requests have been submitted and one of them is running, if you
 call pl330_chan_ctrl(ch_id, PL330_OP_START), there's a window of time
 between the spin_lock_irqsave() and the _state() check in which the
 running transaction may finish.  In that case, we don't receive the
 interrupt (because they are disabled), but _start() sees that the DMA
 is stopped, so it starts it.  The problem is that it sends the
 transaction that has just finished again, because pl330_update()
 hasn't mark it as done yet.

 This patch fixes this race condition by not calling _start() if the
 DMA is already executing transactions.  When interrupts are reenabled,
 pl330_update() will call _start().

 Signed-off-by: Javi Merino javi.mer...@arm.com
 Acked-by: Jassi Brar jassi.b...@samsung.com
 ---
  arch/arm/common/pl330.c |2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)

 diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
 index 97912fa..7129cfb 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 (!_start(thrd))
 +   if (!_thrd_active(thrd)  !_start(thrd))
ret = -EIO;
break;
 
 On Samsung's Exynos4 platform, while testing audio playback with i2s
 interface, the above change causes the playback to freeze. The
 _thrd_active(thrd) call always returns '1' and hence _start(thrd) is
 not getting called.

If _thrd_active(thrd) returns '1', that means there is an active
transfer still running or, if it has finished, you haven't called
pl330_update() to acknowledge that.  pl330_update() calls _start() as
soon as it can.

drivers/dma/pl330.c registers the irq handler in pl330_probe(), so when
the transaction finishes, pl330_update() should clear it and call
_start().  If there is any outstanding transaction, it should start
straight away. If there isn't, it would mark the channel as free, so
_thrd_active() should return '0'.  If _thrd_active() is still '1', then
something has gone wrong in the way.

Does this shed some light?

Cheers,
Javi

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-07 Thread Thomas Abraham
On 7 November 2011 16:18, Javi Merino javi.mer...@arm.com wrote:
 On 05/11/11 19:05, Thomas Abraham wrote:
 Hi Javi,

 On 6 October 2011 05:10, Javi Merino javi.mer...@arm.com wrote:
 If two requests have been submitted and one of them is running, if you
 call pl330_chan_ctrl(ch_id, PL330_OP_START), there's a window of time
 between the spin_lock_irqsave() and the _state() check in which the
 running transaction may finish.  In that case, we don't receive the
 interrupt (because they are disabled), but _start() sees that the DMA
 is stopped, so it starts it.  The problem is that it sends the
 transaction that has just finished again, because pl330_update()
 hasn't mark it as done yet.

 This patch fixes this race condition by not calling _start() if the
 DMA is already executing transactions.  When interrupts are reenabled,
 pl330_update() will call _start().

 Signed-off-by: Javi Merino javi.mer...@arm.com
 Acked-by: Jassi Brar jassi.b...@samsung.com
 ---
  arch/arm/common/pl330.c |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)

 diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
 index 97912fa..7129cfb 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 (!_start(thrd))
 +               if (!_thrd_active(thrd)  !_start(thrd))
                        ret = -EIO;
                break;

 On Samsung's Exynos4 platform, while testing audio playback with i2s
 interface, the above change causes the playback to freeze. The
 _thrd_active(thrd) call always returns '1' and hence _start(thrd) is
 not getting called.

 If _thrd_active(thrd) returns '1', that means there is an active
 transfer still running or, if it has finished, you haven't called
 pl330_update() to acknowledge that.  pl330_update() calls _start() as
 soon as it can.

 drivers/dma/pl330.c registers the irq handler in pl330_probe(), so when
 the transaction finishes, pl330_update() should clear it and call
 _start().  If there is any outstanding transaction, it should start
 straight away. If there isn't, it would mark the channel as free, so
 _thrd_active() should return '0'.  If _thrd_active() is still '1', then
 something has gone wrong in the way.

 Does this shed some light?

Thanks for the detailed explanation. I will check again on the lines
you have mentioned above. Also, the i2s audio playback on exynos had
been working prior to this change. So that might imply that
pl330_update was working as you have mentioned. Anyway, I will check
again.

Thanks,
Thomas.


 Cheers,
 Javi


--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] ARM: pl330: Fix a race condition

2011-11-05 Thread Thomas Abraham
Hi Javi,

On 6 October 2011 05:10, Javi Merino javi.mer...@arm.com wrote:
 If two requests have been submitted and one of them is running, if you
 call pl330_chan_ctrl(ch_id, PL330_OP_START), there's a window of time
 between the spin_lock_irqsave() and the _state() check in which the
 running transaction may finish.  In that case, we don't receive the
 interrupt (because they are disabled), but _start() sees that the DMA
 is stopped, so it starts it.  The problem is that it sends the
 transaction that has just finished again, because pl330_update()
 hasn't mark it as done yet.

 This patch fixes this race condition by not calling _start() if the
 DMA is already executing transactions.  When interrupts are reenabled,
 pl330_update() will call _start().

 Signed-off-by: Javi Merino javi.mer...@arm.com
 Acked-by: Jassi Brar jassi.b...@samsung.com
 ---
  arch/arm/common/pl330.c |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)

 diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
 index 97912fa..7129cfb 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 (!_start(thrd))
 +               if (!_thrd_active(thrd)  !_start(thrd))
                        ret = -EIO;
                break;

On Samsung's Exynos4 platform, while testing audio playback with i2s
interface, the above change causes the playback to freeze. The
_thrd_active(thrd) call always returns '1' and hence _start(thrd) is
not getting called.

I have not debugged this much but if there is something that I am
missing, please let me know. Meanwhile, I will continue checking on
this.

Thanks,
Thomas.



 --
 1.7.0.4



 ___
 linux-arm-kernel mailing list
 linux-arm-ker...@lists.infradead.org
 http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html