version 1.49, 2011/08/10 21:46:02 |
version 1.50, 2011/08/11 17:59:00 |
Line 61 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 61 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include "pci.h" |
#include "pci.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
|
#include <sys/cpu.h> |
#include <sys/kernel.h> |
#include <sys/kernel.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#include <sys/reboot.h> |
#include <sys/reboot.h> |
#include <sys/simplelock.h> |
#include <sys/mutex.h> |
|
|
#include <uvm/uvm.h> |
#include <uvm/uvm.h> |
|
|
Line 82 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 83 __KERNEL_RCSID(0, "$NetBSD$"); |
|
* This lock protects updates to the following mapping and reference-count |
* This lock protects updates to the following mapping and reference-count |
* arrays. The lock does not need to be acquired to read the mapping tables. |
* arrays. The lock does not need to be acquired to read the mapping tables. |
*/ |
*/ |
static struct simplelock irq_mapping_update_lock = SIMPLELOCK_INITIALIZER; |
static kmutex_t evtchn_lock; |
|
|
/* event handlers */ |
/* event handlers */ |
struct evtsource *evtsource[NR_EVENT_CHANNELS]; |
struct evtsource *evtsource[NR_EVENT_CHANNELS]; |
|
|
/* Reference counts for bindings to event channels */ |
/* channel locks */ |
|
static kmutex_t evtlock[NR_EVENT_CHANNELS]; |
|
|
|
/* Reference counts for bindings to event channels XXX: redo for SMP */ |
static uint8_t evtch_bindcount[NR_EVENT_CHANNELS]; |
static uint8_t evtch_bindcount[NR_EVENT_CHANNELS]; |
|
|
|
/* event-channel <-> VCPU mapping for IPIs. XXX: redo for SMP. */ |
|
static evtchn_port_t vcpu_ipi_to_evtch[MAX_VIRT_CPUS]; |
|
|
|
/* event-channel <-> VCPU mapping for VIRQ_TIMER. XXX: redo for SMP. */ |
|
static int virq_timer_to_evtch[MAX_VIRT_CPUS]; |
|
|
/* event-channel <-> VIRQ mapping. */ |
/* event-channel <-> VIRQ mapping. */ |
static int virq_to_evtch[NR_VIRQS]; |
static int virq_to_evtch[NR_VIRQS]; |
|
|
Line 137 events_default_setup(void) |
|
Line 147 events_default_setup(void) |
|
{ |
{ |
int i; |
int i; |
|
|
|
/* No VCPU -> event mappings. */ |
|
for (i = 0; i < MAX_VIRT_CPUS; i++) |
|
vcpu_ipi_to_evtch[i] = -1; |
|
|
|
/* No VIRQ_TIMER -> event mappings. */ |
|
for (i = 0; i < MAX_VIRT_CPUS; i++) |
|
virq_timer_to_evtch[i] = -1; |
|
|
/* No VIRQ -> event mappings. */ |
/* No VIRQ -> event mappings. */ |
for (i = 0; i < NR_VIRQS; i++) |
for (i = 0; i < NR_VIRQS; i++) |
virq_to_evtch[i] = -1; |
virq_to_evtch[i] = -1; |
|
|
events_init(void) |
events_init(void) |
{ |
{ |
debug_port = bind_virq_to_evtch(VIRQ_DEBUG); |
debug_port = bind_virq_to_evtch(VIRQ_DEBUG); |
|
KASSERT(debug_port != -1); |
|
|
aprint_verbose("debug virtual interrupt using event channel %d\n", |
aprint_verbose("debug virtual interrupt using event channel %d\n", |
debug_port); |
debug_port); |
/* |
/* |
Line 197 evtchn_do_event(int evtch, struct intrfr |
|
Line 217 evtchn_do_event(int evtch, struct intrfr |
|
if (evtch == IRQ_DEBUG) |
if (evtch == IRQ_DEBUG) |
printf("evtchn_do_event: evtch %d\n", evtch); |
printf("evtchn_do_event: evtch %d\n", evtch); |
#endif |
#endif |
ci = &cpu_info_primary; |
ci = curcpu(); |
|
|
/* |
/* |
* Shortcut for the debug handler, we want it to always run, |
* Shortcut for the debug handler, we want it to always run, |
Line 217 evtchn_do_event(int evtch, struct intrfr |
|
Line 237 evtchn_do_event(int evtch, struct intrfr |
|
ci->ci_data.cpu_nintr++; |
ci->ci_data.cpu_nintr++; |
evtsource[evtch]->ev_evcnt.ev_count++; |
evtsource[evtch]->ev_evcnt.ev_count++; |
ilevel = ci->ci_ilevel; |
ilevel = ci->ci_ilevel; |
if (evtsource[evtch]->ev_maxlevel <= ilevel) { |
if (evtsource[evtch]->ev_maxlevel <= ilevel || |
|
evtsource[evtch]->ev_cpu != ci /* XXX: get stats */) { |
#ifdef IRQ_DEBUG |
#ifdef IRQ_DEBUG |
if (evtch == IRQ_DEBUG) |
if (evtch == IRQ_DEBUG) |
printf("evtsource[%d]->ev_maxlevel %d <= ilevel %d\n", |
printf("evtsource[%d]->ev_maxlevel %d <= ilevel %d\n", |
evtch, evtsource[evtch]->ev_maxlevel, ilevel); |
evtch, evtsource[evtch]->ev_maxlevel, ilevel); |
#endif |
#endif |
hypervisor_set_ipending(ci, evtsource[evtch]->ev_imask, |
hypervisor_set_ipending(evtsource[evtch]->ev_cpu, |
evtch >> LONG_SHIFT, evtch & LONG_MASK); |
evtsource[evtch]->ev_imask, |
/* leave masked */ |
evtch >> LONG_SHIFT, |
|
evtch & LONG_MASK); |
|
|
|
if (evtsource[evtch]->ev_cpu != ci) { |
|
/* facilitate spllower() on remote cpu */ |
|
struct cpu_info *rci = evtsource[evtch]->ev_cpu; |
|
if (xen_send_ipi(rci, XEN_IPI_KICK) != 0) { |
|
panic("xen_send_ipi(%s, XEN_IPI_KICK) failed\n", cpu_name(rci)); |
|
} |
|
} |
|
|
|
/* leave masked */ |
return 0; |
return 0; |
} |
} |
ci->ci_ilevel = evtsource[evtch]->ev_maxlevel; |
ci->ci_ilevel = evtsource[evtch]->ev_maxlevel; |
iplmask = evtsource[evtch]->ev_imask; |
iplmask = evtsource[evtch]->ev_imask; |
sti(); |
sti(); |
|
mutex_spin_enter(&evtlock[evtch]); |
ih = evtsource[evtch]->ev_handlers; |
ih = evtsource[evtch]->ev_handlers; |
while (ih != NULL) { |
while (ih != NULL) { |
if (ih->ih_level <= ilevel) { |
if (ih->ih_level <= ilevel || |
|
ih->ih_cpu != ci) { |
#ifdef IRQ_DEBUG |
#ifdef IRQ_DEBUG |
if (evtch == IRQ_DEBUG) |
if (evtch == IRQ_DEBUG) |
printf("ih->ih_level %d <= ilevel %d\n", ih->ih_level, ilevel); |
printf("ih->ih_level %d <= ilevel %d\n", ih->ih_level, ilevel); |
#endif |
#endif |
cli(); |
cli(); |
hypervisor_set_ipending(ci, iplmask, |
hypervisor_set_ipending(ih->ih_cpu, iplmask, |
evtch >> LONG_SHIFT, evtch & LONG_MASK); |
evtch >> LONG_SHIFT, evtch & LONG_MASK); |
/* leave masked */ |
/* leave masked */ |
|
mutex_spin_exit(&evtlock[evtch]); |
goto splx; |
goto splx; |
} |
} |
iplmask &= ~IUNMASK(ci, ih->ih_level); |
iplmask &= ~IUNMASK(ci, ih->ih_level); |
Line 250 evtchn_do_event(int evtch, struct intrfr |
|
Line 285 evtchn_do_event(int evtch, struct intrfr |
|
ih_fun(ih->ih_arg, regs); |
ih_fun(ih->ih_arg, regs); |
ih = ih->ih_evt_next; |
ih = ih->ih_evt_next; |
} |
} |
|
mutex_spin_exit(&evtlock[evtch]); |
cli(); |
cli(); |
hypervisor_enable_event(evtch); |
hypervisor_enable_event(evtch); |
splx: |
splx: |
|
|
ci->ci_ilevel = i; |
ci->ci_ilevel = i; |
for (ih = ci->ci_isources[i]->ipl_handlers; |
for (ih = ci->ci_isources[i]->ipl_handlers; |
ih != NULL; ih = ih->ih_ipl_next) { |
ih != NULL; ih = ih->ih_ipl_next) { |
|
KASSERT(ih->ih_cpu == ci); |
sti(); |
sti(); |
ih_fun = (void *)ih->ih_fun; |
ih_fun = (void *)ih->ih_fun; |
ih_fun(ih->ih_arg, regs); |
ih_fun(ih->ih_arg, regs); |
|
|
return 0; |
return 0; |
} |
} |
|
|
|
#define PRIuCPUID "lu" /* XXX: move this somewhere more appropriate */ |
|
|
|
evtchn_port_t |
|
bind_vcpu_to_evtch(cpuid_t vcpu) |
|
{ |
|
evtchn_op_t op; |
|
evtchn_port_t evtchn; |
|
int s; |
|
|
|
s = splhigh(); |
|
mutex_spin_enter(&evtchn_lock); |
|
|
|
evtchn = vcpu_ipi_to_evtch[vcpu]; |
|
if (evtchn == -1) { |
|
op.cmd = EVTCHNOP_bind_ipi; |
|
op.u.bind_ipi.vcpu = (uint32_t) vcpu; |
|
if (HYPERVISOR_event_channel_op(&op) != 0) |
|
panic("Failed to bind ipi to VCPU %"PRIuCPUID"\n", vcpu); |
|
evtchn = op.u.bind_ipi.port; |
|
|
|
vcpu_ipi_to_evtch[vcpu] = evtchn; |
|
} |
|
|
|
evtch_bindcount[evtchn]++; |
|
|
|
mutex_spin_exit(&evtchn_lock); |
|
splx(s); |
|
|
|
return evtchn; |
|
} |
|
|
int |
int |
bind_virq_to_evtch(int virq) |
bind_virq_to_evtch(int virq) |
{ |
{ |
Line 299 bind_virq_to_evtch(int virq) |
|
Line 367 bind_virq_to_evtch(int virq) |
|
int evtchn, s; |
int evtchn, s; |
|
|
s = splhigh(); |
s = splhigh(); |
simple_lock(&irq_mapping_update_lock); |
mutex_spin_enter(&evtchn_lock); |
|
|
|
/* |
|
* XXX: The only per-cpu VIRQ we currently use is VIRQ_TIMER. |
|
* Please re-visit this implementation when others are used. |
|
* Note: VIRQ_DEBUG is special-cased, and not used or bound on APs. |
|
* XXX: event->virq/ipi can be unified in a linked-list |
|
* implementation. |
|
*/ |
|
struct cpu_info *ci = curcpu(); |
|
|
|
if (virq == VIRQ_DEBUG && ci != &cpu_info_primary) { |
|
return -1; |
|
} |
|
|
evtchn = virq_to_evtch[virq]; |
if (virq == VIRQ_TIMER) { |
|
evtchn = virq_timer_to_evtch[ci->ci_cpuid]; |
|
} |
|
else { |
|
evtchn = virq_to_evtch[virq]; |
|
} |
if (evtchn == -1) { |
if (evtchn == -1) { |
op.cmd = EVTCHNOP_bind_virq; |
op.cmd = EVTCHNOP_bind_virq; |
op.u.bind_virq.virq = virq; |
op.u.bind_virq.virq = virq; |
op.u.bind_virq.vcpu = 0; |
op.u.bind_virq.vcpu = ci->ci_cpuid; |
if (HYPERVISOR_event_channel_op(&op) != 0) |
if (HYPERVISOR_event_channel_op(&op) != 0) |
panic("Failed to bind virtual IRQ %d\n", virq); |
panic("Failed to bind virtual IRQ %d\n", virq); |
evtchn = op.u.bind_virq.port; |
evtchn = op.u.bind_virq.port; |
Line 315 bind_virq_to_evtch(int virq) |
|
Line 401 bind_virq_to_evtch(int virq) |
|
|
|
evtch_bindcount[evtchn]++; |
evtch_bindcount[evtchn]++; |
|
|
simple_unlock(&irq_mapping_update_lock); |
mutex_spin_exit(&evtchn_lock); |
splx(s); |
splx(s); |
|
|
return evtchn; |
return evtchn; |
|
|
unbind_virq_from_evtch(int virq) |
unbind_virq_from_evtch(int virq) |
{ |
{ |
evtchn_op_t op; |
evtchn_op_t op; |
int evtchn = virq_to_evtch[virq]; |
int evtchn; |
int s = splhigh(); |
int s; |
|
|
|
struct cpu_info *ci = curcpu(); |
|
|
|
if (virq == VIRQ_TIMER) { |
|
evtchn = virq_timer_to_evtch[ci->ci_cpuid]; |
|
} |
|
else { |
|
evtchn = virq_to_evtch[virq]; |
|
} |
|
|
|
if (evtchn == -1) { |
|
return -1; |
|
} |
|
|
simple_lock(&irq_mapping_update_lock); |
s = splhigh(); |
|
mutex_spin_enter(&evtchn_lock); |
|
|
evtch_bindcount[evtchn]--; |
evtch_bindcount[evtchn]--; |
if (evtch_bindcount[evtchn] == 0) { |
if (evtch_bindcount[evtchn] == 0) { |
Line 340 unbind_virq_from_evtch(int virq) |
|
Line 440 unbind_virq_from_evtch(int virq) |
|
virq_to_evtch[virq] = -1; |
virq_to_evtch[virq] = -1; |
} |
} |
|
|
simple_unlock(&irq_mapping_update_lock); |
mutex_spin_exit(&evtchn_lock); |
splx(s); |
splx(s); |
|
|
return evtchn; |
return evtchn; |
Line 358 bind_pirq_to_evtch(int pirq) |
|
Line 458 bind_pirq_to_evtch(int pirq) |
|
} |
} |
|
|
s = splhigh(); |
s = splhigh(); |
simple_lock(&irq_mapping_update_lock); |
mutex_spin_enter(&evtchn_lock); |
|
|
evtchn = pirq_to_evtch[pirq]; |
evtchn = pirq_to_evtch[pirq]; |
if (evtchn == -1) { |
if (evtchn == -1) { |
Line 377 bind_pirq_to_evtch(int pirq) |
|
Line 477 bind_pirq_to_evtch(int pirq) |
|
|
|
evtch_bindcount[evtchn]++; |
evtch_bindcount[evtchn]++; |
|
|
simple_unlock(&irq_mapping_update_lock); |
mutex_spin_exit(&evtchn_lock); |
splx(s); |
splx(s); |
|
|
return evtchn; |
return evtchn; |
Line 390 unbind_pirq_from_evtch(int pirq) |
|
Line 490 unbind_pirq_from_evtch(int pirq) |
|
int evtchn = pirq_to_evtch[pirq]; |
int evtchn = pirq_to_evtch[pirq]; |
int s = splhigh(); |
int s = splhigh(); |
|
|
simple_lock(&irq_mapping_update_lock); |
mutex_spin_enter(&evtchn_lock); |
|
|
evtch_bindcount[evtchn]--; |
evtch_bindcount[evtchn]--; |
if (evtch_bindcount[evtchn] == 0) { |
if (evtch_bindcount[evtchn] == 0) { |
Line 402 unbind_pirq_from_evtch(int pirq) |
|
Line 502 unbind_pirq_from_evtch(int pirq) |
|
pirq_to_evtch[pirq] = -1; |
pirq_to_evtch[pirq] = -1; |
} |
} |
|
|
simple_unlock(&irq_mapping_update_lock); |
mutex_spin_exit(&evtchn_lock); |
splx(s); |
splx(s); |
|
|
return evtchn; |
return evtchn; |
Line 420 pirq_establish(int pirq, int evtch, int |
|
Line 520 pirq_establish(int pirq, int evtch, int |
|
printf("pirq_establish: can't malloc handler info\n"); |
printf("pirq_establish: can't malloc handler info\n"); |
return NULL; |
return NULL; |
} |
} |
|
if (event_set_handler(evtch, pirq_interrupt, ih, level, evname) != 0) { |
event_set_handler(evtch, pirq_interrupt, ih, level, evname); |
free(ih, M_DEVBUF); |
|
return NULL; |
|
} |
ih->pirq = pirq; |
ih->pirq = pirq; |
ih->evtch = evtch; |
ih->evtch = evtch; |
ih->func = func; |
ih->func = func; |
Line 459 pirq_interrupt(void *arg) |
|
Line 561 pirq_interrupt(void *arg) |
|
|
|
#endif /* NPCI > 0 || NISA > 0 */ |
#endif /* NPCI > 0 || NISA > 0 */ |
|
|
|
|
|
/* |
|
* Recalculate the interrupt from scratch for an event source. |
|
*/ |
|
static void |
|
intr_calculatemasks(struct evtsource *evts, int evtch) |
|
{ |
|
struct intrhand *ih; |
|
|
|
#ifdef MULTIPROCESSOR |
|
KASSERT(!mutex_owned(&evtlock[evtch])); |
|
#endif |
|
mutex_spin_enter(&evtlock[evtch]); |
|
evts->ev_maxlevel = IPL_NONE; |
|
evts->ev_imask = 0; |
|
for (ih = evts->ev_handlers; ih != NULL; ih = ih->ih_evt_next) { |
|
if (ih->ih_level > evts->ev_maxlevel) |
|
evts->ev_maxlevel = ih->ih_level; |
|
evts->ev_imask |= (1 << ih->ih_level); |
|
} |
|
mutex_spin_exit(&evtlock[evtch]); |
|
} |
|
|
int |
int |
event_set_handler(int evtch, int (*func)(void *), void *arg, int level, |
event_set_handler(int evtch, int (*func)(void *), void *arg, int level, |
const char *evname) |
const char *evname) |
{ |
{ |
struct cpu_info *ci = &cpu_info_primary; |
struct cpu_info *ci = curcpu(); /* XXX: pass in ci ? */ |
struct evtsource *evts; |
struct evtsource *evts; |
struct intrhand *ih, **ihp; |
struct intrhand *ih, **ihp; |
int s; |
int s; |
Line 497 event_set_handler(int evtch, int (*func) |
|
Line 622 event_set_handler(int evtch, int (*func) |
|
ih->ih_arg = ih->ih_realarg = arg; |
ih->ih_arg = ih->ih_realarg = arg; |
ih->ih_evt_next = NULL; |
ih->ih_evt_next = NULL; |
ih->ih_ipl_next = NULL; |
ih->ih_ipl_next = NULL; |
|
ih->ih_cpu = ci; |
#ifdef MULTIPROCESSOR |
#ifdef MULTIPROCESSOR |
if (!mpsafe) { |
if (!mpsafe) { |
ih->ih_fun = intr_biglock_wrapper; |
ih->ih_fun = intr_biglock_wrapper; |
Line 506 event_set_handler(int evtch, int (*func) |
|
Line 632 event_set_handler(int evtch, int (*func) |
|
|
|
s = splhigh(); |
s = splhigh(); |
|
|
/* register handler for spllower() */ |
/* register per-cpu handler for spllower() */ |
event_set_iplhandler(ih, level); |
event_set_iplhandler(ci, ih, level); |
|
|
/* register handler for event channel */ |
/* register handler for event channel */ |
if (evtsource[evtch] == NULL) { |
if (evtsource[evtch] == NULL) { |
Line 515 event_set_handler(int evtch, int (*func) |
|
Line 641 event_set_handler(int evtch, int (*func) |
|
M_DEVBUF, M_WAITOK|M_ZERO); |
M_DEVBUF, M_WAITOK|M_ZERO); |
if (evts == NULL) |
if (evts == NULL) |
panic("can't allocate fixed interrupt source"); |
panic("can't allocate fixed interrupt source"); |
|
|
evts->ev_handlers = ih; |
evts->ev_handlers = ih; |
|
/* |
|
* XXX: We're assuming here that ci is the same cpu as |
|
* the one on which this event/port is bound on. The |
|
* api needs to be reshuffled so that this assumption |
|
* is more explicitly implemented. |
|
*/ |
|
evts->ev_cpu = ci; |
|
mutex_init(&evtlock[evtch], MUTEX_DEFAULT, IPL_VM); |
evtsource[evtch] = evts; |
evtsource[evtch] = evts; |
if (evname) |
if (evname) |
strncpy(evts->ev_evname, evname, |
strncpy(evts->ev_evname, evname, |
Line 528 event_set_handler(int evtch, int (*func) |
|
Line 663 event_set_handler(int evtch, int (*func) |
|
} else { |
} else { |
evts = evtsource[evtch]; |
evts = evtsource[evtch]; |
/* sort by IPL order, higher first */ |
/* sort by IPL order, higher first */ |
|
mutex_spin_enter(&evtlock[evtch]); |
for (ihp = &evts->ev_handlers; ; ihp = &((*ihp)->ih_evt_next)) { |
for (ihp = &evts->ev_handlers; ; ihp = &((*ihp)->ih_evt_next)) { |
if ((*ihp)->ih_level < ih->ih_level) { |
if ((*ihp)->ih_level < ih->ih_level) { |
/* insert before *ihp */ |
/* insert before *ihp */ |
Line 540 event_set_handler(int evtch, int (*func) |
|
Line 676 event_set_handler(int evtch, int (*func) |
|
break; |
break; |
} |
} |
} |
} |
|
mutex_spin_exit(&evtlock[evtch]); |
} |
} |
|
|
intr_calculatemasks(evts); |
intr_calculatemasks(evts, evtch); |
splx(s); |
splx(s); |
|
|
return 0; |
return 0; |
} |
} |
|
|
void |
void |
event_set_iplhandler(struct intrhand *ih, int level) |
event_set_iplhandler(struct cpu_info *ci, |
|
struct intrhand *ih, |
|
int level) |
{ |
{ |
struct cpu_info *ci = &cpu_info_primary; |
|
struct iplsource *ipls; |
struct iplsource *ipls; |
|
|
|
KASSERT(ci == ih->ih_cpu); |
if (ci->ci_isources[level] == NULL) { |
if (ci->ci_isources[level] == NULL) { |
ipls = malloc(sizeof (struct iplsource), |
ipls = malloc(sizeof (struct iplsource), |
M_DEVBUF, M_WAITOK|M_ZERO); |
M_DEVBUF, M_WAITOK|M_ZERO); |
Line 577 event_remove_handler(int evtch, int (*fu |
|
Line 716 event_remove_handler(int evtch, int (*fu |
|
struct evtsource *evts; |
struct evtsource *evts; |
struct intrhand *ih; |
struct intrhand *ih; |
struct intrhand **ihp; |
struct intrhand **ihp; |
struct cpu_info *ci = &cpu_info_primary; |
struct cpu_info *ci = curcpu(); |
|
|
evts = evtsource[evtch]; |
evts = evtsource[evtch]; |
if (evts == NULL) |
if (evts == NULL) |
return ENOENT; |
return ENOENT; |
|
|
|
mutex_spin_enter(&evtlock[evtch]); |
for (ihp = &evts->ev_handlers, ih = evts->ev_handlers; |
for (ihp = &evts->ev_handlers, ih = evts->ev_handlers; |
ih != NULL; |
ih != NULL; |
ihp = &ih->ih_evt_next, ih = ih->ih_evt_next) { |
ihp = &ih->ih_evt_next, ih = ih->ih_evt_next) { |
if (ih->ih_fun == func && ih->ih_arg == arg) |
if (ih->ih_fun == func && ih->ih_arg == arg) |
break; |
break; |
} |
} |
if (ih == NULL) |
if (ih == NULL) { |
|
mutex_spin_exit(&evtlock[evtch]); |
return ENOENT; |
return ENOENT; |
|
} |
*ihp = ih->ih_evt_next; |
*ihp = ih->ih_evt_next; |
|
mutex_spin_exit(&evtlock[evtch]); |
|
|
ipls = ci->ci_isources[ih->ih_level]; |
ipls = ci->ci_isources[ih->ih_level]; |
for (ihp = &ipls->ipl_handlers, ih = ipls->ipl_handlers; |
for (ihp = &ipls->ipl_handlers, ih = ipls->ipl_handlers; |
Line 609 event_remove_handler(int evtch, int (*fu |
|
Line 752 event_remove_handler(int evtch, int (*fu |
|
free(evts, M_DEVBUF); |
free(evts, M_DEVBUF); |
evtsource[evtch] = NULL; |
evtsource[evtch] = NULL; |
} else { |
} else { |
intr_calculatemasks(evts); |
intr_calculatemasks(evts, evtch); |
} |
} |
return 0; |
return 0; |
} |
} |