From: Brian Norris <briannorris@chromium.org>
To: Shawn Lin <shawn.lin@rock-chips.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>,
devicetree@vger.kernel.org, Heiko Stuebner <heiko@sntech.de>,
Arnd Bergmann <arnd@arndb.de>,
Marc Zyngier <marc.zyngier@arm.com>,
linux-pci@vger.kernel.org, Wenrui Li <wenrui.li@rock-chips.com>,
linux-kernel@vger.kernel.org,
Doug Anderson <dianders@chromium.org>,
linux-rockchip@lists.infradead.org,
Rob Herring <robh+dt@kernel.org>
Subject: Re: [PATCH v3 2/2] PCI: Rockchip: Add Rockchip PCIe controller support
Date: Wed, 22 Jun 2016 18:35:27 -0700 [thread overview]
Message-ID: <20160623013527.GA46876@google.com> (raw)
In-Reply-To: <dcdc3402-22d9-473a-d9ae-b9bd994c24a6@rock-chips.com>
Hi,
On Thu, Jun 23, 2016 at 09:09:46AM +0800, Shawn Lin wrote:
> 在 2016/6/23 8:29, Brian Norris 写道:
> >On Thu, Jun 16, 2016 at 09:50:35AM +0800, Shawn Lin wrote:
[...]
> >>+ /* 500ms timeout value should be enough for gen1/2 taining */
> >>+ timeout = jiffies + msecs_to_jiffies(500);
> >>+
> >>+ err = -ETIMEDOUT;
> >>+ while (time_before(jiffies, timeout)) {
> >>+ status = pcie_read(port, PCIE_CLIENT_BASIC_STATUS1);
> >>+ if (((status >> PCIE_CLIENT_LINK_STATUS_SHIFT) &
> >>+ PCIE_CLIENT_LINK_STATUS_MASK) ==
> >>+ PCIE_CLIENT_LINK_STATUS_UP) {
> >>+ dev_dbg(port->dev, "pcie link training gen1 pass!\n");
> >>+ err = 0;
> >>+ break;
> >>+ }
> >>+ msleep(20);
> >>+ }
> >
> >Technically, the above timeout loop is not quite correct. Possible error
> >case: we can fail with a timeout after 500 ms if the training completes
> >between the 480-500 ms time window. This can happen because you're
> >doing:
> >
> >(1) read register: if complete, then terminate successfully
> >(2) delay
> >(3) check for timeout: if time is up, return error
> >
> >You actually need:
> >
> >(1) read register: if complete, then terminate successfully
> >(2) delay
> >(3) check for timeout: if time is up, repeat (1), and then report error
> >
> >You can examine the logic for readx_poll_timeout() in
> >include/linux/iopoll.h to see an example of a proper timeout loop. You
> >could even try to use one of the helpers there, except that your
> >pcie_read() takes 2 args.
>
> I see, thanks.
>
> >
> >>+ if (err) {
> >>+ dev_err(port->dev, "pcie link training gen1 timeout!\n");
> >>+ return err;
> >>+ }
> >>+
> >>+ /*
> >>+ * Enable retrain for gen2. This should be configured only after
> >>+ * gen1 finished.
> >>+ */
> >>+ status = pcie_read(port,
> >>+ PCIR_RC_CONFIG_LCS + PCIE_RC_CONFIG_BASE);
> >>+ status |= PCIE_CORE_LCSR_RETAIN_LINK;
> >>+ pcie_write(port, status,
> >>+ PCIR_RC_CONFIG_LCS + PCIE_RC_CONFIG_BASE);
> >
> >I'm not really an expert on this, but how are you actually "retraining
> >for gen2"? Is that just the behavior of the core, that it retries at the
> >higher rate on the 2nd training attempt? I'm just confused, since you
> >set PCIE_CLIENT_GEN_SEL_2 above, so you've already allowed either gen1
> >or gen2 negotiation AFAICT, and so seemingly you might already have
> >negotiated at gen2.
>
>
> Not really. I allow the core to enable gen2, but it needs a extra
> setting of retrain after finishing gen1. It's not so strange as it
> depends on the vendor's design. So I have to say it fits the
> designer's expectation.
OK.
> >>+ err = -ETIMEDOUT;
> >>+
> >>+ while (time_before(jiffies, timeout)) {
> >
> >You never reset 'timeout' when starting this loop. So you only have a
> >cumulative 500 ms to do both the gen1 and gen2 loops. Is that
> >intentional? (I feel like this comment was made on an earlier revision
> >of this driver, though I haven't read everything thoroughly.)
>
> yes, I don't have any docs to let me know how long should I wait for
> gen1/2 to be finished. Maybe someday it will be augmented to a larger
> value if finding a device actually need a longer time. But the only
> thing I can say is that it's from my test for many pcie devices
> currently.
>
>
> Do you agree?
I'm not suggesting increasing the timeout, exactly; I'm suggesting that
you should set some minimum timeout for each training loop, instead of
reusing the same deadline. i.e., something like this before the second
loop:
/* Reset the deadline for gen2 */
timeout = jiffies + msecs_to_jiffies(500);
As it stands, if the first loop takes 490 ms, that leaves you only 10 ms
for the second loop. And I think it'd be confusing if we ever see the
first loop take a "long" time, and then we time out on the second --
we'd be blaming the gen2 training for gen1's slowness.
> >>+ status = pcie_read(port, PCIE_CORE_CTRL_MGMT_BASE);
> >>+ if (((status >> PCIE_CORE_PL_CONF_SPEED_SHIFT) &
> >>+ PCIE_CORE_PL_CONF_SPEED_MASK) ==
> >>+ PCIE_CORE_PL_CONF_SPEED_50G) {
> >>+ dev_dbg(port->dev, "pcie link training gen2 pass!\n");
> >>+ err = 0;
> >>+ break;
> >>+ }
> >>+ msleep(20);
> >>+ }
> >
> >Similar problem with your timeout loop, as mentioned above. Although I
> >confused about what you do in the error case here...
> >
> >>+ if (err)
> >>+ dev_dbg(port->dev, "pcie link training gen2 timeout, force to gen1!\n");
> >
> >... how are you forcing gen1? I don't see any code that indicates this.
> >Should you at least be checking that there aren't some kind of training
> >errors, and that we settled back on gen1/2.5G?
>
> yes, when failing gen2, my pcie controller will fallback to gen1
> automatically.
OK. Well maybe the text should say something like "falling back" instead
of "force"?
> if we pass the gen1 then fail to train gen2, a dbg msg here is enough
> here to let we know that we should check the HW signal. Of course we
> should make sure that this device supports gen2.
OK.
[...]
Brian
next prev parent reply other threads:[~2016-06-23 1:35 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-16 1:50 [PATCH v3 2/2] PCI: Rockchip: Add Rockchip PCIe controller support Shawn Lin
2016-06-16 13:08 ` kbuild test robot
2016-06-16 13:08 ` kbuild test robot
2016-06-23 0:29 ` Brian Norris
2016-06-23 1:09 ` Shawn Lin
2016-06-23 1:35 ` Brian Norris [this message]
2016-06-23 2:15 ` Shawn Lin
2016-06-23 2:15 ` Shawn Lin
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=20160623013527.GA46876@google.com \
--to=briannorris@chromium.org \
--cc=arnd@arndb.de \
--cc=bhelgaas@google.com \
--cc=devicetree@vger.kernel.org \
--cc=dianders@chromium.org \
--cc=heiko@sntech.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=marc.zyngier@arm.com \
--cc=robh+dt@kernel.org \
--cc=shawn.lin@rock-chips.com \
--cc=wenrui.li@rock-chips.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.