linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
@ 2015-09-29 16:20 Gabriele Paoloni
  2015-09-29 16:20 ` [PATCH v6 1/3] PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage Gabriele Paoloni
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Gabriele Paoloni @ 2015-09-29 16:20 UTC (permalink / raw)
  To: bhelgaas, jingoohan1, pratyush.anand
  Cc: linux-pci, gabriele.paoloni, wangzhou1, yuanzhichang, zhudacai,
	zhangjukuo, qiuzhenfa, liguozhu

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

This patchset:
1) fixes a bug in spear13xx when calling dw_pcie_cfg_read and
   dw_pcie_cfg_write usign the patch from Pratyush in
   https://lkml.org/lkml/2015/9/7/5
2) reworks dw_pcie_cfg_read/dw_pcie_cfg_write in pcie-designware.c in
   order to make it easier for callers to pass input parameters;
3) changes dw_pcie_cfg_read implementation to make it symmetric with
   dw_pcie_cfg_write 
4) adds sanity checks in dw_pcie_cfg_read/dw_pcie_cfg_write to make
   sure the PCI header offset does not conflict with the size of
   the read/written field.

Changes from v5: sanity check readibility simplified

Changes from v4:
   - included https://lkml.org/lkml/2015/9/7/5 back as it was lost in v4

Changes from v3:
   - changed dw_pcie_cfg_read implementation to make it symmetric with
     dw_pcie_cfg_write
   - changed dw_pcie_cfg_read/dw_pcie_cfg_write implementations to take
     as input param directly the address of the field to read/write rather
     than the base address and the offset in the PCI header

Change from v2:
   Replaced patch 1/3 with Pratyush one in
   https://lkml.org/lkml/2015/9/7/5

gabriele paoloni (3):
  PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage
  PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
  PCI: designware: add sanity checks on the header offset in
    dw_pcie_cfg_read and dw_pcie_cfg_write

 drivers/pci/host/pci-exynos.c      |  5 ++---
 drivers/pci/host/pci-keystone-dw.c |  4 ++--
 drivers/pci/host/pcie-designware.c | 40 ++++++++++++++++++++------------------
 drivers/pci/host/pcie-designware.h |  4 ++--
 drivers/pci/host/pcie-spear13xx.c  | 24 +++++++++++------------
 5 files changed, 39 insertions(+), 38 deletions(-)

-- 
1.9.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v6 1/3] PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage
  2015-09-29 16:20 [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
@ 2015-09-29 16:20 ` Gabriele Paoloni
  2015-09-29 16:20 ` [PATCH v6 2/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Gabriele Paoloni @ 2015-09-29 16:20 UTC (permalink / raw)
  To: bhelgaas, jingoohan1, pratyush.anand
  Cc: linux-pci, gabriele.paoloni, wangzhou1, yuanzhichang, zhudacai,
	zhangjukuo, qiuzhenfa, liguozhu, Pratyush Anand

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

w_pcie_cfg_read/write() expects 1st argument 'addr' as a 32 bit word
aligned address, 2nd argument 'where' as the offset within that word(0, 1,
2 or 3) and 3rd argument 'size' is the number of bytes need to be read at
the offset(could be 1, 2 ,4).

SPEAr13xx is using dw_pcie_cfg_read() and dw_pcie_cfg_write() incorrectly.
Without this fix, SPEAr13xx host will never work with  few buggy gen1 card
which connects with only gen1 host and also with any endpoint which would
generate a read request of more than 128 bytes.

Cc: stable@vger.kernel.org # v3.17+
Signed-off-by: Pratyush Anand <panand@redhat.com>
Reported-by: Bjorn Helgaas <bhelgaas@google.com>
---
 drivers/pci/host/pcie-spear13xx.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index 98d2683..0754ea3 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -163,34 +163,36 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
 	 * default value in capability register is 512 bytes. So force
 	 * it to 128 here.
 	 */
-	dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val);
+	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
+				0, 2, &val);
 	val &= ~PCI_EXP_DEVCTL_READRQ;
-	dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val);
+	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
+				0, 2, val);
 
-	dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A);
-	dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 0, 2, 0x104A);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 2, 0xCD80);
 
 	/*
 	 * if is_gen1 is set then handle it, so that some buggy card
 	 * also works
 	 */
 	if (spear13xx_pcie->is_gen1) {
-		dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4,
-				 &val);
+		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
+					0, 4, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-			dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-					  PCI_EXP_LNKCAP, 4, val);
+			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+						PCI_EXP_LNKCAP, 0, 4, val);
 		}
 
-		dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4,
-				 &val);
+		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
+					0, 2, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-			dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-					  PCI_EXP_LNKCTL2, 4, val);
+			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+						PCI_EXP_LNKCTL2, 0, 2, val);
 		}
 	}
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v6 2/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
  2015-09-29 16:20 [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
  2015-09-29 16:20 ` [PATCH v6 1/3] PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage Gabriele Paoloni
@ 2015-09-29 16:20 ` Gabriele Paoloni
  2015-09-29 16:20 ` [PATCH v6 3/3] PCI: designware: add sanity checks on the header offset in dw_pcie_cfg_read and dw_pcie_cfg_write Gabriele Paoloni
  2015-10-08 19:25 ` [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Bjorn Helgaas
  3 siblings, 0 replies; 7+ messages in thread
From: Gabriele Paoloni @ 2015-09-29 16:20 UTC (permalink / raw)
  To: bhelgaas, jingoohan1, pratyush.anand
  Cc: linux-pci, gabriele.paoloni, wangzhou1, yuanzhichang, zhudacai,
	zhangjukuo, qiuzhenfa, liguozhu

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.
Currently the callers are obliged to pass the 32bit aligned address
of the register that contains the field of the PCI header that they
want to read/write; also they have to pass the offset of the field
in that register. This is quite tricky to use as the callers are
obliged to sum the PCI header base address to the field offset
masked to retrieve the 32b aligned register address.

With the new API the callers have to pass directly the address of the
field they intend to read/write in the PCI header: so once they have
the base address of the PCI header they will just sum up the offset
of the field they intend to access and pass the sum to the functions'
addr field.

This patch also changes the implementation of dw_pcie_cfg_read to
make it symmetric with dw_pcie_cfg_write.

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 | 36 ++++++++++++++++--------------------
 drivers/pci/host/pcie-designware.h |  4 ++--
 drivers/pci/host/pcie-spear13xx.c  | 18 ++++++++----------
 5 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index f9f468d..01095e1 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 e71da99..51789b7 100644
--- a/drivers/pci/host/pci-keystone-dw.c
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -398,7 +398,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,
@@ -410,7 +410,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 52aa6e3..d771fa5 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -80,28 +80,28 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 	return sys->private_data;
 }
 
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 {
-	*val = readl(addr);
-
-	if (size == 1)
-		*val = (*val >> (8 * (where & 3))) & 0xff;
+	if (size == 4)
+		*val = readl(addr);
 	else if (size == 2)
-		*val = (*val >> (8 * (where & 3))) & 0xffff;
-	else if (size != 4)
+		*val = readw(addr);
+	else if (size == 1)
+		*val = readb(addr);
+	else
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 {
 	if (size == 4)
 		writel(val, addr);
 	else if (size == 2)
-		writew(val, addr + (where & 2));
+		writew(val, addr);
 	else if (size == 1)
-		writeb(val, addr + (where & 3));
+		writeb(val, addr);
 	else
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -132,8 +132,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 +145,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;
 }
@@ -539,13 +537,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;
@@ -562,7 +559,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);
@@ -574,13 +571,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;
@@ -597,7 +593,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);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index d0bbd27..0b29194 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -76,8 +76,8 @@ struct pcie_host_ops {
 	int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
 };
 
-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);
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index 0754ea3..b95b756 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -163,14 +163,12 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
 	 * default value in capability register is 512 bytes. So force
 	 * it to 128 here.
 	 */
-	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
-				0, 2, &val);
+	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
 	val &= ~PCI_EXP_DEVCTL_READRQ;
-	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
-				0, 2, val);
+	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
 
-	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 0, 2, 0x104A);
-	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 2, 0xCD80);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
 
 	/*
 	 * if is_gen1 is set then handle it, so that some buggy card
@@ -178,21 +176,21 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
 	 */
 	if (spear13xx_pcie->is_gen1) {
 		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
-					0, 4, &val);
+					4, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
 			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
-						PCI_EXP_LNKCAP, 0, 4, val);
+				PCI_EXP_LNKCAP, 4, val);
 		}
 
 		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
-					0, 2, &val);
+					2, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
 			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
-						PCI_EXP_LNKCTL2, 0, 2, val);
+					PCI_EXP_LNKCTL2, 2, val);
 		}
 	}
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v6 3/3] PCI: designware: add sanity checks on the header offset in dw_pcie_cfg_read and dw_pcie_cfg_write
  2015-09-29 16:20 [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
  2015-09-29 16:20 ` [PATCH v6 1/3] PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage Gabriele Paoloni
  2015-09-29 16:20 ` [PATCH v6 2/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
@ 2015-09-29 16:20 ` Gabriele Paoloni
  2015-09-29 16:37   ` Pratyush Anand
  2015-10-08 19:25 ` [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Bjorn Helgaas
  3 siblings, 1 reply; 7+ messages in thread
From: Gabriele Paoloni @ 2015-09-29 16:20 UTC (permalink / raw)
  To: bhelgaas, jingoohan1, pratyush.anand
  Cc: linux-pci, gabriele.paoloni, wangzhou1, yuanzhichang, zhudacai,
	zhangjukuo, qiuzhenfa, liguozhu

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

This patch adds sanity checks on "where" input parameter in
dw_pcie_cfg_read and dw_pcie_cfg_write. These checks make sure
that offset passed in by the caller is not in conflict with
the size of the PCI header field that is being read/written

Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
---
 drivers/pci/host/pcie-designware.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index d771fa5..43beaf3 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -82,6 +82,9 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 
 int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 {
+	if ((uintptr_t)addr & (size - 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
 	if (size == 4)
 		*val = readl(addr);
 	else if (size == 2)
@@ -96,6 +99,9 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 
 int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 {
+	if ((uintptr_t)addr & (size - 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
 	if (size == 4)
 		writel(val, addr);
 	else if (size == 2)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v6 3/3] PCI: designware: add sanity checks on the header offset in dw_pcie_cfg_read and dw_pcie_cfg_write
  2015-09-29 16:20 ` [PATCH v6 3/3] PCI: designware: add sanity checks on the header offset in dw_pcie_cfg_read and dw_pcie_cfg_write Gabriele Paoloni
@ 2015-09-29 16:37   ` Pratyush Anand
  0 siblings, 0 replies; 7+ messages in thread
From: Pratyush Anand @ 2015-09-29 16:37 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: Bjorn Helgaas, Jingoo Han, linux-pci@vger.kernel.org, Zhou Wang,
	Zhichang Yuan, zhudacai, Zhang Jukuo, qiuzhenfa, Liguozhu

On Tue, Sep 29, 2015 at 9:50 PM, Gabriele Paoloni
<gabriele.paoloni@huawei.com> wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
>
> This patch adds sanity checks on "where" input parameter in
> dw_pcie_cfg_read and dw_pcie_cfg_write. These checks make sure
> that offset passed in by the caller is not in conflict with
> the size of the PCI header field that is being read/written
>
> Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>

Acked-by: Pratyush Anand <pratyush.anand@gmail.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
  2015-09-29 16:20 [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
                   ` (2 preceding siblings ...)
  2015-09-29 16:20 ` [PATCH v6 3/3] PCI: designware: add sanity checks on the header offset in dw_pcie_cfg_read and dw_pcie_cfg_write Gabriele Paoloni
@ 2015-10-08 19:25 ` Bjorn Helgaas
  2015-10-09  6:37   ` Gabriele Paoloni
  3 siblings, 1 reply; 7+ messages in thread
From: Bjorn Helgaas @ 2015-10-08 19:25 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: bhelgaas, jingoohan1, pratyush.anand, linux-pci, wangzhou1,
	yuanzhichang, zhudacai, zhangjukuo, qiuzhenfa, liguozhu

On Wed, Sep 30, 2015 at 12:20:33AM +0800, Gabriele Paoloni wrote:
> From: gabriele paoloni <gabriele.paoloni@huawei.com>
> 
> This patchset:
> 1) fixes a bug in spear13xx when calling dw_pcie_cfg_read and
>    dw_pcie_cfg_write usign the patch from Pratyush in
>    https://lkml.org/lkml/2015/9/7/5
> 2) reworks dw_pcie_cfg_read/dw_pcie_cfg_write in pcie-designware.c in
>    order to make it easier for callers to pass input parameters;
> 3) changes dw_pcie_cfg_read implementation to make it symmetric with
>    dw_pcie_cfg_write 
> 4) adds sanity checks in dw_pcie_cfg_read/dw_pcie_cfg_write to make
>    sure the PCI header offset does not conflict with the size of
>    the read/written field.
> 
> Changes from v5: sanity check readibility simplified
> 
> Changes from v4:
>    - included https://lkml.org/lkml/2015/9/7/5 back as it was lost in v4
> 
> Changes from v3:
>    - changed dw_pcie_cfg_read implementation to make it symmetric with
>      dw_pcie_cfg_write
>    - changed dw_pcie_cfg_read/dw_pcie_cfg_write implementations to take
>      as input param directly the address of the field to read/write rather
>      than the base address and the offset in the PCI header
> 
> Change from v2:
>    Replaced patch 1/3 with Pratyush one in
>    https://lkml.org/lkml/2015/9/7/5
> 
> gabriele paoloni (3):
>   PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage
>   PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
>   PCI: designware: add sanity checks on the header offset in
>     dw_pcie_cfg_read and dw_pcie_cfg_write

Applied to pci/host-designware for v4.4.  I tweaked a couple things:

  - Split out the dw_pcie_cfg_read() access size change into its own
    patch.  This is an important change that got obscured by being
    combined with the interface change.  Splitting it out makes both
    patches much easier to review.

  - In dw_pcie_cfg_read(), I set *val to zero when we return failure.
    Previously we always set "*val = readl(addr)" even if we later
    returned failure.  That could have been garbage or a misaligned
    read.

Below are the patches as I applied them.  Thanks!

Bjorn


commit 0951120a4c778cf043497e4af508588417bef29a
Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Date:   Wed Sep 30 00:20:34 2015 +0800

    PCI: spear: Fix dw_pcie_cfg_read/write() usage
    
    The first argument of dw_pcie_cfg_read/write() is a 32-bit aligned address.
    The second argument is the byte offset into a 32-bit word, and
    dw_pcie_cfg_read/write() only look at the low two bits.
    
    SPEAr13xx used dw_pcie_cfg_read() and dw_pcie_cfg_write() incorrectly: it
    passed important address bits in the second argument, where they were
    ignored.
    
    Pass the complete 32-bit word address in the first argument and only the
    2-bit offset into that word in the second argument.
    
    Without this fix, SPEAr13xx host will never work with few buggy gen1 card
    which connects with only gen1 host and also with any endpoint which would
    generate a read request of more than 128 bytes.
    
    [bhelgaas: changelog]
    Reported-by: Bjorn Helgaas <bhelgaas@google.com>
    Signed-off-by: Pratyush Anand <panand@redhat.com>
    Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
    CC: stable@vger.kernel.org	# v3.17+

diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index 98d2683..0754ea3 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -163,34 +163,36 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
 	 * default value in capability register is 512 bytes. So force
 	 * it to 128 here.
 	 */
-	dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val);
+	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
+				0, 2, &val);
 	val &= ~PCI_EXP_DEVCTL_READRQ;
-	dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val);
+	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
+				0, 2, val);
 
-	dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A);
-	dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 0, 2, 0x104A);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 2, 0xCD80);
 
 	/*
 	 * if is_gen1 is set then handle it, so that some buggy card
 	 * also works
 	 */
 	if (spear13xx_pcie->is_gen1) {
-		dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4,
-				 &val);
+		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
+					0, 4, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-			dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-					  PCI_EXP_LNKCAP, 4, val);
+			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+						PCI_EXP_LNKCAP, 0, 4, val);
 		}
 
-		dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4,
-				 &val);
+		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
+					0, 2, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-			dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-					  PCI_EXP_LNKCTL2, 4, val);
+			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+						PCI_EXP_LNKCTL2, 0, 2, val);
 		}
 	}
 

commit 6e5d5205ccb07c95931412f1e6fdb9ec5abc8dfd
Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Date:   Thu Oct 8 11:45:41 2015 -0500

    PCI: designware: Use exact access size in dw_pcie_cfg_read()
    
    dw_pcie_cfg_write() uses the exact 8-, 16-, or 32-bit access size
    requested, but dw_pcie_cfg_read() previously performed a 32-bit read and
    masked out the bits requested.
    
    Use the exact access size in dw_pcie_cfg_read().  For example, if we want
    an 8-bit read, use readb() instead of using readl() and masking out the 8
    bits we need.  This makes it symmetric with dw_pcie_cfg_write().
    
    [bhelgaas: split into separate patch, set *val = 0 in failure case]
    Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
    Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 52aa6e3..9073722 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -82,14 +82,16 @@ 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)
 {
-	*val = readl(addr);
-
-	if (size == 1)
-		*val = (*val >> (8 * (where & 3))) & 0xff;
+	if (size == 4)
+		*val = readl(addr);
 	else if (size == 2)
-		*val = (*val >> (8 * (where & 3))) & 0xffff;
-	else if (size != 4)
+		*val = readw(addr + (where & 2));
+	else if (size == 1)
+		*val = readb(addr + (where & 1));
+	else {
+		*val = 0;
 		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
 
 	return PCIBIOS_SUCCESSFUL;
 }

commit 060ca07e0d22f150d237e8d8e7149a88c3055e9a
Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Date:   Wed Sep 30 00:20:35 2015 +0800

    PCI: designware: Simplify dw_pcie_cfg_read/write() interfaces
    
    Callers of dw_pcie_cfg_read() and dw_pcie_cfg_write() previously had to
    split the address into "addr" and "where".  The callees assumed "addr" was
    32-bit aligned (with zeros in the low two bits) and they used only the low
    two bits of "where".
    
    Accept the entire address in "addr" and drop the now-redundant "where"
    argument.  As an example, this replaces this:
    
      int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
        *val = readb(addr + (where & 1));
    
    with this:
    
      int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
        *val = readb(addr):
    
    [bhelgaas: changelog, split access size change to separate patch]
    Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
    Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index f9f468d..01095e1 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 e71da99..51789b7 100644
--- a/drivers/pci/host/pci-keystone-dw.c
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -398,7 +398,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,
@@ -410,7 +410,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 9073722..a7d2352 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -80,14 +80,14 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 	return sys->private_data;
 }
 
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 {
 	if (size == 4)
 		*val = readl(addr);
 	else if (size == 2)
-		*val = readw(addr + (where & 2));
+		*val = readw(addr);
 	else if (size == 1)
-		*val = readb(addr + (where & 1));
+		*val = readb(addr);
 	else {
 		*val = 0;
 		return PCIBIOS_BAD_REGISTER_NUMBER;
@@ -96,14 +96,14 @@ int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 {
 	if (size == 4)
 		writel(val, addr);
 	else if (size == 2)
-		writew(val, addr + (where & 2));
+		writew(val, addr);
 	else if (size == 1)
-		writeb(val, addr + (where & 3));
+		writeb(val, addr);
 	else
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -134,8 +134,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;
 }
@@ -148,8 +147,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 +539,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 +561,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 +573,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 +595,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);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index d0bbd27..0b29194 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -76,8 +76,8 @@ struct pcie_host_ops {
 	int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
 };
 
-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);
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index 0754ea3..b95b756 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -163,14 +163,12 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
 	 * default value in capability register is 512 bytes. So force
 	 * it to 128 here.
 	 */
-	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
-				0, 2, &val);
+	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
 	val &= ~PCI_EXP_DEVCTL_READRQ;
-	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
-				0, 2, val);
+	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
 
-	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 0, 2, 0x104A);
-	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 2, 0xCD80);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
+	dw_pcie_cfg_write(pp->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
 
 	/*
 	 * if is_gen1 is set then handle it, so that some buggy card
@@ -178,21 +176,21 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
 	 */
 	if (spear13xx_pcie->is_gen1) {
 		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
-					0, 4, &val);
+					4, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
 			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
-						PCI_EXP_LNKCAP, 0, 4, val);
+				PCI_EXP_LNKCAP, 4, val);
 		}
 
 		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
-					0, 2, &val);
+					2, &val);
 		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
 			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
 			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
 			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
-						PCI_EXP_LNKCTL2, 0, 2, val);
+					PCI_EXP_LNKCTL2, 2, val);
 		}
 	}
 

commit 08a79800db364aabe4422ac4f2e2efdf450e1c31
Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
Date:   Wed Sep 30 00:20:36 2015 +0800

    PCI: designware: Require config accesses to be naturally aligned
    
    Add sanity checks on "addr" input parameter in dw_pcie_cfg_read() and
    dw_pcie_cfg_write().  These checks make sure that accesses are aligned on
    their size, e.g., a 4-byte config access is aligned on a 4-byte boundary.
    
    [bhelgaas: changelog, set *val = 0 in failure case]
    Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
    Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
    Acked-by: Pratyush Anand <pratyush.anand@gmail.com>

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index a7d2352..6a71f99 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -82,6 +82,11 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 
 int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 {
+	if ((uintptr_t)addr & (size - 1)) {
+		*val = 0;
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
 	if (size == 4)
 		*val = readl(addr);
 	else if (size == 2)
@@ -98,6 +103,9 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 
 int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 {
+	if ((uintptr_t)addr & (size - 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
 	if (size == 4)
 		writel(val, addr);
 	else if (size == 2)

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* RE: [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
  2015-10-08 19:25 ` [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Bjorn Helgaas
@ 2015-10-09  6:37   ` Gabriele Paoloni
  0 siblings, 0 replies; 7+ messages in thread
From: Gabriele Paoloni @ 2015-10-09  6:37 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: bhelgaas@google.com, jingoohan1@gmail.com,
	pratyush.anand@gmail.com, linux-pci@vger.kernel.org, Wangzhou (B),
	Yuanzhichang, Zhudacai, zhangjukuo, qiuzhenfa, Liguozhu (Kenneth)

> -----Original Message-----
> From: Bjorn Helgaas [mailto:helgaas@kernel.org]
> Sent: 08 October 2015 20:26
> To: Gabriele Paoloni
> Cc: bhelgaas@google.com; jingoohan1@gmail.com; pratyush.anand@gmail.com;
> linux-pci@vger.kernel.org; Wangzhou (B); Yuanzhichang; Zhudacai; zhangjukuo;
> qiuzhenfa; Liguozhu (Kenneth)
> Subject: Re: [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and
> dw_pcie_cfg_read()
> 
> On Wed, Sep 30, 2015 at 12:20:33AM +0800, Gabriele Paoloni wrote:
> > From: gabriele paoloni <gabriele.paoloni@huawei.com>
> >
> > This patchset:
> > 1) fixes a bug in spear13xx when calling dw_pcie_cfg_read and
> >    dw_pcie_cfg_write usign the patch from Pratyush in
> >    https://lkml.org/lkml/2015/9/7/5
> > 2) reworks dw_pcie_cfg_read/dw_pcie_cfg_write in pcie-designware.c in
> >    order to make it easier for callers to pass input parameters;
> > 3) changes dw_pcie_cfg_read implementation to make it symmetric with
> >    dw_pcie_cfg_write
> > 4) adds sanity checks in dw_pcie_cfg_read/dw_pcie_cfg_write to make
> >    sure the PCI header offset does not conflict with the size of
> >    the read/written field.
> >
> > Changes from v5: sanity check readibility simplified
> >
> > Changes from v4:
> >    - included https://lkml.org/lkml/2015/9/7/5 back as it was lost in v4
> >
> > Changes from v3:
> >    - changed dw_pcie_cfg_read implementation to make it symmetric with
> >      dw_pcie_cfg_write
> >    - changed dw_pcie_cfg_read/dw_pcie_cfg_write implementations to take
> >      as input param directly the address of the field to read/write rather
> >      than the base address and the offset in the PCI header
> >
> > Change from v2:
> >    Replaced patch 1/3 with Pratyush one in
> >    https://lkml.org/lkml/2015/9/7/5
> >
> > gabriele paoloni (3):
> >   PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage
> >   PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read()
> >   PCI: designware: add sanity checks on the header offset in
> >     dw_pcie_cfg_read and dw_pcie_cfg_write
> 
> Applied to pci/host-designware for v4.4.  I tweaked a couple things:

Great Many Thanks Bjorn!

> 
>   - Split out the dw_pcie_cfg_read() access size change into its own
>     patch.  This is an important change that got obscured by being
>     combined with the interface change.  Splitting it out makes both
>     patches much easier to review.

Yes agreed

> 
>   - In dw_pcie_cfg_read(), I set *val to zero when we return failure.
>     Previously we always set "*val = readl(addr)" even if we later
>     returned failure.  That could have been garbage or a misaligned
>     read.

Yes you re right, I missed that point. Thanks for fixing.

> 
> Below are the patches as I applied them.  Thanks!
> 
> Bjorn
> 
> 
> commit 0951120a4c778cf043497e4af508588417bef29a
> Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Date:   Wed Sep 30 00:20:34 2015 +0800
> 
>     PCI: spear: Fix dw_pcie_cfg_read/write() usage
> 
>     The first argument of dw_pcie_cfg_read/write() is a 32-bit aligned address.
>     The second argument is the byte offset into a 32-bit word, and
>     dw_pcie_cfg_read/write() only look at the low two bits.
> 
>     SPEAr13xx used dw_pcie_cfg_read() and dw_pcie_cfg_write() incorrectly: it
>     passed important address bits in the second argument, where they were
>     ignored.
> 
>     Pass the complete 32-bit word address in the first argument and only the
>     2-bit offset into that word in the second argument.
> 
>     Without this fix, SPEAr13xx host will never work with few buggy gen1 card
>     which connects with only gen1 host and also with any endpoint which would
>     generate a read request of more than 128 bytes.
> 
>     [bhelgaas: changelog]
>     Reported-by: Bjorn Helgaas <bhelgaas@google.com>
>     Signed-off-by: Pratyush Anand <panand@redhat.com>
>     Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
>     CC: stable@vger.kernel.org	# v3.17+
> 
> diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-
> spear13xx.c
> index 98d2683..0754ea3 100644
> --- a/drivers/pci/host/pcie-spear13xx.c
> +++ b/drivers/pci/host/pcie-spear13xx.c
> @@ -163,34 +163,36 @@ static int spear13xx_pcie_establish_link(struct
> pcie_port *pp)
>  	 * default value in capability register is 512 bytes. So force
>  	 * it to 128 here.
>  	 */
> -	dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val);
> +	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
> +				0, 2, &val);
>  	val &= ~PCI_EXP_DEVCTL_READRQ;
> -	dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val);
> +	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
> +				0, 2, val);
> 
> -	dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A);
> -	dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80);
> +	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 0, 2, 0x104A);
> +	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 2, 0xCD80);
> 
>  	/*
>  	 * if is_gen1 is set then handle it, so that some buggy card
>  	 * also works
>  	 */
>  	if (spear13xx_pcie->is_gen1) {
> -		dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4,
> -				 &val);
> +		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
> +					0, 4, &val);
>  		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
>  			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
>  			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
> -			dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
> -					  PCI_EXP_LNKCAP, 4, val);
> +			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
> +						PCI_EXP_LNKCAP, 0, 4, val);
>  		}
> 
> -		dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4,
> -				 &val);
> +		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
> +					0, 2, &val);
>  		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
>  			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
>  			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
> -			dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
> -					  PCI_EXP_LNKCTL2, 4, val);
> +			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
> +						PCI_EXP_LNKCTL2, 0, 2, val);
>  		}
>  	}
> 
> 
> commit 6e5d5205ccb07c95931412f1e6fdb9ec5abc8dfd
> Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Date:   Thu Oct 8 11:45:41 2015 -0500
> 
>     PCI: designware: Use exact access size in dw_pcie_cfg_read()
> 
>     dw_pcie_cfg_write() uses the exact 8-, 16-, or 32-bit access size
>     requested, but dw_pcie_cfg_read() previously performed a 32-bit read and
>     masked out the bits requested.
> 
>     Use the exact access size in dw_pcie_cfg_read().  For example, if we want
>     an 8-bit read, use readb() instead of using readl() and masking out the 8
>     bits we need.  This makes it symmetric with dw_pcie_cfg_write().
> 
>     [bhelgaas: split into separate patch, set *val = 0 in failure case]
>     Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>     Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> designware.c
> index 52aa6e3..9073722 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -82,14 +82,16 @@ 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)
>  {
> -	*val = readl(addr);
> -
> -	if (size == 1)
> -		*val = (*val >> (8 * (where & 3))) & 0xff;
> +	if (size == 4)
> +		*val = readl(addr);
>  	else if (size == 2)
> -		*val = (*val >> (8 * (where & 3))) & 0xffff;
> -	else if (size != 4)
> +		*val = readw(addr + (where & 2));
> +	else if (size == 1)
> +		*val = readb(addr + (where & 1));
> +	else {
> +		*val = 0;
>  		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> 
>  	return PCIBIOS_SUCCESSFUL;
>  }
> 
> commit 060ca07e0d22f150d237e8d8e7149a88c3055e9a
> Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Date:   Wed Sep 30 00:20:35 2015 +0800
> 
>     PCI: designware: Simplify dw_pcie_cfg_read/write() interfaces
> 
>     Callers of dw_pcie_cfg_read() and dw_pcie_cfg_write() previously had to
>     split the address into "addr" and "where".  The callees assumed "addr" was
>     32-bit aligned (with zeros in the low two bits) and they used only the low
>     two bits of "where".
> 
>     Accept the entire address in "addr" and drop the now-redundant "where"
>     argument.  As an example, this replaces this:
> 
>       int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
>         *val = readb(addr + (where & 1));
> 
>     with this:
> 
>       int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
>         *val = readb(addr):
> 
>     [bhelgaas: changelog, split access size change to separate patch]
>     Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>     Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> 
> diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
> index f9f468d..01095e1 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 e71da99..51789b7 100644
> --- a/drivers/pci/host/pci-keystone-dw.c
> +++ b/drivers/pci/host/pci-keystone-dw.c
> @@ -398,7 +398,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,
> @@ -410,7 +410,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 9073722..a7d2352 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -80,14 +80,14 @@ static inline struct pcie_port *sys_to_pcie(struct
> pci_sys_data *sys)
>  	return sys->private_data;
>  }
> 
> -int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
> +int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
>  {
>  	if (size == 4)
>  		*val = readl(addr);
>  	else if (size == 2)
> -		*val = readw(addr + (where & 2));
> +		*val = readw(addr);
>  	else if (size == 1)
> -		*val = readb(addr + (where & 1));
> +		*val = readb(addr);
>  	else {
>  		*val = 0;
>  		return PCIBIOS_BAD_REGISTER_NUMBER;
> @@ -96,14 +96,14 @@ int dw_pcie_cfg_read(void __iomem *addr, int where, int
> size, u32 *val)
>  	return PCIBIOS_SUCCESSFUL;
>  }
> 
> -int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
> +int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
>  {
>  	if (size == 4)
>  		writel(val, addr);
>  	else if (size == 2)
> -		writew(val, addr + (where & 2));
> +		writew(val, addr);
>  	else if (size == 1)
> -		writeb(val, addr + (where & 3));
> +		writeb(val, addr);
>  	else
>  		return PCIBIOS_BAD_REGISTER_NUMBER;
> 
> @@ -134,8 +134,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;
>  }
> @@ -148,8 +147,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 +539,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 +561,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 +573,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 +595,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);
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-
> designware.h
> index d0bbd27..0b29194 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -76,8 +76,8 @@ struct pcie_host_ops {
>  	int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
>  };
> 
> -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);
> +int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
> +int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
>  irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
>  void dw_pcie_msi_init(struct pcie_port *pp);
>  int dw_pcie_link_up(struct pcie_port *pp);
> diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-
> spear13xx.c
> index 0754ea3..b95b756 100644
> --- a/drivers/pci/host/pcie-spear13xx.c
> +++ b/drivers/pci/host/pcie-spear13xx.c
> @@ -163,14 +163,12 @@ static int spear13xx_pcie_establish_link(struct
> pcie_port *pp)
>  	 * default value in capability register is 512 bytes. So force
>  	 * it to 128 here.
>  	 */
> -	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
> -				0, 2, &val);
> +	dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
>  	val &= ~PCI_EXP_DEVCTL_READRQ;
> -	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL,
> -				0, 2, val);
> +	dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
> 
> -	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 0, 2, 0x104A);
> -	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 2, 0xCD80);
> +	dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
> +	dw_pcie_cfg_write(pp->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
> 
>  	/*
>  	 * if is_gen1 is set then handle it, so that some buggy card
> @@ -178,21 +176,21 @@ static int spear13xx_pcie_establish_link(struct
> pcie_port *pp)
>  	 */
>  	if (spear13xx_pcie->is_gen1) {
>  		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
> -					0, 4, &val);
> +					4, &val);
>  		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
>  			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
>  			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
>  			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
> -						PCI_EXP_LNKCAP, 0, 4, val);
> +				PCI_EXP_LNKCAP, 4, val);
>  		}
> 
>  		dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
> -					0, 2, &val);
> +					2, &val);
>  		if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
>  			val &= ~((u32)PCI_EXP_LNKCAP_SLS);
>  			val |= PCI_EXP_LNKCAP_SLS_2_5GB;
>  			dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
> -						PCI_EXP_LNKCTL2, 0, 2, val);
> +					PCI_EXP_LNKCTL2, 2, val);
>  		}
>  	}
> 
> 
> commit 08a79800db364aabe4422ac4f2e2efdf450e1c31
> Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
> Date:   Wed Sep 30 00:20:36 2015 +0800
> 
>     PCI: designware: Require config accesses to be naturally aligned
> 
>     Add sanity checks on "addr" input parameter in dw_pcie_cfg_read() and
>     dw_pcie_cfg_write().  These checks make sure that accesses are aligned on
>     their size, e.g., a 4-byte config access is aligned on a 4-byte boundary.
> 
>     [bhelgaas: changelog, set *val = 0 in failure case]
>     Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
>     Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
>     Acked-by: Pratyush Anand <pratyush.anand@gmail.com>
> 
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-
> designware.c
> index a7d2352..6a71f99 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -82,6 +82,11 @@ static inline struct pcie_port *sys_to_pcie(struct
> pci_sys_data *sys)
> 
>  int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
>  {
> +	if ((uintptr_t)addr & (size - 1)) {
> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +
>  	if (size == 4)
>  		*val = readl(addr);
>  	else if (size == 2)
> @@ -98,6 +103,9 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
> 
>  int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
>  {
> +	if ((uintptr_t)addr & (size - 1))
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +
>  	if (size == 4)
>  		writel(val, addr);
>  	else if (size == 2)

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-10-09  6:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-29 16:20 [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
2015-09-29 16:20 ` [PATCH v6 1/3] PCIe: SPEAr13xx: fix dw_pcie_cfg_read/write() usage Gabriele Paoloni
2015-09-29 16:20 ` [PATCH v6 2/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Gabriele Paoloni
2015-09-29 16:20 ` [PATCH v6 3/3] PCI: designware: add sanity checks on the header offset in dw_pcie_cfg_read and dw_pcie_cfg_write Gabriele Paoloni
2015-09-29 16:37   ` Pratyush Anand
2015-10-08 19:25 ` [PATCH v6 0/3] PCI: designware: change dw_pcie_cfg_write() and dw_pcie_cfg_read() Bjorn Helgaas
2015-10-09  6:37   ` Gabriele Paoloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).