Hi, On 14/06/19 6:08 PM, Marc Gonzalez wrote: > + Doug (who is familiar with usleep_range quirks) > > On 14/06/2019 11:50, Vivek Gautam wrote: > >> On 6/13/2019 5:02 PM, Marc Gonzalez wrote: >> >>> readl_poll_timeout() calls usleep_range() to sleep between reads. >>> usleep_range() doesn't work efficiently for tiny values. >>> >>> Raise the polling delay in qcom_qmp_phy_enable() to bring it in line >>> with the delay in qcom_qmp_phy_com_init(). >>> >>> Signed-off-by: Marc Gonzalez <marc.w.gonzalez@xxxxxxx> >>> --- >>> Vivek, do you remember why you didn't use the same delay value in >>> qcom_qmp_phy_enable) and qcom_qmp_phy_com_init() ? >> >> phy_qcom_init() thingy came from the PCIE phy driver from downstream >> msm-3.18 PCIE did something as below: > > FWIW and IMO, drivers/pci/host/pci-msm.c is a good example of how not to write > a device driver. It's huge (7000+ lines) because it handles multiple platforms > via ifdefs, and lumps everything together (phy, core IP, SoC specific glue) > in a single file. > >> ----- >> do { >> if (pcie_phy_is_ready(dev)) >> break; >> retries++; >> usleep_range(REFCLK_STABILIZATION_DELAY_US_MIN, >> REFCLK_STABILIZATION_DELAY_US_MAX); >> } while (retries < PHY_READY_TIMEOUT_COUNT); >> >> REFCLK_STABILIZATION_DELAY_US_MIN/MAX ==> 1000/1005 >> PHY_READY_TIMEOUT_COUNT ==> 10 >> ----- > > https://source.codeaurora.org/quic/la/kernel/msm-4.4/tree/drivers/pci/host/pci-msm.c?h=LE.UM.1.3.r3.25#n4624 > > https://source.codeaurora.org/quic/la/kernel/msm-4.4/tree/drivers/pci/host/pci-msm.c?h=LE.UM.1.3.r3.25#n1721 > > readl_relaxed(dev->phy + PCIE_N_PCS_STATUS(dev->rc_idx, dev->common_phy)) & BIT(6) > is equivalent to: > the check in qcom_qmp_phy_enable() > > readl_relaxed(dev->phy + PCIE_COM_PCS_READY_STATUS) & 0x1 > is equivalent to: > the check in qcom_qmp_phy_com_init() > > I'll take a closer look, using some printks, to narrow down the run-time > execution path. > >> phy_enable() from the usb phy driver from downstream. >> /* Wait for PHY initialization to be done */ >> do { >> if (readl_relaxed(phy->base + >> phy->phy_reg[USB3_PHY_PCS_STATUS]) & PHYSTATUS) >> usleep_range(1, 2); >> else >> break; >> } while (--init_timeout_usec); >> >> init_timeout_usec ==> 1000 >> ----- >> USB never had a COM_PHY status bit. >> >> So clearly the resolutions were different. >> >> Does this change solve an issue at hand? > > The issue is usleep_range() being misused ^_^ > > Although usleep_range() takes unsigned longs as parameters, it is > not appropriate over the entire 0-2^64 range. > > a) It should not be used with tiny values, because the cost of programming > the timer interrupt, and processing the resulting IRQ would dominate. > > b) It should not be used with large values (above 2000000/HZ) because > msleep() is more efficient, and is acceptable for these ranges. Documentation/timers/timers-howto.txt has all the information on the various kernel delay/sleep mechanisms. For < ~10us, it recommends to use udelay (readx_poll_timeout_atomic). Depending on the actual timeout to be used, the delay mechanism in timers-howto.txt should be used. Thanks Kishon