Commit 43f5c77b authored by Pali Rohár's avatar Pali Rohár Committed by Lorenzo Pieralisi

PCI: aardvark: Fix reporting CRS value

Set CRSVIS flag in emulated root PCI bridge to indicate support for
Completion Retry Status.

Add check for CRSSVE flag from root PCI brige when issuing Configuration
Read Request via PIO to correctly returns fabricated CRS value as it is
required by PCIe spec.

Link: https://lore.kernel.org/r/20210722144041.12661-5-pali@kernel.org
Fixes: 8a3ebd8d ("PCI: aardvark: Implement emulated root PCI bridge config space")
Signed-off-by: default avatarPali Rohár <pali@kernel.org>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: stable@vger.kernel.org # e0d9d30b ("PCI: pci-bridge-emul: Fix big-endian support")
parent e902bb7c
...@@ -178,6 +178,8 @@ ...@@ -178,6 +178,8 @@
#define MSI_IRQ_NUM 32 #define MSI_IRQ_NUM 32
#define CFG_RD_CRS_VAL 0xffff0001
struct advk_pcie { struct advk_pcie {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *base; void __iomem *base;
...@@ -473,7 +475,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) ...@@ -473,7 +475,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG); advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
} }
static int advk_pcie_check_pio_status(struct advk_pcie *pcie, u32 *val) static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u32 *val)
{ {
struct device *dev = &pcie->pdev->dev; struct device *dev = &pcie->pdev->dev;
u32 reg; u32 reg;
...@@ -515,9 +517,30 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, u32 *val) ...@@ -515,9 +517,30 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, u32 *val)
strcomp_status = "UR"; strcomp_status = "UR";
break; break;
case PIO_COMPLETION_STATUS_CRS: case PIO_COMPLETION_STATUS_CRS:
if (allow_crs && val) {
/* PCIe r4.0, sec 2.3.2, says:
* If CRS Software Visibility is enabled:
* For a Configuration Read Request that includes both
* bytes of the Vendor ID field of a device Function's
* Configuration Space Header, the Root Complex must
* complete the Request to the host by returning a
* read-data value of 0001h for the Vendor ID field and
* all '1's for any additional bytes included in the
* request.
*
* So CRS in this case is not an error status.
*/
*val = CFG_RD_CRS_VAL;
strcomp_status = NULL;
break;
}
/* PCIe r4.0, sec 2.3.2, says: /* PCIe r4.0, sec 2.3.2, says:
* If CRS Software Visibility is not enabled, the Root Complex * If CRS Software Visibility is not enabled, the Root Complex
* must re-issue the Configuration Request as a new Request. * must re-issue the Configuration Request as a new Request.
* If CRS Software Visibility is enabled: For a Configuration
* Write Request or for any other Configuration Read Request,
* the Root Complex must re-issue the Configuration Request as
* a new Request.
* A Root Complex implementation may choose to limit the number * A Root Complex implementation may choose to limit the number
* of Configuration Request/CRS Completion Status loops before * of Configuration Request/CRS Completion Status loops before
* determining that something is wrong with the target of the * determining that something is wrong with the target of the
...@@ -586,6 +609,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, ...@@ -586,6 +609,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
case PCI_EXP_RTCTL: { case PCI_EXP_RTCTL: {
u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG); u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
*value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE; *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE;
*value |= PCI_EXP_RTCAP_CRSVIS << 16;
return PCI_BRIDGE_EMUL_HANDLED; return PCI_BRIDGE_EMUL_HANDLED;
} }
...@@ -667,6 +691,7 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = { ...@@ -667,6 +691,7 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
static int advk_sw_pci_bridge_init(struct advk_pcie *pcie) static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
{ {
struct pci_bridge_emul *bridge = &pcie->bridge; struct pci_bridge_emul *bridge = &pcie->bridge;
int ret;
bridge->conf.vendor = bridge->conf.vendor =
cpu_to_le16(advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff); cpu_to_le16(advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff);
...@@ -690,7 +715,15 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie) ...@@ -690,7 +715,15 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
bridge->data = pcie; bridge->data = pcie;
bridge->ops = &advk_pci_bridge_emul_ops; bridge->ops = &advk_pci_bridge_emul_ops;
return pci_bridge_emul_init(bridge, 0); /* PCIe config space can be initialized after pci_bridge_emul_init() */
ret = pci_bridge_emul_init(bridge, 0);
if (ret < 0)
return ret;
/* Indicates supports for Completion Retry Status */
bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS);
return 0;
} }
static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus, static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
...@@ -742,6 +775,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, ...@@ -742,6 +775,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
int where, int size, u32 *val) int where, int size, u32 *val)
{ {
struct advk_pcie *pcie = bus->sysdata; struct advk_pcie *pcie = bus->sysdata;
bool allow_crs;
u32 reg; u32 reg;
int ret; int ret;
...@@ -754,7 +788,24 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, ...@@ -754,7 +788,24 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
return pci_bridge_emul_conf_read(&pcie->bridge, where, return pci_bridge_emul_conf_read(&pcie->bridge, where,
size, val); size, val);
/*
* Completion Retry Status is possible to return only when reading all
* 4 bytes from PCI_VENDOR_ID and PCI_DEVICE_ID registers at once and
* CRSSVE flag on Root Bridge is enabled.
*/
allow_crs = (where == PCI_VENDOR_ID) && (size == 4) &&
(le16_to_cpu(pcie->bridge.pcie_conf.rootctl) &
PCI_EXP_RTCTL_CRSSVE);
if (advk_pcie_pio_is_running(pcie)) { if (advk_pcie_pio_is_running(pcie)) {
/*
* If it is possible return Completion Retry Status so caller
* tries to issue the request again instead of failing.
*/
if (allow_crs) {
*val = CFG_RD_CRS_VAL;
return PCIBIOS_SUCCESSFUL;
}
*val = 0xffffffff; *val = 0xffffffff;
return PCIBIOS_SET_FAILED; return PCIBIOS_SET_FAILED;
} }
...@@ -782,12 +833,20 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, ...@@ -782,12 +833,20 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
ret = advk_pcie_wait_pio(pcie); ret = advk_pcie_wait_pio(pcie);
if (ret < 0) { if (ret < 0) {
/*
* If it is possible return Completion Retry Status so caller
* tries to issue the request again instead of failing.
*/
if (allow_crs) {
*val = CFG_RD_CRS_VAL;
return PCIBIOS_SUCCESSFUL;
}
*val = 0xffffffff; *val = 0xffffffff;
return PCIBIOS_SET_FAILED; return PCIBIOS_SET_FAILED;
} }
/* Check PIO status and get the read result */ /* Check PIO status and get the read result */
ret = advk_pcie_check_pio_status(pcie, val); ret = advk_pcie_check_pio_status(pcie, allow_crs, val);
if (ret < 0) { if (ret < 0) {
*val = 0xffffffff; *val = 0xffffffff;
return PCIBIOS_SET_FAILED; return PCIBIOS_SET_FAILED;
...@@ -856,7 +915,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, ...@@ -856,7 +915,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
if (ret < 0) if (ret < 0)
return PCIBIOS_SET_FAILED; return PCIBIOS_SET_FAILED;
ret = advk_pcie_check_pio_status(pcie, NULL); ret = advk_pcie_check_pio_status(pcie, false, NULL);
if (ret < 0) if (ret < 0)
return PCIBIOS_SET_FAILED; return PCIBIOS_SET_FAILED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment