diff mbox

[v9,1/5] driver core: Find an existing link between two devices

Message ID 20180313085534.11650-2-vivek.gautam@codeaurora.org (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Vivek Gautam March 13, 2018, 8:55 a.m. UTC
The lists managing the device-links can be traversed to
find the link between two devices. The device_link_add() APIs
does traverse these lists to check if there's already a link
setup between the two devices.
So, add a new APIs, device_link_find(), to find an existing
device link between two devices - suppliers and consumers.

Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---

 * New patch added to this series.

 drivers/base/core.c    | 30 +++++++++++++++++++++++++++---
 include/linux/device.h |  2 ++
 2 files changed, 29 insertions(+), 3 deletions(-)

Comments

Rafael J. Wysocki March 13, 2018, 9:40 a.m. UTC | #1
On Tuesday, March 13, 2018 9:55:30 AM CET Vivek Gautam wrote:
> The lists managing the device-links can be traversed to
> find the link between two devices. The device_link_add() APIs
> does traverse these lists to check if there's already a link
> setup between the two devices.
> So, add a new APIs, device_link_find(), to find an existing
> device link between two devices - suppliers and consumers.
> 
> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> ---
> 
>  * New patch added to this series.
> 
>  drivers/base/core.c    | 30 +++++++++++++++++++++++++++---
>  include/linux/device.h |  2 ++
>  2 files changed, 29 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index 5847364f25d9..e8c9774e4ba2 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -144,6 +144,30 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
>  	return 0;
>  }
>  
> +/**
> + * device_link_find - find any existing link between two devices.
> + * @consumer: Consumer end of the link.
> + * @supplier: Supplier end of the link.
> + *
> + * Returns pointer to the existing link between a supplier and
> + * and consumer devices, or NULL if no link exists.
> + */
> +struct device_link *device_link_find(struct device *consumer,
> +				     struct device *supplier)
> +{
> +	struct device_link *link = NULL;
> +
> +	if (!consumer || !supplier)
> +		return NULL;
> +
> +	list_for_each_entry(link, &supplier->links.consumers, s_node)
> +		if (link->consumer == consumer)
> +			break;
> +

Any mutual exclusion?

Or is the caller expected to take care of it?  And if so, then how?

> +	return link;
> +}
> +EXPORT_SYMBOL_GPL(device_link_find);
> +
>  /**
>   * device_link_add - Create a link between two devices.
>   * @consumer: Consumer end of the link.
> @@ -195,9 +219,9 @@ struct device_link *device_link_add(struct device *consumer,
>  		goto out;
>  	}
>  
> -	list_for_each_entry(link, &supplier->links.consumers, s_node)
> -		if (link->consumer == consumer)
> -			goto out;
> +	link = device_link_find(consumer, supplier);
> +	if (link)
> +		goto out;
>  
>  	link = kzalloc(sizeof(*link), GFP_KERNEL);
>  	if (!link)
> diff --git a/include/linux/device.h b/include/linux/device.h
> index b093405ed525..13bc1884c3eb 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -1278,6 +1278,8 @@ extern const char *dev_driver_string(const struct device *dev);
>  struct device_link *device_link_add(struct device *consumer,
>  				    struct device *supplier, u32 flags);
>  void device_link_del(struct device_link *link);
> +struct device_link *device_link_find(struct device *consumer,
> +				     struct device *supplier);
>  
>  #ifdef CONFIG_PRINTK
>  
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vivek Gautam March 13, 2018, 9:55 a.m. UTC | #2
On Tue, Mar 13, 2018 at 3:10 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Tuesday, March 13, 2018 9:55:30 AM CET Vivek Gautam wrote:
>> The lists managing the device-links can be traversed to
>> find the link between two devices. The device_link_add() APIs
>> does traverse these lists to check if there's already a link
>> setup between the two devices.
>> So, add a new APIs, device_link_find(), to find an existing
>> device link between two devices - suppliers and consumers.
>>
>> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
>> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> ---
>>
>>  * New patch added to this series.
>>
>>  drivers/base/core.c    | 30 +++++++++++++++++++++++++++---
>>  include/linux/device.h |  2 ++
>>  2 files changed, 29 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/base/core.c b/drivers/base/core.c
>> index 5847364f25d9..e8c9774e4ba2 100644
>> --- a/drivers/base/core.c
>> +++ b/drivers/base/core.c
>> @@ -144,6 +144,30 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
>>       return 0;
>>  }
>>
>> +/**
>> + * device_link_find - find any existing link between two devices.
>> + * @consumer: Consumer end of the link.
>> + * @supplier: Supplier end of the link.
>> + *
>> + * Returns pointer to the existing link between a supplier and
>> + * and consumer devices, or NULL if no link exists.
>> + */
>> +struct device_link *device_link_find(struct device *consumer,
>> +                                  struct device *supplier)
>> +{
>> +     struct device_link *link = NULL;
>> +
>> +     if (!consumer || !supplier)
>> +             return NULL;
>> +
>> +     list_for_each_entry(link, &supplier->links.consumers, s_node)
>> +             if (link->consumer == consumer)
>> +                     break;
>> +
>
> Any mutual exclusion?
>
> Or is the caller expected to take care of it?  And if so, then how?

I think it's better that we take care of lock here in the code rather
than depending
on the caller.
But i can't take device_links_write_lock() since device_link_add()
already takes that.

regards
Vivek

>
>> +     return link;
>> +}
>> +EXPORT_SYMBOL_GPL(device_link_find);
>> +
>>  /**
>>   * device_link_add - Create a link between two devices.
>>   * @consumer: Consumer end of the link.
>> @@ -195,9 +219,9 @@ struct device_link *device_link_add(struct device *consumer,
>>               goto out;
>>       }
>>
>> -     list_for_each_entry(link, &supplier->links.consumers, s_node)
>> -             if (link->consumer == consumer)
>> -                     goto out;
>> +     link = device_link_find(consumer, supplier);
>> +     if (link)
>> +             goto out;
>>
>>       link = kzalloc(sizeof(*link), GFP_KERNEL);
>>       if (!link)
>> diff --git a/include/linux/device.h b/include/linux/device.h
>> index b093405ed525..13bc1884c3eb 100644
>> --- a/include/linux/device.h
>> +++ b/include/linux/device.h
>> @@ -1278,6 +1278,8 @@ extern const char *dev_driver_string(const struct device *dev);
>>  struct device_link *device_link_add(struct device *consumer,
>>                                   struct device *supplier, u32 flags);
>>  void device_link_del(struct device_link *link);
>> +struct device_link *device_link_find(struct device *consumer,
>> +                                  struct device *supplier);
>>
>>  #ifdef CONFIG_PRINTK
>>
>>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vivek Gautam March 13, 2018, 9:58 a.m. UTC | #3
On Tue, Mar 13, 2018 at 2:25 PM, Vivek Gautam
<vivek.gautam@codeaurora.org> wrote:
> The lists managing the device-links can be traversed to
> find the link between two devices. The device_link_add() APIs
> does traverse these lists to check if there's already a link
> setup between the two devices.
> So, add a new APIs, device_link_find(), to find an existing
> device link between two devices - suppliers and consumers.
>
> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> ---
>
>  * New patch added to this series.
>
>  drivers/base/core.c    | 30 +++++++++++++++++++++++++++---
>  include/linux/device.h |  2 ++
>  2 files changed, 29 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index 5847364f25d9..e8c9774e4ba2 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -144,6 +144,30 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
>         return 0;
>  }
>
> +/**
> + * device_link_find - find any existing link between two devices.
> + * @consumer: Consumer end of the link.
> + * @supplier: Supplier end of the link.
> + *
> + * Returns pointer to the existing link between a supplier and
> + * and consumer devices, or NULL if no link exists.
> + */
> +struct device_link *device_link_find(struct device *consumer,
> +                                    struct device *supplier)
> +{
> +       struct device_link *link = NULL;
> +
> +       if (!consumer || !supplier)
> +               return NULL;
> +
> +       list_for_each_entry(link, &supplier->links.consumers, s_node)
> +               if (link->consumer == consumer)
> +                       break;
> +
> +       return link;

My bad, this too needs fixing (didn't add the changes to the patch :( )

           list_for_each_entry(link, &supplier->links.consumers, s_node)
                   if (link->consumer == consumer)
                           return link;

           return NULL;

> +}
> +EXPORT_SYMBOL_GPL(device_link_find);
> +
>  /**
>   * device_link_add - Create a link between two devices.
>   * @consumer: Consumer end of the link.
> @@ -195,9 +219,9 @@ struct device_link *device_link_add(struct device *consumer,
>                 goto out;
>         }
>
> -       list_for_each_entry(link, &supplier->links.consumers, s_node)
> -               if (link->consumer == consumer)
> -                       goto out;
> +       link = device_link_find(consumer, supplier);
> +       if (link)
> +               goto out;
>
>         link = kzalloc(sizeof(*link), GFP_KERNEL);
>         if (!link)
> diff --git a/include/linux/device.h b/include/linux/device.h
> index b093405ed525..13bc1884c3eb 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -1278,6 +1278,8 @@ extern const char *dev_driver_string(const struct device *dev);
>  struct device_link *device_link_add(struct device *consumer,
>                                     struct device *supplier, u32 flags);
>  void device_link_del(struct device_link *link);
> +struct device_link *device_link_find(struct device *consumer,
> +                                    struct device *supplier);
>
>  #ifdef CONFIG_PRINTK
>
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tomasz Figa March 13, 2018, 10:15 a.m. UTC | #4
Hi Vivek,

Thanks for the patch.

On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
<vivek.gautam@codeaurora.org> wrote:
> The lists managing the device-links can be traversed to
> find the link between two devices. The device_link_add() APIs
> does traverse these lists to check if there's already a link
> setup between the two devices.
> So, add a new APIs, device_link_find(), to find an existing
> device link between two devices - suppliers and consumers.

I'm wondering if this API would be useful for anything else that the
problem we're trying to solve with deleting links without storing them
anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
better alternative?

Best regards,
Tomasz
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vivek Gautam March 13, 2018, 10:34 a.m. UTC | #5
Hi Tomasz,

On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> Hi Vivek,
>
> Thanks for the patch.
>
> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
> <vivek.gautam@codeaurora.org> wrote:
>> The lists managing the device-links can be traversed to
>> find the link between two devices. The device_link_add() APIs
>> does traverse these lists to check if there's already a link
>> setup between the two devices.
>> So, add a new APIs, device_link_find(), to find an existing
>> device link between two devices - suppliers and consumers.
>
> I'm wondering if this API would be useful for anything else that the
> problem we're trying to solve with deleting links without storing them
> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
> better alternative?

Yea, that sounds simpler i think. Will add this API instead of
find_link(). Thanks.

regards
vivek
>
> Best regards,
> Tomasz
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tomasz Figa March 13, 2018, 11:23 a.m. UTC | #6
On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam
<vivek.gautam@codeaurora.org> wrote:
> Hi Tomasz,
>
> On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
>> Hi Vivek,
>>
>> Thanks for the patch.
>>
>> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
>> <vivek.gautam@codeaurora.org> wrote:
>>> The lists managing the device-links can be traversed to
>>> find the link between two devices. The device_link_add() APIs
>>> does traverse these lists to check if there's already a link
>>> setup between the two devices.
>>> So, add a new APIs, device_link_find(), to find an existing
>>> device link between two devices - suppliers and consumers.
>>
>> I'm wondering if this API would be useful for anything else that the
>> problem we're trying to solve with deleting links without storing them
>> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
>> better alternative?
>
> Yea, that sounds simpler i think. Will add this API instead of
> find_link(). Thanks.

Perhaps let's wait for a moment to see if there are other opinions. :)

Rafael, Lucas, any thoughts?

Best regards,
Tomasz
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robin Murphy March 13, 2018, 12:49 p.m. UTC | #7
On 13/03/18 09:55, Vivek Gautam wrote:
> On Tue, Mar 13, 2018 at 3:10 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>> On Tuesday, March 13, 2018 9:55:30 AM CET Vivek Gautam wrote:
>>> The lists managing the device-links can be traversed to
>>> find the link between two devices. The device_link_add() APIs
>>> does traverse these lists to check if there's already a link
>>> setup between the two devices.
>>> So, add a new APIs, device_link_find(), to find an existing
>>> device link between two devices - suppliers and consumers.
>>>
>>> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
>>> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>> ---
>>>
>>>   * New patch added to this series.
>>>
>>>   drivers/base/core.c    | 30 +++++++++++++++++++++++++++---
>>>   include/linux/device.h |  2 ++
>>>   2 files changed, 29 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/base/core.c b/drivers/base/core.c
>>> index 5847364f25d9..e8c9774e4ba2 100644
>>> --- a/drivers/base/core.c
>>> +++ b/drivers/base/core.c
>>> @@ -144,6 +144,30 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
>>>        return 0;
>>>   }
>>>
>>> +/**
>>> + * device_link_find - find any existing link between two devices.
>>> + * @consumer: Consumer end of the link.
>>> + * @supplier: Supplier end of the link.
>>> + *
>>> + * Returns pointer to the existing link between a supplier and
>>> + * and consumer devices, or NULL if no link exists.
>>> + */
>>> +struct device_link *device_link_find(struct device *consumer,
>>> +                                  struct device *supplier)
>>> +{
>>> +     struct device_link *link = NULL;
>>> +
>>> +     if (!consumer || !supplier)
>>> +             return NULL;
>>> +
>>> +     list_for_each_entry(link, &supplier->links.consumers, s_node)
>>> +             if (link->consumer == consumer)
>>> +                     break;
>>> +
>>
>> Any mutual exclusion?
>>
>> Or is the caller expected to take care of it?  And if so, then how?
> 
> I think it's better that we take care of lock here in the code rather
> than depending
> on the caller.
> But i can't take device_links_write_lock() since device_link_add()
> already takes that.

Well, the normal pattern is to break out the internal helper function 
as-is, then add a public wrapper which validates inputs, handles 
locking, etc., equivalently to existing caller(s). See what 
device_link_del() and others do, e.g.:

static struct device_link *__device_link_find(struct device *consumer,
		struct device *supplier)
{
	list_for_each_entry(link, &supplier->links.consumers, s_node)
		if (link->consumer == consumer)
			return link;
	return NULL;
}

struct device_link *device_link_find(struct device *consumer,
		struct device *supplier)
{
	struct device_link *link;

	if (!consumer || !supplier)
		return NULL;

	device_links_write_lock();
	link = __device_link_find(consumer, supplier);	
	device_links_write_unlock();
	return link;
}

where device_link_add() would call __device_link_find() directly.

However, as Tomasz points out (and I hadn't really considered), if the 
only reasonable thing to with a link once you've found it is to delete 
it, then in terms of the public API it may well make more sense to just 
implement something like a device_link_remove() which does both in one go.

Robin.
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vivek Gautam March 13, 2018, 2:39 p.m. UTC | #8
Hi Robin,


On Tue, Mar 13, 2018 at 6:19 PM, Robin Murphy <robin.murphy@arm.com> wrote:
> On 13/03/18 09:55, Vivek Gautam wrote:
>>
>> On Tue, Mar 13, 2018 at 3:10 PM, Rafael J. Wysocki <rjw@rjwysocki.net>
>> wrote:
>>>
>>> On Tuesday, March 13, 2018 9:55:30 AM CET Vivek Gautam wrote:
>>>>
>>>> The lists managing the device-links can be traversed to
>>>> find the link between two devices. The device_link_add() APIs
>>>> does traverse these lists to check if there's already a link
>>>> setup between the two devices.
>>>> So, add a new APIs, device_link_find(), to find an existing
>>>> device link between two devices - suppliers and consumers.
>>>>
>>>> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
>>>> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>>> ---
>>>>
>>>>   * New patch added to this series.
>>>>
>>>>   drivers/base/core.c    | 30 +++++++++++++++++++++++++++---
>>>>   include/linux/device.h |  2 ++
>>>>   2 files changed, 29 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/base/core.c b/drivers/base/core.c
>>>> index 5847364f25d9..e8c9774e4ba2 100644
>>>> --- a/drivers/base/core.c
>>>> +++ b/drivers/base/core.c
>>>> @@ -144,6 +144,30 @@ static int device_reorder_to_tail(struct device
>>>> *dev, void *not_used)
>>>>        return 0;
>>>>   }
>>>>
>>>> +/**
>>>> + * device_link_find - find any existing link between two devices.
>>>> + * @consumer: Consumer end of the link.
>>>> + * @supplier: Supplier end of the link.
>>>> + *
>>>> + * Returns pointer to the existing link between a supplier and
>>>> + * and consumer devices, or NULL if no link exists.
>>>> + */
>>>> +struct device_link *device_link_find(struct device *consumer,
>>>> +                                  struct device *supplier)
>>>> +{
>>>> +     struct device_link *link = NULL;
>>>> +
>>>> +     if (!consumer || !supplier)
>>>> +             return NULL;
>>>> +
>>>> +     list_for_each_entry(link, &supplier->links.consumers, s_node)
>>>> +             if (link->consumer == consumer)
>>>> +                     break;
>>>> +
>>>
>>>
>>> Any mutual exclusion?
>>>
>>> Or is the caller expected to take care of it?  And if so, then how?
>>
>>
>> I think it's better that we take care of lock here in the code rather
>> than depending
>> on the caller.
>> But i can't take device_links_write_lock() since device_link_add()
>> already takes that.
>
>
> Well, the normal pattern is to break out the internal helper function as-is,
> then add a public wrapper which validates inputs, handles locking, etc.,
> equivalently to existing caller(s). See what device_link_del() and others
> do, e.g.:
>
> static struct device_link *__device_link_find(struct device *consumer,
>                 struct device *supplier)
> {
>         list_for_each_entry(link, &supplier->links.consumers, s_node)
>                 if (link->consumer == consumer)
>                         return link;
>         return NULL;
> }
>
> struct device_link *device_link_find(struct device *consumer,
>                 struct device *supplier)
> {
>         struct device_link *link;
>
>         if (!consumer || !supplier)
>                 return NULL;
>
>         device_links_write_lock();
>         link = __device_link_find(consumer, supplier);
>         device_links_write_unlock();
>         return link;
> }
>
> where device_link_add() would call __device_link_find() directly.

Right, I understand it now. Thanks for detailed explanation.

regards
Vivek

>
> However, as Tomasz points out (and I hadn't really considered), if the only
> reasonable thing to with a link once you've found it is to delete it, then
> in terms of the public API it may well make more sense to just implement
> something like a device_link_remove() which does both in one go.
>
> Robin.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki March 14, 2018, 11:12 a.m. UTC | #9
On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
> On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam
> <vivek.gautam@codeaurora.org> wrote:
> > Hi Tomasz,
> >
> > On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> >> Hi Vivek,
> >>
> >> Thanks for the patch.
> >>
> >> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
> >> <vivek.gautam@codeaurora.org> wrote:
> >>> The lists managing the device-links can be traversed to
> >>> find the link between two devices. The device_link_add() APIs
> >>> does traverse these lists to check if there's already a link
> >>> setup between the two devices.
> >>> So, add a new APIs, device_link_find(), to find an existing
> >>> device link between two devices - suppliers and consumers.
> >>
> >> I'm wondering if this API would be useful for anything else that the
> >> problem we're trying to solve with deleting links without storing them
> >> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
> >> better alternative?
> >
> > Yea, that sounds simpler i think. Will add this API instead of
> > find_link(). Thanks.
> 
> Perhaps let's wait for a moment to see if there are other opinions. :)
> 
> Rafael, Lucas, any thoughts?

It is not clear to me what the device_link_del_dev(consumer, supplier) would do.

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tomasz Figa March 14, 2018, 11:50 a.m. UTC | #10
On Wed, Mar 14, 2018 at 8:12 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
>> On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam
>> <vivek.gautam@codeaurora.org> wrote:
>> > Hi Tomasz,
>> >
>> > On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
>> >> Hi Vivek,
>> >>
>> >> Thanks for the patch.
>> >>
>> >> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
>> >> <vivek.gautam@codeaurora.org> wrote:
>> >>> The lists managing the device-links can be traversed to
>> >>> find the link between two devices. The device_link_add() APIs
>> >>> does traverse these lists to check if there's already a link
>> >>> setup between the two devices.
>> >>> So, add a new APIs, device_link_find(), to find an existing
>> >>> device link between two devices - suppliers and consumers.
>> >>
>> >> I'm wondering if this API would be useful for anything else that the
>> >> problem we're trying to solve with deleting links without storing them
>> >> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
>> >> better alternative?
>> >
>> > Yea, that sounds simpler i think. Will add this API instead of
>> > find_link(). Thanks.
>>
>> Perhaps let's wait for a moment to see if there are other opinions. :)
>>
>> Rafael, Lucas, any thoughts?
>
> It is not clear to me what the device_link_del_dev(consumer, supplier) would do.

It would delete a link between consumer and supplier.

Best regards,
Tomasz
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki March 14, 2018, 11:57 a.m. UTC | #11
On Wednesday, March 14, 2018 12:50:54 PM CET Tomasz Figa wrote:
> On Wed, Mar 14, 2018 at 8:12 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> > On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
> >> On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam
> >> <vivek.gautam@codeaurora.org> wrote:
> >> > Hi Tomasz,
> >> >
> >> > On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> >> >> Hi Vivek,
> >> >>
> >> >> Thanks for the patch.
> >> >>
> >> >> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
> >> >> <vivek.gautam@codeaurora.org> wrote:
> >> >>> The lists managing the device-links can be traversed to
> >> >>> find the link between two devices. The device_link_add() APIs
> >> >>> does traverse these lists to check if there's already a link
> >> >>> setup between the two devices.
> >> >>> So, add a new APIs, device_link_find(), to find an existing
> >> >>> device link between two devices - suppliers and consumers.
> >> >>
> >> >> I'm wondering if this API would be useful for anything else that the
> >> >> problem we're trying to solve with deleting links without storing them
> >> >> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
> >> >> better alternative?
> >> >
> >> > Yea, that sounds simpler i think. Will add this API instead of
> >> > find_link(). Thanks.
> >>
> >> Perhaps let's wait for a moment to see if there are other opinions. :)
> >>
> >> Rafael, Lucas, any thoughts?
> >
> > It is not clear to me what the device_link_del_dev(consumer, supplier) would do.
> 
> It would delete a link between consumer and supplier.

If there's one I suppose.

I'm wondering if you are somehow trying to address the same problem as the
device links reference counting patch from Lukas that has been queued up for 4.17
already.

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robin Murphy March 14, 2018, 12:14 p.m. UTC | #12
Hi Rafael,

On 14/03/18 11:57, Rafael J. Wysocki wrote:
> On Wednesday, March 14, 2018 12:50:54 PM CET Tomasz Figa wrote:
>> On Wed, Mar 14, 2018 at 8:12 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>>> On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
>>>> On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam
>>>> <vivek.gautam@codeaurora.org> wrote:
>>>>> Hi Tomasz,
>>>>>
>>>>> On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
>>>>>> Hi Vivek,
>>>>>>
>>>>>> Thanks for the patch.
>>>>>>
>>>>>> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam
>>>>>> <vivek.gautam@codeaurora.org> wrote:
>>>>>>> The lists managing the device-links can be traversed to
>>>>>>> find the link between two devices. The device_link_add() APIs
>>>>>>> does traverse these lists to check if there's already a link
>>>>>>> setup between the two devices.
>>>>>>> So, add a new APIs, device_link_find(), to find an existing
>>>>>>> device link between two devices - suppliers and consumers.
>>>>>>
>>>>>> I'm wondering if this API would be useful for anything else that the
>>>>>> problem we're trying to solve with deleting links without storing them
>>>>>> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
>>>>>> better alternative?
>>>>>
>>>>> Yea, that sounds simpler i think. Will add this API instead of
>>>>> find_link(). Thanks.
>>>>
>>>> Perhaps let's wait for a moment to see if there are other opinions. :)
>>>>
>>>> Rafael, Lucas, any thoughts?
>>>
>>> It is not clear to me what the device_link_del_dev(consumer, supplier) would do.
>>
>> It would delete a link between consumer and supplier.
> 
> If there's one I suppose.
> 
> I'm wondering if you are somehow trying to address the same problem as the
> device links reference counting patch from Lukas that has been queued up for 4.17
> already.

Not quite - the issue here is that we have one supplier with an 
arbitrarily large number of consumers, and would prefer that supplier 
not to have to spend a whole bunch of memory to store all the struct 
device_link pointers for the sole reason of having something to give to 
device_link_del() at the end, given that the device links code is 
already keeping track of everything internally anyway.

The current API would permit doing this:

	iommu_attach(dev) {
		...
		if (!device_link_add(dev, iommu, IOMMU_LINK_FLAGS))
			return -ENODEV;
		...
	}

	iommu_detach(dev) {
		...
		// Will return the existing link from earlier
		link = device_link_add(dev, iommu, IOMMU_LINK_FLAGS);
		device_link_del(link);
		// Needed once refcounting is in place
		//device_link_del(link);
		...
	}

but it looks so wacky and non-obvious that we'd like to encapsulate the 
same behaviour into a more formal interface (my personal naming 
preference would be device_link_remove(consumer, supplier)).

Robin.
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukas Wunner March 14, 2018, 12:23 p.m. UTC | #13
On Wed, Mar 14, 2018 at 12:12:05PM +0100, Rafael J. Wysocki wrote:
> On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
> > On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
> > > On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> > >> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
> > >>> The lists managing the device-links can be traversed to
> > >>> find the link between two devices. The device_link_add() APIs
> > >>> does traverse these lists to check if there's already a link
> > >>> setup between the two devices.
> > >>> So, add a new APIs, device_link_find(), to find an existing
> > >>> device link between two devices - suppliers and consumers.
> > >>
> > >> I'm wondering if this API would be useful for anything else that the
> > >> problem we're trying to solve with deleting links without storing them
> > >> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
> > >> better alternative?
> > >
> > > Yea, that sounds simpler i think. Will add this API instead of
> > > find_link(). Thanks.
> > 
> > Perhaps let's wait for a moment to see if there are other opinions. :)
> > 
> > Rafael, Lucas, any thoughts?
> 
> It is not clear to me what the device_link_del_dev(consumer, supplier)
> would do.

The point appears to be that the pointer to the device_link need not be
stored somewhere for later deletion.  The newly added function would
check if a device link exists and delete it if so.

However I don't understand why storing the pointer would be a problem?
Also, would using DL_FLAG_AUTOREMOVE avoid the need for the additional
function?

Thanks,

Lukas
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukas Wunner March 14, 2018, 12:27 p.m. UTC | #14
On Wed, Mar 14, 2018 at 12:14:15PM +0000, Robin Murphy wrote:
> >>On Wed, Mar 14, 2018 at 8:12 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> >>>On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
> >>>>On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
> >>>>>On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> >>>>>>On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
> >>>>>>>The lists managing the device-links can be traversed to
> >>>>>>>find the link between two devices. The device_link_add() APIs
> >>>>>>>does traverse these lists to check if there's already a link
> >>>>>>>setup between the two devices.
> >>>>>>>So, add a new APIs, device_link_find(), to find an existing
> >>>>>>>device link between two devices - suppliers and consumers.
> >>>>>>
> >>>>>>I'm wondering if this API would be useful for anything else that the
> >>>>>>problem we're trying to solve with deleting links without storing them
> >>>>>>anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
> >>>>>>better alternative?
> >>>>>
> >>>>>Yea, that sounds simpler i think. Will add this API instead of
> >>>>>find_link(). Thanks.
> >>>>
> >>>>Perhaps let's wait for a moment to see if there are other opinions. :)
> >>>>
> >>>>Rafael, Lucas, any thoughts?
> >>>
> >>>It is not clear to me what the device_link_del_dev(consumer, supplier)
> >>>would do.
> 
> Not quite - the issue here is that we have one supplier with an arbitrarily
> large number of consumers, and would prefer that supplier not to have to
> spend a whole bunch of memory to store all the struct device_link pointers
> for the sole reason of having something to give to device_link_del() at the
> end, given that the device links code is already keeping track of everything
> internally anyway.

Makes sense to me.  How about an additional flag which autoremoves the
link on provider unbind?

Thanks,

Lukas
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vivek Gautam March 20, 2018, 7:56 a.m. UTC | #15
Hi Lukasz,


On 3/14/2018 5:57 PM, Lukas Wunner wrote:
> On Wed, Mar 14, 2018 at 12:14:15PM +0000, Robin Murphy wrote:
>>>> On Wed, Mar 14, 2018 at 8:12 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>>>>> On Tuesday, March 13, 2018 12:23:34 PM CET Tomasz Figa wrote:
>>>>>> On Tue, Mar 13, 2018 at 7:34 PM, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
>>>>>>> On Tue, Mar 13, 2018 at 3:45 PM, Tomasz Figa <tfiga@chromium.org> wrote:
>>>>>>>> On Tue, Mar 13, 2018 at 5:55 PM, Vivek Gautam <vivek.gautam@codeaurora.org> wrote:
>>>>>>>>> The lists managing the device-links can be traversed to
>>>>>>>>> find the link between two devices. The device_link_add() APIs
>>>>>>>>> does traverse these lists to check if there's already a link
>>>>>>>>> setup between the two devices.
>>>>>>>>> So, add a new APIs, device_link_find(), to find an existing
>>>>>>>>> device link between two devices - suppliers and consumers.
>>>>>>>> I'm wondering if this API would be useful for anything else that the
>>>>>>>> problem we're trying to solve with deleting links without storing them
>>>>>>>> anywhere. Perhaps a device_link_del_dev(consumer, supplier) would be a
>>>>>>>> better alternative?
>>>>>>> Yea, that sounds simpler i think. Will add this API instead of
>>>>>>> find_link(). Thanks.
>>>>>> Perhaps let's wait for a moment to see if there are other opinions. :)
>>>>>>
>>>>>> Rafael, Lucas, any thoughts?
>>>>> It is not clear to me what the device_link_del_dev(consumer, supplier)
>>>>> would do.
>> Not quite - the issue here is that we have one supplier with an arbitrarily
>> large number of consumers, and would prefer that supplier not to have to
>> spend a whole bunch of memory to store all the struct device_link pointers
>> for the sole reason of having something to give to device_link_del() at the
>> end, given that the device links code is already keeping track of everything
>> internally anyway.
> Makes sense to me.  How about an additional flag which autoremoves the
> link on provider unbind?

If I understand this correctly, if we create the device link with 
DL_FLAG_AUTOREMOVE, the link is deleted after a consumer unbind. During 
a supplier unbind all we get is a WARN_ON with DL_FLAG_AUTOREMOVE. I 
guess that's an intended behavior?

If this is the case, then the consumer/supplier drivers just don't have 
to take care of deleting the device link explicitly.
Is my understanding correct?

regards
Vivek

>
> Thanks,
>
> Lukas

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5847364f25d9..e8c9774e4ba2 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -144,6 +144,30 @@  static int device_reorder_to_tail(struct device *dev, void *not_used)
 	return 0;
 }
 
+/**
+ * device_link_find - find any existing link between two devices.
+ * @consumer: Consumer end of the link.
+ * @supplier: Supplier end of the link.
+ *
+ * Returns pointer to the existing link between a supplier and
+ * and consumer devices, or NULL if no link exists.
+ */
+struct device_link *device_link_find(struct device *consumer,
+				     struct device *supplier)
+{
+	struct device_link *link = NULL;
+
+	if (!consumer || !supplier)
+		return NULL;
+
+	list_for_each_entry(link, &supplier->links.consumers, s_node)
+		if (link->consumer == consumer)
+			break;
+
+	return link;
+}
+EXPORT_SYMBOL_GPL(device_link_find);
+
 /**
  * device_link_add - Create a link between two devices.
  * @consumer: Consumer end of the link.
@@ -195,9 +219,9 @@  struct device_link *device_link_add(struct device *consumer,
 		goto out;
 	}
 
-	list_for_each_entry(link, &supplier->links.consumers, s_node)
-		if (link->consumer == consumer)
-			goto out;
+	link = device_link_find(consumer, supplier);
+	if (link)
+		goto out;
 
 	link = kzalloc(sizeof(*link), GFP_KERNEL);
 	if (!link)
diff --git a/include/linux/device.h b/include/linux/device.h
index b093405ed525..13bc1884c3eb 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1278,6 +1278,8 @@  extern const char *dev_driver_string(const struct device *dev);
 struct device_link *device_link_add(struct device *consumer,
 				    struct device *supplier, u32 flags);
 void device_link_del(struct device_link *link);
+struct device_link *device_link_find(struct device *consumer,
+				     struct device *supplier);
 
 #ifdef CONFIG_PRINTK