svn commit: r217238 - in head/sys/dev/acpica: . Osd

Jung-uk Kim jkim at FreeBSD.org
Mon Jan 10 20:56:59 UTC 2011


Author: jkim
Date: Mon Jan 10 20:56:59 2011
New Revision: 217238
URL: http://svn.freebsd.org/changeset/base/217238

Log:
  Allow AcpiOsInstallInterruptHandler() and AcpiOsRemoveInterruptHandler() to
  install or remove non-SCI interrupt handlers per ACPI Component Architecture
  User Guide and Programmer Reference.  ACPICA may install such interrupt
  handler when a GPE block device is found, for example.  Add a wrapper for
  ACPI_OSD_HANDLER, convert its return values to ours, and make it a filter.
  Prefer KASSERT(9) over panic(9) as we have never seen those in reality.
  Clean up some style(9) nits and add my copyright.

Modified:
  head/sys/dev/acpica/Osd/OsdInterrupt.c
  head/sys/dev/acpica/acpivar.h

Modified: head/sys/dev/acpica/Osd/OsdInterrupt.c
==============================================================================
--- head/sys/dev/acpica/Osd/OsdInterrupt.c	Mon Jan 10 20:48:10 2011	(r217237)
+++ head/sys/dev/acpica/Osd/OsdInterrupt.c	Mon Jan 10 20:56:59 2011	(r217238)
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 2000 Michael Smith
  * Copyright (c) 2000 BSDi
+ * Copyright (c) 2011 Jung-uk Kim <jkim at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,10 +36,13 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <sys/rman.h>
- 
+
 #include <contrib/dev/acpica/include/acpi.h>
 #include <contrib/dev/acpica/include/accommon.h>
 
@@ -47,101 +51,166 @@ __FBSDID("$FreeBSD$");
 #define _COMPONENT	ACPI_OS_SERVICES
 ACPI_MODULE_NAME("INTERRUPT")
 
-static UINT32		InterruptOverride = 0;
+MALLOC_DEFINE(M_ACPIINTR, "acpiintr", "ACPI interrupt");
 
-ACPI_STATUS
-AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,
-    ACPI_OSD_HANDLER ServiceRoutine, void *Context)
-{
-    struct acpi_softc	*sc;
+struct acpi_intr {
+	SLIST_ENTRY(acpi_intr)	ai_link;
+	struct resource		*ai_irq;
+	int			ai_rid;
+	void			*ai_handle;
+	int			ai_number;
+	ACPI_OSD_HANDLER	ai_handler;
+	void			*ai_context;
+};
+static SLIST_HEAD(, acpi_intr) acpi_intr_list =
+    SLIST_HEAD_INITIALIZER(acpi_intr_list);
+static struct mtx	acpi_intr_lock;
 
-    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+static UINT32		InterruptOverride;
 
-    if ((sc = devclass_get_softc(devclass_find("acpi"), 0)) == NULL)
-	panic("can't find ACPI device to register interrupt");
-    if (sc->acpi_dev == NULL)
-	panic("acpi softc has invalid device");
-
-    if (InterruptNumber < 0 || InterruptNumber > 255)
-	return_ACPI_STATUS (AE_BAD_PARAMETER);
-    if (ServiceRoutine == NULL)
-	return_ACPI_STATUS (AE_BAD_PARAMETER);
-
-    /*
-     * If the MADT contained an interrupt override directive for the SCI,
-     * we use that value instead of the one from the FADT.
-     */
-    if (InterruptOverride != 0) {
-	    device_printf(sc->acpi_dev,
-		"Overriding SCI Interrupt from IRQ %u to IRQ %u\n",
-		InterruptNumber, InterruptOverride);
-	    InterruptNumber = InterruptOverride;
-    }
-
-    /* Set up the interrupt resource. */
-    sc->acpi_irq_rid = 0;
-    bus_set_resource(sc->acpi_dev, SYS_RES_IRQ, 0, InterruptNumber, 1);
-    sc->acpi_irq = bus_alloc_resource_any(sc->acpi_dev, SYS_RES_IRQ,
-	&sc->acpi_irq_rid, RF_SHAREABLE | RF_ACTIVE);
-    if (sc->acpi_irq == NULL) {
-	device_printf(sc->acpi_dev, "could not allocate interrupt\n");
-	goto error;
-    }
-    if (bus_setup_intr(sc->acpi_dev, sc->acpi_irq, INTR_TYPE_MISC|INTR_MPSAFE,
-	NULL, (driver_intr_t *)ServiceRoutine, Context, &sc->acpi_irq_handle)) {
-	device_printf(sc->acpi_dev, "could not set up interrupt\n");
-	goto error;
-    }
+static void
+acpi_intr_init(struct mtx *lock)
+{
 
-    return_ACPI_STATUS (AE_OK);
+	mtx_init(lock, "ACPI interrupt lock", NULL, MTX_DEF);
+}
 
-error:
-    if (sc->acpi_irq_handle)
-	bus_teardown_intr(sc->acpi_dev, sc->acpi_irq, sc->acpi_irq_handle);
-    sc->acpi_irq_handle = NULL;
-    if (sc->acpi_irq)
-	bus_release_resource(sc->acpi_dev, SYS_RES_IRQ, 0, sc->acpi_irq);
-    sc->acpi_irq = NULL;
-    bus_delete_resource(sc->acpi_dev, SYS_RES_IRQ, 0);
+SYSINIT(acpi_intr, SI_SUB_DRIVERS, SI_ORDER_FIRST, acpi_intr_init,
+    &acpi_intr_lock);
+
+static int
+acpi_intr_handler(void *arg)
+{
+	struct acpi_intr *ai;
 
-    return_ACPI_STATUS (AE_ALREADY_EXISTS);
+	ai = arg;
+	KASSERT(ai != NULL && ai->ai_handler != NULL,
+	    ("invalid ACPI interrupt handler"));
+	if (ai->ai_handler(ai->ai_context) == ACPI_INTERRUPT_HANDLED)
+		return (FILTER_HANDLED);
+	return (FILTER_STRAY);
 }
 
 ACPI_STATUS
-AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber, ACPI_OSD_HANDLER ServiceRoutine)
+AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,
+    ACPI_OSD_HANDLER ServiceRoutine, void *Context)
 {
-    struct acpi_softc	*sc;
-
-    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	struct acpi_softc *sc;
+	struct acpi_intr *ai, *ap;
 
-    if (InterruptNumber < 0 || InterruptNumber > 255)
-	return_ACPI_STATUS (AE_BAD_PARAMETER);
-    if (ServiceRoutine == NULL)
-	return_ACPI_STATUS (AE_BAD_PARAMETER);
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
-    if ((sc = devclass_get_softc(devclass_find("acpi"), 0)) == NULL)
-	panic("can't find ACPI device to deregister interrupt");
+	sc = devclass_get_softc(devclass_find("acpi"), 0);
+	KASSERT(sc != NULL && sc->acpi_dev != NULL,
+	    ("can't find ACPI device to register interrupt"));
+
+	if (InterruptNumber < 0 || InterruptNumber > 255 ||
+	    ServiceRoutine == NULL)
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+	ai = malloc(sizeof(*ai), M_ACPIINTR, M_WAITOK | M_ZERO);
+	mtx_lock(&acpi_intr_lock);
+	SLIST_FOREACH(ap, &acpi_intr_list, ai_link) {
+		if (InterruptNumber == ap->ai_number ||
+		    (InterruptNumber == InterruptOverride &&
+		    InterruptNumber != AcpiGbl_FADT.SciInterrupt)) {
+			mtx_unlock(&acpi_intr_lock);
+			return_ACPI_STATUS (AE_ALREADY_EXISTS);
+		}
+		if (ai->ai_rid <= ap->ai_rid)
+			ai->ai_rid = ap->ai_rid + 1;
+	}
+	ai->ai_number = InterruptNumber;
+	ai->ai_handler = ServiceRoutine;
+	ai->ai_context = Context;
+
+	/*
+	 * If the MADT contained an interrupt override directive for the SCI,
+	 * we use that value instead of the one from the FADT.
+	 */
+	if (InterruptOverride != 0 &&
+	    InterruptNumber == AcpiGbl_FADT.SciInterrupt) {
+		device_printf(sc->acpi_dev,
+		    "Overriding SCI from IRQ %u to IRQ %u\n",
+		    InterruptNumber, InterruptOverride);
+		InterruptNumber = InterruptOverride;
+	}
+
+	/* Set up the interrupt resource. */
+	bus_set_resource(sc->acpi_dev, SYS_RES_IRQ, ai->ai_rid,
+	    InterruptNumber, 1);
+	ai->ai_irq = bus_alloc_resource_any(sc->acpi_dev, SYS_RES_IRQ,
+	    &ai->ai_rid, RF_SHAREABLE | RF_ACTIVE);
+	if (ai->ai_irq == NULL) {
+		device_printf(sc->acpi_dev, "could not allocate interrupt\n");
+		goto error;
+	}
+	if (bus_setup_intr(sc->acpi_dev, ai->ai_irq,
+	    INTR_TYPE_MISC | INTR_MPSAFE, acpi_intr_handler, NULL, ai,
+	    &ai->ai_handle) != 0) {
+		device_printf(sc->acpi_dev, "could not set up interrupt\n");
+		goto error;
+	}
+	SLIST_INSERT_HEAD(&acpi_intr_list, ai, ai_link);
+	mtx_unlock(&acpi_intr_lock);
+	return_ACPI_STATUS (AE_OK);
 
-    if (sc->acpi_irq == NULL)
-	return_ACPI_STATUS (AE_NOT_EXIST);
+error:
+	mtx_unlock(&acpi_intr_lock);
+	if (ai->ai_handle != NULL)
+		bus_teardown_intr(sc->acpi_dev, ai->ai_irq, ai->ai_handle);
+	if (ai->ai_irq != NULL)
+		bus_release_resource(sc->acpi_dev, SYS_RES_IRQ, ai->ai_rid,
+		    ai->ai_irq);
+	bus_delete_resource(sc->acpi_dev, SYS_RES_IRQ, ai->ai_rid);
+	free(ai, M_ACPIINTR);
+	return_ACPI_STATUS (AE_ALREADY_EXISTS);
+}
 
-    bus_teardown_intr(sc->acpi_dev, sc->acpi_irq, sc->acpi_irq_handle);
-    bus_release_resource(sc->acpi_dev, SYS_RES_IRQ, 0, sc->acpi_irq);
-    bus_delete_resource(sc->acpi_dev, SYS_RES_IRQ, 0);
+ACPI_STATUS
+AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber,
+    ACPI_OSD_HANDLER ServiceRoutine)
+{
+	struct acpi_softc *sc;
+	struct acpi_intr *ai;
 
-    sc->acpi_irq = NULL;
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
-    return_ACPI_STATUS (AE_OK);
+	sc = devclass_get_softc(devclass_find("acpi"), 0);
+	KASSERT(sc != NULL && sc->acpi_dev != NULL,
+	    ("can't find ACPI device to deregister interrupt"));
+
+	if (InterruptNumber < 0 || InterruptNumber > 255 ||
+	    ServiceRoutine == NULL)
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
+	mtx_lock(&acpi_intr_lock);
+	SLIST_FOREACH(ai, &acpi_intr_list, ai_link)
+		if (InterruptNumber == ai->ai_number) {
+			if (ServiceRoutine != ai->ai_handler) {
+				mtx_unlock(&acpi_intr_lock);
+				return_ACPI_STATUS (AE_BAD_PARAMETER);
+			}
+			SLIST_REMOVE(&acpi_intr_list, ai, acpi_intr, ai_link);
+			break;
+		}
+	mtx_unlock(&acpi_intr_lock);
+	if (ai == NULL)
+		return_ACPI_STATUS (AE_NOT_EXIST);
+	bus_teardown_intr(sc->acpi_dev, ai->ai_irq, ai->ai_handle);
+	bus_release_resource(sc->acpi_dev, SYS_RES_IRQ, ai->ai_rid, ai->ai_irq);
+	bus_delete_resource(sc->acpi_dev, SYS_RES_IRQ, ai->ai_rid);
+	free(ai, M_ACPIINTR);
+	return_ACPI_STATUS (AE_OK);
 }
 
 ACPI_STATUS
 acpi_OverrideInterruptLevel(UINT32 InterruptNumber)
 {
 
-    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
-    if (InterruptOverride != 0)
-	return_ACPI_STATUS (AE_ALREADY_EXISTS);
-    InterruptOverride = InterruptNumber;
-    return_ACPI_STATUS (AE_OK);
+	if (InterruptOverride != 0)
+		return_ACPI_STATUS (AE_ALREADY_EXISTS);
+	InterruptOverride = InterruptNumber;
+	return_ACPI_STATUS (AE_OK);
 }

Modified: head/sys/dev/acpica/acpivar.h
==============================================================================
--- head/sys/dev/acpica/acpivar.h	Mon Jan 10 20:48:10 2011	(r217237)
+++ head/sys/dev/acpica/acpivar.h	Mon Jan 10 20:56:59 2011	(r217238)
@@ -51,10 +51,6 @@ struct acpi_softc {
     device_t		acpi_dev;
     struct cdev		*acpi_dev_t;
 
-    struct resource	*acpi_irq;
-    int			acpi_irq_rid;
-    void		*acpi_irq_handle;
-
     int			acpi_enabled;
     int			acpi_sstate;
     int			acpi_sleep_disabled;


More information about the svn-src-head mailing list