Module Name: src Committed By: jmcneill Date: Sun Aug 8 10:28:26 UTC 2021
Modified Files: src/sys/arch/arm/acpi: acpi_machdep.c Log Message: arm: ACPI: Add support for simple sharing of platform interrupts Allow sharing of platform interrupts provided that the type, ipl, and mpsafe-ness are the same. To generate a diff of this commit: cvs rdiff -u -r1.24 -r1.25 src/sys/arch/arm/acpi/acpi_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/acpi/acpi_machdep.c diff -u src/sys/arch/arm/acpi/acpi_machdep.c:1.24 src/sys/arch/arm/acpi/acpi_machdep.c:1.25 --- src/sys/arch/arm/acpi/acpi_machdep.c:1.24 Sat Aug 7 18:40:45 2021 +++ src/sys/arch/arm/acpi/acpi_machdep.c Sun Aug 8 10:28:26 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_machdep.c,v 1.24 2021/08/07 18:40:45 jmcneill Exp $ */ +/* $NetBSD: acpi_machdep.c,v 1.25 2021/08/08 10:28:26 jmcneill Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #include "pci.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.24 2021/08/07 18:40:45 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.25 2021/08/08 10:28:26 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -63,6 +63,27 @@ extern struct bus_space arm_generic_bs_t extern struct arm32_bus_dma_tag acpi_coherent_dma_tag; extern struct arm32_bus_dma_tag arm_generic_dma_tag; +struct acpi_intrhandler { + int (*ah_fn)(void *); + void *ah_arg; + TAILQ_ENTRY(acpi_intrhandler) ah_list; +}; + +struct acpi_intrvec { + int ai_irq; + int ai_ipl; + int ai_type; + bool ai_mpsafe; + int ai_refcnt; + void *ai_arg; + void *ai_ih; + TAILQ_HEAD(, acpi_intrhandler) ai_handlers; + TAILQ_ENTRY(acpi_intrvec) ai_list; +}; + +static TAILQ_HEAD(, acpi_intrvec) acpi_intrvecs = + TAILQ_HEAD_INITIALIZER(acpi_intrvecs); + bus_dma_tag_t arm_acpi_dma32_tag(struct acpi_softc *, struct acpi_devnode *); bus_dma_tag_t arm_acpi_dma64_tag(struct acpi_softc *, struct acpi_devnode *); @@ -256,28 +277,128 @@ acpi_md_OsDisableInterrupt(void) cpsid(I32_bit); } +static struct acpi_intrvec * +acpi_md_intr_lookup(int irq) +{ + struct acpi_intrvec *ai; + + TAILQ_FOREACH(ai, &acpi_intrvecs, ai_list) { + if (ai->ai_irq == irq) { + return ai; + } + } + + return NULL; +} + +static int +acpi_md_intr(void *arg) +{ + struct acpi_intrvec *ai = arg; + struct acpi_intrhandler *ah; + int rv = 0; + + TAILQ_FOREACH(ah, &ai->ai_handlers, ah_list) { + rv += ah->ah_fn(ah->ah_arg); + } + + return rv; +} + void * acpi_md_intr_establish(uint32_t irq, int ipl, int type, int (*handler)(void *), void *arg, bool mpsafe, const char *xname) { - return intr_establish_xname(irq, ipl, type | (mpsafe ? IST_MPSAFE : 0), handler, arg, xname); + struct acpi_intrvec *ai; + struct acpi_intrhandler *ah; + + ai = acpi_md_intr_lookup(irq); + if (ai == NULL) { + ai = kmem_zalloc(sizeof(*ai), KM_SLEEP); + ai->ai_refcnt = 0; + ai->ai_irq = irq; + ai->ai_ipl = ipl; + ai->ai_type = type; + ai->ai_mpsafe = mpsafe; + ai->ai_arg = arg; + TAILQ_INIT(&ai->ai_handlers); + if (arg == NULL) { + ai->ai_ih = intr_establish_xname(irq, ipl, + type | (mpsafe ? IST_MPSAFE : 0), handler, NULL, + xname); + } else { + ai->ai_ih = intr_establish_xname(irq, ipl, + type | (mpsafe ? IST_MPSAFE : 0), acpi_md_intr, ai, + xname); + } + if (ai->ai_ih == NULL) { + kmem_free(ai, sizeof(*ai)); + return NULL; + } + TAILQ_INSERT_TAIL(&acpi_intrvecs, ai, ai_list); + } else { + if (ai->ai_arg == NULL) { + printf("ACPI: cannot share irq with NULL arg\n"); + return NULL; + } + if (ai->ai_ipl != ipl) { + printf("ACPI: cannot share irq with different ipl\n"); + return NULL; + } + if (ai->ai_type != type) { + printf("ACPI: cannot share edge and level interrupts\n"); + return NULL; + } + if (ai->ai_mpsafe != mpsafe) { + printf("ACPI: cannot share between mpsafe/non-mpsafe\n"); + return NULL; + } + } + + ai->ai_refcnt++; + + ah = kmem_zalloc(sizeof(*ah), KM_SLEEP); + ah->ah_fn = handler; + ah->ah_arg = arg; + TAILQ_INSERT_TAIL(&ai->ai_handlers, ah, ah_list); + + return ai->ai_ih; } void -acpi_md_intr_mask(void *ih) +acpi_md_intr_disestablish(void *ih) { - intr_mask(ih); + struct acpi_intrvec *ai; + struct acpi_intrhandler *ah; + + TAILQ_FOREACH(ai, &acpi_intrvecs, ai_list) { + if (ai->ai_ih == ih) { + KASSERT(ai->ai_refcnt > 0); + if (ai->ai_refcnt > 1) { + panic("%s: cannot disestablish shared irq", __func__); + } + + TAILQ_REMOVE(&acpi_intrvecs, ai, ai_list); + ah = TAILQ_FIRST(&ai->ai_handlers); + kmem_free(ah, sizeof(*ah)); + intr_disestablish(ai->ai_ih); + kmem_free(ai, sizeof(*ai)); + return; + } + } + + panic("%s: interrupt not established", __func__); } void -acpi_md_intr_unmask(void *ih) +acpi_md_intr_mask(void *ih) { - intr_unmask(ih); + intr_mask(ih); } void -acpi_md_intr_disestablish(void *ih) +acpi_md_intr_unmask(void *ih) { - intr_disestablish(ih); + intr_unmask(ih); } int