summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2018-01-06 20:31:03 +0000
committerkettenis <kettenis@openbsd.org>2018-01-06 20:31:03 +0000
commit5f9b80c09d01899b9236c70716888c6ce8f727d7 (patch)
treed80bce6446fbd464e57f395418951678dac1043c
parentregen (diff)
downloadwireguard-openbsd-5f9b80c09d01899b9236c70716888c6ce8f727d7.tar.xz
wireguard-openbsd-5f9b80c09d01899b9236c70716888c6ce8f727d7.zip
Don't advertise L0s if the "aspm-no-l0s" property is present. Base available
bus numbers on the "bus-range" property. Create outbound translations based on the "ranges" property.
-rw-r--r--sys/dev/fdt/rkpcie.c164
1 files changed, 127 insertions, 37 deletions
diff --git a/sys/dev/fdt/rkpcie.c b/sys/dev/fdt/rkpcie.c
index 7fdba4594b4..7d8e7a7070b 100644
--- a/sys/dev/fdt/rkpcie.c
+++ b/sys/dev/fdt/rkpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rkpcie.c,v 1.1 2018/01/02 22:33:17 kettenis Exp $ */
+/* $OpenBSD: rkpcie.c,v 1.2 2018/01/06 20:31:03 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -63,6 +63,8 @@
#define PCIE_LM_RCBARPIS (1 << 20)
#define PCIE_RC_BASE 0xa00000
+#define PCIE_RC_PCIE_LCAP (PCIE_RC_BASE + 0x0cc)
+#define PCIE_RC_PCIE_LCAP_APMS_L0S (1 << 10)
#define PCIE_ATR_BASE 0xc00000
#define PCIE_ATR_OB_ADDR0(i) (PCIE_ATR_BASE + 0x000 + (i) * 0x20)
@@ -77,6 +79,9 @@
#define PCIE_ATR_HDR_CFG_TYPE1 0xb
#define PCIE_ATR_HDR_RID (1 << 23)
+#define PCIE_ATR_OB_REGION0_SIZE (32 * 1024 * 1024)
+#define PCIE_ATR_OB_REGION_SIZE (1 * 1024 * 1024)
+
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
@@ -87,6 +92,8 @@ struct rkpcie_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_space_handle_t sc_axi_ioh;
+ bus_addr_t sc_axi_addr;
+ bus_addr_t sc_apb_addr;
int sc_node;
int sc_phy_node;
@@ -94,6 +101,7 @@ struct rkpcie_softc {
struct extent *sc_busex;
struct extent *sc_memex;
struct extent *sc_ioex;
+ int sc_bus;
};
int rkpcie_match(struct device *, void *, void *);
@@ -144,6 +152,7 @@ rkpcie_attach(struct device *parent, struct device *self, void *aux)
struct fdt_attach_args *faa = aux;
struct pcibus_attach_args pba;
uint32_t *ep_gpio;
+ uint32_t bus_range[2];
uint32_t status;
int len, timo;
@@ -167,6 +176,8 @@ rkpcie_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ sc->sc_axi_addr = faa->fa_reg[0].addr;
+ sc->sc_apb_addr = faa->fa_reg[1].addr;
sc->sc_node = faa->fa_node;
printf("\n");
@@ -237,6 +248,31 @@ rkpcie_attach(struct device *parent, struct device *self, void *aux)
PCI_SUBCLASS_BRIDGE_PCI << PCI_SUBCLASS_SHIFT);
HWRITE4(sc, PCIE_LM_RCBAR, PCIE_LM_RCBARPIE | PCIE_LM_RCBARPIS);
+ if (OF_getproplen(sc->sc_node, "aspm-no-l0s") == 0) {
+ status = HREAD4(sc, PCIE_RC_PCIE_LCAP);
+ status &= ~PCIE_RC_PCIE_LCAP_APMS_L0S;
+ HWRITE4(sc, PCIE_RC_PCIE_LCAP, status);
+ }
+
+ /* Create extents for our address spaces. */
+ sc->sc_busex = extent_create("pcibus", 0, 255,
+ M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
+ sc->sc_memex = extent_create("pcimem", 0, (u_long)-1,
+ M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
+ sc->sc_ioex = extent_create("pciio", 0, 0xffffffff,
+ M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
+
+ /* Set up bus range. */
+ if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range,
+ sizeof(bus_range)) != sizeof(bus_range) ||
+ bus_range[0] >= 32 || bus_range[1] >= 32) {
+ bus_range[0] = 0;
+ bus_range[1] = 31;
+ }
+ sc->sc_bus = bus_range[0];
+ extent_free(sc->sc_busex, bus_range[0],
+ bus_range[1] - bus_range[0] + 1, EX_WAITOK);
+
/* Configure Address Translation. */
rkpcie_atr_init(sc);
@@ -267,7 +303,7 @@ rkpcie_attach(struct device *parent, struct device *self, void *aux)
pba.pba_memex = sc->sc_memex;
pba.pba_ioex = sc->sc_ioex;
pba.pba_domain = pci_ndomains++;
- pba.pba_bus = 0;
+ pba.pba_bus = sc->sc_bus;
config_found(self, &pba, NULL);
}
@@ -275,6 +311,12 @@ rkpcie_attach(struct device *parent, struct device *self, void *aux)
void
rkpcie_atr_init(struct rkpcie_softc *sc)
{
+ uint32_t *ranges;
+ struct extent *ex;
+ bus_addr_t addr;
+ bus_size_t size, offset;
+ uint32_t type;
+ int len, region;
int i;
/* Use region 0 to map PCI configuration space. */
@@ -284,36 +326,72 @@ rkpcie_atr_init(struct rkpcie_softc *sc)
PCIE_ATR_HDR_CFG_TYPE0 | PCIE_ATR_HDR_RID);
HWRITE4(sc, PCIE_ATR_OB_DESC1(0), 0);
- /* Use region 1-6 to map PCI memory space. */
- for (i = 1; i < 7; i++) {
- HWRITE4(sc, PCIE_ATR_OB_ADDR0(i), 32 - 1);
- HWRITE4(sc, PCIE_ATR_OB_ADDR1(i), 0);
- HWRITE4(sc, PCIE_ATR_OB_DESC0(i),
- PCIE_ATR_HDR_MEM | PCIE_ATR_HDR_RID);
- HWRITE4(sc, PCIE_ATR_OB_DESC1(i), 0);
+ len = OF_getproplen(sc->sc_node, "ranges");
+ if (len <= 0 || (len % (7 * sizeof(uint32_t))) != 0)
+ goto fail;
+ ranges = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "ranges", ranges, len);
+
+ for (i = 0; i < len / sizeof(uint32_t); i += 7) {
+ /* Handle IO and MMIO. */
+ switch (ranges[i] & 0x03000000) {
+ case 0x01000000:
+ type = PCIE_ATR_HDR_IO;
+ ex = sc->sc_ioex;
+ break;
+ case 0x02000000:
+ case 0x03000000:
+ type = PCIE_ATR_HDR_MEM;
+ ex = sc->sc_memex;
+ break;
+ default:
+ continue;
+ }
+
+ /* Only support identity mappings. */
+ if (ranges[i + 1] != ranges[i + 3] ||
+ ranges[i + 2] != ranges[i + 4])
+ goto fail;
+
+ /* Only support mappings aligned on a region boundary. */
+ addr = ((uint64_t)ranges[i + 1] << 32) + ranges[i + 2];
+ if (addr & (PCIE_ATR_OB_REGION_SIZE - 1))
+ goto fail;
+
+ /* Mappings should lie between AXI and APB regions. */
+ size = ranges[i + 6];
+ if (addr < sc->sc_axi_addr + PCIE_ATR_OB_REGION0_SIZE)
+ goto fail;
+ if (addr + size > sc->sc_apb_addr)
+ goto fail;
+
+ offset = addr - sc->sc_axi_addr - PCIE_ATR_OB_REGION0_SIZE;
+ region = 1 + (offset / PCIE_ATR_OB_REGION_SIZE);
+ while (size > 0) {
+ HWRITE4(sc, PCIE_ATR_OB_ADDR0(region), 32 - 1);
+ HWRITE4(sc, PCIE_ATR_OB_ADDR1(region), 0);
+ HWRITE4(sc, PCIE_ATR_OB_DESC0(region),
+ type | PCIE_ATR_HDR_RID);
+ HWRITE4(sc, PCIE_ATR_OB_DESC1(region), 0);
+
+ extent_free(ex, addr, PCIE_ATR_OB_REGION_SIZE,
+ EX_WAITOK);
+ addr += PCIE_ATR_OB_REGION_SIZE;
+ size -= PCIE_ATR_OB_REGION_SIZE;
+ region++;
+ }
}
- /* Use region 7 to map PCI IO space. */
- HWRITE4(sc, PCIE_ATR_OB_ADDR0(7), 32 - 1);
- HWRITE4(sc, PCIE_ATR_OB_ADDR1(7), 0);
- HWRITE4(sc, PCIE_ATR_OB_DESC0(7),
- PCIE_ATR_HDR_IO | PCIE_ATR_HDR_RID);
- HWRITE4(sc, PCIE_ATR_OB_DESC1(7), 0);
-
/* Passthrought inbound translations unmodified. */
HWRITE4(sc, PCIE_ATR_IB_ADDR0(2), 32 - 1);
HWRITE4(sc, PCIE_ATR_IB_ADDR1(2), 0);
- /* Create extents matching the translations set up above. */
- sc->sc_busex = extent_create("pcibus", 0, 255,
- M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
- extent_free(sc->sc_busex, 0, 2, EX_WAITOK);
- sc->sc_memex = extent_create("pcimem", 0, (u_long)-1,
- M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
- extent_free(sc->sc_memex, 0xfa000000, 0x600000, EX_WAITOK);
- sc->sc_ioex = extent_create("pciio", 0, 0xffffffff,
- M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
- extent_free(sc->sc_ioex, 0xfa600000, 0x100000, EX_WAITOK);
+ free(ranges, M_TEMP, len);
+ return;
+
+fail:
+ printf("%s: can't map ranges\n", sc->sc_dev.dv_xname);
+ free(ranges, M_TEMP, len);
}
void
@@ -323,9 +401,13 @@ rkpcie_attach_hook(struct device *parent, struct device *self,
}
int
-rkpcie_bus_maxdevs(void *v, int busno)
+rkpcie_bus_maxdevs(void *v, int bus)
{
- return 1;
+ struct rkpcie_softc *sc = v;
+
+ if (bus == sc->sc_bus || bus == sc->sc_bus + 1)
+ return 1;
+ return 32;
}
pcitag_t
@@ -359,12 +441,16 @@ rkpcie_conf_read(void *v, pcitag_t tag, int reg)
int bus, dev, fn;
rkpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
- if (bus == 0 && dev == 0)
+ if (bus == sc->sc_bus) {
+ KASSERT(dev == 0);
return HREAD4(sc, PCIE_RC_NORMAL_BASE + tag | reg);
- if (bus != 1)
- return 0xffffffff;
-
- return bus_space_read_4(sc->sc_iot, sc->sc_axi_ioh, tag | reg);
+ }
+ if (bus == sc->sc_bus + 1) {
+ KASSERT(dev == 0);
+ return bus_space_read_4(sc->sc_iot, sc->sc_axi_ioh, tag | reg);
+ }
+
+ return 0xffffffff;
}
void
@@ -374,12 +460,16 @@ rkpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
int bus, dev, fn;
rkpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
- if (bus == 0 && dev == 0)
+ if (bus == sc->sc_bus) {
+ KASSERT(dev == 0);
HWRITE4(sc, PCIE_RC_NORMAL_BASE + tag | reg, data);
- if (bus != 1)
return;
-
- bus_space_write_4(sc->sc_iot, sc->sc_axi_ioh, tag | reg, data);
+ }
+ if (bus == sc->sc_bus + 1) {
+ KASSERT(dev == 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_axi_ioh, tag | reg, data);
+ return;
+ }
}
struct rkpcie_intr_handle {