mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 18:13:04 +00:00
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: David Daney <david.daney@cavium.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
9735a22799
commit
93bf9073a8
@ -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)));
|
||||
@ -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
|
||||
* 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user