From 0d546792d5af128d40fe9210a319bd3cac253227 Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 28 Dec 2023 13:32:56 +0000 Subject: [PATCH] Add stream ID mapping support for PCIe controller found on M2 Pro/Max SoCs. ok patrick@ --- sys/arch/arm64/dev/aplpcie.c | 111 +++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 23 deletions(-) diff --git a/sys/arch/arm64/dev/aplpcie.c b/sys/arch/arm64/dev/aplpcie.c index f3700149b13..fae016ee23f 100644 --- a/sys/arch/arm64/dev/aplpcie.c +++ b/sys/arch/arm64/dev/aplpcie.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplpcie.c,v 1.17 2023/09/21 20:26:17 kettenis Exp $ */ +/* $OpenBSD: aplpcie.c,v 1.18 2023/12/28 13:32:56 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -74,10 +74,13 @@ #define PCIE_PORT_RID2SID_VALID (1U << 31) #define PCIE_PORT_RID2SID_SID_SHIFT 16 #define PCIE_PORT_RID2SID_RID_MASK 0x0000ffff +#define PCIE_PORT_MAX_RID2SID 64 #define PCIE_T6020_PORT_MSI_DOORBELL_LO 0x016c #define PCIE_T6020_PORT_MSI_DOORBELL_HI 0x0170 #define PCIE_T6020_PORT_PERST 0x082c +#define PCIE_T6020_PORT_RID2SID(idx) (0x3000 + (idx) * 4) +#define PCIE_T6020_PORT_MAX_RID2SID 512 #define PCIE_T6020_PORT_MSI_MAP(idx) (0x3800 + (idx) * 4) #define PCIE_T6020_PORT_MSI_MAP_ENABLE (1U << 31) @@ -472,7 +475,7 @@ aplpcie_init_port(struct aplpcie_softc *sc, int node) /* * Clear stream ID mappings. */ - for (idx = 0; idx < 16; idx++) + for (idx = 0; idx < PCIE_PORT_MAX_RID2SID; idx++) PWRITE4(sc, port, PCIE_PORT_RID2SID(idx), 0); /* Check if the link is already up. */ @@ -565,7 +568,7 @@ aplpcie_t6020_init_port(struct aplpcie_softc *sc, int node) uint32_t *reset_gpio; int pwren_gpiolen, reset_gpiolen; uint32_t stat; - int msi, port, timo; + int idx, msi, port, timo; if (OF_getprop(node, "status", status, sizeof(status)) > 0 && strcmp(status, "disabled") == 0) @@ -596,6 +599,12 @@ aplpcie_t6020_init_port(struct aplpcie_softc *sc, int node) PWRITE4(sc, port, PCIE_T6020_PORT_MSI_DOORBELL_HI, sc->sc_msi_doorbell >> 32); + /* + * Clear stream ID mappings. + */ + for (idx = 0; idx < PCIE_T6020_PORT_MAX_RID2SID; idx++) + PWRITE4(sc, port, PCIE_T6020_PORT_RID2SID(idx), 0); + /* Check if the link is already up. */ stat = PREAD4(sc, port, PCIE_PORT_LINK_STAT); if (stat & PCIE_PORT_LINK_STAT_UP) @@ -782,13 +791,76 @@ aplpcie_find_port(struct aplpcie_softc *sc, int bus) return -1; } +int +aplpcie_map_rid(struct aplpcie_softc *sc, int port, uint16_t rid, uint32_t sid) +{ + uint32_t reg; + int idx; + + for (idx = 0; idx < PCIE_PORT_MAX_RID2SID; idx++) { + reg = PREAD4(sc, port, PCIE_PORT_RID2SID(idx)); + + /* If already mapped, we're done. */ + if ((reg & PCIE_PORT_RID2SID_RID_MASK) == rid) + return 0; + + /* Is this an empty slot? */ + if (reg & PCIE_PORT_RID2SID_VALID) + continue; + + /* Map using this slot. */ + reg = (sid << PCIE_PORT_RID2SID_SID_SHIFT) | rid | + PCIE_PORT_RID2SID_VALID; + PWRITE4(sc, port, PCIE_PORT_RID2SID(idx), reg); + + /* Read back to check the slot is implemented. */ + if (PREAD4(sc, port, PCIE_PORT_RID2SID(idx)) != reg) + return ENODEV; + return 0; + } + + return ENODEV; +} + +int +aplpcie_t6020_map_rid(struct aplpcie_softc *sc, int port, uint16_t rid, + uint32_t sid) +{ + uint32_t reg; + int idx; + + for (idx = 0; idx < PCIE_T6020_PORT_MAX_RID2SID; idx++) { + reg = PREAD4(sc, port, PCIE_T6020_PORT_RID2SID(idx)); + + /* If already mapped, we're done. */ + if ((reg & PCIE_PORT_RID2SID_RID_MASK) == rid) + return 0; + + /* Is this an empty slot? */ + if (reg & PCIE_PORT_RID2SID_VALID) + continue; + + /* Map using this slot. */ + reg = (sid << PCIE_PORT_RID2SID_SID_SHIFT) | rid | + PCIE_PORT_RID2SID_VALID; + PWRITE4(sc, port, PCIE_T6020_PORT_RID2SID(idx), reg); + + /* Read back to check the slot is implemented. */ + if (PREAD4(sc, port, PCIE_T6020_PORT_RID2SID(idx)) != reg) + return ENODEV; + return 0; + } + + return ENODEV; +} + int aplpcie_probe_device_hook(void *v, struct pci_attach_args *pa) { struct aplpcie_softc *sc = v; - uint32_t phandle, reg, sid; + uint32_t phandle, sid; uint16_t rid; - int idx, port; + int error, port; rid = pci_requester_id(pa->pa_pc, pa->pa_tag); pa->pa_dmat = iommu_device_map_pci(sc->sc_node, rid, pa->pa_dmat); @@ -807,26 +879,19 @@ aplpcie_probe_device_hook(void *v, struct pci_attach_args *pa) if (port == -1) return EINVAL; - for (idx = 0; idx < 16; idx++) { - reg = PREAD4(sc, port, PCIE_PORT_RID2SID(idx)); - - /* If already mapped, we're done. */ - if ((reg & PCIE_PORT_RID2SID_RID_MASK) == rid) - return 0; - - /* Is this an empty slot? */ - if (reg & PCIE_PORT_RID2SID_VALID) - continue; - - /* Map using this slot. */ - reg = (sid << PCIE_PORT_RID2SID_SID_SHIFT) | rid | - PCIE_PORT_RID2SID_VALID; - PWRITE4(sc, port, PCIE_PORT_RID2SID(idx), reg); - return 0; + if (OF_is_compatible(sc->sc_node, "apple,t6020-pcie")) + error = aplpcie_t6020_map_rid(sc, port, rid, sid); + else + error = aplpcie_map_rid(sc, port, rid, sid); + if (error) { + printf("%s: out of stream ID mapping slots\n", + sc->sc_dev.dv_xname); } - printf("%s: out of stream ID mapping slots\n", - sc->sc_dev.dv_xname); + /* + * Not all PCI devices do DMA, so don't return an error if we + * ran out of stream ID mapping slots. + */ return 0; } -- 2.20.1