Home | History | Annotate | Line # | Download | only in acpi
      1 /* $NetBSD: acpi_pdc.c,v 1.2 2011/06/20 15:39:54 jruoho Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2010, 2011 Jukka Ruohonen <jruohonen (at) iki.fi>
      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  *
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: acpi_pdc.c,v 1.2 2011/06/20 15:39:54 jruoho Exp $");
     31 
     32 #include <sys/param.h>
     33 
     34 #include <x86/cpu.h>
     35 #include <x86/cputypes.h>
     36 #include <x86/cpuvar.h>
     37 
     38 #include <dev/acpi/acpireg.h>
     39 #include <dev/acpi/acpivar.h>
     40 #include <dev/acpi/acpi_cpu.h>
     41 
     42 #include <machine/acpi_machdep.h>
     43 
     44 #define _COMPONENT	ACPI_BUS_COMPONENT
     45 ACPI_MODULE_NAME	("acpi_pdc")
     46 
     47 static uint32_t		flags = 0;
     48 
     49 static ACPI_STATUS	acpi_md_pdc_walk(ACPI_HANDLE, uint32_t,void *,void **);
     50 static void		acpi_md_pdc_set(ACPI_HANDLE, uint32_t);
     51 
     52 uint32_t
     53 acpi_md_pdc(void)
     54 {
     55 	struct cpu_info *ci = curcpu();
     56 	uint32_t regs[4];
     57 
     58 	if (flags != 0)
     59 		return flags;
     60 
     61 	if (cpu_vendor != CPUVENDOR_IDT &&
     62 	    cpu_vendor != CPUVENDOR_INTEL)
     63 		return 0;
     64 
     65 	/*
     66 	 * Basic SMP C-states (required for e.g. _CST).
     67 	 */
     68 	flags |= ACPICPU_PDC_C_C1PT | ACPICPU_PDC_C_C2C3;
     69 
     70 	/*
     71 	 * Claim to support dependency coordination.
     72 	 */
     73 	flags |= ACPICPU_PDC_P_SW | ACPICPU_PDC_C_SW | ACPICPU_PDC_T_SW;
     74 
     75         /*
     76 	 * If MONITOR/MWAIT is available, announce
     77 	 * support for native instructions in all C-states.
     78 	 */
     79         if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0)
     80 		flags |= ACPICPU_PDC_C_C1_FFH | ACPICPU_PDC_C_C2C3_FFH;
     81 
     82 	/*
     83 	 * Set native P- and T-states, if available.
     84 	 */
     85         if ((ci->ci_feat_val[1] & CPUID2_EST) != 0)
     86 		flags |= ACPICPU_PDC_P_FFH;
     87 
     88 	if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0)
     89 		flags |= ACPICPU_PDC_T_FFH;
     90 
     91 	/*
     92 	 * Declare support for APERF and MPERF.
     93 	 */
     94 	if (cpuid_level >= 0x06) {
     95 
     96 		x86_cpuid(0x00000006, regs);
     97 
     98 		if ((regs[2] & CPUID_DSPM_HWF) != 0)
     99 			flags |= ACPICPU_PDC_P_HWF;
    100 	}
    101 
    102 	/*
    103 	 * As the _PDC must be evaluated before the internal namespace
    104 	 * is built, we have no option but to walk with the interpreter.
    105 	 */
    106 	(void)AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
    107 	    UINT32_MAX, acpi_md_pdc_walk, NULL, NULL, NULL);
    108 
    109 	return flags;
    110 }
    111 
    112 static ACPI_STATUS
    113 acpi_md_pdc_walk(ACPI_HANDLE hdl, uint32_t level, void *aux, void **sta)
    114 {
    115 	struct cpu_info *ci;
    116 
    117 	ci = acpi_match_cpu_handle(hdl);
    118 
    119 	if (ci != NULL)
    120 		acpi_md_pdc_set(hdl, flags);
    121 
    122 	return AE_OK;
    123 }
    124 
    125 static void
    126 acpi_md_pdc_set(ACPI_HANDLE hdl, uint32_t val)
    127 {
    128 	ACPI_OBJECT_LIST arg;
    129 	ACPI_OBJECT obj;
    130 	uint32_t cap[3];
    131 
    132 	arg.Count = 1;
    133 	arg.Pointer = &obj;
    134 
    135 	cap[0] = ACPICPU_PDC_REVID;
    136 	cap[1] = 1;
    137 	cap[2] = val;
    138 
    139 	obj.Type = ACPI_TYPE_BUFFER;
    140 	obj.Buffer.Length = sizeof(cap);
    141 	obj.Buffer.Pointer = (void *)cap;
    142 
    143 	(void)AcpiEvaluateObject(hdl, "_PDC", &arg, NULL);
    144 }
    145