linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bjorn Helgaas <helgaas@kernel.org>
To: Yicong Yang <yangyicong@hisilicon.com>
Cc: linux-pci@vger.kernel.org, f.fangjian@huawei.com
Subject: Re: [PATCH] PCI: Improve link speed presentation process
Date: Tue, 14 Jan 2020 16:49:09 -0600	[thread overview]
Message-ID: <20200114224909.GA19633@google.com> (raw)
In-Reply-To: <1578989494-20583-1-git-send-email-yangyicong@hisilicon.com>

On Tue, Jan 14, 2020 at 04:11:34PM +0800, Yicong Yang wrote:
> Currently We use switch-case statements to acquire the speed
> string according to the pci bus speed in current_link_speed_show()
> and pcie_get_speed_cap(). It leads to redundant and when new
> standard comes, we have to add cases in the related functions,
> which is easy to omit at somewhere.
> 
> Abstract the judge statements out. Use macros and pci speed
> arrays instead. Then only the macros and arrays need to be
> extended when next generation comes.
> 
> Link: https://lore.kernel.org/linux-pci/20200113211728.GA113776@google.com/
> Suggested-by: Bjorn Helgaas <helgaas@kernel.org>
> Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
> ---
> Previously we get speed from sysfs likes "16.0 GT/s", etc. In this PATCH,
> we get the speed string from pci_bus_speed_strings[], and it'll look like
> "16.0 GT/s PCIe", etc. It makes no more affects and maybe make the information
> more detailed.

I like the direction this is heading a lot.

It'll be a little redundant in __pcie_print_link_status(), e.g.,

  - nvme 0000:01:00.0: 16.000 Gb/s available PCIe bandwidth, limited by 5 GT/s x4 link at 0000:00:01.1 (capable of 31.504 Gb/s with 8 GT/s x4 link)
  + nvme 0000:01:00.0: 16.000 Gb/s available PCIe bandwidth, limited by 5 GT/s PCIe x4 link at 0000:00:01.1 (capable of 31.504 Gb/s with 8 GT/s PCIe x4 link)

Prior to this patch, the strings containing "PCIe" are only in
bus_speed_read(), i.e., only for PCI slot "cur_bus_speed" and
"max_bus_speed" sysfs files for slots.  I'm not sure "PCIe" really
adds anything there -- I would think the question for a PCIe slot is
"how fast is it *and* how wide is it?"  That's what people need to
know when selecting a slot to plug a card into.

But I think we can defer the sysfs file question and keep all the
user-visible strings the same by removing "PCIe" from the
pci_bus_speed_strings[] and sprintf-ing it back in (when appropriate)
in bus_speed_read().

This patch both (a) removes a lot of redundancy and (b) adds 32 GT/s
in a couple places.  Those should be split: one patch should add 32
GT/s (this is probably just the first version you posted), and a
second patch should combine the strings.

That way the 32 GT/s change isn't buried in a big patch, and if the
string change ("16.0 GT/s" -> "16.0 GT/s PCIe") is in a patch by
itself that we can easily revert if it turns out to be a problem.

Side note: can you add a comment at the pcie_link_speed[] definition
about the index being the Current Link Speed field?  Maybe also a note
at the pcix_bus_speed[] definition (the index is the "Secondary Bus
Mode and Frequency" from the PCI-X Secondary Status Register in the
PCI-X Bridge Capability.

>  drivers/pci/pci-sysfs.c | 24 +++---------------------
>  drivers/pci/pci.c       | 12 +-----------
>  drivers/pci/pci.h       | 20 ++++++++++++++------
>  drivers/pci/slot.c      |  2 +-
>  4 files changed, 19 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index 7934129..8bcb136 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -175,33 +175,15 @@ static ssize_t current_link_speed_show(struct device *dev,
>  	struct pci_dev *pci_dev = to_pci_dev(dev);
>  	u16 linkstat;
>  	int err;
> -	const char *speed;
> +	enum pci_bus_speed link_speed;
>  
>  	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
>  	if (err)
>  		return -EINVAL;
>  
> -	switch (linkstat & PCI_EXP_LNKSTA_CLS) {
> -	case PCI_EXP_LNKSTA_CLS_32_0GB:
> -		speed = "32 GT/s";
> -		break;
> -	case PCI_EXP_LNKSTA_CLS_16_0GB:
> -		speed = "16 GT/s";
> -		break;
> -	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";
> -	}
> +	link_speed = pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
>  
> -	return sprintf(buf, "%s\n", speed);
> +	return sprintf(buf, "%s\n", PCIE_SPEED2STR(link_speed));
>  }
>  static DEVICE_ATTR_RO(current_link_speed);
>  
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index a97e257..ea72e6d8 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5658,17 +5658,7 @@ enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev)
>  	 */
>  	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
>  	if (lnkcap2) { /* PCIe r3.0-compliant */
> -		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_32_0GB)
> -			return PCIE_SPEED_32_0GT;
> -		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
> -			return PCIE_SPEED_16_0GT;
> -		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
> -			return PCIE_SPEED_8_0GT;
> -		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
> -			return PCIE_SPEED_5_0GT;
> -		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
> -			return PCIE_SPEED_2_5GT;
> -		return PCI_SPEED_UNKNOWN;
> +		return PCIE_LNKCAP2_SLS2SPEED(lnkcap2);
>  	}

Remove the braces since there's only one line left.

>  	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 3f6947e..90cacf6 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -9,6 +9,7 @@
>  #define PCI_VSEC_ID_INTEL_TBT	0x1234	/* Thunderbolt */
>  
>  extern const unsigned char pcie_link_speed[];
> +extern const char *pci_bus_speed_strings[];
>  extern bool pci_early_dump;
>  
>  bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
> @@ -286,17 +287,24 @@ void pci_disable_bridge_window(struct pci_dev *dev);
>  struct pci_bus *pci_bus_get(struct pci_bus *bus);
>  void pci_bus_put(struct pci_bus *bus);
>  
> +/* PCIe link information from Link Capabilities 2 */
> +#define PCIE_LNKCAP2_SLS2SPEED(mask) \
> +	((mask) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \
> +	 (mask) & PCI_EXP_LNKCAP2_SLS_16_0GB ? PCIE_SPEED_16_0GT : \
> +	 (mask) & PCI_EXP_LNKCAP2_SLS_8_0GB ? PCIE_SPEED_8_0GT : \
> +	 (mask) & PCI_EXP_LNKCAP2_SLS_5_0GB ? PCIE_SPEED_5_0GT : \
> +	 (mask) & PCI_EXP_LNKCAP2_SLS_2_5GB ? PCIE_SPEED_2_5GT : \
> +	 PCI_SPEED_UNKNOWN)

The argument here is not really a "mask"; it's the entire LNKCAP2
value.  I'd call it "lnkcap2" so it's a hint about what callers should
pass.

>  /* PCIe link information */
>  #define PCIE_SPEED2STR(speed) \
> -	((speed) == PCIE_SPEED_16_0GT ? "16 GT/s" : \
> -	 (speed) == PCIE_SPEED_8_0GT ? "8 GT/s" : \
> -	 (speed) == PCIE_SPEED_5_0GT ? "5 GT/s" : \
> -	 (speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
> -	 "Unknown speed")
> +	((speed) == PCI_SPEED_UNKNOWN ? "Unknown speed" : \
> +	 pci_bus_speed_strings[speed])

I think this will be a problem because pci_bus_speed_strings[] is
defined in slot.c, which is only built when CONFIG_SYSFS=y.  But
PCIE_SPEED2STR() is used by __pcie_print_link_status(), which can be
built without CONFIG_SYSFS=y.  Maybe a preliminary patch could move
pci_bus_speed_strings[] to probe.c, near the related pcix_bus_speed[]
and pcie_link_speed[]?

Also, bus_speed_read() contains what is basically an open-coded
PCIE_SPEED2STR(), except that bus_speed_read() does a bounds check.
I think we should maybe add that bounds check to PCIE_SPEED2STR() and
use it in bus_speed_read().

So I'm envisioning several patches here:

  - Add 32 GT/s to PCIE_SPEED2STR() and PCIE_SPEED2MBS_ENC() (your
    original patch).

  - Move pci_bus_speed_strings[] to probe.c.  No change at all except
    to become non-static.

  - Change PCIE_SPEED2STR() to use pci_bus_speed_strings[] and add
    bounds checking, remove "PCIe" from pci_bus_speed_strings[], use
    PCI_SPEED2STR() and add "PCIe" back in bus_speed_read().

  - Rename PCIE_SPEED2STR() to PCI_SPEED2STR().  Could be squashed
    with above, but keep it separate to start; I can trivially squash
    if it makes sense.

  - Add PCIE_LNKCAP2_SLS2SPEED() and use it in pcie_get_speed_cap().
    Separate patch because it's not related to the strings.

>  /* PCIe speed to Mb/s reduced by encoding overhead */
>  #define PCIE_SPEED2MBS_ENC(speed) \
> -	((speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
> +	((speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \
> +	 (speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
>  	 (speed) == PCIE_SPEED_8_0GT  ?  8000*128/130 : \
>  	 (speed) == PCIE_SPEED_5_0GT  ?  5000*8/10 : \
>  	 (speed) == PCIE_SPEED_2_5GT  ?  2500*8/10 : \
> diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
> index ae4aa0e..08a59ed 100644
> --- a/drivers/pci/slot.c
> +++ b/drivers/pci/slot.c
> @@ -50,7 +50,7 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf)
>  }
>  
>  /* these strings match up with the values in pci_bus_speed */
> -static const char *pci_bus_speed_strings[] = {
> +const char *pci_bus_speed_strings[] = {
>  	"33 MHz PCI",		/* 0x00 */
>  	"66 MHz PCI",		/* 0x01 */
>  	"66 MHz PCI-X",		/* 0x02 */
> -- 
> 2.8.1
> 

  reply	other threads:[~2020-01-14 22:49 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-14  8:11 [PATCH] PCI: Improve link speed presentation process Yicong Yang
2020-01-14 22:49 ` Bjorn Helgaas [this message]
2020-01-16  7:45 ` kbuild test robot
2020-01-16  9:42   ` Yicong Yang

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=20200114224909.GA19633@google.com \
    --to=helgaas@kernel.org \
    --cc=f.fangjian@huawei.com \
    --cc=linux-pci@vger.kernel.org \
    --cc=yangyicong@hisilicon.com \
    /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).