Commit 93bf9073 authored by David Daney's avatar David Daney Committed by Bjorn Helgaas

PCI: thunder: Don't clobber read-only bits in bridge config registers

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, emulate their read-only nature and always set them.
Signed-off-by: default avatarDavid Daney <david.daney@cavium.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 9735a227
...@@ -153,11 +153,11 @@ static int thunder_pem_config_read(struct pci_bus *bus, unsigned int devfn, ...@@ -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 * reserved bits, this makes the code simpler and is OK as the bits
* are not affected by writing zeros to them. * 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; u32 w1c_bits = 0;
switch (where & ~3) { switch (where_aligned) {
case 0x04: /* Command/Status */ case 0x04: /* Command/Status */
case 0x1c: /* Base and I/O Limit/Secondary Status */ case 0x1c: /* Base and I/O Limit/Secondary Status */
w1c_bits = 0xff000000; w1c_bits = 0xff000000;
...@@ -184,12 +184,34 @@ static u32 thunder_pem_bridge_w1c_bits(int where) ...@@ -184,12 +184,34 @@ static u32 thunder_pem_bridge_w1c_bits(int where)
return w1c_bits; 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, static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val) int where, int size, u32 val)
{ {
struct gen_pci *pci = bus->sysdata; struct gen_pci *pci = bus->sysdata;
struct thunder_pem_pci *pem_pci; struct thunder_pem_pci *pem_pci;
u64 write_val, read_val; u64 write_val, read_val;
u64 where_aligned = where & ~3ull;
u32 mask = 0; u32 mask = 0;
pem_pci = container_of(pci, struct thunder_pem_pci, gen_pci); 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, ...@@ -205,8 +227,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
*/ */
switch (size) { switch (size) {
case 1: case 1:
read_val = where & ~3ull; writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD); read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
read_val >>= 32; read_val >>= 32;
mask = ~(0xff << (8 * (where & 3))); mask = ~(0xff << (8 * (where & 3)));
...@@ -215,8 +236,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn, ...@@ -215,8 +236,7 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn,
val |= (u32)read_val; val |= (u32)read_val;
break; break;
case 2: case 2:
read_val = where & ~3ull; writeq(where_aligned, pem_pci->pem_reg_base + PEM_CFG_RD);
writeq(read_val, pem_pci->pem_reg_base + PEM_CFG_RD);
read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD); read_val = readq(pem_pci->pem_reg_base + PEM_CFG_RD);
read_val >>= 32; read_val >>= 32;
mask = ~(0xffff << (8 * (where & 3))); mask = ~(0xffff << (8 * (where & 3)));
...@@ -243,12 +263,18 @@ static int thunder_pem_bridge_write(struct pci_bus *bus, unsigned int devfn, ...@@ -243,12 +263,18 @@ 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 * Low order bits are the config address, the high order 32
* bits are the data to be written. * bits are the data to be written.
*/ */
write_val = where & ~3ull; write_val = (((u64)val) << 32) | where_aligned;
write_val |= (((u64)val) << 32);
writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR); writeq(write_val, pem_pci->pem_reg_base + PEM_CFG_WR);
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment