[libvirt] [PATCH 4/8] Allow PM reset on multi-function PCI devices

Daniel P. Berrange berrange at redhat.com
Thu Aug 13 18:41:47 UTC 2009


On Thu, Aug 13, 2009 at 05:44:33PM +0100, Mark McLoughlin wrote:
> It turns out that a PCI Power Management reset only affects individual
> functions, and not the whole device.
> 
> The PCI Power Management spec talks about resetting the 'device' rather
> than the 'function', but Intel's Dexuan Cui informs me that it is
> actually a per-function reset.
> 
> Also, Yu Zhao has added pci_pm_reset() to the kernel, and it doesn't
> reject multi-function devices, so it must be true! :-)
> 
> (A side issue is that we could defer the PM reset to the kernel if we
> could detect that the kernel has PM reset support, but barring version
> number checks we don't have a way to detect that support)
> 
> * src/pci.c: remove the pciDeviceContainsOtherFunctions() check from
>   pciTryPowerManagementReset() and prefer PM reset over bus reset
>   where both are available
> 
> Cc: Cui, Dexuan <dexuan.cui at intel.com>
> Cc: Yu Zhao <yu.zhao at intel.com>
> ---
>  src/pci.c |   48 +++++++++---------------------------------------
>  1 files changed, 9 insertions(+), 39 deletions(-)
> 
> diff --git a/src/pci.c b/src/pci.c
> index 2dc2e1c..11b3e8b 100644
> --- a/src/pci.c
> +++ b/src/pci.c
> @@ -402,29 +402,6 @@ pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
>      return 1;
>  }
>  
> -/* Any other functions on this device ? */
> -static int
> -pciSharesDevice(pciDevice *a, pciDevice *b)
> -{
> -    return
> -        a->domain == b->domain &&
> -        a->bus == b->bus &&
> -        a->slot == b->slot &&
> -        a->function != b->function;
> -}
> -
> -static int
> -pciDeviceContainsOtherFunctions(virConnectPtr conn, pciDevice *dev)
> -{
> -    pciDevice *matched = NULL;
> -    if (pciIterDevices(conn, pciSharesDevice, dev, &matched) < 0)
> -        return 1;
> -    if (!matched)
> -        return 0;
> -    pciFreeDevice(conn, matched);
> -    return 1;
> -}
> -
>  /* Is @a the parent of @b ? */
>  static int
>  pciIsParent(pciDevice *a, pciDevice *b)
> @@ -529,7 +506,7 @@ out:
>   * above we require the device supports a full internal reset.
>   */
>  static int
> -pciTryPowerManagementReset(virConnectPtr conn, pciDevice *dev)
> +pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
>  {
>      uint8_t config_space[PCI_CONF_LEN];
>      uint32_t ctl;
> @@ -537,16 +514,6 @@ pciTryPowerManagementReset(virConnectPtr conn, pciDevice *dev)
>      if (!dev->pci_pm_cap_pos)
>          return -1;
>  
> -    /* For now, we just refuse to do a power management reset
> -     * if there are other functions on this device.
> -     * In future, we could allow it so long as those functions
> -     * are not in use by the host or other guests.
> -     */
> -    if (pciDeviceContainsOtherFunctions(conn, dev)) {
> -        VIR_WARN("%s contains other functions, not resetting", dev->name);
> -        return -1;
> -    }
> -
>      /* Save and restore the device's config space. */
>      if (pciRead(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
>          VIR_WARN("Failed to save PCI config space for %s", dev->name);
> @@ -604,14 +571,17 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
>      if (dev->has_flr)
>          return 0;
>  
> +    /* If the device supports PCI power management reset,
> +     * that's the next best thing because it only resets
> +     * the function, not the whole device.
> +     */
> +    if (dev->has_pm_reset)
> +        ret = pciTryPowerManagementReset(conn, dev);
> +
>      /* Bus reset is not an option with the root bus */
> -    if (dev->bus != 0)
> +    if (ret < 0 && dev->bus != 0)
>          ret = pciTrySecondaryBusReset(conn, dev);
>  
> -    /* Next best option is a PCI power management reset */
> -    if (ret < 0 && dev->has_pm_reset)
> -        ret = pciTryPowerManagementReset(conn, dev);
> -
>      if (ret < 0)
>          pciReportError(conn, VIR_ERR_NO_SUPPORT,
>                         _("No PCI reset capability available for %s"),

ACK


Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list