The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/xen/cpu/xen_acpi_cpu.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 367c42353edd4240a8564d59683bfac2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.