Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm64/arm64/intr_machdep.c
Show All 32 Lines | |||||
* | * | ||||
* form: src/sys/powerpc/powerpc/intr_machdep.c, r271712 2014/09/17 | * form: src/sys/powerpc/powerpc/intr_machdep.c, r271712 2014/09/17 | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/proc.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/ktr.h> | #include <sys/ktr.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/cpuset.h> | #include <sys/cpuset.h> | ||||
Show All 30 Lines | struct arm64_intr_entry { | ||||
struct intr_event *i_event; | struct intr_event *i_event; | ||||
enum intr_trigger i_trig; | enum intr_trigger i_trig; | ||||
enum intr_polarity i_pol; | enum intr_polarity i_pol; | ||||
u_int i_hw_irq; /* Physical interrupt number */ | u_int i_hw_irq; /* Physical interrupt number */ | ||||
u_int i_cntidx; /* Index in intrcnt table */ | u_int i_cntidx; /* Index in intrcnt table */ | ||||
u_int i_handlers; /* Allocated handlers */ | u_int i_handlers; /* Allocated handlers */ | ||||
u_int i_cpu; /* Assigned CPU */ | |||||
u_long *i_cntp; /* Interrupt hit counter */ | u_long *i_cntp; /* Interrupt hit counter */ | ||||
}; | }; | ||||
/* Counts and names for statistics - see sys/sys/interrupt.h */ | /* Counts and names for statistics - see sys/sys/interrupt.h */ | ||||
/* Tables are indexed by i_cntidx */ | /* Tables are indexed by i_cntidx */ | ||||
u_long intrcnt[NIRQS]; | u_long intrcnt[NIRQS]; | ||||
char intrnames[NIRQS * INTRNAME_LEN]; | char intrnames[NIRQS * INTRNAME_LEN]; | ||||
size_t sintrcnt = sizeof(intrcnt); | size_t sintrcnt = sizeof(intrcnt); | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | intr_allocate(u_int hw_irq) | ||||
/* Do not alloc another intr when max number of IRQs has been reached */ | /* Do not alloc another intr when max number of IRQs has been reached */ | ||||
if (intrcntidx >= NIRQS) | if (intrcntidx >= NIRQS) | ||||
return (NULL); | return (NULL); | ||||
intr = malloc(sizeof(*intr), M_INTR, M_NOWAIT); | intr = malloc(sizeof(*intr), M_INTR, M_NOWAIT); | ||||
if (intr == NULL) | if (intr == NULL) | ||||
return (NULL); | return (NULL); | ||||
/* The default CPU is 0 but can be changed later by bind or shuffle */ | |||||
intr->i_cpu = 0; | |||||
intr->i_event = NULL; | intr->i_event = NULL; | ||||
intr->i_handlers = 0; | intr->i_handlers = 0; | ||||
intr->i_trig = INTR_TRIGGER_CONFORM; | intr->i_trig = INTR_TRIGGER_CONFORM; | ||||
intr->i_pol = INTR_POLARITY_CONFORM; | intr->i_pol = INTR_POLARITY_CONFORM; | ||||
intr->i_cntidx = atomic_fetchadd_int(&intrcntidx, 1); | intr->i_cntidx = atomic_fetchadd_int(&intrcntidx, 1); | ||||
intr->i_cntp = &intrcnt[intr->i_cntidx]; | intr->i_cntp = &intrcnt[intr->i_cntidx]; | ||||
intr->i_hw_irq = hw_irq; | intr->i_hw_irq = hw_irq; | ||||
mtx_lock_spin(&intr_list_lock); | mtx_lock_spin(&intr_list_lock); | ||||
SLIST_INSERT_HEAD(&irq_slist_head, intr, entries); | SLIST_INSERT_HEAD(&irq_slist_head, intr, entries); | ||||
mtx_unlock_spin(&intr_list_lock); | mtx_unlock_spin(&intr_list_lock); | ||||
return intr; | return intr; | ||||
} | } | ||||
static int | |||||
intr_assign_cpu(void *arg, int cpu) | |||||
{ | |||||
#ifdef SMP | |||||
struct arm64_intr_entry *intr; | |||||
int error; | |||||
if (root_pic == NULL) | |||||
panic("Cannot assing interrupt to CPU. No PIC configured"); | |||||
/* | |||||
* Set the interrupt to CPU affinity. | |||||
* Do not configure this in hardware during early boot. | |||||
* We will pick up the assignment once the APs are started. | |||||
*/ | |||||
if (cpu != NOCPU) { | |||||
intr = arg; | |||||
if (!cold && smp_started) { | |||||
/* | |||||
* Bind the interrupt immediately | |||||
* if SMP is up and running. | |||||
*/ | |||||
error = PIC_BIND(root_pic, intr->i_hw_irq, cpu); | |||||
if (error == 0) | |||||
intr->i_cpu = cpu; | |||||
} else { | |||||
/* Postpone binding until SMP is operational */ | |||||
intr->i_cpu = cpu; | |||||
error = 0; | |||||
} | |||||
} else | |||||
error = 0; | |||||
return (error); | |||||
#else | |||||
return (EOPNOTSUPP); | |||||
#endif | |||||
} | |||||
static void | static void | ||||
intr_pre_ithread(void *arg) | intr_pre_ithread(void *arg) | ||||
{ | { | ||||
struct arm64_intr_entry *intr = arg; | struct arm64_intr_entry *intr = arg; | ||||
PIC_PRE_ITHREAD(root_pic, intr->i_hw_irq); | PIC_PRE_ITHREAD(root_pic, intr->i_hw_irq); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | arm_setup_intr(const char *name, driver_filter_t *filt, driver_intr_t handler, | ||||
* table (the interrupts will be deconfigured in arm_enable_intr()). | * table (the interrupts will be deconfigured in arm_enable_intr()). | ||||
*/ | */ | ||||
if (intr->i_cntidx >= NIRQS) | if (intr->i_cntidx >= NIRQS) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (intr->i_event == NULL) { | if (intr->i_event == NULL) { | ||||
error = intr_event_create(&intr->i_event, (void *)intr, 0, | error = intr_event_create(&intr->i_event, (void *)intr, 0, | ||||
hw_irq, intr_pre_ithread, intr_post_ithread, | hw_irq, intr_pre_ithread, intr_post_ithread, | ||||
intr_post_filter, NULL, "irq%u", hw_irq); | intr_post_filter, intr_assign_cpu, "irq%u", hw_irq); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
error = intr_event_add_handler(intr->i_event, name, filt, handler, arg, | error = intr_event_add_handler(intr->i_event, name, filt, handler, arg, | ||||
intr_priority(flags), flags, cookiep); | intr_priority(flags), flags, cookiep); | ||||
if (!error) { | if (!error) { | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
critical_enter(); | critical_enter(); | ||||
PIC_DISPATCH(root_pic, tf); | PIC_DISPATCH(root_pic, tf); | ||||
critical_exit(); | critical_exit(); | ||||
} | } | ||||
#ifdef SMP | #ifdef SMP | ||||
static void | |||||
arm_intr_smp_init(void *dummy __unused) | |||||
{ | |||||
struct arm64_intr_entry *intr; | |||||
int error; | |||||
if (root_pic == NULL) | |||||
panic("Cannot assing interrupts to CPUs. No PIC configured"); | |||||
mtx_lock_spin(&intr_list_lock); | |||||
SLIST_FOREACH(intr, &irq_slist_head, entries) { | |||||
mtx_unlock_spin(&intr_list_lock); | |||||
error = PIC_BIND(root_pic, intr->i_hw_irq, intr->i_cpu); | |||||
if (error != 0) | |||||
intr->i_cpu = 0; | |||||
mtx_lock_spin(&intr_list_lock); | |||||
} | |||||
mtx_unlock_spin(&intr_list_lock); | |||||
} | |||||
SYSINIT(arm_intr_smp_init, SI_SUB_SMP, SI_ORDER_ANY, arm_intr_smp_init, NULL); | |||||
/* Attempt to bind the specified IRQ to the specified CPU. */ | |||||
int | |||||
arm_intr_bind(u_int hw_irq, int cpu) | |||||
{ | |||||
struct arm64_intr_entry *intr; | |||||
mtx_lock_spin(&intr_list_lock); | |||||
intr = intr_lookup_locked(hw_irq); | |||||
mtx_unlock_spin(&intr_list_lock); | |||||
if (intr == NULL) | |||||
return (EINVAL); | |||||
return (intr_event_bind(intr->i_event, cpu)); | |||||
} | |||||
void | void | ||||
arm_setup_ipihandler(driver_filter_t *filt, u_int ipi) | arm_setup_ipihandler(driver_filter_t *filt, u_int ipi) | ||||
{ | { | ||||
arm_setup_intr("ipi", filt, NULL, (void *)((uintptr_t)ipi | 1<<16), ipi, | arm_setup_intr("ipi", filt, NULL, (void *)((uintptr_t)ipi | 1<<16), ipi, | ||||
INTR_TYPE_MISC | INTR_EXCL, NULL); | INTR_TYPE_MISC | INTR_EXCL, NULL); | ||||
arm_unmask_ipi(ipi); | arm_unmask_ipi(ipi); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |