Re: [PATCH] Decouple CFG and IO in Designware PCIe Driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jun 27, 2016 at 6:38 PM, dongbo (E) <dongbo4@xxxxxxxxxx> wrote:
> Hi, all.
>
> How about exchanging the assignments of `MEMORYs' and `CFGs/IOs'?
> In other words, assign MEMEORYs to iatu0, CFGs and IOs to iatu1.
>
> Once the iatu0 is initialized to MEMORY accesses, its BASE_ADDR,
> LIMIT and TYPE is fixed. MEMORYs match with iatu0 at first, so
> they will never being treated as IOs or CFGs by mistake.

This should be acceptable, so you can send it as a formal patch.

However, other corner point for failure is still there. Suppose,
another thread tries to write on IO space when iatu1 was programmed
for CFG.

~Pratyush

>
> The number of viewpoints used remains two, it would be OK for
> platforms only have 2 viewpoints.
>
> Here is the patch:
>
> Signed-off-by: Dong Bo <dongbo4@xxxxxxxxxx>
> ---
>  drivers/pci/host/pcie-designware.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index aafd766..1bd88d9 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -599,11 +599,11 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>                 va_cfg_base = pp->va_cfg1_base;
>         }
>
> -       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
> +       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
>                                   type, cpu_addr,
>                                   busdev, cfg_size);
>         ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
> -       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
> +       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
>                                   PCIE_ATU_TYPE_IO, pp->io_base,
>                                   pp->io_bus_addr, pp->io_size);
>
> @@ -636,11 +636,11 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>                 va_cfg_base = pp->va_cfg1_base;
>         }
>
> -       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
> +       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
>                                   type, cpu_addr,
>                                   busdev, cfg_size);
>         ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
> -       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
> +       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
>                                   PCIE_ATU_TYPE_IO, pp->io_base,
>                                   pp->io_bus_addr, pp->io_size);
>
> @@ -779,7 +779,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
>          * we should not program the ATU here.
>          */
>         if (!pp->ops->rd_other_conf)
> -               dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
> +               dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
>                                           PCIE_ATU_TYPE_MEM, pp->mem_base,
>                                           pp->mem_bus_addr, pp->mem_size);
>
> --
> 1.9.1
>
> On 2016/6/27 12:37, Pratyush Anand wrote:
>> On Wed, Jun 22, 2016 at 1:54 PM, dongbo (E) <dongbo4@xxxxxxxxxx> wrote:
>>> From: Dong Bo <dongbo4@xxxxxxxxxx>
>>>
>>> In designware PCIe driver, the iatu0 is used for both CFG and IO accesses.
>>> When PCIe sends CFGs to peripherals (e.g. lspci),
>>> iatu0 frequently switches between CFG and IO alternatively.
>>>
>>> If the LIMIT of MEMORY is a value between CFGs BASE_ADDR and IOs LIMIT,
>>> this probably results in a MEMORY beging matched to be an IO by mistake.
>>>
>>> Considering the following configurations:
>>> MEMORY          ->      BASE_ADDR: 0xb4100000, LIMIT: 0xb4100FFF, TYPE=mem
>>> CFG             ->      BASE_ADDR: 0xb4000000, LIMIT: 0xb4000FFF, TYPE=cfg
>>> IO              ->      BASE_ADDR: 0xFFFFFFFF, LIMIT: 0xFFFFFFFE, TYPE=io
>>> Suppose PCIe has just completed a CFG access, to switch back to IO, it set the BASE_ADDR to 0xFFFFFFFF, LIMIT 0xFFFFFFFE and TYPE to io.
>>> When another CFG access come,
>>> PCIe first set BASE_ADDR to 0xb4000000 to switch to CFG.
>>> At this moment, a MEMORY access shows up, due to `0xb4000000 <= MEMORY BASE_ADDR <= MEMORY LIMIE <= 0xFFFFFFF, it matches with iatu0.
>>> And it is treated as an IO access by mistake, then sent to perpheral.
>>>
>>
>> Hummm...This portion of driver has always been buggy.
>>
>>> This patch fixes the problem by decoupling CFG and IO, reassigning iatu2 to IO.
>>
>> But, we can not just assign IOs to iatu2.
>> IIRC then, there are atleast two platforms which have only 2
>> viewports, therefore they can not program iatu2.
>>
>> Jingoo,Bjorn: IMHO, we should modify this portion of code, since more
>> number of platforms has 4+ viewports. Probably, we can take following
>> approach:
>>
>> (1) Pass number of viewports through DT. If we have *atleast*  3
>> viewports then assign separate viewports to memory and IO,  and share
>> one with CFG0 and CFG1.
>> (2) If we can have *atleast*  4 then, we may have separate for CFG0
>> and CFG1 as well.
>>
>> (3) If we have *only* 2 then,  either we let them work as they work
>> today with bug, or may be we restrict them from using IO transactions.
>> So assign one to memory and share other for CFG0 and CFG1.
>>
>> Please let me know your opnion.
>>
>> ~Pratyush
>>
>>>
>>> Signed-off-by: Dong Bo <dongbo4@xxxxxxxxxx>
>>> ---
>>>  drivers/pci/host/pcie-designware.c | 14 +++++++-------
>>>  1 file changed, 7 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
>>> index aafd766..1a40305 100644
>>> --- a/drivers/pci/host/pcie-designware.c
>>> +++ b/drivers/pci/host/pcie-designware.c
>>> @@ -51,6 +51,7 @@
>>>  #define PCIE_ATU_VIEWPORT              0x900
>>>  #define PCIE_ATU_REGION_INBOUND                (0x1 << 31)
>>>  #define PCIE_ATU_REGION_OUTBOUND       (0x0 << 31)
>>> +#define PCIE_ATU_REGION_INDEX2         (0x2 << 0)
>>>  #define PCIE_ATU_REGION_INDEX1         (0x1 << 0)
>>>  #define PCIE_ATU_REGION_INDEX0         (0x0 << 0)
>>>  #define PCIE_ATU_CR1                   0x904
>>> @@ -603,9 +604,6 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>>>                                   type, cpu_addr,
>>>                                   busdev, cfg_size);
>>>         ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
>>> -       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
>>> -                                 PCIE_ATU_TYPE_IO, pp->io_base,
>>> -                                 pp->io_bus_addr, pp->io_size);
>>>
>>>         return ret;
>>>  }
>>> @@ -640,9 +638,6 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>>>                                   type, cpu_addr,
>>>                                   busdev, cfg_size);
>>>         ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
>>> -       dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
>>> -                                 PCIE_ATU_TYPE_IO, pp->io_base,
>>> -                                 pp->io_bus_addr, pp->io_size);
>>>
>>>         return ret;
>>>  }
>>> @@ -778,10 +773,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
>>>          * uses its own address translation component rather than ATU, so
>>>          * we should not program the ATU here.
>>>          */
>>> -       if (!pp->ops->rd_other_conf)
>>> +       if (!pp->ops->rd_other_conf) {
>>>                 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
>>>                                           PCIE_ATU_TYPE_MEM, pp->mem_base,
>>>                                           pp->mem_bus_addr, pp->mem_size);
>>> +               dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX2,
>>> +                                       PCIE_ATU_TYPE_IO, pp->io_base,
>>> +                                       pp->io_bus_addr, pp->io_size);
>>> +
>>> +       }
>>>
>>>         dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
>>>
>>> --
>>> 1.9.1
>>>
>>
>> .
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux