diff mbox series

PCI: dwc: Use ATU regions to map memory regions

Message ID 20201005121351.32516-1-vidyas@nvidia.com
State Superseded
Headers show
Series PCI: dwc: Use ATU regions to map memory regions | expand

Commit Message

Vidya Sagar Oct. 5, 2020, 12:13 p.m. UTC
Use ATU region-3 and region-0 to setup mapping for prefetchable and
non-prefetchable memory regions respectively only if their respective CPU
and bus addresses are different.

Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
---
 .../pci/controller/dwc/pcie-designware-host.c | 44 ++++++++++++++++---
 drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
 drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
 3 files changed, 48 insertions(+), 12 deletions(-)

Comments

Vidya Sagar Oct. 19, 2020, 5:51 a.m. UTC | #1
Hi Lorenzo, Rob, Gustavo,
Could you please review this change?

Thanks,
Vidya Sagar

On 10/5/2020 5:43 PM, Vidya Sagar wrote:
> Use ATU region-3 and region-0 to setup mapping for prefetchable and
> non-prefetchable memory regions respectively only if their respective CPU
> and bus addresses are different.
> 
> Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> ---
>   .../pci/controller/dwc/pcie-designware-host.c | 44 ++++++++++++++++---
>   drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
>   drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
>   3 files changed, 48 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 317ff512f8df..cefde8e813e9 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -515,9 +515,40 @@ 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);
> +
> +	if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
> +	    win->offset) {
> +		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 if (win->res->flags & IORESOURCE_PREFETCH &&
> +		   pci->num_viewport < 4) {
> +		dev_warn(pci->dev,
> +			 "Insufficient ATU regions to map Prefetchable memory\n");
> +	} else if (win->offset) {
> +		if (upper_32_bits(resource_size(win->res)))
> +			dev_warn(pci->dev,
> +				 "Memory resource size exceeds max for 32 bits\n");
> +		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);
>   
>   	/*
> @@ -572,13 +603,14 @@ 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) {
> +			switch (resource_type(win->res)) {
> +			case IORESOURCE_MEM:
> +				dw_pcie_setup_mem_atu(pp, win);
> +				break;
> +			}
> +		}
>   
> -		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.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 3c1f17c78241..6033689abb15 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
>   static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>   					     int index, int type,
>   					     u64 cpu_addr, u64 pci_addr,
> -					     u32 size)
> +					     u64 size)
>   {
>   	u32 retries, val;
>   	u64 limit_addr = cpu_addr + size - 1;
> @@ -244,8 +244,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>   				 lower_32_bits(pci_addr));
>   	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
>   				 upper_32_bits(pci_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
> -				 type | PCIE_ATU_FUNC_NUM(func_no));
> +	val = type | PCIE_ATU_FUNC_NUM(func_no);
> +	val = upper_32_bits(size - 1) ?
> +		val | PCIE_ATU_INCREASE_REGION_SIZE : val;
> +	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
>   	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
>   				 PCIE_ATU_ENABLE);
>   
> @@ -266,7 +268,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>   
>   static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>   					int index, int type, u64 cpu_addr,
> -					u64 pci_addr, u32 size)
> +					u64 pci_addr, u64 size)
>   {
>   	u32 retries, val;
>   
> @@ -310,7 +312,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>   }
>   
>   void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
> -			       u64 cpu_addr, u64 pci_addr, u32 size)
> +			       u64 cpu_addr, u64 pci_addr, u64 size)
>   {
>   	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
>   				    cpu_addr, pci_addr, size);
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 97c7063b9e89..b81a1813cf9e 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -80,10 +80,12 @@
>   #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
>   #define PCIE_ATU_CR1			0x904
> +#define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
>   #define PCIE_ATU_TYPE_MEM		0x0
>   #define PCIE_ATU_TYPE_IO		0x2
>   #define PCIE_ATU_TYPE_CFG0		0x4
> @@ -295,7 +297,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
>   int dw_pcie_wait_for_link(struct dw_pcie *pci);
>   void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
>   			       int type, u64 cpu_addr, u64 pci_addr,
> -			       u32 size);
> +			       u64 size);
>   void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
>   				  int type, u64 cpu_addr, u64 pci_addr,
>   				  u32 size);
>
Lorenzo Pieralisi Oct. 20, 2020, 1:20 p.m. UTC | #2
On Mon, Oct 19, 2020 at 11:21:54AM +0530, Vidya Sagar wrote:
> Hi Lorenzo, Rob, Gustavo,
> Could you please review this change?

Next cycle - we are in the middle of the merge window and I am not
queueing any more patches.

Thanks,
Lorenzo

> Thanks,
> Vidya Sagar
> 
> On 10/5/2020 5:43 PM, Vidya Sagar wrote:
> > Use ATU region-3 and region-0 to setup mapping for prefetchable and
> > non-prefetchable memory regions respectively only if their respective CPU
> > and bus addresses are different.
> > 
> > Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> > ---
> >   .../pci/controller/dwc/pcie-designware-host.c | 44 ++++++++++++++++---
> >   drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
> >   drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
> >   3 files changed, 48 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > index 317ff512f8df..cefde8e813e9 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > @@ -515,9 +515,40 @@ 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);
> > +
> > +	if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
> > +	    win->offset) {
> > +		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 if (win->res->flags & IORESOURCE_PREFETCH &&
> > +		   pci->num_viewport < 4) {
> > +		dev_warn(pci->dev,
> > +			 "Insufficient ATU regions to map Prefetchable memory\n");
> > +	} else if (win->offset) {
> > +		if (upper_32_bits(resource_size(win->res)))
> > +			dev_warn(pci->dev,
> > +				 "Memory resource size exceeds max for 32 bits\n");
> > +		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);
> >   	/*
> > @@ -572,13 +603,14 @@ 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) {
> > +			switch (resource_type(win->res)) {
> > +			case IORESOURCE_MEM:
> > +				dw_pcie_setup_mem_atu(pp, win);
> > +				break;
> > +			}
> > +		}
> > -		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.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index 3c1f17c78241..6033689abb15 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > @@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
> >   static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> >   					     int index, int type,
> >   					     u64 cpu_addr, u64 pci_addr,
> > -					     u32 size)
> > +					     u64 size)
> >   {
> >   	u32 retries, val;
> >   	u64 limit_addr = cpu_addr + size - 1;
> > @@ -244,8 +244,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> >   				 lower_32_bits(pci_addr));
> >   	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> >   				 upper_32_bits(pci_addr));
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
> > -				 type | PCIE_ATU_FUNC_NUM(func_no));
> > +	val = type | PCIE_ATU_FUNC_NUM(func_no);
> > +	val = upper_32_bits(size - 1) ?
> > +		val | PCIE_ATU_INCREASE_REGION_SIZE : val;
> > +	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
> >   	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> >   				 PCIE_ATU_ENABLE);
> > @@ -266,7 +268,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> >   static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> >   					int index, int type, u64 cpu_addr,
> > -					u64 pci_addr, u32 size)
> > +					u64 pci_addr, u64 size)
> >   {
> >   	u32 retries, val;
> > @@ -310,7 +312,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> >   }
> >   void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
> > -			       u64 cpu_addr, u64 pci_addr, u32 size)
> > +			       u64 cpu_addr, u64 pci_addr, u64 size)
> >   {
> >   	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
> >   				    cpu_addr, pci_addr, size);
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > index 97c7063b9e89..b81a1813cf9e 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > @@ -80,10 +80,12 @@
> >   #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
> >   #define PCIE_ATU_CR1			0x904
> > +#define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
> >   #define PCIE_ATU_TYPE_MEM		0x0
> >   #define PCIE_ATU_TYPE_IO		0x2
> >   #define PCIE_ATU_TYPE_CFG0		0x4
> > @@ -295,7 +297,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
> >   int dw_pcie_wait_for_link(struct dw_pcie *pci);
> >   void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
> >   			       int type, u64 cpu_addr, u64 pci_addr,
> > -			       u32 size);
> > +			       u64 size);
> >   void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> >   				  int type, u64 cpu_addr, u64 pci_addr,
> >   				  u32 size);
> >
Vidya Sagar Oct. 20, 2020, 1:33 p.m. UTC | #3
On 10/20/2020 6:50 PM, Lorenzo Pieralisi wrote:
> External email: Use caution opening links or attachments
> 
> 
> On Mon, Oct 19, 2020 at 11:21:54AM +0530, Vidya Sagar wrote:
>> Hi Lorenzo, Rob, Gustavo,
>> Could you please review this change?
> 
> Next cycle - we are in the middle of the merge window and I am not
> queueing any more patches.

Thanks for the update.
FWIW, PCIe is broken on Tegra194 with Rob's patches (which got accepted 
already) and without the current patch.

Thanks,
Vidya Sagar

> 
> Thanks,
> Lorenzo
> 
>> Thanks,
>> Vidya Sagar
>>
>> On 10/5/2020 5:43 PM, Vidya Sagar wrote:
>>> Use ATU region-3 and region-0 to setup mapping for prefetchable and
>>> non-prefetchable memory regions respectively only if their respective CPU
>>> and bus addresses are different.
>>>
>>> Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
>>> ---
>>>    .../pci/controller/dwc/pcie-designware-host.c | 44 ++++++++++++++++---
>>>    drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
>>>    drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
>>>    3 files changed, 48 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
>>> index 317ff512f8df..cefde8e813e9 100644
>>> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
>>> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
>>> @@ -515,9 +515,40 @@ 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);
>>> +
>>> +   if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
>>> +       win->offset) {
>>> +           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 if (win->res->flags & IORESOURCE_PREFETCH &&
>>> +              pci->num_viewport < 4) {
>>> +           dev_warn(pci->dev,
>>> +                    "Insufficient ATU regions to map Prefetchable memory\n");
>>> +   } else if (win->offset) {
>>> +           if (upper_32_bits(resource_size(win->res)))
>>> +                   dev_warn(pci->dev,
>>> +                            "Memory resource size exceeds max for 32 bits\n");
>>> +           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);
>>>      /*
>>> @@ -572,13 +603,14 @@ 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) {
>>> +                   switch (resource_type(win->res)) {
>>> +                   case IORESOURCE_MEM:
>>> +                           dw_pcie_setup_mem_atu(pp, win);
>>> +                           break;
>>> +                   }
>>> +           }
>>> -           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.c b/drivers/pci/controller/dwc/pcie-designware.c
>>> index 3c1f17c78241..6033689abb15 100644
>>> --- a/drivers/pci/controller/dwc/pcie-designware.c
>>> +++ b/drivers/pci/controller/dwc/pcie-designware.c
>>> @@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
>>>    static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>>>                                           int index, int type,
>>>                                           u64 cpu_addr, u64 pci_addr,
>>> -                                        u32 size)
>>> +                                        u64 size)
>>>    {
>>>      u32 retries, val;
>>>      u64 limit_addr = cpu_addr + size - 1;
>>> @@ -244,8 +244,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>>>                               lower_32_bits(pci_addr));
>>>      dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
>>>                               upper_32_bits(pci_addr));
>>> -   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
>>> -                            type | PCIE_ATU_FUNC_NUM(func_no));
>>> +   val = type | PCIE_ATU_FUNC_NUM(func_no);
>>> +   val = upper_32_bits(size - 1) ?
>>> +           val | PCIE_ATU_INCREASE_REGION_SIZE : val;
>>> +   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
>>>      dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
>>>                               PCIE_ATU_ENABLE);
>>> @@ -266,7 +268,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>>>    static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>>>                                      int index, int type, u64 cpu_addr,
>>> -                                   u64 pci_addr, u32 size)
>>> +                                   u64 pci_addr, u64 size)
>>>    {
>>>      u32 retries, val;
>>> @@ -310,7 +312,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>>>    }
>>>    void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
>>> -                          u64 cpu_addr, u64 pci_addr, u32 size)
>>> +                          u64 cpu_addr, u64 pci_addr, u64 size)
>>>    {
>>>      __dw_pcie_prog_outbound_atu(pci, 0, index, type,
>>>                                  cpu_addr, pci_addr, size);
>>> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
>>> index 97c7063b9e89..b81a1813cf9e 100644
>>> --- a/drivers/pci/controller/dwc/pcie-designware.h
>>> +++ b/drivers/pci/controller/dwc/pcie-designware.h
>>> @@ -80,10 +80,12 @@
>>>    #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
>>>    #define PCIE_ATU_CR1                      0x904
>>> +#define PCIE_ATU_INCREASE_REGION_SIZE      BIT(13)
>>>    #define PCIE_ATU_TYPE_MEM         0x0
>>>    #define PCIE_ATU_TYPE_IO          0x2
>>>    #define PCIE_ATU_TYPE_CFG0                0x4
>>> @@ -295,7 +297,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
>>>    int dw_pcie_wait_for_link(struct dw_pcie *pci);
>>>    void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
>>>                             int type, u64 cpu_addr, u64 pci_addr,
>>> -                          u32 size);
>>> +                          u64 size);
>>>    void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
>>>                                int type, u64 cpu_addr, u64 pci_addr,
>>>                                u32 size);
>>>
Lorenzo Pieralisi Oct. 20, 2020, 1:41 p.m. UTC | #4
On Tue, Oct 20, 2020 at 07:03:59PM +0530, Vidya Sagar wrote:
> 
> 
> On 10/20/2020 6:50 PM, Lorenzo Pieralisi wrote:
> > External email: Use caution opening links or attachments
> > 
> > 
> > On Mon, Oct 19, 2020 at 11:21:54AM +0530, Vidya Sagar wrote:
> > > Hi Lorenzo, Rob, Gustavo,
> > > Could you please review this change?
> > 
> > Next cycle - we are in the middle of the merge window and I am not
> > queueing any more patches.
> 
> Thanks for the update.
> FWIW, PCIe is broken on Tegra194 with Rob's patches (which got accepted
> already) and without the current patch.

Ah, that changes the picture then, it was not clear, this requires
immediate attention then.

Thanks,
Lorenzo

> Thanks,
> Vidya Sagar
> 
> > 
> > Thanks,
> > Lorenzo
> > 
> > > Thanks,
> > > Vidya Sagar
> > > 
> > > On 10/5/2020 5:43 PM, Vidya Sagar wrote:
> > > > Use ATU region-3 and region-0 to setup mapping for prefetchable and
> > > > non-prefetchable memory regions respectively only if their respective CPU
> > > > and bus addresses are different.
> > > > 
> > > > Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> > > > ---
> > > >    .../pci/controller/dwc/pcie-designware-host.c | 44 ++++++++++++++++---
> > > >    drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
> > > >    drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
> > > >    3 files changed, 48 insertions(+), 12 deletions(-)
> > > > 
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > > > index 317ff512f8df..cefde8e813e9 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > > > @@ -515,9 +515,40 @@ 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);
> > > > +
> > > > +   if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
> > > > +       win->offset) {
> > > > +           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 if (win->res->flags & IORESOURCE_PREFETCH &&
> > > > +              pci->num_viewport < 4) {
> > > > +           dev_warn(pci->dev,
> > > > +                    "Insufficient ATU regions to map Prefetchable memory\n");
> > > > +   } else if (win->offset) {
> > > > +           if (upper_32_bits(resource_size(win->res)))
> > > > +                   dev_warn(pci->dev,
> > > > +                            "Memory resource size exceeds max for 32 bits\n");
> > > > +           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);
> > > >      /*
> > > > @@ -572,13 +603,14 @@ 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) {
> > > > +                   switch (resource_type(win->res)) {
> > > > +                   case IORESOURCE_MEM:
> > > > +                           dw_pcie_setup_mem_atu(pp, win);
> > > > +                           break;
> > > > +                   }
> > > > +           }
> > > > -           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.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > > index 3c1f17c78241..6033689abb15 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > > @@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
> > > >    static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> > > >                                           int index, int type,
> > > >                                           u64 cpu_addr, u64 pci_addr,
> > > > -                                        u32 size)
> > > > +                                        u64 size)
> > > >    {
> > > >      u32 retries, val;
> > > >      u64 limit_addr = cpu_addr + size - 1;
> > > > @@ -244,8 +244,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> > > >                               lower_32_bits(pci_addr));
> > > >      dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> > > >                               upper_32_bits(pci_addr));
> > > > -   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
> > > > -                            type | PCIE_ATU_FUNC_NUM(func_no));
> > > > +   val = type | PCIE_ATU_FUNC_NUM(func_no);
> > > > +   val = upper_32_bits(size - 1) ?
> > > > +           val | PCIE_ATU_INCREASE_REGION_SIZE : val;
> > > > +   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
> > > >      dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> > > >                               PCIE_ATU_ENABLE);
> > > > @@ -266,7 +268,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> > > >    static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> > > >                                      int index, int type, u64 cpu_addr,
> > > > -                                   u64 pci_addr, u32 size)
> > > > +                                   u64 pci_addr, u64 size)
> > > >    {
> > > >      u32 retries, val;
> > > > @@ -310,7 +312,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> > > >    }
> > > >    void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
> > > > -                          u64 cpu_addr, u64 pci_addr, u32 size)
> > > > +                          u64 cpu_addr, u64 pci_addr, u64 size)
> > > >    {
> > > >      __dw_pcie_prog_outbound_atu(pci, 0, index, type,
> > > >                                  cpu_addr, pci_addr, size);
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > > > index 97c7063b9e89..b81a1813cf9e 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > > > @@ -80,10 +80,12 @@
> > > >    #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
> > > >    #define PCIE_ATU_CR1                      0x904
> > > > +#define PCIE_ATU_INCREASE_REGION_SIZE      BIT(13)
> > > >    #define PCIE_ATU_TYPE_MEM         0x0
> > > >    #define PCIE_ATU_TYPE_IO          0x2
> > > >    #define PCIE_ATU_TYPE_CFG0                0x4
> > > > @@ -295,7 +297,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
> > > >    int dw_pcie_wait_for_link(struct dw_pcie *pci);
> > > >    void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
> > > >                             int type, u64 cpu_addr, u64 pci_addr,
> > > > -                          u32 size);
> > > > +                          u64 size);
> > > >    void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> > > >                                int type, u64 cpu_addr, u64 pci_addr,
> > > >                                u32 size);
> > > >
Lorenzo Pieralisi Oct. 20, 2020, 3:59 p.m. UTC | #5
On Mon, Oct 05, 2020 at 05:43:51PM +0530, Vidya Sagar wrote:
> Use ATU region-3 and region-0 to setup mapping for prefetchable and
> non-prefetchable memory regions respectively only if their respective CPU
> and bus addresses are different.
> 

The commit subject and log must be rewritten. You should describe
why you are making this change, add a Link: tag to the discussion
we had about this change and provide a reason why we are making it.

Also, please add a Fixes: tag reference to the commit you are fixing.

I think this is related to prefetchable handling in DT and dwc/tegra,
we do need a link to those discussions here please.

> Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> ---
>  .../pci/controller/dwc/pcie-designware-host.c | 44 ++++++++++++++++---
>  drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
>  drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
>  3 files changed, 48 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 317ff512f8df..cefde8e813e9 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -515,9 +515,40 @@ 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);
> +
> +	if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
> +	    win->offset) {
> +		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 if (win->res->flags & IORESOURCE_PREFETCH &&
> +		   pci->num_viewport < 4) {
> +		dev_warn(pci->dev,
> +			 "Insufficient ATU regions to map Prefetchable memory\n");
> +	} else if (win->offset) {
> +		if (upper_32_bits(resource_size(win->res)))
> +			dev_warn(pci->dev,
> +				 "Memory resource size exceeds max for 32 bits\n");
> +		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 function logic must be explained - anyone else reading it should
be able to understand it, I think it really deserves a comment.

> +}
> +
>  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);
>  
>  	/*
> @@ -572,13 +603,14 @@ 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) {
> +			switch (resource_type(win->res)) {
> +			case IORESOURCE_MEM:
> +				dw_pcie_setup_mem_atu(pp, win);
> +				break;
> +			}

Nit: an if statement would do but that's not where the problem lies.

> +		}
>  
> -		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.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 3c1f17c78241..6033689abb15 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
>  static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>  					     int index, int type,
>  					     u64 cpu_addr, u64 pci_addr,
> -					     u32 size)
> +					     u64 size)
>  {
>  	u32 retries, val;
>  	u64 limit_addr = cpu_addr + size - 1;
> @@ -244,8 +244,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>  				 lower_32_bits(pci_addr));
>  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
>  				 upper_32_bits(pci_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
> -				 type | PCIE_ATU_FUNC_NUM(func_no));
> +	val = type | PCIE_ATU_FUNC_NUM(func_no);
> +	val = upper_32_bits(size - 1) ?
> +		val | PCIE_ATU_INCREASE_REGION_SIZE : val;
> +	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
>  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
>  				 PCIE_ATU_ENABLE);
>  
> @@ -266,7 +268,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>  
>  static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>  					int index, int type, u64 cpu_addr,
> -					u64 pci_addr, u32 size)
> +					u64 pci_addr, u64 size)
>  {
>  	u32 retries, val;
>  
> @@ -310,7 +312,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>  }
>  
>  void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
> -			       u64 cpu_addr, u64 pci_addr, u32 size)
> +			       u64 cpu_addr, u64 pci_addr, u64 size)
>  {
>  	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
>  				    cpu_addr, pci_addr, size);
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 97c7063b9e89..b81a1813cf9e 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -80,10 +80,12 @@
>  #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
>  #define PCIE_ATU_CR1			0x904
> +#define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
>  #define PCIE_ATU_TYPE_MEM		0x0
>  #define PCIE_ATU_TYPE_IO		0x2
>  #define PCIE_ATU_TYPE_CFG0		0x4
> @@ -295,7 +297,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
>  int dw_pcie_wait_for_link(struct dw_pcie *pci);
>  void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
>  			       int type, u64 cpu_addr, u64 pci_addr,
> -			       u32 size);
> +			       u64 size);
>  void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
>  				  int type, u64 cpu_addr, u64 pci_addr,
>  				  u32 size);
> -- 
> 2.17.1
>
diff mbox series

Patch

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 317ff512f8df..cefde8e813e9 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -515,9 +515,40 @@  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);
+
+	if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
+	    win->offset) {
+		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 if (win->res->flags & IORESOURCE_PREFETCH &&
+		   pci->num_viewport < 4) {
+		dev_warn(pci->dev,
+			 "Insufficient ATU regions to map Prefetchable memory\n");
+	} else if (win->offset) {
+		if (upper_32_bits(resource_size(win->res)))
+			dev_warn(pci->dev,
+				 "Memory resource size exceeds max for 32 bits\n");
+		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);
 
 	/*
@@ -572,13 +603,14 @@  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) {
+			switch (resource_type(win->res)) {
+			case IORESOURCE_MEM:
+				dw_pcie_setup_mem_atu(pp, win);
+				break;
+			}
+		}
 
-		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.c b/drivers/pci/controller/dwc/pcie-designware.c
index 3c1f17c78241..6033689abb15 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -227,7 +227,7 @@  static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 					     int index, int type,
 					     u64 cpu_addr, u64 pci_addr,
-					     u32 size)
+					     u64 size)
 {
 	u32 retries, val;
 	u64 limit_addr = cpu_addr + size - 1;
@@ -244,8 +244,10 @@  static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 				 lower_32_bits(pci_addr));
 	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 				 upper_32_bits(pci_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-				 type | PCIE_ATU_FUNC_NUM(func_no));
+	val = type | PCIE_ATU_FUNC_NUM(func_no);
+	val = upper_32_bits(size - 1) ?
+		val | PCIE_ATU_INCREASE_REGION_SIZE : val;
+	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
 	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
 				 PCIE_ATU_ENABLE);
 
@@ -266,7 +268,7 @@  static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 
 static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 					int index, int type, u64 cpu_addr,
-					u64 pci_addr, u32 size)
+					u64 pci_addr, u64 size)
 {
 	u32 retries, val;
 
@@ -310,7 +312,7 @@  static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 }
 
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
-			       u64 cpu_addr, u64 pci_addr, u32 size)
+			       u64 cpu_addr, u64 pci_addr, u64 size)
 {
 	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
 				    cpu_addr, pci_addr, size);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 97c7063b9e89..b81a1813cf9e 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -80,10 +80,12 @@ 
 #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
 #define PCIE_ATU_CR1			0x904
+#define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
 #define PCIE_ATU_TYPE_MEM		0x0
 #define PCIE_ATU_TYPE_IO		0x2
 #define PCIE_ATU_TYPE_CFG0		0x4
@@ -295,7 +297,7 @@  void dw_pcie_upconfig_setup(struct dw_pcie *pci);
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
 			       int type, u64 cpu_addr, u64 pci_addr,
-			       u32 size);
+			       u64 size);
 void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 				  int type, u64 cpu_addr, u64 pci_addr,
 				  u32 size);