1*b93f47eaSRoger Pau Monné /*- 2*b93f47eaSRoger Pau Monné * Copyright (c) 2022 Citrix Systems R&D 3*b93f47eaSRoger Pau Monné * Copyright (c) 2003-2005 Nate Lawson (SDG) 4*b93f47eaSRoger Pau Monné * Copyright (c) 2001 Michael Smith 5*b93f47eaSRoger Pau Monné * All rights reserved. 6*b93f47eaSRoger Pau Monné * 7*b93f47eaSRoger Pau Monné * Redistribution and use in source and binary forms, with or without 8*b93f47eaSRoger Pau Monné * modification, are permitted provided that the following conditions 9*b93f47eaSRoger Pau Monné * are met: 10*b93f47eaSRoger Pau Monné * 1. Redistributions of source code must retain the above copyright 11*b93f47eaSRoger Pau Monné * notice, this list of conditions and the following disclaimer. 12*b93f47eaSRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright 13*b93f47eaSRoger Pau Monné * notice, this list of conditions and the following disclaimer in the 14*b93f47eaSRoger Pau Monné * documentation and/or other materials provided with the distribution. 15*b93f47eaSRoger Pau Monné * 16*b93f47eaSRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*b93f47eaSRoger Pau Monné * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*b93f47eaSRoger Pau Monné * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*b93f47eaSRoger Pau Monné * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*b93f47eaSRoger Pau Monné * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*b93f47eaSRoger Pau Monné * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*b93f47eaSRoger Pau Monné * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*b93f47eaSRoger Pau Monné * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*b93f47eaSRoger Pau Monné * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*b93f47eaSRoger Pau Monné * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*b93f47eaSRoger Pau Monné * SUCH DAMAGE. 27*b93f47eaSRoger Pau Monné */ 28*b93f47eaSRoger Pau Monné 29*b93f47eaSRoger Pau Monné #include <sys/cdefs.h> 30*b93f47eaSRoger Pau Monné __FBSDID("$FreeBSD$"); 31*b93f47eaSRoger Pau Monné 32*b93f47eaSRoger Pau Monné #include "opt_acpi.h" 33*b93f47eaSRoger Pau Monné #include <sys/param.h> 34*b93f47eaSRoger Pau Monné #include <sys/bus.h> 35*b93f47eaSRoger Pau Monné #include <sys/cpu.h> 36*b93f47eaSRoger Pau Monné #include <sys/kernel.h> 37*b93f47eaSRoger Pau Monné #include <sys/malloc.h> 38*b93f47eaSRoger Pau Monné #include <sys/module.h> 39*b93f47eaSRoger Pau Monné #include <sys/pcpu.h> 40*b93f47eaSRoger Pau Monné #include <sys/power.h> 41*b93f47eaSRoger Pau Monné #include <sys/proc.h> 42*b93f47eaSRoger Pau Monné #include <sys/sched.h> 43*b93f47eaSRoger Pau Monné 44*b93f47eaSRoger Pau Monné #include <machine/_inttypes.h> 45*b93f47eaSRoger Pau Monné 46*b93f47eaSRoger Pau Monné #include <contrib/dev/acpica/include/acpi.h> 47*b93f47eaSRoger Pau Monné #include <contrib/dev/acpica/include/accommon.h> 48*b93f47eaSRoger Pau Monné 49*b93f47eaSRoger Pau Monné #include <dev/acpica/acpivar.h> 50*b93f47eaSRoger Pau Monné 51*b93f47eaSRoger Pau Monné #include <xen/xen-os.h> 52*b93f47eaSRoger Pau Monné 53*b93f47eaSRoger Pau Monné #define ACPI_DOMAIN_COORD_TYPE_SW_ALL 0xfc 54*b93f47eaSRoger Pau Monné #define ACPI_DOMAIN_COORD_TYPE_SW_ANY 0xfd 55*b93f47eaSRoger Pau Monné #define ACPI_DOMAIN_COORD_TYPE_HW_ALL 0xfe 56*b93f47eaSRoger Pau Monné 57*b93f47eaSRoger Pau Monné #define ACPI_NOTIFY_PERF_STATES 0x80 /* _PSS changed. */ 58*b93f47eaSRoger Pau Monné #define ACPI_NOTIFY_CX_STATES 0x81 /* _CST changed. */ 59*b93f47eaSRoger Pau Monné 60*b93f47eaSRoger Pau Monné static MALLOC_DEFINE(M_XENACPI, "xen_acpi", "Xen CPU ACPI forwarder"); 61*b93f47eaSRoger Pau Monné 62*b93f47eaSRoger Pau Monné /* Hooks for the ACPI CA debugging infrastructure */ 63*b93f47eaSRoger Pau Monné #define _COMPONENT ACPI_PROCESSOR 64*b93f47eaSRoger Pau Monné ACPI_MODULE_NAME("PROCESSOR") 65*b93f47eaSRoger Pau Monné 66*b93f47eaSRoger Pau Monné struct xen_acpi_cpu_softc { 67*b93f47eaSRoger Pau Monné device_t cpu_dev; 68*b93f47eaSRoger Pau Monné ACPI_HANDLE cpu_handle; 69*b93f47eaSRoger Pau Monné uint32_t cpu_acpi_id; 70*b93f47eaSRoger Pau Monné struct xen_processor_cx *cpu_cx_states; 71*b93f47eaSRoger Pau Monné unsigned int cpu_cx_count; 72*b93f47eaSRoger Pau Monné struct xen_processor_px *cpu_px_states; 73*b93f47eaSRoger Pau Monné unsigned int cpu_px_count; 74*b93f47eaSRoger Pau Monné struct xen_pct_register control_register; 75*b93f47eaSRoger Pau Monné struct xen_pct_register status_register; 76*b93f47eaSRoger Pau Monné struct xen_psd_package psd; 77*b93f47eaSRoger Pau Monné }; 78*b93f47eaSRoger Pau Monné 79*b93f47eaSRoger Pau Monné #define CPUDEV_DEVICE_ID "ACPI0007" 80*b93f47eaSRoger Pau Monné 81*b93f47eaSRoger Pau Monné ACPI_SERIAL_DECL(cpu, "ACPI CPU"); 82*b93f47eaSRoger Pau Monné 83*b93f47eaSRoger Pau Monné #define device_printf(dev,...) \ 84*b93f47eaSRoger Pau Monné if (!device_is_quiet(dev)) \ 85*b93f47eaSRoger Pau Monné device_printf((dev), __VA_ARGS__) 86*b93f47eaSRoger Pau Monné 87*b93f47eaSRoger Pau Monné static int 88*b93f47eaSRoger Pau Monné acpi_get_gas(const ACPI_OBJECT *res, unsigned int idx, 89*b93f47eaSRoger Pau Monné ACPI_GENERIC_ADDRESS *gas) 90*b93f47eaSRoger Pau Monné { 91*b93f47eaSRoger Pau Monné const ACPI_OBJECT *obj = &res->Package.Elements[idx]; 92*b93f47eaSRoger Pau Monné 93*b93f47eaSRoger Pau Monné if (obj == NULL || obj->Type != ACPI_TYPE_BUFFER || 94*b93f47eaSRoger Pau Monné obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) 95*b93f47eaSRoger Pau Monné return (EINVAL); 96*b93f47eaSRoger Pau Monné 97*b93f47eaSRoger Pau Monné memcpy(gas, obj->Buffer.Pointer + 3, sizeof(*gas)); 98*b93f47eaSRoger Pau Monné 99*b93f47eaSRoger Pau Monné return (0); 100*b93f47eaSRoger Pau Monné } 101*b93f47eaSRoger Pau Monné 102*b93f47eaSRoger Pau Monné static int 103*b93f47eaSRoger Pau Monné acpi_get_pct(const ACPI_OBJECT *res, unsigned int idx, 104*b93f47eaSRoger Pau Monné struct xen_pct_register *reg) 105*b93f47eaSRoger Pau Monné { 106*b93f47eaSRoger Pau Monné struct { 107*b93f47eaSRoger Pau Monné uint8_t descriptor; 108*b93f47eaSRoger Pau Monné uint16_t length; 109*b93f47eaSRoger Pau Monné ACPI_GENERIC_ADDRESS gas; 110*b93f47eaSRoger Pau Monné } __packed raw; 111*b93f47eaSRoger Pau Monné const ACPI_OBJECT *obj = &res->Package.Elements[idx]; 112*b93f47eaSRoger Pau Monné 113*b93f47eaSRoger Pau Monné if (obj == NULL || obj->Type != ACPI_TYPE_BUFFER || 114*b93f47eaSRoger Pau Monné obj->Buffer.Length < sizeof(raw)) 115*b93f47eaSRoger Pau Monné return (EINVAL); 116*b93f47eaSRoger Pau Monné 117*b93f47eaSRoger Pau Monné memcpy(&raw, obj->Buffer.Pointer, sizeof(raw)); 118*b93f47eaSRoger Pau Monné reg->descriptor = raw.descriptor; 119*b93f47eaSRoger Pau Monné reg->length = raw.length; 120*b93f47eaSRoger Pau Monné reg->space_id = raw.gas.SpaceId; 121*b93f47eaSRoger Pau Monné reg->bit_width = raw.gas.BitWidth; 122*b93f47eaSRoger Pau Monné reg->bit_offset = raw.gas.BitOffset; 123*b93f47eaSRoger Pau Monné reg->reserved = raw.gas.AccessWidth; 124*b93f47eaSRoger Pau Monné reg->address = raw.gas.Address; 125*b93f47eaSRoger Pau Monné 126*b93f47eaSRoger Pau Monné return (0); 127*b93f47eaSRoger Pau Monné } 128*b93f47eaSRoger Pau Monné 129*b93f47eaSRoger Pau Monné static int 130*b93f47eaSRoger Pau Monné xen_upload_cx(struct xen_acpi_cpu_softc *sc) 131*b93f47eaSRoger Pau Monné { 132*b93f47eaSRoger Pau Monné struct xen_platform_op op = { 133*b93f47eaSRoger Pau Monné .cmd = XENPF_set_processor_pminfo, 134*b93f47eaSRoger Pau Monné .interface_version = XENPF_INTERFACE_VERSION, 135*b93f47eaSRoger Pau Monné .u.set_pminfo.id = sc->cpu_acpi_id, 136*b93f47eaSRoger Pau Monné .u.set_pminfo.type = XEN_PM_CX, 137*b93f47eaSRoger Pau Monné .u.set_pminfo.u.power.count = sc->cpu_cx_count, 138*b93f47eaSRoger Pau Monné .u.set_pminfo.u.power.flags.has_cst = 1, 139*b93f47eaSRoger Pau Monné /* Ignore bm_check and bm_control, Xen will set those. */ 140*b93f47eaSRoger Pau Monné }; 141*b93f47eaSRoger Pau Monné int error; 142*b93f47eaSRoger Pau Monné 143*b93f47eaSRoger Pau Monné set_xen_guest_handle(op.u.set_pminfo.u.power.states, sc->cpu_cx_states); 144*b93f47eaSRoger Pau Monné 145*b93f47eaSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 146*b93f47eaSRoger Pau Monné if (error != 0) 147*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 148*b93f47eaSRoger Pau Monné "ACPI ID %u Cx upload failed: %d\n", sc->cpu_acpi_id, 149*b93f47eaSRoger Pau Monné error); 150*b93f47eaSRoger Pau Monné return (error); 151*b93f47eaSRoger Pau Monné } 152*b93f47eaSRoger Pau Monné 153*b93f47eaSRoger Pau Monné static int 154*b93f47eaSRoger Pau Monné xen_upload_px(struct xen_acpi_cpu_softc *sc) 155*b93f47eaSRoger Pau Monné { 156*b93f47eaSRoger Pau Monné struct xen_platform_op op = { 157*b93f47eaSRoger Pau Monné .cmd = XENPF_set_processor_pminfo, 158*b93f47eaSRoger Pau Monné .interface_version = XENPF_INTERFACE_VERSION, 159*b93f47eaSRoger Pau Monné .u.set_pminfo.id = sc->cpu_acpi_id, 160*b93f47eaSRoger Pau Monné .u.set_pminfo.type = XEN_PM_PX, 161*b93f47eaSRoger Pau Monné .u.set_pminfo.u.perf.state_count = sc->cpu_px_count, 162*b93f47eaSRoger Pau Monné .u.set_pminfo.u.perf.control_register = sc->control_register, 163*b93f47eaSRoger Pau Monné .u.set_pminfo.u.perf.status_register = sc->status_register, 164*b93f47eaSRoger Pau Monné .u.set_pminfo.u.perf.domain_info = sc->psd, 165*b93f47eaSRoger Pau Monné .u.set_pminfo.u.perf.flags = XEN_PX_PPC | XEN_PX_PCT | 166*b93f47eaSRoger Pau Monné XEN_PX_PSS | XEN_PX_PSD, 167*b93f47eaSRoger Pau Monné }; 168*b93f47eaSRoger Pau Monné ACPI_STATUS status; 169*b93f47eaSRoger Pau Monné int error; 170*b93f47eaSRoger Pau Monné 171*b93f47eaSRoger Pau Monné status = acpi_GetInteger(sc->cpu_handle, "_PPC", 172*b93f47eaSRoger Pau Monné &op.u.set_pminfo.u.perf.platform_limit); 173*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 174*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "missing _PPC object\n"); 175*b93f47eaSRoger Pau Monné return (ENXIO); 176*b93f47eaSRoger Pau Monné } 177*b93f47eaSRoger Pau Monné 178*b93f47eaSRoger Pau Monné set_xen_guest_handle(op.u.set_pminfo.u.perf.states, sc->cpu_px_states); 179*b93f47eaSRoger Pau Monné 180*b93f47eaSRoger Pau Monné /* 181*b93f47eaSRoger Pau Monné * NB: it's unclear the exact purpose of the shared_type field, or why 182*b93f47eaSRoger Pau Monné * it can't be calculated by Xen itself. Naively set it here to allow 183*b93f47eaSRoger Pau Monné * the upload to succeed. 184*b93f47eaSRoger Pau Monné */ 185*b93f47eaSRoger Pau Monné switch (sc->psd.coord_type) { 186*b93f47eaSRoger Pau Monné case ACPI_DOMAIN_COORD_TYPE_SW_ALL: 187*b93f47eaSRoger Pau Monné op.u.set_pminfo.u.perf.shared_type = 188*b93f47eaSRoger Pau Monné XEN_CPUPERF_SHARED_TYPE_ALL; 189*b93f47eaSRoger Pau Monné break; 190*b93f47eaSRoger Pau Monné 191*b93f47eaSRoger Pau Monné case ACPI_DOMAIN_COORD_TYPE_HW_ALL: 192*b93f47eaSRoger Pau Monné op.u.set_pminfo.u.perf.shared_type = 193*b93f47eaSRoger Pau Monné XEN_CPUPERF_SHARED_TYPE_HW; 194*b93f47eaSRoger Pau Monné break; 195*b93f47eaSRoger Pau Monné 196*b93f47eaSRoger Pau Monné case ACPI_DOMAIN_COORD_TYPE_SW_ANY: 197*b93f47eaSRoger Pau Monné op.u.set_pminfo.u.perf.shared_type = 198*b93f47eaSRoger Pau Monné XEN_CPUPERF_SHARED_TYPE_ANY; 199*b93f47eaSRoger Pau Monné break; 200*b93f47eaSRoger Pau Monné default: 201*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 202*b93f47eaSRoger Pau Monné "unknown coordination type %#" PRIx64 "\n", 203*b93f47eaSRoger Pau Monné sc->psd.coord_type); 204*b93f47eaSRoger Pau Monné return (EINVAL); 205*b93f47eaSRoger Pau Monné } 206*b93f47eaSRoger Pau Monné 207*b93f47eaSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 208*b93f47eaSRoger Pau Monné if (error != 0) 209*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 210*b93f47eaSRoger Pau Monné "ACPI ID %u Px upload failed: %d\n", sc->cpu_acpi_id, error); 211*b93f47eaSRoger Pau Monné return (error); 212*b93f47eaSRoger Pau Monné } 213*b93f47eaSRoger Pau Monné 214*b93f47eaSRoger Pau Monné static int 215*b93f47eaSRoger Pau Monné acpi_set_pdc(const struct xen_acpi_cpu_softc *sc) 216*b93f47eaSRoger Pau Monné { 217*b93f47eaSRoger Pau Monné struct xen_platform_op op = { 218*b93f47eaSRoger Pau Monné .cmd = XENPF_set_processor_pminfo, 219*b93f47eaSRoger Pau Monné .interface_version = XENPF_INTERFACE_VERSION, 220*b93f47eaSRoger Pau Monné .u.set_pminfo.id = -1, 221*b93f47eaSRoger Pau Monné .u.set_pminfo.type = XEN_PM_PDC, 222*b93f47eaSRoger Pau Monné }; 223*b93f47eaSRoger Pau Monné uint32_t pdc[3] = {1, 1}; 224*b93f47eaSRoger Pau Monné ACPI_OBJECT arg = { 225*b93f47eaSRoger Pau Monné .Buffer.Type = ACPI_TYPE_BUFFER, 226*b93f47eaSRoger Pau Monné .Buffer.Length = sizeof(pdc), 227*b93f47eaSRoger Pau Monné .Buffer.Pointer = (uint8_t *)pdc, 228*b93f47eaSRoger Pau Monné }; 229*b93f47eaSRoger Pau Monné ACPI_OBJECT_LIST arglist = { 230*b93f47eaSRoger Pau Monné .Pointer = &arg, 231*b93f47eaSRoger Pau Monné .Count = 1, 232*b93f47eaSRoger Pau Monné }; 233*b93f47eaSRoger Pau Monné ACPI_STATUS status; 234*b93f47eaSRoger Pau Monné int error; 235*b93f47eaSRoger Pau Monné 236*b93f47eaSRoger Pau Monné set_xen_guest_handle(op.u.set_pminfo.u.pdc, pdc); 237*b93f47eaSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 238*b93f47eaSRoger Pau Monné if (error != 0) { 239*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 240*b93f47eaSRoger Pau Monné "unable to get _PDC features from Xen: %d\n", error); 241*b93f47eaSRoger Pau Monné return (error); 242*b93f47eaSRoger Pau Monné } 243*b93f47eaSRoger Pau Monné 244*b93f47eaSRoger Pau Monné status = AcpiEvaluateObject(sc->cpu_handle, "_PDC", &arglist, NULL); 245*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 246*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "unable to execute _PDC - %s\n", 247*b93f47eaSRoger Pau Monné AcpiFormatException(status)); 248*b93f47eaSRoger Pau Monné return (ENXIO); 249*b93f47eaSRoger Pau Monné } 250*b93f47eaSRoger Pau Monné 251*b93f47eaSRoger Pau Monné return (0); 252*b93f47eaSRoger Pau Monné } 253*b93f47eaSRoger Pau Monné 254*b93f47eaSRoger Pau Monné /* 255*b93f47eaSRoger Pau Monné * Parse a _CST package and set up its Cx states. Since the _CST object 256*b93f47eaSRoger Pau Monné * can change dynamically, our notify handler may call this function 257*b93f47eaSRoger Pau Monné * to clean up and probe the new _CST package. 258*b93f47eaSRoger Pau Monné */ 259*b93f47eaSRoger Pau Monné static int 260*b93f47eaSRoger Pau Monné acpi_fetch_cx(struct xen_acpi_cpu_softc *sc) 261*b93f47eaSRoger Pau Monné { 262*b93f47eaSRoger Pau Monné ACPI_STATUS status; 263*b93f47eaSRoger Pau Monné ACPI_BUFFER buf = { 264*b93f47eaSRoger Pau Monné .Length = ACPI_ALLOCATE_BUFFER, 265*b93f47eaSRoger Pau Monné }; 266*b93f47eaSRoger Pau Monné ACPI_OBJECT *top; 267*b93f47eaSRoger Pau Monné uint32_t count; 268*b93f47eaSRoger Pau Monné unsigned int i; 269*b93f47eaSRoger Pau Monné 270*b93f47eaSRoger Pau Monné status = AcpiEvaluateObject(sc->cpu_handle, "_CST", NULL, &buf); 271*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 272*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "missing _CST object\n"); 273*b93f47eaSRoger Pau Monné return (ENXIO); 274*b93f47eaSRoger Pau Monné } 275*b93f47eaSRoger Pau Monné 276*b93f47eaSRoger Pau Monné /* _CST is a package with a count and at least one Cx package. */ 277*b93f47eaSRoger Pau Monné top = (ACPI_OBJECT *)buf.Pointer; 278*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(top, 2) || acpi_PkgInt32(top, 0, &count) != 0) { 279*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "invalid _CST package\n"); 280*b93f47eaSRoger Pau Monné AcpiOsFree(buf.Pointer); 281*b93f47eaSRoger Pau Monné return (ENXIO); 282*b93f47eaSRoger Pau Monné } 283*b93f47eaSRoger Pau Monné if (count != top->Package.Count - 1) { 284*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 285*b93f47eaSRoger Pau Monné "invalid _CST state count (%u != %u)\n", 286*b93f47eaSRoger Pau Monné count, top->Package.Count - 1); 287*b93f47eaSRoger Pau Monné count = top->Package.Count - 1; 288*b93f47eaSRoger Pau Monné } 289*b93f47eaSRoger Pau Monné 290*b93f47eaSRoger Pau Monné sc->cpu_cx_states = mallocarray(count, sizeof(struct xen_processor_cx), 291*b93f47eaSRoger Pau Monné M_XENACPI, M_WAITOK | M_ZERO); 292*b93f47eaSRoger Pau Monné 293*b93f47eaSRoger Pau Monné sc->cpu_cx_count = 0; 294*b93f47eaSRoger Pau Monné for (i = 0; i < count; i++) { 295*b93f47eaSRoger Pau Monné uint32_t type; 296*b93f47eaSRoger Pau Monné ACPI_GENERIC_ADDRESS gas; 297*b93f47eaSRoger Pau Monné ACPI_OBJECT *pkg = &top->Package.Elements[i + 1]; 298*b93f47eaSRoger Pau Monné struct xen_processor_cx *cx_ptr = 299*b93f47eaSRoger Pau Monné &sc->cpu_cx_states[sc->cpu_cx_count]; 300*b93f47eaSRoger Pau Monné 301*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(pkg, 4) || 302*b93f47eaSRoger Pau Monné acpi_PkgInt32(pkg, 1, &type) != 0 || 303*b93f47eaSRoger Pau Monné acpi_PkgInt32(pkg, 2, &cx_ptr->latency) != 0 || 304*b93f47eaSRoger Pau Monné acpi_PkgInt32(pkg, 3, &cx_ptr->power) != 0 || 305*b93f47eaSRoger Pau Monné acpi_get_gas(pkg, 0, &gas) != 0) { 306*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 307*b93f47eaSRoger Pau Monné "skipping invalid _CST %u package\n", 308*b93f47eaSRoger Pau Monné i + 1); 309*b93f47eaSRoger Pau Monné continue; 310*b93f47eaSRoger Pau Monné } 311*b93f47eaSRoger Pau Monné 312*b93f47eaSRoger Pau Monné cx_ptr->type = type; 313*b93f47eaSRoger Pau Monné cx_ptr->reg.space_id = gas.SpaceId; 314*b93f47eaSRoger Pau Monné cx_ptr->reg.bit_width = gas.BitWidth; 315*b93f47eaSRoger Pau Monné cx_ptr->reg.bit_offset = gas.BitOffset; 316*b93f47eaSRoger Pau Monné cx_ptr->reg.access_size = gas.AccessWidth; 317*b93f47eaSRoger Pau Monné cx_ptr->reg.address = gas.Address; 318*b93f47eaSRoger Pau Monné sc->cpu_cx_count++; 319*b93f47eaSRoger Pau Monné } 320*b93f47eaSRoger Pau Monné AcpiOsFree(buf.Pointer); 321*b93f47eaSRoger Pau Monné 322*b93f47eaSRoger Pau Monné if (sc->cpu_cx_count == 0) { 323*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "no valid _CST package found\n"); 324*b93f47eaSRoger Pau Monné free(sc->cpu_cx_states, M_XENACPI); 325*b93f47eaSRoger Pau Monné sc->cpu_cx_states = NULL; 326*b93f47eaSRoger Pau Monné return (ENXIO); 327*b93f47eaSRoger Pau Monné } 328*b93f47eaSRoger Pau Monné 329*b93f47eaSRoger Pau Monné return (0); 330*b93f47eaSRoger Pau Monné } 331*b93f47eaSRoger Pau Monné 332*b93f47eaSRoger Pau Monné /* Probe and setup any valid performance states (Px). */ 333*b93f47eaSRoger Pau Monné static int 334*b93f47eaSRoger Pau Monné acpi_fetch_px(struct xen_acpi_cpu_softc *sc) 335*b93f47eaSRoger Pau Monné { 336*b93f47eaSRoger Pau Monné ACPI_BUFFER buf = { 337*b93f47eaSRoger Pau Monné .Length = ACPI_ALLOCATE_BUFFER, 338*b93f47eaSRoger Pau Monné }; 339*b93f47eaSRoger Pau Monné ACPI_OBJECT *pkg, *res; 340*b93f47eaSRoger Pau Monné ACPI_STATUS status; 341*b93f47eaSRoger Pau Monné unsigned int count, i; 342*b93f47eaSRoger Pau Monné int error; 343*b93f47eaSRoger Pau Monné uint64_t *p; 344*b93f47eaSRoger Pau Monné 345*b93f47eaSRoger Pau Monné /* _PSS */ 346*b93f47eaSRoger Pau Monné status = AcpiEvaluateObject(sc->cpu_handle, "_PSS", NULL, &buf); 347*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 348*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "missing _PSS object\n"); 349*b93f47eaSRoger Pau Monné return (ENXIO); 350*b93f47eaSRoger Pau Monné } 351*b93f47eaSRoger Pau Monné 352*b93f47eaSRoger Pau Monné pkg = (ACPI_OBJECT *)buf.Pointer; 353*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(pkg, 1)) { 354*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "invalid top level _PSS package\n"); 355*b93f47eaSRoger Pau Monné goto error; 356*b93f47eaSRoger Pau Monné } 357*b93f47eaSRoger Pau Monné count = pkg->Package.Count; 358*b93f47eaSRoger Pau Monné 359*b93f47eaSRoger Pau Monné sc->cpu_px_states = mallocarray(count, sizeof(struct xen_processor_px), 360*b93f47eaSRoger Pau Monné M_XENACPI, M_WAITOK | M_ZERO); 361*b93f47eaSRoger Pau Monné 362*b93f47eaSRoger Pau Monné /* 363*b93f47eaSRoger Pau Monné * Each state is a package of {CoreFreq, Power, TransitionLatency, 364*b93f47eaSRoger Pau Monné * BusMasterLatency, ControlVal, StatusVal}, sorted from highest 365*b93f47eaSRoger Pau Monné * performance to lowest. 366*b93f47eaSRoger Pau Monné */ 367*b93f47eaSRoger Pau Monné sc->cpu_px_count = 0; 368*b93f47eaSRoger Pau Monné for (i = 0; i < count; i++) { 369*b93f47eaSRoger Pau Monné unsigned int j; 370*b93f47eaSRoger Pau Monné 371*b93f47eaSRoger Pau Monné res = &pkg->Package.Elements[i]; 372*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(res, 6)) { 373*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 374*b93f47eaSRoger Pau Monné "invalid _PSS package idx %u\n", i); 375*b93f47eaSRoger Pau Monné continue; 376*b93f47eaSRoger Pau Monné } 377*b93f47eaSRoger Pau Monné 378*b93f47eaSRoger Pau Monné /* Parse the rest of the package into the struct. */ 379*b93f47eaSRoger Pau Monné p = (uint64_t *)&sc->cpu_px_states[sc->cpu_px_count++]; 380*b93f47eaSRoger Pau Monné for (j = 0; j < 6; j++, p++) 381*b93f47eaSRoger Pau Monné acpi_PkgInt(res, j, p); 382*b93f47eaSRoger Pau Monné } 383*b93f47eaSRoger Pau Monné 384*b93f47eaSRoger Pau Monné /* No valid Px state found so give up. */ 385*b93f47eaSRoger Pau Monné if (sc->cpu_px_count == 0) { 386*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "no valid _PSS package found\n"); 387*b93f47eaSRoger Pau Monné goto error; 388*b93f47eaSRoger Pau Monné } 389*b93f47eaSRoger Pau Monné AcpiOsFree(buf.Pointer); 390*b93f47eaSRoger Pau Monné 391*b93f47eaSRoger Pau Monné /* _PCT */ 392*b93f47eaSRoger Pau Monné buf.Pointer = NULL; 393*b93f47eaSRoger Pau Monné buf.Length = ACPI_ALLOCATE_BUFFER; 394*b93f47eaSRoger Pau Monné status = AcpiEvaluateObject(sc->cpu_handle, "_PCT", NULL, &buf); 395*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 396*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "missing _PCT object\n"); 397*b93f47eaSRoger Pau Monné goto error; 398*b93f47eaSRoger Pau Monné } 399*b93f47eaSRoger Pau Monné 400*b93f47eaSRoger Pau Monné /* Check the package of two registers, each a Buffer in GAS format. */ 401*b93f47eaSRoger Pau Monné pkg = (ACPI_OBJECT *)buf.Pointer; 402*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(pkg, 2)) { 403*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "invalid top level _PCT package\n"); 404*b93f47eaSRoger Pau Monné goto error; 405*b93f47eaSRoger Pau Monné } 406*b93f47eaSRoger Pau Monné 407*b93f47eaSRoger Pau Monné error = acpi_get_pct(pkg, 0, &sc->control_register); 408*b93f47eaSRoger Pau Monné if (error != 0) { 409*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 410*b93f47eaSRoger Pau Monné "unable to fetch _PCT control register: %d\n", error); 411*b93f47eaSRoger Pau Monné goto error; 412*b93f47eaSRoger Pau Monné } 413*b93f47eaSRoger Pau Monné error = acpi_get_pct(pkg, 1, &sc->status_register); 414*b93f47eaSRoger Pau Monné if (error != 0) { 415*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, 416*b93f47eaSRoger Pau Monné "unable to fetch _PCT status register: %d\n", error); 417*b93f47eaSRoger Pau Monné goto error; 418*b93f47eaSRoger Pau Monné } 419*b93f47eaSRoger Pau Monné AcpiOsFree(buf.Pointer); 420*b93f47eaSRoger Pau Monné 421*b93f47eaSRoger Pau Monné /* _PSD */ 422*b93f47eaSRoger Pau Monné buf.Pointer = NULL; 423*b93f47eaSRoger Pau Monné buf.Length = ACPI_ALLOCATE_BUFFER; 424*b93f47eaSRoger Pau Monné status = AcpiEvaluateObject(sc->cpu_handle, "_PSD", NULL, &buf); 425*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 426*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "missing _PSD object\n"); 427*b93f47eaSRoger Pau Monné goto error; 428*b93f47eaSRoger Pau Monné } 429*b93f47eaSRoger Pau Monné 430*b93f47eaSRoger Pau Monné pkg = (ACPI_OBJECT *)buf.Pointer; 431*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(pkg, 1)) { 432*b93f47eaSRoger Pau Monné device_printf(sc->cpu_dev, "invalid top level _PSD package\n"); 433*b93f47eaSRoger Pau Monné goto error; 434*b93f47eaSRoger Pau Monné } 435*b93f47eaSRoger Pau Monné 436*b93f47eaSRoger Pau Monné res = &pkg->Package.Elements[0]; 437*b93f47eaSRoger Pau Monné if (!ACPI_PKG_VALID(res, 5)) { 438*b93f47eaSRoger Pau Monné printf("invalid _PSD package\n"); 439*b93f47eaSRoger Pau Monné goto error; 440*b93f47eaSRoger Pau Monné } 441*b93f47eaSRoger Pau Monné 442*b93f47eaSRoger Pau Monné p = (uint64_t *)&sc->psd; 443*b93f47eaSRoger Pau Monné for (i = 0; i < 5; i++, p++) 444*b93f47eaSRoger Pau Monné acpi_PkgInt(res, i, p); 445*b93f47eaSRoger Pau Monné AcpiOsFree(buf.Pointer); 446*b93f47eaSRoger Pau Monné 447*b93f47eaSRoger Pau Monné return (0); 448*b93f47eaSRoger Pau Monné 449*b93f47eaSRoger Pau Monné error: 450*b93f47eaSRoger Pau Monné if (buf.Pointer != NULL) 451*b93f47eaSRoger Pau Monné AcpiOsFree(buf.Pointer); 452*b93f47eaSRoger Pau Monné if (sc->cpu_px_states != NULL) { 453*b93f47eaSRoger Pau Monné free(sc->cpu_px_states, M_XENACPI); 454*b93f47eaSRoger Pau Monné sc->cpu_px_states = NULL; 455*b93f47eaSRoger Pau Monné } 456*b93f47eaSRoger Pau Monné return (ENXIO); 457*b93f47eaSRoger Pau Monné } 458*b93f47eaSRoger Pau Monné 459*b93f47eaSRoger Pau Monné static void 460*b93f47eaSRoger Pau Monné acpi_notify(ACPI_HANDLE h, UINT32 notify, void *context) 461*b93f47eaSRoger Pau Monné { 462*b93f47eaSRoger Pau Monné struct xen_acpi_cpu_softc *sc = context; 463*b93f47eaSRoger Pau Monné 464*b93f47eaSRoger Pau Monné switch (notify) { 465*b93f47eaSRoger Pau Monné case ACPI_NOTIFY_PERF_STATES: 466*b93f47eaSRoger Pau Monné if (acpi_fetch_px(sc) != 0) 467*b93f47eaSRoger Pau Monné break; 468*b93f47eaSRoger Pau Monné xen_upload_px(sc); 469*b93f47eaSRoger Pau Monné free(sc->cpu_px_states, M_XENACPI); 470*b93f47eaSRoger Pau Monné sc->cpu_px_states = NULL; 471*b93f47eaSRoger Pau Monné break; 472*b93f47eaSRoger Pau Monné 473*b93f47eaSRoger Pau Monné case ACPI_NOTIFY_CX_STATES: 474*b93f47eaSRoger Pau Monné if (acpi_fetch_cx(sc) != 0) 475*b93f47eaSRoger Pau Monné break; 476*b93f47eaSRoger Pau Monné xen_upload_cx(sc); 477*b93f47eaSRoger Pau Monné free(sc->cpu_cx_states, M_XENACPI); 478*b93f47eaSRoger Pau Monné sc->cpu_cx_states = NULL; 479*b93f47eaSRoger Pau Monné break; 480*b93f47eaSRoger Pau Monné } 481*b93f47eaSRoger Pau Monné } 482*b93f47eaSRoger Pau Monné 483*b93f47eaSRoger Pau Monné static int 484*b93f47eaSRoger Pau Monné xen_acpi_cpu_probe(device_t dev) 485*b93f47eaSRoger Pau Monné { 486*b93f47eaSRoger Pau Monné static char *cpudev_ids[] = { CPUDEV_DEVICE_ID, NULL }; 487*b93f47eaSRoger Pau Monné ACPI_OBJECT_TYPE type = acpi_get_type(dev); 488*b93f47eaSRoger Pau Monné 489*b93f47eaSRoger Pau Monné if (!xen_initial_domain()) 490*b93f47eaSRoger Pau Monné return (ENXIO); 491*b93f47eaSRoger Pau Monné if (type != ACPI_TYPE_PROCESSOR && type != ACPI_TYPE_DEVICE) 492*b93f47eaSRoger Pau Monné return (ENXIO); 493*b93f47eaSRoger Pau Monné if (type == ACPI_TYPE_DEVICE && 494*b93f47eaSRoger Pau Monné ACPI_ID_PROBE(device_get_parent(dev), dev, cpudev_ids, NULL) >= 0) 495*b93f47eaSRoger Pau Monné return (ENXIO); 496*b93f47eaSRoger Pau Monné 497*b93f47eaSRoger Pau Monné device_set_desc(dev, "XEN ACPI CPU"); 498*b93f47eaSRoger Pau Monné if (!bootverbose) 499*b93f47eaSRoger Pau Monné device_quiet(dev); 500*b93f47eaSRoger Pau Monné 501*b93f47eaSRoger Pau Monné /* 502*b93f47eaSRoger Pau Monné * Use SPECIFIC because when running as a Xen dom0 the ACPI PROCESSOR 503*b93f47eaSRoger Pau Monné * data is the native one, and needs to be forwarded to Xen but not 504*b93f47eaSRoger Pau Monné * used by FreeBSD itself. 505*b93f47eaSRoger Pau Monné */ 506*b93f47eaSRoger Pau Monné return (BUS_PROBE_SPECIFIC); 507*b93f47eaSRoger Pau Monné } 508*b93f47eaSRoger Pau Monné 509*b93f47eaSRoger Pau Monné static int 510*b93f47eaSRoger Pau Monné xen_acpi_cpu_attach(device_t dev) 511*b93f47eaSRoger Pau Monné { 512*b93f47eaSRoger Pau Monné struct xen_acpi_cpu_softc *sc = device_get_softc(dev); 513*b93f47eaSRoger Pau Monné ACPI_STATUS status; 514*b93f47eaSRoger Pau Monné int error; 515*b93f47eaSRoger Pau Monné 516*b93f47eaSRoger Pau Monné sc->cpu_dev = dev; 517*b93f47eaSRoger Pau Monné sc->cpu_handle = acpi_get_handle(dev); 518*b93f47eaSRoger Pau Monné 519*b93f47eaSRoger Pau Monné if (acpi_get_type(dev) == ACPI_TYPE_PROCESSOR) { 520*b93f47eaSRoger Pau Monné ACPI_BUFFER buf = { 521*b93f47eaSRoger Pau Monné .Length = ACPI_ALLOCATE_BUFFER, 522*b93f47eaSRoger Pau Monné }; 523*b93f47eaSRoger Pau Monné ACPI_OBJECT *obj; 524*b93f47eaSRoger Pau Monné 525*b93f47eaSRoger Pau Monné status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); 526*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 527*b93f47eaSRoger Pau Monné device_printf(dev, 528*b93f47eaSRoger Pau Monné "attach failed to get Processor obj - %s\n", 529*b93f47eaSRoger Pau Monné AcpiFormatException(status)); 530*b93f47eaSRoger Pau Monné return (ENXIO); 531*b93f47eaSRoger Pau Monné } 532*b93f47eaSRoger Pau Monné obj = (ACPI_OBJECT *)buf.Pointer; 533*b93f47eaSRoger Pau Monné sc->cpu_acpi_id = obj->Processor.ProcId; 534*b93f47eaSRoger Pau Monné AcpiOsFree(obj); 535*b93f47eaSRoger Pau Monné } else { 536*b93f47eaSRoger Pau Monné KASSERT(acpi_get_type(dev) == ACPI_TYPE_DEVICE, 537*b93f47eaSRoger Pau Monné ("Unexpected ACPI object")); 538*b93f47eaSRoger Pau Monné status = acpi_GetInteger(sc->cpu_handle, "_UID", 539*b93f47eaSRoger Pau Monné &sc->cpu_acpi_id); 540*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) { 541*b93f47eaSRoger Pau Monné device_printf(dev, "device object has bad value - %s\n", 542*b93f47eaSRoger Pau Monné AcpiFormatException(status)); 543*b93f47eaSRoger Pau Monné return (ENXIO); 544*b93f47eaSRoger Pau Monné } 545*b93f47eaSRoger Pau Monné } 546*b93f47eaSRoger Pau Monné 547*b93f47eaSRoger Pau Monné /* 548*b93f47eaSRoger Pau Monné * Install the notify handler now: even if we fail to parse or upload 549*b93f47eaSRoger Pau Monné * the states it shouldn't prevent us from attempting to parse further 550*b93f47eaSRoger Pau Monné * updates. 551*b93f47eaSRoger Pau Monné */ 552*b93f47eaSRoger Pau Monné status = AcpiInstallNotifyHandler(sc->cpu_handle, ACPI_DEVICE_NOTIFY, 553*b93f47eaSRoger Pau Monné acpi_notify, sc); 554*b93f47eaSRoger Pau Monné if (ACPI_FAILURE(status)) 555*b93f47eaSRoger Pau Monné device_printf(dev, "failed to register notify handler - %s\n", 556*b93f47eaSRoger Pau Monné AcpiFormatException(status)); 557*b93f47eaSRoger Pau Monné 558*b93f47eaSRoger Pau Monné /* 559*b93f47eaSRoger Pau Monné * Don't report errors: it's likely there are processor objects 560*b93f47eaSRoger Pau Monné * belonging to CPUs that are not online, but the MADT provided to 561*b93f47eaSRoger Pau Monné * FreeBSD is crafted to report the number of CPUs available to dom0. 562*b93f47eaSRoger Pau Monné * 563*b93f47eaSRoger Pau Monné * Parsing or uploading those states could result in errors, just 564*b93f47eaSRoger Pau Monné * ignore them in order to avoid pointless noise. 565*b93f47eaSRoger Pau Monné */ 566*b93f47eaSRoger Pau Monné error = acpi_set_pdc(sc); 567*b93f47eaSRoger Pau Monné if (error != 0) 568*b93f47eaSRoger Pau Monné return (0); 569*b93f47eaSRoger Pau Monné 570*b93f47eaSRoger Pau Monné error = acpi_fetch_px(sc); 571*b93f47eaSRoger Pau Monné if (error != 0) 572*b93f47eaSRoger Pau Monné return (0); 573*b93f47eaSRoger Pau Monné error = xen_upload_px(sc); 574*b93f47eaSRoger Pau Monné free(sc->cpu_px_states, M_XENACPI); 575*b93f47eaSRoger Pau Monné sc->cpu_px_states = NULL; 576*b93f47eaSRoger Pau Monné if (error != 0) 577*b93f47eaSRoger Pau Monné return (0); 578*b93f47eaSRoger Pau Monné 579*b93f47eaSRoger Pau Monné error = acpi_fetch_cx(sc); 580*b93f47eaSRoger Pau Monné if (error != 0) 581*b93f47eaSRoger Pau Monné return (0); 582*b93f47eaSRoger Pau Monné xen_upload_cx(sc); 583*b93f47eaSRoger Pau Monné free(sc->cpu_cx_states, M_XENACPI); 584*b93f47eaSRoger Pau Monné sc->cpu_cx_states = NULL; 585*b93f47eaSRoger Pau Monné 586*b93f47eaSRoger Pau Monné return (0); 587*b93f47eaSRoger Pau Monné } 588*b93f47eaSRoger Pau Monné 589*b93f47eaSRoger Pau Monné static device_method_t xen_acpi_cpu_methods[] = { 590*b93f47eaSRoger Pau Monné /* Device interface */ 591*b93f47eaSRoger Pau Monné DEVMETHOD(device_probe, xen_acpi_cpu_probe), 592*b93f47eaSRoger Pau Monné DEVMETHOD(device_attach, xen_acpi_cpu_attach), 593*b93f47eaSRoger Pau Monné 594*b93f47eaSRoger Pau Monné DEVMETHOD_END 595*b93f47eaSRoger Pau Monné }; 596*b93f47eaSRoger Pau Monné 597*b93f47eaSRoger Pau Monné static driver_t xen_acpi_cpu_driver = { 598*b93f47eaSRoger Pau Monné "xen cpu", 599*b93f47eaSRoger Pau Monné xen_acpi_cpu_methods, 600*b93f47eaSRoger Pau Monné sizeof(struct xen_acpi_cpu_softc), 601*b93f47eaSRoger Pau Monné }; 602*b93f47eaSRoger Pau Monné 603*b93f47eaSRoger Pau Monné static devclass_t xen_acpi_cpu_devclass; 604*b93f47eaSRoger Pau Monné DRIVER_MODULE(xen_cpu, acpi, xen_acpi_cpu_driver, xen_acpi_cpu_devclass, 0, 0); 605*b93f47eaSRoger Pau Monné MODULE_DEPEND(xen_cpu, acpi, 1, 1, 1); 606