Re: [PATCH v2] PCI: correctly check availability of PCIe Link Cap/Status/Control registers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 28, 2013 at 11:23 AM, Jiang Liu <liuj97@xxxxxxxxx> wrote:
> From: Jiang Liu <jiang.liu@xxxxxxxxxx>
>
> According to PCIe Base Specification 3.0, devices are guarenteed to
> return zero for unimplemented V2 PCI Express Capability registers.
> But there's no such guarantee for unimplemented V1 PCI Express
> Capability registers, so we need to explicitly check availability of
> V1 PCI Express Capability registers and return zero for unimplemented
> registers.
>
> Changeset 1b6b8ce2ac372e "PCI: only save/restore existent registers in
> the PCIe capability" introduces pcie_cap_has_lnkctl(), which assumes that
> PCIe root port, endpoint and legacy endpoint with 1.0 PCIe Capability
> implement Link Cap/Status/Control registers.
>
> On the other hand, section 7.8 of PCIe Base Spec V1.1 and V3.0 states that
> "The Link Capabilities, Link Status, and Link Control registers are
> required for all Root Ports, Switch Ports, Bridges, and Endpoints that
> are not Root Complex Integrated Endpoints."
> That means Link Capability/Status/Control registers are also available
> for PCIe Upstream Port, Downstream Port, PCIe-to-PCI bridge and PCI-to-PCIe
> bridge. So change pcie_cap_has_lnkctl() to follow PCIe specifications.
>
> Also refine pcie_cap_has_sltctl() and pcie_cap_has_rtctl() for readability.
>
> Signed-off-by: Jiang Liu <jiang.liu@xxxxxxxxxx>
> Reported-by: Yuval Mintz <yuvalmin@xxxxxxxxxxxx>
> ---
>  drivers/pci/access.c | 39 ++++++++++++++++++++++++++++-----------
>  1 file changed, 28 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/pci/access.c b/drivers/pci/access.c
> index 1cc2366..b9af3d1 100644
> --- a/drivers/pci/access.c
> +++ b/drivers/pci/access.c
> @@ -470,6 +470,13 @@ void pci_cfg_access_unlock(struct pci_dev *dev)
>  }
>  EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
>
> +/*
> + * According to PCIe base spec 3.0, devices are guarenteed to return zero for
> + * unimplemented V2 PCI Express Capability registers. But there's no such
> + * guarantee for unimplemented V1 PCI Express Capability registers, so
> + * explicitly check availability of V1 PCI Express Capability registers
> + * and return zero for unimplemented registers.
> + */
>  static inline int pcie_cap_version(const struct pci_dev *dev)
>  {
>         return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
> @@ -484,29 +491,39 @@ static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
>  {
>         int type = pci_pcie_type(dev);
>
> -       return pcie_cap_version(dev) > 1 ||
> -              type == PCI_EXP_TYPE_ROOT_PORT ||
> -              type == PCI_EXP_TYPE_ENDPOINT ||
> -              type == PCI_EXP_TYPE_LEG_END;
> +       if (pcie_cap_version(dev) == 1)
> +               return  type == PCI_EXP_TYPE_ENDPOINT ||
> +                       type == PCI_EXP_TYPE_LEG_END ||
> +                       type == PCI_EXP_TYPE_ROOT_PORT ||
> +                       type == PCI_EXP_TYPE_UPSTREAM ||
> +                       type == PCI_EXP_TYPE_DOWNSTREAM ||
> +                       type == PCI_EXP_TYPE_PCI_BRIDGE ||
> +                       type == PCI_EXP_TYPE_PCIE_BRIDGE;

I split this out into a separate patch because it's a bug fix, and I
don't want to clutter the bugfix with the readability changes.

And I think I changed my mind about the capability version checks.
You previously suggested removing the check, at least for
pcie_cap_has_lnkctl().  I think that's a good idea for all the
pcie_cap_has_*() functions because it makes the code cleaner and
easier to read.

I'll post the tweaks I have in mind as a separate series; see what you think.

Bjorn

> +
> +       return true;
>  }
>
>  static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
>  {
>         int type = pci_pcie_type(dev);
>
> -       return pcie_cap_version(dev) > 1 ||
> -              type == PCI_EXP_TYPE_ROOT_PORT ||
> -              (type == PCI_EXP_TYPE_DOWNSTREAM &&
> -               pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT);
> +       if (pcie_cap_version(dev) == 1)
> +               return type == PCI_EXP_TYPE_ROOT_PORT ||
> +                      (type == PCI_EXP_TYPE_DOWNSTREAM &&
> +                       pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT);
> +
> +       return true;
>  }
>
>  static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
>  {
>         int type = pci_pcie_type(dev);
>
> -       return pcie_cap_version(dev) > 1 ||
> -              type == PCI_EXP_TYPE_ROOT_PORT ||
> -              type == PCI_EXP_TYPE_RC_EC;
> +       if (pcie_cap_version(dev) == 1)
> +               return type == PCI_EXP_TYPE_ROOT_PORT ||
> +                      type == PCI_EXP_TYPE_RC_EC;
> +
> +       return true;
>  }
>
>  static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
> --
> 1.8.1.2
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux