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/acpica/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) 2003-2005 Nate Lawson (SDG)
    3  * Copyright (c) 2001 Michael Smith
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.72 2008/04/12 12:06:00 rpaulo Exp $
   28  */
   29 
   30 #include "opt_acpi.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/bus.h>
   34 #include <sys/kernel.h>
   35 #include <sys/sysctl.h>
   36 
   37 #include <machine/globaldata.h>
   38 #include <machine/smp.h>
   39 
   40 #include "acpi.h"
   41 #include "acpivar.h"
   42 #include "acpi_cpu.h"
   43 
   44 #define ACPI_NOTIFY_CX_STATES   0x81    /* _CST changed. */
   45 
   46 static int      acpi_cpu_probe(device_t dev);
   47 static int      acpi_cpu_attach(device_t dev);
   48 static struct resource_list *
   49                 acpi_cpu_get_rlist(device_t, device_t);
   50 static struct resource *
   51                 acpi_cpu_alloc_resource(device_t, device_t,
   52                         int, int *, u_long, u_long, u_long, u_int, int);
   53 static int      acpi_cpu_release_resource(device_t, device_t,
   54                         int, int, struct resource *);
   55 
   56 static int      acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *);
   57 static void     acpi_cpu_notify(ACPI_HANDLE, UINT32, void *);
   58 
   59 static device_method_t acpi_cpu_methods[] = {
   60     /* Device interface */
   61     DEVMETHOD(device_probe,             acpi_cpu_probe),
   62     DEVMETHOD(device_attach,            acpi_cpu_attach),
   63     DEVMETHOD(device_detach,            bus_generic_detach),
   64     DEVMETHOD(device_shutdown,          bus_generic_shutdown),
   65     DEVMETHOD(device_suspend,           bus_generic_suspend),
   66     DEVMETHOD(device_resume,            bus_generic_resume),
   67 
   68     /* Bus interface */
   69     DEVMETHOD(bus_add_child,            bus_generic_add_child),
   70     DEVMETHOD(bus_print_child,          bus_generic_print_child),
   71     DEVMETHOD(bus_read_ivar,            bus_generic_read_ivar),
   72     DEVMETHOD(bus_write_ivar,           bus_generic_write_ivar),
   73     DEVMETHOD(bus_get_resource_list,    acpi_cpu_get_rlist),
   74     DEVMETHOD(bus_set_resource,         bus_generic_rl_set_resource),
   75     DEVMETHOD(bus_get_resource,         bus_generic_rl_get_resource),
   76     DEVMETHOD(bus_alloc_resource,       acpi_cpu_alloc_resource),
   77     DEVMETHOD(bus_release_resource,     acpi_cpu_release_resource),
   78     DEVMETHOD(bus_driver_added,         bus_generic_driver_added),
   79     DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
   80     DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
   81     DEVMETHOD(bus_setup_intr,           bus_generic_setup_intr),
   82     DEVMETHOD(bus_teardown_intr,        bus_generic_teardown_intr),
   83 
   84     DEVMETHOD_END
   85 };
   86 
   87 static driver_t acpi_cpu_driver = {
   88     "cpu",
   89     acpi_cpu_methods,
   90     sizeof(struct acpi_cpux_softc)
   91 };
   92 
   93 static devclass_t acpi_cpu_devclass;
   94 DRIVER_MODULE(cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, NULL, NULL);
   95 MODULE_DEPEND(cpu, acpi, 1, 1, 1);
   96 
   97 static int
   98 acpi_cpu_probe(device_t dev)
   99 {
  100     int acpi_id, cpu_id;
  101     ACPI_BUFFER buf;
  102     ACPI_HANDLE handle;
  103     ACPI_STATUS status;
  104     ACPI_OBJECT *obj;
  105 
  106     if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
  107         return ENXIO;
  108 
  109     handle = acpi_get_handle(dev);
  110 
  111     /*
  112      * Get our Processor object.
  113      */
  114     buf.Pointer = NULL;
  115     buf.Length = ACPI_ALLOCATE_BUFFER;
  116     status = AcpiEvaluateObject(handle, NULL, NULL, &buf);
  117     if (ACPI_FAILURE(status)) {
  118         device_printf(dev, "probe failed to get Processor obj - %s\n",
  119                       AcpiFormatException(status));
  120         return ENXIO;
  121     }
  122 
  123     obj = (ACPI_OBJECT *)buf.Pointer;
  124     if (obj->Type != ACPI_TYPE_PROCESSOR) {
  125         device_printf(dev, "Processor object has bad type %d\n", obj->Type);
  126         AcpiOsFree(obj);
  127         return ENXIO;
  128     }
  129 
  130     acpi_id = obj->Processor.ProcId;
  131     AcpiOsFree(obj);
  132 
  133     /*
  134      * Find the processor associated with our unit.  We could use the
  135      * ProcId as a key, however, some boxes do not have the same values
  136      * in their Processor object as the ProcId values in the MADT.
  137      */
  138     if (acpi_cpu_get_id(device_get_unit(dev), &acpi_id, &cpu_id) != 0)
  139         return ENXIO;
  140 
  141     acpi_set_magic(dev, cpu_id);
  142     device_set_desc(dev, "ACPI CPU");
  143 
  144     return 0;
  145 }
  146 
  147 static int
  148 acpi_cpu_attach(device_t dev)
  149 {
  150     struct acpi_cpux_softc *sc = device_get_softc(dev);
  151     ACPI_HANDLE handle;
  152     device_t child;
  153     int cpu_id, cpu_features;
  154     struct acpi_softc *acpi_sc;
  155 
  156     handle = acpi_get_handle(dev);
  157     cpu_id = acpi_get_magic(dev);
  158 
  159     acpi_sc = acpi_device_get_parent_softc(dev);
  160     if (cpu_id == 0) {
  161         sysctl_ctx_init(&sc->glob_sysctl_ctx);
  162         sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx,
  163                                SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
  164                                OID_AUTO, "cpu", CTLFLAG_RD, 0,
  165                                "node for CPU global settings");
  166         if (sc->glob_sysctl_tree == NULL)
  167             return ENOMEM;
  168     }
  169 
  170     sysctl_ctx_init(&sc->pcpu_sysctl_ctx);
  171     sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx,
  172                            SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
  173                            OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0,
  174                            "node for per-CPU settings");
  175     if (sc->pcpu_sysctl_tree == NULL) {
  176         sysctl_ctx_free(&sc->glob_sysctl_ctx);
  177         return ENOMEM;
  178     }
  179 
  180     /*
  181      * Before calling any CPU methods, collect child driver feature hints
  182      * and notify ACPI of them.  We support unified SMP power control
  183      * so advertise this ourselves.  Note this is not the same as independent
  184      * SMP control where each CPU can have different settings.
  185      */
  186     cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3;
  187     cpu_features |= acpi_cpu_md_features();
  188 
  189     /*
  190      * CPU capabilities are specified as a buffer of 32-bit integers:
  191      * revision, count, and one or more capabilities.
  192      */
  193     if (cpu_features) {
  194         ACPI_OBJECT_LIST arglist;
  195         uint32_t cap_set[3];
  196         ACPI_OBJECT arg[4];
  197         ACPI_STATUS status;
  198 
  199         /* UUID needed by _OSC evaluation */
  200         static uint8_t cpu_oscuuid[16] = {
  201            0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47,
  202            0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53
  203         };
  204 
  205         arglist.Pointer = arg;
  206         arglist.Count = 4;
  207         arg[0].Type = ACPI_TYPE_BUFFER;
  208         arg[0].Buffer.Length = sizeof(cpu_oscuuid);
  209         arg[0].Buffer.Pointer = cpu_oscuuid;    /* UUID */
  210         arg[1].Type = ACPI_TYPE_INTEGER;
  211         arg[1].Integer.Value = 1;               /* revision */
  212         arg[2].Type = ACPI_TYPE_INTEGER;
  213         arg[2].Integer.Value = 2;               /* # of capabilities integers */
  214         arg[3].Type = ACPI_TYPE_BUFFER;
  215         arg[3].Buffer.Length = sizeof(cap_set[0]) * 2; /* capabilities buffer */
  216         arg[3].Buffer.Pointer = (uint8_t *)cap_set;
  217         cap_set[0] = 0;
  218         cap_set[1] = cpu_features;
  219         status = AcpiEvaluateObject(handle, "_OSC", &arglist, NULL);
  220 
  221         if (!ACPI_SUCCESS(status)) {
  222             if (bootverbose)
  223                 device_printf(dev, "_OSC failed, use _PDC\n");
  224 
  225             arglist.Pointer = arg;
  226             arglist.Count = 1;
  227             arg[0].Type = ACPI_TYPE_BUFFER;
  228             arg[0].Buffer.Length = sizeof(cap_set);
  229             arg[0].Buffer.Pointer = (uint8_t *)cap_set;
  230             cap_set[0] = 1; /* revision */
  231             cap_set[1] = 1; /* # of capabilities integers */
  232             cap_set[2] = cpu_features;
  233             AcpiEvaluateObject(handle, "_PDC", &arglist, NULL);
  234         }
  235     }
  236 
  237     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1);
  238     if (child == NULL)
  239         return ENXIO;
  240     acpi_set_handle(child, handle);
  241     acpi_set_magic(child, cpu_id);
  242     sc->cpux_cst = child;
  243 
  244     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1);
  245     if (child == NULL)
  246         return ENXIO;
  247     acpi_set_handle(child, handle);
  248     acpi_set_magic(child, cpu_id);
  249 
  250     bus_generic_attach(dev);
  251 
  252     AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc);
  253 
  254     return 0;
  255 }
  256 
  257 /*
  258  * All resources are assigned directly to us by acpi,
  259  * so 'child' is bypassed here.
  260  */
  261 static struct resource_list *
  262 acpi_cpu_get_rlist(device_t dev, device_t child __unused)
  263 {
  264     return BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
  265 }
  266 
  267 static struct resource *
  268 acpi_cpu_alloc_resource(device_t dev, device_t child __unused,
  269                         int type, int *rid, u_long start, u_long end,
  270                         u_long count, u_int flags, int cpuid)
  271 {
  272     return BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid,
  273                               start, end, count, flags, cpuid);
  274 }
  275 
  276 static int
  277 acpi_cpu_release_resource(device_t dev, device_t child __unused,
  278                           int type, int rid, struct resource *r)
  279 {
  280     return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, rid, r);
  281 }
  282 
  283 /*
  284  * Find the nth present CPU and return its pc_cpuid as well as set the
  285  * pc_acpi_id from the most reliable source.
  286  */
  287 static int
  288 acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id)
  289 {
  290     struct mdglobaldata *md;
  291     uint32_t i;
  292 
  293     KASSERT(acpi_id != NULL, ("Null acpi_id"));
  294     KASSERT(cpu_id != NULL, ("Null cpu_id"));
  295     for (i = 0; i < ncpus; i++) {
  296         if ((smp_active_mask & CPUMASK(i)) == 0)
  297             continue;
  298         md = (struct mdglobaldata *)globaldata_find(i);
  299         KASSERT(md != NULL, ("no pcpu data for %d", i));
  300         if (idx-- == 0) {
  301             /*
  302              * If pc_acpi_id was not initialized (e.g., a non-APIC UP box)
  303              * override it with the value from the ASL.  Otherwise, if the
  304              * two don't match, prefer the MADT-derived value.  Finally,
  305              * return the pc_cpuid to reference this processor.
  306              */
  307             if (md->gd_acpi_id == 0xffffffff)
  308                 md->gd_acpi_id = *acpi_id;
  309             else if (md->gd_acpi_id != *acpi_id)
  310                 *acpi_id = md->gd_acpi_id;
  311             *cpu_id = md->mi.gd_cpuid;
  312             return 0;
  313         }
  314     }
  315     return ESRCH;
  316 }
  317 
  318 static void
  319 acpi_cpu_notify(ACPI_HANDLE handler __unused, UINT32 notify, void *xsc)
  320 {
  321     struct acpi_cpux_softc *sc = xsc;
  322 
  323     switch (notify) {
  324     case ACPI_NOTIFY_CX_STATES:
  325         if (sc->cpux_cst_notify != NULL)
  326             sc->cpux_cst_notify(sc->cpux_cst);
  327         break;
  328     }
  329 }

Cache object: 92c14752f20af2400f241ea8f383802b


[ 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.