2012-03-21 02:53:10 +04:00
# include <linux/init.h>
2012-05-18 11:34:45 +04:00
2012-03-21 02:53:10 +04:00
# include <asm/x86_init.h>
2012-04-30 20:16:27 +04:00
# include <asm/apic.h>
# include <asm/xen/hypercall.h>
2012-03-21 02:53:10 +04:00
2012-05-18 11:34:45 +04:00
# include <xen/xen.h>
# include <xen/interface/physdev.h>
2012-08-21 22:49:34 +04:00
# include "xen-ops.h"
2015-03-02 20:06:23 +03:00
# include "smp.h"
2012-05-18 11:34:45 +04:00
2012-08-21 22:49:34 +04:00
static unsigned int xen_io_apic_read ( unsigned apic , unsigned reg )
2012-03-21 02:53:10 +04:00
{
2012-04-30 20:16:27 +04:00
struct physdev_apic apic_op ;
int ret ;
apic_op . apic_physbase = mpc_ioapic_addr ( apic ) ;
apic_op . reg = reg ;
ret = HYPERVISOR_physdev_op ( PHYSDEVOP_apic_read , & apic_op ) ;
if ( ! ret )
return apic_op . value ;
/* fallback to return an emulated IO_APIC values */
2012-03-21 02:53:10 +04:00
if ( reg = = 0x1 )
return 0x00170020 ;
else if ( reg = = 0x0 )
return apic < < 24 ;
return 0xfd ;
}
2015-03-02 20:06:23 +03:00
static unsigned long xen_set_apic_id ( unsigned int x )
{
WARN_ON ( 1 ) ;
return x ;
}
static unsigned int xen_get_apic_id ( unsigned long x )
{
return ( ( x ) > > 24 ) & 0xFFu ;
}
static u32 xen_apic_read ( u32 reg )
{
struct xen_platform_op op = {
. cmd = XENPF_get_cpuinfo ,
. interface_version = XENPF_INTERFACE_VERSION ,
. u . pcpu_info . xen_cpuid = 0 ,
} ;
int ret = 0 ;
/* Shouldn't need this as APIC is turned off for PV, and we only
* get called on the bootup processor . But just in case . */
if ( ! xen_initial_domain ( ) | | smp_processor_id ( ) )
return 0 ;
if ( reg = = APIC_LVR )
return 0x10 ;
# ifdef CONFIG_X86_32
if ( reg = = APIC_LDR )
return SET_APIC_LOGICAL_ID ( 1UL < < smp_processor_id ( ) ) ;
# endif
if ( reg ! = APIC_ID )
return 0 ;
ret = HYPERVISOR_dom0_op ( & op ) ;
if ( ret )
return 0 ;
return op . u . pcpu_info . apic_id < < 24 ;
}
static void xen_apic_write ( u32 reg , u32 val )
{
2015-08-10 23:34:34 +03:00
if ( reg = = APIC_LVTPC )
return ;
2015-03-02 20:06:23 +03:00
/* Warn to see if there's any stray references */
2015-03-04 00:12:12 +03:00
WARN ( 1 , " register: %x, value: %x \n " , reg , val ) ;
2015-03-02 20:06:23 +03:00
}
static u64 xen_apic_icr_read ( void )
{
return 0 ;
}
static void xen_apic_icr_write ( u32 low , u32 id )
{
/* Warn to see if there's any stray references */
WARN_ON ( 1 ) ;
}
static u32 xen_safe_apic_wait_icr_idle ( void )
{
return 0 ;
}
static int xen_apic_probe_pv ( void )
{
if ( xen_pv_domain ( ) )
return 1 ;
return 0 ;
}
static int xen_madt_oem_check ( char * oem_id , char * oem_table_id )
{
return xen_pv_domain ( ) ;
}
static int xen_id_always_valid ( int apicid )
{
return 1 ;
}
static int xen_id_always_registered ( void )
{
return 1 ;
}
static int xen_phys_pkg_id ( int initial_apic_id , int index_msb )
{
return initial_apic_id > > index_msb ;
}
# ifdef CONFIG_X86_32
static int xen_x86_32_early_logical_apicid ( int cpu )
{
/* Match with APIC_LDR read. Otherwise setup_local_APIC complains. */
return 1 < < cpu ;
}
# endif
static void xen_noop ( void )
{
}
static void xen_silent_inquire ( int apicid )
{
}
static struct apic xen_pv_apic = {
. name = " Xen PV " ,
. probe = xen_apic_probe_pv ,
. acpi_madt_oem_check = xen_madt_oem_check ,
. apic_id_valid = xen_id_always_valid ,
. apic_id_registered = xen_id_always_registered ,
/* .irq_delivery_mode - used in native_compose_msi_msg only */
/* .irq_dest_mode - used in native_compose_msi_msg only */
. target_cpus = default_target_cpus ,
. disable_esr = 0 ,
/* .dest_logical - default_send_IPI_ use it but we use our own. */
. check_apicid_used = default_check_apicid_used , /* Used on 32-bit */
. vector_allocation_domain = flat_vector_allocation_domain ,
. init_apic_ldr = xen_noop , /* setup_local_APIC calls it */
. ioapic_phys_id_map = default_ioapic_phys_id_map , /* Used on 32-bit */
. setup_apic_routing = NULL ,
. cpu_present_to_apicid = default_cpu_present_to_apicid ,
. apicid_to_cpu_present = physid_set_mask_of_physid , /* Used on 32-bit */
. check_phys_apicid_present = default_check_phys_apicid_present , /* smp_sanity_check needs it */
. phys_pkg_id = xen_phys_pkg_id , /* detect_ht */
. get_apic_id = xen_get_apic_id ,
. set_apic_id = xen_set_apic_id , /* Can be NULL on 32-bit. */
. apic_id_mask = 0xFF < < 24 , /* Used by verify_local_APIC. Match with what xen_get_apic_id does. */
. cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and ,
# ifdef CONFIG_SMP
. send_IPI_mask = xen_send_IPI_mask ,
. send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself ,
. send_IPI_allbutself = xen_send_IPI_allbutself ,
. send_IPI_all = xen_send_IPI_all ,
. send_IPI_self = xen_send_IPI_self ,
# endif
/* .wait_for_init_deassert- used by AP bootup - smp_callin which we don't use */
. inquire_remote_apic = xen_silent_inquire ,
. read = xen_apic_read ,
. write = xen_apic_write ,
. eoi_write = xen_apic_write ,
. icr_read = xen_apic_icr_read ,
. icr_write = xen_apic_icr_write ,
. wait_icr_idle = xen_noop ,
. safe_wait_icr_idle = xen_safe_apic_wait_icr_idle ,
# ifdef CONFIG_X86_32
/* generic_processor_info and setup_local_APIC. */
. x86_32_early_logical_apicid = xen_x86_32_early_logical_apicid ,
# endif
} ;
static void __init xen_apic_check ( void )
{
if ( apic = = & xen_pv_apic )
return ;
pr_info ( " Switched APIC routing from %s to %s. \n " , apic - > name ,
xen_pv_apic . name ) ;
apic = & xen_pv_apic ;
}
2012-03-21 02:53:10 +04:00
void __init xen_init_apic ( void )
{
x86_io_apic_ops . read = xen_io_apic_read ;
2015-03-02 20:06:23 +03:00
/* On PV guests the APIC CPUID bit is disabled so none of the
* routines end up executing . */
if ( ! xen_initial_domain ( ) )
apic = & xen_pv_apic ;
x86_platform . apic_post_init = xen_apic_check ;
2012-03-21 02:53:10 +04:00
}
2015-03-02 20:06:23 +03:00
apic_driver ( xen_pv_apic ) ;