This diff checks whether the PCI ROMs have been assigned sensible
addresses.  If not it resets the address to 0 such that drivers that
want to map the ROM can assign a suitable address themselves.  This
replicates what we have been doing for PCI BARs for the last couple of
years.

This should fix issues with some ATI/AMD Radeon cards behind bridges
on machines with broken firmware.

ok?


Index: pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/pci.c,v
retrieving revision 1.105
diff -u -p -r1.105 pci.c
--- pci.c       14 Sep 2014 14:17:25 -0000      1.105
+++ pci.c       25 Oct 2014 13:59:28 -0000
@@ -797,12 +797,14 @@ pci_reserve_resources(struct pci_attach_
        pci_chipset_tag_t pc = pa->pa_pc;
        pcitag_t tag = pa->pa_tag;
        pcireg_t bhlc, blr, type, bir;
+       pcireg_t addr, mask;
        bus_addr_t base, limit;
        bus_size_t size;
-       int reg, reg_start, reg_end;
+       int reg, reg_start, reg_end, reg_rom;
        int bus, dev, func;
        int sec, sub;
        int flags;
+       int s;
 
        pci_decompose_tag(pc, tag, &bus, &dev, &func);
 
@@ -811,14 +813,17 @@ pci_reserve_resources(struct pci_attach_
        case 0:
                reg_start = PCI_MAPREG_START;
                reg_end = PCI_MAPREG_END;
+               reg_rom = PCI_ROM_REG;
                break;
        case 1: /* PCI-PCI bridge */
                reg_start = PCI_MAPREG_START;
                reg_end = PCI_MAPREG_PPB_END;
+               reg_rom = 0;    /* 0x38 */
                break;
        case 2: /* PCI-CardBus bridge */
                reg_start = PCI_MAPREG_START;
                reg_end = PCI_MAPREG_PCB_END;
+               reg_rom = 0;
                break;
        default:
                return (0);
@@ -863,6 +868,28 @@ pci_reserve_resources(struct pci_attach_
 
                if (type & PCI_MAPREG_MEM_TYPE_64BIT)
                        reg += 4;
+       }
+
+       if (reg_rom != 0) {
+               s = splhigh();
+               addr = pci_conf_read(pc, tag, PCI_ROM_REG);
+               pci_conf_write(pc, tag, PCI_ROM_REG, ~PCI_ROM_ENABLE);
+               mask = pci_conf_read(pc, tag, PCI_ROM_REG);
+               pci_conf_write(pc, tag, PCI_ROM_REG, addr);
+               splx(s);
+
+               base = PCI_ROM_ADDR(addr);
+               size = PCI_ROM_SIZE(mask);
+               if (base != 0 && size != 0) {
+                       if (pa->pa_pmemex && extent_alloc_region(pa->pa_pmemex,
+                           base, size, EX_NOWAIT) &&
+                           pa->pa_memex && extent_alloc_region(pa->pa_memex,
+                           base, size, EX_NOWAIT)) {
+                               printf("%d:%d:%d: mem address conflict 
0x%lx/0x%lx\n",
+                                   bus, dev, func, base, size);
+                               pci_conf_write(pc, tag, PCI_ROM_REG, 0);
+                       }
+               }
        }
 
        if (PCI_HDRTYPE_TYPE(bhlc) != 1)

Reply via email to