From 511a9a6f8de5dc66d327a145669a0369d8023e72 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 4 Jan 2014 15:42:47 +0100
Subject: [PATCH 5/5] WIP tstate

---
 share/man/man4/acpi.4            |   8 +-
 sys/conf/files                   |   1 +
 sys/dev/acpica/Makefile          |   3 +-
 sys/dev/acpica/acpi_cpu.c        |   6 +
 sys/dev/acpica/acpi_cpu_tstate.c | 510 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 526 insertions(+), 2 deletions(-)
 create mode 100644 sys/dev/acpica/acpi_cpu_tstate.c

diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4
index cc1a324..2bd55fe 100644
--- a/share/man/man4/acpi.4
+++ b/share/man/man4/acpi.4
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man4/acpi.4,v 1.61.8.1 2009/04/15 03:14:26 kensmith Exp $
 .\"
-.Dd February 10, 2013
+.Dd September 13, 2013
 .Dt ACPI 4
 .Os
 .Sh NAME
@@ -339,6 +339,12 @@ Supports CPU speed-setting.
 Disabling
 .Dq Li cpu
 will also disable this device.
+.Dq Li cpu_tst
+.Pq Vt device
+Supports CPU throttling.
+Disabling
+.Dq Li cpu
+will also disable this device.
 .It Li ec
 .Pq Vt device
 Supports the ACPI Embedded Controller interface, used to communicate
diff --git a/sys/conf/files b/sys/conf/files
index 1aa421a..873423f 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2178,6 +2178,7 @@ ${OSACPI_MI_DIR}/acpi_cmbat.c		optional acpi
 ${OSACPI_MI_DIR}/acpi_cpu.c		optional acpi
 ${OSACPI_MI_DIR}/acpi_cpu_cstate.c	optional acpi
 ${OSACPI_MI_DIR}/acpi_cpu_pstate.c	optional acpi
+${OSACPI_MI_DIR}/acpi_cpu.tstate.c	optional acpi
 ${OSACPI_MI_DIR}/acpi_ec.c		optional acpi
 ${OSACPI_MI_DIR}/acpi_hpet.c		optional acpi
 ${OSACPI_MI_DIR}/acpi_if.m		optional acpi
diff --git a/sys/dev/acpica/Makefile b/sys/dev/acpica/Makefile
index 82a4746..f052c66 100644
--- a/sys/dev/acpica/Makefile
+++ b/sys/dev/acpica/Makefile
@@ -67,7 +67,8 @@ SRCS+=	utxferror.c utxfinit.c
 # OSD layer
 #
 SRCS+=  acpi.c acpi_acad.c acpi_battery.c acpi_button.c acpi_cmbat.c
-SRCS+=	acpi_cpu.c acpi_cpu_cstate.c acpi_cpu_pstate.c acpi_smbat.c
+SRCS+=	acpi_cpu.c acpi_cpu_cstate.c acpi_cpu_pstate.c acpi_cpu_tstate.c
+SRCS+=	acpi_smbat.c
 SRCS+=  acpi_ec.c acpi_isab.c acpi_lid.c
 SRCS+=  acpi_package.c
 # The PCI part of ACPI5 doesn't work with the current infrastructure
diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c
index de7db65..4703066 100644
--- a/sys/dev/acpica/acpi_cpu.c
+++ b/sys/dev/acpica/acpi_cpu.c
@@ -247,6 +247,12 @@ acpi_cpu_attach(device_t dev)
     acpi_set_handle(child, handle);
     acpi_set_magic(child, cpu_id);
 
+    child = BUS_ADD_CHILD(dev, dev, 0, "cpu_tst", -1);
+    if (child == NULL)
+	return ENXIO;
+    acpi_set_handle(child, handle);
+    acpi_set_magic(child, cpu_id);
+
     bus_generic_attach(dev);
 
     AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc);
diff --git a/sys/dev/acpica/acpi_cpu_tstate.c b/sys/dev/acpica/acpi_cpu_tstate.c
new file mode 100644
index 0000000..1695483
--- /dev/null
+++ b/sys/dev/acpica/acpi_cpu_tstate.c
@@ -0,0 +1,510 @@
+/*-
+ * Copyright (c) 2003-2005 Nate Lawson (SDG)
+ * Copyright (c) 2001 Michael Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/dev/acpica/acpi_throttle.c 246128 2013-01-30 18:01:20Z sbz $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include "acpi.h"
+#include "acpivar.h"
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT	ACPI_THROTTLE
+ACPI_MODULE_NAME("THROTTLE")
+
+/*
+ * Throttling provides relative frequency control.  It involves modulating
+ * the clock so that the CPU is active for only a fraction of the normal
+ * clock cycle.  It does not change voltage and so is less efficient than
+ * other mechanisms.  Since it is relative, it can be used in addition to
+ * absolute cpufreq drivers.  We support the ACPI 2.0 specification.
+ */
+
+struct acpi_tst_softc {
+	device_t	 cpu_dev;
+	ACPI_HANDLE	 cpu_handle;
+	uint32_t	 cpu_p_blk;	/* ACPI P_BLK location */
+	uint32_t	 cpu_p_blk_len;	/* P_BLK length (must be 6). */
+	struct resource	*cpu_p_cnt;	/* Throttling control register */
+	int		 cpu_p_type;	/* Resource type for cpu_p_cnt. */
+	uint32_t	 cpu_thr_state;	/* Current throttle setting. */
+};
+
+#define THR_GET_REG(reg) 					\
+	(bus_space_read_4(rman_get_bustag((reg)), 		\
+			  rman_get_bushandle((reg)), 0))
+#define THR_SET_REG(reg, val)					\
+	(bus_space_write_4(rman_get_bustag((reg)), 		\
+			   rman_get_bushandle((reg)), 0, (val)))
+
+/*
+ * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and
+ * reported to the user in hundredths of a percent.
+ */
+#define CPU_MAX_SPEED		(1 << cpu_duty_width)
+#define CPU_SPEED_PERCENT(x)	((10000 * (x)) / CPU_MAX_SPEED)
+#define CPU_SPEED_PRINTABLE(x)	(CPU_SPEED_PERCENT(x) / 10),	\
+				(CPU_SPEED_PERCENT(x) % 10)
+#define CPU_P_CNT_THT_EN	(1<<4)
+#define CPU_QUIRK_NO_THROTTLE	(1<<1)	/* Throttling is not usable. */
+
+static uint32_t	cpu_duty_offset;	/* Offset in P_CNT of throttle val. */
+static uint32_t	cpu_duty_width;		/* Bit width of throttle value. */
+static int	thr_rid;		/* Driver-wide resource id. */
+
+static int	acpi_tst_probe(device_t dev);
+static int	acpi_tst_attach(device_t dev);
+static int	acpi_tst_evaluate(struct acpi_tst_softc *sc);
+#if 0
+static int	acpi_tst_settings(device_t dev, struct cf_setting *sets,
+		    int *count);
+static int	acpi_tst_set(device_t dev, const struct cf_setting *set);
+static int	acpi_tst_get(device_t dev, struct cf_setting *set);
+static int	acpi_tst_type(device_t dev, int *type);
+#endif
+
+static device_method_t acpi_tst_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		acpi_tst_probe),
+	DEVMETHOD(device_attach,	acpi_tst_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t acpi_tst_driver = {
+	"cpu_tst",
+	acpi_tst_methods,
+	sizeof(struct acpi_tst_softc),
+};
+
+static devclass_t acpi_tst_devclass;
+DRIVER_MODULE(acpi_tst, cpu, acpi_tst_driver,
+    acpi_tst_devclass, NULL, NULL);
+MODULE_DEPEND(acpi_tst, acpi, 1, 1, 1);
+
+static int
+acpi_tst_probe(device_t dev)
+{
+	ACPI_BUFFER buf;
+	ACPI_HANDLE handle;
+	ACPI_STATUS status;
+	ACPI_OBJECT *obj;
+	int error;
+
+	error = ENXIO;
+
+	/* Check for a valid duty width and parent CPU type. */
+	if (acpi_disabled("cpu_tst") ||
+	    acpi_get_type(dev) != ACPI_TYPE_PROCESSOR ||
+	    AcpiGbl_FADT.DutyWidth == 0)
+		return (error);
+
+	handle = acpi_get_handle(dev);
+
+#ifdef __i386__
+	/*
+	 * On i386 platforms at least, ACPI throttling is accomplished by
+	 * the chipset modulating the STPCLK# pin based on the duty cycle.
+	 * Since p4tcc uses the same mechanism (but internal to the CPU),
+	 * we disable cpu_tst when p4tcc is also present.
+	 */
+	if (device_find_child(device_get_parent(dev), "p4tcc", -1) &&
+	    !resource_disabled("p4tcc", 0))
+		return (error);
+#endif
+
+	/*
+	 * Succeed if there is a non-NULL P_BLK and correct length, or
+	 * if the _PTC method is present.
+	 */
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, NULL, NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		if (bootverbose) {
+			device_printf(dev, "P_BLK is NULL - %s\n",
+			    AcpiFormatException(status));
+		}
+		return (error);
+	}
+
+	/* Check _PTC package */
+	status = AcpiEvaluateObject(handle, "_PTC", NULL, NULL);
+	obj = (ACPI_OBJECT *)buf.Pointer;
+	if ((obj->Processor.PblkAddress && obj->Processor.PblkLength < 4) &&
+	    ACPI_FAILURE(status)) {
+		if (bootverbose) {
+			device_printf(dev, "Can't get _PTC package - %s\n",
+			    AcpiFormatException(status));
+		}
+		return (error);
+	}
+#if 0
+	if (!ACPI_PKG_VALID_EQ(obj, 2)) {
+		device_printf(dev, "Invalid _PTC package\n");
+		goto done;
+	}
+#else
+	device_printf(dev, "_PTC count: %d\n", obj->Package.Count);
+#endif
+	AcpiOsFree(obj);
+
+	/* Check _TSS package */
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_TSS", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		if (bootverbose) {
+			device_printf(dev, "Can't get _TSS package - %s\n",
+			    AcpiFormatException(status));
+		}
+		return (error);
+	}
+	obj = (ACPI_OBJECT *)buf.Pointer;
+#if 0
+	if (!ACPI_PKG_VALID_EQ(obj, 1)) {
+		device_printf(dev, "Invalid _TSS package\n");
+		goto done;
+	}
+#else
+	device_printf(dev, "_TSS count: %d\n", obj->Package.Count);
+#endif
+	AcpiOsFree(obj);
+
+	/* Check _TPC package */
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_TPC", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		if (bootverbose) {
+			device_printf(dev, "Can't get _TPC package - %s\n",
+			    AcpiFormatException(status));
+		}
+		return (error);
+	}
+	obj = (ACPI_OBJECT *)buf.Pointer;
+#if 0
+	if (!ACPI_PKG_VALID_EQ(obj, 1)) {
+		device_printf(dev, "Invalid _TPC package\n");
+		goto done;
+	}
+#else
+	device_printf(dev, "_TPC count: %d\n", obj->Package.Count);
+#endif
+	AcpiOsFree(obj);
+
+	/* Check _TSD package */
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_TSD", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		if (bootverbose) {
+			device_printf(dev, "Can't get _TSD package - %s\n",
+			    AcpiFormatException(status));
+		}
+		return (error);
+	}
+	obj = (ACPI_OBJECT *)buf.Pointer;
+#if 0
+	if (!ACPI_PKG_VALID_EQ(obj, 1)) {
+		device_printf(dev, "Invalid _TSD package\n");
+		goto done;
+	}
+#else
+	device_printf(dev, "_TSD count: %d\n", obj->Package.Count);
+#endif
+	AcpiOsFree(obj);
+
+	/* Check _TDL package */
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_TDL", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		if (bootverbose) {
+			device_printf(dev, "Can't get _TDL package - %s\n",
+			    AcpiFormatException(status));
+		}
+		return (error);
+	}
+	obj = (ACPI_OBJECT *)buf.Pointer;
+#if 0
+	if (!ACPI_PKG_VALID_EQ(obj, 1)) {
+		device_printf(dev, "Invalid _TDL package\n");
+		goto done;
+	}
+#else
+	device_printf(dev, "_TDL count: %d\n", obj->Package.Count);
+#endif
+
+	device_set_desc(dev, "ACPI CPU T-State");
+	error = 0;
+
+done:
+	AcpiOsFree(obj);
+
+	return (error);
+}
+
+static int
+acpi_tst_attach(device_t dev)
+{
+#if 0
+	struct acpi_tst_softc *sc;
+#if 0
+	struct cf_setting set;
+#endif
+	ACPI_BUFFER buf;
+	ACPI_OBJECT *obj;
+	ACPI_STATUS status;
+	int error;
+
+	sc = device_get_softc(dev);
+	sc->cpu_dev = dev;
+	sc->cpu_handle = acpi_get_handle(dev);
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "attach failed to get Processor obj - %s\n",
+		    AcpiFormatException(status));
+		return (ENXIO);
+	}
+	obj = (ACPI_OBJECT *)buf.Pointer;
+	sc->cpu_p_blk = obj->Processor.PblkAddress;
+	sc->cpu_p_blk_len = obj->Processor.PblkLength;
+	AcpiOsFree(obj);
+
+	/* Attempt to attach the actual throttling register. */
+	error = acpi_tst_evaluate(sc);
+	if (error)
+		return (error);
+
+	/*
+	 * Set our initial frequency to the highest since some systems
+	 * seem to boot with this at the lowest setting.
+	 */
+#if 0
+	set.freq = 10000;
+	acpi_tst_set(dev, &set);
+
+	/* Everything went ok, register with cpufreq(4). */
+	cpufreq_register(dev);
+#endif
+#else
+	return (0);
+#endif
+}
+
+static int
+acpi_tst_evaluate(struct acpi_tst_softc *sc)
+{
+	uint32_t duty_end;
+	ACPI_BUFFER buf;
+	ACPI_OBJECT obj;
+	ACPI_GENERIC_ADDRESS gas;
+	ACPI_STATUS status;
+
+	/* Get throttling parameters from the FADT.  0 means not supported. */
+	if (device_get_unit(sc->cpu_dev) == 0) {
+		cpu_duty_offset = AcpiGbl_FADT.DutyOffset;
+		cpu_duty_width = AcpiGbl_FADT.DutyWidth;
+	}
+	if (cpu_duty_width == 0)
+		return (ENXIO);
+
+	/* Validate the duty offset/width. */
+	duty_end = cpu_duty_offset + cpu_duty_width - 1;
+	if (duty_end > 31) {
+		device_printf(sc->cpu_dev,
+		    "CLK_VAL field overflows P_CNT register\n");
+		return (ENXIO);
+	}
+	if (cpu_duty_offset <= 4 && duty_end >= 4) {
+		device_printf(sc->cpu_dev,
+		    "CLK_VAL field overlaps THT_EN bit\n");
+		return (ENXIO);
+	}
+
+	/*
+	 * If not present, fall back to using the processor's P_BLK to find
+	 * the P_CNT register.
+	 *
+	 * Note that some systems seem to duplicate the P_BLK pointer
+	 * across multiple CPUs, so not getting the resource is not fatal.
+	 */
+	buf.Pointer = &obj;
+	buf.Length = sizeof(obj);
+	status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf);
+	if (ACPI_SUCCESS(status)) {
+		if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) {
+			device_printf(sc->cpu_dev, "_PTC buffer too small\n");
+			return (ENXIO);
+		}
+		memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas));
+		acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
+		    &gas, &sc->cpu_p_cnt, 0);
+		if (sc->cpu_p_cnt != NULL && bootverbose) {
+			device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n",
+			    gas.Address);
+		}
+	}
+
+	/* If _PTC not present or other failure, try the P_BLK. */
+	if (sc->cpu_p_cnt == NULL) {
+		/*
+		 * The spec says P_BLK must be 6 bytes long.  However, some
+		 * systems use it to indicate a fractional set of features
+		 * present so we take anything >= 4.
+		 */
+		if (sc->cpu_p_blk_len < 4)
+			return (ENXIO);
+		gas.Address = sc->cpu_p_blk;
+		gas.SpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
+		gas.BitWidth = 32;
+		acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
+		    &gas, &sc->cpu_p_cnt, 0);
+		if (sc->cpu_p_cnt != NULL) {
+			if (bootverbose)
+				device_printf(sc->cpu_dev,
+				    "P_CNT from P_BLK %#x\n", sc->cpu_p_blk);
+		} else {
+			device_printf(sc->cpu_dev, "failed to attach P_CNT\n");
+			return (ENXIO);
+		}
+	}
+	thr_rid++;
+
+	return (0);
+}
+
+#if 0
+static int
+acpi_tst_settings(device_t dev, struct cf_setting *sets, int *count)
+{
+	int i, speed;
+
+	if (sets == NULL || count == NULL)
+		return (EINVAL);
+	if (*count < CPU_MAX_SPEED)
+		return (E2BIG);
+
+	/* Return a list of valid settings for this driver. */
+	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED);
+	for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) {
+		sets[i].freq = CPU_SPEED_PERCENT(speed);
+		sets[i].dev = dev;
+	}
+	*count = CPU_MAX_SPEED;
+
+	return (0);
+}
+
+static int
+acpi_tst_set(device_t dev, const struct cf_setting *set)
+{
+	struct acpi_tst_softc *sc;
+	uint32_t clk_val, p_cnt, speed;
+
+	if (set == NULL)
+		return (EINVAL);
+	sc = device_get_softc(dev);
+
+	/*
+	 * Validate requested state converts to a duty cycle that is an
+	 * integer from [1 .. CPU_MAX_SPEED].
+	 */
+	speed = set->freq * CPU_MAX_SPEED / 10000;
+	if (speed * 10000 != set->freq * CPU_MAX_SPEED ||
+	    speed < 1 || speed > CPU_MAX_SPEED)
+		return (EINVAL);
+
+	/* If we're at this setting, don't bother applying it again. */
+	if (speed == sc->cpu_thr_state)
+		return (0);
+
+	/* Get the current P_CNT value and disable throttling */
+	p_cnt = THR_GET_REG(sc->cpu_p_cnt);
+	p_cnt &= ~CPU_P_CNT_THT_EN;
+	THR_SET_REG(sc->cpu_p_cnt, p_cnt);
+
+	/* If we're at maximum speed, that's all */
+	if (speed < CPU_MAX_SPEED) {
+		/* Mask the old CLK_VAL off and OR in the new value */
+		clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset;
+		p_cnt &= ~clk_val;
+		p_cnt |= (speed << cpu_duty_offset);
+
+		/* Write the new P_CNT value and then enable throttling */
+		THR_SET_REG(sc->cpu_p_cnt, p_cnt);
+		p_cnt |= CPU_P_CNT_THT_EN;
+		THR_SET_REG(sc->cpu_p_cnt, p_cnt);
+	}
+	sc->cpu_thr_state = speed;
+
+	return (0);
+}
+
+static int
+acpi_tst_get(device_t dev, struct cf_setting *set)
+{
+	struct acpi_tst_softc *sc;
+	uint32_t p_cnt, clk_val;
+
+	if (set == NULL)
+		return (EINVAL);
+	sc = device_get_softc(dev);
+
+	/* Get the current throttling setting from P_CNT. */
+	p_cnt = THR_GET_REG(sc->cpu_p_cnt);
+	clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1);
+	sc->cpu_thr_state = clk_val;
+
+	memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set));
+	set->freq = CPU_SPEED_PERCENT(clk_val);
+	set->dev = dev;
+
+	return (0);
+}
+
+static int
+acpi_tst_type(device_t dev, int *type)
+{
+
+	if (type == NULL)
+		return (EINVAL);
+
+	*type = CPUFREQ_TYPE_RELATIVE;
+	return (0);
+}
+#endif
-- 
1.8.4.3

