diff mbox series

[v4,6/6] PCI: Expose reset type to users of pci_reset_bus()

Message ID 20180919163037.13497-7-okaya@kernel.org (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show
Series PCI: Add reset type parameter to PCI reset functions | expand

Commit Message

Sinan Kaya Sept. 19, 2018, 4:30 p.m. UTC
Looking to have more control between the users of the API vs. what the API
can do internally. The new reset_type tells the PCI core about the bounds
of the request.

Signed-off-by: Sinan Kaya <okaya@kernel.org>
---
 drivers/pci/pci.c           | 18 +++++++++++++++---
 drivers/vfio/pci/vfio_pci.c |  6 ++++--
 include/linux/pci.h         |  2 +-
 3 files changed, 20 insertions(+), 6 deletions(-)

Comments

Alex Williamson Sept. 19, 2018, 7 p.m. UTC | #1
On Wed, 19 Sep 2018 16:30:37 +0000
Sinan Kaya <okaya@kernel.org> wrote:

> Looking to have more control between the users of the API vs. what the API
> can do internally. The new reset_type tells the PCI core about the bounds
> of the request.
> 
> Signed-off-by: Sinan Kaya <okaya@kernel.org>
> ---
>  drivers/pci/pci.c           | 18 +++++++++++++++---
>  drivers/vfio/pci/vfio_pci.c |  6 ++++--
>  include/linux/pci.h         |  2 +-
>  3 files changed, 20 insertions(+), 6 deletions(-)

Acked-by: Alex Williamson <alex.williamson@redhat.com>

> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index b4f14419bd51..f11d29f32119 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5232,13 +5232,25 @@ static int __pci_reset_bus(struct pci_bus *bus)
>  /**
>   * pci_reset_bus - Try to reset a PCI bus
>   * @pdev: top level PCI device to reset via slot/bus
> + * @reset_type: resets to try
>   *
>   * Same as above except return -EAGAIN if the bus cannot be locked
>   */
> -int pci_reset_bus(struct pci_dev *pdev)
> +int pci_reset_bus(struct pci_dev *pdev, u32 reset_type)
>  {
> -	return (!pci_probe_reset_slot(pdev->slot)) ?
> -	    __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
> +	if (reset_type & PCI_RESET_LINK) {
> +		return (!pci_probe_reset_slot(pdev->slot)) ?
> +				__pci_reset_slot(pdev->slot) :
> +				__pci_reset_bus(pdev->bus);
> +	}
> +
> +	if (reset_type & PCI_RESET_BUS)
> +		return __pci_reset_bus(pdev->bus);
> +
> +	if (reset_type & PCI_RESET_SLOT)
> +		return __pci_reset_slot(pdev->slot);
> +
> +	return -EINVAL;
>  }
>  EXPORT_SYMBOL_GPL(pci_reset_bus);
>  
> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
> index fe7ada997c51..0e80c72b1eaa 100644
> --- a/drivers/vfio/pci/vfio_pci.c
> +++ b/drivers/vfio/pci/vfio_pci.c
> @@ -1015,7 +1015,8 @@ static long vfio_pci_ioctl(void *device_data,
>  						    &info, slot);
>  		if (!ret)
>  			/* User has access, do the reset */
> -			ret = pci_reset_bus(vdev->pdev);
> +			ret = pci_reset_bus(vdev->pdev,
> +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
>  
>  hot_reset_release:
>  		for (i--; i >= 0; i--)
> @@ -1390,7 +1391,8 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
>  	}
>  
>  	if (needs_reset)
> -		ret = pci_reset_bus(vdev->pdev);
> +		ret = pci_reset_bus(vdev->pdev,
> +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
>  
>  put_devs:
>  	for (i = 0; i < devs.cur_index; i++) {
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 4fdddcb85066..85f48e156753 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1128,7 +1128,7 @@ int pci_reset_function_locked(struct pci_dev *dev, u32 reset_type);
>  int pci_try_reset_function(struct pci_dev *dev, u32 reset_type);
>  int pci_probe_reset_slot(struct pci_slot *slot);
>  int pci_probe_reset_bus(struct pci_bus *bus);
> -int pci_reset_bus(struct pci_dev *dev);
> +int pci_reset_bus(struct pci_dev *dev, u32 reset_type);
>  void pci_reset_secondary_bus(struct pci_dev *dev);
>  void pcibios_reset_secondary_bus(struct pci_dev *dev);
>  void pci_update_resource(struct pci_dev *dev, int resno);
Bjorn Helgaas Sept. 25, 2018, 8:54 p.m. UTC | #2
On Wed, Sep 19, 2018 at 04:30:37PM +0000, Sinan Kaya wrote:
> Looking to have more control between the users of the API vs. what the API
> can do internally. The new reset_type tells the PCI core about the bounds
> of the request.
> 
> Signed-off-by: Sinan Kaya <okaya@kernel.org>
> ---
>  drivers/pci/pci.c           | 18 +++++++++++++++---
>  drivers/vfio/pci/vfio_pci.c |  6 ++++--
>  include/linux/pci.h         |  2 +-
>  3 files changed, 20 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index b4f14419bd51..f11d29f32119 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5232,13 +5232,25 @@ static int __pci_reset_bus(struct pci_bus *bus)
>  /**
>   * pci_reset_bus - Try to reset a PCI bus
>   * @pdev: top level PCI device to reset via slot/bus
> + * @reset_type: resets to try
>   *
>   * Same as above except return -EAGAIN if the bus cannot be locked
>   */
> -int pci_reset_bus(struct pci_dev *pdev)
> +int pci_reset_bus(struct pci_dev *pdev, u32 reset_type)
>  {
> -	return (!pci_probe_reset_slot(pdev->slot)) ?
> -	    __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
> +	if (reset_type & PCI_RESET_LINK) {
> +		return (!pci_probe_reset_slot(pdev->slot)) ?
> +				__pci_reset_slot(pdev->slot) :
> +				__pci_reset_bus(pdev->bus);
> +	}
> +
> +	if (reset_type & PCI_RESET_BUS)
> +		return __pci_reset_bus(pdev->bus);
> +
> +	if (reset_type & PCI_RESET_SLOT)
> +		return __pci_reset_slot(pdev->slot);

I don't understand this code.  We have

  #define PCI_RESET_LINK         (PCI_RESET_SLOT | PCI_RESET_BUS)

so if either PCI_RESET_BUS or PCI_RESET_SLOT is set, we should take
the first "if" above, which always returns, and the last two should
never be reached.  What am I missing?

> +
> +	return -EINVAL;
>  }
>  EXPORT_SYMBOL_GPL(pci_reset_bus);
>  
> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
> index fe7ada997c51..0e80c72b1eaa 100644
> --- a/drivers/vfio/pci/vfio_pci.c
> +++ b/drivers/vfio/pci/vfio_pci.c
> @@ -1015,7 +1015,8 @@ static long vfio_pci_ioctl(void *device_data,
>  						    &info, slot);
>  		if (!ret)
>  			/* User has access, do the reset */
> -			ret = pci_reset_bus(vdev->pdev);
> +			ret = pci_reset_bus(vdev->pdev,
> +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);

This is the only place in the whole series where a caller uses
something other than PCI_RESET_ANY.  Inquiring minds want to know why.
I'm sure it's the right thing to do, it's just that we'll need to know
how to choose in future cases.

>  
>  hot_reset_release:
>  		for (i--; i >= 0; i--)
> @@ -1390,7 +1391,8 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
>  	}
>  
>  	if (needs_reset)
> -		ret = pci_reset_bus(vdev->pdev);
> +		ret = pci_reset_bus(vdev->pdev,
> +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
>  
>  put_devs:
>  	for (i = 0; i < devs.cur_index; i++) {
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 4fdddcb85066..85f48e156753 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1128,7 +1128,7 @@ int pci_reset_function_locked(struct pci_dev *dev, u32 reset_type);
>  int pci_try_reset_function(struct pci_dev *dev, u32 reset_type);
>  int pci_probe_reset_slot(struct pci_slot *slot);
>  int pci_probe_reset_bus(struct pci_bus *bus);
> -int pci_reset_bus(struct pci_dev *dev);
> +int pci_reset_bus(struct pci_dev *dev, u32 reset_type);
>  void pci_reset_secondary_bus(struct pci_dev *dev);
>  void pcibios_reset_secondary_bus(struct pci_dev *dev);
>  void pci_update_resource(struct pci_dev *dev, int resno);
> -- 
> 2.18.0
>
Sinan Kaya Sept. 25, 2018, 9:15 p.m. UTC | #3
On 9/25/2018 4:54 PM, Bjorn Helgaas wrote:
> On Wed, Sep 19, 2018 at 04:30:37PM +0000, Sinan Kaya wrote:
>> Looking to have more control between the users of the API vs. what the API
>> can do internally. The new reset_type tells the PCI core about the bounds
>> of the request.
>>
>> Signed-off-by: Sinan Kaya <okaya@kernel.org>
>> ---
>>   drivers/pci/pci.c           | 18 +++++++++++++++---
>>   drivers/vfio/pci/vfio_pci.c |  6 ++++--
>>   include/linux/pci.h         |  2 +-
>>   3 files changed, 20 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>> index b4f14419bd51..f11d29f32119 100644
>> --- a/drivers/pci/pci.c
>> +++ b/drivers/pci/pci.c
>> @@ -5232,13 +5232,25 @@ static int __pci_reset_bus(struct pci_bus *bus)
>>   /**
>>    * pci_reset_bus - Try to reset a PCI bus
>>    * @pdev: top level PCI device to reset via slot/bus
>> + * @reset_type: resets to try
>>    *
>>    * Same as above except return -EAGAIN if the bus cannot be locked
>>    */
>> -int pci_reset_bus(struct pci_dev *pdev)
>> +int pci_reset_bus(struct pci_dev *pdev, u32 reset_type)
>>   {
>> -	return (!pci_probe_reset_slot(pdev->slot)) ?
>> -	    __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
>> +	if (reset_type & PCI_RESET_LINK) {
>> +		return (!pci_probe_reset_slot(pdev->slot)) ?
>> +				__pci_reset_slot(pdev->slot) :
>> +				__pci_reset_bus(pdev->bus);
>> +	}
>> +
>> +	if (reset_type & PCI_RESET_BUS)
>> +		return __pci_reset_bus(pdev->bus);
>> +
>> +	if (reset_type & PCI_RESET_SLOT)
>> +		return __pci_reset_slot(pdev->slot);
> 
> I don't understand this code.  We have
> 
>    #define PCI_RESET_LINK         (PCI_RESET_SLOT | PCI_RESET_BUS)
> 
> so if either PCI_RESET_BUS or PCI_RESET_SLOT is set, we should take
> the first "if" above, which always returns, and the last two should
> never be reached.  What am I missing?

Yup, this is broken. I need to follow up with another patchset.

I was trying to cover the case where user said,

"I need a link reset. I don't care whether it is a slot reset or bus reset
as long as we achieve a reset."

That's when PCI_RESET_LINK is used. We expect most drivers to PCI_RESET_LINK
if they are interested in a link reset and doesn't need to know about the
hotplug capability of a particular slot.

> 
>> +
>> +	return -EINVAL;
>>   }
>>   EXPORT_SYMBOL_GPL(pci_reset_bus);
>>   
>> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
>> index fe7ada997c51..0e80c72b1eaa 100644
>> --- a/drivers/vfio/pci/vfio_pci.c
>> +++ b/drivers/vfio/pci/vfio_pci.c
>> @@ -1015,7 +1015,8 @@ static long vfio_pci_ioctl(void *device_data,
>>   						    &info, slot);
>>   		if (!ret)
>>   			/* User has access, do the reset */
>> -			ret = pci_reset_bus(vdev->pdev);
>> +			ret = pci_reset_bus(vdev->pdev,
>> +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
> 
> This is the only place in the whole series where a caller uses
> something other than PCI_RESET_ANY.  Inquiring minds want to know why.
> I'm sure it's the right thing to do, it's just that we'll need to know
> how to choose in future cases.

Use PCI_RESET_ANY for the existing behavior where you want one type of
reset and don't care if it is PM/function/slot/bus/specific.

Use PCI_RESET_LINK when you need link to retrain.

Use PCI_RESET_SLOT when you know that this system is hotplug capable
by calling probe functions.

Use PCI_RESET_BUS when you know that this system is not hotplug capable
and this endpoint will never be used in such a system.

I can capture this into the commit message.

> 
>>   
>>   hot_reset_release:
>>   		for (i--; i >= 0; i--)
>> @@ -1390,7 +1391,8 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
>>   	}
>>   
>>   	if (needs_reset)
>> -		ret = pci_reset_bus(vdev->pdev);
>> +		ret = pci_reset_bus(vdev->pdev,
>> +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
>>   
>>   put_devs:
>>   	for (i = 0; i < devs.cur_index; i++) {
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index 4fdddcb85066..85f48e156753 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -1128,7 +1128,7 @@ int pci_reset_function_locked(struct pci_dev *dev, u32 reset_type);
>>   int pci_try_reset_function(struct pci_dev *dev, u32 reset_type);
>>   int pci_probe_reset_slot(struct pci_slot *slot);
>>   int pci_probe_reset_bus(struct pci_bus *bus);
>> -int pci_reset_bus(struct pci_dev *dev);
>> +int pci_reset_bus(struct pci_dev *dev, u32 reset_type);
>>   void pci_reset_secondary_bus(struct pci_dev *dev);
>>   void pcibios_reset_secondary_bus(struct pci_dev *dev);
>>   void pci_update_resource(struct pci_dev *dev, int resno);
>> -- 
>> 2.18.0
>>
>
Bjorn Helgaas Sept. 25, 2018, 9:56 p.m. UTC | #4
On Tue, Sep 25, 2018 at 05:15:52PM -0400, Sinan Kaya wrote:
> On 9/25/2018 4:54 PM, Bjorn Helgaas wrote:
> > On Wed, Sep 19, 2018 at 04:30:37PM +0000, Sinan Kaya wrote:
> > > Looking to have more control between the users of the API vs. what the API
> > > can do internally. The new reset_type tells the PCI core about the bounds
> > > of the request.
> > > 
> > > Signed-off-by: Sinan Kaya <okaya@kernel.org>
> > > ---
> > >   drivers/pci/pci.c           | 18 +++++++++++++++---
> > >   drivers/vfio/pci/vfio_pci.c |  6 ++++--
> > >   include/linux/pci.h         |  2 +-
> > >   3 files changed, 20 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > > index b4f14419bd51..f11d29f32119 100644
> > > --- a/drivers/pci/pci.c
> > > +++ b/drivers/pci/pci.c
> > > @@ -5232,13 +5232,25 @@ static int __pci_reset_bus(struct pci_bus *bus)
> > >   /**
> > >    * pci_reset_bus - Try to reset a PCI bus
> > >    * @pdev: top level PCI device to reset via slot/bus
> > > + * @reset_type: resets to try
> > >    *
> > >    * Same as above except return -EAGAIN if the bus cannot be locked
> > >    */
> > > -int pci_reset_bus(struct pci_dev *pdev)
> > > +int pci_reset_bus(struct pci_dev *pdev, u32 reset_type)
> > >   {
> > > -	return (!pci_probe_reset_slot(pdev->slot)) ?
> > > -	    __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
> > > +	if (reset_type & PCI_RESET_LINK) {
> > > +		return (!pci_probe_reset_slot(pdev->slot)) ?
> > > +				__pci_reset_slot(pdev->slot) :
> > > +				__pci_reset_bus(pdev->bus);
> > > +	}
> > > +
> > > +	if (reset_type & PCI_RESET_BUS)
> > > +		return __pci_reset_bus(pdev->bus);
> > > +
> > > +	if (reset_type & PCI_RESET_SLOT)
> > > +		return __pci_reset_slot(pdev->slot);
> > 
> > I don't understand this code.  We have
> > 
> >    #define PCI_RESET_LINK         (PCI_RESET_SLOT | PCI_RESET_BUS)
> > 
> > so if either PCI_RESET_BUS or PCI_RESET_SLOT is set, we should take
> > the first "if" above, which always returns, and the last two should
> > never be reached.  What am I missing?
> 
> Yup, this is broken. I need to follow up with another patchset.
> 
> I was trying to cover the case where user said,
> 
> "I need a link reset. I don't care whether it is a slot reset or bus reset
> as long as we achieve a reset."
> 
> That's when PCI_RESET_LINK is used. We expect most drivers to PCI_RESET_LINK
> if they are interested in a link reset and doesn't need to know about the
> hotplug capability of a particular slot.
> 
> > 
> > > +
> > > +	return -EINVAL;
> > >   }
> > >   EXPORT_SYMBOL_GPL(pci_reset_bus);
> > > diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
> > > index fe7ada997c51..0e80c72b1eaa 100644
> > > --- a/drivers/vfio/pci/vfio_pci.c
> > > +++ b/drivers/vfio/pci/vfio_pci.c
> > > @@ -1015,7 +1015,8 @@ static long vfio_pci_ioctl(void *device_data,
> > >   						    &info, slot);
> > >   		if (!ret)
> > >   			/* User has access, do the reset */
> > > -			ret = pci_reset_bus(vdev->pdev);
> > > +			ret = pci_reset_bus(vdev->pdev,
> > > +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
> > 
> > This is the only place in the whole series where a caller uses
> > something other than PCI_RESET_ANY.  Inquiring minds want to know why.
> > I'm sure it's the right thing to do, it's just that we'll need to know
> > how to choose in future cases.
> 
> Use PCI_RESET_ANY for the existing behavior where you want one type of
> reset and don't care if it is PM/function/slot/bus/specific.
> 
> Use PCI_RESET_LINK when you need link to retrain.

There are no callers using this.  Is this intended specifically for
the case of "the hardware wasn't smart enough to train at the correct
speed, so we fiddled things and want to retrain"?

Maybe it doesn't need to be exposed in include/linux/pci.h and could
be defined internally in drivers/pci/pci.c if it's needed there?

> Use PCI_RESET_SLOT when you know that this system is hotplug capable
> by calling probe functions.

I raise my eyebrows at this because (a) a driver generally can't tell
whether hotplug is supported and (b) even if the driver does know,
what is the benefit to the driver to specify this?  What probe
functions does this refer to?  If I'm a driver writer, I really can't
tell what I'm supposed to do with this guidance.  If I'm supposed to
call a probe function, what is it, when should I call it, and what
should I do with the result?  Am I supposed to know whether hotplug is
supported?  Why would I care?

I'm sure you have good answers for all these questions; I just don't
know what they are :)

> Use PCI_RESET_BUS when you know that this system is not hotplug capable
> and this endpoint will never be used in such a system.

How can a driver know this?  And what's the benefit of being specific?

> I can capture this into the commit message.

I think it needs to be more accessible, e.g., comments near the constants
and/or the function declaration.  We shouldn't expect users of the
interface to dig through the changelogs for it.

> > >   hot_reset_release:
> > >   		for (i--; i >= 0; i--)
> > > @@ -1390,7 +1391,8 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
> > >   	}
> > >   	if (needs_reset)
> > > -		ret = pci_reset_bus(vdev->pdev);
> > > +		ret = pci_reset_bus(vdev->pdev,
> > > +				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
> > >   put_devs:
> > >   	for (i = 0; i < devs.cur_index; i++) {
> > > diff --git a/include/linux/pci.h b/include/linux/pci.h
> > > index 4fdddcb85066..85f48e156753 100644
> > > --- a/include/linux/pci.h
> > > +++ b/include/linux/pci.h
> > > @@ -1128,7 +1128,7 @@ int pci_reset_function_locked(struct pci_dev *dev, u32 reset_type);
> > >   int pci_try_reset_function(struct pci_dev *dev, u32 reset_type);
> > >   int pci_probe_reset_slot(struct pci_slot *slot);
> > >   int pci_probe_reset_bus(struct pci_bus *bus);
> > > -int pci_reset_bus(struct pci_dev *dev);
> > > +int pci_reset_bus(struct pci_dev *dev, u32 reset_type);
> > >   void pci_reset_secondary_bus(struct pci_dev *dev);
> > >   void pcibios_reset_secondary_bus(struct pci_dev *dev);
> > >   void pci_update_resource(struct pci_dev *dev, int resno);
> > > -- 
> > > 2.18.0
> > > 
> > 
>
Sinan Kaya Sept. 25, 2018, 10:18 p.m. UTC | #5
On 9/25/2018 5:56 PM, Bjorn Helgaas wrote:
>> Use PCI_RESET_LINK when you need link to retrain.
> There are no callers using this.  Is this intended specifically for
> the case of "the hardware wasn't smart enough to train at the correct
> speed, so we fiddled things and want to retrain"?
> 

Yup, I'll go ahead and change the hfi1 driver to use PCI_RESET_LINK
as originally planned so that there is an actual user.

These constants are intended to be used by the user of pci_reset
APIs. I think it makes sense to keep them there as well. I see
your point that PCI_RESET_LINK was not used. We should also make the hfi1
follow the rules.

> Maybe it doesn't need to be exposed in include/linux/pci.h and could
> be defined internally in drivers/pci/pci.c if it's needed there?
> 

see above.

>> Use PCI_RESET_SLOT when you know that this system is hotplug capable
>> by calling probe functions.
> I raise my eyebrows at this because (a) a driver generally can't tell
> whether hotplug is supported and (b) even if the driver does know,
> what is the benefit to the driver to specify this?  What probe
> functions does this refer to?  If I'm a driver writer, I really can't
> tell what I'm supposed to do with this guidance.  If I'm supposed to
> call a probe function, what is it, when should I call it, and what
> should I do with the result?  Am I supposed to know whether hotplug is
> supported?  Why would I care?

That was the whole reason why I hid the secondary bus reset API from the
user and folded into pci_reset_bus() so that PCI core can deal with hotplug
internally and can go to hotplug reset or bus reset internally.

User just calls pci_reset_bus().

I fully agree with your assessment but there are also exceptions like VFIO
where the code finds out which particular devices are part of a slot hierarchy
and for each one it checks that VFIO ownership has been claimed.
(Alex, please correct me if I'm not getting this right. I just read
200 lines of code in VFIO)

		/* Can we do a slot or bus reset or neither? */
		if (!pci_probe_reset_slot(vdev->pdev->slot))
			slot = true;
		else if (pci_probe_reset_bus(vdev->pdev->bus))
			return -ENODEV;

		ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
						    vfio_pci_fill_devs,
						    &fill, slot);



> 
> I'm sure you have good answers for all these questions; I just don't
> know what they are:)
> 
>> Use PCI_RESET_BUS when you know that this system is not hotplug capable
>> and this endpoint will never be used in such a system.
> How can a driver know this?  And what's the benefit of being specific?

There is really no benefit but there are drivers making assumptions about
the type of platform they want to run like supporting single segment only
etc.

PCI_RESET_BUS gives you direct access to secondary bus reset. If you are
calling this directly, you are responsible for saving and restoring state
like the hfi1 driver and need to ensure that this card will never work
on a hotplug capable system. If not, you are ...ed.

That's why, I'm suggesting that most users will use PCI_RESET_LINK so
that code works on all platforms.

> 
>> I can capture this into the commit message.
> I think it needs to be more accessible, e.g., comments near the constants
> and/or the function declaration.  We shouldn't expect users of the
> interface to dig through the changelogs for it.
> 

I can work on this once we agree if this is the way to go. I was responding
to Alex's request to have a contact between the PCI core and the drivers
because there are some driver that are more intelligent about the PCI tree
than a simple endpoint driver.
diff mbox series

Patch

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b4f14419bd51..f11d29f32119 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5232,13 +5232,25 @@  static int __pci_reset_bus(struct pci_bus *bus)
 /**
  * pci_reset_bus - Try to reset a PCI bus
  * @pdev: top level PCI device to reset via slot/bus
+ * @reset_type: resets to try
  *
  * Same as above except return -EAGAIN if the bus cannot be locked
  */
-int pci_reset_bus(struct pci_dev *pdev)
+int pci_reset_bus(struct pci_dev *pdev, u32 reset_type)
 {
-	return (!pci_probe_reset_slot(pdev->slot)) ?
-	    __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
+	if (reset_type & PCI_RESET_LINK) {
+		return (!pci_probe_reset_slot(pdev->slot)) ?
+				__pci_reset_slot(pdev->slot) :
+				__pci_reset_bus(pdev->bus);
+	}
+
+	if (reset_type & PCI_RESET_BUS)
+		return __pci_reset_bus(pdev->bus);
+
+	if (reset_type & PCI_RESET_SLOT)
+		return __pci_reset_slot(pdev->slot);
+
+	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(pci_reset_bus);
 
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index fe7ada997c51..0e80c72b1eaa 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -1015,7 +1015,8 @@  static long vfio_pci_ioctl(void *device_data,
 						    &info, slot);
 		if (!ret)
 			/* User has access, do the reset */
-			ret = pci_reset_bus(vdev->pdev);
+			ret = pci_reset_bus(vdev->pdev,
+				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
 
 hot_reset_release:
 		for (i--; i >= 0; i--)
@@ -1390,7 +1391,8 @@  static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
 	}
 
 	if (needs_reset)
-		ret = pci_reset_bus(vdev->pdev);
+		ret = pci_reset_bus(vdev->pdev,
+				slot ? PCI_RESET_SLOT :	PCI_RESET_BUS);
 
 put_devs:
 	for (i = 0; i < devs.cur_index; i++) {
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4fdddcb85066..85f48e156753 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1128,7 +1128,7 @@  int pci_reset_function_locked(struct pci_dev *dev, u32 reset_type);
 int pci_try_reset_function(struct pci_dev *dev, u32 reset_type);
 int pci_probe_reset_slot(struct pci_slot *slot);
 int pci_probe_reset_bus(struct pci_bus *bus);
-int pci_reset_bus(struct pci_dev *dev);
+int pci_reset_bus(struct pci_dev *dev, u32 reset_type);
 void pci_reset_secondary_bus(struct pci_dev *dev);
 void pcibios_reset_secondary_bus(struct pci_dev *dev);
 void pci_update_resource(struct pci_dev *dev, int resno);