162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/init.h> 362306a36Sopenharmony_ci#include <linux/thread_info.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <asm/x86_init.h> 662306a36Sopenharmony_ci#include <asm/apic.h> 762306a36Sopenharmony_ci#include <asm/io_apic.h> 862306a36Sopenharmony_ci#include <asm/xen/hypercall.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <xen/xen.h> 1162306a36Sopenharmony_ci#include <xen/interface/physdev.h> 1262306a36Sopenharmony_ci#include "xen-ops.h" 1362306a36Sopenharmony_ci#include "pmu.h" 1462306a36Sopenharmony_ci#include "smp.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic unsigned int xen_io_apic_read(unsigned apic, unsigned reg) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci struct physdev_apic apic_op; 1962306a36Sopenharmony_ci int ret; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci apic_op.apic_physbase = mpc_ioapic_addr(apic); 2262306a36Sopenharmony_ci apic_op.reg = reg; 2362306a36Sopenharmony_ci ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op); 2462306a36Sopenharmony_ci if (!ret) 2562306a36Sopenharmony_ci return apic_op.value; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci /* fallback to return an emulated IO_APIC values */ 2862306a36Sopenharmony_ci if (reg == 0x1) 2962306a36Sopenharmony_ci return 0x00170020; 3062306a36Sopenharmony_ci else if (reg == 0x0) 3162306a36Sopenharmony_ci return apic << 24; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return 0xfd; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic u32 xen_set_apic_id(unsigned int x) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci WARN_ON(1); 3962306a36Sopenharmony_ci return x; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic unsigned int xen_get_apic_id(unsigned long x) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return ((x)>>24) & 0xFFu; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic u32 xen_apic_read(u32 reg) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct xen_platform_op op = { 5062306a36Sopenharmony_ci .cmd = XENPF_get_cpuinfo, 5162306a36Sopenharmony_ci .interface_version = XENPF_INTERFACE_VERSION, 5262306a36Sopenharmony_ci .u.pcpu_info.xen_cpuid = 0, 5362306a36Sopenharmony_ci }; 5462306a36Sopenharmony_ci int ret; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* Shouldn't need this as APIC is turned off for PV, and we only 5762306a36Sopenharmony_ci * get called on the bootup processor. But just in case. */ 5862306a36Sopenharmony_ci if (!xen_initial_domain() || smp_processor_id()) 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (reg == APIC_LVR) 6262306a36Sopenharmony_ci return 0x14; 6362306a36Sopenharmony_ci if (reg != APIC_ID) 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret = HYPERVISOR_platform_op(&op); 6762306a36Sopenharmony_ci if (ret) 6862306a36Sopenharmony_ci op.u.pcpu_info.apic_id = BAD_APICID; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return op.u.pcpu_info.apic_id << 24; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void xen_apic_write(u32 reg, u32 val) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci if (reg == APIC_LVTPC) { 7662306a36Sopenharmony_ci (void)pmu_apic_update(reg); 7762306a36Sopenharmony_ci return; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Warn to see if there's any stray references */ 8162306a36Sopenharmony_ci WARN(1,"register: %x, value: %x\n", reg, val); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void xen_apic_eoi(void) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci WARN_ON_ONCE(1); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic u64 xen_apic_icr_read(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void xen_apic_icr_write(u32 low, u32 id) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci /* Warn to see if there's any stray references */ 9762306a36Sopenharmony_ci WARN_ON(1); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int xen_apic_probe_pv(void) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci if (xen_pv_domain()) 10362306a36Sopenharmony_ci return 1; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int xen_madt_oem_check(char *oem_id, char *oem_table_id) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return xen_pv_domain(); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int xen_phys_pkg_id(int initial_apic_id, int index_msb) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return initial_apic_id >> index_msb; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int xen_cpu_present_to_apicid(int cpu) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci if (cpu_present(cpu)) 12162306a36Sopenharmony_ci return cpu_data(cpu).apicid; 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci return BAD_APICID; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic struct apic xen_pv_apic __ro_after_init = { 12762306a36Sopenharmony_ci .name = "Xen PV", 12862306a36Sopenharmony_ci .probe = xen_apic_probe_pv, 12962306a36Sopenharmony_ci .acpi_madt_oem_check = xen_madt_oem_check, 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* .delivery_mode and .dest_mode_logical not used by XENPV */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci .disable_esr = 0, 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci .cpu_present_to_apicid = xen_cpu_present_to_apicid, 13662306a36Sopenharmony_ci .phys_pkg_id = xen_phys_pkg_id, /* detect_ht */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci .max_apic_id = UINT_MAX, 13962306a36Sopenharmony_ci .get_apic_id = xen_get_apic_id, 14062306a36Sopenharmony_ci .set_apic_id = xen_set_apic_id, 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci .calc_dest_apicid = apic_flat_calc_apicid, 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#ifdef CONFIG_SMP 14562306a36Sopenharmony_ci .send_IPI_mask = xen_send_IPI_mask, 14662306a36Sopenharmony_ci .send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself, 14762306a36Sopenharmony_ci .send_IPI_allbutself = xen_send_IPI_allbutself, 14862306a36Sopenharmony_ci .send_IPI_all = xen_send_IPI_all, 14962306a36Sopenharmony_ci .send_IPI_self = xen_send_IPI_self, 15062306a36Sopenharmony_ci#endif 15162306a36Sopenharmony_ci .read = xen_apic_read, 15262306a36Sopenharmony_ci .write = xen_apic_write, 15362306a36Sopenharmony_ci .eoi = xen_apic_eoi, 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci .icr_read = xen_apic_icr_read, 15662306a36Sopenharmony_ci .icr_write = xen_apic_icr_write, 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ciapic_driver(xen_pv_apic); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_civoid __init xen_init_apic(void) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci x86_apic_ops.io_apic_read = xen_io_apic_read; 16362306a36Sopenharmony_ci} 164