Implement support for IO space, and better-handle both variants of MMIO space.
This commit is contained in:
parent
2cc9171b5c
commit
3689f53f38
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pcihost_fdt.c,v 1.6 2018/11/19 11:08:16 jmcneill Exp $ */
|
||||
/* $NetBSD: pcihost_fdt.c,v 1.7 2019/02/28 00:17:13 jakllsch Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2018 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.6 2018/11/19 11:08:16 jmcneill Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.7 2019/02/28 00:17:13 jakllsch Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
@ -81,6 +81,19 @@ enum pcihost_type {
|
||||
PCIHOST_ECAM,
|
||||
};
|
||||
|
||||
struct pcih_bus_space {
|
||||
struct bus_space bst;
|
||||
|
||||
int (*map)(void *, bus_addr_t, bus_size_t,
|
||||
int, bus_space_handle_t *);
|
||||
struct space_range {
|
||||
bus_addr_t bpci;
|
||||
bus_addr_t bbus;
|
||||
bus_size_t size;
|
||||
} ranges[4];
|
||||
size_t nranges;
|
||||
};
|
||||
|
||||
struct pcihost_softc {
|
||||
device_t sc_dev;
|
||||
bus_dma_tag_t sc_dmat;
|
||||
@ -95,6 +108,9 @@ struct pcihost_softc {
|
||||
u_int sc_bus_max;
|
||||
|
||||
struct arm32_pci_chipset sc_pc;
|
||||
|
||||
struct pcih_bus_space sc_io;
|
||||
struct pcih_bus_space sc_mem;
|
||||
};
|
||||
|
||||
static int pcihost_match(device_t, cfdata_t, void *);
|
||||
@ -126,6 +142,9 @@ static void * pcihost_intr_establish(void *, pci_intr_handle_t,
|
||||
const char *);
|
||||
static void pcihost_intr_disestablish(void *, void *);
|
||||
|
||||
static int pcihost_bus_space_map(void *, bus_addr_t, bus_size_t,
|
||||
int, bus_space_handle_t *);
|
||||
|
||||
CFATTACH_DECL_NEW(pcihost_fdt, sizeof(struct pcihost_softc),
|
||||
pcihost_match, pcihost_attach, NULL, NULL);
|
||||
|
||||
@ -203,6 +222,7 @@ pcihost_attach(device_t parent, device_t self, void *aux)
|
||||
pba.pba_flags = PCI_FLAGS_MRL_OKAY |
|
||||
PCI_FLAGS_MRM_OKAY |
|
||||
PCI_FLAGS_MWI_OKAY |
|
||||
PCI_FLAGS_IO_OKAY |
|
||||
PCI_FLAGS_MEM_OKAY;
|
||||
#ifdef __HAVE_PCI_MSI_MSIX
|
||||
if (sc->sc_type == PCIHOST_ECAM) {
|
||||
@ -210,8 +230,8 @@ pcihost_attach(device_t parent, device_t self, void *aux)
|
||||
PCI_FLAGS_MSIX_OKAY;
|
||||
}
|
||||
#endif
|
||||
pba.pba_iot = 0;
|
||||
pba.pba_memt = sc->sc_bst;
|
||||
pba.pba_iot = &sc->sc_io.bst;
|
||||
pba.pba_memt = &sc->sc_mem.bst;
|
||||
pba.pba_dmat = sc->sc_dmat;
|
||||
#ifdef _PCI_HAVE_DMA64
|
||||
pba.pba_dmat64 = sc->sc_dmat;
|
||||
@ -253,6 +273,18 @@ pcihost_config(struct pcihost_softc *sc)
|
||||
u_int probe_only;
|
||||
int error, len;
|
||||
|
||||
struct pcih_bus_space * const pibs = &sc->sc_io;
|
||||
pibs->bst = *sc->sc_bst;
|
||||
pibs->bst.bs_cookie = pibs;
|
||||
pibs->map = pibs->bst.bs_map;
|
||||
pibs->bst.bs_map = pcihost_bus_space_map;
|
||||
|
||||
struct pcih_bus_space * const pmbs = &sc->sc_mem;
|
||||
pmbs->bst = *sc->sc_bst;
|
||||
pmbs->bst.bs_cookie = pmbs;
|
||||
pmbs->map = pmbs->bst.bs_map;
|
||||
pmbs->bst.bs_map = pcihost_bus_space_map;
|
||||
|
||||
/*
|
||||
* If this flag is set, skip configuration of the PCI bus and use existing config.
|
||||
*/
|
||||
@ -276,47 +308,73 @@ pcihost_config(struct pcihost_softc *sc)
|
||||
*/
|
||||
while (len >= 28) {
|
||||
const uint32_t phys_hi = be32dec(&ranges[0]);
|
||||
const uint64_t bus_phys = be64dec(&ranges[1]);
|
||||
const uint64_t cpu_phys = be64dec(&ranges[3]);
|
||||
const uint64_t size = be64dec(&ranges[5]);
|
||||
|
||||
len -= 28;
|
||||
ranges += 7;
|
||||
|
||||
const bool is64 = (__SHIFTOUT(phys_hi, PHYS_HI_SPACE) ==
|
||||
PHYS_HI_SPACE_MEM64) ? true : false;
|
||||
switch (__SHIFTOUT(phys_hi, PHYS_HI_SPACE)) {
|
||||
case PHYS_HI_SPACE_IO:
|
||||
if (pibs->nranges + 1 >= __arraycount(pibs->ranges)) {
|
||||
aprint_error_dev(sc->sc_dev, "too many IO ranges\n");
|
||||
continue;
|
||||
}
|
||||
pibs->ranges[pibs->nranges].bpci = bus_phys;
|
||||
pibs->ranges[pibs->nranges].bbus = cpu_phys;
|
||||
pibs->ranges[pibs->nranges].size = size;
|
||||
++pibs->nranges;
|
||||
if (ioext != NULL) {
|
||||
aprint_error_dev(sc->sc_dev, "ignoring duplicate IO space range\n");
|
||||
continue;
|
||||
}
|
||||
ioext = extent_create("pciio", cpu_phys, cpu_phys + size - 1, NULL, 0, EX_NOWAIT);
|
||||
ioext = extent_create("pciio", bus_phys, bus_phys + size - 1, NULL, 0, EX_NOWAIT);
|
||||
aprint_verbose_dev(sc->sc_dev,
|
||||
"I/O memory @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
|
||||
cpu_phys, size);
|
||||
"IO: 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
|
||||
bus_phys, size, cpu_phys);
|
||||
/* reserve a PC-like legacy IO ports range, perhaps for access to VGA registers */
|
||||
if (bus_phys == 0 && size >= 0x10000)
|
||||
extent_alloc_region(ioext, 0, 0x1000, EX_WAITOK);
|
||||
break;
|
||||
case PHYS_HI_SPACE_MEM64:
|
||||
/* FALLTHROUGH */
|
||||
case PHYS_HI_SPACE_MEM32:
|
||||
if ((phys_hi & PHYS_HI_PREFETCH) != 0) {
|
||||
if (pmbs->nranges + 1 >= __arraycount(pmbs->ranges)) {
|
||||
aprint_error_dev(sc->sc_dev, "too many mem ranges\n");
|
||||
continue;
|
||||
}
|
||||
/* both pmem and mem spaces are in the same tag */
|
||||
pmbs->ranges[pmbs->nranges].bpci = bus_phys;
|
||||
pmbs->ranges[pmbs->nranges].bbus = cpu_phys;
|
||||
pmbs->ranges[pmbs->nranges].size = size;
|
||||
++pmbs->nranges;
|
||||
if ((phys_hi & PHYS_HI_PREFETCH) != 0 ||
|
||||
__SHIFTOUT(phys_hi, PHYS_HI_SPACE) == PHYS_HI_SPACE_MEM64) {
|
||||
if (pmemext != NULL) {
|
||||
aprint_error_dev(sc->sc_dev, "ignoring duplicate mem (prefetchable) range\n");
|
||||
continue;
|
||||
}
|
||||
pmemext = extent_create("pcipmem", cpu_phys, cpu_phys + size - 1, NULL, 0, EX_NOWAIT);
|
||||
pmemext = extent_create("pcipmem", bus_phys, bus_phys + size - 1, NULL, 0, EX_NOWAIT);
|
||||
aprint_verbose_dev(sc->sc_dev,
|
||||
"32-bit MMIO (prefetchable) @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
|
||||
cpu_phys, size);
|
||||
"MMIO (%d-bit prefetchable): 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
|
||||
is64 ? 64 : 32, bus_phys, size, cpu_phys);
|
||||
} else {
|
||||
if (memext != NULL) {
|
||||
aprint_error_dev(sc->sc_dev, "ignoring duplicate mem (non-prefetchable) range\n");
|
||||
continue;
|
||||
}
|
||||
memext = extent_create("pcimem", cpu_phys, cpu_phys + size - 1, NULL, 0, EX_NOWAIT);
|
||||
memext = extent_create("pcimem", bus_phys, bus_phys + size - 1, NULL, 0, EX_NOWAIT);
|
||||
aprint_verbose_dev(sc->sc_dev,
|
||||
"32-bit MMIO (non-prefetchable) @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
|
||||
cpu_phys, size);
|
||||
"MMIO (%d-bit non-prefetchable): 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
|
||||
is64 ? 64 : 32, bus_phys, size, cpu_phys);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
len -= 28;
|
||||
ranges += 7;
|
||||
}
|
||||
|
||||
error = pci_configure_bus(&sc->sc_pc, ioext, memext, pmemext, sc->sc_bus_min, PCIHOST_CACHELINE_SIZE);
|
||||
@ -597,3 +655,20 @@ pcihost_intr_disestablish(void *v, void *vih)
|
||||
|
||||
fdtbus_intr_disestablish(sc->sc_phandle, vih);
|
||||
}
|
||||
|
||||
static int
|
||||
pcihost_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
|
||||
bus_space_handle_t *bshp)
|
||||
{
|
||||
struct pcih_bus_space * const pbs = t;
|
||||
|
||||
for (size_t i = 0; i < pbs->nranges; i++) {
|
||||
const bus_addr_t rmin = pbs->ranges[i].bpci;
|
||||
const bus_addr_t rmax = pbs->ranges[i].bpci - 1 + pbs->ranges[i].size;
|
||||
if ((bpa >= rmin) && ((bpa - 1 + size) <= rmax)) {
|
||||
return pbs->map(t, bpa - pbs->ranges[i].bpci + pbs->ranges[i].bbus, size, flag, bshp);
|
||||
}
|
||||
}
|
||||
|
||||
return ERANGE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user