From: patrick Date: Wed, 10 Aug 2022 17:02:37 +0000 (+0000) Subject: On the Qualcomm SoC as implemented on the Lenovo x13s the BIOS already X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=d0fbdf687140191c5d2b5973e7267c9b0df473e0;p=openbsd On the Qualcomm SoC as implemented on the Lenovo x13s the BIOS already configures and makes use of the SMMU. We need to keep those mappings alive as otherwise the machine will die and reboot. Unfortunately we cannot simply set those domains to bypass, as when we set a domain to bypass it is actually set to fault. Instead reserve a domain and set it to disabled, which behaves the same as if we used a bypass mapping. With feedback from kettenis@ --- diff --git a/sys/arch/arm64/dev/smmu.c b/sys/arch/arm64/dev/smmu.c index 6849487a649..e8f103add8c 100644 --- a/sys/arch/arm64/dev/smmu.c +++ b/sys/arch/arm64/dev/smmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smmu.c,v 1.18 2021/06/25 19:55:22 patrick Exp $ */ +/* $OpenBSD: smmu.c,v 1.19 2022/08/10 17:02:37 patrick Exp $ */ /* * Copyright (c) 2008-2009,2014-2016 Dale Rahn * Copyright (c) 2021 Patrick Wildt @@ -242,13 +242,48 @@ smmu_attach(struct smmu_softc *sc) break; } - printf(": %u CBs (%u S2-only)\n", + printf(": %u CBs (%u S2-only)", sc->sc_num_context_banks, sc->sc_num_s2_context_banks); + if (sc->sc_is_qcom) { + /* + * In theory we should check if bypass quirk is needed by + * modifying S2CR and re-checking if the value is different. + * This does not work on the last S2CR, but on the first, + * which is in use. Revisit this once we have other QCOM HW. + */ + sc->sc_bypass_quirk = 1; + printf(", bypass quirk"); + /* + * Create special context that is turned off. This allows us + * to map a stream to a context bank where translation is not + * happening, and hence bypassed. + */ + sc->sc_cb[sc->sc_num_context_banks - 1] = + malloc(sizeof(struct smmu_cb), M_DEVBUF, M_WAITOK | M_ZERO); + smmu_gr1_write_4(sc, SMMU_CBAR(sc->sc_num_context_banks - 1), + SMMU_CBAR_TYPE_S1_TRANS_S2_BYPASS); + } + printf("\n"); /* Clear Global Fault Status Register */ smmu_gr0_write_4(sc, SMMU_SGFSR, smmu_gr0_read_4(sc, SMMU_SGFSR)); for (i = 0; i < sc->sc_num_streams; i++) { + /* On QCOM HW we need to keep current streams running. */ + if (sc->sc_is_qcom && sc->sc_smr && + smmu_gr0_read_4(sc, SMMU_SMR(i)) & SMMU_SMR_VALID) { + sc->sc_smr[i] = malloc(sizeof(struct smmu_smr), + M_DEVBUF, M_WAITOK | M_ZERO); + if (sc->sc_bypass_quirk) { + smmu_gr0_write_4(sc, SMMU_S2CR(i), + SMMU_S2CR_TYPE_TRANS | + sc->sc_num_context_banks - 1); + } else { + smmu_gr0_write_4(sc, SMMU_S2CR(i), + SMMU_S2CR_TYPE_BYPASS | 0xff); + } + continue; + } #if 1 /* Setup all streams to fault by default */ smmu_gr0_write_4(sc, SMMU_S2CR(i), SMMU_S2CR_TYPE_FAULT); diff --git a/sys/arch/arm64/dev/smmu_acpi.c b/sys/arch/arm64/dev/smmu_acpi.c index 72f888b6a10..97b4804d806 100644 --- a/sys/arch/arm64/dev/smmu_acpi.c +++ b/sys/arch/arm64/dev/smmu_acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smmu_acpi.c,v 1.4 2022/04/06 18:59:26 naddy Exp $ */ +/* $OpenBSD: smmu_acpi.c,v 1.5 2022/08/10 17:02:37 patrick Exp $ */ /* * Copyright (c) 2021 Patrick Wildt * @@ -37,6 +37,8 @@ struct smmu_acpi_softc { int smmu_acpi_match(struct device *, void *, void *); void smmu_acpi_attach(struct device *, struct device *, void *); +int smmu_acpi_foundqcom(struct aml_node *, void *); + const struct cfattach smmu_acpi_ca = { sizeof(struct smmu_acpi_softc), smmu_acpi_match, smmu_acpi_attach }; @@ -97,6 +99,9 @@ smmu_acpi_attach(struct device *parent, struct device *self, void *aux) if (smmu->flags & ACPI_IORT_SMMU_COHERENT) sc->sc_coherent = 1; + /* Check for QCOM devices to enable quirk. */ + aml_find_node(acpi_softc->sc_root, "_HID", smmu_acpi_foundqcom, sc); + if (smmu_attach(sc) != 0) return; @@ -129,3 +134,18 @@ smmu_acpi_attach(struct device *parent, struct device *self, void *aux) as->as_reserve = smmu_reserve_region; acpiiort_smmu_register(as); } + +int +smmu_acpi_foundqcom(struct aml_node *node, void *arg) +{ + struct smmu_softc *sc = (struct smmu_softc *)arg; + char cdev[32], dev[32]; + + if (acpi_parsehid(node, arg, cdev, dev, sizeof(dev)) != 0) + return 0; + + if (strcmp(dev, "QCOM0609") == 0) + sc->sc_is_qcom = 1; + + return 0; +} diff --git a/sys/arch/arm64/dev/smmuvar.h b/sys/arch/arm64/dev/smmuvar.h index 7824c970d4f..e7d97fddc4d 100644 --- a/sys/arch/arm64/dev/smmuvar.h +++ b/sys/arch/arm64/dev/smmuvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smmuvar.h,v 1.6 2021/06/25 17:41:22 patrick Exp $ */ +/* $OpenBSD: smmuvar.h,v 1.7 2022/08/10 17:02:37 patrick Exp $ */ /* * Copyright (c) 2021 Patrick Wildt * @@ -55,6 +55,8 @@ struct smmu_softc { bus_dma_tag_t sc_dmat; int sc_is_mmu500; int sc_is_ap806; + int sc_is_qcom; + int sc_bypass_quirk; size_t sc_pagesize; int sc_numpage; int sc_num_context_banks;