Changeset View
Changeset View
Standalone View
Standalone View
head/sys/x86/x86/msi.c
Show All 38 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_acpi.h" | #include "opt_acpi.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/limits.h> | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <x86/apicreg.h> | #include <x86/apicreg.h> | ||||
#include <machine/cputypes.h> | #include <machine/cputypes.h> | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | struct pic msi_pic = { | ||||
.pic_resume = NULL, | .pic_resume = NULL, | ||||
.pic_config_intr = msi_config_intr, | .pic_config_intr = msi_config_intr, | ||||
.pic_assign_cpu = msi_assign_cpu, | .pic_assign_cpu = msi_assign_cpu, | ||||
.pic_reprogram_pin = NULL, | .pic_reprogram_pin = NULL, | ||||
}; | }; | ||||
u_int first_msi_irq; | u_int first_msi_irq; | ||||
u_int num_msi_irqs = 512; | |||||
SYSCTL_UINT(_machdep, OID_AUTO, num_msi_irqs, CTLFLAG_RDTUN, &num_msi_irqs, 0, | |||||
"Number of IRQs reserved for MSI and MSI-X interrupts"); | |||||
#ifdef SMP | #ifdef SMP | ||||
/** | /** | ||||
* Xen hypervisors prior to 4.6.0 do not properly handle updates to | * Xen hypervisors prior to 4.6.0 do not properly handle updates to | ||||
* enabled MSI-X table entries. Allow migration of MSI-X interrupts | * enabled MSI-X table entries. Allow migration of MSI-X interrupts | ||||
* to be disabled via a tunable. Values have the following meaning: | * to be disabled via a tunable. Values have the following meaning: | ||||
* | * | ||||
* -1: automatic detection by FreeBSD | * -1: automatic detection by FreeBSD | ||||
* 0: enable migration | * 0: enable migration | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | |||||
#ifdef SMP | #ifdef SMP | ||||
if (msix_disable_migration == -1) { | if (msix_disable_migration == -1) { | ||||
/* The default is to allow migration of MSI-X interrupts. */ | /* The default is to allow migration of MSI-X interrupts. */ | ||||
msix_disable_migration = 0; | msix_disable_migration = 0; | ||||
} | } | ||||
#endif | #endif | ||||
if (num_msi_irqs == 0) | |||||
return; | |||||
first_msi_irq = max(MINIMUM_MSI_INT, num_io_irqs); | first_msi_irq = max(MINIMUM_MSI_INT, num_io_irqs); | ||||
num_io_irqs = first_msi_irq + NUM_MSI_INTS; | if (num_msi_irqs > UINT_MAX - first_msi_irq) | ||||
panic("num_msi_irq too high"); | |||||
num_io_irqs = first_msi_irq + num_msi_irqs; | |||||
msi_enabled = 1; | msi_enabled = 1; | ||||
intr_register_pic(&msi_pic); | intr_register_pic(&msi_pic); | ||||
mtx_init(&msi_lock, "msi", NULL, MTX_DEF); | mtx_init(&msi_lock, "msi", NULL, MTX_DEF); | ||||
} | } | ||||
static void | static void | ||||
msi_create_source(void) | msi_create_source(void) | ||||
{ | { | ||||
struct msi_intsrc *msi; | struct msi_intsrc *msi; | ||||
u_int irq; | u_int irq; | ||||
mtx_lock(&msi_lock); | mtx_lock(&msi_lock); | ||||
if (msi_last_irq >= NUM_MSI_INTS) { | if (msi_last_irq >= num_msi_irqs) { | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
return; | return; | ||||
} | } | ||||
irq = msi_last_irq + first_msi_irq; | irq = msi_last_irq + first_msi_irq; | ||||
msi_last_irq++; | msi_last_irq++; | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
msi = malloc(sizeof(struct msi_intsrc), M_MSI, M_WAITOK | M_ZERO); | msi = malloc(sizeof(struct msi_intsrc), M_MSI, M_WAITOK | M_ZERO); | ||||
Show All 27 Lines | if (count > 1) | ||||
mirqs = malloc(count * sizeof(*mirqs), M_MSI, M_WAITOK); | mirqs = malloc(count * sizeof(*mirqs), M_MSI, M_WAITOK); | ||||
else | else | ||||
mirqs = NULL; | mirqs = NULL; | ||||
again: | again: | ||||
mtx_lock(&msi_lock); | mtx_lock(&msi_lock); | ||||
/* Try to find 'count' free IRQs. */ | /* Try to find 'count' free IRQs. */ | ||||
cnt = 0; | cnt = 0; | ||||
for (i = first_msi_irq; i < first_msi_irq + NUM_MSI_INTS; i++) { | for (i = first_msi_irq; i < first_msi_irq + num_msi_irqs; i++) { | ||||
msi = (struct msi_intsrc *)intr_lookup_source(i); | msi = (struct msi_intsrc *)intr_lookup_source(i); | ||||
/* End of allocated sources, so break. */ | /* End of allocated sources, so break. */ | ||||
if (msi == NULL) | if (msi == NULL) | ||||
break; | break; | ||||
/* If this is a free one, save its IRQ in the array. */ | /* If this is a free one, save its IRQ in the array. */ | ||||
if (msi->msi_dev == NULL) { | if (msi->msi_dev == NULL) { | ||||
irqs[cnt] = i; | irqs[cnt] = i; | ||||
cnt++; | cnt++; | ||||
if (cnt == count) | if (cnt == count) | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Do we need to create some new sources? */ | /* Do we need to create some new sources? */ | ||||
if (cnt < count) { | if (cnt < count) { | ||||
/* If we would exceed the max, give up. */ | /* If we would exceed the max, give up. */ | ||||
if (i + (count - cnt) > first_msi_irq + NUM_MSI_INTS) { | if (i + (count - cnt) > first_msi_irq + num_msi_irqs) { | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
free(mirqs, M_MSI); | free(mirqs, M_MSI); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
/* We need count - cnt more sources. */ | /* We need count - cnt more sources. */ | ||||
while (cnt < count) { | while (cnt < count) { | ||||
▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | if (msi->msi_first == NULL) { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
msi = msi->msi_first; | msi = msi->msi_first; | ||||
} | } | ||||
#ifdef ACPI_DMAR | #ifdef ACPI_DMAR | ||||
if (!msi->msi_msix) { | if (!msi->msi_msix) { | ||||
for (k = msi->msi_count - 1, i = first_msi_irq; k > 0 && | for (k = msi->msi_count - 1, i = first_msi_irq; k > 0 && | ||||
i < first_msi_irq + NUM_MSI_INTS; i++) { | i < first_msi_irq + num_msi_irqs; i++) { | ||||
if (i == msi->msi_irq) | if (i == msi->msi_irq) | ||||
continue; | continue; | ||||
msi1 = (struct msi_intsrc *)intr_lookup_source(i); | msi1 = (struct msi_intsrc *)intr_lookup_source(i); | ||||
if (!msi1->msi_msix && msi1->msi_first == msi) { | if (!msi1->msi_msix && msi1->msi_first == msi) { | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
iommu_map_msi_intr(msi1->msi_dev, | iommu_map_msi_intr(msi1->msi_dev, | ||||
msi1->msi_cpu, msi1->msi_vector, | msi1->msi_cpu, msi1->msi_vector, | ||||
msi1->msi_remap_cookie, NULL, NULL); | msi1->msi_remap_cookie, NULL, NULL); | ||||
Show All 33 Lines | #endif | ||||
if (bus_get_domain(dev, &domain) != 0) | if (bus_get_domain(dev, &domain) != 0) | ||||
domain = 0; | domain = 0; | ||||
again: | again: | ||||
mtx_lock(&msi_lock); | mtx_lock(&msi_lock); | ||||
/* Find a free IRQ. */ | /* Find a free IRQ. */ | ||||
for (i = first_msi_irq; i < first_msi_irq + NUM_MSI_INTS; i++) { | for (i = first_msi_irq; i < first_msi_irq + num_msi_irqs; i++) { | ||||
msi = (struct msi_intsrc *)intr_lookup_source(i); | msi = (struct msi_intsrc *)intr_lookup_source(i); | ||||
/* End of allocated sources, so break. */ | /* End of allocated sources, so break. */ | ||||
if (msi == NULL) | if (msi == NULL) | ||||
break; | break; | ||||
/* Stop at the first free source. */ | /* Stop at the first free source. */ | ||||
if (msi->msi_dev == NULL) | if (msi->msi_dev == NULL) | ||||
break; | break; | ||||
} | } | ||||
/* Are all IRQs in use? */ | /* Are all IRQs in use? */ | ||||
if (i == first_msi_irq + NUM_MSI_INTS) { | if (i == first_msi_irq + num_msi_irqs) { | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Do we need to create a new source? */ | /* Do we need to create a new source? */ | ||||
if (msi == NULL) { | if (msi == NULL) { | ||||
mtx_unlock(&msi_lock); | mtx_unlock(&msi_lock); | ||||
▲ Show 20 Lines • Show All 85 Lines • Show Last 20 Lines |