-/* $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 <kettenis@openbsd.org>
*
#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)
/*
* 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. */
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)
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)
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);
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;
}