diff mbox

PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()

Message ID 1441817460-174811-1-git-send-email-gabriele.paoloni@huawei.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Gabriele Paoloni Sept. 9, 2015, 4:51 p.m. UTC
From: gabriele paoloni <gabriele.paoloni@huawei.com>

This patch changes the implementation of dw_pcie_cfg_read() and
dw_pcie_cfg_write() to:
- improve the function usage from the callers perspective;
- make sure that the callers specify proper address offsets
  according to the size of the field being read/written
- fix a bug in pcie-spear13xx.c where the callers where passing
  the wrong address as they missed to add the appropriate offset

This patch is a follow up from the discussion in:
http://www.spinics.net/lists/linux-pci/msg44351.html

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 drivers/pci/host/pci-exynos.c      |  5 ++--
 drivers/pci/host/pci-keystone-dw.c |  4 +--
 drivers/pci/host/pcie-designware.c | 51 ++++++++++++++++++++++----------------
 3 files changed, 34 insertions(+), 26 deletions(-)

Comments

Pratyush Anand Sept. 9, 2015, 6:02 p.m. UTC | #1
On Wed, Sep 9, 2015 at 10:21 PM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:

>  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
>  {
> +       addr += (where & ~0x3);

Lets see what Jingoo and other have to say on it. IMO, where should be
better kept as an offset within 32 bit word and addr should be 32 bit
aligned.  I think this is how where has been considered at other
places like pci-mvebu.c.

>         *val = readl(addr);
> -
> -       if (size == 1)
> -               *val = (*val >> (8 * (where & 3))) & 0xff;
> -       else if (size == 2)
> -               *val = (*val >> (8 * (where & 3))) & 0xffff;
> -       else if (size != 4)
> +       where &= 3;
> +
> +       if (size == 1) {
> +               *val = (*val >> (8 * where)) & 0xff;
> +       } else if (size == 2) {
> +               if (where & 1)
> +                       return PCIBIOS_BAD_REGISTER_NUMBER;

Do we really need such cross check? I do not think that any caller is
expected for such misbehave.

~Pratyush
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjorn Helgaas Sept. 9, 2015, 7:44 p.m. UTC | #2
Hi Gabriele,

On Wed, Sep 9, 2015 at 11:51 AM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
>
> This patch changes the implementation of dw_pcie_cfg_read() and
> dw_pcie_cfg_write() to:
> - improve the function usage from the callers perspective;
> - make sure that the callers specify proper address offsets
>   according to the size of the field being read/written
> - fix a bug in pcie-spear13xx.c where the callers where passing
>   the wrong address as they missed to add the appropriate offset

Please split this into separate patches, so each patch does one thing,
i.e., separate the "where" usage change from the "return
PCIBIOS_BAD_REGISTER_NUMBER for bad offsets" change.

I think there was a separate patch for the pcie-spear13xx.c bug,
wasn't there?  At least, I don't see that fix in *this* patch.

> This patch is a follow up from the discussion in:
> http://www.spinics.net/lists/linux-pci/msg44351.html
>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> ---
>  drivers/pci/host/pci-exynos.c      |  5 ++--
>  drivers/pci/host/pci-keystone-dw.c |  4 +--
>  drivers/pci/host/pcie-designware.c | 51 ++++++++++++++++++++++----------------
>  3 files changed, 34 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
> index f9f468d..8b0e04b 100644
> --- a/drivers/pci/host/pci-exynos.c
> +++ b/drivers/pci/host/pci-exynos.c
> @@ -454,7 +454,7 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
>         int ret;
>
>         exynos_pcie_sideband_dbi_r_mode(pp, true);
> -       ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
> +       ret = dw_pcie_cfg_read(pp->dbi_base, where, size, val);
>         exynos_pcie_sideband_dbi_r_mode(pp, false);
>         return ret;
>  }
> @@ -465,8 +465,7 @@ static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
>         int ret;
>
>         exynos_pcie_sideband_dbi_w_mode(pp, true);
> -       ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
> -                       where, size, val);
> +       ret = dw_pcie_cfg_write(pp->dbi_base, where, size, val);
>         exynos_pcie_sideband_dbi_w_mode(pp, false);
>         return ret;
>  }
> diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
> index f34892e..2b391f4 100644
> --- a/drivers/pci/host/pci-keystone-dw.c
> +++ b/drivers/pci/host/pci-keystone-dw.c
> @@ -403,7 +403,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>
>         addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
>
> -       return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
> +       return dw_pcie_cfg_read(addr, where, size, val);
>  }
>
>  int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
> @@ -415,7 +415,7 @@ int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>
>         addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
>
> -       return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
> +       return dw_pcie_cfg_write(addr, where, size, val);
>  }
>
>  /**
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index 69486be..b53aa38 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -82,13 +82,20 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
>
>  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
>  {
> +       addr += (where & ~0x3);
>         *val = readl(addr);
> -
> -       if (size == 1)
> -               *val = (*val >> (8 * (where & 3))) & 0xff;
> -       else if (size == 2)
> -               *val = (*val >> (8 * (where & 3))) & 0xffff;
> -       else if (size != 4)
> +       where &= 3;
> +
> +       if (size == 1) {
> +               *val = (*val >> (8 * where)) & 0xff;
> +       } else if (size == 2) {
> +               if (where & 1)
> +                       return PCIBIOS_BAD_REGISTER_NUMBER;
> +               *val = (*val >> (8 * where)) & 0xffff;
> +       } else if (size == 4) {
> +               if (where & 3)
> +                       return PCIBIOS_BAD_REGISTER_NUMBER;
> +       } else
>                 return PCIBIOS_BAD_REGISTER_NUMBER;
>
>         return PCIBIOS_SUCCESSFUL;
> @@ -96,12 +103,18 @@ int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
>
>  int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
>  {
> -       if (size == 4)
> +       addr += where;
> +
> +       if (size == 4) {
> +               if ((uintptr_t)addr & 3)
> +                       return PCIBIOS_BAD_REGISTER_NUMBER;
>                 writel(val, addr);
> -       else if (size == 2)
> -               writew(val, addr + (where & 2));
> -       else if (size == 1)
> -               writeb(val, addr + (where & 3));
> +       } else if (size == 2) {
> +               if ((uintptr_t)addr & 1)
> +                       return PCIBIOS_BAD_REGISTER_NUMBER;
> +               writew(val, addr);
> +       } else if (size == 1)
> +               writeb(val, addr);
>         else
>                 return PCIBIOS_BAD_REGISTER_NUMBER;
>
> @@ -132,8 +145,7 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
>         if (pp->ops->rd_own_conf)
>                 ret = pp->ops->rd_own_conf(pp, where, size, val);
>         else
> -               ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
> -                               size, val);
> +               ret = dw_pcie_cfg_read(pp->dbi_base, where, size, val);
>
>         return ret;
>  }
> @@ -146,8 +158,7 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
>         if (pp->ops->wr_own_conf)
>                 ret = pp->ops->wr_own_conf(pp, where, size, val);
>         else
> -               ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
> -                               size, val);
> +               ret = dw_pcie_cfg_write(pp->dbi_base, where, size, val);
>
>         return ret;
>  }
> @@ -541,13 +552,12 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>                 u32 devfn, int where, int size, u32 *val)
>  {
>         int ret, type;
> -       u32 address, busdev, cfg_size;
> +       u32 busdev, cfg_size;
>         u64 cpu_addr;
>         void __iomem *va_cfg_base;
>
>         busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
>                  PCIE_ATU_FUNC(PCI_FUNC(devfn));
> -       address = where & ~0x3;
>
>         if (bus->parent->number == pp->root_bus_nr) {
>                 type = PCIE_ATU_TYPE_CFG0;
> @@ -564,7 +574,7 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>         dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
>                                   type, cpu_addr,
>                                   busdev, cfg_size);
> -       ret = dw_pcie_cfg_read(va_cfg_base + address, where, size, val);
> +       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_mod_base,
>                                   pp->io_bus_addr, pp->io_size);
> @@ -576,13 +586,12 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>                 u32 devfn, int where, int size, u32 val)
>  {
>         int ret, type;
> -       u32 address, busdev, cfg_size;
> +       u32 busdev, cfg_size;
>         u64 cpu_addr;
>         void __iomem *va_cfg_base;
>
>         busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
>                  PCIE_ATU_FUNC(PCI_FUNC(devfn));
> -       address = where & ~0x3;
>
>         if (bus->parent->number == pp->root_bus_nr) {
>                 type = PCIE_ATU_TYPE_CFG0;
> @@ -599,7 +608,7 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
>         dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
>                                   type, cpu_addr,
>                                   busdev, cfg_size);
> -       ret = dw_pcie_cfg_write(va_cfg_base + address, where, size, val);
> +       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_mod_base,
>                                   pp->io_bus_addr, pp->io_size);
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Gabriele Paoloni Sept. 10, 2015, 11:26 a.m. UTC | #3
Hi Bjorn, thanks for your comments

> -----Original Message-----

> From: Bjorn Helgaas [mailto:bhelgaas@google.com]

> Sent: Wednesday, September 09, 2015 8:45 PM

> To: Gabriele Paoloni

> Cc: Jingoo Han; Pratyush Anand Thakur; linux-pci@vger.kernel.org;

> Wangzhou (B); Yuanzhichang; Zhudacai; zhangjukuo; qiuzhenfa; Liguozhu

> (Kenneth)

> Subject: Re: [PATCH] PCI: designware: change dw_pcie_cfg_write() and

> dw_pcie_cfg_read()

> 

> Hi Gabriele,

> 

> On Wed, Sep 9, 2015 at 11:51 AM, Gabriele Paoloni

> <gabriele.paoloni@huawei.com> wrote:

> > From: gabriele paoloni <gabriele.paoloni@huawei.com>

> >

> > This patch changes the implementation of dw_pcie_cfg_read() and

> > dw_pcie_cfg_write() to:

> > - improve the function usage from the callers perspective;

> > - make sure that the callers specify proper address offsets

> >   according to the size of the field being read/written

> > - fix a bug in pcie-spear13xx.c where the callers where passing

> >   the wrong address as they missed to add the appropriate offset

> 

> Please split this into separate patches, so each patch does one thing,

> i.e., separate the "where" usage change from the "return

> PCIBIOS_BAD_REGISTER_NUMBER for bad offsets" change.


Ok I will send out a patchset with separate patches 

> 

> I think there was a separate patch for the pcie-spear13xx.c bug,

> wasn't there?  At least, I don't see that fix in *this* patch.

> 


From your previous comments:
********
*2) Pratyush, this one's for you :)  spear13xx_pcie_establish_link()
*   calls dw_pcie_cfg_read() and dw_pcie_cfg_write() several times like
*   this:
*
*    dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, ...)
*    dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, ...)
********

I think that the implementation of dw_pcie_cfg_read() and 
dw_pcie_cfg_write() that I proposed in this patch is compatible with
the previous calls in pcie-spear13xx.c. So the calls in pcie-spear13xx.c
were buggy for the previous implementations of the functions; with
the reworked functions there is no need to modify the function calls
in pcie-spear13xx.c...do you agree?

> > This patch is a follow up from the discussion in:

> > http://www.spinics.net/lists/linux-pci/msg44351.html

> >

> > Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>

> > ---

> >  drivers/pci/host/pci-exynos.c      |  5 ++--

> >  drivers/pci/host/pci-keystone-dw.c |  4 +--

> >  drivers/pci/host/pcie-designware.c | 51 ++++++++++++++++++++++------

> ----------

> >  3 files changed, 34 insertions(+), 26 deletions(-)

> >

> > diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-

> exynos.c

> > index f9f468d..8b0e04b 100644

> > --- a/drivers/pci/host/pci-exynos.c

> > +++ b/drivers/pci/host/pci-exynos.c

> > @@ -454,7 +454,7 @@ static int exynos_pcie_rd_own_conf(struct

> pcie_port *pp, int where, int size,

> >         int ret;

> >

> >         exynos_pcie_sideband_dbi_r_mode(pp, true);

> > -       ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,

> size, val);

> > +       ret = dw_pcie_cfg_read(pp->dbi_base, where, size, val);

> >         exynos_pcie_sideband_dbi_r_mode(pp, false);

> >         return ret;

> >  }

> > @@ -465,8 +465,7 @@ static int exynos_pcie_wr_own_conf(struct

> pcie_port *pp, int where, int size,

> >         int ret;

> >

> >         exynos_pcie_sideband_dbi_w_mode(pp, true);

> > -       ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),

> > -                       where, size, val);

> > +       ret = dw_pcie_cfg_write(pp->dbi_base, where, size, val);

> >         exynos_pcie_sideband_dbi_w_mode(pp, false);

> >         return ret;

> >  }

> > diff --git a/drivers/pci/host/pci-keystone-dw.c

> b/drivers/pci/host/pci-keystone-dw.c

> > index f34892e..2b391f4 100644

> > --- a/drivers/pci/host/pci-keystone-dw.c

> > +++ b/drivers/pci/host/pci-keystone-dw.c

> > @@ -403,7 +403,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp,

> struct pci_bus *bus,

> >

> >         addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);

> >

> > -       return dw_pcie_cfg_read(addr + (where & ~0x3), where, size,

> val);

> > +       return dw_pcie_cfg_read(addr, where, size, val);

> >  }

> >

> >  int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus

> *bus,

> > @@ -415,7 +415,7 @@ int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,

> struct pci_bus *bus,

> >

> >         addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);

> >

> > -       return dw_pcie_cfg_write(addr + (where & ~0x3), where, size,

> val);

> > +       return dw_pcie_cfg_write(addr, where, size, val);

> >  }

> >

> >  /**

> > diff --git a/drivers/pci/host/pcie-designware.c

> b/drivers/pci/host/pcie-designware.c

> > index 69486be..b53aa38 100644

> > --- a/drivers/pci/host/pcie-designware.c

> > +++ b/drivers/pci/host/pcie-designware.c

> > @@ -82,13 +82,20 @@ static inline struct pcie_port

> *sys_to_pcie(struct pci_sys_data *sys)

> >

> >  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32

> *val)

> >  {

> > +       addr += (where & ~0x3);

> >         *val = readl(addr);

> > -

> > -       if (size == 1)

> > -               *val = (*val >> (8 * (where & 3))) & 0xff;

> > -       else if (size == 2)

> > -               *val = (*val >> (8 * (where & 3))) & 0xffff;

> > -       else if (size != 4)

> > +       where &= 3;

> > +

> > +       if (size == 1) {

> > +               *val = (*val >> (8 * where)) & 0xff;

> > +       } else if (size == 2) {

> > +               if (where & 1)

> > +                       return PCIBIOS_BAD_REGISTER_NUMBER;

> > +               *val = (*val >> (8 * where)) & 0xffff;

> > +       } else if (size == 4) {

> > +               if (where & 3)

> > +                       return PCIBIOS_BAD_REGISTER_NUMBER;

> > +       } else

> >                 return PCIBIOS_BAD_REGISTER_NUMBER;

> >

> >         return PCIBIOS_SUCCESSFUL;

> > @@ -96,12 +103,18 @@ int dw_pcie_cfg_read(void __iomem *addr, int

> where, int size, u32 *val)

> >

> >  int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32

> val)

> >  {

> > -       if (size == 4)

> > +       addr += where;

> > +

> > +       if (size == 4) {

> > +               if ((uintptr_t)addr & 3)

> > +                       return PCIBIOS_BAD_REGISTER_NUMBER;

> >                 writel(val, addr);

> > -       else if (size == 2)

> > -               writew(val, addr + (where & 2));

> > -       else if (size == 1)

> > -               writeb(val, addr + (where & 3));

> > +       } else if (size == 2) {

> > +               if ((uintptr_t)addr & 1)

> > +                       return PCIBIOS_BAD_REGISTER_NUMBER;

> > +               writew(val, addr);

> > +       } else if (size == 1)

> > +               writeb(val, addr);

> >         else

> >                 return PCIBIOS_BAD_REGISTER_NUMBER;

> >

> > @@ -132,8 +145,7 @@ static int dw_pcie_rd_own_conf(struct pcie_port

> *pp, int where, int size,

> >         if (pp->ops->rd_own_conf)

> >                 ret = pp->ops->rd_own_conf(pp, where, size, val);

> >         else

> > -               ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3),

> where,

> > -                               size, val);

> > +               ret = dw_pcie_cfg_read(pp->dbi_base, where, size,

> val);

> >

> >         return ret;

> >  }

> > @@ -146,8 +158,7 @@ static int dw_pcie_wr_own_conf(struct pcie_port

> *pp, int where, int size,

> >         if (pp->ops->wr_own_conf)

> >                 ret = pp->ops->wr_own_conf(pp, where, size, val);

> >         else

> > -               ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),

> where,

> > -                               size, val);

> > +               ret = dw_pcie_cfg_write(pp->dbi_base, where, size,

> val);

> >

> >         return ret;

> >  }

> > @@ -541,13 +552,12 @@ static int dw_pcie_rd_other_conf(struct

> pcie_port *pp, struct pci_bus *bus,

> >                 u32 devfn, int where, int size, u32 *val)

> >  {

> >         int ret, type;

> > -       u32 address, busdev, cfg_size;

> > +       u32 busdev, cfg_size;

> >         u64 cpu_addr;

> >         void __iomem *va_cfg_base;

> >

> >         busdev = PCIE_ATU_BUS(bus->number) |

> PCIE_ATU_DEV(PCI_SLOT(devfn)) |

> >                  PCIE_ATU_FUNC(PCI_FUNC(devfn));

> > -       address = where & ~0x3;

> >

> >         if (bus->parent->number == pp->root_bus_nr) {

> >                 type = PCIE_ATU_TYPE_CFG0;

> > @@ -564,7 +574,7 @@ static int dw_pcie_rd_other_conf(struct pcie_port

> *pp, struct pci_bus *bus,

> >         dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,

> >                                   type, cpu_addr,

> >                                   busdev, cfg_size);

> > -       ret = dw_pcie_cfg_read(va_cfg_base + address, where, size,

> val);

> > +       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_mod_base,

> >                                   pp->io_bus_addr, pp->io_size);

> > @@ -576,13 +586,12 @@ static int dw_pcie_wr_other_conf(struct

> pcie_port *pp, struct pci_bus *bus,

> >                 u32 devfn, int where, int size, u32 val)

> >  {

> >         int ret, type;

> > -       u32 address, busdev, cfg_size;

> > +       u32 busdev, cfg_size;

> >         u64 cpu_addr;

> >         void __iomem *va_cfg_base;

> >

> >         busdev = PCIE_ATU_BUS(bus->number) |

> PCIE_ATU_DEV(PCI_SLOT(devfn)) |

> >                  PCIE_ATU_FUNC(PCI_FUNC(devfn));

> > -       address = where & ~0x3;

> >

> >         if (bus->parent->number == pp->root_bus_nr) {

> >                 type = PCIE_ATU_TYPE_CFG0;

> > @@ -599,7 +608,7 @@ static int dw_pcie_wr_other_conf(struct pcie_port

> *pp, struct pci_bus *bus,

> >         dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,

> >                                   type, cpu_addr,

> >                                   busdev, cfg_size);

> > -       ret = dw_pcie_cfg_write(va_cfg_base + address, where, size,

> val);

> > +       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_mod_base,

> >                                   pp->io_bus_addr, pp->io_size);

> > --

> > 1.9.1

> >

> > --

> > To unsubscribe from this list: send the line "unsubscribe linux-pci"

> in

> > the body of a message to majordomo@vger.kernel.org

> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjorn Helgaas Sept. 10, 2015, 12:39 p.m. UTC | #4
On Thu, Sep 10, 2015 at 6:26 AM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:
>> From: Bjorn Helgaas [mailto:bhelgaas@google.com]

>> I think there was a separate patch for the pcie-spear13xx.c bug,
>> wasn't there?  At least, I don't see that fix in *this* patch.
>>
>
> From your previous comments:
> ********
> *2) Pratyush, this one's for you :)  spear13xx_pcie_establish_link()
> *   calls dw_pcie_cfg_read() and dw_pcie_cfg_write() several times like
> *   this:
> *
> *    dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, ...)
> *    dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, ...)
> ********
>
> I think that the implementation of dw_pcie_cfg_read() and
> dw_pcie_cfg_write() that I proposed in this patch is compatible with
> the previous calls in pcie-spear13xx.c. So the calls in pcie-spear13xx.c
> were buggy for the previous implementations of the functions; with
> the reworked functions there is no need to modify the function calls
> in pcie-spear13xx.c...do you agree?

Oh, I see, I didn't read it closely enough, but you're probably right.
What I would probably do is apply Pratyush's fix first, then apply
your patch on top.  That way we can do the spear13xx bug fix by itself
(which should be a fairly obviously-correct patch), then your
interface change (which would be extended to touch all the calls
including spear13xx and be similarly obviously correct).  I think that
would make it a bit easier for future changelog archaeologists.

Bjorn
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Gabriele Paoloni Sept. 10, 2015, 1:06 p.m. UTC | #5
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQmpvcm4gSGVsZ2FhcyBb
bWFpbHRvOmJoZWxnYWFzQGdvb2dsZS5jb21dDQo+IFNlbnQ6IFRodXJzZGF5LCBTZXB0ZW1iZXIg
MTAsIDIwMTUgMTo0MCBQTQ0KPiBUbzogR2FicmllbGUgUGFvbG9uaQ0KPiBDYzogSmluZ29vIEhh
bjsgUHJhdHl1c2ggQW5hbmQgVGhha3VyOyBsaW51eC1wY2lAdmdlci5rZXJuZWwub3JnOw0KPiBX
YW5nemhvdSAoQik7IFl1YW56aGljaGFuZzsgWmh1ZGFjYWk7IHpoYW5nanVrdW87IHFpdXpoZW5m
YTsgTGlndW96aHUNCj4gKEtlbm5ldGgpDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0hdIFBDSTogZGVz
aWdud2FyZTogY2hhbmdlIGR3X3BjaWVfY2ZnX3dyaXRlKCkgYW5kDQo+IGR3X3BjaWVfY2ZnX3Jl
YWQoKQ0KPiANCj4gT24gVGh1LCBTZXAgMTAsIDIwMTUgYXQgNjoyNiBBTSwgR2FicmllbGUgUGFv
bG9uaQ0KPiA8Z2FicmllbGUucGFvbG9uaUBodWF3ZWkuY29tPiB3cm90ZToNCj4gPj4gRnJvbTog
Qmpvcm4gSGVsZ2FhcyBbbWFpbHRvOmJoZWxnYWFzQGdvb2dsZS5jb21dDQo+IA0KPiA+PiBJIHRo
aW5rIHRoZXJlIHdhcyBhIHNlcGFyYXRlIHBhdGNoIGZvciB0aGUgcGNpZS1zcGVhcjEzeHguYyBi
dWcsDQo+ID4+IHdhc24ndCB0aGVyZT8gIEF0IGxlYXN0LCBJIGRvbid0IHNlZSB0aGF0IGZpeCBp
biAqdGhpcyogcGF0Y2guDQo+ID4+DQo+ID4NCj4gPiBGcm9tIHlvdXIgcHJldmlvdXMgY29tbWVu
dHM6DQo+ID4gKioqKioqKioNCj4gPiAqMikgUHJhdHl1c2gsIHRoaXMgb25lJ3MgZm9yIHlvdSA6
KSAgc3BlYXIxM3h4X3BjaWVfZXN0YWJsaXNoX2xpbmsoKQ0KPiA+ICogICBjYWxscyBkd19wY2ll
X2NmZ19yZWFkKCkgYW5kIGR3X3BjaWVfY2ZnX3dyaXRlKCkgc2V2ZXJhbCB0aW1lcw0KPiBsaWtl
DQo+ID4gKiAgIHRoaXM6DQo+ID4gKg0KPiA+ICogICAgZHdfcGNpZV9jZmdfcmVhZChwcC0+ZGJp
X2Jhc2UsIGV4cF9jYXBfb2ZmICsgUENJX0VYUF9ERVZDVEwsDQo+IDQsIC4uLikNCj4gPiAqICAg
IGR3X3BjaWVfY2ZnX3dyaXRlKHBwLT5kYmlfYmFzZSwgZXhwX2NhcF9vZmYgKyBQQ0lfRVhQX0RF
VkNUTCwNCj4gNCwgLi4uKQ0KPiA+ICoqKioqKioqDQo+ID4NCj4gPiBJIHRoaW5rIHRoYXQgdGhl
IGltcGxlbWVudGF0aW9uIG9mIGR3X3BjaWVfY2ZnX3JlYWQoKSBhbmQNCj4gPiBkd19wY2llX2Nm
Z193cml0ZSgpIHRoYXQgSSBwcm9wb3NlZCBpbiB0aGlzIHBhdGNoIGlzIGNvbXBhdGlibGUgd2l0
aA0KPiA+IHRoZSBwcmV2aW91cyBjYWxscyBpbiBwY2llLXNwZWFyMTN4eC5jLiBTbyB0aGUgY2Fs
bHMgaW4gcGNpZS0NCj4gc3BlYXIxM3h4LmMNCj4gPiB3ZXJlIGJ1Z2d5IGZvciB0aGUgcHJldmlv
dXMgaW1wbGVtZW50YXRpb25zIG9mIHRoZSBmdW5jdGlvbnM7IHdpdGgNCj4gPiB0aGUgcmV3b3Jr
ZWQgZnVuY3Rpb25zIHRoZXJlIGlzIG5vIG5lZWQgdG8gbW9kaWZ5IHRoZSBmdW5jdGlvbiBjYWxs
cw0KPiA+IGluIHBjaWUtc3BlYXIxM3h4LmMuLi5kbyB5b3UgYWdyZWU/DQo+IA0KPiBPaCwgSSBz
ZWUsIEkgZGlkbid0IHJlYWQgaXQgY2xvc2VseSBlbm91Z2gsIGJ1dCB5b3UncmUgcHJvYmFibHkg
cmlnaHQuDQo+IFdoYXQgSSB3b3VsZCBwcm9iYWJseSBkbyBpcyBhcHBseSBQcmF0eXVzaCdzIGZp
eCBmaXJzdCwgdGhlbiBhcHBseQ0KPiB5b3VyIHBhdGNoIG9uIHRvcC4gIFRoYXQgd2F5IHdlIGNh
biBkbyB0aGUgc3BlYXIxM3h4IGJ1ZyBmaXggYnkgaXRzZWxmDQo+ICh3aGljaCBzaG91bGQgYmUg
YSBmYWlybHkgb2J2aW91c2x5LWNvcnJlY3QgcGF0Y2gpLCB0aGVuIHlvdXINCj4gaW50ZXJmYWNl
IGNoYW5nZSAod2hpY2ggd291bGQgYmUgZXh0ZW5kZWQgdG8gdG91Y2ggYWxsIHRoZSBjYWxscw0K
PiBpbmNsdWRpbmcgc3BlYXIxM3h4IGFuZCBiZSBzaW1pbGFybHkgb2J2aW91c2x5IGNvcnJlY3Qp
LiAgSSB0aGluayB0aGF0DQo+IHdvdWxkIG1ha2UgaXQgYSBiaXQgZWFzaWVyIGZvciBmdXR1cmUg
Y2hhbmdlbG9nIGFyY2hhZW9sb2dpc3RzLg0KDQpTaW5jZSBQcmF0eXVzaCBoYXMgbm90IHB1c2hl
ZCB0aGUgZml4IHlldCwgbWF5YmUgSSBjYW4gcHJlcGFyZSBhIHYyIGFzIA0KYSBwYXRjaHNldCBv
ZiAyIHBhdGNoZXMuLi4uDQoodG8gYmVuZWZpdCB0aGUgTGludXggYXJjaGVvbG9naXN0cyBhcyB5
b3Ugc2FpZCA6LSkgKQ0KDQo+IA0KPiBCam9ybg0K
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index f9f468d..8b0e04b 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -454,7 +454,7 @@  static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
 	int ret;
 
 	exynos_pcie_sideband_dbi_r_mode(pp, true);
-	ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
+	ret = dw_pcie_cfg_read(pp->dbi_base, where, size, val);
 	exynos_pcie_sideband_dbi_r_mode(pp, false);
 	return ret;
 }
@@ -465,8 +465,7 @@  static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
 	int ret;
 
 	exynos_pcie_sideband_dbi_w_mode(pp, true);
-	ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
-			where, size, val);
+	ret = dw_pcie_cfg_write(pp->dbi_base, where, size, val);
 	exynos_pcie_sideband_dbi_w_mode(pp, false);
 	return ret;
 }
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
index f34892e..2b391f4 100644
--- a/drivers/pci/host/pci-keystone-dw.c
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -403,7 +403,7 @@  int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 
 	addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
 
-	return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+	return dw_pcie_cfg_read(addr, where, size, val);
 }
 
 int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
@@ -415,7 +415,7 @@  int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 
 	addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
 
-	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+	return dw_pcie_cfg_write(addr, where, size, val);
 }
 
 /**
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 69486be..b53aa38 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -82,13 +82,20 @@  static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
 {
+	addr += (where & ~0x3);
 	*val = readl(addr);
-
-	if (size == 1)
-		*val = (*val >> (8 * (where & 3))) & 0xff;
-	else if (size == 2)
-		*val = (*val >> (8 * (where & 3))) & 0xffff;
-	else if (size != 4)
+	where &= 3;
+
+	if (size == 1) {
+		*val = (*val >> (8 * where)) & 0xff;
+	} else if (size == 2) {
+		if (where & 1)
+			return PCIBIOS_BAD_REGISTER_NUMBER;
+		*val = (*val >> (8 * where)) & 0xffff;
+	} else if (size == 4) {
+		if (where & 3)
+			return PCIBIOS_BAD_REGISTER_NUMBER;
+	} else
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
 	return PCIBIOS_SUCCESSFUL;
@@ -96,12 +103,18 @@  int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
 
 int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
 {
-	if (size == 4)
+	addr += where;
+
+	if (size == 4) {
+		if ((uintptr_t)addr & 3)
+			return PCIBIOS_BAD_REGISTER_NUMBER;
 		writel(val, addr);
-	else if (size == 2)
-		writew(val, addr + (where & 2));
-	else if (size == 1)
-		writeb(val, addr + (where & 3));
+	} else if (size == 2) {
+		if ((uintptr_t)addr & 1)
+			return PCIBIOS_BAD_REGISTER_NUMBER;
+		writew(val, addr);
+	} else if (size == 1)
+		writeb(val, addr);
 	else
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -132,8 +145,7 @@  static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
 	if (pp->ops->rd_own_conf)
 		ret = pp->ops->rd_own_conf(pp, where, size, val);
 	else
-		ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
-				size, val);
+		ret = dw_pcie_cfg_read(pp->dbi_base, where, size, val);
 
 	return ret;
 }
@@ -146,8 +158,7 @@  static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
 	if (pp->ops->wr_own_conf)
 		ret = pp->ops->wr_own_conf(pp, where, size, val);
 	else
-		ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
-				size, val);
+		ret = dw_pcie_cfg_write(pp->dbi_base, where, size, val);
 
 	return ret;
 }
@@ -541,13 +552,12 @@  static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 		u32 devfn, int where, int size, u32 *val)
 {
 	int ret, type;
-	u32 address, busdev, cfg_size;
+	u32 busdev, cfg_size;
 	u64 cpu_addr;
 	void __iomem *va_cfg_base;
 
 	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
 		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-	address = where & ~0x3;
 
 	if (bus->parent->number == pp->root_bus_nr) {
 		type = PCIE_ATU_TYPE_CFG0;
@@ -564,7 +574,7 @@  static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
 				  type, cpu_addr,
 				  busdev, cfg_size);
-	ret = dw_pcie_cfg_read(va_cfg_base + address, where, size, val);
+	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_mod_base,
 				  pp->io_bus_addr, pp->io_size);
@@ -576,13 +586,12 @@  static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 		u32 devfn, int where, int size, u32 val)
 {
 	int ret, type;
-	u32 address, busdev, cfg_size;
+	u32 busdev, cfg_size;
 	u64 cpu_addr;
 	void __iomem *va_cfg_base;
 
 	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
 		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-	address = where & ~0x3;
 
 	if (bus->parent->number == pp->root_bus_nr) {
 		type = PCIE_ATU_TYPE_CFG0;
@@ -599,7 +608,7 @@  static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 	dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
 				  type, cpu_addr,
 				  busdev, cfg_size);
-	ret = dw_pcie_cfg_write(va_cfg_base + address, where, size, val);
+	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_mod_base,
 				  pp->io_bus_addr, pp->io_size);