pcie-designware: Incorrect programming of msi address register on some setups.
Srinivas Kandagatla
srinivas.kandagatla at linaro.org
Tue Jan 24 06:07:56 PST 2017
Hi,
Recently I hit a bug with pcie-designware driver with triggers a board
reboot, this is my analysis so far on the issue. Issue is because
designware driver is programming msi address which is above 32 address
space eventhough one of the pcie endpoint indicated that it does not
support 64 bit msi addresses.
My setup is arm64 board DB820c with 3 root complexes, and the system has
memory which spans across 4GB address space.
First root complex is connected to a WLAN Chip (QCA6174) only supports
32 bit addresses.
Second one is connected to a Ethernet Controller (ATL1c)
value of MSI control register aka PCI_MSI_FLAGS (0x2) for device QCA6174
is 0x106
value of MSI control register aka PCI_MSI_FLAGS (0x2) for device ATL1C
is 0x80
Now the problem is that on Synopsis IP, the MSI address register is
programmed at two places
1> one at controller config dbi address space itself in
PCIE_MSI_ADDR_LO(0x820) & PCIE_MSI_ADDR_HI (0x824)
2> at PCI_MSI_ADDRESS_LO (0x2) and PCI_MSI_ADDRESS_HI of the device cfg.
If step 1 allocates msi address which is above 32 bit address space,
then step 2 would truncate it to 32 bit address if it discovers endpoint
which does not support 64 bit msi address.
Then if endpoint tries to read/write this address as part of MSI
mechanism it would fault and crash system.
Am not sure how we can solve this correctly because we do not know about
endpoints at step 1. On the other hand if we can force step 1 to
allocate addresses with in 32 bit address space than it would work for
both 32 bit and 64 bit.
Has anyone hit this issue before?
Do we already have a solution?
Any suggestions?
Below ugly Hack is what Am using to workaround this issue on my platform
but am not sure how this will influence other platforms.
---------------------------->cut<-------------------------------
diff --git a/drivers/pci/host/pcie-designware.c
b/drivers/pci/host/pcie-designware.c
index 4a81b72..d694e66 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -286,9 +286,8 @@ void dw_pcie_msi_init(struct pcie_port *pp)
{
u64 msi_target;
- pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
+ pp->msi_data = __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
msi_target = virt_to_phys((void *)pp->msi_data);
/* program the msi_data */
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
(u32)(msi_target & 0xffffffff));
---------------------------->cut<-------------------------------
Thanks,
srini
More information about the linux-arm-kernel
mailing list