diff mbox

pci, pci-thunder-pem: Don't clobber read-only bits in bridge config registers.

Message ID 1460417372-13147-1-git-send-email-ddaney.cavm@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

David Daney April 11, 2016, 11:29 p.m. UTC
From: David Daney <david.daney@cavium.com>

The 32-bit addressing modes in the I/O and Prefetchable Memory
registers are required to be read-only.  Since the underlying access
method allows them to be set, we must emulate their read-only nature
and always set them.

Signed-off-by: David Daney <david.daney@cavium.com>
---
 drivers/pci/host/pci-thunder-pem.c | 42 ++++++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 8 deletions(-)

Comments

Bjorn Helgaas May 2, 2016, 5:34 p.m. UTC | #1
On Mon, Apr 11, 2016 at 04:29:32PM -0700, David Daney wrote:
> From: David Daney <david.daney@cavium.com>
> 
> The 32-bit addressing modes in the I/O and Prefetchable Memory
> registers are required to be read-only.  Since the underlying access
> method allows them to be set, we must emulate their read-only nature
> and always set them.
> 
> Signed-off-by: David Daney <david.daney@cavium.com>

Applied to pci/host-thunder for v4.7, thanks, David!

> ---
>  drivers/pci/host/pci-thunder-pem.c | 42 ++++++++++++++++++++++++++++++--------
>  1 file changed, 34 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
> index cabb92a..196adf6 100644
> --- a/drivers/pci/host/pci-thunder-pem.c
> +++ b/drivers/pci/host/pci-thunder-pem.c
> @@ -153,11 +153,11 @@ static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
>   * reserved bits, this makes the code simpler and is OK as the bits
>   * are not affected by writing zeros to them.
>   */
> -static u32 thunder_pem_bridge_w1c_bits(int where)
> +static u32 thunder_pem_bridge_w1c_bits(u64 where_aligned)
>  {
>  	u32 w1c_bits = 0;
>  
> -	switch (where & ~3) {
> +	switch (where_aligned) {
>  	case 0x04: /* Command/Status */
>  	case 0x1c: /* Base and I/O Limit/Secondary Status */
>  		w1c_bits = 0xff000000;
> @@ -184,12 +184,34 @@ static u32 thunder_pem_bridge_w1c_bits(int where)
>  	return w1c_bits;
>  }
>  
> +/* Some bits must be written to one so they appear to be read-only. */
> +static u32 thunder_pem_bridge_w1_bits(u64 where_aligned)
> +{
> +	u32 w1_bits;
> +
> +	switch (where_aligned) {
> +	case 0x1c: /* I/O Base / I/O Limit, Secondary Status*/
> +		/* Force 32-bit I/O addressing. */
> +		w1_bits = 0x0101;
> +		break;
> +	case 0x24: /* Prefetchable Memory Base / Prefetchable Memory Limit */
> +		/* Force 64-bit addressing */
> +		w1_bits = 0x00010001;
> +		break;
> +	default:
> +		w1_bits = 0;
> +		break;
> +	}
> +	return w1_bits;
> +}
> +
>  static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
>  				    int where, int size, u32 val)
>  {
>  	struct gen_pci *pci = bus->sysdata;
>  	struct thunder_pem_pci *pem_pci;
>  	u64 write_val, read_val;
> +	u64 where_aligned = where & ~3ull;
>  	u32 mask = 0;
>  
>  	pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
> @@ -205,8 +227,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
>  	 */
>  	switch (size) {
>  	case 1:
> -		read_val = where & ~3ull;
> -		writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
> +		writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
>  		read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
>  		read_val >>= 32;
>  		mask = ~(0xff << (8 * (where & 3)));
> @@ -215,8 +236,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
>  		val |= (u32)read_val;
>  		break;
>  	case 2:
> -		read_val = where & ~3ull;
> -		writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
> +		writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
>  		read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
>  		read_val >>= 32;
>  		mask = ~(0xffff << (8 * (where & 3)));
> @@ -244,11 +264,17 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
>  	}
>  
>  	/*
> +	 * Some bits must be read-only with value of one.  Since the
> +	 * access method allows these to be cleared if a zero is
> +	 * written, force them to one before writing.
> +	 */
> +	val |= thunder_pem_bridge_w1_bits(where_aligned);
> +
> +	/*
>  	 * Low order bits are the config address, the high order 32
>  	 * bits are the data to be written.
>  	 */
> -	write_val = where & ~3ull;
> -	write_val |= (((u64)val) << 32);
> +	write_val = (((u64)val) << 32) | where_aligned;
>  	writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
>  	return PCIBIOS_SUCCESSFUL;
>  }
> -- 
> 1.8.3.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
diff mbox

Patch

diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
index cabb92a..196adf6 100644
--- a/drivers/pci/host/pci-thunder-pem.c
+++ b/drivers/pci/host/pci-thunder-pem.c
@@ -153,11 +153,11 @@  static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn,
  * reserved bits, this makes the code simpler and is OK as the bits
  * are not affected by writing zeros to them.
  */
-static u32 thunder_pem_bridge_w1c_bits(int where)
+static u32 thunder_pem_bridge_w1c_bits(u64 where_aligned)
 {
 	u32 w1c_bits = 0;
 
-	switch (where & ~3) {
+	switch (where_aligned) {
 	case 0x04: /* Command/Status */
 	case 0x1c: /* Base and I/O Limit/Secondary Status */
 		w1c_bits = 0xff000000;
@@ -184,12 +184,34 @@  static u32 thunder_pem_bridge_w1c_bits(int where)
 	return w1c_bits;
 }
 
+/* Some bits must be written to one so they appear to be read-only. */
+static u32 thunder_pem_bridge_w1_bits(u64 where_aligned)
+{
+	u32 w1_bits;
+
+	switch (where_aligned) {
+	case 0x1c: /* I/O Base / I/O Limit, Secondary Status*/
+		/* Force 32-bit I/O addressing. */
+		w1_bits = 0x0101;
+		break;
+	case 0x24: /* Prefetchable Memory Base / Prefetchable Memory Limit */
+		/* Force 64-bit addressing */
+		w1_bits = 0x00010001;
+		break;
+	default:
+		w1_bits = 0;
+		break;
+	}
+	return w1_bits;
+}
+
 static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
 				    int where, int size, u32 val)
 {
 	struct gen_pci *pci = bus->sysdata;
 	struct thunder_pem_pci *pem_pci;
 	u64 write_val, read_val;
+	u64 where_aligned = where & ~3ull;
 	u32 mask = 0;
 
 	pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci);
@@ -205,8 +227,7 @@  static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
 	 */
 	switch (size) {
 	case 1:
-		read_val = where & ~3ull;
-		writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+		writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
 		read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
 		read_val >>= 32;
 		mask = ~(0xff << (8 * (where & 3)));
@@ -215,8 +236,7 @@  static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
 		val |= (u32)read_val;
 		break;
 	case 2:
-		read_val = where & ~3ull;
-		writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
+		writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
 		read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
 		read_val >>= 32;
 		mask = ~(0xffff << (8 * (where & 3)));
@@ -244,11 +264,17 @@  static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
 	}
 
 	/*
+	 * Some bits must be read-only with value of one.  Since the
+	 * access method allows these to be cleared if a zero is
+	 * written, force them to one before writing.
+	 */
+	val |= thunder_pem_bridge_w1_bits(where_aligned);
+
+	/*
 	 * Low order bits are the config address, the high order 32
 	 * bits are the data to be written.
 	 */
-	write_val = where & ~3ull;
-	write_val |= (((u64)val) << 32);
+	write_val = (((u64)val) << 32) | where_aligned;
 	writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
 	return PCIBIOS_SUCCESSFUL;
 }