The embedded controller handled timeouts wrong in several ways:
* It confused ms and usecs for ec_timeout * It tried to handle waiting like on platforms that can't do better timing than ms. Haiku can do much better, which simplifies the code a lot. This should fix #4623 and #5825. At least on my laptop BatteryStatus never shows weirdness or reports errors in syslog. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36511 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
56943eaa58
commit
8b0107016a
@ -50,10 +50,7 @@
|
||||
// name of pnp generator of path ids
|
||||
#define ACPI_EC_PATHID_GENERATOR "embedded_controller/path_id"
|
||||
|
||||
// cpu frequency in Hz
|
||||
int64 gHz;
|
||||
|
||||
|
||||
|
||||
uint8
|
||||
bus_space_read_1(int address)
|
||||
{
|
||||
@ -259,12 +256,6 @@ static status_t
|
||||
embedded_controller_init_driver(device_node* dev, void** _driverCookie)
|
||||
{
|
||||
TRACE("init driver\n");
|
||||
// first get the cpu speed, needed to calculate a timeout
|
||||
// ToDo: catch frequency changes
|
||||
system_info systemInfo;
|
||||
if (get_system_info(&systemInfo) != B_OK)
|
||||
return B_ERROR;
|
||||
gHz = systemInfo.cpu_clock_speed;
|
||||
|
||||
acpi_ec_cookie* sc;
|
||||
sc = (acpi_ec_cookie*) malloc(sizeof(acpi_ec_cookie));
|
||||
@ -689,7 +680,7 @@ EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 gen_count)
|
||||
|
||||
// int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending;
|
||||
int need_poll = ec_polled_mode || sc->ec_suspending;
|
||||
|
||||
|
||||
/*
|
||||
* The main CPU should be much faster than the EC. So the status should
|
||||
* be "not ready" when we start waiting. But if the main CPU is really
|
||||
@ -716,26 +707,17 @@ EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 gen_count)
|
||||
|
||||
/* Wait for event by polling or GPE (interrupt). */
|
||||
if (need_poll) {
|
||||
count = ec_timeout / EC_POLL_DELAY;
|
||||
count = (ec_timeout * 1000) / EC_POLL_DELAY;
|
||||
if (count == 0)
|
||||
count = 1;
|
||||
for (i = 0; i < count; i++) {
|
||||
status = EcCheckStatus(sc, "poll", event);
|
||||
if (status == B_OK)
|
||||
if (status == AE_OK)
|
||||
break;
|
||||
spin(EC_POLL_DELAY);
|
||||
}
|
||||
} else {
|
||||
bigtime_t slp_ival = gHz / 1000000;
|
||||
if (slp_ival != 0) {
|
||||
count = ec_timeout;
|
||||
} else {
|
||||
/* hz has less than 1 ms resolution so scale timeout. */
|
||||
slp_ival = 1;
|
||||
count = ec_timeout / (1000 / gHz);
|
||||
}
|
||||
|
||||
count = ec_timeout;
|
||||
bigtime_t slp_ival = system_time() + ec_timeout * 1000;
|
||||
|
||||
/*
|
||||
* Wait for the GPE to signal the status changed, checking the
|
||||
@ -743,7 +725,8 @@ EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 gen_count)
|
||||
* GPE for an event we're not interested in here (i.e., SCI for
|
||||
* EC query).
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
status_t waitStatus = B_NO_ERROR;
|
||||
while (waitStatus != B_TIMED_OUT) {
|
||||
if (gen_count != sc->ec_gencount) {
|
||||
/*
|
||||
* Record new generation count. It's possible the GPE was
|
||||
@ -756,7 +739,8 @@ EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 gen_count)
|
||||
if (status == AE_OK)
|
||||
break;
|
||||
}
|
||||
sc->ec_condition_var.Wait(B_RELATIVE_TIMEOUT, slp_ival);
|
||||
waitStatus = sc->ec_condition_var.Wait(B_ABSOLUTE_TIMEOUT,
|
||||
slp_ival);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -768,7 +752,7 @@ EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 gen_count)
|
||||
if (status != AE_OK) {
|
||||
status = EcCheckStatus(sc, "sleep_end", event);
|
||||
TRACE("wait timed out (%sresponse), forcing polled mode\n",
|
||||
status == B_OK ? "" : "no ");
|
||||
status == AE_OK ? "" : "no ");
|
||||
ec_polled_mode = TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -55,17 +55,17 @@ extern "C" {
|
||||
|
||||
#define ACPI_REGION_DEACTIVATE 1
|
||||
|
||||
#define ACPI_READ 0
|
||||
#define ACPI_WRITE 1
|
||||
#define ACPI_READ 0
|
||||
#define ACPI_WRITE 1
|
||||
|
||||
typedef uint8 EC_COMMAND;
|
||||
typedef uint8 EC_COMMAND;
|
||||
|
||||
#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00)
|
||||
#define EC_COMMAND_READ ((EC_COMMAND) 0x80)
|
||||
#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81)
|
||||
#define EC_COMMAND_BURST_ENABLE ((EC_COMMAND) 0x82)
|
||||
#define EC_COMMAND_BURST_DISABLE ((EC_COMMAND) 0x83)
|
||||
#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84)
|
||||
#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00)
|
||||
#define EC_COMMAND_READ ((EC_COMMAND) 0x80)
|
||||
#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81)
|
||||
#define EC_COMMAND_BURST_ENABLE ((EC_COMMAND) 0x82)
|
||||
#define EC_COMMAND_BURST_DISABLE ((EC_COMMAND) 0x83)
|
||||
#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84)
|
||||
|
||||
/*
|
||||
* EC_STATUS:
|
||||
@ -88,48 +88,48 @@ typedef uint8 EC_COMMAND;
|
||||
*
|
||||
*/
|
||||
|
||||
typedef uint8 EC_STATUS;
|
||||
typedef uint8 EC_STATUS;
|
||||
|
||||
#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01)
|
||||
#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02)
|
||||
#define EC_FLAG_DATA_IS_CMD ((EC_STATUS) 0x08)
|
||||
#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10)
|
||||
#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01)
|
||||
#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02)
|
||||
#define EC_FLAG_DATA_IS_CMD ((EC_STATUS) 0x08)
|
||||
#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10)
|
||||
|
||||
/*
|
||||
* EC_EVENT:
|
||||
* ---------
|
||||
*/
|
||||
typedef uint8 EC_EVENT;
|
||||
typedef uint8 EC_EVENT;
|
||||
|
||||
#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00)
|
||||
#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01)
|
||||
#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02)
|
||||
#define EC_EVENT_SCI ((EC_EVENT) 0x20)
|
||||
#define EC_EVENT_SMI ((EC_EVENT) 0x40)
|
||||
#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00)
|
||||
#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01)
|
||||
#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02)
|
||||
#define EC_EVENT_SCI ((EC_EVENT) 0x20)
|
||||
#define EC_EVENT_SMI ((EC_EVENT) 0x40)
|
||||
|
||||
/* Data byte returned after burst enable indicating it was successful. */
|
||||
#define EC_BURST_ACK 0x90
|
||||
#define EC_BURST_ACK 0x90
|
||||
|
||||
|
||||
/*
|
||||
* Register access primitives
|
||||
*/
|
||||
#define EC_GET_DATA(sc) \
|
||||
bus_space_read_1((sc)->ec_data_pci_address)
|
||||
#define EC_GET_DATA(sc) \
|
||||
bus_space_read_1((sc)->ec_data_pci_address)
|
||||
|
||||
#define EC_SET_DATA(sc, v) \
|
||||
bus_space_write_1((sc)->ec_data_pci_address, (v))
|
||||
#define EC_SET_DATA(sc, v) \
|
||||
bus_space_write_1((sc)->ec_data_pci_address, (v))
|
||||
|
||||
#define EC_GET_CSR(sc) \
|
||||
bus_space_read_1((sc)->ec_csr_pci_address)
|
||||
#define EC_GET_CSR(sc) \
|
||||
bus_space_read_1((sc)->ec_csr_pci_address)
|
||||
|
||||
#define EC_SET_CSR(sc, v) \
|
||||
bus_space_write_1((sc)->ec_csr_pci_address, (v))
|
||||
#define EC_SET_CSR(sc, v) \
|
||||
bus_space_write_1((sc)->ec_csr_pci_address, (v))
|
||||
|
||||
|
||||
#define ACPI_PKG_VALID(pkg, size) \
|
||||
((pkg) != NULL && (pkg)->object_type == ACPI_TYPE_PACKAGE && \
|
||||
(pkg)->data.package.count >= (size))
|
||||
#define ACPI_PKG_VALID(pkg, size) \
|
||||
((pkg) != NULL && (pkg)->object_type == ACPI_TYPE_PACKAGE && \
|
||||
(pkg)->data.package.count >= (size))
|
||||
|
||||
int32 acpi_get_type(device_node* dev);
|
||||
|
||||
@ -137,25 +137,25 @@ int32 acpi_get_type(device_node* dev);
|
||||
* Driver cookie.
|
||||
*/
|
||||
struct acpi_ec_cookie {
|
||||
device_node* ec_dev;
|
||||
acpi_module_info* ec_acpi_module;
|
||||
acpi_device_module_info* ec_acpi;
|
||||
acpi_device ec_handle;
|
||||
int ec_uid;
|
||||
acpi_handle ec_gpehandle;
|
||||
uint8 ec_gpebit;
|
||||
device_node* ec_dev;
|
||||
acpi_module_info* ec_acpi_module;
|
||||
acpi_device_module_info* ec_acpi;
|
||||
acpi_device ec_handle;
|
||||
int ec_uid;
|
||||
acpi_handle ec_gpehandle;
|
||||
uint8 ec_gpebit;
|
||||
|
||||
int ec_data_pci_address;
|
||||
int ec_csr_pci_address;
|
||||
int ec_csr_pci_address;
|
||||
|
||||
int ec_glk;
|
||||
uint32 ec_glkhandle;
|
||||
mutex ec_lock;
|
||||
int ec_burstactive;
|
||||
int ec_sci_pending;
|
||||
vint32 ec_gencount;
|
||||
ConditionVariable ec_condition_var;
|
||||
int ec_suspending;
|
||||
int ec_glk;
|
||||
uint32 ec_glkhandle;
|
||||
mutex ec_lock;
|
||||
int ec_burstactive;
|
||||
int ec_sci_pending;
|
||||
vint32 ec_gencount;
|
||||
ConditionVariable ec_condition_var;
|
||||
int ec_suspending;
|
||||
};
|
||||
|
||||
|
||||
@ -168,66 +168,64 @@ struct acpi_ec_cookie {
|
||||
#define EC_LOCK_TIMEOUT 1000
|
||||
|
||||
/* Default delay in microseconds between each run of the status polling loop. */
|
||||
#define EC_POLL_DELAY 5
|
||||
#define EC_POLL_DELAY 5
|
||||
|
||||
/* Total time in ms spent waiting for a response from EC. */
|
||||
#define EC_TIMEOUT 750
|
||||
#define EC_TIMEOUT 750
|
||||
|
||||
#define EVENT_READY(event, status) \
|
||||
(((event) == EC_EVENT_OUTPUT_BUFFER_FULL && \
|
||||
((status) & EC_FLAG_OUTPUT_BUFFER) != 0) || \
|
||||
((event) == EC_EVENT_INPUT_BUFFER_EMPTY && \
|
||||
((status) & EC_FLAG_INPUT_BUFFER) == 0))
|
||||
#define EVENT_READY(event, status) \
|
||||
(((event) == EC_EVENT_OUTPUT_BUFFER_FULL && \
|
||||
((status) & EC_FLAG_OUTPUT_BUFFER) != 0) || \
|
||||
((event) == EC_EVENT_INPUT_BUFFER_EMPTY && \
|
||||
((status) & EC_FLAG_INPUT_BUFFER) == 0))
|
||||
|
||||
|
||||
static int ec_burst_mode = 1;
|
||||
static int ec_polled_mode = 0;
|
||||
|
||||
static int ec_timeout = EC_TIMEOUT;
|
||||
static int ec_burst_mode = 1;
|
||||
static int ec_polled_mode = 0;
|
||||
|
||||
static int ec_timeout = EC_TIMEOUT;
|
||||
|
||||
static status_t
|
||||
EcLock(struct acpi_ec_cookie *sc)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
|
||||
/* If _GLK is non-zero, acquire the global lock. */
|
||||
status = B_OK;
|
||||
if (sc->ec_glk) {
|
||||
status = sc->ec_acpi_module->acquire_global_lock(EC_LOCK_TIMEOUT,
|
||||
&sc->ec_glkhandle);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
/* If _GLK is non-zero, acquire the global lock. */
|
||||
status_t status = B_OK;
|
||||
if (sc->ec_glk) {
|
||||
status = sc->ec_acpi_module->acquire_global_lock(EC_LOCK_TIMEOUT,
|
||||
&sc->ec_glkhandle);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
mutex_lock(&sc->ec_lock);
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
EcUnlock(struct acpi_ec_cookie *sc)
|
||||
{
|
||||
mutex_unlock(&sc->ec_lock);
|
||||
if (sc->ec_glk)
|
||||
sc->ec_acpi_module->release_global_lock(sc->ec_glkhandle);
|
||||
mutex_unlock(&sc->ec_lock);
|
||||
if (sc->ec_glk)
|
||||
sc->ec_acpi_module->release_global_lock(sc->ec_glkhandle);
|
||||
}
|
||||
|
||||
|
||||
static uint32 EcGpeHandler(void *context);
|
||||
static uint32 EcGpeHandler(void *context);
|
||||
|
||||
static acpi_status EcSpaceSetup(acpi_handle region, uint32 function,
|
||||
void *context, void **return_Context);
|
||||
void *context, void **return_Context);
|
||||
static acpi_status EcSpaceHandler(uint32 function,
|
||||
acpi_physical_address address,
|
||||
uint32 width, int *value,
|
||||
void *context, void *regionContext);
|
||||
acpi_physical_address address,
|
||||
uint32 width, int *value,
|
||||
void *context, void *regionContext);
|
||||
static acpi_status EcWaitEvent(struct acpi_ec_cookie *sc, EC_EVENT event,
|
||||
int32 gen_count);
|
||||
int32 gen_count);
|
||||
static acpi_status EcCommand(struct acpi_ec_cookie *sc, EC_COMMAND cmd);
|
||||
static acpi_status EcRead(struct acpi_ec_cookie *sc, uint8 address,
|
||||
uint8 *readData);
|
||||
uint8 *readData);
|
||||
static acpi_status EcWrite(struct acpi_ec_cookie *sc, uint8 address,
|
||||
uint8 *writeData);
|
||||
uint8 *writeData);
|
||||
|
||||
|
||||
#endif // ACPI_EMBEDDED_CONTROLLER_H
|
||||
|
Loading…
Reference in New Issue
Block a user