Re: [PATCH] PCI: rockchip: fix wrong access of root port register

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

 



On Mon, Jul 03, 2017 at 05:21:02PM +0800, Shawn Lin wrote:
> Rockchip's RC has two banks of register for root port,
> one is strictly compatible to the PCIe spec(normal bank), but
> the other one could be used to change the RO bit of root port
> register(privileged bank).
> 
> When probing the RC driver, we was using the privileged bank to
> do some basic setup work as some RO bits of the root port register
> is hw-inited to wrong value. But we didn't change to use the normal
> bank when finishing to probe the driver. This could lead to a serious
> problem when the PME code try to clear the PME status by writing
> PCI_EXP_RTSTA_PME to the register of PCI_EXP_RTSTA. Per the PCIe 3.0
> spec, section 7.8.14, PME status bit is RW1C. So the PME code is doing
> the right thing to clear the PME status but we find the RC doesn't
> clear it but actually setting it to one. So finally the system trap in
> pcie_pme_work_fn as PCI_EXP_RTSTA_PME is true now forever. And this
> issue could be reproduced by booting kernel with pci=nomsi.
> 
> To fix it, we should change to use the normal bank of root port register
> for PCI core to visit root port.
> 
> Fixes: e77f847d ("PCI: rockchip: Add Rockchip PCIe controller support")
> Cc: stable@xxxxxxxxxxxxxxx
> Cc: Jeffy Chen <jeffy.chen@xxxxxxxxxxxxxx>
> Cc: Brian Norris <briannorris@xxxxxxxxxxxx>
> Signed-off-by: Shawn Lin <shawn.lin@xxxxxxxxxxxxxx>

Applied to pci/host-rockchip for v4.13, thanks!

> ---
> 
>  drivers/pci/host/pcie-rockchip.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> index eb070ab..5acf869 100644
> --- a/drivers/pci/host/pcie-rockchip.c
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -139,6 +139,7 @@
>  		 PCIE_CORE_INT_CT | PCIE_CORE_INT_UTC | \
>  		 PCIE_CORE_INT_MMVC)
>  
> +#define PCIE_RC_CONFIG_NORMAL_BASE	0x800000
>  #define PCIE_RC_CONFIG_BASE		0xa00000
>  #define PCIE_RC_CONFIG_RID_CCR		(PCIE_RC_CONFIG_BASE + 0x08)
>  #define   PCIE_RC_CONFIG_SCC_SHIFT		16
> @@ -301,7 +302,9 @@ static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip,
>  static int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip,
>  				     int where, int size, u32 *val)
>  {
> -	void __iomem *addr = rockchip->apb_base + PCIE_RC_CONFIG_BASE + where;
> +	void __iomem *addr;
> +
> +	addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + where;
>  
>  	if (!IS_ALIGNED((uintptr_t)addr, size)) {
>  		*val = 0;
> @@ -325,11 +328,13 @@ static int rockchip_pcie_wr_own_conf(struct rockchip_pcie *rockchip,
>  				     int where, int size, u32 val)
>  {
>  	u32 mask, tmp, offset;
> +	void __iomem *addr;
>  
>  	offset = where & ~0x3;
> +	addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + offset;
>  
>  	if (size == 4) {
> -		writel(val, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +		writel(val, addr);
>  		return PCIBIOS_SUCCESSFUL;
>  	}
>  
> @@ -340,9 +345,9 @@ static int rockchip_pcie_wr_own_conf(struct rockchip_pcie *rockchip,
>  	 * corrupt RW1C bits in adjacent registers.  But the hardware
>  	 * doesn't support smaller writes.
>  	 */
> -	tmp = readl(rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset) & mask;
> +	tmp = readl(addr) & mask;
>  	tmp |= val << ((where & 0x3) * 8);
> -	writel(tmp, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +	writel(tmp, addr);
>  
>  	return PCIBIOS_SUCCESSFUL;
>  }
> -- 
> 1.9.1
> 
> 



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]