Re: [PATCH] pci, pci-thunder-pem: Don't clobber read-only bits in bridge config registers.
From: Bjorn Helgaas
Date: Mon May 02 2016 - 13:34:22 EST
On Mon, Apr 11, 2016 at 04:29:32PM -0700, David Daney wrote:
> From: David Daney <david.daney@xxxxxxxxxx>
>
> 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@xxxxxxxxxx>
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@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html