Re: [RESEND PATCH v3] pci-sysfs: Make PCI bridge attribute visible in sysfs

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

 



On Thu, Jun 01, 2017 at 05:43:06PM +0800, Wong Vee Khee wrote:
> From: vwong <vee.khee.wong@xxxxxx>
> 
>  In this commit, we are exposing PCIe bridges attributes
>  such as secondary bus number, subordinate bus number,
>  max link speed and link width, current link speed and
>  link width to sysfs located in /sys/bus/pci/devices/...
> 
>  Part of the reasons we are doing this rather than getting
>  these information through parsing lspci is due to the fact
>  that accessing PCIe link information via lspci require root
>  privilege.
> 
>  This changes also allow clients to get PCIe bridges information
>  easily because lspci list out all PCIe devices.
> 
> Signed-off-by: Wong Vee Khee <vee.khee.wong@xxxxxx>
> Signed-off-by: Hui Chun Ong <hui.chun.ong@xxxxxx>

Applied to pci/enumeration for v4.13, thanks!

> ---
> v3: Update commit message to be more explicit
> v2: Remove error checking on LNKCAP
>     Add define of PCI_LNKCAP_SLS_8_0GB
> ---
>  drivers/pci/pci-sysfs.c       | 197 +++++++++++++++++++++++++++++++++++++++++-
>  include/uapi/linux/pci_regs.h |   1 +
>  2 files changed, 194 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index 31e9961..a2ada91 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -154,6 +154,127 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
>  }
>  static DEVICE_ATTR_RO(resource);
>  
> +static ssize_t max_link_speed_show(struct device *dev,
> +				   struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pci_dev = to_pci_dev(dev);
> +	u32 linkcap;
> +	int err;
> +	const char *speed;
> +
> +	err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap);
> +
> +	if (!err) {
> +		switch (linkcap & PCI_EXP_LNKCAP_SLS) {
> +		case PCI_EXP_LNKCAP_SLS_8_0GB:
> +			speed = "8 GT/s";
> +			break;
> +		case PCI_EXP_LNKCAP_SLS_5_0GB:
> +			speed = "5 GT/s";
> +			break;
> +		case PCI_EXP_LNKCAP_SLS_2_5GB:
> +			speed = "2.5 GT/s";
> +			break;
> +		default:
> +			speed = "Unknown speed";
> +		}
> +
> +		return sprintf(buf, "%s\n", speed);
> +	}
> +
> +	return -EINVAL;
> +}
> +static DEVICE_ATTR_RO(max_link_speed);
> +
> +static ssize_t max_link_width_show(struct device *dev,
> +				   struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pci_dev = to_pci_dev(dev);
> +	u32 linkcap;
> +	int err;
> +
> +	err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap);
> +
> +	return err ? -EINVAL : sprintf(
> +		buf, "%u\n", (linkcap & PCI_EXP_LNKCAP_MLW) >> 4);
> +}
> +static DEVICE_ATTR_RO(max_link_width);
> +
> +static ssize_t current_link_speed_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pci_dev = to_pci_dev(dev);
> +	u16 linkstat;
> +	int err;
> +	const char *speed;
> +
> +	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
> +
> +	if (!err) {
> +		switch (linkstat & PCI_EXP_LNKSTA_CLS) {
> +		case PCI_EXP_LNKSTA_CLS_8_0GB:
> +			speed = "8 GT/s";
> +			break;
> +		case PCI_EXP_LNKSTA_CLS_5_0GB:
> +			speed = "5 GT/s";
> +			break;
> +		case PCI_EXP_LNKSTA_CLS_2_5GB:
> +			speed = "2.5 GT/s";
> +			break;
> +		default:
> +			speed = "Unknown speed";
> +		}
> +
> +		return sprintf(buf, "%s\n", speed);
> +	}
> +
> +	return -EINVAL;
> +}
> +static DEVICE_ATTR_RO(current_link_speed);
> +
> +static ssize_t current_link_width_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pci_dev = to_pci_dev(dev);
> +	u16 linkstat;
> +	int err;
> +
> +	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
> +
> +	return err ? -EINVAL : sprintf(
> +		buf, "%u\n",
> +		(linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT);
> +}
> +static DEVICE_ATTR_RO(current_link_width);
> +
> +static ssize_t secondary_bus_number_show(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	struct pci_dev *pci_dev = to_pci_dev(dev);
> +	u8 sec_bus;
> +	int err;
> +
> +	err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
> +
> +	return err ? -EINVAL : sprintf(buf, "%u\n", sec_bus);
> +}
> +static DEVICE_ATTR_RO(secondary_bus_number);
> +
> +static ssize_t subordinate_bus_number_show(struct device *dev,
> +					   struct device_attribute *attr,
> +					   char *buf)
> +{
> +	struct pci_dev *pci_dev = to_pci_dev(dev);
> +	u8 sub_bus;
> +	int err;
> +
> +	err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
> +
> +	return err ? -EINVAL : sprintf(buf, "%u\n", sub_bus);
> +}
> +static DEVICE_ATTR_RO(subordinate_bus_number);
> +
>  static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
>  			     char *buf)
>  {
> @@ -629,12 +750,17 @@ static struct attribute *pci_dev_attrs[] = {
>  	NULL,
>  };
>  
> -static const struct attribute_group pci_dev_group = {
> -	.attrs = pci_dev_attrs,
> +static struct attribute *pci_bridge_attrs[] = {
> +	&dev_attr_subordinate_bus_number.attr,
> +	&dev_attr_secondary_bus_number.attr,
> +	NULL,
>  };
>  
> -const struct attribute_group *pci_dev_groups[] = {
> -	&pci_dev_group,
> +static struct attribute *pcie_dev_attrs[] = {
> +	&dev_attr_current_link_speed.attr,
> +	&dev_attr_current_link_width.attr,
> +	&dev_attr_max_link_width.attr,
> +	&dev_attr_max_link_speed.attr,
>  	NULL,
>  };
>  
> @@ -1557,6 +1683,57 @@ static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj,
>  	return a->mode;
>  }
>  
> +static umode_t pci_bridge_attrs_are_visible(struct kobject *kobj,
> +					    struct attribute *a, int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +
> +	if (pci_is_bridge(pdev))
> +		return a->mode;
> +
> +	return 0;
> +}
> +
> +static umode_t pcie_dev_attrs_are_visible(struct kobject *kobj,
> +					  struct attribute *a, int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +
> +	if (pci_is_pcie(pdev))
> +		return a->mode;
> +
> +	return 0;
> +}
> +
> +static const struct attribute_group pci_dev_group = {
> +	.attrs = pci_dev_attrs,
> +};
> +
> +const struct attribute_group *pci_dev_groups[] = {
> +	&pci_dev_group,
> +	NULL,
> +};
> +
> +static const struct attribute_group pci_bridge_group = {
> +	.attrs = pci_bridge_attrs,
> +};
> +
> +const struct attribute_group *pci_bridge_groups[] = {
> +	&pci_bridge_group,
> +	NULL,
> +};
> +
> +static const struct attribute_group pcie_dev_group = {
> +	.attrs = pcie_dev_attrs,
> +};
> +
> +const struct attribute_group *pcie_dev_groups[] = {
> +	&pcie_dev_group,
> +	NULL,
> +};
> +
>  static struct attribute_group pci_dev_hp_attr_group = {
>  	.attrs = pci_dev_hp_attrs,
>  	.is_visible = pci_dev_hp_attrs_are_visible,
> @@ -1592,12 +1769,24 @@ static struct attribute_group pci_dev_attr_group = {
>  	.is_visible = pci_dev_attrs_are_visible,
>  };
>  
> +static struct attribute_group pci_bridge_attr_group = {
> +	.attrs = pci_bridge_attrs,
> +	.is_visible = pci_bridge_attrs_are_visible,
> +};
> +
> +static struct attribute_group pcie_dev_attr_group = {
> +	.attrs = pcie_dev_attrs,
> +	.is_visible = pcie_dev_attrs_are_visible,
> +};
> +
>  static const struct attribute_group *pci_dev_attr_groups[] = {
>  	&pci_dev_attr_group,
>  	&pci_dev_hp_attr_group,
>  #ifdef CONFIG_PCI_IOV
>  	&sriov_dev_attr_group,
>  #endif
> +	&pci_bridge_attr_group,
> +	&pcie_dev_attr_group,
>  	NULL,
>  };
>  
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index d56bb00..c22d3eb 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -517,6 +517,7 @@
>  #define  PCI_EXP_LNKCAP_SLS	0x0000000f /* Supported Link Speeds */
>  #define  PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
>  #define  PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
> +#define  PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
>  #define  PCI_EXP_LNKCAP_MLW	0x000003f0 /* Maximum Link Width */
>  #define  PCI_EXP_LNKCAP_ASPMS	0x00000c00 /* ASPM Support */
>  #define  PCI_EXP_LNKCAP_L0SEL	0x00007000 /* L0s Exit Latency */
> -- 
> 2.7.4
> 



[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