machintr: Add intr_config interface
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 18 Mar 2011 09:05:44 +0000 (17:05 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 18 Mar 2011 09:11:13 +0000 (17:11 +0800)
This interface is used to change pre-configured interrupt's trigger
mode and polarity.

sys/platform/pc32/apic/ioapic_abi.c
sys/platform/pc32/icu/icu_abi.c
sys/platform/pc64/apic/ioapic_abi.c
sys/platform/pc64/icu/icu_abi.c
sys/sys/machintr.h

index a8c3240..a1ac440 100644 (file)
@@ -457,6 +457,7 @@ static struct ioapic_irqmap {
        enum intr_trigger       im_trig;
        enum intr_polarity      im_pola;
        int                     im_gsi;
+       uint32_t                im_flags;       /* IOAPIC_IMF_ */
 } ioapic_irqmaps[MAX_HARDINTS];        /* XXX MAX_HARDINTS may not be correct */
 
 #define IOAPIC_IMT_UNUSED      0
@@ -464,6 +465,8 @@ static struct ioapic_irqmap {
 #define IOAPIC_IMT_LINE                2
 #define IOAPIC_IMT_SYSCALL     3
 
+#define IOAPIC_IMF_CONF                0x1
+
 extern void    IOAPIC_INTREN(int);
 extern void    IOAPIC_INTRDIS(int);
 
@@ -475,6 +478,7 @@ static void ioapic_cleanup(void);
 static void    ioapic_setdefault(void);
 static void    ioapic_stabilize(void);
 static void    ioapic_initmap(void);
+static void    ioapic_intr_config(int, enum intr_trigger, enum intr_polarity);
 
 static int     ioapic_imcr_present;
 
@@ -489,7 +493,8 @@ struct machintr_abi MachIntrABI_IOAPIC = {
        .cleanup        = ioapic_cleanup,
        .setdefault     = ioapic_setdefault,
        .stabilize      = ioapic_stabilize,
-       .initmap        = ioapic_initmap
+       .initmap        = ioapic_initmap,
+       .intr_config    = ioapic_intr_config
 };
 
 static int
@@ -755,11 +760,11 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
 
        if (bootverbose) {
                kprintf("IOAPIC: irq %d -> gsi %d %c\n", irq, map->im_gsi,
-                       trig == INTR_TRIGGER_LEVEL ? 'L' : 'E');
+                       map->im_trig == INTR_TRIGGER_LEVEL ? 'L' : 'E');
        }
 
-       pin = ioapic_gsi_pin(gsi);
-       ioaddr = ioapic_gsi_ioaddr(gsi);
+       pin = ioapic_gsi_pin(map->im_gsi);
+       ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
 
        info = &int_to_apicintpin[irq];
 
@@ -768,7 +773,68 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
        info->apic_address = ioaddr;
        info->redirindex = IOAPIC_REDTBL + (2 * pin);
        info->flags = IOAPIC_IM_FLAG_MASKED;
-       if (trig == INTR_TRIGGER_LEVEL)
+       if (map->im_trig == INTR_TRIGGER_LEVEL)
+               info->flags |= IOAPIC_IM_FLAG_LEVEL;
+
+       ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
+           map->im_trig, map->im_pola);
+}
+
+static void
+ioapic_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
+{
+       struct apic_intmapinfo *info;
+       struct ioapic_irqmap *map;
+       void *ioaddr;
+       int pin;
+
+       if (ioapic_use_old)
+               return;
+
+       KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
+       KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
+       KKASSERT((trig == INTR_TRIGGER_EDGE && pola == INTR_POLARITY_HIGH) ||
+                (trig == INTR_TRIGGER_LEVEL && pola == INTR_POLARITY_LOW));
+
+       KKASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS);
+       map = &ioapic_irqmaps[irq];
+
+       KKASSERT(map->im_type == IOAPIC_IMT_LINE);
+
+       if (map->im_flags & IOAPIC_IMF_CONF) {
+               if (trig != map->im_trig) {
+                       panic("ioapic_intr_config: trig %c -> %c\n",
+                             map->im_trig == INTR_TRIGGER_EDGE ? 'E' : 'L',
+                             trig == INTR_TRIGGER_EDGE ? 'E' : 'L');
+               }
+               if (pola != map->im_pola) {
+                       panic("ioapic_intr_config: pola %s -> %s\n",
+                             map->im_pola == INTR_POLARITY_HIGH ? "hi" : "lo",
+                             pola == INTR_POLARITY_HIGH ? "hi" : "lo");
+               }
+               return;
+       }
+       map->im_flags |= IOAPIC_IMF_CONF;
+
+       if (trig == map->im_trig && pola == map->im_pola)
+               return;
+
+       if (bootverbose) {
+               kprintf("IOAPIC: irq %d, gsi %d %c -> %c\n", irq, map->im_gsi,
+                       map->im_trig == INTR_TRIGGER_LEVEL ? 'L' : 'E',
+                       trig == INTR_TRIGGER_LEVEL ? 'L' : 'E');
+       }
+
+       map->im_trig = trig;
+       map->im_pola = pola;
+
+       pin = ioapic_gsi_pin(map->im_gsi);
+       ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
+
+       info = &int_to_apicintpin[irq];
+
+       info->flags &= ~IOAPIC_IM_FLAG_LEVEL;
+       if (map->im_trig == INTR_TRIGGER_LEVEL)
                info->flags |= IOAPIC_IM_FLAG_LEVEL;
 
        ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
index a26d92c..67b4f00 100644 (file)
@@ -102,6 +102,7 @@ static void icu_cleanup(void);
 static void    icu_setdefault(void);
 static void    icu_stabilize(void);
 static void    icu_initmap(void);
+static void    icu_intr_config(int, enum intr_trigger, enum intr_polarity);
 
 struct machintr_abi MachIntrABI_ICU = {
        MACHINTR_ICU,
@@ -114,7 +115,8 @@ struct machintr_abi MachIntrABI_ICU = {
        .cleanup        = icu_cleanup,
        .setdefault     = icu_setdefault,
        .stabilize      = icu_stabilize,
-       .initmap        = icu_initmap
+       .initmap        = icu_initmap,
+       .intr_config    = icu_intr_config
 };
 
 static int     icu_imcr_present;
@@ -308,3 +310,9 @@ icu_initmap(void)
        }
        icu_irqmaps[IDT_OFFSET_SYSCALL - IDT_OFFSET].im_type = ICU_IMT_SYSCALL;
 }
+
+static void
+icu_intr_config(int irq __unused, enum intr_trigger trig __unused,
+    enum intr_polarity pola __unused)
+{
+}
index a2db183..cdd6946 100644 (file)
@@ -457,6 +457,7 @@ static struct ioapic_irqmap {
        enum intr_trigger       im_trig;
        enum intr_polarity      im_pola;
        int                     im_gsi;
+       uint32_t                im_flags;       /* IOAPIC_IMF_ */
 } ioapic_irqmaps[MAX_HARDINTS];        /* XXX MAX_HARDINTS may not be correct */
 
 #define IOAPIC_IMT_UNUSED      0
@@ -464,6 +465,8 @@ static struct ioapic_irqmap {
 #define IOAPIC_IMT_LINE                2
 #define IOAPIC_IMT_SYSCALL     3
 
+#define IOAPIC_IMF_CONF                0x1
+
 extern void    IOAPIC_INTREN(int);
 extern void    IOAPIC_INTRDIS(int);
 
@@ -475,6 +478,7 @@ static void ioapic_cleanup(void);
 static void    ioapic_setdefault(void);
 static void    ioapic_stabilize(void);
 static void    ioapic_initmap(void);
+static void    ioapic_intr_config(int, enum intr_trigger, enum intr_polarity);
 
 static int     ioapic_imcr_present;
 
@@ -489,7 +493,8 @@ struct machintr_abi MachIntrABI_IOAPIC = {
        .cleanup        = ioapic_cleanup,
        .setdefault     = ioapic_setdefault,
        .stabilize      = ioapic_stabilize,
-       .initmap        = ioapic_initmap
+       .initmap        = ioapic_initmap,
+       .intr_config    = ioapic_intr_config
 };
 
 static int
@@ -748,11 +753,11 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
 
        if (bootverbose) {
                kprintf("IOAPIC: irq %d -> gsi %d %c\n", irq, map->im_gsi,
-                       trig == INTR_TRIGGER_LEVEL ? 'L' : 'E');
+                       map->im_trig == INTR_TRIGGER_LEVEL ? 'L' : 'E');
        }
 
-       pin = ioapic_gsi_pin(gsi);
-       ioaddr = ioapic_gsi_ioaddr(gsi);
+       pin = ioapic_gsi_pin(map->im_gsi);
+       ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
 
        info = &int_to_apicintpin[irq];
 
@@ -761,7 +766,68 @@ ioapic_abi_set_irqmap(int irq, int gsi, enum intr_trigger trig,
        info->apic_address = ioaddr;
        info->redirindex = IOAPIC_REDTBL + (2 * pin);
        info->flags = IOAPIC_IM_FLAG_MASKED;
-       if (trig == INTR_TRIGGER_LEVEL)
+       if (map->im_trig == INTR_TRIGGER_LEVEL)
+               info->flags |= IOAPIC_IM_FLAG_LEVEL;
+
+       ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
+           map->im_trig, map->im_pola);
+}
+
+static void
+ioapic_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
+{
+       struct apic_intmapinfo *info;
+       struct ioapic_irqmap *map;
+       void *ioaddr;
+       int pin;
+
+       if (ioapic_use_old)
+               return;
+
+       KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
+       KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
+       KKASSERT((trig == INTR_TRIGGER_EDGE && pola == INTR_POLARITY_HIGH) ||
+                (trig == INTR_TRIGGER_LEVEL && pola == INTR_POLARITY_LOW));
+
+       KKASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS);
+       map = &ioapic_irqmaps[irq];
+
+       KKASSERT(map->im_type == IOAPIC_IMT_LINE);
+
+       if (map->im_flags & IOAPIC_IMF_CONF) {
+               if (trig != map->im_trig) {
+                       panic("ioapic_intr_config: trig %c -> %c\n",
+                             map->im_trig == INTR_TRIGGER_EDGE ? 'E' : 'L',
+                             trig == INTR_TRIGGER_EDGE ? 'E' : 'L');
+               }
+               if (pola != map->im_pola) {
+                       panic("ioapic_intr_config: pola %s -> %s\n",
+                             map->im_pola == INTR_POLARITY_HIGH ? "hi" : "lo",
+                             pola == INTR_POLARITY_HIGH ? "hi" : "lo");
+               }
+               return;
+       }
+       map->im_flags |= IOAPIC_IMF_CONF;
+
+       if (trig == map->im_trig && pola == map->im_pola)
+               return;
+
+       if (bootverbose) {
+               kprintf("IOAPIC: irq %d, gsi %d %c -> %c\n", irq, map->im_gsi,
+                       map->im_trig == INTR_TRIGGER_LEVEL ? 'L' : 'E',
+                       trig == INTR_TRIGGER_LEVEL ? 'L' : 'E');
+       }
+
+       map->im_trig = trig;
+       map->im_pola = pola;
+
+       pin = ioapic_gsi_pin(map->im_gsi);
+       ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
+
+       info = &int_to_apicintpin[irq];
+
+       info->flags &= ~IOAPIC_IM_FLAG_LEVEL;
+       if (map->im_trig == INTR_TRIGGER_LEVEL)
                info->flags |= IOAPIC_IM_FLAG_LEVEL;
 
        ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
index ab6197f..1004bc7 100644 (file)
@@ -102,6 +102,7 @@ static void icu_cleanup(void);
 static void    icu_setdefault(void);
 static void    icu_stabilize(void);
 static void    icu_initmap(void);
+static void    icu_intr_config(int, enum intr_trigger, enum intr_polarity);
 
 struct machintr_abi MachIntrABI_ICU = {
        MACHINTR_ICU,
@@ -114,7 +115,8 @@ struct machintr_abi MachIntrABI_ICU = {
        .cleanup        = icu_cleanup,
        .setdefault     = icu_setdefault,
        .stabilize      = icu_stabilize,
-       .initmap        = icu_initmap
+       .initmap        = icu_initmap,
+       .intr_config    = icu_intr_config
 };
 
 static int     icu_imcr_present;
@@ -308,3 +310,9 @@ icu_initmap(void)
        }
        icu_irqmaps[i].im_type = ICU_IMT_SYSCALL;
 }
+
+static void
+icu_intr_config(int irq __unused, enum intr_trigger trig __unused,
+    enum intr_polarity pola __unused)
+{
+}
index 3655d63..dda6fbd 100644 (file)
@@ -38,6 +38,9 @@
  * vector and masking layer.
  */
 
+#ifndef _SYS_BUS_H_
+#include <sys/bus.h>
+#endif
 #ifndef _SYS_QUEUE_H_
 #include <sys/queue.h>
 #endif
@@ -66,6 +69,8 @@ struct machintr_abi {
     void       (*setdefault)(void);            /* set default vectors */
     void       (*stabilize)(void);             /* stable before ints enabled */
     void       (*initmap)(void);               /* init irq mapping */
+    void       (*intr_config)                  /* config intr */
+               (int, enum intr_trigger, enum intr_polarity);
 };
 
 #define machintr_intren(intr)  MachIntrABI.intren(intr)
@@ -75,6 +80,9 @@ struct machintr_abi {
 #define machintr_vector_teardown(intr)         \
            MachIntrABI.vectorctl(MACHINTR_VECTOR_TEARDOWN, intr, 0)
 
+#define machintr_intr_config(intr, trig, pola) \
+           MachIntrABI.intr_config((intr), (trig), (pola))
+
 #ifdef _KERNEL
 
 extern struct machintr_abi MachIntrABI;