* [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-01-12 19:44 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-01-12 19:44 UTC (permalink / raw)
To: Minghuan Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi,
Rob Herring, Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
From: Xiaowei Bao <xiaowei.bao@nxp.com>
When a link down or hot reset event occurs, the PCI Express EP
controller's Link Capabilities Register should retain the values of
the Maximum Link Width and Supported Link Speed configured by RCW.
Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
.../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
1 file changed, 111 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index ed5cfc9408d9..1b884854c18e 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -18,6 +18,22 @@
#include "pcie-designware.h"
+#define PCIE_LINK_CAP 0x7C /* PCIe Link Capabilities*/
+#define MAX_LINK_SP_MASK 0x0F
+#define MAX_LINK_W_MASK 0x3F
+#define MAX_LINK_W_SHIFT 4
+
+/* PEX PFa PCIE pme and message interrupt registers*/
+#define PEX_PF0_PME_MES_DR 0xC0020
+#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
+#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
+#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
+
+#define PEX_PF0_PME_MES_IER 0xC0028
+#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
+#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
+#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
+
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
struct ls_pcie_ep_drvdata {
@@ -30,8 +46,90 @@ struct ls_pcie_ep {
struct dw_pcie *pci;
struct pci_epc_features *ls_epc;
const struct ls_pcie_ep_drvdata *drvdata;
+ u8 max_speed;
+ u8 max_width;
+ bool big_endian;
+ int irq;
};
+static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
+{
+ struct dw_pcie *pci = pcie->pci;
+
+ if (pcie->big_endian)
+ return ioread32be(pci->dbi_base + offset);
+ else
+ return ioread32(pci->dbi_base + offset);
+}
+
+static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
+ u32 value)
+{
+ struct dw_pcie *pci = pcie->pci;
+
+ if (pcie->big_endian)
+ iowrite32be(value, pci->dbi_base + offset);
+ else
+ iowrite32(value, pci->dbi_base + offset);
+}
+
+static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
+{
+ struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
+ struct dw_pcie *pci = pcie->pci;
+ u32 val;
+
+ val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
+ if (!val)
+ return IRQ_NONE;
+
+ if (val & PEX_PF0_PME_MES_DR_LUD)
+ dev_info(pci->dev, "Detect the link up state !\n");
+ else if (val & PEX_PF0_PME_MES_DR_LDD)
+ dev_info(pci->dev, "Detect the link down state !\n");
+ else if (val & PEX_PF0_PME_MES_DR_HRD)
+ dev_info(pci->dev, "Detect the hot reset state !\n");
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
+ (pcie->max_width << MAX_LINK_W_SHIFT) |
+ pcie->max_speed);
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
+
+ return IRQ_HANDLED;
+}
+
+static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
+ struct platform_device *pdev)
+{
+ u32 val;
+ int ret;
+
+ pcie->irq = platform_get_irq_byname(pdev, "pme");
+ if (pcie->irq < 0) {
+ dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
+ return pcie->irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, pcie->irq,
+ ls_pcie_ep_event_handler, IRQF_SHARED,
+ pdev->name, pcie);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
+ return ret;
+ }
+
+ /* Enable interrupts */
+ val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
+ val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
+ PEX_PF0_PME_MES_IER_LUDIE;
+ ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
+
+ return 0;
+}
+
static const struct pci_epc_features*
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
{
@@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
struct ls_pcie_ep *pcie;
struct pci_epc_features *ls_epc;
struct resource *dbi_base;
+ int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
pci->ep.ops = &ls_pcie_ep_ops;
+ pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
+
+ pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
+ MAX_LINK_SP_MASK;
+ pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
+ MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
+
platform_set_drvdata(pdev, pcie);
- return dw_pcie_ep_init(&pci->ep);
+ ret = dw_pcie_ep_init(&pci->ep);
+ if (ret)
+ return ret;
+
+ return ls_pcie_ep_interrupt_init(pcie, pdev);
}
static struct platform_driver ls_pcie_ep_driver = {
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-01-12 19:44 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-01-12 19:44 UTC (permalink / raw)
To: Minghuan Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi,
Rob Herring, Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
From: Xiaowei Bao <xiaowei.bao@nxp.com>
When a link down or hot reset event occurs, the PCI Express EP
controller's Link Capabilities Register should retain the values of
the Maximum Link Width and Supported Link Speed configured by RCW.
Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
.../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
1 file changed, 111 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index ed5cfc9408d9..1b884854c18e 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -18,6 +18,22 @@
#include "pcie-designware.h"
+#define PCIE_LINK_CAP 0x7C /* PCIe Link Capabilities*/
+#define MAX_LINK_SP_MASK 0x0F
+#define MAX_LINK_W_MASK 0x3F
+#define MAX_LINK_W_SHIFT 4
+
+/* PEX PFa PCIE pme and message interrupt registers*/
+#define PEX_PF0_PME_MES_DR 0xC0020
+#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
+#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
+#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
+
+#define PEX_PF0_PME_MES_IER 0xC0028
+#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
+#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
+#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
+
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
struct ls_pcie_ep_drvdata {
@@ -30,8 +46,90 @@ struct ls_pcie_ep {
struct dw_pcie *pci;
struct pci_epc_features *ls_epc;
const struct ls_pcie_ep_drvdata *drvdata;
+ u8 max_speed;
+ u8 max_width;
+ bool big_endian;
+ int irq;
};
+static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
+{
+ struct dw_pcie *pci = pcie->pci;
+
+ if (pcie->big_endian)
+ return ioread32be(pci->dbi_base + offset);
+ else
+ return ioread32(pci->dbi_base + offset);
+}
+
+static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
+ u32 value)
+{
+ struct dw_pcie *pci = pcie->pci;
+
+ if (pcie->big_endian)
+ iowrite32be(value, pci->dbi_base + offset);
+ else
+ iowrite32(value, pci->dbi_base + offset);
+}
+
+static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
+{
+ struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
+ struct dw_pcie *pci = pcie->pci;
+ u32 val;
+
+ val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
+ if (!val)
+ return IRQ_NONE;
+
+ if (val & PEX_PF0_PME_MES_DR_LUD)
+ dev_info(pci->dev, "Detect the link up state !\n");
+ else if (val & PEX_PF0_PME_MES_DR_LDD)
+ dev_info(pci->dev, "Detect the link down state !\n");
+ else if (val & PEX_PF0_PME_MES_DR_HRD)
+ dev_info(pci->dev, "Detect the hot reset state !\n");
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
+ (pcie->max_width << MAX_LINK_W_SHIFT) |
+ pcie->max_speed);
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
+
+ return IRQ_HANDLED;
+}
+
+static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
+ struct platform_device *pdev)
+{
+ u32 val;
+ int ret;
+
+ pcie->irq = platform_get_irq_byname(pdev, "pme");
+ if (pcie->irq < 0) {
+ dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
+ return pcie->irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, pcie->irq,
+ ls_pcie_ep_event_handler, IRQF_SHARED,
+ pdev->name, pcie);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
+ return ret;
+ }
+
+ /* Enable interrupts */
+ val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
+ val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
+ PEX_PF0_PME_MES_IER_LUDIE;
+ ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
+
+ return 0;
+}
+
static const struct pci_epc_features*
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
{
@@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
struct ls_pcie_ep *pcie;
struct pci_epc_features *ls_epc;
struct resource *dbi_base;
+ int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
pci->ep.ops = &ls_pcie_ep_ops;
+ pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
+
+ pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
+ MAX_LINK_SP_MASK;
+ pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
+ MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
+
platform_set_drvdata(pdev, pcie);
- return dw_pcie_ep_init(&pci->ep);
+ ret = dw_pcie_ep_init(&pci->ep);
+ if (ret)
+ return ret;
+
+ return ls_pcie_ep_interrupt_init(pcie, pdev);
}
static struct platform_driver ls_pcie_ep_driver = {
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 14+ messages in thread
* RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
2023-01-12 19:44 ` Frank Li
@ 2023-02-02 17:43 ` Frank Li
-1 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-02-02 17:43 UTC (permalink / raw)
To: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
> Subject: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
>
> From: Xiaowei Bao <xiaowei.bao@nxp.com>
>
> When a link down or hot reset event occurs, the PCI Express EP
> controller's Link Capabilities Register should retain the values of
> the Maximum Link Width and Supported Link Speed configured by RCW.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
Ping
> .../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
> 1 file changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> index ed5cfc9408d9..1b884854c18e 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> @@ -18,6 +18,22 @@
>
> #include "pcie-designware.h"
>
> +#define PCIE_LINK_CAP 0x7C /* PCIe Link
> Capabilities*/
> +#define MAX_LINK_SP_MASK 0x0F
> +#define MAX_LINK_W_MASK 0x3F
> +#define MAX_LINK_W_SHIFT 4
> +
> +/* PEX PFa PCIE pme and message interrupt registers*/
> +#define PEX_PF0_PME_MES_DR 0xC0020
> +#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
> +#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
> +#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
> +
> +#define PEX_PF0_PME_MES_IER 0xC0028
> +#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
> +#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
> +#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
> +
> #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
>
> struct ls_pcie_ep_drvdata {
> @@ -30,8 +46,90 @@ struct ls_pcie_ep {
> struct dw_pcie *pci;
> struct pci_epc_features *ls_epc;
> const struct ls_pcie_ep_drvdata *drvdata;
> + u8 max_speed;
> + u8 max_width;
> + bool big_endian;
> + int irq;
> };
>
> +static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + return ioread32be(pci->dbi_base + offset);
> + else
> + return ioread32(pci->dbi_base + offset);
> +}
> +
> +static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
> + u32 value)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + iowrite32be(value, pci->dbi_base + offset);
> + else
> + iowrite32(value, pci->dbi_base + offset);
> +}
> +
> +static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
> +{
> + struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
> + struct dw_pcie *pci = pcie->pci;
> + u32 val;
> +
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
> + if (!val)
> + return IRQ_NONE;
> +
> + if (val & PEX_PF0_PME_MES_DR_LUD)
> + dev_info(pci->dev, "Detect the link up state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_LDD)
> + dev_info(pci->dev, "Detect the link down state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_HRD)
> + dev_info(pci->dev, "Detect the hot reset state !\n");
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
> + (pcie->max_width << MAX_LINK_W_SHIFT) |
> + pcie->max_speed);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
> + struct platform_device *pdev)
> +{
> + u32 val;
> + int ret;
> +
> + pcie->irq = platform_get_irq_byname(pdev, "pme");
> + if (pcie->irq < 0) {
> + dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
> + return pcie->irq;
> + }
> +
> + ret = devm_request_irq(&pdev->dev, pcie->irq,
> + ls_pcie_ep_event_handler, IRQF_SHARED,
> + pdev->name, pcie);
> + if (ret) {
> + dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
> + return ret;
> + }
> +
> + /* Enable interrupts */
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
> + val |= PEX_PF0_PME_MES_IER_LDDIE |
> PEX_PF0_PME_MES_IER_HRDIE |
> + PEX_PF0_PME_MES_IER_LUDIE;
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
> +
> + return 0;
> +}
> +
> static const struct pci_epc_features*
> ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
> {
> @@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct
> platform_device *pdev)
> struct ls_pcie_ep *pcie;
> struct pci_epc_features *ls_epc;
> struct resource *dbi_base;
> + int ret;
>
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> @@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct
> platform_device *pdev)
>
> pci->ep.ops = &ls_pcie_ep_ops;
>
> + pcie->big_endian = of_property_read_bool(dev->of_node, "big-
> endian");
> +
> + pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
> + MAX_LINK_SP_MASK;
> + pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
> + MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
> +
> platform_set_drvdata(pdev, pcie);
>
> - return dw_pcie_ep_init(&pci->ep);
> + ret = dw_pcie_ep_init(&pci->ep);
> + if (ret)
> + return ret;
> +
> + return ls_pcie_ep_interrupt_init(pcie, pdev);
> }
>
> static struct platform_driver ls_pcie_ep_driver = {
> --
> 2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-02-02 17:43 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-02-02 17:43 UTC (permalink / raw)
To: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
> Subject: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
>
> From: Xiaowei Bao <xiaowei.bao@nxp.com>
>
> When a link down or hot reset event occurs, the PCI Express EP
> controller's Link Capabilities Register should retain the values of
> the Maximum Link Width and Supported Link Speed configured by RCW.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
Ping
> .../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
> 1 file changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> index ed5cfc9408d9..1b884854c18e 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> @@ -18,6 +18,22 @@
>
> #include "pcie-designware.h"
>
> +#define PCIE_LINK_CAP 0x7C /* PCIe Link
> Capabilities*/
> +#define MAX_LINK_SP_MASK 0x0F
> +#define MAX_LINK_W_MASK 0x3F
> +#define MAX_LINK_W_SHIFT 4
> +
> +/* PEX PFa PCIE pme and message interrupt registers*/
> +#define PEX_PF0_PME_MES_DR 0xC0020
> +#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
> +#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
> +#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
> +
> +#define PEX_PF0_PME_MES_IER 0xC0028
> +#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
> +#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
> +#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
> +
> #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
>
> struct ls_pcie_ep_drvdata {
> @@ -30,8 +46,90 @@ struct ls_pcie_ep {
> struct dw_pcie *pci;
> struct pci_epc_features *ls_epc;
> const struct ls_pcie_ep_drvdata *drvdata;
> + u8 max_speed;
> + u8 max_width;
> + bool big_endian;
> + int irq;
> };
>
> +static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + return ioread32be(pci->dbi_base + offset);
> + else
> + return ioread32(pci->dbi_base + offset);
> +}
> +
> +static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
> + u32 value)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + iowrite32be(value, pci->dbi_base + offset);
> + else
> + iowrite32(value, pci->dbi_base + offset);
> +}
> +
> +static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
> +{
> + struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
> + struct dw_pcie *pci = pcie->pci;
> + u32 val;
> +
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
> + if (!val)
> + return IRQ_NONE;
> +
> + if (val & PEX_PF0_PME_MES_DR_LUD)
> + dev_info(pci->dev, "Detect the link up state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_LDD)
> + dev_info(pci->dev, "Detect the link down state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_HRD)
> + dev_info(pci->dev, "Detect the hot reset state !\n");
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
> + (pcie->max_width << MAX_LINK_W_SHIFT) |
> + pcie->max_speed);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
> + struct platform_device *pdev)
> +{
> + u32 val;
> + int ret;
> +
> + pcie->irq = platform_get_irq_byname(pdev, "pme");
> + if (pcie->irq < 0) {
> + dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
> + return pcie->irq;
> + }
> +
> + ret = devm_request_irq(&pdev->dev, pcie->irq,
> + ls_pcie_ep_event_handler, IRQF_SHARED,
> + pdev->name, pcie);
> + if (ret) {
> + dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
> + return ret;
> + }
> +
> + /* Enable interrupts */
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
> + val |= PEX_PF0_PME_MES_IER_LDDIE |
> PEX_PF0_PME_MES_IER_HRDIE |
> + PEX_PF0_PME_MES_IER_LUDIE;
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
> +
> + return 0;
> +}
> +
> static const struct pci_epc_features*
> ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
> {
> @@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct
> platform_device *pdev)
> struct ls_pcie_ep *pcie;
> struct pci_epc_features *ls_epc;
> struct resource *dbi_base;
> + int ret;
>
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> @@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct
> platform_device *pdev)
>
> pci->ep.ops = &ls_pcie_ep_ops;
>
> + pcie->big_endian = of_property_read_bool(dev->of_node, "big-
> endian");
> +
> + pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
> + MAX_LINK_SP_MASK;
> + pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
> + MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
> +
> platform_set_drvdata(pdev, pcie);
>
> - return dw_pcie_ep_init(&pci->ep);
> + ret = dw_pcie_ep_init(&pci->ep);
> + if (ret)
> + return ret;
> +
> + return ls_pcie_ep_interrupt_init(pcie, pdev);
> }
>
> static struct platform_driver ls_pcie_ep_driver = {
> --
> 2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
2023-02-02 17:43 ` Frank Li
@ 2023-02-14 17:33 ` Frank Li
-1 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-02-14 17:33 UTC (permalink / raw)
To: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
> -----Original Message-----
> From: Frank Li
> Subject: RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
>
> > Subject: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
> >
> > From: Xiaowei Bao <xiaowei.bao@nxp.com>
> >
> > When a link down or hot reset event occurs, the PCI Express EP
> > controller's Link Capabilities Register should retain the values of
> > the Maximum Link Width and Supported Link Speed configured by RCW.
> >
> > Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> > Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
>
> Ping
Friendly ping.
>
>
> > static struct platform_driver ls_pcie_ep_driver = {
> > --
> > 2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-02-14 17:33 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-02-14 17:33 UTC (permalink / raw)
To: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
> -----Original Message-----
> From: Frank Li
> Subject: RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
>
> > Subject: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
> >
> > From: Xiaowei Bao <xiaowei.bao@nxp.com>
> >
> > When a link down or hot reset event occurs, the PCI Express EP
> > controller's Link Capabilities Register should retain the values of
> > the Maximum Link Width and Supported Link Speed configured by RCW.
> >
> > Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> > Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
>
> Ping
Friendly ping.
>
>
> > static struct platform_driver ls_pcie_ep_driver = {
> > --
> > 2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
2023-02-14 17:33 ` Frank Li
@ 2023-03-14 19:57 ` Frank Li
-1 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-03-14 19:57 UTC (permalink / raw)
To: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
>
> > -----Original Message-----
> > From: Frank Li
> > Subject: RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
> >
> > > Subject: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
> > >
> > > From: Xiaowei Bao <xiaowei.bao@nxp.com>
> > >
> > > When a link down or hot reset event occurs, the PCI Express EP
> > > controller's Link Capabilities Register should retain the values of
> > > the Maximum Link Width and Supported Link Speed configured by RCW.
> > >
> > > Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> > > Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> >
> > Ping
>
> Friendly ping.
Ping. No feedback for over 1 month!
>
> >
> >
> > > static struct platform_driver ls_pcie_ep_driver = {
> > > --
> > > 2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-03-14 19:57 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-03-14 19:57 UTC (permalink / raw)
To: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list
Cc: imx
>
> > -----Original Message-----
> > From: Frank Li
> > Subject: RE: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
> >
> > > Subject: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
> > >
> > > From: Xiaowei Bao <xiaowei.bao@nxp.com>
> > >
> > > When a link down or hot reset event occurs, the PCI Express EP
> > > controller's Link Capabilities Register should retain the values of
> > > the Maximum Link Width and Supported Link Speed configured by RCW.
> > >
> > > Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> > > Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> > > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> >
> > Ping
>
> Friendly ping.
Ping. No feedback for over 1 month!
>
> >
> >
> > > static struct platform_driver ls_pcie_ep_driver = {
> > > --
> > > 2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
2023-01-12 19:44 ` Frank Li
(?)
@ 2023-03-14 20:32 ` Bjorn Helgaas
-1 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2023-03-14 20:32 UTC (permalink / raw)
To: Frank Li
Cc: Minghuan Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi,
Rob Herring, Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list,
imx
On Thu, Jan 12, 2023 at 02:44:33PM -0500, Frank Li wrote:
> From: Xiaowei Bao <xiaowei.bao@nxp.com>
>
> When a link down or hot reset event occurs, the PCI Express EP
> controller's Link Capabilities Register should retain the values of
> the Maximum Link Width and Supported Link Speed configured by RCW.
Can you rework this to say what the patch does and why it's necessary?
Apparently it's a workaround for some issue in A-010305? The subject
line could also use more content. What is A-010305? What is the
problem this works around?
I don't see a check for A-010305; do *all* devices handled by this
driver have this problem?
The PCIe Link Capabilities is supposed to be read-only; maybe this
device loses the value on link down or hot reset? And I guess the
device interrupts on link up/down and reset, and you restore the value
then?
Link Capabilities contains several things other than Max Link Width
and Max Link Speed. But they don't need to be restored?
What is RCW?
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> .../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
> 1 file changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> index ed5cfc9408d9..1b884854c18e 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> @@ -18,6 +18,22 @@
>
> #include "pcie-designware.h"
>
> +#define PCIE_LINK_CAP 0x7C /* PCIe Link Capabilities*/
Is this something you can find by searching the capability list
instead of hard-coding the config space offset?
> +#define MAX_LINK_SP_MASK 0x0F
> +#define MAX_LINK_W_MASK 0x3F
> +#define MAX_LINK_W_SHIFT 4
These look like they should use PCI_EXP_LNKCAP_SLS and
PCI_EXP_LNKCAP_MLW instead of defining new ones.
> +/* PEX PFa PCIE pme and message interrupt registers*/
> +#define PEX_PF0_PME_MES_DR 0xC0020
> +#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
> +#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
> +#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
> +
> +#define PEX_PF0_PME_MES_IER 0xC0028
> +#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
> +#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
> +#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
> +
> #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
>
> struct ls_pcie_ep_drvdata {
> @@ -30,8 +46,90 @@ struct ls_pcie_ep {
> struct dw_pcie *pci;
> struct pci_epc_features *ls_epc;
> const struct ls_pcie_ep_drvdata *drvdata;
> + u8 max_speed;
> + u8 max_width;
> + bool big_endian;
> + int irq;
> };
>
> +static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + return ioread32be(pci->dbi_base + offset);
> + else
> + return ioread32(pci->dbi_base + offset);
> +}
> +
> +static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
> + u32 value)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + iowrite32be(value, pci->dbi_base + offset);
> + else
> + iowrite32(value, pci->dbi_base + offset);
> +}
> +
> +static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
> +{
> + struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
> + struct dw_pcie *pci = pcie->pci;
> + u32 val;
> +
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
> + if (!val)
> + return IRQ_NONE;
> +
> + if (val & PEX_PF0_PME_MES_DR_LUD)
> + dev_info(pci->dev, "Detect the link up state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_LDD)
> + dev_info(pci->dev, "Detect the link down state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_HRD)
> + dev_info(pci->dev, "Detect the hot reset state !\n");
No space before "!". Seems possibly more verbose than necessary,
since the endpoint may be reset as part of normal operation.
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
> + (pcie->max_width << MAX_LINK_W_SHIFT) |
Use FIELD_PREP() so you don't need a shift.
> + pcie->max_speed);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
> + struct platform_device *pdev)
> +{
> + u32 val;
> + int ret;
> +
> + pcie->irq = platform_get_irq_byname(pdev, "pme");
> + if (pcie->irq < 0) {
> + dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
> + return pcie->irq;
> + }
> +
> + ret = devm_request_irq(&pdev->dev, pcie->irq,
> + ls_pcie_ep_event_handler, IRQF_SHARED,
> + pdev->name, pcie);
> + if (ret) {
> + dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
Use "IRQ" consistently (it was "irq" in the message above). No period
needed at end.
> + return ret;
> + }
> +
> + /* Enable interrupts */
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
> + val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
> + PEX_PF0_PME_MES_IER_LUDIE;
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
> +
> + return 0;
> +}
> +
> static const struct pci_epc_features*
> ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
> {
> @@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
> struct ls_pcie_ep *pcie;
> struct pci_epc_features *ls_epc;
> struct resource *dbi_base;
> + int ret;
>
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> @@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
>
> pci->ep.ops = &ls_pcie_ep_ops;
>
> + pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
Somewhat surprising that 6c389328c985 ("dt-bindings: pci:
layerscape-pci: Add a optional property big-endian") added this
property a year ago, but it has been unused until now?
> + pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
> + MAX_LINK_SP_MASK;
> + pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
> + MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
Use FIELD_GET() instead of shifting/masking. Or save the whole
register instead of extracting and reconstructing the value.
> platform_set_drvdata(pdev, pcie);
>
> - return dw_pcie_ep_init(&pci->ep);
> + ret = dw_pcie_ep_init(&pci->ep);
> + if (ret)
> + return ret;
> +
> + return ls_pcie_ep_interrupt_init(pcie, pdev);
> }
>
> static struct platform_driver ls_pcie_ep_driver = {
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-03-14 20:32 ` Bjorn Helgaas
0 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2023-03-14 20:32 UTC (permalink / raw)
To: Frank Li
Cc: Krzysztof Wilczyński, imx, Rob Herring,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE, Lorenzo Pieralisi,
open list, Minghuan Lian,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, Roy Zang,
Bjorn Helgaas, open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
Mingkai Hu
On Thu, Jan 12, 2023 at 02:44:33PM -0500, Frank Li wrote:
> From: Xiaowei Bao <xiaowei.bao@nxp.com>
>
> When a link down or hot reset event occurs, the PCI Express EP
> controller's Link Capabilities Register should retain the values of
> the Maximum Link Width and Supported Link Speed configured by RCW.
Can you rework this to say what the patch does and why it's necessary?
Apparently it's a workaround for some issue in A-010305? The subject
line could also use more content. What is A-010305? What is the
problem this works around?
I don't see a check for A-010305; do *all* devices handled by this
driver have this problem?
The PCIe Link Capabilities is supposed to be read-only; maybe this
device loses the value on link down or hot reset? And I guess the
device interrupts on link up/down and reset, and you restore the value
then?
Link Capabilities contains several things other than Max Link Width
and Max Link Speed. But they don't need to be restored?
What is RCW?
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> .../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
> 1 file changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> index ed5cfc9408d9..1b884854c18e 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> @@ -18,6 +18,22 @@
>
> #include "pcie-designware.h"
>
> +#define PCIE_LINK_CAP 0x7C /* PCIe Link Capabilities*/
Is this something you can find by searching the capability list
instead of hard-coding the config space offset?
> +#define MAX_LINK_SP_MASK 0x0F
> +#define MAX_LINK_W_MASK 0x3F
> +#define MAX_LINK_W_SHIFT 4
These look like they should use PCI_EXP_LNKCAP_SLS and
PCI_EXP_LNKCAP_MLW instead of defining new ones.
> +/* PEX PFa PCIE pme and message interrupt registers*/
> +#define PEX_PF0_PME_MES_DR 0xC0020
> +#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
> +#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
> +#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
> +
> +#define PEX_PF0_PME_MES_IER 0xC0028
> +#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
> +#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
> +#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
> +
> #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
>
> struct ls_pcie_ep_drvdata {
> @@ -30,8 +46,90 @@ struct ls_pcie_ep {
> struct dw_pcie *pci;
> struct pci_epc_features *ls_epc;
> const struct ls_pcie_ep_drvdata *drvdata;
> + u8 max_speed;
> + u8 max_width;
> + bool big_endian;
> + int irq;
> };
>
> +static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + return ioread32be(pci->dbi_base + offset);
> + else
> + return ioread32(pci->dbi_base + offset);
> +}
> +
> +static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
> + u32 value)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + iowrite32be(value, pci->dbi_base + offset);
> + else
> + iowrite32(value, pci->dbi_base + offset);
> +}
> +
> +static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
> +{
> + struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
> + struct dw_pcie *pci = pcie->pci;
> + u32 val;
> +
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
> + if (!val)
> + return IRQ_NONE;
> +
> + if (val & PEX_PF0_PME_MES_DR_LUD)
> + dev_info(pci->dev, "Detect the link up state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_LDD)
> + dev_info(pci->dev, "Detect the link down state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_HRD)
> + dev_info(pci->dev, "Detect the hot reset state !\n");
No space before "!". Seems possibly more verbose than necessary,
since the endpoint may be reset as part of normal operation.
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
> + (pcie->max_width << MAX_LINK_W_SHIFT) |
Use FIELD_PREP() so you don't need a shift.
> + pcie->max_speed);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
> + struct platform_device *pdev)
> +{
> + u32 val;
> + int ret;
> +
> + pcie->irq = platform_get_irq_byname(pdev, "pme");
> + if (pcie->irq < 0) {
> + dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
> + return pcie->irq;
> + }
> +
> + ret = devm_request_irq(&pdev->dev, pcie->irq,
> + ls_pcie_ep_event_handler, IRQF_SHARED,
> + pdev->name, pcie);
> + if (ret) {
> + dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
Use "IRQ" consistently (it was "irq" in the message above). No period
needed at end.
> + return ret;
> + }
> +
> + /* Enable interrupts */
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
> + val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
> + PEX_PF0_PME_MES_IER_LUDIE;
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
> +
> + return 0;
> +}
> +
> static const struct pci_epc_features*
> ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
> {
> @@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
> struct ls_pcie_ep *pcie;
> struct pci_epc_features *ls_epc;
> struct resource *dbi_base;
> + int ret;
>
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> @@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
>
> pci->ep.ops = &ls_pcie_ep_ops;
>
> + pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
Somewhat surprising that 6c389328c985 ("dt-bindings: pci:
layerscape-pci: Add a optional property big-endian") added this
property a year ago, but it has been unused until now?
> + pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
> + MAX_LINK_SP_MASK;
> + pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
> + MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
Use FIELD_GET() instead of shifting/masking. Or save the whole
register instead of extracting and reconstructing the value.
> platform_set_drvdata(pdev, pcie);
>
> - return dw_pcie_ep_init(&pci->ep);
> + ret = dw_pcie_ep_init(&pci->ep);
> + if (ret)
> + return ret;
> +
> + return ls_pcie_ep_interrupt_init(pcie, pdev);
> }
>
> static struct platform_driver ls_pcie_ep_driver = {
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-03-14 20:32 ` Bjorn Helgaas
0 siblings, 0 replies; 14+ messages in thread
From: Bjorn Helgaas @ 2023-03-14 20:32 UTC (permalink / raw)
To: Frank Li
Cc: Minghuan Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi,
Rob Herring, Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list,
imx
On Thu, Jan 12, 2023 at 02:44:33PM -0500, Frank Li wrote:
> From: Xiaowei Bao <xiaowei.bao@nxp.com>
>
> When a link down or hot reset event occurs, the PCI Express EP
> controller's Link Capabilities Register should retain the values of
> the Maximum Link Width and Supported Link Speed configured by RCW.
Can you rework this to say what the patch does and why it's necessary?
Apparently it's a workaround for some issue in A-010305? The subject
line could also use more content. What is A-010305? What is the
problem this works around?
I don't see a check for A-010305; do *all* devices handled by this
driver have this problem?
The PCIe Link Capabilities is supposed to be read-only; maybe this
device loses the value on link down or hot reset? And I guess the
device interrupts on link up/down and reset, and you restore the value
then?
Link Capabilities contains several things other than Max Link Width
and Max Link Speed. But they don't need to be restored?
What is RCW?
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> .../pci/controller/dwc/pci-layerscape-ep.c | 112 +++++++++++++++++-
> 1 file changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> index ed5cfc9408d9..1b884854c18e 100644
> --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
> +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
> @@ -18,6 +18,22 @@
>
> #include "pcie-designware.h"
>
> +#define PCIE_LINK_CAP 0x7C /* PCIe Link Capabilities*/
Is this something you can find by searching the capability list
instead of hard-coding the config space offset?
> +#define MAX_LINK_SP_MASK 0x0F
> +#define MAX_LINK_W_MASK 0x3F
> +#define MAX_LINK_W_SHIFT 4
These look like they should use PCI_EXP_LNKCAP_SLS and
PCI_EXP_LNKCAP_MLW instead of defining new ones.
> +/* PEX PFa PCIE pme and message interrupt registers*/
> +#define PEX_PF0_PME_MES_DR 0xC0020
> +#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
> +#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
> +#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
> +
> +#define PEX_PF0_PME_MES_IER 0xC0028
> +#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
> +#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
> +#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
> +
> #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
>
> struct ls_pcie_ep_drvdata {
> @@ -30,8 +46,90 @@ struct ls_pcie_ep {
> struct dw_pcie *pci;
> struct pci_epc_features *ls_epc;
> const struct ls_pcie_ep_drvdata *drvdata;
> + u8 max_speed;
> + u8 max_width;
> + bool big_endian;
> + int irq;
> };
>
> +static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + return ioread32be(pci->dbi_base + offset);
> + else
> + return ioread32(pci->dbi_base + offset);
> +}
> +
> +static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
> + u32 value)
> +{
> + struct dw_pcie *pci = pcie->pci;
> +
> + if (pcie->big_endian)
> + iowrite32be(value, pci->dbi_base + offset);
> + else
> + iowrite32(value, pci->dbi_base + offset);
> +}
> +
> +static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
> +{
> + struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
> + struct dw_pcie *pci = pcie->pci;
> + u32 val;
> +
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
> + if (!val)
> + return IRQ_NONE;
> +
> + if (val & PEX_PF0_PME_MES_DR_LUD)
> + dev_info(pci->dev, "Detect the link up state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_LDD)
> + dev_info(pci->dev, "Detect the link down state !\n");
> + else if (val & PEX_PF0_PME_MES_DR_HRD)
> + dev_info(pci->dev, "Detect the hot reset state !\n");
No space before "!". Seems possibly more verbose than necessary,
since the endpoint may be reset as part of normal operation.
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
> + (pcie->max_width << MAX_LINK_W_SHIFT) |
Use FIELD_PREP() so you don't need a shift.
> + pcie->max_speed);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
> + struct platform_device *pdev)
> +{
> + u32 val;
> + int ret;
> +
> + pcie->irq = platform_get_irq_byname(pdev, "pme");
> + if (pcie->irq < 0) {
> + dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
> + return pcie->irq;
> + }
> +
> + ret = devm_request_irq(&pdev->dev, pcie->irq,
> + ls_pcie_ep_event_handler, IRQF_SHARED,
> + pdev->name, pcie);
> + if (ret) {
> + dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
Use "IRQ" consistently (it was "irq" in the message above). No period
needed at end.
> + return ret;
> + }
> +
> + /* Enable interrupts */
> + val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
> + val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
> + PEX_PF0_PME_MES_IER_LUDIE;
> + ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
> +
> + return 0;
> +}
> +
> static const struct pci_epc_features*
> ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
> {
> @@ -125,6 +223,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
> struct ls_pcie_ep *pcie;
> struct pci_epc_features *ls_epc;
> struct resource *dbi_base;
> + int ret;
>
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> @@ -155,9 +254,20 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
>
> pci->ep.ops = &ls_pcie_ep_ops;
>
> + pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
Somewhat surprising that 6c389328c985 ("dt-bindings: pci:
layerscape-pci: Add a optional property big-endian") added this
property a year ago, but it has been unused until now?
> + pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
> + MAX_LINK_SP_MASK;
> + pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
> + MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
Use FIELD_GET() instead of shifting/masking. Or save the whole
register instead of extracting and reconstructing the value.
> platform_set_drvdata(pdev, pcie);
>
> - return dw_pcie_ep_init(&pci->ep);
> + ret = dw_pcie_ep_init(&pci->ep);
> + if (ret)
> + return ret;
> +
> + return ls_pcie_ep_interrupt_init(pcie, pdev);
> }
>
> static struct platform_driver ls_pcie_ep_driver = {
> --
> 2.34.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [EXT] Re: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
2023-03-14 20:32 ` Bjorn Helgaas
(?)
@ 2023-03-17 15:58 ` Frank Li
-1 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-03-17 15:58 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list,
imx
> > pci->ep.ops = &ls_pcie_ep_ops;
> >
> > + pcie->big_endian = of_property_read_bool(dev->of_node, "big-
> endian");
>
> Somewhat surprising that 6c389328c985 ("dt-bindings: pci:
> layerscape-pci: Add a optional property big-endian") added this
> property a year ago, but it has been unused until now?
>
No, it also for pci host part. Zhiqiang send patch
https://lore.kernel.org/lkml/20210407030948.3845-1-Zhiqiang.Hou@nxp.com/
Not sure why bind-doc accepted, but driver code patch have not accepted.
The same case happen at https://lore.kernel.org/imx/20230209151050.233973-1-Frank.Li@nxp.com/T/#t
I tried repost the missed part. But no any response over months. The above one is just one line change.
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [EXT] Re: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-03-17 15:58 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-03-17 15:58 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Krzysztof Wilczyński, imx, Rob Herring,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE, Lorenzo Pieralisi,
open list, M.H. Lian,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, Roy Zang,
Bjorn Helgaas, open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
Mingkai Hu
> > pci->ep.ops = &ls_pcie_ep_ops;
> >
> > + pcie->big_endian = of_property_read_bool(dev->of_node, "big-
> endian");
>
> Somewhat surprising that 6c389328c985 ("dt-bindings: pci:
> layerscape-pci: Add a optional property big-endian") added this
> property a year ago, but it has been unused until now?
>
No, it also for pci host part. Zhiqiang send patch
https://lore.kernel.org/lkml/20210407030948.3845-1-Zhiqiang.Hou@nxp.com/
Not sure why bind-doc accepted, but driver code patch have not accepted.
The same case happen at https://lore.kernel.org/imx/20230209151050.233973-1-Frank.Li@nxp.com/T/#t
I tried repost the missed part. But no any response over months. The above one is just one line change.
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [EXT] Re: [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305
@ 2023-03-17 15:58 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2023-03-17 15:58 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: M.H. Lian, Mingkai Hu, Roy Zang, Lorenzo Pieralisi, Rob Herring,
Krzysztof Wilczyński, Bjorn Helgaas,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
open list:PCI DRIVER FOR FREESCALE LAYERSCAPE,
moderated list:PCI DRIVER FOR FREESCALE LAYERSCAPE, open list,
imx
> > pci->ep.ops = &ls_pcie_ep_ops;
> >
> > + pcie->big_endian = of_property_read_bool(dev->of_node, "big-
> endian");
>
> Somewhat surprising that 6c389328c985 ("dt-bindings: pci:
> layerscape-pci: Add a optional property big-endian") added this
> property a year ago, but it has been unused until now?
>
No, it also for pci host part. Zhiqiang send patch
https://lore.kernel.org/lkml/20210407030948.3845-1-Zhiqiang.Hou@nxp.com/
Not sure why bind-doc accepted, but driver code patch have not accepted.
The same case happen at https://lore.kernel.org/imx/20230209151050.233973-1-Frank.Li@nxp.com/T/#t
I tried repost the missed part. But no any response over months. The above one is just one line change.
> > --
> > 2.34.1
> >
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2023-03-17 16:14 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-12 19:44 [PATCH 1/1] PCI: layerscape: Add the workaround for A-010305 Frank Li
2023-01-12 19:44 ` Frank Li
2023-02-02 17:43 ` Frank Li
2023-02-02 17:43 ` Frank Li
2023-02-14 17:33 ` Frank Li
2023-02-14 17:33 ` Frank Li
2023-03-14 19:57 ` Frank Li
2023-03-14 19:57 ` Frank Li
2023-03-14 20:32 ` Bjorn Helgaas
2023-03-14 20:32 ` Bjorn Helgaas
2023-03-14 20:32 ` Bjorn Helgaas
2023-03-17 15:58 ` [EXT] " Frank Li
2023-03-17 15:58 ` Frank Li
2023-03-17 15:58 ` Frank Li
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.