1/* 2 * Written by: Garry Forsgren, Unisys Corporation 3 * Natalie Protasevich, Unisys Corporation 4 * 5 * This file contains the code to configure and interface 6 * with Unisys ES7000 series hardware system manager. 7 * 8 * Copyright (c) 2003 Unisys Corporation. 9 * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar 10 * 11 * All Rights Reserved. 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of version 2 of the GNU General Public License as 15 * published by the Free Software Foundation. 16 * 17 * This program is distributed in the hope that it would be useful, but 18 * WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 * 21 * You should have received a copy of the GNU General Public License along 22 * with this program; if not, write the Free Software Foundation, Inc., 59 23 * Temple Place - Suite 330, Boston MA 02111-1307, USA. 24 * 25 * Contact information: Unisys Corporation, Township Line & Union Meeting 26 * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or: 27 * 28 * http://www.unisys.com 29 */ 30 31#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 32 33#include <linux/notifier.h> 34#include <linux/spinlock.h> 35#include <linux/cpumask.h> 36#include <linux/threads.h> 37#include <linux/kernel.h> 38#include <linux/module.h> 39#include <linux/reboot.h> 40#include <linux/string.h> 41#include <linux/types.h> 42#include <linux/errno.h> 43#include <linux/acpi.h> 44#include <linux/init.h> 45#include <linux/gfp.h> 46#include <linux/nmi.h> 47#include <linux/smp.h> 48#include <linux/io.h> 49 50#include <asm/apicdef.h> 51#include <asm/atomic.h> 52#include <asm/fixmap.h> 53#include <asm/mpspec.h> 54#include <asm/setup.h> 55#include <asm/apic.h> 56#include <asm/ipi.h> 57 58/* 59 * ES7000 chipsets 60 */ 61 62#define NON_UNISYS 0 63#define ES7000_CLASSIC 1 64#define ES7000_ZORRO 2 65 66#define MIP_REG 1 67#define MIP_PSAI_REG 4 68 69#define MIP_BUSY 1 70#define MIP_SPIN 0xf0000 71#define MIP_VALID 0x0100000000000000ULL 72#define MIP_SW_APIC 0x1020b 73 74#define MIP_PORT(val) ((val >> 32) & 0xffff) 75 76#define MIP_RD_LO(val) (val & 0xffffffff) 77 78struct mip_reg { 79 unsigned long long off_0x00; 80 unsigned long long off_0x08; 81 unsigned long long off_0x10; 82 unsigned long long off_0x18; 83 unsigned long long off_0x20; 84 unsigned long long off_0x28; 85 unsigned long long off_0x30; 86 unsigned long long off_0x38; 87}; 88 89struct mip_reg_info { 90 unsigned long long mip_info; 91 unsigned long long delivery_info; 92 unsigned long long host_reg; 93 unsigned long long mip_reg; 94}; 95 96struct psai { 97 unsigned long long entry_type; 98 unsigned long long addr; 99 unsigned long long bep_addr; 100}; 101 102#ifdef CONFIG_ACPI 103 104struct es7000_oem_table { 105 struct acpi_table_header Header; 106 u32 OEMTableAddr; 107 u32 OEMTableSize; 108}; 109 110static unsigned long oem_addrX; 111static unsigned long oem_size; 112 113#endif 114 115/* 116 * ES7000 Globals 117 */ 118 119static volatile unsigned long *psai; 120static struct mip_reg *mip_reg; 121static struct mip_reg *host_reg; 122static int mip_port; 123static unsigned long mip_addr; 124static unsigned long host_addr; 125 126int es7000_plat; 127 128/* 129 * GSI override for ES7000 platforms. 130 */ 131 132 133static int __cpuinit wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip) 134{ 135 unsigned long vect = 0, psaival = 0; 136 137 if (psai == NULL) 138 return -1; 139 140 vect = ((unsigned long)__pa(eip)/0x1000) << 16; 141 psaival = (0x1000000 | vect | cpu); 142 143 while (*psai & 0x1000000) 144 ; 145 146 *psai = psaival; 147 148 return 0; 149} 150 151static int es7000_apic_is_cluster(void) 152{ 153 /* MPENTIUMIII */ 154 if (boot_cpu_data.x86 == 6 && 155 (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11)) 156 return 1; 157 158 return 0; 159} 160 161static void setup_unisys(void) 162{ 163 /* 164 * Determine the generation of the ES7000 currently running. 165 * 166 * es7000_plat = 1 if the machine is a 5xx ES7000 box 167 * es7000_plat = 2 if the machine is a x86_64 ES7000 box 168 * 169 */ 170 if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2)) 171 es7000_plat = ES7000_ZORRO; 172 else 173 es7000_plat = ES7000_CLASSIC; 174} 175 176/* 177 * Parse the OEM Table: 178 */ 179static int parse_unisys_oem(char *oemptr) 180{ 181 int i; 182 int success = 0; 183 unsigned char type, size; 184 unsigned long val; 185 char *tp = NULL; 186 struct psai *psaip = NULL; 187 struct mip_reg_info *mi; 188 struct mip_reg *host, *mip; 189 190 tp = oemptr; 191 192 tp += 8; 193 194 for (i = 0; i <= 6; i++) { 195 type = *tp++; 196 size = *tp++; 197 tp -= 2; 198 switch (type) { 199 case MIP_REG: 200 mi = (struct mip_reg_info *)tp; 201 val = MIP_RD_LO(mi->host_reg); 202 host_addr = val; 203 host = (struct mip_reg *)val; 204 host_reg = __va(host); 205 val = MIP_RD_LO(mi->mip_reg); 206 mip_port = MIP_PORT(mi->mip_info); 207 mip_addr = val; 208 mip = (struct mip_reg *)val; 209 mip_reg = __va(mip); 210 pr_debug("host_reg = 0x%lx\n", 211 (unsigned long)host_reg); 212 pr_debug("mip_reg = 0x%lx\n", 213 (unsigned long)mip_reg); 214 success++; 215 break; 216 case MIP_PSAI_REG: 217 psaip = (struct psai *)tp; 218 if (tp != NULL) { 219 if (psaip->addr) 220 psai = __va(psaip->addr); 221 else 222 psai = NULL; 223 success++; 224 } 225 break; 226 default: 227 break; 228 } 229 tp += size; 230 } 231 232 if (success < 2) 233 es7000_plat = NON_UNISYS; 234 else 235 setup_unisys(); 236 237 return es7000_plat; 238} 239 240#ifdef CONFIG_ACPI 241static int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) 242{ 243 struct acpi_table_header *header = NULL; 244 struct es7000_oem_table *table; 245 acpi_size tbl_size; 246 acpi_status ret; 247 int i = 0; 248 249 for (;;) { 250 ret = acpi_get_table_with_size("OEM1", i++, &header, &tbl_size); 251 if (!ACPI_SUCCESS(ret)) 252 return -1; 253 254 if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) 255 break; 256 257 early_acpi_os_unmap_memory(header, tbl_size); 258 } 259 260 table = (void *)header; 261 262 oem_addrX = table->OEMTableAddr; 263 oem_size = table->OEMTableSize; 264 265 early_acpi_os_unmap_memory(header, tbl_size); 266 267 *oem_addr = (unsigned long)__acpi_map_table(oem_addrX, oem_size); 268 269 return 0; 270} 271 272static void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr) 273{ 274 if (!oem_addr) 275 return; 276 277 __acpi_unmap_table((char *)oem_addr, oem_size); 278} 279 280static int es7000_check_dsdt(void) 281{ 282 struct acpi_table_header header; 283 284 if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) && 285 !strncmp(header.oem_id, "UNISYS", 6)) 286 return 1; 287 return 0; 288} 289 290static int es7000_acpi_ret; 291 292/* Hook from generic ACPI tables.c */ 293static int __init es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id) 294{ 295 unsigned long oem_addr = 0; 296 int check_dsdt; 297 int ret = 0; 298 299 /* check dsdt at first to avoid clear fix_map for oem_addr */ 300 check_dsdt = es7000_check_dsdt(); 301 302 if (!find_unisys_acpi_oem_table(&oem_addr)) { 303 if (check_dsdt) { 304 ret = parse_unisys_oem((char *)oem_addr); 305 } else { 306 setup_unisys(); 307 ret = 1; 308 } 309 /* 310 * we need to unmap it 311 */ 312 unmap_unisys_acpi_oem_table(oem_addr); 313 } 314 315 es7000_acpi_ret = ret; 316 317 return ret && !es7000_apic_is_cluster(); 318} 319 320static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id) 321{ 322 int ret = es7000_acpi_ret; 323 324 return ret && es7000_apic_is_cluster(); 325} 326 327#else /* !CONFIG_ACPI: */ 328static int es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id) 329{ 330 return 0; 331} 332 333static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id) 334{ 335 return 0; 336} 337#endif /* !CONFIG_ACPI */ 338 339static void es7000_spin(int n) 340{ 341 int i = 0; 342 343 while (i++ < n) 344 rep_nop(); 345} 346 347static int es7000_mip_write(struct mip_reg *mip_reg) 348{ 349 int status = 0; 350 int spin; 351 352 spin = MIP_SPIN; 353 while ((host_reg->off_0x38 & MIP_VALID) != 0) { 354 if (--spin <= 0) { 355 WARN(1, "Timeout waiting for Host Valid Flag\n"); 356 return -1; 357 } 358 es7000_spin(MIP_SPIN); 359 } 360 361 memcpy(host_reg, mip_reg, sizeof(struct mip_reg)); 362 outb(1, mip_port); 363 364 spin = MIP_SPIN; 365 366 while ((mip_reg->off_0x38 & MIP_VALID) == 0) { 367 if (--spin <= 0) { 368 WARN(1, "Timeout waiting for MIP Valid Flag\n"); 369 return -1; 370 } 371 es7000_spin(MIP_SPIN); 372 } 373 374 status = (mip_reg->off_0x00 & 0xffff0000000000ULL) >> 48; 375 mip_reg->off_0x38 &= ~MIP_VALID; 376 377 return status; 378} 379 380static void es7000_enable_apic_mode(void) 381{ 382 struct mip_reg es7000_mip_reg; 383 int mip_status; 384 385 if (!es7000_plat) 386 return; 387 388 pr_info("Enabling APIC mode.\n"); 389 memset(&es7000_mip_reg, 0, sizeof(struct mip_reg)); 390 es7000_mip_reg.off_0x00 = MIP_SW_APIC; 391 es7000_mip_reg.off_0x38 = MIP_VALID; 392 393 while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0) 394 WARN(1, "Command failed, status = %x\n", mip_status); 395} 396 397static void es7000_vector_allocation_domain(int cpu, struct cpumask *retmask) 398{ 399 /* Careful. Some cpus do not strictly honor the set of cpus 400 * specified in the interrupt destination when using lowest 401 * priority interrupt delivery mode. 402 * 403 * In particular there was a hyperthreading cpu observed to 404 * deliver interrupts to the wrong hyperthread when only one 405 * hyperthread was specified in the interrupt desitination. 406 */ 407 cpumask_clear(retmask); 408 cpumask_bits(retmask)[0] = APIC_ALL_CPUS; 409} 410 411 412static void es7000_wait_for_init_deassert(atomic_t *deassert) 413{ 414 while (!atomic_read(deassert)) 415 cpu_relax(); 416} 417 418static unsigned int es7000_get_apic_id(unsigned long x) 419{ 420 return (x >> 24) & 0xFF; 421} 422 423static void es7000_send_IPI_mask(const struct cpumask *mask, int vector) 424{ 425 default_send_IPI_mask_sequence_phys(mask, vector); 426} 427 428static void es7000_send_IPI_allbutself(int vector) 429{ 430 default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); 431} 432 433static void es7000_send_IPI_all(int vector) 434{ 435 es7000_send_IPI_mask(cpu_online_mask, vector); 436} 437 438static int es7000_apic_id_registered(void) 439{ 440 return 1; 441} 442 443static const struct cpumask *target_cpus_cluster(void) 444{ 445 return cpu_all_mask; 446} 447 448static const struct cpumask *es7000_target_cpus(void) 449{ 450 return cpumask_of(smp_processor_id()); 451} 452 453static unsigned long es7000_check_apicid_used(physid_mask_t *map, int apicid) 454{ 455 return 0; 456} 457 458static unsigned long es7000_check_apicid_present(int bit) 459{ 460 return physid_isset(bit, phys_cpu_present_map); 461} 462 463static unsigned long calculate_ldr(int cpu) 464{ 465 unsigned long id = per_cpu(x86_bios_cpu_apicid, cpu); 466 467 return SET_APIC_LOGICAL_ID(id); 468} 469 470/* 471 * Set up the logical destination ID. 472 * 473 * Intel recommends to set DFR, LdR and TPR before enabling 474 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel 475 * document number 292116). So here it goes... 476 */ 477static void es7000_init_apic_ldr_cluster(void) 478{ 479 unsigned long val; 480 int cpu = smp_processor_id(); 481 482 apic_write(APIC_DFR, APIC_DFR_CLUSTER); 483 val = calculate_ldr(cpu); 484 apic_write(APIC_LDR, val); 485} 486 487static void es7000_init_apic_ldr(void) 488{ 489 unsigned long val; 490 int cpu = smp_processor_id(); 491 492 apic_write(APIC_DFR, APIC_DFR_FLAT); 493 val = calculate_ldr(cpu); 494 apic_write(APIC_LDR, val); 495} 496 497static void es7000_setup_apic_routing(void) 498{ 499 int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id()); 500 501 pr_info("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n", 502 (apic_version[apic] == 0x14) ? 503 "Physical Cluster" : "Logical Cluster", 504 nr_ioapics, cpumask_bits(es7000_target_cpus())[0]); 505} 506 507static int es7000_apicid_to_node(int logical_apicid) 508{ 509 return 0; 510} 511 512 513static int es7000_cpu_present_to_apicid(int mps_cpu) 514{ 515 if (!mps_cpu) 516 return boot_cpu_physical_apicid; 517 else if (mps_cpu < nr_cpu_ids) 518 return per_cpu(x86_bios_cpu_apicid, mps_cpu); 519 else 520 return BAD_APICID; 521} 522 523static int cpu_id; 524 525static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap) 526{ 527 physid_set_mask_of_physid(cpu_id, retmap); 528 ++cpu_id; 529} 530 531/* Mapping from cpu number to logical apicid */ 532static int es7000_cpu_to_logical_apicid(int cpu) 533{ 534#ifdef CONFIG_SMP 535 if (cpu >= nr_cpu_ids) 536 return BAD_APICID; 537 return cpu_2_logical_apicid[cpu]; 538#else 539 return logical_smp_processor_id(); 540#endif 541} 542 543static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap) 544{ 545 /* For clustered we don't have a good way to do this yet - hack */ 546 physids_promote(0xFFL, retmap); 547} 548 549static int es7000_check_phys_apicid_present(int cpu_physical_apicid) 550{ 551 boot_cpu_physical_apicid = read_apic_id(); 552 return 1; 553} 554 555static unsigned int es7000_cpu_mask_to_apicid(const struct cpumask *cpumask) 556{ 557 unsigned int round = 0; 558 int cpu, uninitialized_var(apicid); 559 560 /* 561 * The cpus in the mask must all be on the apic cluster. 562 */ 563 for_each_cpu(cpu, cpumask) { 564 int new_apicid = es7000_cpu_to_logical_apicid(cpu); 565 566 if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) { 567 WARN(1, "Not a valid mask!"); 568 569 return BAD_APICID; 570 } 571 apicid = new_apicid; 572 round++; 573 } 574 return apicid; 575} 576 577static unsigned int 578es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask, 579 const struct cpumask *andmask) 580{ 581 int apicid = es7000_cpu_to_logical_apicid(0); 582 cpumask_var_t cpumask; 583 584 if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC)) 585 return apicid; 586 587 cpumask_and(cpumask, inmask, andmask); 588 cpumask_and(cpumask, cpumask, cpu_online_mask); 589 apicid = es7000_cpu_mask_to_apicid(cpumask); 590 591 free_cpumask_var(cpumask); 592 593 return apicid; 594} 595 596static int es7000_phys_pkg_id(int cpuid_apic, int index_msb) 597{ 598 return cpuid_apic >> index_msb; 599} 600 601static int probe_es7000(void) 602{ 603 /* probed later in mptable/ACPI hooks */ 604 return 0; 605} 606 607static int es7000_mps_ret; 608static int es7000_mps_oem_check(struct mpc_table *mpc, char *oem, 609 char *productid) 610{ 611 int ret = 0; 612 613 if (mpc->oemptr) { 614 struct mpc_oemtable *oem_table = 615 (struct mpc_oemtable *)mpc->oemptr; 616 617 if (!strncmp(oem, "UNISYS", 6)) 618 ret = parse_unisys_oem((char *)oem_table); 619 } 620 621 es7000_mps_ret = ret; 622 623 return ret && !es7000_apic_is_cluster(); 624} 625 626static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem, 627 char *productid) 628{ 629 int ret = es7000_mps_ret; 630 631 return ret && es7000_apic_is_cluster(); 632} 633 634/* We've been warned by a false positive warning.Use __refdata to keep calm. */ 635struct apic __refdata apic_es7000_cluster = { 636 637 .name = "es7000", 638 .probe = probe_es7000, 639 .acpi_madt_oem_check = es7000_acpi_madt_oem_check_cluster, 640 .apic_id_registered = es7000_apic_id_registered, 641 642 .irq_delivery_mode = dest_LowestPrio, 643 /* logical delivery broadcast to all procs: */ 644 .irq_dest_mode = 1, 645 646 .target_cpus = target_cpus_cluster, 647 .disable_esr = 1, 648 .dest_logical = 0, 649 .check_apicid_used = es7000_check_apicid_used, 650 .check_apicid_present = es7000_check_apicid_present, 651 652 .vector_allocation_domain = es7000_vector_allocation_domain, 653 .init_apic_ldr = es7000_init_apic_ldr_cluster, 654 655 .ioapic_phys_id_map = es7000_ioapic_phys_id_map, 656 .setup_apic_routing = es7000_setup_apic_routing, 657 .multi_timer_check = NULL, 658 .apicid_to_node = es7000_apicid_to_node, 659 .cpu_to_logical_apicid = es7000_cpu_to_logical_apicid, 660 .cpu_present_to_apicid = es7000_cpu_present_to_apicid, 661 .apicid_to_cpu_present = es7000_apicid_to_cpu_present, 662 .setup_portio_remap = NULL, 663 .check_phys_apicid_present = es7000_check_phys_apicid_present, 664 .enable_apic_mode = es7000_enable_apic_mode, 665 .phys_pkg_id = es7000_phys_pkg_id, 666 .mps_oem_check = es7000_mps_oem_check_cluster, 667 668 .get_apic_id = es7000_get_apic_id, 669 .set_apic_id = NULL, 670 .apic_id_mask = 0xFF << 24, 671 672 .cpu_mask_to_apicid = es7000_cpu_mask_to_apicid, 673 .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and, 674 675 .send_IPI_mask = es7000_send_IPI_mask, 676 .send_IPI_mask_allbutself = NULL, 677 .send_IPI_allbutself = es7000_send_IPI_allbutself, 678 .send_IPI_all = es7000_send_IPI_all, 679 .send_IPI_self = default_send_IPI_self, 680 681 .wakeup_secondary_cpu = wakeup_secondary_cpu_via_mip, 682 683 .trampoline_phys_low = 0x467, 684 .trampoline_phys_high = 0x469, 685 686 .wait_for_init_deassert = NULL, 687 688 /* Nothing to do for most platforms, since cleared by the INIT cycle: */ 689 .smp_callin_clear_local_apic = NULL, 690 .inquire_remote_apic = default_inquire_remote_apic, 691 692 .read = native_apic_mem_read, 693 .write = native_apic_mem_write, 694 .icr_read = native_apic_icr_read, 695 .icr_write = native_apic_icr_write, 696 .wait_icr_idle = native_apic_wait_icr_idle, 697 .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, 698}; 699 700struct apic __refdata apic_es7000 = { 701 702 .name = "es7000", 703 .probe = probe_es7000, 704 .acpi_madt_oem_check = es7000_acpi_madt_oem_check, 705 .apic_id_registered = es7000_apic_id_registered, 706 707 .irq_delivery_mode = dest_Fixed, 708 /* phys delivery to target CPUs: */ 709 .irq_dest_mode = 0, 710 711 .target_cpus = es7000_target_cpus, 712 .disable_esr = 1, 713 .dest_logical = 0, 714 .check_apicid_used = es7000_check_apicid_used, 715 .check_apicid_present = es7000_check_apicid_present, 716 717 .vector_allocation_domain = es7000_vector_allocation_domain, 718 .init_apic_ldr = es7000_init_apic_ldr, 719 720 .ioapic_phys_id_map = es7000_ioapic_phys_id_map, 721 .setup_apic_routing = es7000_setup_apic_routing, 722 .multi_timer_check = NULL, 723 .apicid_to_node = es7000_apicid_to_node, 724 .cpu_to_logical_apicid = es7000_cpu_to_logical_apicid, 725 .cpu_present_to_apicid = es7000_cpu_present_to_apicid, 726 .apicid_to_cpu_present = es7000_apicid_to_cpu_present, 727 .setup_portio_remap = NULL, 728 .check_phys_apicid_present = es7000_check_phys_apicid_present, 729 .enable_apic_mode = es7000_enable_apic_mode, 730 .phys_pkg_id = es7000_phys_pkg_id, 731 .mps_oem_check = es7000_mps_oem_check, 732 733 .get_apic_id = es7000_get_apic_id, 734 .set_apic_id = NULL, 735 .apic_id_mask = 0xFF << 24, 736 737 .cpu_mask_to_apicid = es7000_cpu_mask_to_apicid, 738 .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and, 739 740 .send_IPI_mask = es7000_send_IPI_mask, 741 .send_IPI_mask_allbutself = NULL, 742 .send_IPI_allbutself = es7000_send_IPI_allbutself, 743 .send_IPI_all = es7000_send_IPI_all, 744 .send_IPI_self = default_send_IPI_self, 745 746 .trampoline_phys_low = 0x467, 747 .trampoline_phys_high = 0x469, 748 749 .wait_for_init_deassert = es7000_wait_for_init_deassert, 750 751 /* Nothing to do for most platforms, since cleared by the INIT cycle: */ 752 .smp_callin_clear_local_apic = NULL, 753 .inquire_remote_apic = default_inquire_remote_apic, 754 755 .read = native_apic_mem_read, 756 .write = native_apic_mem_write, 757 .icr_read = native_apic_icr_read, 758 .icr_write = native_apic_icr_write, 759 .wait_icr_idle = native_apic_wait_icr_idle, 760 .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, 761}; 762