/* * Describe an interrupt thread. There is one of these per interrupt vector. * Note that this actually describes an interrupt source. There may or may * not be an actual kernel thread attached to a given source. */ struct ithd { struct mtx it_lock; struct thread *it_td; /* Interrupt process. */ LIST_ENTRY(ithd) it_list; /* All interrupt threads. */ TAILQ_HEAD(, intrhand) it_handlers; /* Interrupt handlers. */ struct ithd *it_interrupted; /* Who we interrupted. */ void (*it_disable)(uintptr_t); /* Enable interrupt source. */ void (*it_enable)(uintptr_t); /* Disable interrupt source. */ void *it_md; /* Hook for MD interrupt code. */ int it_flags; /* Interrupt-specific flags. */ int it_need; /* Needs service. */ uintptr_t it_vector; char it_name[MAXCOMLEN + 1]; };
/* * Register a new interrupt source with the global interrupt system. * The global interrupts need to be disabled when this function is * called. */ int intr_register_source(struct intsrc *isrc) { int error, vector;
vector = isrc->is_pic->pic_vector(isrc); if (interrupt_sources[vector] != NULL) return (EEXIST); error = ithread_create(&isrc->is_ithread, (uintptr_t)isrc, 0, (mask_fn)isrc->is_pic->pic_disable_source, (mask_fn)isrc->is_pic->pic_enable_source, "irq%d:", vector); if (error) return (error); mtx_lock_spin(&intr_table_lock); if (interrupt_sources[vector] != NULL) { mtx_unlock_spin(&intr_table_lock); ithread_destroy(isrc->is_ithread); return (EEXIST); } intrcnt_register(isrc); interrupt_sources[vector] = isrc; mtx_unlock_spin(&intr_table_lock); return (0); }
int ithread_create(struct ithd **ithread, uintptr_t vector, int flags, void (*disable)(uintptr_t), void (*enable)(uintptr_t), const char *fmt, ...) { struct ithd *ithd; struct thread *td; struct proc *p; int error; va_list ap;
/* The only valid flag during creation is IT_SOFT. */ if ((flags & ~IT_SOFT) != 0) return (EINVAL);
ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); ithd->it_vector = vector; ithd->it_disable = disable; ithd->it_enable = enable; ithd->it_flags = flags; TAILQ_INIT(&ithd->it_handlers); mtx_init(&ithd->it_lock, "ithread", NULL, MTX_DEF);
va_start(ap, fmt); vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); va_end(ap);
error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 0, "%s", ithd->it_name); if (error) { mtx_destroy(&ithd->it_lock); free(ithd, M_ITHREAD); return (error); } td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */ mtx_lock_spin(&sched_lock); td->td_ksegrp->kg_pri_class = PRI_ITHD; td->td_priority = PRI_MAX_ITHD; TD_SET_IWAIT(td); mtx_unlock_spin(&sched_lock); ithd->it_td = td; td->td_ithd = ithd; if (ithread != NULL) *ithread = ithd; CTR2(KTR_INTR, "%s: created %s", __func__, ithd->it_name); return (0); }
|