diff options
| author | Justin Hibbits <jhibbits@FreeBSD.org> | 2019-08-04 19:28:10 +0000 |
|---|---|---|
| committer | Justin Hibbits <jhibbits@FreeBSD.org> | 2019-08-04 19:28:10 +0000 |
| commit | 937a05ba81c3d6fc5c9558b98b882fd61fa56e7b (patch) | |
| tree | 26ef59b7f1915afab357ad092a3605618b441b8a /sys/dev | |
| parent | 69a277d98e6c67ad95cc7b32e9029cee124f3871 (diff) | |
Notes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ofw/ofwpci.c | 42 | ||||
| -rw-r--r-- | sys/dev/pci/vga_pci.c | 123 |
2 files changed, 159 insertions, 6 deletions
diff --git a/sys/dev/ofw/ofwpci.c b/sys/dev/ofw/ofwpci.c index 7ebfe4ab86a1..95d4421ccddf 100644 --- a/sys/dev/ofw/ofwpci.c +++ b/sys/dev/ofw/ofwpci.c @@ -76,6 +76,8 @@ static int ofw_pci_deactivate_resource(device_t, device_t, int, int, struct resource *); static int ofw_pci_adjust_resource(device_t, device_t, int, struct resource *, rman_res_t, rman_res_t); +static int ofw_pci_translate_resource(device_t bus, int type, + rman_res_t start, rman_res_t *newstart); #ifdef __powerpc__ static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t); @@ -116,6 +118,7 @@ static device_method_t ofw_pci_methods[] = { DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, ofw_pci_deactivate_resource), DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), + DEVMETHOD(bus_translate_resource, ofw_pci_translate_resource), #ifdef __powerpc__ DEVMETHOD(bus_get_bus_tag, ofw_pci_bus_get_bus_tag), #endif @@ -479,6 +482,45 @@ ofw_pci_release_resource(device_t bus, device_t child, int type, int rid, } static int +ofw_pci_translate_resource(device_t bus, int type, rman_res_t start, + rman_res_t *newstart) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_range *rp; + int space; + + sc = device_get_softc(bus); + + /* + * Map this through the ranges list + */ + for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange && + rp->pci_hi != 0; rp++) { + if (start < rp->pci || start >= rp->pci + rp->size) + continue; + + switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { + case OFW_PCI_PHYS_HI_SPACE_IO: + space = SYS_RES_IOPORT; + break; + case OFW_PCI_PHYS_HI_SPACE_MEM32: + case OFW_PCI_PHYS_HI_SPACE_MEM64: + space = SYS_RES_MEMORY; + break; + default: + space = -1; + } + + if (type == space) { + start += (rp->host - rp->pci); + break; + } + } + *newstart = start; + return (0); +} + +static int ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c index 6019ffb67701..bde5cd7a55ca 100644 --- a/sys/dev/pci/vga_pci.c +++ b/sys/dev/pci/vga_pci.c @@ -142,11 +142,35 @@ vga_pci_is_boot_display(device_t dev) return (1); } +static void +vga_pci_reset(device_t dev) +{ + int ps; + /* + * FLR is unsupported on GPUs so attempt a power-management reset by cycling + * the device in/out of D3 state. + * PCI spec says we can only go into D3 state from D0 state. + * Transition from D[12] into D0 before going to D3 state. + */ + ps = pci_get_powerstate(dev); + if (ps != PCI_POWERSTATE_D0 && ps != PCI_POWERSTATE_D3) + pci_set_powerstate(dev, PCI_POWERSTATE_D0); + if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3) + pci_set_powerstate(dev, PCI_POWERSTATE_D3); + pci_set_powerstate(dev, ps); +} + + void * vga_pci_map_bios(device_t dev, size_t *size) { - int rid; + struct vga_resource *vr; struct resource *res; + device_t pcib; + uint32_t rom_addr; + uint16_t config; + volatile char *bios; + int i, rid, found; #if defined(__amd64__) || defined(__i386__) if (vga_pci_is_boot_display(dev)) { @@ -164,21 +188,96 @@ vga_pci_map_bios(device_t dev, size_t *size) } #endif - rid = PCIR_BIOS; + pcib = device_get_parent(device_get_parent(dev)); + if (device_get_devclass(device_get_parent(pcib)) == + devclass_find("pci")) { + /* + * The parent bridge is a PCI-to-PCI bridge: check the + * value of the "VGA Enable" bit. + */ + config = pci_read_config(pcib, PCIR_BRIDGECTL_1, 2); + if ((config & PCIB_BCR_VGA_ENABLE) == 0) { + config |= PCIB_BCR_VGA_ENABLE; + pci_write_config(pcib, PCIR_BRIDGECTL_1, config, 2); + } + } + + switch(pci_read_config(dev, PCIR_HDRTYPE, 1)) { + case PCIM_HDRTYPE_BRIDGE: + rid = PCIR_BIOS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + rid = 0; + break; + default: + rid = PCIR_BIOS; + break; + } + if (rid == 0) + return (NULL); res = vga_pci_alloc_resource(dev, NULL, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE); + if (res == NULL) { + device_printf(dev, "vga_pci_alloc_resource failed\n"); return (NULL); } + bios = rman_get_virtual(res); + *size = rman_get_size(res); + for (found = i = 0; i < hz; i++) { + found = (bios[0] == 0x55 && bios[1] == 0xaa); + if (found) + break; + pause("vgabios", 1); + } + if (found) + return (__DEVOLATILE(void *, bios)); + if (bootverbose) + device_printf(dev, "initial ROM mapping failed -- resetting\n"); + /* + * Enable ROM decode + */ + vga_pci_reset(dev); + rom_addr = pci_read_config(dev, rid, 4); + rom_addr &= 0x7ff; + rom_addr |= rman_get_start(res) | 0x1; + pci_write_config(dev, rid, rom_addr, 4); + vr = lookup_res(device_get_softc(dev), rid); + vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, rid, + vr->vr_res); + + /* + * re-allocate + */ + res = vga_pci_alloc_resource(dev, NULL, SYS_RES_MEMORY, &rid, 0, + ~0, 1, RF_ACTIVE); + if (res == NULL) { + device_printf(dev, "vga_pci_alloc_resource failed\n"); + return (NULL); + } + bios = rman_get_virtual(res); *size = rman_get_size(res); - return (rman_get_virtual(res)); + for (found = i = 0; i < 3*hz; i++) { + found = (bios[0] == 0x55 && bios[1] == 0xaa); + if (found) + break; + pause("vgabios", 1); + } + if (found) + return (__DEVOLATILE(void *, bios)); + device_printf(dev, "ROM mapping failed\n"); + vr = lookup_res(device_get_softc(dev), rid); + vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, rid, + vr->vr_res); + return (NULL); } void vga_pci_unmap_bios(device_t dev, void *bios) { struct vga_resource *vr; + int rid; if (bios == NULL) { return; @@ -192,16 +291,28 @@ vga_pci_unmap_bios(device_t dev, void *bios) return; } #endif - + switch(pci_read_config(dev, PCIR_HDRTYPE, 1)) { + case PCIM_HDRTYPE_BRIDGE: + rid = PCIR_BIOS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + rid = 0; + break; + default: + rid = PCIR_BIOS; + break; + } + if (rid == 0) + return; /* * Look up the PCIR_BIOS resource in our softc. It should match * the address we returned previously. */ - vr = lookup_res(device_get_softc(dev), PCIR_BIOS); + vr = lookup_res(device_get_softc(dev), rid); KASSERT(vr->vr_res != NULL, ("vga_pci_unmap_bios: bios not mapped")); KASSERT(rman_get_virtual(vr->vr_res) == bios, ("vga_pci_unmap_bios: mismatch")); - vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, PCIR_BIOS, + vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, rid, vr->vr_res); } |
