amd64/i386: introduce APIC hooks for different APIC implementations.

This is needed for Xen PV(H) guests, since there's no hardware lapic
available on this kind of domains. This commit should not change
functionality.

Sponsored by: Citrix Systems R&D
Reviewed by: jhb
Approved by: gibbs

amd64/include/cpu.h:
amd64/amd64/mp_machdep.c:
i386/include/cpu.h:
i386/i386/mp_machdep.c:
 - Remove lapic_ipi_vectored hook from cpu_ops, since it's now
   implemented in the lapic hooks.

amd64/amd64/mp_machdep.c:
i386/i386/mp_machdep.c:
 - Use lapic_ipi_vectored directly, since it's now an inline function
   that will call the appropiate hook.

x86/x86/local_apic.c:
 - Prefix bare metal public lapic functions with native_ and mark them
   as static.
 - Define default implementation of apic_ops.

x86/include/apicvar.h:
 - Declare the apic_ops structure and create inline functions to
   access the hooks, so the change is transparent to existing users of
   the lapic_ functions.

x86/xen/hvm.c:
 - Switch to use the new apic_ops.
This commit is contained in:
Roger Pau Monné 2014-06-16 08:43:03 +00:00
parent 5f35f84fa0
commit ef409ede7b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=267526
7 changed files with 358 additions and 100 deletions

View File

@ -125,9 +125,7 @@ static u_long *ipi_hardclock_counts[MAXCPU];
#endif
/* Default cpu_ops implementation. */
struct cpu_ops cpu_ops = {
.ipi_vectored = lapic_ipi_vectored
};
struct cpu_ops cpu_ops;
extern inthand_t IDTVEC(fast_syscall), IDTVEC(fast_syscall32);
@ -1125,7 +1123,7 @@ ipi_send_cpu(int cpu, u_int ipi)
if (old_pending)
return;
}
cpu_ops.ipi_vectored(ipi, cpu_apic_ids[cpu]);
lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
}
/*
@ -1395,7 +1393,7 @@ ipi_all_but_self(u_int ipi)
CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
cpu_ops.ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
}
int

View File

@ -63,7 +63,6 @@
struct cpu_ops {
void (*cpu_init)(void);
void (*cpu_resume)(void);
void (*ipi_vectored)(u_int, int);
};
extern struct cpu_ops cpu_ops;

View File

@ -168,9 +168,7 @@ static u_long *ipi_hardclock_counts[MAXCPU];
#endif
/* Default cpu_ops implementation. */
struct cpu_ops cpu_ops = {
.ipi_vectored = lapic_ipi_vectored
};
struct cpu_ops cpu_ops;
/*
* Local data and functions.
@ -1208,7 +1206,7 @@ ipi_send_cpu(int cpu, u_int ipi)
if (old_pending)
return;
}
cpu_ops.ipi_vectored(ipi, cpu_apic_ids[cpu]);
lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
}
/*
@ -1459,7 +1457,7 @@ ipi_all_but_self(u_int ipi)
CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
cpu_ops.ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
}
int

View File

@ -63,7 +63,6 @@
struct cpu_ops {
void (*cpu_init)(void);
void (*cpu_resume)(void);
void (*ipi_vectored)(u_int, int);
};
extern struct cpu_ops cpu_ops;

View File

@ -168,15 +168,7 @@ inthand_t
extern vm_paddr_t lapic_paddr;
extern int apic_cpuids[];
u_int apic_alloc_vector(u_int apic_id, u_int irq);
u_int apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count,
u_int align);
void apic_disable_vector(u_int apic_id, u_int vector);
void apic_enable_vector(u_int apic_id, u_int vector);
void apic_free_vector(u_int apic_id, u_int vector, u_int irq);
u_int apic_idt_to_irq(u_int apic_id, u_int vector);
void apic_register_enumerator(struct apic_enumerator *enumerator);
u_int apic_cpuid(u_int apic_id);
void *ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase);
int ioapic_disable_pin(void *cookie, u_int pin);
int ioapic_get_vector(void *cookie, u_int pin);
@ -189,33 +181,240 @@ int ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol);
int ioapic_set_triggermode(void *cookie, u_int pin,
enum intr_trigger trigger);
int ioapic_set_smi(void *cookie, u_int pin);
void lapic_create(u_int apic_id, int boot_cpu);
void lapic_disable(void);
void lapic_disable_pmc(void);
void lapic_dump(const char *str);
void lapic_enable_cmc(void);
int lapic_enable_pmc(void);
void lapic_eoi(void);
int lapic_id(void);
void lapic_init(vm_paddr_t addr);
int lapic_intr_pending(u_int vector);
void lapic_ipi_raw(register_t icrlo, u_int dest);
void lapic_ipi_vectored(u_int vector, int dest);
int lapic_ipi_wait(int delay);
/*
* Struct containing pointers to APIC functions whose
* implementation is run time selectable.
*/
struct apic_ops {
void (*create)(u_int, int);
void (*init)(vm_paddr_t);
void (*setup)(int);
void (*dump)(const char *);
void (*disable)(void);
void (*eoi)(void);
int (*id)(void);
int (*intr_pending)(u_int);
void (*set_logical_id)(u_int, u_int, u_int);
u_int (*cpuid)(u_int);
/* Vectors */
u_int (*alloc_vector)(u_int, u_int);
u_int (*alloc_vectors)(u_int, u_int *, u_int, u_int);
void (*enable_vector)(u_int, u_int);
void (*disable_vector)(u_int, u_int);
void (*free_vector)(u_int, u_int, u_int);
/* PMC */
int (*enable_pmc)(void);
void (*disable_pmc)(void);
void (*reenable_pmc)(void);
/* CMC */
void (*enable_cmc)(void);
/* IPI */
void (*ipi_raw)(register_t, u_int);
void (*ipi_vectored)(u_int, int);
int (*ipi_wait)(int);
/* LVT */
int (*set_lvt_mask)(u_int, u_int, u_char);
int (*set_lvt_mode)(u_int, u_int, u_int32_t);
int (*set_lvt_polarity)(u_int, u_int, enum intr_polarity);
int (*set_lvt_triggermode)(u_int, u_int, enum intr_trigger);
};
extern struct apic_ops apic_ops;
static inline void
lapic_create(u_int apic_id, int boot_cpu)
{
apic_ops.create(apic_id, boot_cpu);
}
static inline void
lapic_init(vm_paddr_t addr)
{
apic_ops.init(addr);
}
static inline void
lapic_setup(int boot)
{
apic_ops.setup(boot);
}
static inline void
lapic_dump(const char *str)
{
apic_ops.dump(str);
}
static inline void
lapic_disable(void)
{
apic_ops.disable();
}
static inline void
lapic_eoi(void)
{
apic_ops.eoi();
}
static inline int
lapic_id(void)
{
return (apic_ops.id());
}
static inline int
lapic_intr_pending(u_int vector)
{
return (apic_ops.intr_pending(vector));
}
/* XXX: UNUSED */
static inline void
lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
{
apic_ops.set_logical_id(apic_id, cluster, cluster_id);
}
static inline u_int
apic_cpuid(u_int apic_id)
{
return (apic_ops.cpuid(apic_id));
}
static inline u_int
apic_alloc_vector(u_int apic_id, u_int irq)
{
return (apic_ops.alloc_vector(apic_id, irq));
}
static inline u_int
apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align)
{
return (apic_ops.alloc_vectors(apic_id, irqs, count, align));
}
static inline void
apic_enable_vector(u_int apic_id, u_int vector)
{
apic_ops.enable_vector(apic_id, vector);
}
static inline void
apic_disable_vector(u_int apic_id, u_int vector)
{
apic_ops.disable_vector(apic_id, vector);
}
static inline void
apic_free_vector(u_int apic_id, u_int vector, u_int irq)
{
apic_ops.free_vector(apic_id, vector, irq);
}
static inline int
lapic_enable_pmc(void)
{
return (apic_ops.enable_pmc());
}
static inline void
lapic_disable_pmc(void)
{
apic_ops.disable_pmc();
}
static inline void
lapic_reenable_pmc(void)
{
apic_ops.reenable_pmc();
}
static inline void
lapic_enable_cmc(void)
{
apic_ops.enable_cmc();
}
static inline void
lapic_ipi_raw(register_t icrlo, u_int dest)
{
apic_ops.ipi_raw(icrlo, dest);
}
static inline void
lapic_ipi_vectored(u_int vector, int dest)
{
apic_ops.ipi_vectored(vector, dest);
}
static inline int
lapic_ipi_wait(int delay)
{
return (apic_ops.ipi_wait(delay));
}
static inline int
lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked)
{
return (apic_ops.set_lvt_mask(apic_id, lvt, masked));
}
static inline int
lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode)
{
return (apic_ops.set_lvt_mode(apic_id, lvt, mode));
}
static inline int
lapic_set_lvt_polarity(u_int apic_id, u_int lvt, enum intr_polarity pol)
{
return (apic_ops.set_lvt_polarity(apic_id, lvt, pol));
}
static inline int
lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, enum intr_trigger trigger)
{
return (apic_ops.set_lvt_triggermode(apic_id, lvt, trigger));
}
void lapic_handle_cmc(void);
void lapic_handle_error(void);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
void lapic_reenable_pmc(void);
void lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id);
int lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked);
int lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode);
int lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
enum intr_polarity pol);
int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
enum intr_trigger trigger);
void lapic_set_tpr(u_int vector);
void lapic_setup(int boot);
void xen_intr_handle_upcall(struct trapframe *frame);
#endif /* !LOCORE */

View File

@ -169,11 +169,76 @@ static void lapic_timer_stop(struct lapic *);
static void lapic_timer_set_divisor(u_int divisor);
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
static int lapic_et_start(struct eventtimer *et,
sbintime_t first, sbintime_t period);
sbintime_t first, sbintime_t period);
static int lapic_et_stop(struct eventtimer *et);
static u_int apic_idt_to_irq(u_int apic_id, u_int vector);
static void lapic_set_tpr(u_int vector);
struct pic lapic_pic = { .pic_resume = lapic_resume };
/* Forward declarations for apic_ops */
static void native_lapic_create(u_int apic_id, int boot_cpu);
static void native_lapic_init(vm_paddr_t addr);
static void native_lapic_setup(int boot);
static void native_lapic_dump(const char *str);
static void native_lapic_disable(void);
static void native_lapic_eoi(void);
static int native_lapic_id(void);
static int native_lapic_intr_pending(u_int vector);
static u_int native_apic_cpuid(u_int apic_id);
static u_int native_apic_alloc_vector(u_int apic_id, u_int irq);
static u_int native_apic_alloc_vectors(u_int apic_id, u_int *irqs,
u_int count, u_int align);
static void native_apic_disable_vector(u_int apic_id, u_int vector);
static void native_apic_enable_vector(u_int apic_id, u_int vector);
static void native_apic_free_vector(u_int apic_id, u_int vector, u_int irq);
static void native_lapic_set_logical_id(u_int apic_id, u_int cluster,
u_int cluster_id);
static int native_lapic_enable_pmc(void);
static void native_lapic_disable_pmc(void);
static void native_lapic_reenable_pmc(void);
static void native_lapic_enable_cmc(void);
static void native_lapic_ipi_raw(register_t icrlo, u_int dest);
static void native_lapic_ipi_vectored(u_int vector, int dest);
static int native_lapic_ipi_wait(int delay);
static int native_lapic_set_lvt_mask(u_int apic_id, u_int lvt,
u_char masked);
static int native_lapic_set_lvt_mode(u_int apic_id, u_int lvt,
uint32_t mode);
static int native_lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
enum intr_polarity pol);
static int native_lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
enum intr_trigger trigger);
struct apic_ops apic_ops = {
.create = native_lapic_create,
.init = native_lapic_init,
.setup = native_lapic_setup,
.dump = native_lapic_dump,
.disable = native_lapic_disable,
.eoi = native_lapic_eoi,
.id = native_lapic_id,
.intr_pending = native_lapic_intr_pending,
.set_logical_id = native_lapic_set_logical_id,
.cpuid = native_apic_cpuid,
.alloc_vector = native_apic_alloc_vector,
.alloc_vectors = native_apic_alloc_vectors,
.enable_vector = native_apic_enable_vector,
.disable_vector = native_apic_disable_vector,
.free_vector = native_apic_free_vector,
.enable_pmc = native_lapic_enable_pmc,
.disable_pmc = native_lapic_disable_pmc,
.reenable_pmc = native_lapic_reenable_pmc,
.enable_cmc = native_lapic_enable_cmc,
.ipi_raw = native_lapic_ipi_raw,
.ipi_vectored = native_lapic_ipi_vectored,
.ipi_wait = native_lapic_ipi_wait,
.set_lvt_mask = native_lapic_set_lvt_mask,
.set_lvt_mode = native_lapic_set_lvt_mode,
.set_lvt_polarity = native_lapic_set_lvt_polarity,
.set_lvt_triggermode = native_lapic_set_lvt_triggermode,
};
static uint32_t
lvt_mode(struct lapic *la, u_int pin, uint32_t value)
{
@ -218,8 +283,8 @@ lvt_mode(struct lapic *la, u_int pin, uint32_t value)
/*
* Map the local APIC and setup necessary interrupt vectors.
*/
void
lapic_init(vm_paddr_t addr)
static void
native_lapic_init(vm_paddr_t addr)
{
u_int regs[4];
int i, arat;
@ -280,8 +345,8 @@ lapic_init(vm_paddr_t addr)
/*
* Create a local APIC instance.
*/
void
lapic_create(u_int apic_id, int boot_cpu)
static void
native_lapic_create(u_int apic_id, int boot_cpu)
{
int i;
@ -326,8 +391,8 @@ lapic_create(u_int apic_id, int boot_cpu)
/*
* Dump contents of local APIC registers
*/
void
lapic_dump(const char* str)
static void
native_lapic_dump(const char* str)
{
uint32_t maxlvt;
@ -346,8 +411,8 @@ lapic_dump(const char* str)
printf(" cmci: 0x%08x\n", lapic->lvt_cmci);
}
void
lapic_setup(int boot)
static void
native_lapic_setup(int boot)
{
struct lapic *la;
u_int32_t maxlvt;
@ -405,8 +470,8 @@ lapic_setup(int boot)
intr_restore(saveintr);
}
void
lapic_reenable_pmc(void)
static void
native_lapic_reenable_pmc(void)
{
#ifdef HWPMC_HOOKS
uint32_t value;
@ -428,8 +493,8 @@ lapic_update_pmc(void *dummy)
}
#endif
int
lapic_enable_pmc(void)
static int
native_lapic_enable_pmc(void)
{
#ifdef HWPMC_HOOKS
u_int32_t maxlvt;
@ -462,8 +527,8 @@ lapic_enable_pmc(void)
#endif
}
void
lapic_disable_pmc(void)
static void
native_lapic_disable_pmc(void)
{
#ifdef HWPMC_HOOKS
u_int32_t maxlvt;
@ -540,8 +605,8 @@ lapic_et_stop(struct eventtimer *et)
return (0);
}
void
lapic_disable(void)
static void
native_lapic_disable(void)
{
uint32_t value;
@ -571,16 +636,16 @@ lapic_resume(struct pic *pic, bool suspend_cancelled)
lapic_setup(0);
}
int
lapic_id(void)
static int
native_lapic_id(void)
{
KASSERT(lapic != NULL, ("local APIC is not mapped"));
return (lapic->id >> APIC_ID_SHIFT);
}
int
lapic_intr_pending(u_int vector)
static int
native_lapic_intr_pending(u_int vector)
{
volatile u_int32_t *irr;
@ -597,8 +662,8 @@ lapic_intr_pending(u_int vector)
return (irr[(vector / 32) * 4] & 1 << (vector % 32));
}
void
lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
static void
native_lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
{
struct lapic *la;
@ -613,8 +678,8 @@ lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
la->la_cluster_id = cluster_id;
}
int
lapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked)
static int
native_lapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked)
{
if (pin > APIC_LVT_MAX)
@ -636,8 +701,8 @@ lapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked)
return (0);
}
int
lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode)
static int
native_lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode)
{
struct lvt *lvt;
@ -692,8 +757,8 @@ lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode)
return (0);
}
int
lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
static int
native_lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
{
if (pin > APIC_LVT_MAX || pol == INTR_POLARITY_CONFORM)
@ -717,8 +782,9 @@ lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
return (0);
}
int
lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
static int
native_lapic_set_lvt_triggermode(u_int apic_id, u_int pin,
enum intr_trigger trigger)
{
if (pin > APIC_LVT_MAX || trigger == INTR_TRIGGER_CONFORM)
@ -746,7 +812,7 @@ lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
* Adjust the TPR of the current CPU so that it blocks all interrupts below
* the passed in vector.
*/
void
static void
lapic_set_tpr(u_int vector)
{
#ifdef CHEAP_TPR
@ -760,8 +826,8 @@ lapic_set_tpr(u_int vector)
#endif
}
void
lapic_eoi(void)
static void
native_lapic_eoi(void)
{
lapic->eoi = 0;
@ -882,8 +948,8 @@ lapic_handle_cmc(void)
* is called prior to lapic_setup() during boot, this just needs to unmask
* this CPU's LVT_CMCI entry.
*/
void
lapic_enable_cmc(void)
static void
native_lapic_enable_cmc(void)
{
u_int apic_id;
@ -918,8 +984,8 @@ lapic_handle_error(void)
lapic_eoi();
}
u_int
apic_cpuid(u_int apic_id)
static u_int
native_apic_cpuid(u_int apic_id)
{
#ifdef SMP
return apic_cpuids[apic_id];
@ -929,8 +995,8 @@ apic_cpuid(u_int apic_id)
}
/* Request a free IDT vector to be used by the specified IRQ. */
u_int
apic_alloc_vector(u_int apic_id, u_int irq)
static u_int
native_apic_alloc_vector(u_int apic_id, u_int irq)
{
u_int vector;
@ -958,8 +1024,8 @@ apic_alloc_vector(u_int apic_id, u_int irq)
* aligned on a boundary of 'align'. If the request cannot be
* satisfied, 0 is returned.
*/
u_int
apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align)
static u_int
native_apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align)
{
u_int first, run, vector;
@ -1018,8 +1084,8 @@ apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align)
* which do not have the vector configured would report spurious interrupts
* should it fire.
*/
void
apic_enable_vector(u_int apic_id, u_int vector)
static void
native_apic_enable_vector(u_int apic_id, u_int vector)
{
KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
@ -1033,8 +1099,8 @@ apic_enable_vector(u_int apic_id, u_int vector)
GSEL_APIC);
}
void
apic_disable_vector(u_int apic_id, u_int vector)
static void
native_apic_disable_vector(u_int apic_id, u_int vector)
{
KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
@ -1054,8 +1120,8 @@ apic_disable_vector(u_int apic_id, u_int vector)
}
/* Release an APIC vector when it's no longer in use. */
void
apic_free_vector(u_int apic_id, u_int vector, u_int irq)
static void
native_apic_free_vector(u_int apic_id, u_int vector, u_int irq)
{
struct thread *td;
@ -1093,7 +1159,7 @@ apic_free_vector(u_int apic_id, u_int vector, u_int irq)
}
/* Map an IDT vector (APIC) to an IRQ (interrupt source). */
u_int
static u_int
apic_idt_to_irq(u_int apic_id, u_int vector)
{
int irq;
@ -1389,8 +1455,8 @@ SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_SECOND, apic_setup_io, NULL);
* private to the MD code. The public interface for the rest of the
* kernel is defined in mp_machdep.c.
*/
int
lapic_ipi_wait(int delay)
static int
native_lapic_ipi_wait(int delay)
{
int x, incr;
@ -1412,8 +1478,8 @@ lapic_ipi_wait(int delay)
return (0);
}
void
lapic_ipi_raw(register_t icrlo, u_int dest)
static void
native_lapic_ipi_raw(register_t icrlo, u_int dest)
{
register_t value, saveintr;
@ -1446,8 +1512,8 @@ lapic_ipi_raw(register_t icrlo, u_int dest)
#define AFTER_SPIN 1000
#endif
void
lapic_ipi_vectored(u_int vector, int dest)
static void
native_lapic_ipi_vectored(u_int vector, int dest)
{
register_t icrlo, destfield;

View File

@ -108,7 +108,6 @@ enum xen_domain_type xen_domain_type = XEN_NATIVE;
#ifdef SMP
struct cpu_ops xen_hvm_cpu_ops = {
.ipi_vectored = lapic_ipi_vectored,
.cpu_init = xen_hvm_cpu_init,
.cpu_resume = xen_hvm_cpu_resume
};
@ -365,7 +364,7 @@ xen_setup_cpus(void)
xen_cpu_ipi_init(i);
/* Set the xen pv ipi ops to replace the native ones */
cpu_ops.ipi_vectored = xen_ipi_vectored;
apic_ops.ipi_vectored = xen_ipi_vectored;
}
#endif