aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJustin Hibbits <jhibbits@FreeBSD.org>2019-08-04 19:28:10 +0000
committerJustin Hibbits <jhibbits@FreeBSD.org>2019-08-04 19:28:10 +0000
commit937a05ba81c3d6fc5c9558b98b882fd61fa56e7b (patch)
tree26ef59b7f1915afab357ad092a3605618b441b8a /sys/dev
parent69a277d98e6c67ad95cc7b32e9029cee124f3871 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ofw/ofwpci.c42
-rw-r--r--sys/dev/pci/vga_pci.c123
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);
}