[3/3] PCI: dwc: Add support to handle prefetchable memory mapping
diff mbox series

Message ID 20201023195655.11242-4-vidyas@nvidia.com
State New, archived
Headers show
Series
  • Add support to handle prefetchable memory
Related show

Commit Message

Vidya Sagar Oct. 23, 2020, 7:56 p.m. UTC
DWC sub-system currently doesn't differentiate between prefetchable and
non-prefetchable memory aperture entries in the 'ranges' property and
provides ATU mapping only for the first memory aperture entry out of all
the entries present. This was introduced by the
commit 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources").
Mapping for a memory apreture is required if its CPU address and the bus
address are different and the current mechanism works only if the memory
aperture which needs mapping happens to be the first entry. It doesn't
work either if the memory aperture that needs mapping is not the first
entry or if both prefetchable and non-prefetchable apertures need mapping.

This patch fixes this issue by differentiating between prefetchable and
non-prefetchable apertures in the 'ranges' property there by removing the
dependency on the order in which they are specified and adds support for
mapping prefetchable aperture using ATU region-3 if required.

Fixes: 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources")
Link: http://patchwork.ozlabs.org/project/linux-pci/patch/20200513190855.23318-1-vidyas@nvidia.com/

Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
---
Changes from previous versions:
* Addressed Rob's comments and as part of that split the patch into three sub-patches
* Rewrote commit subject and description
* Addressed review comments from Lorenzo

 .../pci/controller/dwc/pcie-designware-host.c | 39 ++++++++++++++++---
 drivers/pci/controller/dwc/pcie-designware.h  |  1 +
 2 files changed, 34 insertions(+), 6 deletions(-)

Comments

Rob Herring Oct. 26, 2020, 3:40 p.m. UTC | #1
On Fri, Oct 23, 2020 at 2:57 PM Vidya Sagar <vidyas@nvidia.com> wrote:
>
> DWC sub-system currently doesn't differentiate between prefetchable and
> non-prefetchable memory aperture entries in the 'ranges' property and
> provides ATU mapping only for the first memory aperture entry out of all
> the entries present. This was introduced by the
> commit 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources").
> Mapping for a memory apreture is required if its CPU address and the bus
> address are different and the current mechanism works only if the memory
> aperture which needs mapping happens to be the first entry. It doesn't
> work either if the memory aperture that needs mapping is not the first
> entry or if both prefetchable and non-prefetchable apertures need mapping.
>
> This patch fixes this issue by differentiating between prefetchable and
> non-prefetchable apertures in the 'ranges' property there by removing the
> dependency on the order in which they are specified and adds support for
> mapping prefetchable aperture using ATU region-3 if required.
>
> Fixes: 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources")

Fixes should come first, then new features.

> Link: http://patchwork.ozlabs.org/project/linux-pci/patch/20200513190855.23318-1-vidyas@nvidia.com/

'Link' is the link for this message and should be a lore.kernel.org
link. Maintainers will add it.

>
> Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> ---
> Changes from previous versions:
> * Addressed Rob's comments and as part of that split the patch into three sub-patches
> * Rewrote commit subject and description
> * Addressed review comments from Lorenzo
>
>  .../pci/controller/dwc/pcie-designware-host.c | 39 ++++++++++++++++---
>  drivers/pci/controller/dwc/pcie-designware.h  |  1 +
>  2 files changed, 34 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 674f32db85ca..a1f319ccd816 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -529,9 +529,39 @@ static struct pci_ops dw_pcie_ops = {
>         .write = pci_generic_config_write,
>  };
>
> +static void dw_pcie_setup_mem_atu(struct pcie_port *pp,
> +                                 struct resource_entry *win)
> +{
> +       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +
> +       /* Check for prefetchable memory aperture */
> +       if (win->res->flags & IORESOURCE_PREFETCH) {
> +               /* Number of view ports must at least be 4 to enable mapping */
> +               if (pci->num_viewport < 4) {
> +                       dev_warn(pci->dev,
> +                                "Insufficient ATU regions to map Prefetchable memory\n");
> +               } else {
> +                       dw_pcie_prog_outbound_atu(pci,
> +                                                 PCIE_ATU_REGION_INDEX3,
> +                                                 PCIE_ATU_TYPE_MEM,
> +                                                 win->res->start,
> +                                                 win->res->start - win->offset,
> +                                                 resource_size(win->res));
> +               }
> +       } else { /* Non-prefetchable memory aperture */
> +               dw_pcie_prog_outbound_atu(pci,
> +                                         PCIE_ATU_REGION_INDEX0,
> +                                         PCIE_ATU_TYPE_MEM,
> +                                         win->res->start,
> +                                         win->res->start - win->offset,
> +                                         resource_size(win->res));
> +       }
> +}
> +

This is in no way a minimal fix. I'll send my proposed fix.

>  void dw_pcie_setup_rc(struct pcie_port *pp)
>  {
>         u32 val, ctrl, num_ctrls;
> +       struct resource_entry *win;
>         struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>
>         /*
> @@ -586,13 +616,10 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
>          * ATU, so we should not program the ATU here.
>          */
>         if (pp->bridge->child_ops == &dw_child_pcie_ops) {
> -               struct resource_entry *entry =
> -                       resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM);
> +               resource_list_for_each_entry(win, &pp->bridge->windows)
> +                       if (resource_type(win->res) == IORESOURCE_MEM)
> +                               dw_pcie_setup_mem_atu(pp, win);
>
> -               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
> -                                         PCIE_ATU_TYPE_MEM, entry->res->start,
> -                                         entry->res->start - entry->offset,
> -                                         resource_size(entry->res));
>                 if (pci->num_viewport > 2)
>                         dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
>                                                   PCIE_ATU_TYPE_IO, pp->io_base,
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index e7f441441db2..21dd06831b50 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -80,6 +80,7 @@
>  #define PCIE_ATU_VIEWPORT              0x900
>  #define PCIE_ATU_REGION_INBOUND                BIT(31)
>  #define PCIE_ATU_REGION_OUTBOUND       0
> +#define PCIE_ATU_REGION_INDEX3         0x3
>  #define PCIE_ATU_REGION_INDEX2         0x2
>  #define PCIE_ATU_REGION_INDEX1         0x1
>  #define PCIE_ATU_REGION_INDEX0         0x0
> --
> 2.17.1
>

Patch
diff mbox series

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 674f32db85ca..a1f319ccd816 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -529,9 +529,39 @@  static struct pci_ops dw_pcie_ops = {
 	.write = pci_generic_config_write,
 };
 
+static void dw_pcie_setup_mem_atu(struct pcie_port *pp,
+				  struct resource_entry *win)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+	/* Check for prefetchable memory aperture */
+	if (win->res->flags & IORESOURCE_PREFETCH) {
+		/* Number of view ports must at least be 4 to enable mapping */
+		if (pci->num_viewport < 4) {
+			dev_warn(pci->dev,
+				 "Insufficient ATU regions to map Prefetchable memory\n");
+		} else {
+			dw_pcie_prog_outbound_atu(pci,
+						  PCIE_ATU_REGION_INDEX3,
+						  PCIE_ATU_TYPE_MEM,
+						  win->res->start,
+						  win->res->start - win->offset,
+						  resource_size(win->res));
+		}
+	} else { /* Non-prefetchable memory aperture */
+		dw_pcie_prog_outbound_atu(pci,
+					  PCIE_ATU_REGION_INDEX0,
+					  PCIE_ATU_TYPE_MEM,
+					  win->res->start,
+					  win->res->start - win->offset,
+					  resource_size(win->res));
+	}
+}
+
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
 	u32 val, ctrl, num_ctrls;
+	struct resource_entry *win;
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
 	/*
@@ -586,13 +616,10 @@  void dw_pcie_setup_rc(struct pcie_port *pp)
 	 * ATU, so we should not program the ATU here.
 	 */
 	if (pp->bridge->child_ops == &dw_child_pcie_ops) {
-		struct resource_entry *entry =
-			resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM);
+		resource_list_for_each_entry(win, &pp->bridge->windows)
+			if (resource_type(win->res) == IORESOURCE_MEM)
+				dw_pcie_setup_mem_atu(pp, win);
 
-		dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
-					  PCIE_ATU_TYPE_MEM, entry->res->start,
-					  entry->res->start - entry->offset,
-					  resource_size(entry->res));
 		if (pci->num_viewport > 2)
 			dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
 						  PCIE_ATU_TYPE_IO, pp->io_base,
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index e7f441441db2..21dd06831b50 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -80,6 +80,7 @@ 
 #define PCIE_ATU_VIEWPORT		0x900
 #define PCIE_ATU_REGION_INBOUND		BIT(31)
 #define PCIE_ATU_REGION_OUTBOUND	0
+#define PCIE_ATU_REGION_INDEX3		0x3
 #define PCIE_ATU_REGION_INDEX2		0x2
 #define PCIE_ATU_REGION_INDEX1		0x1
 #define PCIE_ATU_REGION_INDEX0		0x0