Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+34 −8
Original line number Diff line number Diff line
@@ -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;
}