From 759fc5332c2b97c3a48b5aefb94b6cab57de07a4 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Thu, 29 Dec 2011 13:56:31 +0800 Subject: [PATCH] x86_64: Add MSI support for ICU MachIntrABI --- sys/platform/pc64/icu/icu_abi.c | 202 +++++++++++++++++++++++++++++++++++--- sys/platform/pc64/x86_64/nexus.c | 4 - 2 files changed, 186 insertions(+), 20 deletions(-) diff --git a/sys/platform/pc64/icu/icu_abi.c b/sys/platform/pc64/icu/icu_abi.c index 7d9ff0c..db6e8f3 100644 --- a/sys/platform/pc64/icu/icu_abi.c +++ b/sys/platform/pc64/icu/icu_abi.c @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -85,12 +86,17 @@ static inthand_t *icu_intr[ICU_HWI_VECTORS] = { static struct icu_irqmap { int im_type; /* ICU_IMT_ */ enum intr_trigger im_trig; + int im_msi_base; } icu_irqmaps[MAXCPU][IDT_HWI_VECTORS]; +static struct lwkt_token icu_irqmap_tok = + LWKT_TOKEN_INITIALIZER(icu_irqmap_token); + #define ICU_IMT_UNUSED 0 /* KEEP THIS */ #define ICU_IMT_RESERVED 1 #define ICU_IMT_LINE 2 #define ICU_IMT_SYSCALL 3 +#define ICU_IMT_MSI 4 #define ICU_IMT_ISHWI(map) ((map)->im_type != ICU_IMT_RESERVED && \ (map)->im_type != ICU_IMT_SYSCALL) @@ -107,6 +113,10 @@ static void icu_abi_intr_teardown(int); static void icu_abi_intr_config(int, enum intr_trigger, enum intr_polarity); static int icu_abi_intr_cpuid(int); +static int icu_abi_msi_alloc(int [], int, int); +static void icu_abi_msi_release(const int [], int, int); +static void icu_abi_msi_map(int, uint64_t *, uint32_t *, int); + static void icu_abi_finalize(void); static void icu_abi_cleanup(void); static void icu_abi_setdefault(void); @@ -123,6 +133,10 @@ struct machintr_abi MachIntrABI_ICU = { .intr_config = icu_abi_intr_config, .intr_cpuid = icu_abi_intr_cpuid, + .msi_alloc = icu_abi_msi_alloc, + .msi_release = icu_abi_msi_release, + .msi_map = icu_abi_msi_map, + .finalize = icu_abi_finalize, .cleanup = icu_abi_cleanup, .setdefault = icu_abi_setdefault, @@ -131,6 +145,8 @@ struct machintr_abi MachIntrABI_ICU = { .rman_setup = icu_abi_rman_setup }; +static int icu_abi_msi_start; /* NOTE: for testing only */ + /* * WARNING! SMP builds can use the ICU now so this code must be MP safe. */ @@ -147,11 +163,8 @@ icu_abi_intr_enable(int irq) KASSERT(ICU_IMT_ISHWI(map), ("icu enable, not hwi irq %d, type %d, cpu%d\n", irq, map->im_type, mycpuid)); - if (map->im_type != ICU_IMT_LINE) { - kprintf("icu enable, irq %d cpu%d not LINE\n", - irq, mycpuid); + if (map->im_type != ICU_IMT_LINE) return; - } ICU_INTREN(irq); } @@ -168,11 +181,8 @@ icu_abi_intr_disable(int irq) KASSERT(ICU_IMT_ISHWI(map), ("icu disable, not hwi irq %d, type %d, cpu%d\n", irq, map->im_type, mycpuid)); - if (map->im_type != ICU_IMT_LINE) { - kprintf("icu disable, irq %d cpu%d not LINE\n", - irq, mycpuid); + if (map->im_type != ICU_IMT_LINE) return; - } ICU_INTRDIS(irq); } @@ -238,11 +248,8 @@ icu_abi_intr_setup(int intr, int flags) KASSERT(ICU_IMT_ISHWI(map), ("icu setup, not hwi irq %d, type %d, cpu%d\n", intr, map->im_type, mycpuid)); - if (map->im_type != ICU_IMT_LINE) { - kprintf("icu setup, irq %d cpu%d not LINE\n", - intr, mycpuid); + if (map->im_type != ICU_IMT_LINE) return; - } ef = read_rflags(); cpu_disable_intr(); @@ -265,11 +272,8 @@ icu_abi_intr_teardown(int intr) KASSERT(ICU_IMT_ISHWI(map), ("icu teardown, not hwi irq %d, type %d, cpu%d\n", intr, map->im_type, mycpuid)); - if (map->im_type != ICU_IMT_LINE) { - kprintf("icu teardown, irq %d cpu%d not LINE\n", - intr, mycpuid); + if (map->im_type != ICU_IMT_LINE) return; - } ef = read_rflags(); cpu_disable_intr(); @@ -297,6 +301,9 @@ icu_abi_initmap(void) { int cpu; + kgetenv_int("hw.icu.msi_start", &icu_abi_msi_start); + icu_abi_msi_start &= ~0x1f; /* MUST be 32 aligned */ + /* * NOTE: ncpus is not ready yet */ @@ -327,6 +334,10 @@ icu_abi_initmap(void) } } } + + for (i = 0; i < IDT_HWI_VECTORS; ++i) + icu_irqmaps[cpu][i].im_msi_base = -1; + icu_irqmaps[cpu][IDT_OFFSET_SYSCALL - IDT_OFFSET].im_type = ICU_IMT_SYSCALL; } @@ -416,3 +427,162 @@ icu_abi_rman_setup(struct rman *rm) } } } + +static int +icu_abi_msi_alloc(int intrs[], int count, int cpuid) +{ + int i, error; + + KASSERT(cpuid >= 0 && cpuid < ncpus, + ("invalid cpuid %d", cpuid)); + + KASSERT(count > 0 && count <= 32, ("invalid count %d\n", count)); + KASSERT((count & (count - 1)) == 0, + ("count %d is not power of 2\n", count)); + + lwkt_gettoken(&icu_irqmap_tok); + + /* + * NOTE: + * Since IDT_OFFSET is 32, which is the maximum valid 'count', + * we do not need to find out the first properly aligned + * interrupt vector. + */ + + error = EMSGSIZE; + for (i = icu_abi_msi_start; i < IDT_HWI_VECTORS; i += count) { + int j; + + if (icu_irqmaps[cpuid][i].im_type != ICU_IMT_UNUSED) + continue; + + for (j = 1; j < count; ++j) { + if (icu_irqmaps[cpuid][i + j].im_type != ICU_IMT_UNUSED) + break; + } + if (j != count) + continue; + + for (j = 0; j < count; ++j) { + struct icu_irqmap *map; + int intr = i + j; + + map = &icu_irqmaps[cpuid][intr]; + KASSERT(map->im_msi_base < 0, + ("intr %d, stale MSI-base %d\n", + intr, map->im_msi_base)); + + map->im_type = ICU_IMT_MSI; + map->im_msi_base = i; + + intrs[j] = intr; + msi_setup(intr, cpuid); + + if (bootverbose) { + kprintf("alloc MSI intr %d on cpu%d\n", + intr, cpuid); + } + + } + error = 0; + break; + } + + lwkt_reltoken(&icu_irqmap_tok); + + return error; +} + +static void +icu_abi_msi_release(const int intrs[], int count, int cpuid) +{ + int i, msi_base = -1, intr_next = -1, mask; + + KASSERT(cpuid >= 0 && cpuid < ncpus, + ("invalid cpuid %d", cpuid)); + + KASSERT(count > 0 && count <= 32, ("invalid count %d\n", count)); + + mask = count - 1; + KASSERT((count & mask) == 0, ("count %d is not power of 2\n", count)); + + lwkt_gettoken(&icu_irqmap_tok); + + for (i = 0; i < count; ++i) { + struct icu_irqmap *map; + int intr = intrs[i]; + + KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS, + ("invalid intr %d\n", intr)); + + map = &icu_irqmaps[cpuid][intr]; + KASSERT(map->im_type == ICU_IMT_MSI, + ("try release non-MSI intr %d, type %d\n", + intr, map->im_type)); + KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr, + ("intr %d, invalid MSI-base %d\n", intr, map->im_msi_base)); + KASSERT((map->im_msi_base & mask) == 0, + ("intr %d, MSI-base %d is not proper aligned %d\n", + intr, map->im_msi_base, count)); + + if (msi_base < 0) { + msi_base = map->im_msi_base; + } else { + KASSERT(map->im_msi_base == msi_base, + ("intr %d, inconsistent MSI-base, " + "was %d, now %d\n", + intr, msi_base, map->im_msi_base)); + } + + if (intr_next < intr) + intr_next = intr; + + map->im_type = ICU_IMT_UNUSED; + map->im_msi_base = -1; + + if (bootverbose) + kprintf("release MSI intr %d on cpu%d\n", intr, cpuid); + } + + KKASSERT(intr_next > 0); + KKASSERT(msi_base >= 0); + + ++intr_next; + if (intr_next < IDT_HWI_VECTORS) { + const struct icu_irqmap *map = &icu_irqmaps[cpuid][intr_next]; + + if (map->im_type == ICU_IMT_MSI) { + KASSERT(map->im_msi_base != msi_base, + ("more than %d MSI was allocated\n", count)); + } + } + + lwkt_reltoken(&icu_irqmap_tok); +} + +static void +icu_abi_msi_map(int intr, uint64_t *addr, uint32_t *data, int cpuid) +{ + const struct icu_irqmap *map; + + KASSERT(cpuid >= 0 && cpuid < ncpus, + ("invalid cpuid %d", cpuid)); + + KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS, + ("invalid intr %d\n", intr)); + + lwkt_gettoken(&icu_irqmap_tok); + + map = &icu_irqmaps[cpuid][intr]; + KASSERT(map->im_type == ICU_IMT_MSI, + ("try map non-MSI intr %d, type %d\n", intr, map->im_type)); + KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr, + ("intr %d, invalid MSI-base %d\n", intr, map->im_msi_base)); + + msi_map(map->im_msi_base, addr, data, cpuid); + + if (bootverbose) + kprintf("map MSI intr %d on cpu%d\n", intr, cpuid); + + lwkt_reltoken(&icu_irqmap_tok); +} diff --git a/sys/platform/pc64/x86_64/nexus.c b/sys/platform/pc64/x86_64/nexus.c index 4365898..1f999bc 100644 --- a/sys/platform/pc64/x86_64/nexus.c +++ b/sys/platform/pc64/x86_64/nexus.c @@ -576,10 +576,6 @@ nexus_alloc_msi(device_t dev, device_t child, int count, int maxcount, if (!lapic_enable) return ENODEV; - /* XXX temporary */ - if (MachIntrABI.msi_alloc == NULL) - return ENODEV; - return MachIntrABI.msi_alloc(irqs, count, cpuid); } -- 1.7.7.2