Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0fbb3726
Commit
0fbb3726
authored
Oct 22, 2008
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ec' into test
parents
47bf31ad
c0ff1772
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
198 additions
and
187 deletions
+198
-187
drivers/acpi/bus.c
drivers/acpi/bus.c
+6
-0
drivers/acpi/ec.c
drivers/acpi/ec.c
+191
-183
drivers/acpi/scan.c
drivers/acpi/scan.c
+0
-4
include/acpi/acpi_drivers.h
include/acpi/acpi_drivers.h
+1
-0
No files found.
drivers/acpi/bus.c
View file @
0fbb3726
...
@@ -793,6 +793,12 @@ static int __init acpi_bus_init(void)
...
@@ -793,6 +793,12 @@ static int __init acpi_bus_init(void)
goto
error1
;
goto
error1
;
}
}
/*
* Maybe EC region is required at bus_scan/acpi_get_devices. So it
* is necessary to enable it as early as possible.
*/
acpi_boot_ec_enable
();
printk
(
KERN_INFO
PREFIX
"Interpreter enabled
\n
"
);
printk
(
KERN_INFO
PREFIX
"Interpreter enabled
\n
"
);
/* Initialize sleep structures */
/* Initialize sleep structures */
...
...
drivers/acpi/ec.c
View file @
0fbb3726
/*
/*
* ec.c - ACPI Embedded Controller Driver (v2.
0
)
* ec.c - ACPI Embedded Controller Driver (v2.
1
)
*
*
* Copyright (C) 2006
, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com
>
* Copyright (C) 2006
-2008 Alexey Starikovskiy <astarikovskiy@suse.de
>
* Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
*/
/* Uncomment next line to get verbose print
outs
*/
/* Uncomment next line to get verbose print
out
*/
/* #define DEBUG */
/* #define DEBUG */
#include <linux/kernel.h>
#include <linux/kernel.h>
...
@@ -38,6 +38,7 @@
...
@@ -38,6 +38,7 @@
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_drivers.h>
...
@@ -65,22 +66,21 @@ enum ec_command {
...
@@ -65,22 +66,21 @@ enum ec_command {
ACPI_EC_COMMAND_QUERY
=
0x84
,
ACPI_EC_COMMAND_QUERY
=
0x84
,
};
};
/* EC events */
enum
ec_event
{
ACPI_EC_EVENT_OBF_1
=
1
,
/* Output buffer full */
ACPI_EC_EVENT_IBF_0
,
/* Input buffer empty */
};
#define ACPI_EC_DELAY 500
/* Wait 500ms max. during EC ops */
#define ACPI_EC_DELAY 500
/* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000
/* Wait 1ms max. to get global lock */
#define ACPI_EC_UDELAY_GLK 1000
/* Wait 1ms max. to get global lock */
#define ACPI_EC_UDELAY 100
/* Wait 100us before polling EC again */
#define ACPI_EC_UDELAY 100
/* Wait 100us before polling EC again */
#define ACPI_EC_STORM_THRESHOLD 20
/* number of false interrupts
per one transaction */
enum
{
enum
{
EC_FLAGS_WAIT_GPE
=
0
,
/* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING
,
/* Query is pending */
EC_FLAGS_QUERY_PENDING
,
/* Query is pending */
EC_FLAGS_GPE_MODE
,
/* Expect GPE to be sent for status change */
EC_FLAGS_GPE_MODE
,
/* Expect GPE to be sent
* for status change */
EC_FLAGS_NO_GPE
,
/* Don't use GPE mode */
EC_FLAGS_NO_GPE
,
/* Don't use GPE mode */
EC_FLAGS_RESCHEDULE_POLL
/* Re-schedule poll */
EC_FLAGS_GPE_STORM
,
/* GPE storm detected */
EC_FLAGS_HANDLERS_INSTALLED
/* Handlers for GPE and
* OpReg are installed */
};
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
...
@@ -95,6 +95,15 @@ struct acpi_ec_query_handler {
...
@@ -95,6 +95,15 @@ struct acpi_ec_query_handler {
u8
query_bit
;
u8
query_bit
;
};
};
struct
transaction
{
const
u8
*
wdata
;
u8
*
rdata
;
unsigned
short
irq_count
;
u8
command
;
u8
wlen
;
u8
rlen
;
};
static
struct
acpi_ec
{
static
struct
acpi_ec
{
acpi_handle
handle
;
acpi_handle
handle
;
unsigned
long
gpe
;
unsigned
long
gpe
;
...
@@ -105,9 +114,8 @@ static struct acpi_ec {
...
@@ -105,9 +114,8 @@ static struct acpi_ec {
struct
mutex
lock
;
struct
mutex
lock
;
wait_queue_head_t
wait
;
wait_queue_head_t
wait
;
struct
list_head
list
;
struct
list_head
list
;
struct
delayed_work
work
;
struct
transaction
*
curr
;
atomic_t
irq_count
;
spinlock_t
curr_lock
;
u8
handlers_installed
;
}
*
boot_ec
,
*
first_ec
;
}
*
boot_ec
,
*
first_ec
;
/*
/*
...
@@ -150,7 +158,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
...
@@ -150,7 +158,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
{
u8
x
=
inb
(
ec
->
data_addr
);
u8
x
=
inb
(
ec
->
data_addr
);
pr_debug
(
PREFIX
"---> data = 0x%2.2x
\n
"
,
x
);
pr_debug
(
PREFIX
"---> data = 0x%2.2x
\n
"
,
x
);
return
inb
(
ec
->
data_addr
)
;
return
x
;
}
}
static
inline
void
acpi_ec_write_cmd
(
struct
acpi_ec
*
ec
,
u8
command
)
static
inline
void
acpi_ec_write_cmd
(
struct
acpi_ec
*
ec
,
u8
command
)
...
@@ -165,158 +173,172 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
...
@@ -165,158 +173,172 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb
(
data
,
ec
->
data_addr
);
outb
(
data
,
ec
->
data_addr
);
}
}
static
in
line
int
acpi_ec_check_status
(
struct
acpi_ec
*
ec
,
enum
ec_event
event
)
static
in
t
ec_transaction_done
(
struct
acpi_ec
*
ec
)
{
{
if
(
test_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
))
unsigned
long
flags
;
return
0
;
int
ret
=
0
;
if
(
event
==
ACPI_EC_EVENT_OBF_1
)
{
spin_lock_irqsave
(
&
ec
->
curr_lock
,
flags
);
if
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_OBF
)
if
(
!
ec
->
curr
||
(
!
ec
->
curr
->
wlen
&&
!
ec
->
curr
->
rlen
))
return
1
;
ret
=
1
;
}
else
if
(
event
==
ACPI_EC_EVENT_IBF_0
)
{
spin_unlock_irqrestore
(
&
ec
->
curr_lock
,
flags
);
if
(
!
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_IBF
))
return
ret
;
return
1
;
}
return
0
;
}
}
static
void
ec_schedule_ec_poll
(
struct
acpi_ec
*
ec
)
static
void
gpe_transaction
(
struct
acpi_ec
*
ec
,
u8
status
)
{
{
if
(
test_bit
(
EC_FLAGS_RESCHEDULE_POLL
,
&
ec
->
flags
))
unsigned
long
flags
;
schedule_delayed_work
(
&
ec
->
work
,
spin_lock_irqsave
(
&
ec
->
curr_lock
,
flags
);
msecs_to_jiffies
(
ACPI_EC_DELAY
));
if
(
!
ec
->
curr
)
}
goto
unlock
;
if
(
ec
->
curr
->
wlen
>
0
)
{
if
((
status
&
ACPI_EC_FLAG_IBF
)
==
0
)
{
acpi_ec_write_data
(
ec
,
*
(
ec
->
curr
->
wdata
++
));
--
ec
->
curr
->
wlen
;
}
else
/* false interrupt, state didn't change */
++
ec
->
curr
->
irq_count
;
static
void
ec_switch_to_poll_mode
(
struct
acpi_ec
*
ec
)
}
else
if
(
ec
->
curr
->
rlen
>
0
)
{
{
if
((
status
&
ACPI_EC_FLAG_OBF
)
==
1
)
{
set_bit
(
EC_FLAGS_NO_GPE
,
&
ec
->
flags
);
*
(
ec
->
curr
->
rdata
++
)
=
acpi_ec_read_data
(
ec
);
clear_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
--
ec
->
curr
->
rlen
;
acpi_disable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
}
else
set_bit
(
EC_FLAGS_RESCHEDULE_POLL
,
&
ec
->
flags
);
/* false interrupt, state didn't change */
++
ec
->
curr
->
irq_count
;
}
unlock:
spin_unlock_irqrestore
(
&
ec
->
curr_lock
,
flags
);
}
}
static
int
acpi_ec_wait
(
struct
acpi_ec
*
ec
,
enum
ec_event
event
,
int
force_poll
)
static
int
acpi_ec_wait
(
struct
acpi_ec
*
ec
)
{
{
atomic_set
(
&
ec
->
irq_count
,
0
);
if
(
wait_event_timeout
(
ec
->
wait
,
ec_transaction_done
(
ec
),
if
(
likely
(
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
))
&&
likely
(
!
force_poll
))
{
if
(
wait_event_timeout
(
ec
->
wait
,
acpi_ec_check_status
(
ec
,
event
),
msecs_to_jiffies
(
ACPI_EC_DELAY
)))
msecs_to_jiffies
(
ACPI_EC_DELAY
)))
return
0
;
return
0
;
clear_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
if
(
acpi_ec_check_status
(
ec
,
event
))
{
/* missing GPEs, switch back to poll mode */
/* missing GPEs, switch back to poll mode */
if
(
printk_ratelimit
())
if
(
printk_ratelimit
())
pr_info
(
PREFIX
"missing confirmations, "
pr_info
(
PREFIX
"missing confirmations, "
"switch off interrupt mode.
\n
"
);
"switch off interrupt mode.
\n
"
);
ec_switch_to_poll_mode
(
ec
);
set_bit
(
EC_FLAGS_NO_GPE
,
&
ec
->
flags
);
ec_schedule_ec_poll
(
ec
);
clear_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
return
0
;
return
1
;
}
static
void
acpi_ec_gpe_query
(
void
*
ec_cxt
);
static
int
ec_check_sci
(
struct
acpi_ec
*
ec
,
u8
state
)
{
if
(
state
&
ACPI_EC_FLAG_SCI
)
{
if
(
!
test_and_set_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
))
return
acpi_os_execute
(
OSL_EC_BURST_HANDLER
,
acpi_ec_gpe_query
,
ec
);
}
}
}
else
{
return
0
;
}
static
int
ec_poll
(
struct
acpi_ec
*
ec
)
{
unsigned
long
delay
=
jiffies
+
msecs_to_jiffies
(
ACPI_EC_DELAY
);
unsigned
long
delay
=
jiffies
+
msecs_to_jiffies
(
ACPI_EC_DELAY
);
clear_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
msleep
(
1
);
while
(
time_before
(
jiffies
,
delay
))
{
while
(
time_before
(
jiffies
,
delay
))
{
if
(
acpi_ec_check_status
(
ec
,
event
))
gpe_transaction
(
ec
,
acpi_ec_read_status
(
ec
));
return
0
;
msleep
(
1
);
msleep
(
1
);
}
if
(
ec_transaction_done
(
ec
))
if
(
acpi_ec_check_status
(
ec
,
event
))
return
0
;
return
0
;
}
}
pr_err
(
PREFIX
"acpi_ec_wait timeout, status = 0x%2.2x, event = %s
\n
"
,
acpi_ec_read_status
(
ec
),
(
event
==
ACPI_EC_EVENT_OBF_1
)
?
"
\"
b0=1
\"
"
:
"
\"
b1=0
\"
"
);
return
-
ETIME
;
return
-
ETIME
;
}
}
static
int
acpi_ec_transaction_unlocked
(
struct
acpi_ec
*
ec
,
u8
command
,
static
int
acpi_ec_transaction_unlocked
(
struct
acpi_ec
*
ec
,
const
u8
*
wdata
,
unsigned
wdata_len
,
struct
transaction
*
t
,
u8
*
rdata
,
unsigned
rdata_len
,
int
force_poll
)
int
force_poll
)
{
{
int
result
=
0
;
unsigned
long
tmp
;
set_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
)
;
int
ret
=
0
;
pr_debug
(
PREFIX
"transaction start
\n
"
);
pr_debug
(
PREFIX
"transaction start
\n
"
);
acpi_ec_write_cmd
(
ec
,
command
);
/* disable GPE during transaction if storm is detected */
for
(;
wdata_len
>
0
;
--
wdata_len
)
{
if
(
test_bit
(
EC_FLAGS_GPE_STORM
,
&
ec
->
flags
))
{
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
force_poll
);
clear_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
if
(
result
)
{
acpi_disable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
pr_err
(
PREFIX
"write_cmd timeout, command = %d
\n
"
,
command
);
goto
end
;
}
}
set_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
/* start transaction */
acpi_ec_write_data
(
ec
,
*
(
wdata
++
));
spin_lock_irqsave
(
&
ec
->
curr_lock
,
tmp
);
/* following two actions should be kept atomic */
t
->
irq_count
=
0
;
ec
->
curr
=
t
;
acpi_ec_write_cmd
(
ec
,
ec
->
curr
->
command
);
if
(
ec
->
curr
->
command
==
ACPI_EC_COMMAND_QUERY
)
clear_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
);
spin_unlock_irqrestore
(
&
ec
->
curr_lock
,
tmp
);
/* if we selected poll mode or failed in GPE-mode do a poll loop */
if
(
force_poll
||
!
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
)
||
acpi_ec_wait
(
ec
))
ret
=
ec_poll
(
ec
);
pr_debug
(
PREFIX
"transaction end
\n
"
);
spin_lock_irqsave
(
&
ec
->
curr_lock
,
tmp
);
ec
->
curr
=
NULL
;
spin_unlock_irqrestore
(
&
ec
->
curr_lock
,
tmp
);
if
(
test_bit
(
EC_FLAGS_GPE_STORM
,
&
ec
->
flags
))
{
/* check if we received SCI during transaction */
ec_check_sci
(
ec
,
acpi_ec_read_status
(
ec
));
/* it is safe to enable GPE outside of transaction */
acpi_enable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
}
else
if
(
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
)
&&
t
->
irq_count
>
ACPI_EC_STORM_THRESHOLD
)
{
pr_debug
(
PREFIX
"GPE storm detected
\n
"
);
set_bit
(
EC_FLAGS_GPE_STORM
,
&
ec
->
flags
);
}
}
return
ret
;
}
if
(
!
rdata_len
)
{
static
int
ec_check_ibf0
(
struct
acpi_ec
*
ec
)
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
force_poll
);
{
if
(
result
)
{
u8
status
=
acpi_ec_read_status
(
ec
);
pr_err
(
PREFIX
return
(
status
&
ACPI_EC_FLAG_IBF
)
==
0
;
"finish-write timeout, command = %d
\n
"
,
command
);
}
goto
end
;
}
}
else
if
(
command
==
ACPI_EC_COMMAND_QUERY
)
clear_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
);
for
(;
rdata_len
>
0
;
--
rdata_len
)
{
static
int
ec_wait_ibf0
(
struct
acpi_ec
*
ec
)
result
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_OBF_1
,
force_poll
);
{
if
(
result
)
{
unsigned
long
delay
=
jiffies
+
msecs_to_jiffies
(
ACPI_EC_DELAY
);
pr_err
(
PREFIX
"read timeout, command = %d
\n
"
,
command
);
/* interrupt wait manually if GPE mode is not active */
goto
end
;
unsigned
long
timeout
=
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
)
?
}
msecs_to_jiffies
(
ACPI_EC_DELAY
)
:
msecs_to_jiffies
(
1
);
/* Don't expect GPE after last read */
while
(
time_before
(
jiffies
,
delay
))
if
(
rdata_len
>
1
)
if
(
wait_event_timeout
(
ec
->
wait
,
ec_check_ibf0
(
ec
),
timeout
))
set_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
return
0
;
*
(
rdata
++
)
=
acpi_ec_read_data
(
ec
);
return
-
ETIME
;
}
end:
pr_debug
(
PREFIX
"transaction end
\n
"
);
return
result
;
}
}
static
int
acpi_ec_transaction
(
struct
acpi_ec
*
ec
,
u8
command
,
static
int
acpi_ec_transaction
(
struct
acpi_ec
*
ec
,
struct
transaction
*
t
,
const
u8
*
wdata
,
unsigned
wdata_len
,
u8
*
rdata
,
unsigned
rdata_len
,
int
force_poll
)
int
force_poll
)
{
{
int
status
;
int
status
;
u32
glk
;
u32
glk
;
if
(
!
ec
||
(
!
t
)
||
(
t
->
wlen
&&
!
t
->
wdata
)
||
(
t
->
rlen
&&
!
t
->
rdata
))
if
(
!
ec
||
(
wdata_len
&&
!
wdata
)
||
(
rdata_len
&&
!
rdata
))
return
-
EINVAL
;
return
-
EINVAL
;
if
(
t
->
rdata
)
if
(
rdata
)
memset
(
t
->
rdata
,
0
,
t
->
rlen
);
memset
(
rdata
,
0
,
rdata_len
);
mutex_lock
(
&
ec
->
lock
);
mutex_lock
(
&
ec
->
lock
);
if
(
ec
->
global_lock
)
{
if
(
ec
->
global_lock
)
{
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
status
=
acpi_acquire_global_lock
(
ACPI_EC_UDELAY_GLK
,
&
glk
);
if
(
ACPI_FAILURE
(
status
))
{
if
(
ACPI_FAILURE
(
status
))
{
mutex_unlock
(
&
ec
->
lock
)
;
status
=
-
ENODEV
;
return
-
ENODEV
;
goto
unlock
;
}
}
}
}
if
(
ec_wait_ibf0
(
ec
))
{
status
=
acpi_ec_wait
(
ec
,
ACPI_EC_EVENT_IBF_0
,
0
);
if
(
status
)
{
pr_err
(
PREFIX
"input buffer is not empty, "
pr_err
(
PREFIX
"input buffer is not empty, "
"aborting transaction
\n
"
);
"aborting transaction
\n
"
);
status
=
-
ETIME
;
goto
end
;
goto
end
;
}
}
status
=
acpi_ec_transaction_unlocked
(
ec
,
t
,
force_poll
);
status
=
acpi_ec_transaction_unlocked
(
ec
,
command
,
end:
wdata
,
wdata_len
,
rdata
,
rdata_len
,
force_poll
);
end:
if
(
ec
->
global_lock
)
if
(
ec
->
global_lock
)
acpi_release_global_lock
(
glk
);
acpi_release_global_lock
(
glk
);
unlock:
mutex_unlock
(
&
ec
->
lock
);
mutex_unlock
(
&
ec
->
lock
);
return
status
;
return
status
;
}
}
...
@@ -327,21 +349,32 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
...
@@ -327,21 +349,32 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
int
acpi_ec_burst_enable
(
struct
acpi_ec
*
ec
)
int
acpi_ec_burst_enable
(
struct
acpi_ec
*
ec
)
{
{
u8
d
;
u8
d
;
return
acpi_ec_transaction
(
ec
,
ACPI_EC_BURST_ENABLE
,
NULL
,
0
,
&
d
,
1
,
0
);
struct
transaction
t
=
{.
command
=
ACPI_EC_BURST_ENABLE
,
.
wdata
=
NULL
,
.
rdata
=
&
d
,
.
wlen
=
0
,
.
rlen
=
1
};
return
acpi_ec_transaction
(
ec
,
&
t
,
0
);
}
}
int
acpi_ec_burst_disable
(
struct
acpi_ec
*
ec
)
int
acpi_ec_burst_disable
(
struct
acpi_ec
*
ec
)
{
{
return
acpi_ec_transaction
(
ec
,
ACPI_EC_BURST_DISABLE
,
NULL
,
0
,
NULL
,
0
,
0
);
struct
transaction
t
=
{.
command
=
ACPI_EC_BURST_DISABLE
,
.
wdata
=
NULL
,
.
rdata
=
NULL
,
.
wlen
=
0
,
.
rlen
=
0
};
return
(
acpi_ec_read_status
(
ec
)
&
ACPI_EC_FLAG_BURST
)
?
acpi_ec_transaction
(
ec
,
&
t
,
0
)
:
0
;
}
}
static
int
acpi_ec_read
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
*
data
)
static
int
acpi_ec_read
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
*
data
)
{
{
int
result
;
int
result
;
u8
d
;
u8
d
;
struct
transaction
t
=
{.
command
=
ACPI_EC_COMMAND_READ
,
.
wdata
=
&
address
,
.
rdata
=
&
d
,
.
wlen
=
1
,
.
rlen
=
1
};
result
=
acpi_ec_transaction
(
ec
,
ACPI_EC_COMMAND_READ
,
result
=
acpi_ec_transaction
(
ec
,
&
t
,
0
);
&
address
,
1
,
&
d
,
1
,
0
);
*
data
=
d
;
*
data
=
d
;
return
result
;
return
result
;
}
}
...
@@ -349,8 +382,11 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
...
@@ -349,8 +382,11 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
static
int
acpi_ec_write
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
data
)
static
int
acpi_ec_write
(
struct
acpi_ec
*
ec
,
u8
address
,
u8
data
)
{
{
u8
wdata
[
2
]
=
{
address
,
data
};
u8
wdata
[
2
]
=
{
address
,
data
};
return
acpi_ec_transaction
(
ec
,
ACPI_EC_COMMAND_WRITE
,
struct
transaction
t
=
{.
command
=
ACPI_EC_COMMAND_WRITE
,
wdata
,
2
,
NULL
,
0
,
0
);
.
wdata
=
wdata
,
.
rdata
=
NULL
,
.
wlen
=
2
,
.
rlen
=
0
};
return
acpi_ec_transaction
(
ec
,
&
t
,
0
);
}
}
/*
/*
...
@@ -412,12 +448,13 @@ int ec_transaction(u8 command,
...
@@ -412,12 +448,13 @@ int ec_transaction(u8 command,
u8
*
rdata
,
unsigned
rdata_len
,
u8
*
rdata
,
unsigned
rdata_len
,
int
force_poll
)
int
force_poll
)
{
{
struct
transaction
t
=
{.
command
=
command
,
.
wdata
=
wdata
,
.
rdata
=
rdata
,
.
wlen
=
wdata_len
,
.
rlen
=
rdata_len
};
if
(
!
first_ec
)
if
(
!
first_ec
)
return
-
ENODEV
;
return
-
ENODEV
;
return
acpi_ec_transaction
(
first_ec
,
command
,
wdata
,
return
acpi_ec_transaction
(
first_ec
,
&
t
,
force_poll
);
wdata_len
,
rdata
,
rdata_len
,
force_poll
);
}
}
EXPORT_SYMBOL
(
ec_transaction
);
EXPORT_SYMBOL
(
ec_transaction
);
...
@@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
...
@@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
{
{
int
result
;
int
result
;
u8
d
;
u8
d
;
struct
transaction
t
=
{.
command
=
ACPI_EC_COMMAND_QUERY
,
.
wdata
=
NULL
,
.
rdata
=
&
d
,
.
wlen
=
0
,
.
rlen
=
1
};
if
(
!
ec
||
!
data
)
if
(
!
ec
||
!
data
)
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -436,7 +475,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
...
@@ -436,7 +475,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
* bit to be cleared (and thus clearing the interrupt source).
* bit to be cleared (and thus clearing the interrupt source).
*/
*/
result
=
acpi_ec_transaction
(
ec
,
ACPI_EC_COMMAND_QUERY
,
NULL
,
0
,
&
d
,
1
,
0
);
result
=
acpi_ec_transaction
(
ec
,
&
t
,
0
);
if
(
result
)
if
(
result
)
return
result
;
return
result
;
...
@@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt)
...
@@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt)
static
u32
acpi_ec_gpe_handler
(
void
*
data
)
static
u32
acpi_ec_gpe_handler
(
void
*
data
)
{
{
acpi_status
status
=
AE_OK
;
struct
acpi_ec
*
ec
=
data
;
struct
acpi_ec
*
ec
=
data
;
u8
stat
e
=
acpi_ec_read_status
(
ec
)
;
u8
stat
us
;
pr_debug
(
PREFIX
"~~~> interrupt
\n
"
);
pr_debug
(
PREFIX
"~~~> interrupt
\n
"
);
atomic_inc
(
&
ec
->
irq_count
);
status
=
acpi_ec_read_status
(
ec
);
if
(
atomic_read
(
&
ec
->
irq_count
)
>
5
)
{
pr_err
(
PREFIX
"GPE storm detected, disabling EC GPE
\n
"
);
gpe_transaction
(
ec
,
status
);
ec_switch_to_poll_mode
(
ec
);
if
(
ec_transaction_done
(
ec
)
&&
(
status
&
ACPI_EC_FLAG_IBF
)
==
0
)
goto
end
;
}
clear_bit
(
EC_FLAGS_WAIT_GPE
,
&
ec
->
flags
);
if
(
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
))
wake_up
(
&
ec
->
wait
);
wake_up
(
&
ec
->
wait
);
if
(
state
&
ACPI_EC_FLAG_SCI
)
{
ec_check_sci
(
ec
,
status
);
if
(
!
test_and_set_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
))
if
(
!
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
)
&&
status
=
acpi_os_execute
(
OSL_EC_BURST_HANDLER
,
!
test_bit
(
EC_FLAGS_NO_GPE
,
&
ec
->
flags
))
{
acpi_ec_gpe_query
,
ec
);
}
else
if
(
!
test_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
)
&&
!
test_bit
(
EC_FLAGS_NO_GPE
,
&
ec
->
flags
)
&&
in_interrupt
())
{
/* this is non-query, must be confirmation */
/* this is non-query, must be confirmation */
if
(
printk_ratelimit
())
if
(
printk_ratelimit
())
pr_info
(
PREFIX
"non-query interrupt received,"
pr_info
(
PREFIX
"non-query interrupt received,"
" switching to interrupt mode
\n
"
);
" switching to interrupt mode
\n
"
);
set_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
set_bit
(
EC_FLAGS_GPE_MODE
,
&
ec
->
flags
);
clear_bit
(
EC_FLAGS_RESCHEDULE_POLL
,
&
ec
->
flags
);
}
}
end:
return
ACPI_INTERRUPT_HANDLED
;
ec_schedule_ec_poll
(
ec
);
return
ACPI_SUCCESS
(
status
)
?
ACPI_INTERRUPT_HANDLED
:
ACPI_INTERRUPT_NOT_HANDLED
;
}
static
void
do_ec_poll
(
struct
work_struct
*
work
)
{
struct
acpi_ec
*
ec
=
container_of
(
work
,
struct
acpi_ec
,
work
.
work
);
atomic_set
(
&
ec
->
irq_count
,
0
);
(
void
)
acpi_ec_gpe_handler
(
ec
);
}
}
/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
...
@@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void)
...
@@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void)
mutex_init
(
&
ec
->
lock
);
mutex_init
(
&
ec
->
lock
);
init_waitqueue_head
(
&
ec
->
wait
);
init_waitqueue_head
(
&
ec
->
wait
);
INIT_LIST_HEAD
(
&
ec
->
list
);
INIT_LIST_HEAD
(
&
ec
->
list
);
INIT_DELAYED_WORK_DEFERRABLE
(
&
ec
->
work
,
do_ec_poll
);
spin_lock_init
(
&
ec
->
curr_lock
);
atomic_set
(
&
ec
->
irq_count
,
0
);
return
ec
;
return
ec
;
}
}
...
@@ -736,22 +754,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
...
@@ -736,22 +754,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
return
AE_CTRL_TERMINATE
;
return
AE_CTRL_TERMINATE
;
}
}
static
void
ec_poll_stop
(
struct
acpi_ec
*
ec
)
{
clear_bit
(
EC_FLAGS_RESCHEDULE_POLL
,
&
ec
->
flags
);
cancel_delayed_work
(
&
ec
->
work
);
}
static
void
ec_remove_handlers
(
struct
acpi_ec
*
ec
)
static
void
ec_remove_handlers
(
struct
acpi_ec
*
ec
)
{
{
ec_poll_stop
(
ec
);
if
(
ACPI_FAILURE
(
acpi_remove_address_space_handler
(
ec
->
handle
,
if
(
ACPI_FAILURE
(
acpi_remove_address_space_handler
(
ec
->
handle
,
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
)))
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
)))
pr_err
(
PREFIX
"failed to remove space handler
\n
"
);
pr_err
(
PREFIX
"failed to remove space handler
\n
"
);
if
(
ACPI_FAILURE
(
acpi_remove_gpe_handler
(
NULL
,
ec
->
gpe
,
if
(
ACPI_FAILURE
(
acpi_remove_gpe_handler
(
NULL
,
ec
->
gpe
,
&
acpi_ec_gpe_handler
)))
&
acpi_ec_gpe_handler
)))
pr_err
(
PREFIX
"failed to remove gpe handler
\n
"
);
pr_err
(
PREFIX
"failed to remove gpe handler
\n
"
);
ec
->
handlers_installed
=
0
;
clear_bit
(
EC_FLAGS_HANDLERS_INSTALLED
,
&
ec
->
flags
)
;
}
}
static
int
acpi_ec_add
(
struct
acpi_device
*
device
)
static
int
acpi_ec_add
(
struct
acpi_device
*
device
)
...
@@ -846,17 +857,15 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
...
@@ -846,17 +857,15 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
static
int
ec_install_handlers
(
struct
acpi_ec
*
ec
)
static
int
ec_install_handlers
(
struct
acpi_ec
*
ec
)
{
{
acpi_status
status
;
acpi_status
status
;
if
(
ec
->
handlers_installed
)
if
(
test_bit
(
EC_FLAGS_HANDLERS_INSTALLED
,
&
ec
->
flags
)
)
return
0
;
return
0
;
status
=
acpi_install_gpe_handler
(
NULL
,
ec
->
gpe
,
status
=
acpi_install_gpe_handler
(
NULL
,
ec
->
gpe
,
ACPI_GPE_EDGE_TRIGGERED
,
ACPI_GPE_EDGE_TRIGGERED
,
&
acpi_ec_gpe_handler
,
ec
);
&
acpi_ec_gpe_handler
,
ec
);
if
(
ACPI_FAILURE
(
status
))
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
return
-
ENODEV
;
acpi_set_gpe_type
(
NULL
,
ec
->
gpe
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_set_gpe_type
(
NULL
,
ec
->
gpe
,
ACPI_GPE_TYPE_RUNTIME
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
acpi_enable_gpe
(
NULL
,
ec
->
gpe
,
ACPI_NOT_ISR
);
status
=
acpi_install_address_space_handler
(
ec
->
handle
,
status
=
acpi_install_address_space_handler
(
ec
->
handle
,
ACPI_ADR_SPACE_EC
,
ACPI_ADR_SPACE_EC
,
&
acpi_ec_space_handler
,
&
acpi_ec_space_handler
,
...
@@ -877,7 +886,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
...
@@ -877,7 +886,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
}
}
}
}
ec
->
handlers_installed
=
1
;
set_bit
(
EC_FLAGS_HANDLERS_INSTALLED
,
&
ec
->
flags
)
;
return
0
;
return
0
;
}
}
...
@@ -898,7 +907,6 @@ static int acpi_ec_start(struct acpi_device *device)
...
@@ -898,7 +907,6 @@ static int acpi_ec_start(struct acpi_device *device)
/* EC is fully operational, allow queries */
/* EC is fully operational, allow queries */
clear_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
);
clear_bit
(
EC_FLAGS_QUERY_PENDING
,
&
ec
->
flags
);
ec_schedule_ec_poll
(
ec
);
return
ret
;
return
ret
;
}
}
...
@@ -917,7 +925,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
...
@@ -917,7 +925,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
int
__init
acpi_boot_ec_enable
(
void
)
int
__init
acpi_boot_ec_enable
(
void
)
{
{
if
(
!
boot_ec
||
boot_ec
->
handlers_installed
)
if
(
!
boot_ec
||
test_bit
(
EC_FLAGS_HANDLERS_INSTALLED
,
&
boot_ec
->
flags
)
)
return
0
;
return
0
;
if
(
!
ec_install_handlers
(
boot_ec
))
{
if
(
!
ec_install_handlers
(
boot_ec
))
{
first_ec
=
boot_ec
;
first_ec
=
boot_ec
;
...
...
drivers/acpi/scan.c
View file @
0fbb3726
...
@@ -1565,7 +1565,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
...
@@ -1565,7 +1565,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
return
result
;
return
result
;
}
}
int
__init
acpi_boot_ec_enable
(
void
);
static
int
__init
acpi_scan_init
(
void
)
static
int
__init
acpi_scan_init
(
void
)
{
{
...
@@ -1599,9 +1598,6 @@ static int __init acpi_scan_init(void)
...
@@ -1599,9 +1598,6 @@ static int __init acpi_scan_init(void)
*/
*/
result
=
acpi_bus_scan_fixed
(
acpi_root
);
result
=
acpi_bus_scan_fixed
(
acpi_root
);
/* EC region might be needed at bus_scan, so enable it now */
acpi_boot_ec_enable
();
if
(
!
result
)
if
(
!
result
)
result
=
acpi_bus_scan
(
acpi_root
,
&
ops
);
result
=
acpi_bus_scan
(
acpi_root
,
&
ops
);
...
...
include/acpi/acpi_drivers.h
View file @
0fbb3726
...
@@ -101,6 +101,7 @@ extern int acpi_power_nocheck;
...
@@ -101,6 +101,7 @@ extern int acpi_power_nocheck;
-------------------------------------------------------------------------- */
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_EC
#ifdef CONFIG_ACPI_EC
int
acpi_ec_ecdt_probe
(
void
);
int
acpi_ec_ecdt_probe
(
void
);
int
acpi_boot_ec_enable
(
void
);
#endif
#endif
/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment