mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	PCI: Warn on possible RW1C corruption for sub-32 bit config writes
Hardware that supports only 32-bit config writes is not spec-compliant. For example, if software performs a 16-bit write, we must do a 32-bit read, merge in the 16 bits we intend to write, followed by a 32-bit write. If the 16 bits we *don't* intend to write happen to have any RW1C (write-one- to-clear) bits set, we just inadvertently cleared something we shouldn't have. Add a rate-limited warning when we do sub-32 bit config writes. Remove similar probe-time warnings from some of the affected host bridge drivers. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Enthusiastically-Acked-by: Russell King <rmk+kernel@armlinux.org.uk> Acked-by: Shawn Lin <shawn.lin@rock-chips.com> # rockchip Acked-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
		
							parent
							
								
									702ed3be1b
								
							
						
					
					
						commit
						fb26592301
					
				
					 3 changed files with 14 additions and 7 deletions
				
			
		| 
						 | 
					@ -142,10 +142,22 @@ int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn,
 | 
				
			||||||
	if (size == 4) {
 | 
						if (size == 4) {
 | 
				
			||||||
		writel(val, addr);
 | 
							writel(val, addr);
 | 
				
			||||||
		return PCIBIOS_SUCCESSFUL;
 | 
							return PCIBIOS_SUCCESSFUL;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * In general, hardware that supports only 32-bit writes on PCI is
 | 
				
			||||||
 | 
						 * not spec-compliant.  For example, software may perform a 16-bit
 | 
				
			||||||
 | 
						 * write.  If the hardware only supports 32-bit accesses, we must
 | 
				
			||||||
 | 
						 * do a 32-bit read, merge in the 16 bits we intend to write,
 | 
				
			||||||
 | 
						 * followed by a 32-bit write.  If the 16 bits we *don't* intend to
 | 
				
			||||||
 | 
						 * write happen to have any RW1C (write-one-to-clear) bits set, we
 | 
				
			||||||
 | 
						 * just inadvertently cleared something we shouldn't have.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n",
 | 
				
			||||||
 | 
								     size, pci_domain_nr(bus), bus->number,
 | 
				
			||||||
 | 
								     PCI_SLOT(devfn), PCI_FUNC(devfn), where);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
 | 
				
			||||||
	tmp = readl(addr) & mask;
 | 
						tmp = readl(addr) & mask;
 | 
				
			||||||
	tmp |= val << ((where & 0x3) * 8);
 | 
						tmp |= val << ((where & 0x3) * 8);
 | 
				
			||||||
	writel(tmp, addr);
 | 
						writel(tmp, addr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,8 +194,6 @@ static int hisi_pcie_probe(struct platform_device *pdev)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_warn(dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1187,9 +1187,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
 | 
				
			||||||
		pcie_bus_configure_settings(child);
 | 
							pcie_bus_configure_settings(child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_bus_add_devices(bus);
 | 
						pci_bus_add_devices(bus);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	dev_warn(dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_vpcie:
 | 
					err_vpcie:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue