diff mbox

[3/3] DMA: PL330: Balance module remove function with probe

Message ID 1348563456-30569-4-git-send-email-inderpal.singh@linaro.org
State New
Headers show

Commit Message

Inderpal Singh Sept. 25, 2012, 8:57 a.m. UTC
Since peripheral channel resources are not being allocated at probe,
no need to flush the channels and free the resources in remove function.

Signed-off-by: Inderpal Singh <inderpal.singh@linaro.org>
---
 drivers/dma/pl330.c |    8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

Comments

Jassi Brar Sept. 25, 2012, 1:17 p.m. UTC | #1
On Tue, Sep 25, 2012 at 2:27 PM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:
> Since peripheral channel resources are not being allocated at probe,
> no need to flush the channels and free the resources in remove function.
>
> Signed-off-by: Inderpal Singh <inderpal.singh@linaro.org>
> ---
>  drivers/dma/pl330.c |    8 +-------
>  1 file changed, 1 insertion(+), 7 deletions(-)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 04d83e6..6f06080 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -3012,16 +3012,10 @@ static int __devexit pl330_remove(struct amba_device *adev)
>
>         /* Idle the DMAC */
>         list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
> -                       chan.device_node) {
> -
> +                       chan.device_node)
>                 /* Remove the channel */
>                 list_del(&pch->chan.device_node);
>
> -               /* Flush the channel */
> -               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
> -               pl330_free_chan_resources(&pch->chan);
> -       }
> -
>         while (!list_empty(&pdmac->desc_pool)) {
>                 desc = list_entry(pdmac->desc_pool.next,
>                                 struct dma_pl330_desc, node);

I am not sure about this patch. The DMA_TERMINATE_ALL is only called
by the client and if the pl330 module is forced unloaded while some
client is queued, we have to manually do DMA_TERMINATE_ALL.
A better option could be to simply fail pl330_remove if some client is
queued on the DMAC.

-jassi
Inderpal Singh Sept. 26, 2012, 6:41 a.m. UTC | #2
On 25 September 2012 18:47, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Tue, Sep 25, 2012 at 2:27 PM, Inderpal Singh
> <inderpal.singh@linaro.org> wrote:
>> Since peripheral channel resources are not being allocated at probe,
>> no need to flush the channels and free the resources in remove function.
>>
>> Signed-off-by: Inderpal Singh <inderpal.singh@linaro.org>
>> ---
>>  drivers/dma/pl330.c |    8 +-------
>>  1 file changed, 1 insertion(+), 7 deletions(-)
>>
>> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
>> index 04d83e6..6f06080 100644
>> --- a/drivers/dma/pl330.c
>> +++ b/drivers/dma/pl330.c
>> @@ -3012,16 +3012,10 @@ static int __devexit pl330_remove(struct amba_device *adev)
>>
>>         /* Idle the DMAC */
>>         list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
>> -                       chan.device_node) {
>> -
>> +                       chan.device_node)
>>                 /* Remove the channel */
>>                 list_del(&pch->chan.device_node);
>>
>> -               /* Flush the channel */
>> -               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>> -               pl330_free_chan_resources(&pch->chan);
>> -       }
>> -
>>         while (!list_empty(&pdmac->desc_pool)) {
>>                 desc = list_entry(pdmac->desc_pool.next,
>>                                 struct dma_pl330_desc, node);
>
> I am not sure about this patch. The DMA_TERMINATE_ALL is only called
> by the client and if the pl330 module is forced unloaded while some
> client is queued, we have to manually do DMA_TERMINATE_ALL.
> A better option could be to simply fail pl330_remove if some client is
> queued on the DMAC.
>
If we fail pl330_remove while some client is queued, the force unload
will fail and the
force unload will lose its purpose.
How about conditionally DMA_TERMINATE_ALL and free resources like below ?

@@ -3017,9 +3017,11 @@ static int __devexit pl330_remove(struct
amba_device *adev)
                /* Remove the channel */
                list_del(&pch->chan.device_node);

-               /* Flush the channel */
-               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
-               pl330_free_chan_resources(&pch->chan);
+               if (pch->chan.client_count != 0) {
+                       /* Flush the channel */
+                       pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
+                       pl330_free_chan_resources(&pch->chan);
+               }
        }

        while (!list_empty(&pdmac->desc_pool)) {


Thanks,
Inder


> -jassi
Jassi Brar Sept. 26, 2012, 9:32 a.m. UTC | #3
On Wed, Sep 26, 2012 at 12:11 PM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:

> How about conditionally DMA_TERMINATE_ALL and free resources like below ?
>
> @@ -3017,9 +3017,11 @@ static int __devexit pl330_remove(struct
> amba_device *adev)
>                 /* Remove the channel */
>                 list_del(&pch->chan.device_node);
>
> -               /* Flush the channel */
> -               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
> -               pl330_free_chan_resources(&pch->chan);
> +               if (pch->chan.client_count != 0) {
> +                       /* Flush the channel */
> +                       pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
> +                       pl330_free_chan_resources(&pch->chan);
> +               }
>         }
>
It is perfectly safe to flush the channels that have client_count == 0
as well. Which is already the case.
Inderpal Singh Sept. 26, 2012, 10:55 a.m. UTC | #4
On 26 September 2012 15:02, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Wed, Sep 26, 2012 at 12:11 PM, Inderpal Singh
> <inderpal.singh@linaro.org> wrote:
>
>> How about conditionally DMA_TERMINATE_ALL and free resources like below ?
>>
>> @@ -3017,9 +3017,11 @@ static int __devexit pl330_remove(struct
>> amba_device *adev)
>>                 /* Remove the channel */
>>                 list_del(&pch->chan.device_node);
>>
>> -               /* Flush the channel */
>> -               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>> -               pl330_free_chan_resources(&pch->chan);
>> +               if (pch->chan.client_count != 0) {
>> +                       /* Flush the channel */
>> +                       pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>> +                       pl330_free_chan_resources(&pch->chan);
>> +               }
>>         }
>>
> It is perfectly safe to flush the channels that have client_count == 0
> as well. Which is already the case.

As per my understanding, if client_count ==0, It may mean following:

1. This channel was never allocated to any client. Hence
alloc_chan_resources was not done for it.
So, no need to flush and free resources if it was never allocated at
the first place. If we free_chan_resources, it will not be balanced
against alloc_chan_resources. Scenario: insmod and then rmmod.

Or,

2. The channel was allocated to some client, alloc_chan_resource was
done, the work for the client is completed and free_chan_resources was
performed. Now  since resources have already been freed, no need to
flush and free_chan_resources again in remove.

The whole idea of this patch is to balance alloc_chan_resources and
free_chan_resources.

Thanks,
Inder
Jassi Brar Sept. 26, 2012, 4:49 p.m. UTC | #5
On Wed, Sep 26, 2012 at 4:25 PM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:
> On 26 September 2012 15:02, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>> On Wed, Sep 26, 2012 at 12:11 PM, Inderpal Singh
>> <inderpal.singh@linaro.org> wrote:
>>
>>> How about conditionally DMA_TERMINATE_ALL and free resources like below ?
>>>
>>> @@ -3017,9 +3017,11 @@ static int __devexit pl330_remove(struct
>>> amba_device *adev)
>>>                 /* Remove the channel */
>>>                 list_del(&pch->chan.device_node);
>>>
>>> -               /* Flush the channel */
>>> -               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>>> -               pl330_free_chan_resources(&pch->chan);
>>> +               if (pch->chan.client_count != 0) {
>>> +                       /* Flush the channel */
>>> +                       pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>>> +                       pl330_free_chan_resources(&pch->chan);
>>> +               }
>>>         }
>>>
>> It is perfectly safe to flush the channels that have client_count == 0
>> as well. Which is already the case.
>
> As per my understanding, if client_count ==0, It may mean following:
>
> 1. This channel was never allocated to any client. Hence
> alloc_chan_resources was not done for it.
> So, no need to flush and free resources if it was never allocated at
> the first place. If we free_chan_resources, it will not be balanced
> against alloc_chan_resources. Scenario: insmod and then rmmod.
>
> Or,
>
> 2. The channel was allocated to some client, alloc_chan_resource was
> done, the work for the client is completed and free_chan_resources was
> performed. Now  since resources have already been freed, no need to
> flush and free_chan_resources again in remove.
>
> The whole idea of this patch is to balance alloc_chan_resources and
> free_chan_resources.
>
Do you see any issue with channels that have zero client_count ?
AFAIU there are already enough checks in the path to weed out unused
channels, so let us please not uglify the code by adding new
unnecessary checks.

thanks.
Inderpal Singh Sept. 27, 2012, 4:13 a.m. UTC | #6
On 26 September 2012 22:19, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Wed, Sep 26, 2012 at 4:25 PM, Inderpal Singh
> <inderpal.singh@linaro.org> wrote:
>> On 26 September 2012 15:02, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>>> On Wed, Sep 26, 2012 at 12:11 PM, Inderpal Singh
>>> <inderpal.singh@linaro.org> wrote:
>>>
>>>> How about conditionally DMA_TERMINATE_ALL and free resources like below ?
>>>>
>>>> @@ -3017,9 +3017,11 @@ static int __devexit pl330_remove(struct
>>>> amba_device *adev)
>>>>                 /* Remove the channel */
>>>>                 list_del(&pch->chan.device_node);
>>>>
>>>> -               /* Flush the channel */
>>>> -               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>>>> -               pl330_free_chan_resources(&pch->chan);
>>>> +               if (pch->chan.client_count != 0) {
>>>> +                       /* Flush the channel */
>>>> +                       pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
>>>> +                       pl330_free_chan_resources(&pch->chan);
>>>> +               }
>>>>         }
>>>>
>>> It is perfectly safe to flush the channels that have client_count == 0
>>> as well. Which is already the case.
>>
>> As per my understanding, if client_count ==0, It may mean following:
>>
>> 1. This channel was never allocated to any client. Hence
>> alloc_chan_resources was not done for it.
>> So, no need to flush and free resources if it was never allocated at
>> the first place. If we free_chan_resources, it will not be balanced
>> against alloc_chan_resources. Scenario: insmod and then rmmod.
>>
>> Or,
>>
>> 2. The channel was allocated to some client, alloc_chan_resource was
>> done, the work for the client is completed and free_chan_resources was
>> performed. Now  since resources have already been freed, no need to
>> flush and free_chan_resources again in remove.
>>
>> The whole idea of this patch is to balance alloc_chan_resources and
>> free_chan_resources.
>>
> Do you see any issue with channels that have zero client_count ?

As I explained in my previous mail, If the client_count is zero,
either the alloc_chan_resources is not done(or failed) for that
channel or the free_chan_resource have already been done. Please refer
below code from dmaengine.c

static void dma_chan_put(struct dma_chan *chan)
{
        if (!chan->client_count)
                return; /* this channel failed alloc_chan_resources */
        chan->client_count--;
        module_put(dma_chan_to_owner(chan));
        if (chan->client_count == 0)
                chan->device->device_free_chan_resources(chan);
}

As you mentioned channel flush is needed if some client is queued and
force unload happens.
I am not against flushing and freeing channels. I am __only__
suggesting to flush and free channels for which alloc_chan_resource
was successful, which can be decided by "chan->client_count" as being
done in above function.

Don't you think free_chan_resource should be done __only if__
alloc_chan_resource was successful ?

Thanks,
Inder

> AFAIU there are already enough checks in the path to weed out unused
> channels, so let us please not uglify the code by adding new
> unnecessary checks.
>
> thanks.
Jassi Brar Sept. 27, 2012, 5:05 a.m. UTC | #7
On Thu, Sep 27, 2012 at 9:43 AM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:
>
> Don't you think free_chan_resource should be done __only if__
> alloc_chan_resource was successful ?
>
No, I don't think so. Thanks.
Inderpal Singh Sept. 27, 2012, 5:30 a.m. UTC | #8
On 27 September 2012 10:35, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Thu, Sep 27, 2012 at 9:43 AM, Inderpal Singh
> <inderpal.singh@linaro.org> wrote:
>>
>> Don't you think free_chan_resource should be done __only if__
>> alloc_chan_resource was successful ?
>>
> No, I don't think so. Thanks.

Thanks for quick response.
Please elaborate more on this as I find it against the general rule
and against the dmaengine implementation which checks on the same
condition before proceeding for free_chan_resouces in dma_chan_put
function.

Thanks,
Inder
Jassi Brar Sept. 27, 2012, 6:03 a.m. UTC | #9
On Thu, Sep 27, 2012 at 11:00 AM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:
> On 27 September 2012 10:35, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>> On Thu, Sep 27, 2012 at 9:43 AM, Inderpal Singh
>> <inderpal.singh@linaro.org> wrote:
>>>
>>> Don't you think free_chan_resource should be done __only if__
>>> alloc_chan_resource was successful ?
>>>
>> No, I don't think so. Thanks.
>
> Thanks for quick response.
> Please elaborate more on this as I find it against the general rule
> and against the dmaengine implementation which checks on the same
> condition before proceeding for free_chan_resouces in dma_chan_put
> function.
>
I thought I already explained it, but here is the summary.
Calling pl330_free_chan_resources() for channels that have zero client
is already safe. Preventing the call by checking !client_count only
increases LOC making it uglier.

** If the new check provides any more security, please let me know. **

Food for thought : we never check for NULL before passing a pointer to
kfree(). Why ?
Vinod Koul Sept. 27, 2012, 9:48 a.m. UTC | #10
On Wed, 2012-09-26 at 12:11 +0530, Inderpal Singh wrote:
> If we fail pl330_remove while some client is queued, the force unload
> will fail and the
> force unload will lose its purpose.
> How about conditionally DMA_TERMINATE_ALL and free resources like
> below ? 
Why would you want to remove the driver when it is doing something
useful? You have to ensure driver is not doing anything.

What is point here?
Inderpal Singh Sept. 27, 2012, 3:41 p.m. UTC | #11
On 27 September 2012 15:18, Vinod Koul <vinod.koul@linux.intel.com> wrote:
> On Wed, 2012-09-26 at 12:11 +0530, Inderpal Singh wrote:
>> If we fail pl330_remove while some client is queued, the force unload
>> will fail and the
>> force unload will lose its purpose.
>> How about conditionally DMA_TERMINATE_ALL and free resources like
>> below ?
> Why would you want to remove the driver when it is doing something
> useful? You have to ensure driver is not doing anything.
>
> What is point here?
>
As mentioned by jassi,  if the pl330 module is forced unloaded while
some client is queued, we have to manually do DMA_TERMINATE_ALL.

If failing remove is a better option in case some client is queued, we
can do away with DMA_TERMINATE_ALL and free_chan_resources and simply
return a suitable error code from remove.

Kindly suggest.

Thanks,
Inder

> --
> ~Vinod
>
Jassi Brar Sept. 27, 2012, 4:06 p.m. UTC | #12
On Thu, Sep 27, 2012 at 9:11 PM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:
> On 27 September 2012 15:18, Vinod Koul <vinod.koul@linux.intel.com> wrote:
>> On Wed, 2012-09-26 at 12:11 +0530, Inderpal Singh wrote:
>>> If we fail pl330_remove while some client is queued, the force unload
>>> will fail and the
>>> force unload will lose its purpose.
>>> How about conditionally DMA_TERMINATE_ALL and free resources like
>>> below ?
>> Why would you want to remove the driver when it is doing something
>> useful? You have to ensure driver is not doing anything.
>>
>> What is point here?
>>
> As mentioned by jassi,  if the pl330 module is forced unloaded while
> some client is queued, we have to manually do DMA_TERMINATE_ALL.
>
I meant that in the current situation. Not ideally.

> If failing remove is a better option in case some client is queued, we
> can do away with DMA_TERMINATE_ALL and free_chan_resources and simply
> return a suitable error code from remove.
>
That was exactly what I suggested as an alternative.
Inderpal Singh Sept. 28, 2012, 4:33 a.m. UTC | #13
On 27 September 2012 21:36, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Thu, Sep 27, 2012 at 9:11 PM, Inderpal Singh
> <inderpal.singh@linaro.org> wrote:
>> On 27 September 2012 15:18, Vinod Koul <vinod.koul@linux.intel.com> wrote:
>>> On Wed, 2012-09-26 at 12:11 +0530, Inderpal Singh wrote:
>>>> If we fail pl330_remove while some client is queued, the force unload
>>>> will fail and the
>>>> force unload will lose its purpose.
>>>> How about conditionally DMA_TERMINATE_ALL and free resources like
>>>> below ?
>>> Why would you want to remove the driver when it is doing something
>>> useful? You have to ensure driver is not doing anything.
>>>
>>> What is point here?
>>>
>> As mentioned by jassi,  if the pl330 module is forced unloaded while
>> some client is queued, we have to manually do DMA_TERMINATE_ALL.
>>
> I meant that in the current situation. Not ideally.
>
>> If failing remove is a better option in case some client is queued, we
>> can do away with DMA_TERMINATE_ALL and free_chan_resources and simply
>> return a suitable error code from remove.
>>
> That was exactly what I suggested as an alternative.

Yes, but our discussion went about continue doing DMA_TERMINATE_ALL and freeing.

Now, if we have to check if any client is using the channel and then
decide. We will have to traverse the channel list twice once to check
the usage and second time to delete the nodes from the list if we go
ahead with remove.
The remove will look like below:

@@ -3008,18 +3008,19 @@ static int __devexit pl330_remove(struct
amba_device *adev)
        if (!pdmac)
                return 0;

+       /* check if any client is using any channel */
+       list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
+                       chan.device_node) {
+
+               if (pch->chan.client_count)
+                       return -EBUSY;
+       }
+
        amba_set_drvdata(adev, NULL);

-       /* Idle the DMAC */
        list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
                        chan.device_node) {

                /* Remove the channel */
                list_del(&pch->chan.device_node);
-
-               /* Flush the channel */
-               pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
-               pl330_free_chan_resources(&pch->chan);
        }

Please suggest if there is any better way to do it.

Thanks,
Inder
Jassi Brar Sept. 28, 2012, 10:58 a.m. UTC | #14
On Fri, Sep 28, 2012 at 10:03 AM, Inderpal Singh
<inderpal.singh@linaro.org> wrote:
>
> Now, if we have to check if any client is using the channel and then
> decide. We will have to traverse the channel list twice once to check
> the usage and second time to delete the nodes from the list if we go
> ahead with remove.
> The remove will look like below:
>
> @@ -3008,18 +3008,19 @@ static int __devexit pl330_remove(struct
> amba_device *adev)
>         if (!pdmac)
>                 return 0;
>
> +       /* check if any client is using any channel */
> +       list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
> +                       chan.device_node) {
> +
> +               if (pch->chan.client_count)
> +                       return -EBUSY;
> +       }
> +
The iteration doesn't have to be the 'safe' version here. Other than
that it seems OK.
Inderpal Singh Oct. 1, 2012, 9:59 a.m. UTC | #15
On 28 September 2012 16:28, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Fri, Sep 28, 2012 at 10:03 AM, Inderpal Singh
> <inderpal.singh@linaro.org> wrote:
>>
>> Now, if we have to check if any client is using the channel and then
>> decide. We will have to traverse the channel list twice once to check
>> the usage and second time to delete the nodes from the list if we go
>> ahead with remove.
>> The remove will look like below:
>>
>> @@ -3008,18 +3008,19 @@ static int __devexit pl330_remove(struct
>> amba_device *adev)
>>         if (!pdmac)
>>                 return 0;
>>
>> +       /* check if any client is using any channel */
>> +       list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
>> +                       chan.device_node) {
>> +
>> +               if (pch->chan.client_count)
>> +                       return -EBUSY;
>> +       }
>> +
> The iteration doesn't have to be the 'safe' version here. Other than
> that it seems OK.

Ok. I will update the patch and send again.

Thanks,
Inder
diff mbox

Patch

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 04d83e6..6f06080 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -3012,16 +3012,10 @@  static int __devexit pl330_remove(struct amba_device *adev)
 
 	/* Idle the DMAC */
 	list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
-			chan.device_node) {
-
+			chan.device_node)
 		/* Remove the channel */
 		list_del(&pch->chan.device_node);
 
-		/* Flush the channel */
-		pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
-		pl330_free_chan_resources(&pch->chan);
-	}
-
 	while (!list_empty(&pdmac->desc_pool)) {
 		desc = list_entry(pdmac->desc_pool.next,
 				struct dma_pl330_desc, node);