Skip to content

Commit 3300fdd

Browse files
Enrico GranataEnric Balletbo i Serra
authored andcommitted
platform/chrome: cros_ec: handle MKBP more events flag
The ChromeOS EC has support for signaling to the host that a single IRQ can serve multiple MKBP (Matrix KeyBoard Protocol) events. Doing this serves an optimization purpose, as it minimizes the number of round-trips into the interrupt handling machinery, and it proves beneficial to sensor timestamping as it keeps the desired synchronization of event times between the two processors. This patch adds kernel support for this EC feature, allowing the ec_irq to loop until all events have been served. Signed-off-by: Enrico Granata <[email protected]> Signed-off-by: Gwendal Grignou <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Acked-by: Lee Jones <[email protected]> Signed-off-by: Enric Balletbo i Serra <[email protected]>
1 parent da94658 commit 3300fdd

File tree

6 files changed

+107
-61
lines changed

6 files changed

+107
-61
lines changed

drivers/platform/chrome/cros_ec.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,23 @@ static irqreturn_t ec_irq_handler(int irq, void *data)
4040
return IRQ_WAKE_THREAD;
4141
}
4242

43-
static irqreturn_t ec_irq_thread(int irq, void *data)
43+
/**
44+
* cros_ec_handle_event() - process and forward pending events on EC
45+
* @ec_dev: Device with events to process.
46+
*
47+
* Call this function in a loop when the kernel is notified that the EC has
48+
* pending events.
49+
*
50+
* Return: true if more events are still pending and this function should be
51+
* called again.
52+
*/
53+
bool cros_ec_handle_event(struct cros_ec_device *ec_dev)
4454
{
45-
struct cros_ec_device *ec_dev = data;
46-
bool wake_event = true;
55+
bool wake_event;
56+
bool ec_has_more_events;
4757
int ret;
4858

49-
ret = cros_ec_get_next_event(ec_dev, &wake_event);
59+
ret = cros_ec_get_next_event(ec_dev, &wake_event, &ec_has_more_events);
5060

5161
/*
5262
* Signal only if wake host events or any interrupt if
@@ -59,6 +69,20 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
5969
if (ret > 0)
6070
blocking_notifier_call_chain(&ec_dev->event_notifier,
6171
0, ec_dev);
72+
73+
return ec_has_more_events;
74+
}
75+
EXPORT_SYMBOL(cros_ec_handle_event);
76+
77+
static irqreturn_t ec_irq_thread(int irq, void *data)
78+
{
79+
struct cros_ec_device *ec_dev = data;
80+
bool ec_has_more_events;
81+
82+
do {
83+
ec_has_more_events = cros_ec_handle_event(ec_dev);
84+
} while (ec_has_more_events);
85+
6286
return IRQ_HANDLED;
6387
}
6488

@@ -274,7 +298,7 @@ EXPORT_SYMBOL(cros_ec_suspend);
274298
static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
275299
{
276300
while (ec_dev->mkbp_event_supported &&
277-
cros_ec_get_next_event(ec_dev, NULL) > 0)
301+
cros_ec_get_next_event(ec_dev, NULL, NULL) > 0)
278302
blocking_notifier_call_chain(&ec_dev->event_notifier,
279303
1, ec_dev);
280304
}

drivers/platform/chrome/cros_ec_ishtp.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ static void ish_evt_handler(struct work_struct *work)
136136
struct ishtp_cl_data *client_data =
137137
container_of(work, struct ishtp_cl_data, work_ec_evt);
138138
struct cros_ec_device *ec_dev = client_data->ec_dev;
139+
bool ec_has_more_events;
139140

140-
if (cros_ec_get_next_event(ec_dev, NULL) > 0) {
141-
blocking_notifier_call_chain(&ec_dev->event_notifier,
142-
0, ec_dev);
143-
}
141+
do {
142+
ec_has_more_events = cros_ec_handle_event(ec_dev);
143+
} while (ec_has_more_events);
144144
}
145145

146146
/**

drivers/platform/chrome/cros_ec_lpc.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,20 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
312312
static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
313313
{
314314
struct cros_ec_device *ec_dev = data;
315+
bool ec_has_more_events;
316+
int ret;
315317

316318
ec_dev->last_event_time = cros_ec_get_time_ns();
317319

318-
if (ec_dev->mkbp_event_supported &&
319-
cros_ec_get_next_event(ec_dev, NULL) > 0)
320-
blocking_notifier_call_chain(&ec_dev->event_notifier, 0,
321-
ec_dev);
320+
if (ec_dev->mkbp_event_supported)
321+
do {
322+
ret = cros_ec_get_next_event(ec_dev, NULL,
323+
&ec_has_more_events);
324+
if (ret > 0)
325+
blocking_notifier_call_chain(
326+
&ec_dev->event_notifier, 0,
327+
ec_dev);
328+
} while (ec_has_more_events);
322329

323330
if (value == ACPI_NOTIFY_DEVICE_WAKE)
324331
pm_system_wakeup();

drivers/platform/chrome/cros_ec_proto.c

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,10 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
456456
if (ret < 0 || ver_mask == 0)
457457
ec_dev->mkbp_event_supported = 0;
458458
else
459-
ec_dev->mkbp_event_supported = 1;
459+
ec_dev->mkbp_event_supported = fls(ver_mask);
460+
461+
dev_dbg(ec_dev->dev, "MKBP support version %u\n",
462+
ec_dev->mkbp_event_supported - 1);
460463

461464
/* Probe if host sleep v1 is supported for S0ix failure detection. */
462465
ret = cros_ec_get_host_command_version_mask(ec_dev,
@@ -569,6 +572,7 @@ EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
569572

570573
static int get_next_event_xfer(struct cros_ec_device *ec_dev,
571574
struct cros_ec_command *msg,
575+
struct ec_response_get_next_event_v1 *event,
572576
int version, uint32_t size)
573577
{
574578
int ret;
@@ -581,38 +585,34 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
581585
ret = cros_ec_cmd_xfer(ec_dev, msg);
582586
if (ret > 0) {
583587
ec_dev->event_size = ret - 1;
584-
memcpy(&ec_dev->event_data, msg->data, ret);
588+
ec_dev->event_data = *event;
585589
}
586590

587591
return ret;
588592
}
589593

590594
static int get_next_event(struct cros_ec_device *ec_dev)
591595
{
592-
u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
593-
struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
594-
static int cmd_version = 1;
595-
int ret;
596+
struct {
597+
struct cros_ec_command msg;
598+
struct ec_response_get_next_event_v1 event;
599+
} __packed buf;
600+
struct cros_ec_command *msg = &buf.msg;
601+
struct ec_response_get_next_event_v1 *event = &buf.event;
602+
const int cmd_version = ec_dev->mkbp_event_supported - 1;
596603

604+
memset(msg, 0, sizeof(*msg));
597605
if (ec_dev->suspended) {
598606
dev_dbg(ec_dev->dev, "Device suspended.\n");
599607
return -EHOSTDOWN;
600608
}
601609

602-
if (cmd_version == 1) {
603-
ret = get_next_event_xfer(ec_dev, msg, cmd_version,
604-
sizeof(struct ec_response_get_next_event_v1));
605-
if (ret < 0 || msg->result != EC_RES_INVALID_VERSION)
606-
return ret;
607-
608-
/* Fallback to version 0 for future send attempts */
609-
cmd_version = 0;
610-
}
611-
612-
ret = get_next_event_xfer(ec_dev, msg, cmd_version,
610+
if (cmd_version == 0)
611+
return get_next_event_xfer(ec_dev, msg, event, 0,
613612
sizeof(struct ec_response_get_next_event));
614613

615-
return ret;
614+
return get_next_event_xfer(ec_dev, msg, event, cmd_version,
615+
sizeof(struct ec_response_get_next_event_v1));
616616
}
617617

618618
static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
@@ -639,32 +639,55 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
639639
* @ec_dev: Device to fetch event from.
640640
* @wake_event: Pointer to a bool set to true upon return if the event might be
641641
* treated as a wake event. Ignored if null.
642+
* @has_more_events: Pointer to bool set to true if more than one event is
643+
* pending.
644+
* Some EC will set this flag to indicate cros_ec_get_next_event()
645+
* can be called multiple times in a row.
646+
* It is an optimization to prevent issuing a EC command for
647+
* nothing or wait for another interrupt from the EC to process
648+
* the next message.
649+
* Ignored if null.
642650
*
643651
* Return: negative error code on errors; 0 for no data; or else number of
644652
* bytes received (i.e., an event was retrieved successfully). Event types are
645653
* written out to @ec_dev->event_data.event_type on success.
646654
*/
647-
int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
655+
int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
656+
bool *wake_event,
657+
bool *has_more_events)
648658
{
649659
u8 event_type;
650660
u32 host_event;
651661
int ret;
652662

653-
if (!ec_dev->mkbp_event_supported) {
654-
ret = get_keyboard_state_event(ec_dev);
655-
if (ret <= 0)
656-
return ret;
663+
/*
664+
* Default value for wake_event.
665+
* Wake up on keyboard event, wake up for spurious interrupt or link
666+
* error to the EC.
667+
*/
668+
if (wake_event)
669+
*wake_event = true;
657670

658-
if (wake_event)
659-
*wake_event = true;
671+
/*
672+
* Default value for has_more_events.
673+
* EC will raise another interrupt if AP does not process all events
674+
* anyway.
675+
*/
676+
if (has_more_events)
677+
*has_more_events = false;
660678

661-
return ret;
662-
}
679+
if (!ec_dev->mkbp_event_supported)
680+
return get_keyboard_state_event(ec_dev);
663681

664682
ret = get_next_event(ec_dev);
665683
if (ret <= 0)
666684
return ret;
667685

686+
if (has_more_events)
687+
*has_more_events = ec_dev->event_data.event_type &
688+
EC_MKBP_HAS_MORE_EVENTS;
689+
ec_dev->event_data.event_type &= EC_MKBP_EVENT_TYPE_MASK;
690+
668691
if (wake_event) {
669692
event_type = ec_dev->event_data.event_type;
670693
host_event = cros_ec_get_host_event(ec_dev);
@@ -679,9 +702,6 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
679702
else if (host_event &&
680703
!(host_event & ec_dev->host_event_wake_mask))
681704
*wake_event = false;
682-
/* Consider all other events as wake events. */
683-
else
684-
*wake_event = true;
685705
}
686706

687707
return ret;

drivers/platform/chrome/cros_ec_rpmsg.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -143,22 +143,11 @@ cros_ec_rpmsg_host_event_function(struct work_struct *host_event_work)
143143
struct cros_ec_rpmsg,
144144
host_event_work);
145145
struct cros_ec_device *ec_dev = dev_get_drvdata(&ec_rpmsg->rpdev->dev);
146-
bool wake_event = true;
147-
int ret;
148-
149-
ret = cros_ec_get_next_event(ec_dev, &wake_event);
150-
151-
/*
152-
* Signal only if wake host events or any interrupt if
153-
* cros_ec_get_next_event() returned an error (default value for
154-
* wake_event is true)
155-
*/
156-
if (wake_event && device_may_wakeup(ec_dev->dev))
157-
pm_wakeup_event(ec_dev->dev, 0);
146+
bool ec_has_more_events;
158147

159-
if (ret > 0)
160-
blocking_notifier_call_chain(&ec_dev->event_notifier,
161-
0, ec_dev);
148+
do {
149+
ec_has_more_events = cros_ec_handle_event(ec_dev);
150+
} while (ec_has_more_events);
162151
}
163152

164153
static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,

include/linux/platform_data/cros_ec_proto.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ struct cros_ec_command {
116116
* code.
117117
* @pkt_xfer: Send packet to EC and get response.
118118
* @lock: One transaction at a time.
119-
* @mkbp_event_supported: True if this EC supports the MKBP event protocol.
119+
* @mkbp_event_supported: 0 if MKBP not supported. Otherwise its value is
120+
* the maximum supported version of the MKBP host event
121+
* command + 1.
120122
* @host_sleep_v1: True if this EC supports the sleep v1 command.
121123
* @event_notifier: Interrupt event notifier for transport devices.
122124
* @event_data: Raw payload transferred with the MKBP event.
@@ -156,7 +158,7 @@ struct cros_ec_device {
156158
int (*pkt_xfer)(struct cros_ec_device *ec,
157159
struct cros_ec_command *msg);
158160
struct mutex lock;
159-
bool mkbp_event_supported;
161+
u8 mkbp_event_supported;
160162
bool host_sleep_v1;
161163
struct blocking_notifier_head event_notifier;
162164

@@ -205,14 +207,18 @@ int cros_ec_unregister(struct cros_ec_device *ec_dev);
205207

206208
int cros_ec_query_all(struct cros_ec_device *ec_dev);
207209

208-
int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
210+
int cros_ec_get_next_event(struct cros_ec_device *ec_dev,
211+
bool *wake_event,
212+
bool *has_more_events);
209213

210214
u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
211215

212216
int cros_ec_check_features(struct cros_ec_dev *ec, int feature);
213217

214218
int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
215219

220+
bool cros_ec_handle_event(struct cros_ec_device *ec_dev);
221+
216222
/**
217223
* cros_ec_get_time_ns() - Return time in ns.
218224
*

0 commit comments

Comments
 (0)