]>
Commit | Line | Data |
---|---|---|
bb104d9e SL |
1 | From d2e11daade9f949dd1cfdfa5e8c61e83972395bc Mon Sep 17 00:00:00 2001 |
2 | From: Marek Vasut <marek.vasut+renesas@gmail.com> | |
3 | Date: Mon, 25 Mar 2019 12:41:01 +0100 | |
4 | Subject: PCI: rcar: Fix 64bit MSI message address handling | |
5 | ||
6 | [ Upstream commit 954b4b752a4c4e963b017ed8cef4c453c5ed308d ] | |
7 | ||
8 | The MSI message address in the RC address space can be 64 bit. The | |
9 | R-Car PCIe RC supports such a 64bit MSI message address as well. | |
10 | The code currently uses virt_to_phys(__get_free_pages()) to obtain | |
11 | a reserved page for the MSI message address, and the return value | |
12 | of which can be a 64 bit physical address on 64 bit system. | |
13 | ||
14 | However, the driver only programs PCIEMSIALR register with the bottom | |
15 | 32 bits of the virt_to_phys(__get_free_pages()) return value and does | |
16 | not program the top 32 bits into PCIEMSIAUR, but rather programs the | |
17 | PCIEMSIAUR register with 0x0. This worked fine on older 32 bit R-Car | |
18 | SoCs, however may fail on new 64 bit R-Car SoCs. | |
19 | ||
20 | Since from a PCIe controller perspective, an inbound MSI is a memory | |
21 | write to a special address (in case of this controller, defined by | |
22 | the value in PCIEMSIAUR:PCIEMSIALR), which triggers an interrupt, but | |
23 | never hits the DRAM _and_ because allocation of an MSI by a PCIe card | |
24 | driver obtains the MSI message address by reading PCIEMSIAUR:PCIEMSIALR | |
25 | in rcar_msi_setup_irqs(), incorrectly programmed PCIEMSIAUR cannot | |
26 | cause memory corruption or other issues. | |
27 | ||
28 | There is however the possibility that if virt_to_phys(__get_free_pages()) | |
29 | returned address above the 32bit boundary _and_ PCIEMSIAUR was programmed | |
30 | to 0x0 _and_ if the system had physical RAM at the address matching the | |
31 | value of PCIEMSIALR, a PCIe card driver could allocate a buffer with a | |
32 | physical address matching the value of PCIEMSIALR and a remote write to | |
33 | such a buffer by a PCIe card would trigger a spurious MSI. | |
34 | ||
35 | Fixes: e015f88c368d ("PCI: rcar: Add support for R-Car H3 to pcie-rcar") | |
36 | Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com> | |
37 | Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | |
38 | Reviewed-by: Simon Horman <horms+renesas@verge.net.au> | |
39 | Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> | |
40 | Cc: Geert Uytterhoeven <geert+renesas@glider.be> | |
41 | Cc: Phil Edworthy <phil.edworthy@renesas.com> | |
42 | Cc: Simon Horman <horms+renesas@verge.net.au> | |
43 | Cc: Wolfram Sang <wsa@the-dreams.de> | |
44 | Cc: linux-renesas-soc@vger.kernel.org | |
45 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
46 | --- | |
47 | drivers/pci/host/pcie-rcar.c | 6 +++--- | |
48 | 1 file changed, 3 insertions(+), 3 deletions(-) | |
49 | ||
50 | diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c | |
51 | index 77d931178178..7f6b454bca65 100644 | |
52 | --- a/drivers/pci/host/pcie-rcar.c | |
53 | +++ b/drivers/pci/host/pcie-rcar.c | |
54 | @@ -847,7 +847,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) | |
55 | { | |
56 | struct device *dev = pcie->dev; | |
57 | struct rcar_msi *msi = &pcie->msi; | |
58 | - unsigned long base; | |
59 | + phys_addr_t base; | |
60 | int err, i; | |
61 | ||
62 | mutex_init(&msi->lock); | |
63 | @@ -892,8 +892,8 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) | |
64 | } | |
65 | base = virt_to_phys((void *)msi->pages); | |
66 | ||
67 | - rcar_pci_write_reg(pcie, base | MSIFE, PCIEMSIALR); | |
68 | - rcar_pci_write_reg(pcie, 0, PCIEMSIAUR); | |
69 | + rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); | |
70 | + rcar_pci_write_reg(pcie, upper_32_bits(base), PCIEMSIAUR); | |
71 | ||
72 | /* enable all MSI interrupts */ | |
73 | rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); | |
74 | -- | |
75 | 2.20.1 | |
76 |