patch-2.4.0-test3 linux/drivers/acpi/hardware/hwxface.c

Next file: linux/drivers/acpi/include/acenv.h
Previous file: linux/drivers/acpi/hardware/hwregs.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test2/linux/drivers/acpi/hardware/hwxface.c linux/drivers/acpi/hardware/hwxface.c
@@ -0,0 +1,576 @@
+
+/******************************************************************************
+ *
+ * Name: hwxface.c - Hardware access external interfaces
+ *
+ *****************************************************************************/
+
+/*
+ *  Copyright (C) 2000 R. Byron Moore
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "acpi.h"
+#include "namesp.h"
+#include "hardware.h"
+
+#define _COMPONENT          HARDWARE
+	 MODULE_NAME         ("hwxface");
+
+
+/******************************************************************************
+ *
+ * Hardware globals
+ *
+ ******************************************************************************/
+
+
+ACPI_C_STATE_HANDLER        acpi_hw_cx_handlers[MAX_CX_STATES] =
+			  {NULL, acpi_hw_enter_c1, NULL, NULL};
+
+u32                         acpi_hw_active_cx_state = 1;
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    Acpi_get_processor_throttling_info
+ *
+ * PARAMETERS:  Processor_handle    - handle for the cpu to get info about
+ *              User_buffer         - caller supplied buffer
+ *
+ * RETURN:      Status of function
+ *
+ * DESCRIPTION: Get throttling capabilities for the processor, this routine
+ *              builds the data directly into the callers buffer
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_get_processor_throttling_info (
+	ACPI_HANDLE             processor_handle,
+	ACPI_BUFFER             *user_buffer)
+{
+	NATIVE_UINT             percent_step;
+	NATIVE_UINT             next_percent;
+	NATIVE_UINT             num_throttle_states;
+	NATIVE_UINT             buffer_space_needed;
+	NATIVE_UINT             i;
+	u8                      duty_offset;
+	u8                      duty_width;
+	ACPI_NAMED_OBJECT       *cpu_entry;
+	ACPI_OBJECT_INTERNAL    *cpu_obj;
+	ACPI_CPU_THROTTLING_STATE *state_ptr;
+
+
+	/*
+	 *  Have to at least have a buffer to return info in
+	 */
+	if (!user_buffer) {
+		return(AE_BAD_PARAMETER);
+	}
+
+	/*
+	 *  Convert and validate the device handle
+	 */
+
+	cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+	if (!cpu_entry) {
+		return (AE_BAD_PARAMETER);
+	}
+
+   /*
+	*   Check for an existing internal object
+	*/
+
+	cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+	if (!cpu_obj) {
+		return (AE_NOT_FOUND);
+	}
+
+	duty_offset = acpi_gbl_FACP->duty_offset;
+	duty_width = acpi_gbl_FACP->duty_width;
+
+	/*
+	 *  P0 must always have a P_BLK all others may be null
+	 *  in either case, we can't thottle a processor that has no P_BLK
+	 *
+	 *  Also if no Duty width, one state and it is 100%
+	 *
+	 */
+	if (!cpu_obj->processor.pblk_length || !duty_width ||
+		(0xFFFF < cpu_obj->processor.pblk_address))
+	{
+		/*
+		 *  Acpi_even though we can't throttle, we still have one state (100%)
+		 */
+		num_throttle_states = 1;
+	}
+
+	else {
+		num_throttle_states = (int) acpi_hw_local_pow (2,duty_width);
+	}
+
+	buffer_space_needed = num_throttle_states * sizeof (ACPI_CPU_THROTTLING_STATE);
+
+	if ((user_buffer->length < buffer_space_needed) || !user_buffer->pointer) {
+		user_buffer->length = buffer_space_needed;
+		return (AE_BUFFER_OVERFLOW);
+	}
+
+	user_buffer->length = buffer_space_needed;
+	state_ptr           = (ACPI_CPU_THROTTLING_STATE *) user_buffer->pointer;
+	percent_step        = 1000 / num_throttle_states;
+
+	/*
+	 * Build each entry in the buffer.  Note that we're using the value
+	 * 1000 and dividing each state by 10 to better avoid round-off
+	 * accumulation.  Also note that the throttling STATES are ordered
+	 * sequentially from 100% (state 0) on down (e.g. 87.5% = state 1),
+	 * which is exactly opposite from duty cycle values (12.5% = state 1).
+	 */
+	for (i = 0, next_percent = 1000; i < num_throttle_states; i++) {
+		state_ptr[i].state_number = i;
+		state_ptr[i].percent_of_clock = next_percent / 10;
+		next_percent -= percent_step;
+	}
+
+	return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    Acpi_get_processor_throttling_state
+ *
+ * PARAMETERS:  Processor_handle    - handle for the cpu to throttle
+ *              Throttle_state      - throttling state to enter
+ *
+ * RETURN:      Status of function
+ *
+ * DESCRIPTION: Get current hardware throttling state
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_get_processor_throttling_state (
+	ACPI_HANDLE             processor_handle,
+	u32                     *throttle_state)
+{
+	ACPI_NAMED_OBJECT       *cpu_entry;
+	ACPI_OBJECT_INTERNAL    *cpu_obj;
+	u32                     num_throttle_states;
+	u32                     duty_cycle;
+	u8                      duty_offset;
+	u8                      duty_width;
+
+
+	/* Convert and validate the device handle */
+
+	cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+	if (!cpu_entry || !throttle_state) {
+		return (AE_BAD_PARAMETER);
+	}
+
+   /* Check for an existing internal object */
+
+	cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+	if (!cpu_obj) {
+		return (AE_NOT_FOUND);
+	}
+
+	duty_offset = acpi_gbl_FACP->duty_offset;
+	duty_width = acpi_gbl_FACP->duty_width;
+
+	/*
+	 *  Must have a valid P_BLK P0 must have a P_BLK all others may be null
+	 *  in either case, we can't thottle a processor that has no P_BLK
+	 *  that means we are in the only supported state (0 - 100%)
+	 *
+	 *  also, if Duty_width is zero there are no additional states
+	 */
+	if (!cpu_obj->processor.pblk_length || !duty_width ||
+		(0xFFFF < cpu_obj->processor.pblk_address))
+	{
+		*throttle_state = 0;
+		return(AE_OK);
+	}
+
+	num_throttle_states = (u32) acpi_hw_local_pow (2,duty_width);
+
+	/*
+	 *  Get the current duty cycle value.
+	 */
+	duty_cycle = acpi_hw_get_duty_cycle (duty_offset,
+			   cpu_obj->processor.pblk_address,
+			   num_throttle_states);
+
+	/*
+	 * Convert duty cycle to throttling state (invert).
+	 */
+	if (duty_cycle == 0) {
+		*throttle_state = 0;
+	}
+
+	else {
+		*throttle_state = num_throttle_states - duty_cycle;
+	}
+
+	return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    Acpi_set_processor_throttling_state
+ *
+ * PARAMETERS:  Processor_handle    - handle for the cpu to throttle
+ *              Throttle_state      - throttling state to enter
+ *
+ * RETURN:      Status of function
+ *
+ * DESCRIPTION: Set hardware into requested throttling state, the handle
+ *              passed in must have a valid P_BLK
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_set_processor_throttling_state (
+	ACPI_HANDLE             processor_handle,
+	u32                     throttle_state)
+{
+	ACPI_NAMED_OBJECT      *cpu_entry;
+	ACPI_OBJECT_INTERNAL   *cpu_obj;
+	u32                     num_throttle_states = 0;
+	u8                      duty_offset = 0;
+	u8                      duty_width = 0;
+	u32                     duty_cycle = 0;
+
+
+	/* Convert and validate the device handle */
+
+	cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+	if (!cpu_entry) {
+		return (AE_BAD_PARAMETER);
+	}
+
+   /* Check for an existing internal object */
+
+	cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+	if (!cpu_obj) {
+		return (AE_NOT_FOUND);
+	}
+
+	duty_offset = acpi_gbl_FACP->duty_offset;
+	duty_width = acpi_gbl_FACP->duty_width;
+
+	/*
+	 *  Must have a valid P_BLK P0 must have a P_BLK all others may be null
+	 *  in either case, we can't thottle a processor that has no P_BLK
+	 *  that means we are in the only supported state (0 - 100%)
+	 *
+	 *  also, if Duty_width is zero there are no additional states
+	 */
+	if (!cpu_obj->processor.pblk_length || !duty_width ||
+		(0xFFFF < cpu_obj->processor.pblk_address))
+	{
+		/*
+		 *  If caller wants to set the state to the only state we handle
+		 *  we're done.
+		 */
+		if (throttle_state == 0) {
+			return (AE_OK);
+		}
+
+		/*
+		 *  Can't set this state
+		 */
+		return (AE_SUPPORT);
+	}
+
+	num_throttle_states = (int) acpi_hw_local_pow (2,duty_width);
+
+	/*
+	 * Convert throttling state to duty cycle (invert).
+	 */
+	if (throttle_state > 0) {
+		duty_cycle = num_throttle_states - throttle_state;
+	}
+
+	/*
+	 *  Turn off throttling (don't muck with the h/w while throttling).
+	 */
+	acpi_hw_disable_throttling (cpu_obj->processor.pblk_address);
+
+	/*
+	 *  Program the throttling state.
+	 */
+	acpi_hw_program_duty_cycle (duty_offset, duty_cycle,
+			 cpu_obj->processor.pblk_address, num_throttle_states);
+
+	/*
+	 *  Only enable throttling for non-zero states (0 - 100%)
+	 */
+	if (throttle_state) {
+		acpi_hw_enable_throttling (cpu_obj->processor.pblk_address);
+	}
+
+	return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    Acpi_get_processor_cx_info
+ *
+ * PARAMETERS:  Processor_handle    - handle for the cpu return info about
+ *              User_buffer         - caller supplied buffer
+ *
+ * RETURN:      Status of function
+ *
+ * DESCRIPTION: Get Cx state latencies, this routine
+ *              builds the data directly into the callers buffer
+ *
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_get_processor_cx_info (
+	ACPI_HANDLE             processor_handle,
+	ACPI_BUFFER             *user_buffer)
+{
+	ACPI_STATUS             status = AE_OK;
+	u32                     cx_state_latencies[4] = {0, 0, 0, 0};
+	NATIVE_UINT             buffer_space_needed = 0;
+	ACPI_CX_STATE           *state_ptr = NULL;
+	NATIVE_UINT             i = 0;
+
+
+	/*
+	 *  Have to at least have a buffer to return info in
+	 */
+	if (!user_buffer) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	status = acpi_hw_get_cx_info (cx_state_latencies);
+	if (ACPI_FAILURE (status)) {
+		return (status);
+	}
+
+	buffer_space_needed = 4 * sizeof (ACPI_CX_STATE);
+
+	if ((user_buffer->length < buffer_space_needed) || !user_buffer->pointer) {
+		user_buffer->length = buffer_space_needed;
+		return (AE_BUFFER_OVERFLOW);
+	}
+
+	user_buffer->length = buffer_space_needed;
+
+	state_ptr = (ACPI_CX_STATE *) user_buffer->pointer;
+
+	for (i = 0; i < 4; i++) {
+		state_ptr[i].state_number = i;
+		state_ptr[i].latency = cx_state_latencies[i];
+	}
+
+	return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    Acpi_set_processor_sleep_state
+ *
+ * PARAMETERS:  Processor_handle    - handle for the cpu return info about
+ *              Cx_state            - the Cx sleeping state (C1-C3) to make
+ *                                      'active'
+ *
+ * RETURN:      Status of function
+ *
+ * DESCRIPTION: Sets which Cx state will be used during calls to
+ *              Acpi_processor_sleep ()
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_set_processor_sleep_state (
+	ACPI_HANDLE             processor_handle,
+	u32                     cx_state)
+{
+	ACPI_STATUS             status;
+
+
+	status = acpi_hw_set_cx (cx_state);
+
+	return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    Acpi_processor_sleep
+ *
+ * PARAMETERS:  Processor_handle    - handle for the cpu to put to sleep (Cx)
+ *              Time_sleeping       - time (in microseconds) elapsed while
+ *                                      sleeping
+ *
+ * RETURN:      Status of function
+ *
+ * DESCRIPTION: Puts the processor into the currently active sleep state (Cx)
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_processor_sleep (
+	ACPI_HANDLE             processor_handle,
+	u32                     *pm_timer_ticks)
+{
+	ACPI_NAMED_OBJECT       *cpu_entry = NULL;
+	ACPI_OBJECT_INTERNAL    *cpu_obj = NULL;
+	ACPI_IO_ADDRESS         pblk_address = 0;
+
+
+	/*
+	 * Convert Processor_handle to Pblk_addres...
+	 */
+
+	/* Convert and validate the device handle */
+
+	cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+	if (!cpu_entry) {
+		return AE_BAD_PARAMETER;
+	}
+
+   /* Check for an existing internal object */
+
+	cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+	if (!cpu_obj) {
+		return AE_NOT_FOUND;
+	}
+
+	/* Get the processor register block (P_BLK) address */
+
+	pblk_address = cpu_obj->processor.pblk_address;
+	if (!cpu_obj->processor.pblk_length) {
+		/* Ensure a NULL addresss (note that P_BLK isn't required for C1) */
+
+		pblk_address = 0;
+	}
+
+	/*
+	 * Enter the currently active Cx sleep state.
+	 */
+	return acpi_hw_enter_cx (pblk_address, pm_timer_ticks);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION:    Acpi_get_timer
+ *
+ * PARAMETERS:  none
+ *
+ * RETURN:      Current value of the ACPI PMT (timer)
+ *
+ * DESCRIPTION: Obtains current value of ACPI PMT
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_timer (
+	u32                     *out_ticks)
+{
+
+	if (!out_ticks) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	*out_ticks = acpi_hw_pmt_ticks ();
+
+	return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION:    Acpi_set_firmware_waking_vector
+ *
+ * PARAMETERS:  Physical_address    - Physical address of ACPI real mode
+ *                                    entry point.
+ *
+ * RETURN:      AE_OK or AE_ERROR
+ *
+ * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_set_firmware_waking_vector (
+	void                    *physical_address)
+{
+
+	/* Make sure that we have an FACS */
+
+	if (!acpi_gbl_FACS) {
+		return (AE_NO_ACPI_TABLES);
+	}
+
+	/* Set the vector */
+
+	* ((void **) acpi_gbl_FACS->firmware_waking_vector) = physical_address;
+
+	return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION:    Acpi_get_firmware_waking_vector
+ *
+ * PARAMETERS:  *Physical_address   - Output buffer where contents of
+ *                                    the d_firmware_waking_vector field of
+ *                                    the FACS will be stored.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_firmware_waking_vector (
+	void                    **physical_address)
+{
+
+	if (!physical_address) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	/* Make sure that we have an FACS */
+
+	if (!acpi_gbl_FACS) {
+		return (AE_NO_ACPI_TABLES);
+	}
+
+	/* Get the vector */
+
+	*physical_address = * ((void **) acpi_gbl_FACS->firmware_waking_vector);
+
+
+	return (AE_OK);
+}
+
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)