diff options
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r-- | drivers/pci/access.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index d11cdbb8fba3..db239547fefd 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -142,10 +142,22 @@ int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, | |||
142 | if (size == 4) { | 142 | if (size == 4) { |
143 | writel(val, addr); | 143 | writel(val, addr); |
144 | return PCIBIOS_SUCCESSFUL; | 144 | return PCIBIOS_SUCCESSFUL; |
145 | } else { | ||
146 | mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); | ||
147 | } | 145 | } |
148 | 146 | ||
147 | /* | ||
148 | * In general, hardware that supports only 32-bit writes on PCI is | ||
149 | * not spec-compliant. For example, software may perform a 16-bit | ||
150 | * write. If the hardware only supports 32-bit accesses, we must | ||
151 | * do a 32-bit read, merge in the 16 bits we intend to write, | ||
152 | * followed by a 32-bit write. If the 16 bits we *don't* intend to | ||
153 | * write happen to have any RW1C (write-one-to-clear) bits set, we | ||
154 | * just inadvertently cleared something we shouldn't have. | ||
155 | */ | ||
156 | dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", | ||
157 | size, pci_domain_nr(bus), bus->number, | ||
158 | PCI_SLOT(devfn), PCI_FUNC(devfn), where); | ||
159 | |||
160 | mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); | ||
149 | tmp = readl(addr) & mask; | 161 | tmp = readl(addr) & mask; |
150 | tmp |= val << ((where & 0x3) * 8); | 162 | tmp |= val << ((where & 0x3) * 8); |
151 | writel(tmp, addr); | 163 | writel(tmp, addr); |