Minor fixes and tweaks to the x86 interrupt code:

- Split the intr_table_lock into an sx lock used for most things, and a
  spin lock to protect intrcnt_index.  Originally I had this as a spin lock
  so interrupt code could use it to lookup sources.  However, we don't
  actually do that because it would add a lot of overhead to interrupts,
  and if we ever do support removing interrupt sources, we can use other
  means to safely do so w/o locking in the interrupt handling code.
- Replace is_enabled (boolean) with is_handlers (a count of handlers) to
  determine if a source is enabled or not.  This allows us to notice when
  a source is no longer in use.  When that happens, we now invoke a new
  PIC method (pic_disable_intr()) to inform the PIC driver that the
  source is no longer in use.  The I/O APIC driver frees the APIC IDT
  vector when this happens.  The MSI driver no longer needs to have a
  hack to clear is_enabled during msi_alloc() and msix_alloc() as a result
  of this change as well.
- Add an apic_disable_vector() to reset an IDT vector back to Xrsvd to
  complement apic_enable_vector() and use it in the I/O APIC and MSI code
  when freeing an IDT vector.
- Add a new nexus hook: nexus_add_irq() to ask the nexus driver to add an
  IRQ to its irq_rman.  The MSI code uses this when it creates new
  interrupt sources to let the nexus know about newly valid IRQs.
  Previously the msi_alloc() and msix_alloc() passed some extra stuff
  back to the nexus methods which then added the IRQs.  This approach is
  a bit cleaner.
- Change the MSI sx lock to a mutex.  If we need to create new sources,
  drop the lock, create the required number of sources, then get the lock
  and try the allocation again.
This commit is contained in:
John Baldwin 2007-05-08 21:29:14 +00:00
parent d287f59062
commit fb610ca1f9
16 changed files with 339 additions and 216 deletions

View File

@ -43,13 +43,14 @@
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/lock.h>
#include <sys/ktr.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/sx.h>
#include <machine/clock.h>
#include <machine/intr_machdep.h>
#include <machine/smp.h>
@ -71,7 +72,8 @@ typedef void (*mask_fn)(void *);
static int intrcnt_index;
static struct intsrc *interrupt_sources[NUM_IO_INTS];
static struct mtx intr_table_lock;
static struct sx intr_table_lock;
static struct mtx intrcnt_lock;
static STAILQ_HEAD(, pic) pics;
#ifdef INTR_FILTER
@ -115,14 +117,14 @@ intr_register_pic(struct pic *pic)
{
int error;
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
if (intr_pic_registered(pic))
error = EBUSY;
else {
STAILQ_INSERT_TAIL(&pics, pic, pics);
error = 0;
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
return (error);
}
@ -150,16 +152,16 @@ intr_register_source(struct intsrc *isrc)
#endif
if (error)
return (error);
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
if (interrupt_sources[vector] != NULL) {
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
intr_event_destroy(isrc->is_event);
return (EEXIST);
}
intrcnt_register(isrc);
interrupt_sources[vector] = isrc;
isrc->is_enabled = 0;
mtx_unlock_spin(&intr_table_lock);
isrc->is_handlers = 0;
sx_xunlock(&intr_table_lock);
return (0);
}
@ -183,19 +185,18 @@ intr_add_handler(const char *name, int vector, driver_filter_t filter,
error = intr_event_add_handler(isrc->is_event, name, filter, handler,
arg, intr_priority(flags), flags, cookiep);
if (error == 0) {
sx_xlock(&intr_table_lock);
intrcnt_updatename(isrc);
mtx_lock_spin(&intr_table_lock);
if (!isrc->is_enabled) {
isrc->is_enabled = 1;
isrc->is_handlers++;
if (isrc->is_handlers == 1) {
#ifdef SMP
if (assign_cpu)
intr_assign_next_cpu(isrc);
#endif
mtx_unlock_spin(&intr_table_lock);
isrc->is_pic->pic_enable_intr(isrc);
} else
mtx_unlock_spin(&intr_table_lock);
isrc->is_pic->pic_enable_source(isrc);
isrc->is_pic->pic_enable_source(isrc);
}
sx_xunlock(&intr_table_lock);
}
return (error);
}
@ -208,8 +209,16 @@ intr_remove_handler(void *cookie)
isrc = intr_handler_source(cookie);
error = intr_event_remove_handler(cookie);
if (error == 0)
if (error == 0) {
sx_xlock(&intr_table_lock);
isrc->is_handlers--;
if (isrc->is_handlers == 0) {
isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI);
isrc->is_pic->pic_disable_intr(isrc);
}
intrcnt_updatename(isrc);
sx_xunlock(&intr_table_lock);
}
return (error);
}
@ -391,12 +400,12 @@ intr_resume(void)
#ifndef DEV_ATPIC
atpic_reset();
#endif
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
STAILQ_FOREACH(pic, &pics, pics) {
if (pic->pic_resume != NULL)
pic->pic_resume(pic);
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
}
void
@ -404,12 +413,12 @@ intr_suspend(void)
{
struct pic *pic;
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
STAILQ_FOREACH(pic, &pics, pics) {
if (pic->pic_suspend != NULL)
pic->pic_suspend(pic);
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
}
static void
@ -432,8 +441,8 @@ intrcnt_register(struct intsrc *is)
{
char straystr[MAXCOMLEN + 1];
/* mtx_assert(&intr_table_lock, MA_OWNED); */
KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__));
mtx_lock_spin(&intrcnt_lock);
is->is_index = intrcnt_index;
intrcnt_index += 2;
snprintf(straystr, MAXCOMLEN + 1, "stray irq%d",
@ -442,17 +451,18 @@ intrcnt_register(struct intsrc *is)
is->is_count = &intrcnt[is->is_index];
intrcnt_setname(straystr, is->is_index + 1);
is->is_straycount = &intrcnt[is->is_index + 1];
mtx_unlock_spin(&intrcnt_lock);
}
void
intrcnt_add(const char *name, u_long **countp)
{
mtx_lock_spin(&intr_table_lock);
mtx_lock_spin(&intrcnt_lock);
*countp = &intrcnt[intrcnt_index];
intrcnt_setname(name, intrcnt_index);
intrcnt_index++;
mtx_unlock_spin(&intr_table_lock);
mtx_unlock_spin(&intrcnt_lock);
}
static void
@ -462,7 +472,8 @@ intr_init(void *dummy __unused)
intrcnt_setname("???", 0);
intrcnt_index = 1;
STAILQ_INIT(&pics);
mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
sx_init(&intr_table_lock, "intr sources");
mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL)
@ -570,14 +581,14 @@ intr_shuffle_irqs(void *arg __unused)
return;
/* Round-robin assign a CPU to each enabled source. */
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
assign_cpu = 1;
for (i = 0; i < NUM_IO_INTS; i++) {
isrc = interrupt_sources[i];
if (isrc != NULL && isrc->is_enabled)
if (isrc != NULL && isrc->is_handlers > 0)
intr_assign_next_cpu(isrc);
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
}
SYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs, NULL)
#endif

View File

@ -114,6 +114,7 @@ static void ioapic_enable_source(struct intsrc *isrc);
static void ioapic_disable_source(struct intsrc *isrc, int eoi);
static void ioapic_eoi_source(struct intsrc *isrc);
static void ioapic_enable_intr(struct intsrc *isrc);
static void ioapic_disable_intr(struct intsrc *isrc);
static int ioapic_vector(struct intsrc *isrc);
static int ioapic_source_pending(struct intsrc *isrc);
static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
@ -125,8 +126,8 @@ static void ioapic_program_intpin(struct ioapic_intsrc *intpin);
static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
ioapic_eoi_source, ioapic_enable_intr,
ioapic_vector, ioapic_source_pending,
NULL, ioapic_resume,
ioapic_disable_intr, ioapic_vector,
ioapic_source_pending, NULL, ioapic_resume,
ioapic_config_intr, ioapic_assign_cpu };
static int next_ioapic_base;
@ -359,6 +360,23 @@ ioapic_enable_intr(struct intsrc *isrc)
}
}
static void
ioapic_disable_intr(struct intsrc *isrc)
{
struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
u_int vector;
if (intpin->io_vector != 0) {
/* Mask this interrupt pin and free its APIC vector. */
vector = intpin->io_vector;
apic_disable_vector(vector);
intpin->io_masked = 1;
intpin->io_vector = 0;
ioapic_program_intpin(intpin);
apic_free_vector(vector, intpin->io_irq);
}
}
static int
ioapic_vector(struct intsrc *isrc)
{

View File

@ -147,6 +147,8 @@ static u_int32_t lapic_timer_divisors[] = {
APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128
};
extern inthand_t IDTVEC(rsvd);
volatile lapic_t *lapic;
vm_paddr_t lapic_paddr;
static u_long lapic_timer_divisor, lapic_timer_period, lapic_timer_hz;
@ -837,6 +839,16 @@ apic_enable_vector(u_int vector)
setidt(vector, ioint_handlers[vector / 32], SDT_SYSIGT, SEL_KPL, 0);
}
void
apic_disable_vector(u_int vector)
{
KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
KASSERT(ioint_handlers[vector / 32] != NULL,
("No ISR handler for vector %u", vector));
setidt(vector, &IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
}
/* Release an APIC vector when it's no longer in use. */
void
apic_free_vector(u_int vector, u_int irq)

View File

@ -112,11 +112,12 @@ struct msi_intsrc {
u_int msi_count:8; /* Messages in this group. (g) */
};
static struct msi_intsrc *msi_create_source(u_int irq);
static void msi_create_source(void);
static void msi_enable_source(struct intsrc *isrc);
static void msi_disable_source(struct intsrc *isrc, int eoi);
static void msi_eoi_source(struct intsrc *isrc);
static void msi_enable_intr(struct intsrc *isrc);
static void msi_disable_intr(struct intsrc *isrc);
static int msi_vector(struct intsrc *isrc);
static int msi_source_pending(struct intsrc *isrc);
static int msi_config_intr(struct intsrc *isrc, enum intr_trigger trig,
@ -124,11 +125,13 @@ static int msi_config_intr(struct intsrc *isrc, enum intr_trigger trig,
static void msi_assign_cpu(struct intsrc *isrc, u_int apic_id);
struct pic msi_pic = { msi_enable_source, msi_disable_source, msi_eoi_source,
msi_enable_intr, msi_vector, msi_source_pending,
NULL, NULL, msi_config_intr, msi_assign_cpu };
msi_enable_intr, msi_disable_intr, msi_vector,
msi_source_pending, NULL, NULL, msi_config_intr,
msi_assign_cpu };
static int msi_enabled;
static struct sx msi_sx;
static int msi_last_irq;
static struct mtx msi_lock;
static void
msi_enable_source(struct intsrc *isrc)
@ -158,6 +161,14 @@ msi_enable_intr(struct intsrc *isrc)
apic_enable_vector(msi->msi_vector);
}
static void
msi_disable_intr(struct intsrc *isrc)
{
struct msi_intsrc *msi = (struct msi_intsrc *)isrc;
apic_disable_vector(msi->msi_vector);
}
static int
msi_vector(struct intsrc *isrc)
{
@ -191,8 +202,7 @@ msi_assign_cpu(struct intsrc *isrc, u_int apic_id)
printf("msi: Assigning %s IRQ %d to local APIC %u\n",
msi->msi_msix ? "MSI-X" : "MSI", msi->msi_irq,
msi->msi_cpu);
if (isrc->is_enabled)
pci_remap_msi_irq(msi->msi_dev, msi->msi_irq);
pci_remap_msi_irq(msi->msi_dev, msi->msi_irq);
}
void
@ -206,19 +216,29 @@ msi_init(void)
msi_enabled = 1;
intr_register_pic(&msi_pic);
sx_init(&msi_sx, "msi");
mtx_init(&msi_lock, "msi", NULL, MTX_DEF);
}
struct msi_intsrc *
msi_create_source(u_int irq)
void
msi_create_source(void)
{
struct msi_intsrc *msi;
u_int irq;
msi = malloc(sizeof(struct msi_intsrc), M_MSI, M_WAITOK | M_ZERO);
mtx_lock(&msi_lock);
if (msi_last_irq >= NUM_MSI_INTS) {
mtx_unlock(&msi_lock);
return;
}
irq = msi_last_irq + FIRST_MSI_INT;
msi_last_irq++;
mtx_unlock(&msi_lock);
msi = malloc(sizeof(struct msi_intsrc), M_MSI, M_WAITOK | M_ZERO);
msi->msi_intsrc.is_pic = &msi_pic;
msi->msi_irq = irq;
intr_register_source(&msi->msi_intsrc);
return (msi);
nexus_add_irq(irq);
}
/*
@ -228,18 +248,16 @@ msi_create_source(u_int irq)
* and *newcount being the number of new IRQ values added.
*/
int
msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
int *newcount)
msi_alloc(device_t dev, int count, int maxcount, int *irqs)
{
struct msi_intsrc *msi, *fsrc;
int cnt, i, j, vector;
int cnt, i, vector;
*newirq = 0;
*newcount = 0;
if (!msi_enabled)
return (ENXIO);
sx_xlock(&msi_sx);
again:
mtx_lock(&msi_lock);
/* Try to find 'count' free IRQs. */
cnt = 0;
@ -263,20 +281,17 @@ msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
if (cnt < count) {
/* If we would exceed the max, give up. */
if (i + (count - cnt) > FIRST_MSI_INT + NUM_MSI_INTS) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
mtx_unlock(&msi_lock);
/* We need count - cnt more sources starting at index 'cnt'. */
*newirq = cnt;
*newcount = count - cnt;
for (j = 0; j < *newcount; j++) {
/* Create a new MSI source and add it to our array. */
msi_create_source(i + j);
irqs[cnt] = i + j;
/* We need count - cnt more sources. */
while (cnt < count) {
msi_create_source();
cnt++;
}
goto again;
}
/* Ok, we now have the IRQs allocated. */
@ -285,7 +300,7 @@ msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
/* Allocate 'count' IDT vectors. */
vector = apic_alloc_vectors(irqs, count, maxcount);
if (vector == 0) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOSPC);
}
@ -299,12 +314,11 @@ msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
printf("msi: routing MSI IRQ %d to vector %u\n",
msi->msi_irq, msi->msi_vector);
msi->msi_first = fsrc;
/* XXX: Somewhat gross. */
msi->msi_intsrc.is_enabled = 0;
KASSERT(msi->msi_intsrc.is_handlers == 0,
("dead MSI has handlers"));
}
fsrc->msi_count = count;
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}
@ -315,22 +329,22 @@ msi_release(int *irqs, int count)
struct msi_intsrc *msi, *first;
int i;
sx_xlock(&msi_sx);
mtx_lock(&msi_lock);
first = (struct msi_intsrc *)intr_lookup_source(irqs[0]);
if (first == NULL) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOENT);
}
/* Make sure this isn't an MSI-X message. */
if (first->msi_msix) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (EINVAL);
}
/* Make sure this message is allocated to a group. */
if (first->msi_first == NULL) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
@ -339,7 +353,7 @@ msi_release(int *irqs, int count)
* the entire group.
*/
if (first->msi_first != first || first->msi_count != count) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (EINVAL);
}
KASSERT(first->msi_dev != NULL, ("unowned group"));
@ -362,7 +376,7 @@ msi_release(int *irqs, int count)
first->msi_vector = 0;
first->msi_count = 0;
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}
@ -371,27 +385,27 @@ msi_map(int irq, uint64_t *addr, uint32_t *data)
{
struct msi_intsrc *msi;
sx_slock(&msi_sx);
mtx_lock(&msi_lock);
msi = (struct msi_intsrc *)intr_lookup_source(irq);
if (msi == NULL) {
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOENT);
}
/* Make sure this message is allocated to a device. */
if (msi->msi_dev == NULL) {
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
/*
* If this message isn't an MSI-X message, make sure it's part
* of a gruop, and switch to the first message in the
* of a group, and switch to the first message in the
* group.
*/
if (!msi->msi_msix) {
if (msi->msi_first == NULL) {
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
msi = msi->msi_first;
@ -399,21 +413,21 @@ msi_map(int irq, uint64_t *addr, uint32_t *data)
*addr = INTEL_ADDR(msi);
*data = INTEL_DATA(msi);
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}
int
msix_alloc(device_t dev, int *irq, int *new)
msix_alloc(device_t dev, int *irq)
{
struct msi_intsrc *msi;
int i, vector;
*new = 0;
if (!msi_enabled)
return (ENXIO);
sx_xlock(&msi_sx);
again:
mtx_lock(&msi_lock);
/* Find a free IRQ. */
for (i = FIRST_MSI_INT; i < FIRST_MSI_INT + NUM_MSI_INTS; i++) {
@ -423,7 +437,7 @@ msix_alloc(device_t dev, int *irq, int *new)
if (msi == NULL)
break;
/* If this is a free one, start or continue a run. */
/* Stop at the first free source. */
if (msi->msi_dev == NULL)
break;
}
@ -432,13 +446,14 @@ msix_alloc(device_t dev, int *irq, int *new)
if (msi == NULL) {
/* If we would exceed the max, give up. */
if (i + 1 > FIRST_MSI_INT + NUM_MSI_INTS) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
mtx_unlock(&msi_lock);
/* Create a new source. */
*new = 1;
msi = msi_create_source(i);
msi_create_source();
goto again;
}
/* Allocate an IDT vector. */
@ -452,9 +467,8 @@ msix_alloc(device_t dev, int *irq, int *new)
msi->msi_vector = vector;
msi->msi_msix = 1;
/* XXX: Somewhat gross. */
msi->msi_intsrc.is_enabled = 0;
sx_xunlock(&msi_sx);
KASSERT(msi->msi_intsrc.is_handlers == 0, ("dead MSI-X has handlers"));
mtx_unlock(&msi_lock);
*irq = i;
return (0);
@ -465,16 +479,16 @@ msix_release(int irq)
{
struct msi_intsrc *msi;
sx_xlock(&msi_sx);
mtx_lock(&msi_lock);
msi = (struct msi_intsrc *)intr_lookup_source(irq);
if (msi == NULL) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOENT);
}
/* Make sure this is an MSI-X message. */
if (!msi->msi_msix) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (EINVAL);
}
@ -486,6 +500,6 @@ msix_release(int irq)
msi->msi_vector = 0;
msi->msi_msix = 0;
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}

View File

@ -503,15 +503,20 @@ nexus_delete_resource(device_t dev, device_t child, int type, int rid)
resource_list_delete(rl, type, rid);
}
/* Called from the MSI code to add new IRQs to the IRQ rman. */
void
nexus_add_irq(u_long irq)
{
if (rman_manage_region(&irq_rman, irq, irq) != 0)
panic("%s: failed", __func__);
}
static int
nexus_alloc_msix(device_t pcib, device_t dev, int *irq)
{
int error, new;
error = msix_alloc(dev, irq, &new);
if (new)
rman_manage_region(&irq_rman, *irq, *irq);
return (error);
return (msix_alloc(dev, irq));
}
static int
@ -524,17 +529,8 @@ nexus_release_msix(device_t pcib, device_t dev, int irq)
static int
nexus_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
{
int error, i, newirq, newcount;
/* First alloc the messages. */
error = msi_alloc(dev, count, maxcount, irqs, &newirq, &newcount);
/* Always add any new IRQs to the rman, even on failure. */
for (i = 0; i < newcount; i++)
rman_manage_region(&irq_rman, irqs[newirq + i],
irqs[newirq + i]);
return (error);
return (msi_alloc(dev, count, maxcount, irqs));
}
static int

View File

@ -178,6 +178,7 @@ extern vm_paddr_t lapic_paddr;
u_int apic_alloc_vector(u_int irq);
u_int apic_alloc_vectors(u_int *irqs, u_int count, u_int align);
void apic_disable_vector(u_int vector);
void apic_enable_vector(u_int vector);
void apic_free_vector(u_int vector, u_int irq);
u_int apic_idt_to_irq(u_int vector);

View File

@ -86,6 +86,7 @@ struct pic {
void (*pic_disable_source)(struct intsrc *, int);
void (*pic_eoi_source)(struct intsrc *);
void (*pic_enable_intr)(struct intsrc *);
void (*pic_disable_intr)(struct intsrc *);
int (*pic_vector)(struct intsrc *);
int (*pic_source_pending)(struct intsrc *);
void (*pic_suspend)(struct pic *);
@ -114,7 +115,7 @@ struct intsrc {
u_long *is_count;
u_long *is_straycount;
u_int is_index;
u_int is_enabled:1;
u_int is_handlers;
};
struct trapframe;
@ -146,12 +147,12 @@ int intr_remove_handler(void *cookie);
void intr_resume(void);
void intr_suspend(void);
void intrcnt_add(const char *name, u_long **countp);
int msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
int *newcount);
void nexus_add_irq(u_long irq);
int msi_alloc(device_t dev, int count, int maxcount, int *irqs);
void msi_init(void);
int msi_map(int irq, uint64_t *addr, uint32_t *data);
int msi_release(int *irqs, int count);
int msix_alloc(device_t dev, int *irq, int *new);
int msix_alloc(device_t dev, int *irq);
int msix_release(int irq);
#endif /* !LOCORE */

View File

@ -107,9 +107,10 @@ inthand_t
#define ATPIC(io, base, eoi, imenptr) \
{ { atpic_enable_source, atpic_disable_source, (eoi), \
atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
atpic_resume, atpic_config_intr, atpic_assign_cpu }, (io), \
(base), IDT_IO_INTS + (base), (imenptr) }
atpic_enable_intr, atpic_disable_intr, atpic_vector, \
atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\
atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \
(imenptr) }
#define INTSRC(irq) \
{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \
@ -137,6 +138,7 @@ static void atpic_disable_source(struct intsrc *isrc, int eoi);
static void atpic_eoi_master(struct intsrc *isrc);
static void atpic_eoi_slave(struct intsrc *isrc);
static void atpic_enable_intr(struct intsrc *isrc);
static void atpic_disable_intr(struct intsrc *isrc);
static int atpic_vector(struct intsrc *isrc);
static void atpic_resume(struct pic *pic);
static int atpic_source_pending(struct intsrc *isrc);
@ -266,6 +268,12 @@ atpic_enable_intr(struct intsrc *isrc)
{
}
static void
atpic_disable_intr(struct intsrc *isrc)
{
}
static int
atpic_vector(struct intsrc *isrc)
{

View File

@ -42,13 +42,14 @@
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/lock.h>
#include <sys/ktr.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/sx.h>
#include <machine/clock.h>
#include <machine/intr_machdep.h>
#include <machine/smp.h>
@ -62,7 +63,8 @@ typedef void (*mask_fn)(void *);
static int intrcnt_index;
static struct intsrc *interrupt_sources[NUM_IO_INTS];
static struct mtx intr_table_lock;
static struct sx intr_table_lock;
static struct mtx intrcnt_lock;
static STAILQ_HEAD(, pic) pics;
#ifdef INTR_FILTER
@ -106,14 +108,14 @@ intr_register_pic(struct pic *pic)
{
int error;
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
if (intr_pic_registered(pic))
error = EBUSY;
else {
STAILQ_INSERT_TAIL(&pics, pic, pics);
error = 0;
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
return (error);
}
@ -141,16 +143,16 @@ intr_register_source(struct intsrc *isrc)
#endif
if (error)
return (error);
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
if (interrupt_sources[vector] != NULL) {
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
intr_event_destroy(isrc->is_event);
return (EEXIST);
}
intrcnt_register(isrc);
interrupt_sources[vector] = isrc;
isrc->is_enabled = 0;
mtx_unlock_spin(&intr_table_lock);
isrc->is_handlers = 0;
sx_xunlock(&intr_table_lock);
return (0);
}
@ -174,19 +176,18 @@ intr_add_handler(const char *name, int vector, driver_filter_t filter,
error = intr_event_add_handler(isrc->is_event, name, filter, handler,
arg, intr_priority(flags), flags, cookiep);
if (error == 0) {
sx_xlock(&intr_table_lock);
intrcnt_updatename(isrc);
mtx_lock_spin(&intr_table_lock);
if (!isrc->is_enabled) {
isrc->is_enabled = 1;
isrc->is_handlers++;
if (isrc->is_handlers == 1) {
#ifdef SMP
if (assign_cpu)
intr_assign_next_cpu(isrc);
#endif
mtx_unlock_spin(&intr_table_lock);
isrc->is_pic->pic_enable_intr(isrc);
} else
mtx_unlock_spin(&intr_table_lock);
isrc->is_pic->pic_enable_source(isrc);
isrc->is_pic->pic_enable_source(isrc);
}
sx_xunlock(&intr_table_lock);
}
return (error);
}
@ -199,8 +200,16 @@ intr_remove_handler(void *cookie)
isrc = intr_handler_source(cookie);
error = intr_event_remove_handler(cookie);
if (error == 0)
if (error == 0) {
sx_xlock(&intr_table_lock);
isrc->is_handlers--;
if (isrc->is_handlers == 0) {
isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI);
isrc->is_pic->pic_disable_intr(isrc);
}
intrcnt_updatename(isrc);
sx_xunlock(&intr_table_lock);
}
return (error);
}
@ -379,12 +388,12 @@ intr_resume(void)
{
struct pic *pic;
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
STAILQ_FOREACH(pic, &pics, pics) {
if (pic->pic_resume != NULL)
pic->pic_resume(pic);
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
}
void
@ -392,12 +401,12 @@ intr_suspend(void)
{
struct pic *pic;
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
STAILQ_FOREACH(pic, &pics, pics) {
if (pic->pic_suspend != NULL)
pic->pic_suspend(pic);
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
}
static void
@ -420,8 +429,8 @@ intrcnt_register(struct intsrc *is)
{
char straystr[MAXCOMLEN + 1];
/* mtx_assert(&intr_table_lock, MA_OWNED); */
KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__));
mtx_lock_spin(&intrcnt_lock);
is->is_index = intrcnt_index;
intrcnt_index += 2;
snprintf(straystr, MAXCOMLEN + 1, "stray irq%d",
@ -430,17 +439,18 @@ intrcnt_register(struct intsrc *is)
is->is_count = &intrcnt[is->is_index];
intrcnt_setname(straystr, is->is_index + 1);
is->is_straycount = &intrcnt[is->is_index + 1];
mtx_unlock_spin(&intrcnt_lock);
}
void
intrcnt_add(const char *name, u_long **countp)
{
mtx_lock_spin(&intr_table_lock);
mtx_lock_spin(&intrcnt_lock);
*countp = &intrcnt[intrcnt_index];
intrcnt_setname(name, intrcnt_index);
intrcnt_index++;
mtx_unlock_spin(&intr_table_lock);
mtx_unlock_spin(&intrcnt_lock);
}
static void
@ -450,7 +460,8 @@ intr_init(void *dummy __unused)
intrcnt_setname("???", 0);
intrcnt_index = 1;
STAILQ_INIT(&pics);
mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
sx_init(&intr_table_lock, "intr sources");
mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL)
@ -536,14 +547,14 @@ intr_shuffle_irqs(void *arg __unused)
return;
/* Round-robin assign a CPU to each enabled source. */
mtx_lock_spin(&intr_table_lock);
sx_xlock(&intr_table_lock);
assign_cpu = 1;
for (i = 0; i < NUM_IO_INTS; i++) {
isrc = interrupt_sources[i];
if (isrc != NULL && isrc->is_enabled)
if (isrc != NULL && isrc->is_handlers > 0)
intr_assign_next_cpu(isrc);
}
mtx_unlock_spin(&intr_table_lock);
sx_xunlock(&intr_table_lock);
}
SYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs, NULL)
#endif

View File

@ -114,6 +114,7 @@ static void ioapic_enable_source(struct intsrc *isrc);
static void ioapic_disable_source(struct intsrc *isrc, int eoi);
static void ioapic_eoi_source(struct intsrc *isrc);
static void ioapic_enable_intr(struct intsrc *isrc);
static void ioapic_disable_intr(struct intsrc *isrc);
static int ioapic_vector(struct intsrc *isrc);
static int ioapic_source_pending(struct intsrc *isrc);
static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
@ -125,8 +126,8 @@ static void ioapic_program_intpin(struct ioapic_intsrc *intpin);
static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
ioapic_eoi_source, ioapic_enable_intr,
ioapic_vector, ioapic_source_pending,
NULL, ioapic_resume,
ioapic_disable_intr, ioapic_vector,
ioapic_source_pending, NULL, ioapic_resume,
ioapic_config_intr, ioapic_assign_cpu };
static int next_ioapic_base;
@ -359,6 +360,23 @@ ioapic_enable_intr(struct intsrc *isrc)
}
}
static void
ioapic_disable_intr(struct intsrc *isrc)
{
struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
u_int vector;
if (intpin->io_vector != 0) {
/* Mask this interrupt pin and free its APIC vector. */
vector = intpin->io_vector;
apic_disable_vector(vector);
intpin->io_masked = 1;
intpin->io_vector = 0;
ioapic_program_intpin(intpin);
apic_free_vector(vector, intpin->io_irq);
}
}
static int
ioapic_vector(struct intsrc *isrc)
{

View File

@ -147,6 +147,8 @@ static u_int32_t lapic_timer_divisors[] = {
APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128
};
extern inthand_t IDTVEC(rsvd);
volatile lapic_t *lapic;
vm_paddr_t lapic_paddr;
static u_long lapic_timer_divisor, lapic_timer_period, lapic_timer_hz;
@ -840,6 +842,17 @@ apic_enable_vector(u_int vector)
GSEL(GCODE_SEL, SEL_KPL));
}
void
apic_disable_vector(u_int vector)
{
KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
KASSERT(ioint_handlers[vector / 32] != NULL,
("No ISR handler for vector %u", vector));
setidt(vector, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
}
/* Release an APIC vector when it's no longer in use. */
void
apic_free_vector(u_int vector, u_int irq)

View File

@ -112,11 +112,12 @@ struct msi_intsrc {
u_int msi_count:8; /* Messages in this group. (g) */
};
static struct msi_intsrc *msi_create_source(u_int irq);
static void msi_create_source(void);
static void msi_enable_source(struct intsrc *isrc);
static void msi_disable_source(struct intsrc *isrc, int eoi);
static void msi_eoi_source(struct intsrc *isrc);
static void msi_enable_intr(struct intsrc *isrc);
static void msi_disable_intr(struct intsrc *isrc);
static int msi_vector(struct intsrc *isrc);
static int msi_source_pending(struct intsrc *isrc);
static int msi_config_intr(struct intsrc *isrc, enum intr_trigger trig,
@ -124,11 +125,13 @@ static int msi_config_intr(struct intsrc *isrc, enum intr_trigger trig,
static void msi_assign_cpu(struct intsrc *isrc, u_int apic_id);
struct pic msi_pic = { msi_enable_source, msi_disable_source, msi_eoi_source,
msi_enable_intr, msi_vector, msi_source_pending,
NULL, NULL, msi_config_intr, msi_assign_cpu };
msi_enable_intr, msi_disable_intr, msi_vector,
msi_source_pending, NULL, NULL, msi_config_intr,
msi_assign_cpu };
static int msi_enabled;
static struct sx msi_sx;
static int msi_last_irq;
static struct mtx msi_lock;
static void
msi_enable_source(struct intsrc *isrc)
@ -158,6 +161,14 @@ msi_enable_intr(struct intsrc *isrc)
apic_enable_vector(msi->msi_vector);
}
static void
msi_disable_intr(struct intsrc *isrc)
{
struct msi_intsrc *msi = (struct msi_intsrc *)isrc;
apic_disable_vector(msi->msi_vector);
}
static int
msi_vector(struct intsrc *isrc)
{
@ -191,8 +202,7 @@ msi_assign_cpu(struct intsrc *isrc, u_int apic_id)
printf("msi: Assigning %s IRQ %d to local APIC %u\n",
msi->msi_msix ? "MSI-X" : "MSI", msi->msi_irq,
msi->msi_cpu);
if (isrc->is_enabled)
pci_remap_msi_irq(msi->msi_dev, msi->msi_irq);
pci_remap_msi_irq(msi->msi_dev, msi->msi_irq);
}
void
@ -206,19 +216,29 @@ msi_init(void)
msi_enabled = 1;
intr_register_pic(&msi_pic);
sx_init(&msi_sx, "msi");
mtx_init(&msi_lock, "msi", NULL, MTX_DEF);
}
struct msi_intsrc *
msi_create_source(u_int irq)
void
msi_create_source(void)
{
struct msi_intsrc *msi;
u_int irq;
msi = malloc(sizeof(struct msi_intsrc), M_MSI, M_WAITOK | M_ZERO);
mtx_lock(&msi_lock);
if (msi_last_irq >= NUM_MSI_INTS) {
mtx_unlock(&msi_lock);
return;
}
irq = msi_last_irq + FIRST_MSI_INT;
msi_last_irq++;
mtx_unlock(&msi_lock);
msi = malloc(sizeof(struct msi_intsrc), M_MSI, M_WAITOK | M_ZERO);
msi->msi_intsrc.is_pic = &msi_pic;
msi->msi_irq = irq;
intr_register_source(&msi->msi_intsrc);
return (msi);
nexus_add_irq(irq);
}
/*
@ -228,18 +248,16 @@ msi_create_source(u_int irq)
* and *newcount being the number of new IRQ values added.
*/
int
msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
int *newcount)
msi_alloc(device_t dev, int count, int maxcount, int *irqs)
{
struct msi_intsrc *msi, *fsrc;
int cnt, i, j, vector;
int cnt, i, vector;
*newirq = 0;
*newcount = 0;
if (!msi_enabled)
return (ENXIO);
sx_xlock(&msi_sx);
again:
mtx_lock(&msi_lock);
/* Try to find 'count' free IRQs. */
cnt = 0;
@ -263,20 +281,17 @@ msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
if (cnt < count) {
/* If we would exceed the max, give up. */
if (i + (count - cnt) > FIRST_MSI_INT + NUM_MSI_INTS) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
mtx_unlock(&msi_lock);
/* We need count - cnt more sources starting at index 'cnt'. */
*newirq = cnt;
*newcount = count - cnt;
for (j = 0; j < *newcount; j++) {
/* Create a new MSI source and add it to our array. */
msi_create_source(i + j);
irqs[cnt] = i + j;
/* We need count - cnt more sources. */
while (cnt < count) {
msi_create_source();
cnt++;
}
goto again;
}
/* Ok, we now have the IRQs allocated. */
@ -285,7 +300,7 @@ msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
/* Allocate 'count' IDT vectors. */
vector = apic_alloc_vectors(irqs, count, maxcount);
if (vector == 0) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOSPC);
}
@ -299,12 +314,11 @@ msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
printf("msi: routing MSI IRQ %d to vector %u\n",
msi->msi_irq, msi->msi_vector);
msi->msi_first = fsrc;
/* XXX: Somewhat gross. */
msi->msi_intsrc.is_enabled = 0;
KASSERT(msi->msi_intsrc.is_handlers == 0,
("dead MSI has handlers"));
}
fsrc->msi_count = count;
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}
@ -315,22 +329,22 @@ msi_release(int *irqs, int count)
struct msi_intsrc *msi, *first;
int i;
sx_xlock(&msi_sx);
mtx_lock(&msi_lock);
first = (struct msi_intsrc *)intr_lookup_source(irqs[0]);
if (first == NULL) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOENT);
}
/* Make sure this isn't an MSI-X message. */
if (first->msi_msix) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (EINVAL);
}
/* Make sure this message is allocated to a group. */
if (first->msi_first == NULL) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
@ -339,7 +353,7 @@ msi_release(int *irqs, int count)
* the entire group.
*/
if (first->msi_first != first || first->msi_count != count) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (EINVAL);
}
KASSERT(first->msi_dev != NULL, ("unowned group"));
@ -362,7 +376,7 @@ msi_release(int *irqs, int count)
first->msi_vector = 0;
first->msi_count = 0;
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}
@ -371,27 +385,27 @@ msi_map(int irq, uint64_t *addr, uint32_t *data)
{
struct msi_intsrc *msi;
sx_slock(&msi_sx);
mtx_lock(&msi_lock);
msi = (struct msi_intsrc *)intr_lookup_source(irq);
if (msi == NULL) {
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOENT);
}
/* Make sure this message is allocated to a device. */
if (msi->msi_dev == NULL) {
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
/*
* If this message isn't an MSI-X message, make sure it's part
* of a gruop, and switch to the first message in the
* of a group, and switch to the first message in the
* group.
*/
if (!msi->msi_msix) {
if (msi->msi_first == NULL) {
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
msi = msi->msi_first;
@ -399,21 +413,21 @@ msi_map(int irq, uint64_t *addr, uint32_t *data)
*addr = INTEL_ADDR(msi);
*data = INTEL_DATA(msi);
sx_sunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}
int
msix_alloc(device_t dev, int *irq, int *new)
msix_alloc(device_t dev, int *irq)
{
struct msi_intsrc *msi;
int i, vector;
*new = 0;
if (!msi_enabled)
return (ENXIO);
sx_xlock(&msi_sx);
again:
mtx_lock(&msi_lock);
/* Find a free IRQ. */
for (i = FIRST_MSI_INT; i < FIRST_MSI_INT + NUM_MSI_INTS; i++) {
@ -423,7 +437,7 @@ msix_alloc(device_t dev, int *irq, int *new)
if (msi == NULL)
break;
/* If this is a free one, start or continue a run. */
/* Stop at the first free source. */
if (msi->msi_dev == NULL)
break;
}
@ -432,13 +446,14 @@ msix_alloc(device_t dev, int *irq, int *new)
if (msi == NULL) {
/* If we would exceed the max, give up. */
if (i + 1 > FIRST_MSI_INT + NUM_MSI_INTS) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENXIO);
}
mtx_unlock(&msi_lock);
/* Create a new source. */
*new = 1;
msi = msi_create_source(i);
msi_create_source();
goto again;
}
/* Allocate an IDT vector. */
@ -452,9 +467,8 @@ msix_alloc(device_t dev, int *irq, int *new)
msi->msi_vector = vector;
msi->msi_msix = 1;
/* XXX: Somewhat gross. */
msi->msi_intsrc.is_enabled = 0;
sx_xunlock(&msi_sx);
KASSERT(msi->msi_intsrc.is_handlers == 0, ("dead MSI-X has handlers"));
mtx_unlock(&msi_lock);
*irq = i;
return (0);
@ -465,16 +479,16 @@ msix_release(int irq)
{
struct msi_intsrc *msi;
sx_xlock(&msi_sx);
mtx_lock(&msi_lock);
msi = (struct msi_intsrc *)intr_lookup_source(irq);
if (msi == NULL) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (ENOENT);
}
/* Make sure this is an MSI-X message. */
if (!msi->msi_msix) {
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (EINVAL);
}
@ -486,6 +500,6 @@ msix_release(int irq)
msi->msi_vector = 0;
msi->msi_msix = 0;
sx_xunlock(&msi_sx);
mtx_unlock(&msi_lock);
return (0);
}

View File

@ -550,16 +550,21 @@ nexus_delete_resource(device_t dev, device_t child, int type, int rid)
resource_list_delete(rl, type, rid);
}
/* Called from the MSI code to add new IRQs to the IRQ rman. */
void
nexus_add_irq(u_long irq)
{
if (rman_manage_region(&irq_rman, irq, irq) != 0)
panic("%s: failed", __func__);
}
#ifdef DEV_APIC
static int
nexus_alloc_msix(device_t pcib, device_t dev, int *irq)
{
int error, new;
error = msix_alloc(dev, irq, &new);
if (new)
rman_manage_region(&irq_rman, *irq, *irq);
return (error);
return (msix_alloc(dev, irq));
}
static int
@ -572,17 +577,8 @@ nexus_release_msix(device_t pcib, device_t dev, int irq)
static int
nexus_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
{
int error, i, newirq, newcount;
/* First alloc the messages. */
error = msi_alloc(dev, count, maxcount, irqs, &newirq, &newcount);
/* Always add any new IRQs to the rman, even on failure. */
for (i = 0; i < newcount; i++)
rman_manage_region(&irq_rman, irqs[newirq + i],
irqs[newirq + i]);
return (error);
return (msi_alloc(dev, count, maxcount, irqs));
}
static int

View File

@ -177,6 +177,7 @@ extern vm_paddr_t lapic_paddr;
u_int apic_alloc_vector(u_int irq);
u_int apic_alloc_vectors(u_int *irqs, u_int count, u_int align);
void apic_disable_vector(u_int vector);
void apic_enable_vector(u_int vector);
void apic_free_vector(u_int vector, u_int irq);
u_int apic_idt_to_irq(u_int vector);

View File

@ -86,6 +86,7 @@ struct pic {
void (*pic_disable_source)(struct intsrc *, int);
void (*pic_eoi_source)(struct intsrc *);
void (*pic_enable_intr)(struct intsrc *);
void (*pic_disable_intr)(struct intsrc *);
int (*pic_vector)(struct intsrc *);
int (*pic_source_pending)(struct intsrc *);
void (*pic_suspend)(struct pic *);
@ -114,7 +115,7 @@ struct intsrc {
u_long *is_count;
u_long *is_straycount;
u_int is_index;
u_int is_enabled:1;
u_int is_handlers;
};
struct trapframe;
@ -142,12 +143,12 @@ int intr_remove_handler(void *cookie);
void intr_resume(void);
void intr_suspend(void);
void intrcnt_add(const char *name, u_long **countp);
int msi_alloc(device_t dev, int count, int maxcount, int *irqs, int *newirq,
int *newcount);
void nexus_add_irq(u_long irq);
int msi_alloc(device_t dev, int count, int maxcount, int *irqs);
void msi_init(void);
int msi_map(int irq, uint64_t *addr, uint32_t *data);
int msi_release(int* irqs, int count);
int msix_alloc(device_t dev, int *irq, int *new);
int msix_alloc(device_t dev, int *irq);
int msix_release(int irq);
#endif /* !LOCORE */

View File

@ -125,9 +125,10 @@ inthand_t
#define ATPIC(io, base, eoi, imenptr) \
{ { atpic_enable_source, atpic_disable_source, (eoi), \
atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
atpic_resume, atpic_config_intr, atpic_assign_cpu }, (io), \
(base), IDT_IO_INTS + (base), (imenptr) }
atpic_enable_intr, atpic_disable_intr, atpic_vector, \
atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\
atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \
(imenptr) }
#define INTSRC(irq) \
{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \
@ -155,6 +156,7 @@ static void atpic_disable_source(struct intsrc *isrc, int eoi);
static void atpic_eoi_master(struct intsrc *isrc);
static void atpic_eoi_slave(struct intsrc *isrc);
static void atpic_enable_intr(struct intsrc *isrc);
static void atpic_disable_intr(struct intsrc *isrc);
static int atpic_vector(struct intsrc *isrc);
static void atpic_resume(struct pic *pic);
static int atpic_source_pending(struct intsrc *isrc);
@ -284,6 +286,12 @@ atpic_enable_intr(struct intsrc *isrc)
{
}
static void
atpic_disable_intr(struct intsrc *isrc)
{
}
static int
atpic_vector(struct intsrc *isrc)
{