18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * acpi_processor.c - ACPI processor enumeration support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> 88c2ecf20Sopenharmony_ci * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> 98c2ecf20Sopenharmony_ci * Copyright (C) 2013, Intel Corporation 108c2ecf20Sopenharmony_ci * Rafael J. Wysocki <rafael.j.wysocki@intel.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/acpi.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <acpi/processor.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/cpu.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "internal.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define _COMPONENT ACPI_PROCESSOR_COMPONENT 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciACPI_MODULE_NAME("processor"); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciDEFINE_PER_CPU(struct acpi_processor *, processors); 308c2ecf20Sopenharmony_ciEXPORT_PER_CPU_SYMBOL(processors); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 338c2ecf20Sopenharmony_ci Errata Handling 348c2ecf20Sopenharmony_ci -------------------------------------------------------------------------- */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct acpi_processor_errata errata __read_mostly; 378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(errata); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int acpi_processor_errata_piix4(struct pci_dev *dev) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci u8 value1 = 0; 428c2ecf20Sopenharmony_ci u8 value2 = 0; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!dev) 468c2ecf20Sopenharmony_ci return -EINVAL; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * Note that 'dev' references the PIIX4 ACPI Controller. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci switch (dev->revision) { 538c2ecf20Sopenharmony_ci case 0: 548c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n")); 558c2ecf20Sopenharmony_ci break; 568c2ecf20Sopenharmony_ci case 1: 578c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n")); 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci case 2: 608c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n")); 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case 3: 638c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n")); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci default: 668c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n")); 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci switch (dev->revision) { 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci case 0: /* PIIX4 A-step */ 738c2ecf20Sopenharmony_ci case 1: /* PIIX4 B-step */ 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * See specification changes #13 ("Manual Throttle Duty Cycle") 768c2ecf20Sopenharmony_ci * and #14 ("Enabling and Disabling Manual Throttle"), plus 778c2ecf20Sopenharmony_ci * erratum #5 ("STPCLK# Deassertion Time") from the January 788c2ecf20Sopenharmony_ci * 2002 PIIX4 specification update. Applies to only older 798c2ecf20Sopenharmony_ci * PIIX4 models. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci errata.piix4.throttle = 1; 828c2ecf20Sopenharmony_ci fallthrough; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci case 2: /* PIIX4E */ 858c2ecf20Sopenharmony_ci case 3: /* PIIX4M */ 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA 888c2ecf20Sopenharmony_ci * Livelock") from the January 2002 PIIX4 specification update. 898c2ecf20Sopenharmony_ci * Applies to all PIIX4 models. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* 938c2ecf20Sopenharmony_ci * BM-IDE 948c2ecf20Sopenharmony_ci * ------ 958c2ecf20Sopenharmony_ci * Find the PIIX4 IDE Controller and get the Bus Master IDE 968c2ecf20Sopenharmony_ci * Status register address. We'll use this later to read 978c2ecf20Sopenharmony_ci * each IDE controller's DMA status to make sure we catch all 988c2ecf20Sopenharmony_ci * DMA activity. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, 1018c2ecf20Sopenharmony_ci PCI_DEVICE_ID_INTEL_82371AB, 1028c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, NULL); 1038c2ecf20Sopenharmony_ci if (dev) { 1048c2ecf20Sopenharmony_ci errata.piix4.bmisx = pci_resource_start(dev, 4); 1058c2ecf20Sopenharmony_ci pci_dev_put(dev); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* 1098c2ecf20Sopenharmony_ci * Type-F DMA 1108c2ecf20Sopenharmony_ci * ---------- 1118c2ecf20Sopenharmony_ci * Find the PIIX4 ISA Controller and read the Motherboard 1128c2ecf20Sopenharmony_ci * DMA controller's status to see if Type-F (Fast) DMA mode 1138c2ecf20Sopenharmony_ci * is enabled (bit 7) on either channel. Note that we'll 1148c2ecf20Sopenharmony_ci * disable C3 support if this is enabled, as some legacy 1158c2ecf20Sopenharmony_ci * devices won't operate well if fast DMA is disabled. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, 1188c2ecf20Sopenharmony_ci PCI_DEVICE_ID_INTEL_82371AB_0, 1198c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, NULL); 1208c2ecf20Sopenharmony_ci if (dev) { 1218c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x76, &value1); 1228c2ecf20Sopenharmony_ci pci_read_config_byte(dev, 0x77, &value2); 1238c2ecf20Sopenharmony_ci if ((value1 & 0x80) || (value2 & 0x80)) 1248c2ecf20Sopenharmony_ci errata.piix4.fdma = 1; 1258c2ecf20Sopenharmony_ci pci_dev_put(dev); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (errata.piix4.bmisx) 1328c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1338c2ecf20Sopenharmony_ci "Bus master activity detection (BM-IDE) erratum enabled\n")); 1348c2ecf20Sopenharmony_ci if (errata.piix4.fdma) 1358c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1368c2ecf20Sopenharmony_ci "Type-F DMA livelock erratum (C3 disabled)\n")); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int acpi_processor_errata(void) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci int result = 0; 1448c2ecf20Sopenharmony_ci struct pci_dev *dev = NULL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * PIIX4 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, 1508c2ecf20Sopenharmony_ci PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, 1518c2ecf20Sopenharmony_ci PCI_ANY_ID, NULL); 1528c2ecf20Sopenharmony_ci if (dev) { 1538c2ecf20Sopenharmony_ci result = acpi_processor_errata_piix4(dev); 1548c2ecf20Sopenharmony_ci pci_dev_put(dev); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return result; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 1618c2ecf20Sopenharmony_ci Initialization 1628c2ecf20Sopenharmony_ci -------------------------------------------------------------------------- */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_HOTPLUG_CPU 1658c2ecf20Sopenharmony_ciint __weak acpi_map_cpu(acpi_handle handle, 1668c2ecf20Sopenharmony_ci phys_cpuid_t physid, u32 acpi_id, int *pcpu) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci return -ENODEV; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint __weak acpi_unmap_cpu(int cpu) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return -ENODEV; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciint __weak arch_register_cpu(int cpu) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return -ENODEV; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_civoid __weak arch_unregister_cpu(int cpu) {} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int acpi_processor_hotadd_init(struct acpi_processor *pr) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci unsigned long long sta; 1868c2ecf20Sopenharmony_ci acpi_status status; 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (invalid_phys_cpuid(pr->phys_id)) 1908c2ecf20Sopenharmony_ci return -ENODEV; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta); 1938c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) 1948c2ecf20Sopenharmony_ci return -ENODEV; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci cpu_maps_update_begin(); 1978c2ecf20Sopenharmony_ci cpu_hotplug_begin(); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci ret = acpi_map_cpu(pr->handle, pr->phys_id, pr->acpi_id, &pr->id); 2008c2ecf20Sopenharmony_ci if (ret) 2018c2ecf20Sopenharmony_ci goto out; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = arch_register_cpu(pr->id); 2048c2ecf20Sopenharmony_ci if (ret) { 2058c2ecf20Sopenharmony_ci acpi_unmap_cpu(pr->id); 2068c2ecf20Sopenharmony_ci goto out; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* 2108c2ecf20Sopenharmony_ci * CPU got hot-added, but cpu_data is not initialized yet. Set a flag 2118c2ecf20Sopenharmony_ci * to delay cpu_idle/throttling initialization and do it when the CPU 2128c2ecf20Sopenharmony_ci * gets online for the first time. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci pr_info("CPU%d has been hot-added\n", pr->id); 2158c2ecf20Sopenharmony_ci pr->flags.need_hotplug_init = 1; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciout: 2188c2ecf20Sopenharmony_ci cpu_hotplug_done(); 2198c2ecf20Sopenharmony_ci cpu_maps_update_done(); 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci#else 2238c2ecf20Sopenharmony_cistatic inline int acpi_processor_hotadd_init(struct acpi_processor *pr) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci return -ENODEV; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI_HOTPLUG_CPU */ 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int acpi_processor_get_info(struct acpi_device *device) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci union acpi_object object = { 0 }; 2328c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; 2338c2ecf20Sopenharmony_ci struct acpi_processor *pr = acpi_driver_data(device); 2348c2ecf20Sopenharmony_ci int device_declaration = 0; 2358c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 2368c2ecf20Sopenharmony_ci static int cpu0_initialized; 2378c2ecf20Sopenharmony_ci unsigned long long value; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci acpi_processor_errata(); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * Check to see if we have bus mastering arbitration control. This 2438c2ecf20Sopenharmony_ci * is required for proper C3 usage (to maintain cache coherency). 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { 2468c2ecf20Sopenharmony_ci pr->flags.bm_control = 1; 2478c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2488c2ecf20Sopenharmony_ci "Bus mastering arbitration control present\n")); 2498c2ecf20Sopenharmony_ci } else 2508c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2518c2ecf20Sopenharmony_ci "No bus mastering arbitration control\n")); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { 2548c2ecf20Sopenharmony_ci /* Declared with "Processor" statement; match ProcessorID */ 2558c2ecf20Sopenharmony_ci status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); 2568c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 2578c2ecf20Sopenharmony_ci dev_err(&device->dev, 2588c2ecf20Sopenharmony_ci "Failed to evaluate processor object (0x%x)\n", 2598c2ecf20Sopenharmony_ci status); 2608c2ecf20Sopenharmony_ci return -ENODEV; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci pr->acpi_id = object.processor.proc_id; 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * Declared with "Device" statement; match _UID. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, 2698c2ecf20Sopenharmony_ci NULL, &value); 2708c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 2718c2ecf20Sopenharmony_ci dev_err(&device->dev, 2728c2ecf20Sopenharmony_ci "Failed to evaluate processor _UID (0x%x)\n", 2738c2ecf20Sopenharmony_ci status); 2748c2ecf20Sopenharmony_ci return -ENODEV; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci device_declaration = 1; 2778c2ecf20Sopenharmony_ci pr->acpi_id = value; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (acpi_duplicate_processor_id(pr->acpi_id)) { 2818c2ecf20Sopenharmony_ci if (pr->acpi_id == 0xff) 2828c2ecf20Sopenharmony_ci dev_info_once(&device->dev, 2838c2ecf20Sopenharmony_ci "Entry not well-defined, consider updating BIOS\n"); 2848c2ecf20Sopenharmony_ci else 2858c2ecf20Sopenharmony_ci dev_err(&device->dev, 2868c2ecf20Sopenharmony_ci "Failed to get unique processor _UID (0x%x)\n", 2878c2ecf20Sopenharmony_ci pr->acpi_id); 2888c2ecf20Sopenharmony_ci return -ENODEV; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci pr->phys_id = acpi_get_phys_id(pr->handle, device_declaration, 2928c2ecf20Sopenharmony_ci pr->acpi_id); 2938c2ecf20Sopenharmony_ci if (invalid_phys_cpuid(pr->phys_id)) 2948c2ecf20Sopenharmony_ci acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci pr->id = acpi_map_cpuid(pr->phys_id, pr->acpi_id); 2978c2ecf20Sopenharmony_ci if (!cpu0_initialized && !acpi_has_cpu_in_madt()) { 2988c2ecf20Sopenharmony_ci cpu0_initialized = 1; 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * Handle UP system running SMP kernel, with no CPU 3018c2ecf20Sopenharmony_ci * entry in MADT 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci if (invalid_logical_cpuid(pr->id) && (num_online_cpus() == 1)) 3048c2ecf20Sopenharmony_ci pr->id = 0; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * Extra Processor objects may be enumerated on MP systems with 3098c2ecf20Sopenharmony_ci * less than the max # of CPUs. They should be ignored _iff 3108c2ecf20Sopenharmony_ci * they are physically not present. 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * NOTE: Even if the processor has a cpuid, it may not be present 3138c2ecf20Sopenharmony_ci * because cpuid <-> apicid mapping is persistent now. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (invalid_logical_cpuid(pr->id) || !cpu_present(pr->id)) { 3168c2ecf20Sopenharmony_ci int ret = acpi_processor_hotadd_init(pr); 3178c2ecf20Sopenharmony_ci if (ret) 3188c2ecf20Sopenharmony_ci return ret; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* 3228c2ecf20Sopenharmony_ci * On some boxes several processors use the same processor bus id. 3238c2ecf20Sopenharmony_ci * But they are located in different scope. For example: 3248c2ecf20Sopenharmony_ci * \_SB.SCK0.CPU0 3258c2ecf20Sopenharmony_ci * \_SB.SCK1.CPU0 3268c2ecf20Sopenharmony_ci * Rename the processor device bus id. And the new bus id will be 3278c2ecf20Sopenharmony_ci * generated as the following format: 3288c2ecf20Sopenharmony_ci * CPU+CPU ID. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci sprintf(acpi_device_bid(device), "CPU%X", pr->id); 3318c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, 3328c2ecf20Sopenharmony_ci pr->acpi_id)); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!object.processor.pblk_address) 3358c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); 3368c2ecf20Sopenharmony_ci else if (object.processor.pblk_length != 6) 3378c2ecf20Sopenharmony_ci dev_err(&device->dev, "Invalid PBLK length [%d]\n", 3388c2ecf20Sopenharmony_ci object.processor.pblk_length); 3398c2ecf20Sopenharmony_ci else { 3408c2ecf20Sopenharmony_ci pr->throttling.address = object.processor.pblk_address; 3418c2ecf20Sopenharmony_ci pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset; 3428c2ecf20Sopenharmony_ci pr->throttling.duty_width = acpi_gbl_FADT.duty_width; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci pr->pblk = object.processor.pblk_address; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * If ACPI describes a slot number for this CPU, we can use it to 3498c2ecf20Sopenharmony_ci * ensure we get the right value in the "physical id" field 3508c2ecf20Sopenharmony_ci * of /proc/cpuinfo 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(pr->handle, "_SUN", NULL, &value); 3538c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 3548c2ecf20Sopenharmony_ci arch_fix_phys_package_id(pr->id, value); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* 3608c2ecf20Sopenharmony_ci * Do not put anything in here which needs the core to be online. 3618c2ecf20Sopenharmony_ci * For example MSR access or setting up things which check for cpuinfo_x86 3628c2ecf20Sopenharmony_ci * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc. 3638c2ecf20Sopenharmony_ci * Such things have to be put in and set up by the processor driver's .probe(). 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(void *, processor_device_array); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic int acpi_processor_add(struct acpi_device *device, 3688c2ecf20Sopenharmony_ci const struct acpi_device_id *id) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct acpi_processor *pr; 3718c2ecf20Sopenharmony_ci struct device *dev; 3728c2ecf20Sopenharmony_ci int result = 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); 3758c2ecf20Sopenharmony_ci if (!pr) 3768c2ecf20Sopenharmony_ci return -ENOMEM; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { 3798c2ecf20Sopenharmony_ci result = -ENOMEM; 3808c2ecf20Sopenharmony_ci goto err_free_pr; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci pr->handle = device->handle; 3848c2ecf20Sopenharmony_ci strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); 3858c2ecf20Sopenharmony_ci strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); 3868c2ecf20Sopenharmony_ci device->driver_data = pr; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci result = acpi_processor_get_info(device); 3898c2ecf20Sopenharmony_ci if (result) /* Processor is not physically present or unavailable */ 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci BUG_ON(pr->id >= nr_cpu_ids); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * Buggy BIOS check. 3968c2ecf20Sopenharmony_ci * ACPI id of processors can be reported wrongly by the BIOS. 3978c2ecf20Sopenharmony_ci * Don't trust it blindly 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ci if (per_cpu(processor_device_array, pr->id) != NULL && 4008c2ecf20Sopenharmony_ci per_cpu(processor_device_array, pr->id) != device) { 4018c2ecf20Sopenharmony_ci dev_warn(&device->dev, 4028c2ecf20Sopenharmony_ci "BIOS reported wrong ACPI id %d for the processor\n", 4038c2ecf20Sopenharmony_ci pr->id); 4048c2ecf20Sopenharmony_ci /* Give up, but do not abort the namespace scan. */ 4058c2ecf20Sopenharmony_ci goto err; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * processor_device_array is not cleared on errors to allow buggy BIOS 4098c2ecf20Sopenharmony_ci * checks. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci per_cpu(processor_device_array, pr->id) = device; 4128c2ecf20Sopenharmony_ci per_cpu(processors, pr->id) = pr; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci dev = get_cpu_device(pr->id); 4158c2ecf20Sopenharmony_ci if (!dev) { 4168c2ecf20Sopenharmony_ci result = -ENODEV; 4178c2ecf20Sopenharmony_ci goto err; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci result = acpi_bind_one(dev, device); 4218c2ecf20Sopenharmony_ci if (result) 4228c2ecf20Sopenharmony_ci goto err; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci pr->dev = dev; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Trigger the processor driver's .probe() if present. */ 4278c2ecf20Sopenharmony_ci if (device_attach(dev) >= 0) 4288c2ecf20Sopenharmony_ci return 1; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci dev_err(dev, "Processor driver could not be attached\n"); 4318c2ecf20Sopenharmony_ci acpi_unbind_one(dev); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci err: 4348c2ecf20Sopenharmony_ci free_cpumask_var(pr->throttling.shared_cpu_map); 4358c2ecf20Sopenharmony_ci device->driver_data = NULL; 4368c2ecf20Sopenharmony_ci per_cpu(processors, pr->id) = NULL; 4378c2ecf20Sopenharmony_ci err_free_pr: 4388c2ecf20Sopenharmony_ci kfree(pr); 4398c2ecf20Sopenharmony_ci return result; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_HOTPLUG_CPU 4438c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 4448c2ecf20Sopenharmony_ci Removal 4458c2ecf20Sopenharmony_ci -------------------------------------------------------------------------- */ 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void acpi_processor_remove(struct acpi_device *device) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct acpi_processor *pr; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!device || !acpi_driver_data(device)) 4528c2ecf20Sopenharmony_ci return; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci pr = acpi_driver_data(device); 4558c2ecf20Sopenharmony_ci if (pr->id >= nr_cpu_ids) 4568c2ecf20Sopenharmony_ci goto out; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* 4598c2ecf20Sopenharmony_ci * The only reason why we ever get here is CPU hot-removal. The CPU is 4608c2ecf20Sopenharmony_ci * already offline and the ACPI device removal locking prevents it from 4618c2ecf20Sopenharmony_ci * being put back online at this point. 4628c2ecf20Sopenharmony_ci * 4638c2ecf20Sopenharmony_ci * Unbind the driver from the processor device and detach it from the 4648c2ecf20Sopenharmony_ci * ACPI companion object. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci device_release_driver(pr->dev); 4678c2ecf20Sopenharmony_ci acpi_unbind_one(pr->dev); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Clean up. */ 4708c2ecf20Sopenharmony_ci per_cpu(processor_device_array, pr->id) = NULL; 4718c2ecf20Sopenharmony_ci per_cpu(processors, pr->id) = NULL; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci cpu_maps_update_begin(); 4748c2ecf20Sopenharmony_ci cpu_hotplug_begin(); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Remove the CPU. */ 4778c2ecf20Sopenharmony_ci arch_unregister_cpu(pr->id); 4788c2ecf20Sopenharmony_ci acpi_unmap_cpu(pr->id); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci cpu_hotplug_done(); 4818c2ecf20Sopenharmony_ci cpu_maps_update_done(); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci try_offline_node(cpu_to_node(pr->id)); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci out: 4868c2ecf20Sopenharmony_ci free_cpumask_var(pr->throttling.shared_cpu_map); 4878c2ecf20Sopenharmony_ci kfree(pr); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI_HOTPLUG_CPU */ 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci#ifdef CONFIG_X86 4928c2ecf20Sopenharmony_cistatic bool acpi_hwp_native_thermal_lvt_set; 4938c2ecf20Sopenharmony_cistatic acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, 4948c2ecf20Sopenharmony_ci u32 lvl, 4958c2ecf20Sopenharmony_ci void *context, 4968c2ecf20Sopenharmony_ci void **rv) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; 4998c2ecf20Sopenharmony_ci u32 capbuf[2]; 5008c2ecf20Sopenharmony_ci struct acpi_osc_context osc_context = { 5018c2ecf20Sopenharmony_ci .uuid_str = sb_uuid_str, 5028c2ecf20Sopenharmony_ci .rev = 1, 5038c2ecf20Sopenharmony_ci .cap.length = 8, 5048c2ecf20Sopenharmony_ci .cap.pointer = capbuf, 5058c2ecf20Sopenharmony_ci }; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (acpi_hwp_native_thermal_lvt_set) 5088c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci capbuf[0] = 0x0000; 5118c2ecf20Sopenharmony_ci capbuf[1] = 0x1000; /* set bit 12 */ 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) { 5148c2ecf20Sopenharmony_ci if (osc_context.ret.pointer && osc_context.ret.length > 1) { 5158c2ecf20Sopenharmony_ci u32 *capbuf_ret = osc_context.ret.pointer; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (capbuf_ret[1] & 0x1000) { 5188c2ecf20Sopenharmony_ci acpi_handle_info(handle, 5198c2ecf20Sopenharmony_ci "_OSC native thermal LVT Acked\n"); 5208c2ecf20Sopenharmony_ci acpi_hwp_native_thermal_lvt_set = true; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci kfree(osc_context.ret.pointer); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return AE_OK; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_civoid __init acpi_early_processor_osc(void) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_HWP)) { 5328c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 5338c2ecf20Sopenharmony_ci ACPI_UINT32_MAX, 5348c2ecf20Sopenharmony_ci acpi_hwp_native_thermal_lvt_osc, 5358c2ecf20Sopenharmony_ci NULL, NULL, NULL); 5368c2ecf20Sopenharmony_ci acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, 5378c2ecf20Sopenharmony_ci acpi_hwp_native_thermal_lvt_osc, 5388c2ecf20Sopenharmony_ci NULL, NULL); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci#endif 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* 5448c2ecf20Sopenharmony_ci * The following ACPI IDs are known to be suitable for representing as 5458c2ecf20Sopenharmony_ci * processor devices. 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_cistatic const struct acpi_device_id processor_device_ids[] = { 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci { ACPI_PROCESSOR_OBJECT_HID, }, 5508c2ecf20Sopenharmony_ci { ACPI_PROCESSOR_DEVICE_HID, }, 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci { } 5538c2ecf20Sopenharmony_ci}; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic struct acpi_scan_handler processor_handler = { 5568c2ecf20Sopenharmony_ci .ids = processor_device_ids, 5578c2ecf20Sopenharmony_ci .attach = acpi_processor_add, 5588c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_HOTPLUG_CPU 5598c2ecf20Sopenharmony_ci .detach = acpi_processor_remove, 5608c2ecf20Sopenharmony_ci#endif 5618c2ecf20Sopenharmony_ci .hotplug = { 5628c2ecf20Sopenharmony_ci .enabled = true, 5638c2ecf20Sopenharmony_ci }, 5648c2ecf20Sopenharmony_ci}; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int acpi_processor_container_attach(struct acpi_device *dev, 5678c2ecf20Sopenharmony_ci const struct acpi_device_id *id) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci return 1; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic const struct acpi_device_id processor_container_ids[] = { 5738c2ecf20Sopenharmony_ci { ACPI_PROCESSOR_CONTAINER_HID, }, 5748c2ecf20Sopenharmony_ci { } 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic struct acpi_scan_handler processor_container_handler = { 5788c2ecf20Sopenharmony_ci .ids = processor_container_ids, 5798c2ecf20Sopenharmony_ci .attach = acpi_processor_container_attach, 5808c2ecf20Sopenharmony_ci}; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/* The number of the unique processor IDs */ 5838c2ecf20Sopenharmony_cistatic int nr_unique_ids __initdata; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/* The number of the duplicate processor IDs */ 5868c2ecf20Sopenharmony_cistatic int nr_duplicate_ids; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/* Used to store the unique processor IDs */ 5898c2ecf20Sopenharmony_cistatic int unique_processor_ids[] __initdata = { 5908c2ecf20Sopenharmony_ci [0 ... NR_CPUS - 1] = -1, 5918c2ecf20Sopenharmony_ci}; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* Used to store the duplicate processor IDs */ 5948c2ecf20Sopenharmony_cistatic int duplicate_processor_ids[] = { 5958c2ecf20Sopenharmony_ci [0 ... NR_CPUS - 1] = -1, 5968c2ecf20Sopenharmony_ci}; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic void __init processor_validated_ids_update(int proc_id) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci int i; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (nr_unique_ids == NR_CPUS||nr_duplicate_ids == NR_CPUS) 6038c2ecf20Sopenharmony_ci return; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * Firstly, compare the proc_id with duplicate IDs, if the proc_id is 6078c2ecf20Sopenharmony_ci * already in the IDs, do nothing. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci for (i = 0; i < nr_duplicate_ids; i++) { 6108c2ecf20Sopenharmony_ci if (duplicate_processor_ids[i] == proc_id) 6118c2ecf20Sopenharmony_ci return; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * Secondly, compare the proc_id with unique IDs, if the proc_id is in 6168c2ecf20Sopenharmony_ci * the IDs, put it in the duplicate IDs. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci for (i = 0; i < nr_unique_ids; i++) { 6198c2ecf20Sopenharmony_ci if (unique_processor_ids[i] == proc_id) { 6208c2ecf20Sopenharmony_ci duplicate_processor_ids[nr_duplicate_ids] = proc_id; 6218c2ecf20Sopenharmony_ci nr_duplicate_ids++; 6228c2ecf20Sopenharmony_ci return; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* 6278c2ecf20Sopenharmony_ci * Lastly, the proc_id is a unique ID, put it in the unique IDs. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci unique_processor_ids[nr_unique_ids] = proc_id; 6308c2ecf20Sopenharmony_ci nr_unique_ids++; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic acpi_status __init acpi_processor_ids_walk(acpi_handle handle, 6348c2ecf20Sopenharmony_ci u32 lvl, 6358c2ecf20Sopenharmony_ci void *context, 6368c2ecf20Sopenharmony_ci void **rv) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci acpi_status status; 6398c2ecf20Sopenharmony_ci acpi_object_type acpi_type; 6408c2ecf20Sopenharmony_ci unsigned long long uid; 6418c2ecf20Sopenharmony_ci union acpi_object object = { 0 }; 6428c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci status = acpi_get_type(handle, &acpi_type); 6458c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 6468c2ecf20Sopenharmony_ci return status; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (acpi_type) { 6498c2ecf20Sopenharmony_ci case ACPI_TYPE_PROCESSOR: 6508c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, NULL, NULL, &buffer); 6518c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 6528c2ecf20Sopenharmony_ci goto err; 6538c2ecf20Sopenharmony_ci uid = object.processor.proc_id; 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci case ACPI_TYPE_DEVICE: 6578c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "_UID", NULL, &uid); 6588c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 6598c2ecf20Sopenharmony_ci goto err; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci default: 6628c2ecf20Sopenharmony_ci goto err; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci processor_validated_ids_update(uid); 6668c2ecf20Sopenharmony_ci return AE_OK; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cierr: 6698c2ecf20Sopenharmony_ci /* Exit on error, but don't abort the namespace walk */ 6708c2ecf20Sopenharmony_ci acpi_handle_info(handle, "Invalid processor object\n"); 6718c2ecf20Sopenharmony_ci return AE_OK; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic void __init acpi_processor_check_duplicates(void) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci /* check the correctness for all processors in ACPI namespace */ 6788c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 6798c2ecf20Sopenharmony_ci ACPI_UINT32_MAX, 6808c2ecf20Sopenharmony_ci acpi_processor_ids_walk, 6818c2ecf20Sopenharmony_ci NULL, NULL, NULL); 6828c2ecf20Sopenharmony_ci acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_ids_walk, 6838c2ecf20Sopenharmony_ci NULL, NULL); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cibool acpi_duplicate_processor_id(int proc_id) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci int i; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * compare the proc_id with duplicate IDs, if the proc_id is already 6928c2ecf20Sopenharmony_ci * in the duplicate IDs, return true, otherwise, return false. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci for (i = 0; i < nr_duplicate_ids; i++) { 6958c2ecf20Sopenharmony_ci if (duplicate_processor_ids[i] == proc_id) 6968c2ecf20Sopenharmony_ci return true; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci return false; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_civoid __init acpi_processor_init(void) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci acpi_processor_check_duplicates(); 7048c2ecf20Sopenharmony_ci acpi_scan_add_handler_with_hotplug(&processor_handler, "processor"); 7058c2ecf20Sopenharmony_ci acpi_scan_add_handler(&processor_container_handler); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_PROCESSOR_CSTATE 7098c2ecf20Sopenharmony_ci/** 7108c2ecf20Sopenharmony_ci * acpi_processor_claim_cst_control - Request _CST control from the platform. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_cibool acpi_processor_claim_cst_control(void) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci static bool cst_control_claimed; 7158c2ecf20Sopenharmony_ci acpi_status status; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (!acpi_gbl_FADT.cst_control || cst_control_claimed) 7188c2ecf20Sopenharmony_ci return true; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci status = acpi_os_write_port(acpi_gbl_FADT.smi_command, 7218c2ecf20Sopenharmony_ci acpi_gbl_FADT.cst_control, 8); 7228c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 7238c2ecf20Sopenharmony_ci pr_warn("ACPI: Failed to claim processor _CST control\n"); 7248c2ecf20Sopenharmony_ci return false; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci cst_control_claimed = true; 7288c2ecf20Sopenharmony_ci return true; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_processor_claim_cst_control); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/** 7338c2ecf20Sopenharmony_ci * acpi_processor_evaluate_cst - Evaluate the processor _CST control method. 7348c2ecf20Sopenharmony_ci * @handle: ACPI handle of the processor object containing the _CST. 7358c2ecf20Sopenharmony_ci * @cpu: The numeric ID of the target CPU. 7368c2ecf20Sopenharmony_ci * @info: Object write the C-states information into. 7378c2ecf20Sopenharmony_ci * 7388c2ecf20Sopenharmony_ci * Extract the C-state information for the given CPU from the output of the _CST 7398c2ecf20Sopenharmony_ci * control method under the corresponding ACPI processor object (or processor 7408c2ecf20Sopenharmony_ci * device object) and populate @info with it. 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * If any ACPI_ADR_SPACE_FIXED_HARDWARE C-states are found, invoke 7438c2ecf20Sopenharmony_ci * acpi_processor_ffh_cstate_probe() to verify them and update the 7448c2ecf20Sopenharmony_ci * cpu_cstate_entry data for @cpu. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ciint acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, 7478c2ecf20Sopenharmony_ci struct acpi_processor_power *info) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 7508c2ecf20Sopenharmony_ci union acpi_object *cst; 7518c2ecf20Sopenharmony_ci acpi_status status; 7528c2ecf20Sopenharmony_ci u64 count; 7538c2ecf20Sopenharmony_ci int last_index = 0; 7548c2ecf20Sopenharmony_ci int i, ret = 0; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "_CST", NULL, &buffer); 7578c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 7588c2ecf20Sopenharmony_ci acpi_handle_debug(handle, "No _CST\n"); 7598c2ecf20Sopenharmony_ci return -ENODEV; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci cst = buffer.pointer; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* There must be at least 2 elements. */ 7658c2ecf20Sopenharmony_ci if (!cst || cst->type != ACPI_TYPE_PACKAGE || cst->package.count < 2) { 7668c2ecf20Sopenharmony_ci acpi_handle_warn(handle, "Invalid _CST output\n"); 7678c2ecf20Sopenharmony_ci ret = -EFAULT; 7688c2ecf20Sopenharmony_ci goto end; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci count = cst->package.elements[0].integer.value; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* Validate the number of C-states. */ 7748c2ecf20Sopenharmony_ci if (count < 1 || count != cst->package.count - 1) { 7758c2ecf20Sopenharmony_ci acpi_handle_warn(handle, "Inconsistent _CST data\n"); 7768c2ecf20Sopenharmony_ci ret = -EFAULT; 7778c2ecf20Sopenharmony_ci goto end; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci for (i = 1; i <= count; i++) { 7818c2ecf20Sopenharmony_ci union acpi_object *element; 7828c2ecf20Sopenharmony_ci union acpi_object *obj; 7838c2ecf20Sopenharmony_ci struct acpi_power_register *reg; 7848c2ecf20Sopenharmony_ci struct acpi_processor_cx cx; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* 7878c2ecf20Sopenharmony_ci * If there is not enough space for all C-states, skip the 7888c2ecf20Sopenharmony_ci * excess ones and log a warning. 7898c2ecf20Sopenharmony_ci */ 7908c2ecf20Sopenharmony_ci if (last_index >= ACPI_PROCESSOR_MAX_POWER - 1) { 7918c2ecf20Sopenharmony_ci acpi_handle_warn(handle, 7928c2ecf20Sopenharmony_ci "No room for more idle states (limit: %d)\n", 7938c2ecf20Sopenharmony_ci ACPI_PROCESSOR_MAX_POWER - 1); 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci memset(&cx, 0, sizeof(cx)); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci element = &cst->package.elements[i]; 8008c2ecf20Sopenharmony_ci if (element->type != ACPI_TYPE_PACKAGE) { 8018c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d type(%x) is not package, skip...\n", 8028c2ecf20Sopenharmony_ci i, element->type); 8038c2ecf20Sopenharmony_ci continue; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (element->package.count != 4) { 8078c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d package count(%d) is not 4, skip...\n", 8088c2ecf20Sopenharmony_ci i, element->package.count); 8098c2ecf20Sopenharmony_ci continue; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci obj = &element->package.elements[0]; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_BUFFER) { 8158c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d package element[0] type(%x) is not buffer, skip...\n", 8168c2ecf20Sopenharmony_ci i, obj->type); 8178c2ecf20Sopenharmony_ci continue; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci reg = (struct acpi_power_register *)obj->buffer.pointer; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci obj = &element->package.elements[1]; 8238c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_INTEGER) { 8248c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C[%d] package element[1] type(%x) is not integer, skip...\n", 8258c2ecf20Sopenharmony_ci i, obj->type); 8268c2ecf20Sopenharmony_ci continue; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci cx.type = obj->integer.value; 8308c2ecf20Sopenharmony_ci /* 8318c2ecf20Sopenharmony_ci * There are known cases in which the _CST output does not 8328c2ecf20Sopenharmony_ci * contain C1, so if the type of the first state found is not 8338c2ecf20Sopenharmony_ci * C1, leave an empty slot for C1 to be filled in later. 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_ci if (i == 1 && cx.type != ACPI_STATE_C1) 8368c2ecf20Sopenharmony_ci last_index = 1; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci cx.address = reg->address; 8398c2ecf20Sopenharmony_ci cx.index = last_index + 1; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { 8428c2ecf20Sopenharmony_ci if (!acpi_processor_ffh_cstate_probe(cpu, &cx, reg)) { 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * In the majority of cases _CST describes C1 as 8458c2ecf20Sopenharmony_ci * a FIXED_HARDWARE C-state, but if the command 8468c2ecf20Sopenharmony_ci * line forbids using MWAIT, use CSTATE_HALT for 8478c2ecf20Sopenharmony_ci * C1 regardless. 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci if (cx.type == ACPI_STATE_C1 && 8508c2ecf20Sopenharmony_ci boot_option_idle_override == IDLE_NOMWAIT) { 8518c2ecf20Sopenharmony_ci cx.entry_method = ACPI_CSTATE_HALT; 8528c2ecf20Sopenharmony_ci snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT"); 8538c2ecf20Sopenharmony_ci } else { 8548c2ecf20Sopenharmony_ci cx.entry_method = ACPI_CSTATE_FFH; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci } else if (cx.type == ACPI_STATE_C1) { 8578c2ecf20Sopenharmony_ci /* 8588c2ecf20Sopenharmony_ci * In the special case of C1, FIXED_HARDWARE can 8598c2ecf20Sopenharmony_ci * be handled by executing the HLT instruction. 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_ci cx.entry_method = ACPI_CSTATE_HALT; 8628c2ecf20Sopenharmony_ci snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT"); 8638c2ecf20Sopenharmony_ci } else { 8648c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d declares FIXED_HARDWARE C-state but not supported in hardware, skip...\n", 8658c2ecf20Sopenharmony_ci i); 8668c2ecf20Sopenharmony_ci continue; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci } else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { 8698c2ecf20Sopenharmony_ci cx.entry_method = ACPI_CSTATE_SYSTEMIO; 8708c2ecf20Sopenharmony_ci snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x", 8718c2ecf20Sopenharmony_ci cx.address); 8728c2ecf20Sopenharmony_ci } else { 8738c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d space_id(%x) neither FIXED_HARDWARE nor SYSTEM_IO, skip...\n", 8748c2ecf20Sopenharmony_ci i, reg->space_id); 8758c2ecf20Sopenharmony_ci continue; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (cx.type == ACPI_STATE_C1) 8798c2ecf20Sopenharmony_ci cx.valid = 1; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci obj = &element->package.elements[2]; 8828c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_INTEGER) { 8838c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d package element[2] type(%x) not integer, skip...\n", 8848c2ecf20Sopenharmony_ci i, obj->type); 8858c2ecf20Sopenharmony_ci continue; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci cx.latency = obj->integer.value; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci obj = &element->package.elements[3]; 8918c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_INTEGER) { 8928c2ecf20Sopenharmony_ci acpi_handle_info(handle, "_CST C%d package element[3] type(%x) not integer, skip...\n", 8938c2ecf20Sopenharmony_ci i, obj->type); 8948c2ecf20Sopenharmony_ci continue; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci memcpy(&info->states[++last_index], &cx, sizeof(cx)); 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci acpi_handle_info(handle, "Found %d idle states\n", last_index); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci info->count = last_index; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci end: 9058c2ecf20Sopenharmony_ci kfree(buffer.pointer); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return ret; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_processor_evaluate_cst); 9108c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ 911