Commit 06cf35f903aa6da0cc8d9f81e9bcd1f7e1b534bb
Committed by
Bjorn Helgaas
1 parent
51ac3d2f0c
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
PCI: Handle read-only BARs on AMD CS553x devices
Some AMD CS553x devices have read-only BARs because of a firmware or hardware defect. There's a workaround in quirk_cs5536_vsa(), but it no longer works after 36e8164882ca ("PCI: Restore detection of read-only BARs"). Prior to 36e8164882ca, we filled in res->start; afterwards we leave it zeroed out. The quirk only updated the size, so the driver tried to use a region starting at zero, which didn't work. Expand quirk_cs5536_vsa() to read the base addresses from the BARs and hard-code the sizes. On Nix's system BAR 2's read-only value is 0x6200. Prior to 36e8164882ca, we interpret that as a 512-byte BAR based on the lowest-order bit set. Per datasheet sec 5.6.1, that BAR (MFGPT) requires only 64 bytes; use that to avoid clearing any address bits if a platform uses only 64-byte alignment. [bhelgaas: changelog, reduce BAR 2 size to 64] Fixes: 36e8164882ca ("PCI: Restore detection of read-only BARs") Link: https://bugzilla.kernel.org/show_bug.cgi?id=85991#c4 Link: http://support.amd.com/TechDocs/31506_cs5535_databook.pdf Link: http://support.amd.com/TechDocs/33238G_cs5536_db.pdf Reported-and-tested-by: Nix <nix@esperi.org.uk> Signed-off-by: Myron Stowe <myron.stowe@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> CC: stable@vger.kernel.org # v.2.6.27+
Showing 1 changed file with 37 additions and 3 deletions Side-by-side Diff
drivers/pci/quirks.c
... | ... | @@ -324,18 +324,52 @@ |
324 | 324 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); |
325 | 325 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); |
326 | 326 | |
327 | +static void quirk_io(struct pci_dev *dev, int pos, unsigned size, | |
328 | + const char *name) | |
329 | +{ | |
330 | + u32 region; | |
331 | + struct pci_bus_region bus_region; | |
332 | + struct resource *res = dev->resource + pos; | |
333 | + | |
334 | + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (pos << 2), ®ion); | |
335 | + | |
336 | + if (!region) | |
337 | + return; | |
338 | + | |
339 | + res->name = pci_name(dev); | |
340 | + res->flags = region & ~PCI_BASE_ADDRESS_IO_MASK; | |
341 | + res->flags |= | |
342 | + (IORESOURCE_IO | IORESOURCE_PCI_FIXED | IORESOURCE_SIZEALIGN); | |
343 | + region &= ~(size - 1); | |
344 | + | |
345 | + /* Convert from PCI bus to resource space */ | |
346 | + bus_region.start = region; | |
347 | + bus_region.end = region + size - 1; | |
348 | + pcibios_bus_to_resource(dev->bus, res, &bus_region); | |
349 | + | |
350 | + dev_info(&dev->dev, FW_BUG "%s quirk: reg 0x%x: %pR\n", | |
351 | + name, PCI_BASE_ADDRESS_0 + (pos << 2), res); | |
352 | +} | |
353 | + | |
327 | 354 | /* |
328 | 355 | * Some CS5536 BIOSes (for example, the Soekris NET5501 board w/ comBIOS |
329 | 356 | * ver. 1.33 20070103) don't set the correct ISA PCI region header info. |
330 | 357 | * BAR0 should be 8 bytes; instead, it may be set to something like 8k |
331 | 358 | * (which conflicts w/ BAR1's memory range). |
359 | + * | |
360 | + * CS553x's ISA PCI BARs may also be read-only (ref: | |
361 | + * https://bugzilla.kernel.org/show_bug.cgi?id=85991 - Comment #4 forward). | |
332 | 362 | */ |
333 | 363 | static void quirk_cs5536_vsa(struct pci_dev *dev) |
334 | 364 | { |
365 | + static char *name = "CS5536 ISA bridge"; | |
366 | + | |
335 | 367 | if (pci_resource_len(dev, 0) != 8) { |
336 | - struct resource *res = &dev->resource[0]; | |
337 | - res->end = res->start + 8 - 1; | |
338 | - dev_info(&dev->dev, "CS5536 ISA bridge bug detected (incorrect header); workaround applied\n"); | |
368 | + quirk_io(dev, 0, 8, name); /* SMB */ | |
369 | + quirk_io(dev, 1, 256, name); /* GPIO */ | |
370 | + quirk_io(dev, 2, 64, name); /* MFGPT */ | |
371 | + dev_info(&dev->dev, "%s bug detected (incorrect header); workaround applied\n", | |
372 | + name); | |
339 | 373 | } |
340 | 374 | } |
341 | 375 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa); |