From: Alex Williamson <alex.williamson@redhat.com>
To: Mark D Rustad <mark.d.rustad@intel.com>
Cc: bhelgaas@google.com, linux-pci@vger.kernel.org,
intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
Myron Stowe <myron.stowe@redhat.com>
Subject: Re: [PATCH V4 1/2] pci: Add dev_flags bit to access VPD through function 0
Date: Tue, 15 Sep 2015 12:19:12 -0600 [thread overview]
Message-ID: <1442341152.23936.122.camel@redhat.com> (raw)
In-Reply-To: <20150713184001.19985.64867.stgit@mdrustad-wks.jf.intel.com>
On Mon, 2015-07-13 at 11:40 -0700, Mark D Rustad wrote:
> From: Mark Rustad <mark.d.rustad@intel.com>
>
> Add a dev_flags bit, PCI_DEV_FLAGS_VPD_REF_F0, to access VPD through
> function 0 to provide VPD access on other functions. This is for
> hardware devices that provide copies of the same VPD capability
> registers in multiple functions. Because the kernel expects that
> each function has its own registers, both the locking and the state
> tracking are affected by VPD accesses to different functions.
>
> On such devices for example, if a VPD write is performed on function
> 0, *any* later attempt to read VPD from any other function of that
> device will hang. This has to do with how the kernel tracks the
> expected value of the F bit per function.
>
> Concurrent accesses to different functions of the same device can
> not only hang but also corrupt both read and write VPD data.
>
> When hangs occur, typically the error message:
>
> vpd r/w failed. This is likely a firmware bug on this device.
>
> will be seen.
>
> Never set this bit on function 0 or there will be an infinite recursion.
>
> Signed-off-by: Mark Rustad <mark.d.rustad@intel.com>
> ---
> Changes in V2:
> - Corrected spelling in log message
> - Added checks to see that the referenced function 0 is reasonable
> Changes in V3:
> - Don't leak a device reference
> - Check that function 0 has VPD
> - Make a helper for the function 0 checks
> - Do multifunction check in the quirk
> Changes in V4:
> - Provide a much more detailed explanation in the commit log
> ---
> drivers/pci/access.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++-
> include/linux/pci.h | 2 ++
> 2 files changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/access.c b/drivers/pci/access.c
> index d9b64a175990..b965c12168b7 100644
> --- a/drivers/pci/access.c
> +++ b/drivers/pci/access.c
> @@ -439,6 +439,56 @@ static const struct pci_vpd_ops pci_vpd_pci22_ops = {
> .release = pci_vpd_pci22_release,
> };
>
> +static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count,
> + void *arg)
> +{
> + struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_SLOT(dev->devfn));
> + ssize_t ret;
> +
> + if (!tdev)
> + return -ENODEV;
> +
> + ret = pci_read_vpd(tdev, pos, count, arg);
> + pci_dev_put(tdev);
> + return ret;
> +}
> +
> +static ssize_t pci_vpd_f0_write(struct pci_dev *dev, loff_t pos, size_t count,
> + const void *arg)
> +{
> + struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_SLOT(dev->devfn));
> + ssize_t ret;
> +
> + if (!tdev)
> + return -ENODEV;
> +
> + ret = pci_write_vpd(tdev, pos, count, arg);
> + pci_dev_put(tdev);
> + return ret;
> +}
> +
> +static const struct pci_vpd_ops pci_vpd_f0_ops = {
> + .read = pci_vpd_f0_read,
> + .write = pci_vpd_f0_write,
> + .release = pci_vpd_pci22_release,
> +};
> +
> +static int pci_vpd_f0_dev_check(struct pci_dev *dev)
> +{
> + struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_SLOT(dev->devfn));
> + int ret = 0;
> +
> + if (!tdev)
> + return -ENODEV;
> + if (!tdev->vpd || !tdev->multifunction ||
> + dev->class != tdev->class || dev->vendor != tdev->vendor ||
> + dev->device != tdev->device)
> + ret = -ENODEV;
> +
> + pci_dev_put(tdev);
> + return ret;
> +}
> +
> int pci_vpd_pci22_init(struct pci_dev *dev)
> {
> struct pci_vpd_pci22 *vpd;
> @@ -447,12 +497,21 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
> cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
> if (!cap)
> return -ENODEV;
> + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
> + int ret = pci_vpd_f0_dev_check(dev);
> +
> + if (ret)
> + return ret;
> + }
In addition to the (PCI_SLOT() != devfn) issue, I'm concerned about
topologies like we see on Skylake. IIRC, the integrated NIC appears at
something like 00:1f.6. I don't know if that specific NIC has VPD, nor
am I sure it really matter because another example or some future
version might. So we'll set the PCI_DEV_FLAGS_VPD_REF_F0 because we do
so for all (PCI_FUNC() != 0) Intel NICs, we'll call
pci_vpd_f0_dev_check(), which will error because function 0 has a
different class code and device ID, so we return error and if VPD exists
on the device, it's now inaccessible.
I thought there was talk about whitelisting anything on the root bus to
avoid strange root complex integrated devices (and perhaps avoid the
general case for assigned devices within a VM), but I don't see anything
like that here.
Perhaps instead of failing and hiding VPD we should fail, clear the
flag, and allow normal access. Thanks,
Alex
> vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC);
> if (!vpd)
> return -ENOMEM;
>
> vpd->base.len = PCI_VPD_PCI22_SIZE;
> - vpd->base.ops = &pci_vpd_pci22_ops;
> + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0)
> + vpd->base.ops = &pci_vpd_f0_ops;
> + else
> + vpd->base.ops = &pci_vpd_pci22_ops;
> mutex_init(&vpd->lock);
> vpd->cap = cap;
> vpd->busy = false;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 8a0321a8fb59..8edb125db13a 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -180,6 +180,8 @@ enum pci_dev_flags {
> PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6),
> /* Do not use PM reset even if device advertises NoSoftRst- */
> PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 7),
> + /* Get VPD from function 0 VPD */
> + PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 8),
> };
>
> enum pci_irq_reroute_variant {
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2015-09-15 18:19 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-13 18:39 [PATCH V4 0/2] pci: Provide a flag to access VPD through function 0 Mark D Rustad
2015-07-13 18:40 ` [PATCH V4 1/2] pci: Add dev_flags bit " Mark D Rustad
2015-09-15 18:19 ` Alex Williamson [this message]
2015-09-15 18:39 ` Rustad, Mark D
2015-09-15 19:04 ` Alex Williamson
2015-09-15 20:47 ` Rustad, Mark D
2015-09-15 21:17 ` Alex Williamson
2015-09-15 21:47 ` Rustad, Mark D
2015-07-13 18:40 ` [PATCH V4 2/2] pci: Add VPD quirk for Intel Ethernet devices Mark D Rustad
2015-07-21 18:24 ` [PATCH V4 0/2] pci: Provide a flag to access VPD through function 0 Bjorn Helgaas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1442341152.23936.122.camel@redhat.com \
--to=alex.williamson@redhat.com \
--cc=bhelgaas@google.com \
--cc=intel-wired-lan@lists.osuosl.org \
--cc=linux-pci@vger.kernel.org \
--cc=mark.d.rustad@intel.com \
--cc=myron.stowe@redhat.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).