Message ID | 1460417372-13147-1-git-send-email-ddaney.cavm@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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 --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; }