* [PATCH RESEND v3 0/2] Add a property to turn off the max touch controller in suspend mode
From: Stefan Eichenberger @ 2024-02-09 10:50 UTC (permalink / raw)
To: nick, dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, linus.walleij
Cc: linux-input, devicetree, linux-arm-kernel, linux-kernel,
francesco.dolcini
Our hardware has a shared regulator that powers various peripherals such
as the display, touch, USB hub, etc. Since the Maxtouch controller
doesn't currently allow it to be turned off, this regulator has to stay
on in suspend mode. This increases the overall power consumption. In
order to turn off the controller when the system goes into suspend mode,
this series adds a device tree property to the maxtouch driver that
allows the controller to be turned off completely and ensurs that it can
resume from the power off state.
Resend v3:
- Previously I messed up the series because send-email crashed. This is
a resend of the original series:
https://lore.kernel.org/linux-input/20240209084543.14726-1-eichest@gmail.com/T/#t
https://lore.kernel.org/linux-input/20240209084818.14925-1-eichest@gmail.com/T/#u
Changes since v2:
- Add Reviewed-by tags from Linus and Krzysztof to the dt-bindings patch
Changes since v1:
- Rename the property and change the description (Krzysztof, Linus,
Dmitry, Conor)
Stefan Eichenberger (2):
dt-bindings: input: atmel,maxtouch: add poweroff-sleep property
Input: atmel_mxt_ts - support poweroff in suspend
.../bindings/input/atmel,maxtouch.yaml | 6 ++
drivers/input/touchscreen/atmel_mxt_ts.c | 72 ++++++++++++++-----
2 files changed, 61 insertions(+), 17 deletions(-)
--
2.40.1
^ permalink raw reply
* [PATCH RESEND v3 1/2] dt-bindings: input: atmel,maxtouch: add poweroff-sleep property
From: Stefan Eichenberger @ 2024-02-09 10:50 UTC (permalink / raw)
To: nick, dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, linus.walleij
Cc: linux-input, devicetree, linux-arm-kernel, linux-kernel,
francesco.dolcini, Stefan Eichenberger, Krzysztof Kozlowski
In-Reply-To: <20240209105012.22470-1-eichest@gmail.com>
From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
Add a new property to indicate that the device should power off rather
than use deep sleep. Deep sleep is a feature of the controller that
expects the controller to remain powered in suspend. However, if a
display shares its regulator with the touch controller, we may want to
do a power off so that the display and touch controller do not use any
power.
Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
Documentation/devicetree/bindings/input/atmel,maxtouch.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml b/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
index c40799355ed7..8de5f539b30e 100644
--- a/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
+++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
@@ -87,6 +87,12 @@ properties:
- 2 # ATMEL_MXT_WAKEUP_GPIO
default: 0
+ atmel,poweroff-sleep:
+ description: |
+ Instead of using the deep sleep feature of the maXTouch controller,
+ poweroff the regulators.
+ type: boolean
+
wakeup-source:
type: boolean
--
2.40.1
^ permalink raw reply related
* [PATCH RESEND v3 2/2] Input: atmel_mxt_ts - support poweroff in suspend
From: Stefan Eichenberger @ 2024-02-09 10:50 UTC (permalink / raw)
To: nick, dmitry.torokhov, robh+dt, krzysztof.kozlowski+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, linus.walleij
Cc: linux-input, devicetree, linux-arm-kernel, linux-kernel,
francesco.dolcini, Stefan Eichenberger
In-Reply-To: <20240209105012.22470-1-eichest@gmail.com>
From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
Add a new device tree property to indicate that the device should be
powered off in suspend mode. We have a shared regulator that powers the
display, a USB hub and some other peripherals. The maXTouch controller
doesn't normally disable the regulator in suspend mode, so our extra
peripherals stay powered on. This is not desirable as it consumes more
power. With this patch we add the option to disable the regulator in
suspend mode for the maXTouch and accept the longer initialisation time.
Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 72 ++++++++++++++++++------
1 file changed, 55 insertions(+), 17 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 542a31448c8f..2d5655385702 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -317,6 +317,7 @@ struct mxt_data {
struct gpio_desc *reset_gpio;
struct gpio_desc *wake_gpio;
bool use_retrigen_workaround;
+ bool poweroff_sleep;
/* Cached parameters from object table */
u16 T5_address;
@@ -2799,15 +2800,18 @@ static int mxt_configure_objects(struct mxt_data *data,
dev_warn(dev, "Error %d updating config\n", error);
}
- if (data->multitouch) {
- error = mxt_initialize_input_device(data);
- if (error)
- return error;
- } else {
- dev_warn(dev, "No touch object detected\n");
- }
+ /* If input device is not already registered */
+ if (!data->input_dev) {
+ if (data->multitouch) {
+ error = mxt_initialize_input_device(data);
+ if (error)
+ return error;
+ } else {
+ dev_warn(dev, "No touch object detected\n");
+ }
- mxt_debug_init(data);
+ mxt_debug_init(data);
+ }
return 0;
}
@@ -3325,6 +3329,8 @@ static int mxt_probe(struct i2c_client *client)
msleep(MXT_RESET_INVALID_CHG);
}
+ data->poweroff_sleep = device_property_read_bool(&client->dev,
+ "atmel,poweroff-sleep");
/*
* Controllers like mXT1386 have a dedicated WAKE line that could be
* connected to a GPIO or to I2C SCL pin, or permanently asserted low.
@@ -3387,12 +3393,21 @@ static int mxt_suspend(struct device *dev)
if (!input_dev)
return 0;
- mutex_lock(&input_dev->mutex);
+ if (!device_may_wakeup(dev) && data->poweroff_sleep) {
+ if (data->reset_gpio)
+ gpiod_set_value(data->reset_gpio, 1);
- if (input_device_enabled(input_dev))
- mxt_stop(data);
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ data->T44_address = 0;
+ } else {
+ mutex_lock(&input_dev->mutex);
+
+ if (input_device_enabled(input_dev))
+ mxt_stop(data);
- mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&input_dev->mutex);
+ }
disable_irq(data->irq);
@@ -3408,14 +3423,37 @@ static int mxt_resume(struct device *dev)
if (!input_dev)
return 0;
- enable_irq(data->irq);
+ if (!device_may_wakeup(dev) && data->poweroff_sleep) {
+ int ret;
- mutex_lock(&input_dev->mutex);
+ ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (ret) {
+ dev_err(dev, "failed to enable regulators: %d\n",
+ ret);
+ return ret;
+ }
+ msleep(MXT_BACKUP_TIME);
- if (input_device_enabled(input_dev))
- mxt_start(data);
+ if (data->reset_gpio) {
+ /* Wait a while and then de-assert the RESET GPIO line */
+ msleep(MXT_RESET_GPIO_TIME);
+ gpiod_set_value(data->reset_gpio, 0);
+ msleep(MXT_RESET_INVALID_CHG);
+ }
- mutex_unlock(&input_dev->mutex);
+ /* This also enables the irq again */
+ mxt_initialize(data);
+ } else {
+ enable_irq(data->irq);
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_device_enabled(input_dev))
+ mxt_start(data);
+
+ mutex_unlock(&input_dev->mutex);
+ }
return 0;
}
--
2.40.1
^ permalink raw reply related
* [PATCH RFC bpf-next 0/9] allow HID-BPF to do device IOs
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
[Putting this as a RFC because I'm pretty sure I'm not doing the things
correctly at the BPF level.]
[Also using bpf-next as the base tree as there will be conflicting
changes otherwise]
Ideally I'd like to have something similar to bpf_timers, but not
in soft IRQ context. So I'm emulating this with a sleepable
bpf_tail_call() (see "HID: bpf: allow to defer work in a delayed
workqueue").
Basically, I need to be able to defer a HID-BPF program for the
following reasons (from the aforementioned patch):
1. defer an event:
Sometimes we receive an out of proximity event, but the device can not
be trusted enough, and we need to ensure that we won't receive another
one in the following n milliseconds. So we need to wait those n
milliseconds, and eventually re-inject that event in the stack.
2. inject new events in reaction to one given event:
We might want to transform one given event into several. This is the
case for macro keys where a single key press is supposed to send
a sequence of key presses. But this could also be used to patch a
faulty behavior, if a device forgets to send a release event.
3. communicate with the device in reaction to one event:
We might want to communicate back to the device after a given event.
For example a device might send us an event saying that it came back
from sleeping state and needs to be re-initialized.
Currently we can achieve that by keeping a userspace program around,
raise a bpf event, and let that userspace program inject the events and
commands.
However, we are just keeping that program alive as a daemon for just
scheduling commands. There is no logic in it, so it doesn't really justify
an actual userspace wakeup. So a kernel workqueue seems simpler to handle.
Besides the "this is insane to reimplement the wheel", the other part I'm
not sure is whether we can say that BPF maps of type prog_array and of
type queue/stack can be used in sleepable context.
I don't see any warning when running the test programs, but that's probably
not a guarantee I'm doing the things properly :)
Cheers,
Benjamin
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
Benjamin Tissoires (9):
bpf: allow more maps in sleepable bpf programs
HID: bpf/dispatch: regroup kfuncs definitions
HID: bpf: export hid_hw_output_report as a BPF kfunc
selftests/hid: Add test for hid_bpf_hw_output_report
HID: bpf: allow to inject HID event from BPF
selftests/hid: add tests for hid_bpf_input_report
HID: bpf: allow to defer work in a delayed workqueue
selftests/hid: add test for hid_bpf_schedule_delayed_work
selftests/hid: add another set of delayed work tests
Documentation/hid/hid-bpf.rst | 26 +-
drivers/hid/bpf/entrypoints/entrypoints.bpf.c | 8 +
drivers/hid/bpf/entrypoints/entrypoints.lskel.h | 236 +++++++++------
drivers/hid/bpf/hid_bpf_dispatch.c | 315 ++++++++++++++++-----
drivers/hid/bpf/hid_bpf_jmp_table.c | 34 ++-
drivers/hid/hid-core.c | 2 +
include/linux/hid_bpf.h | 10 +
kernel/bpf/verifier.c | 3 +
tools/testing/selftests/hid/hid_bpf.c | 286 ++++++++++++++++++-
tools/testing/selftests/hid/progs/hid.c | 205 ++++++++++++++
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 8 +
11 files changed, 962 insertions(+), 171 deletions(-)
---
base-commit: 4f7a05917237b006ceae760507b3d15305769ade
change-id: 20240205-hid-bpf-sleepable-c01260fd91c4
Best regards,
--
Benjamin Tissoires <bentiss@kernel.org>
^ permalink raw reply
* [PATCH RFC bpf-next 1/9] bpf: allow more maps in sleepable bpf programs
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
These 3 maps types are required for HID-BPF when a user wants to do
IO with a device from a sleepable tracing point.
HID-BPF relies on `bpf_tail_call()` to selectively call the BPF programs
attached to a device, thus we need BPF_MAP_TYPE_PROG_ARRAY access.
Allowing BPF_MAP_TYPE_QUEUE (and therefore BPF_MAP_TYPE_STACK) allows
for a BPF program to prepare from an IRQ the list of HID commands to send
back to the device and then these commands can be retrieved from the
sleepable trace point.
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
kernel/bpf/verifier.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 64fa188d00ad..3cc880ecd3e4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18028,6 +18028,9 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
case BPF_MAP_TYPE_SK_STORAGE:
case BPF_MAP_TYPE_TASK_STORAGE:
case BPF_MAP_TYPE_CGRP_STORAGE:
+ case BPF_MAP_TYPE_PROG_ARRAY:
+ case BPF_MAP_TYPE_QUEUE:
+ case BPF_MAP_TYPE_STACK:
break;
default:
verbose(env,
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 2/9] HID: bpf/dispatch: regroup kfuncs definitions
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
No code change, just move down the hid_bpf_get_data() kfunc definition
so we have only one block of __bpf_kfunc_start/end_defs()
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
drivers/hid/bpf/hid_bpf_dispatch.c | 80 ++++++++++++++++++--------------------
1 file changed, 38 insertions(+), 42 deletions(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index e630caf644e8..52abb27426f4 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -143,48 +143,6 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
}
EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
-/* Disables missing prototype warnings */
-__bpf_kfunc_start_defs();
-
-/**
- * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
- *
- * @ctx: The HID-BPF context
- * @offset: The offset within the memory
- * @rdwr_buf_size: the const size of the buffer
- *
- * @returns %NULL on error, an %__u8 memory pointer on success
- */
-__bpf_kfunc __u8 *
-hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
-{
- struct hid_bpf_ctx_kern *ctx_kern;
-
- if (!ctx)
- return NULL;
-
- ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
-
- if (rdwr_buf_size + offset > ctx->allocated_size)
- return NULL;
-
- return ctx_kern->data + offset;
-}
-__bpf_kfunc_end_defs();
-
-/*
- * The following set contains all functions we agree BPF programs
- * can use.
- */
-BTF_KFUNCS_START(hid_bpf_kfunc_ids)
-BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
-BTF_KFUNCS_END(hid_bpf_kfunc_ids)
-
-static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
- .owner = THIS_MODULE,
- .set = &hid_bpf_kfunc_ids,
-};
-
static int device_match_id(struct device *dev, const void *id)
{
struct hid_device *hdev = to_hid_device(dev);
@@ -281,6 +239,31 @@ static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct b
/* Disables missing prototype warnings */
__bpf_kfunc_start_defs();
+/**
+ * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
+ *
+ * @ctx: The HID-BPF context
+ * @offset: The offset within the memory
+ * @rdwr_buf_size: the const size of the buffer
+ *
+ * @returns %NULL on error, an %__u8 memory pointer on success
+ */
+__bpf_kfunc __u8 *
+hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+
+ if (!ctx)
+ return NULL;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+
+ if (rdwr_buf_size + offset > ctx->allocated_size)
+ return NULL;
+
+ return ctx_kern->data + offset;
+}
+
/**
* hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
*
@@ -474,6 +457,19 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
}
__bpf_kfunc_end_defs();
+/*
+ * The following set contains all functions we agree BPF programs
+ * can use.
+ */
+BTF_KFUNCS_START(hid_bpf_kfunc_ids)
+BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
+BTF_KFUNCS_END(hid_bpf_kfunc_ids)
+
+static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &hid_bpf_kfunc_ids,
+};
+
/* our HID-BPF entrypoints */
BTF_SET8_START(hid_bpf_fmodret_ids)
BTF_ID_FLAGS(func, hid_bpf_device_event)
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 3/9] HID: bpf: export hid_hw_output_report as a BPF kfunc
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
We currently only export hid_hw_raw_request() as a BPF kfunc.
However, some devices require an explicit write on the Output Report
instead of the use of the control channel.
So also export hid_hw_output_report to BPF
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
Documentation/hid/hid-bpf.rst | 2 +-
drivers/hid/bpf/hid_bpf_dispatch.c | 112 +++++++++++++++++++++++++++----------
drivers/hid/hid-core.c | 1 +
include/linux/hid_bpf.h | 1 +
4 files changed, 86 insertions(+), 30 deletions(-)
diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst
index 4fad83a6ebc3..a575004d9025 100644
--- a/Documentation/hid/hid-bpf.rst
+++ b/Documentation/hid/hid-bpf.rst
@@ -179,7 +179,7 @@ Available API that can be used in syscall HID-BPF programs:
-----------------------------------------------------------
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
- :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_allocate_context hid_bpf_release_context
+ :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_allocate_context hid_bpf_release_context
General overview of a HID-BPF program
=====================================
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 52abb27426f4..a5b88b491b80 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -376,6 +376,46 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
put_device(&hid->dev);
}
+static int
+__hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
+ enum hid_report_type rtype)
+{
+ struct hid_report_enum *report_enum;
+ struct hid_report *report;
+ struct hid_device *hdev;
+ u32 report_len;
+
+ /* check arguments */
+ if (!ctx || !hid_bpf_ops || !buf)
+ return -EINVAL;
+
+ switch (rtype) {
+ case HID_INPUT_REPORT:
+ case HID_OUTPUT_REPORT:
+ case HID_FEATURE_REPORT:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (*buf__sz < 1)
+ return -EINVAL;
+
+ hdev = (struct hid_device *)ctx->hid; /* discard const */
+
+ report_enum = hdev->report_enum + rtype;
+ report = hid_bpf_ops->hid_get_report(report_enum, buf);
+ if (!report)
+ return -EINVAL;
+
+ report_len = hid_report_len(report);
+
+ if (*buf__sz > report_len)
+ *buf__sz = report_len;
+
+ return 0;
+}
+
/**
* hid_bpf_hw_request - Communicate with a HID device
*
@@ -392,24 +432,14 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
enum hid_report_type rtype, enum hid_class_request reqtype)
{
struct hid_device *hdev;
- struct hid_report *report;
- struct hid_report_enum *report_enum;
+ size_t size = buf__sz;
u8 *dma_data;
- u32 report_len;
int ret;
/* check arguments */
- if (!ctx || !hid_bpf_ops || !buf)
- return -EINVAL;
-
- switch (rtype) {
- case HID_INPUT_REPORT:
- case HID_OUTPUT_REPORT:
- case HID_FEATURE_REPORT:
- break;
- default:
- return -EINVAL;
- }
+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype);
+ if (ret)
+ return ret;
switch (reqtype) {
case HID_REQ_GET_REPORT:
@@ -423,29 +453,16 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
return -EINVAL;
}
- if (buf__sz < 1)
- return -EINVAL;
-
hdev = (struct hid_device *)ctx->hid; /* discard const */
- report_enum = hdev->report_enum + rtype;
- report = hid_bpf_ops->hid_get_report(report_enum, buf);
- if (!report)
- return -EINVAL;
-
- report_len = hid_report_len(report);
-
- if (buf__sz > report_len)
- buf__sz = report_len;
-
- dma_data = kmemdup(buf, buf__sz, GFP_KERNEL);
+ dma_data = kmemdup(buf, size, GFP_KERNEL);
if (!dma_data)
return -ENOMEM;
ret = hid_bpf_ops->hid_hw_raw_request(hdev,
dma_data[0],
dma_data,
- buf__sz,
+ size,
rtype,
reqtype);
@@ -455,6 +472,42 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
kfree(dma_data);
return ret;
}
+
+/**
+ * hid_bpf_hw_output_report - Send an output report to a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ *
+ * @returns the number of bytes transferred on success, a negative error code otherwise.
+ */
+__bpf_kfunc int
+hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
+{
+ struct hid_device *hdev;
+ size_t size = buf__sz;
+ u8 *dma_data;
+ int ret;
+
+ /* check arguments */
+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT);
+ if (ret)
+ return ret;
+
+ hdev = (struct hid_device *)ctx->hid; /* discard const */
+
+ dma_data = kmemdup(buf, size, GFP_KERNEL);
+ if (!dma_data)
+ return -ENOMEM;
+
+ ret = hid_bpf_ops->hid_hw_output_report(hdev,
+ dma_data,
+ size);
+
+ kfree(dma_data);
+ return ret;
+}
__bpf_kfunc_end_defs();
/*
@@ -488,6 +541,7 @@ BTF_ID_FLAGS(func, hid_bpf_attach_prog)
BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
BTF_ID_FLAGS(func, hid_bpf_hw_request)
+BTF_ID_FLAGS(func, hid_bpf_hw_output_report)
BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index de7a477d6665..1243595890ba 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2974,6 +2974,7 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
static struct hid_bpf_ops hid_ops = {
.hid_get_report = hid_get_report,
.hid_hw_raw_request = hid_hw_raw_request,
+ .hid_hw_output_report = hid_hw_output_report,
.owner = THIS_MODULE,
.bus_type = &hid_bus_type,
};
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 7118ac28d468..5c7ff93dc73e 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -103,6 +103,7 @@ struct hid_bpf_ops {
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype);
+ int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len);
struct module *owner;
const struct bus_type *bus_type;
};
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 4/9] selftests/hid: Add test for hid_bpf_hw_output_report
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
This time we need to ensure uhid receives it, thus the new mutex and
condition.
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
tools/testing/selftests/hid/hid_bpf.c | 63 ++++++++++++++++++++++
tools/testing/selftests/hid/progs/hid.c | 24 +++++++++
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 2 +
3 files changed, 89 insertions(+)
diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index 2cf96f818f25..a6d72c8ae7cd 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -16,6 +16,11 @@
#define SHOW_UHID_DEBUG 0
+#define min(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a < _b ? _a : _b; })
+
static unsigned char rdesc[] = {
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
0x09, 0x21, /* Usage (Vendor Usage 0x21) */
@@ -111,6 +116,10 @@ struct hid_hw_request_syscall_args {
static pthread_mutex_t uhid_started_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t uhid_started = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t uhid_output_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t uhid_output_cond = PTHREAD_COND_INITIALIZER;
+static unsigned char output_report[10];
+
/* no need to protect uhid_stopped, only one thread accesses it */
static bool uhid_stopped;
@@ -205,6 +214,13 @@ static int uhid_event(struct __test_metadata *_metadata, int fd)
break;
case UHID_OUTPUT:
UHID_LOG("UHID_OUTPUT from uhid-dev");
+
+ pthread_mutex_lock(&uhid_output_mtx);
+ memcpy(output_report,
+ ev.u.output.data,
+ min(ev.u.output.size, sizeof(output_report)));
+ pthread_cond_signal(&uhid_output_cond);
+ pthread_mutex_unlock(&uhid_output_mtx);
break;
case UHID_GET_REPORT:
UHID_LOG("UHID_GET_REPORT from uhid-dev");
@@ -733,6 +749,53 @@ TEST_F(hid_bpf, test_hid_change_report)
ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");
}
+/*
+ * Call hid_bpf_hw_output_report against the given uhid device,
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_user_output_report_call)
+{
+ struct hid_hw_request_syscall_args args = {
+ .retval = -1,
+ .size = 10,
+ };
+ DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
+ .ctx_in = &args,
+ .ctx_size_in = sizeof(args),
+ );
+ int err, cond_err, prog_fd;
+ struct timespec time_to_wait;
+
+ LOAD_BPF;
+
+ args.hid = self->hid_id;
+ args.data[0] = 1; /* report ID */
+ args.data[1] = 2; /* report ID */
+ args.data[2] = 42; /* report ID */
+
+ prog_fd = bpf_program__fd(self->skel->progs.hid_user_output_report);
+
+ pthread_mutex_lock(&uhid_output_mtx);
+
+ memset(output_report, 0, sizeof(output_report));
+ clock_gettime(CLOCK_REALTIME, &time_to_wait);
+ time_to_wait.tv_sec += 2;
+
+ err = bpf_prog_test_run_opts(prog_fd, &tattrs);
+ cond_err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);
+
+ ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");
+ ASSERT_OK(cond_err) TH_LOG("error while calling waiting for the condition");
+
+ ASSERT_EQ(args.retval, 3);
+
+ ASSERT_EQ(output_report[0], 1);
+ ASSERT_EQ(output_report[1], 2);
+ ASSERT_EQ(output_report[2], 42);
+
+ pthread_mutex_unlock(&uhid_output_mtx);
+}
+
/*
* Attach hid_user_raw_request to the given uhid device,
* call the bpf program from userspace
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index 1e558826b809..2c2b679a83b1 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -101,6 +101,30 @@ int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
return 0;
}
+SEC("syscall")
+int hid_user_output_report(struct hid_hw_request_syscall_args *args)
+{
+ struct hid_bpf_ctx *ctx;
+ const size_t size = args->size;
+ int i, ret = 0;
+
+ if (size > sizeof(args->data))
+ return -7; /* -E2BIG */
+
+ ctx = hid_bpf_allocate_context(args->hid);
+ if (!ctx)
+ return -1; /* EPERM check */
+
+ ret = hid_bpf_hw_output_report(ctx,
+ args->data,
+ size);
+ args->retval = ret;
+
+ hid_bpf_release_context(ctx);
+
+ return 0;
+}
+
static const __u8 rdesc[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x32, /* USAGE (Z) */
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index 65e657ac1198..50c6a0d5765e 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -94,5 +94,7 @@ extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
size_t buf__sz,
enum hid_report_type type,
enum hid_class_request reqtype) __ksym;
+extern int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx,
+ __u8 *buf, size_t buf__sz) __ksym;
#endif /* __HID_BPF_HELPERS_H */
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 5/9] HID: bpf: allow to inject HID event from BPF
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
It can be interesting to inject events from BPF as if the event were
to come from the device.
For example, some multitouch devices do not all the time send a proximity
out event, and we might want to send it for the physical device.
Compared to uhid, we can now inject events on any physical device, not
just uhid virtual ones.
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
Documentation/hid/hid-bpf.rst | 2 +-
drivers/hid/bpf/hid_bpf_dispatch.c | 29 +++++++++++++++++++++++++++++
drivers/hid/hid-core.c | 1 +
include/linux/hid_bpf.h | 2 ++
4 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst
index a575004d9025..0765b3298ecf 100644
--- a/Documentation/hid/hid-bpf.rst
+++ b/Documentation/hid/hid-bpf.rst
@@ -179,7 +179,7 @@ Available API that can be used in syscall HID-BPF programs:
-----------------------------------------------------------
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
- :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_allocate_context hid_bpf_release_context
+ :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context
General overview of a HID-BPF program
=====================================
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index a5b88b491b80..e1a650f4a626 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -508,6 +508,34 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
kfree(dma_data);
return ret;
}
+
+/**
+ * hid_bpf_input_report - Inject a HID report in the kernel from a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @type: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ *
+ * @returns %0 on success, a negative error code otherwise.
+ */
+__bpf_kfunc int
+hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf,
+ const size_t buf__sz)
+{
+ struct hid_device *hdev;
+ size_t size = buf__sz;
+ int ret;
+
+ /* check arguments */
+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, type);
+ if (ret)
+ return ret;
+
+ hdev = (struct hid_device *)ctx->hid; /* discard const */
+
+ return hid_input_report(hdev, type, buf, size, 0);
+}
__bpf_kfunc_end_defs();
/*
@@ -542,6 +570,7 @@ BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
BTF_ID_FLAGS(func, hid_bpf_hw_request)
BTF_ID_FLAGS(func, hid_bpf_hw_output_report)
+BTF_ID_FLAGS(func, hid_bpf_input_report)
BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1243595890ba..b1fa0378e8f4 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2975,6 +2975,7 @@ static struct hid_bpf_ops hid_ops = {
.hid_get_report = hid_get_report,
.hid_hw_raw_request = hid_hw_raw_request,
.hid_hw_output_report = hid_hw_output_report,
+ .hid_input_report = hid_input_report,
.owner = THIS_MODULE,
.bus_type = &hid_bus_type,
};
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 5c7ff93dc73e..17b08f500098 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -104,6 +104,8 @@ struct hid_bpf_ops {
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype);
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len);
+ int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
+ u8 *data, u32 size, int interrupt);
struct module *owner;
const struct bus_type *bus_type;
};
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 6/9] selftests/hid: add tests for hid_bpf_input_report
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
Usual way of testing, we call the function and ensures we receive
the event
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
tools/testing/selftests/hid/hid_bpf.c | 49 +++++++++++++++++++++-
tools/testing/selftests/hid/progs/hid.c | 22 ++++++++++
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 4 ++
3 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index a6d72c8ae7cd..9ff02c737144 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -749,6 +749,52 @@ TEST_F(hid_bpf, test_hid_change_report)
ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");
}
+/*
+ * Call hid_bpf_input_report against the given uhid device,
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_user_input_report_call)
+{
+ struct hid_hw_request_syscall_args args = {
+ .retval = -1,
+ .size = 10,
+ };
+ DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
+ .ctx_in = &args,
+ .ctx_size_in = sizeof(args),
+ );
+ __u8 buf[10] = {0};
+ int err, prog_fd;
+
+ LOAD_BPF;
+
+ args.hid = self->hid_id;
+ args.data[0] = 1; /* report ID */
+ args.data[1] = 2; /* report ID */
+ args.data[2] = 42; /* report ID */
+
+ prog_fd = bpf_program__fd(self->skel->progs.hid_user_input_report);
+
+ /* check that there is no data to read from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, -1) TH_LOG("read_hidraw");
+
+ err = bpf_prog_test_run_opts(prog_fd, &tattrs);
+
+ ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");
+
+ ASSERT_EQ(args.retval, 0);
+
+ /* read the data from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+ ASSERT_EQ(buf[0], 1);
+ ASSERT_EQ(buf[1], 2);
+ ASSERT_EQ(buf[2], 42);
+}
+
/*
* Call hid_bpf_hw_output_report against the given uhid device,
* check that the program is called and does the expected.
@@ -797,8 +843,7 @@ TEST_F(hid_bpf, test_hid_user_output_report_call)
}
/*
- * Attach hid_user_raw_request to the given uhid device,
- * call the bpf program from userspace
+ * Call hid_hw_raw_request against the given uhid device,
* check that the program is called and does the expected.
*/
TEST_F(hid_bpf, test_hid_user_raw_request_call)
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index 2c2b679a83b1..f67d35def142 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -125,6 +125,28 @@ int hid_user_output_report(struct hid_hw_request_syscall_args *args)
return 0;
}
+SEC("syscall")
+int hid_user_input_report(struct hid_hw_request_syscall_args *args)
+{
+ struct hid_bpf_ctx *ctx;
+ const size_t size = args->size;
+ int i, ret = 0;
+
+ if (size > sizeof(args->data))
+ return -7; /* -E2BIG */
+
+ ctx = hid_bpf_allocate_context(args->hid);
+ if (!ctx)
+ return -1; /* EPERM check */
+
+ ret = hid_bpf_input_report(ctx, HID_INPUT_REPORT, args->data, size);
+ args->retval = ret;
+
+ hid_bpf_release_context(ctx);
+
+ return 0;
+}
+
static const __u8 rdesc[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x32, /* USAGE (Z) */
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index 50c6a0d5765e..9cd56821d0f1 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -96,5 +96,9 @@ extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
enum hid_class_request reqtype) __ksym;
extern int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx,
__u8 *buf, size_t buf__sz) __ksym;
+extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
+ enum hid_report_type type,
+ __u8 *data,
+ size_t buf__sz) __ksym;
#endif /* __HID_BPF_HELPERS_H */
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 7/9] HID: bpf: allow to defer work in a delayed workqueue
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
This allows to defer work for later for being able to:
1. defer an event:
Sometimes we receive an out of proximity event, but the device can not
be trusted enough, and we need to ensure that we won't receive another
one in the n following milliseconds. So we need to wait those n
milliseconds, and eventually re-inject that event in the stack.
2. inject new events in reaction to one given event:
We might want to transform one given event into several. This is the
case for macro keys where a single key press is supposed to send
a sequence of key presses. But this could also be used to patch a
faulty behavior, if a device forgets to send a release event
3. communicate with the device in reaction to one event:
We might want to communicate back to the device after a given event.
For example a device might send us an event saying that it came back
from sleep state and needs to be re-initialized.
Currently we can achieve that by keeping a userspace program around,
raise a bpf event, and let that userspace program inject the events and
commands.
However, we are just keeping that program alive as a daemon for just
scheduling commands, so there is no logic that would justify an actual
userspace wakeup. So a kernel workqueue is simpler to handle.
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
Documentation/hid/hid-bpf.rst | 24 ++-
drivers/hid/bpf/entrypoints/entrypoints.bpf.c | 8 +
drivers/hid/bpf/entrypoints/entrypoints.lskel.h | 236 +++++++++++++++---------
drivers/hid/bpf/hid_bpf_dispatch.c | 94 +++++++++-
drivers/hid/bpf/hid_bpf_jmp_table.c | 34 +++-
include/linux/hid_bpf.h | 7 +
6 files changed, 307 insertions(+), 96 deletions(-)
diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst
index 0765b3298ecf..25b157fd8ed2 100644
--- a/Documentation/hid/hid-bpf.rst
+++ b/Documentation/hid/hid-bpf.rst
@@ -140,6 +140,7 @@ HID-BPF has the following attachment types available:
1. event processing/filtering with ``SEC("fmod_ret/hid_bpf_device_event")`` in libbpf
2. actions coming from userspace with ``SEC("syscall")`` in libbpf
3. change of the report descriptor with ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` in libbpf
+4. execute a delayed action with ``SEC("fmod_ret.s/hid_bpf_offload")`` in libbpf
A ``hid_bpf_device_event`` is calling a BPF program when an event is received from
the device. Thus we are in IRQ context and can act on the data or notify userspace.
@@ -149,6 +150,12 @@ A ``syscall`` means that userspace called the syscall ``BPF_PROG_RUN`` facility.
This time, we can do any operations allowed by HID-BPF, and talking to the device is
allowed.
+A ``hid_bpf_offload`` is called whenever a HID-BPF program attached to ``hid_bpf_device_event``
+is calling the kfunc ``hid_bpf_schedule_delayed_work``. The jobs are globally
+shared per HID device, this might be called more than expected, because another
+HID-BPF program might call ``hid_bpf_schedule_delayed_work``. So please ensure
+you actually have job scheduled.
+
Last, ``hid_bpf_rdesc_fixup`` is different from the others as there can be only one
BPF program of this type. This is called on ``probe`` from the driver and allows to
change the report descriptor from the BPF program. Once a ``hid_bpf_rdesc_fixup``
@@ -167,13 +174,13 @@ Available tracing functions to attach a HID-BPF program:
--------------------------------------------------------
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
- :functions: hid_bpf_device_event hid_bpf_rdesc_fixup
+ :functions: hid_bpf_device_event hid_bpf_rdesc_fixup hid_bpf_offload
Available API that can be used in all HID-BPF programs:
-------------------------------------------------------
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
- :functions: hid_bpf_get_data
+ :functions: hid_bpf_get_data hid_bpf_schedule_delayed_work
Available API that can be used in syscall HID-BPF programs:
-----------------------------------------------------------
@@ -181,6 +188,19 @@ Available API that can be used in syscall HID-BPF programs:
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
:functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context
+Available API that can be used in sleepable HID-BPF programs:
+-------------------------------------------------------------
+
+When using a sleepable HID-BPF program (attached with ``SEC("fmod_ret.s/hid_bpf_offload")``),
+you can use the following functions:
+
+- ``hid_bpf_hw_request``
+- ``hid_bpf_hw_output_report``
+- ``hid_bpf_input_report``
+- ``hid_bpf_schedule_delayed_work``
+- ``hid_bpf_allocate_context``
+- ``hid_bpf_release_context``
+
General overview of a HID-BPF program
=====================================
diff --git a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c b/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
index c22921125a1a..fe7d5c808034 100644
--- a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
+++ b/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
@@ -22,4 +22,12 @@ int BPF_PROG(hid_tail_call, struct hid_bpf_ctx *hctx)
return 0;
}
+SEC("fmod_ret.s/__hid_bpf_tail_call_sleepable")
+int BPF_PROG(hid_tail_call_sleepable, struct hid_bpf_ctx *hctx)
+{
+ bpf_tail_call(ctx, &hid_jmp_table, hctx->index);
+
+ return 0;
+}
+
char LICENSE[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h b/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
index 35618051598c..8883c436ab8c 100644
--- a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
+++ b/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
@@ -12,9 +12,11 @@ struct entrypoints_bpf {
} maps;
struct {
struct bpf_prog_desc hid_tail_call;
+ struct bpf_prog_desc hid_tail_call_sleepable;
} progs;
struct {
int hid_tail_call_fd;
+ int hid_tail_call_sleepable_fd;
} links;
};
@@ -29,12 +31,24 @@ entrypoints_bpf__hid_tail_call__attach(struct entrypoints_bpf *skel)
return fd;
}
+static inline int
+entrypoints_bpf__hid_tail_call_sleepable__attach(struct entrypoints_bpf *skel)
+{
+ int prog_fd = skel->progs.hid_tail_call_sleepable.prog_fd;
+ int fd = skel_raw_tracepoint_open(NULL, prog_fd);
+
+ if (fd > 0)
+ skel->links.hid_tail_call_sleepable_fd = fd;
+ return fd;
+}
+
static inline int
entrypoints_bpf__attach(struct entrypoints_bpf *skel)
{
int ret = 0;
ret = ret < 0 ? ret : entrypoints_bpf__hid_tail_call__attach(skel);
+ ret = ret < 0 ? ret : entrypoints_bpf__hid_tail_call_sleepable__attach(skel);
return ret < 0 ? ret : 0;
}
@@ -42,6 +56,7 @@ static inline void
entrypoints_bpf__detach(struct entrypoints_bpf *skel)
{
skel_closenz(skel->links.hid_tail_call_fd);
+ skel_closenz(skel->links.hid_tail_call_sleepable_fd);
}
static void
entrypoints_bpf__destroy(struct entrypoints_bpf *skel)
@@ -50,6 +65,7 @@ entrypoints_bpf__destroy(struct entrypoints_bpf *skel)
return;
entrypoints_bpf__detach(skel);
skel_closenz(skel->progs.hid_tail_call.prog_fd);
+ skel_closenz(skel->progs.hid_tail_call_sleepable.prog_fd);
skel_closenz(skel->maps.hid_jmp_table.map_fd);
skel_free(skel);
}
@@ -73,10 +89,7 @@ entrypoints_bpf__load(struct entrypoints_bpf *skel)
{
struct bpf_load_and_run_opts opts = {};
int err;
-
- opts.ctx = (struct bpf_loader_ctx *)skel;
- opts.data_sz = 2856;
- opts.data = (void *)"\
+ static const char opts_data[] __attribute__((__aligned__(8))) = "\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
@@ -110,7 +123,7 @@ entrypoints_bpf__load(struct entrypoints_bpf *skel)
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\
-\x18\0\0\0\0\0\0\0\x60\x02\0\0\x60\x02\0\0\x12\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\
+\x18\0\0\0\0\0\0\0\x80\x02\0\0\x80\x02\0\0\x93\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\
\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\
\0\0\x04\0\0\0\x03\0\0\0\x05\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\
\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\
@@ -123,96 +136,141 @@ entrypoints_bpf__load(struct entrypoints_bpf *skel)
\0\0\0\0\0\0\0\x1b\x01\0\0\x12\0\0\0\x40\0\0\0\x1f\x01\0\0\x10\0\0\0\x80\0\0\0\
\x2e\x01\0\0\x14\0\0\0\xa0\0\0\0\0\0\0\0\x15\0\0\0\xc0\0\0\0\x3a\x01\0\0\0\0\0\
\x08\x11\0\0\0\x40\x01\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x13\
-\0\0\0\0\0\0\0\0\0\0\x0a\x1c\0\0\0\x4d\x01\0\0\x04\0\0\x06\x04\0\0\0\x5d\x01\0\
+\0\0\0\0\0\0\0\0\0\0\x0a\x1e\0\0\0\x4d\x01\0\0\x04\0\0\x06\x04\0\0\0\x5d\x01\0\
\0\0\0\0\0\x6e\x01\0\0\x01\0\0\0\x80\x01\0\0\x02\0\0\0\x93\x01\0\0\x03\0\0\0\0\
\0\0\0\x02\0\0\x05\x04\0\0\0\xa4\x01\0\0\x16\0\0\0\0\0\0\0\xab\x01\0\0\x16\0\0\
-\0\0\0\0\0\xb0\x01\0\0\0\0\0\x08\x02\0\0\0\xec\x01\0\0\0\0\0\x01\x01\0\0\0\x08\
-\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\xf1\x01\0\0\0\
-\0\0\x0e\x18\0\0\0\x01\0\0\0\xf9\x01\0\0\x01\0\0\x0f\x20\0\0\0\x0a\0\0\0\0\0\0\
-\0\x20\0\0\0\xff\x01\0\0\x01\0\0\x0f\x04\0\0\0\x19\0\0\0\0\0\0\0\x04\0\0\0\x07\
-\x02\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\
-\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\x78\x5f\
-\x65\x6e\x74\x72\x69\x65\x73\0\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\x61\x6c\
-\x75\x65\x5f\x73\x69\x7a\x65\0\x68\x69\x64\x5f\x6a\x6d\x70\x5f\x74\x61\x62\x6c\
-\x65\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\
-\0\x63\x74\x78\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\x66\x6d\
-\x6f\x64\x5f\x72\x65\x74\x2f\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\
-\x69\x6c\x5f\x63\x61\x6c\x6c\0\x2f\x68\x6f\x6d\x65\x2f\x62\x74\x69\x73\x73\x6f\
-\x69\x72\x2f\x53\x72\x63\x2f\x68\x69\x64\x2f\x64\x72\x69\x76\x65\x72\x73\x2f\
-\x68\x69\x64\x2f\x62\x70\x66\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\
-\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\x2e\x62\x70\x66\x2e\x63\0\x69\
-\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\x28\x68\x69\x64\x5f\x74\x61\x69\
-\x6c\x5f\x63\x61\x6c\x6c\x2c\x20\x73\x74\x72\x75\x63\x74\x20\x68\x69\x64\x5f\
-\x62\x70\x66\x5f\x63\x74\x78\x20\x2a\x68\x63\x74\x78\x29\0\x68\x69\x64\x5f\x62\
-\x70\x66\x5f\x63\x74\x78\0\x69\x6e\x64\x65\x78\0\x68\x69\x64\0\x61\x6c\x6c\x6f\
-\x63\x61\x74\x65\x64\x5f\x73\x69\x7a\x65\0\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\
-\x70\x65\0\x5f\x5f\x75\x33\x32\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\
-\x74\0\x68\x69\x64\x5f\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\x70\x65\0\x48\x49\
-\x44\x5f\x49\x4e\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x4f\
-\x55\x54\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x46\x45\x41\
-\x54\x55\x52\x45\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x52\x45\x50\x4f\
-\x52\x54\x5f\x54\x59\x50\x45\x53\0\x72\x65\x74\x76\x61\x6c\0\x73\x69\x7a\x65\0\
-\x5f\x5f\x73\x33\x32\0\x30\x3a\x30\0\x09\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\
-\x63\x61\x6c\x6c\x28\x63\x74\x78\x2c\x20\x26\x68\x69\x64\x5f\x6a\x6d\x70\x5f\
-\x74\x61\x62\x6c\x65\x2c\x20\x68\x63\x74\x78\x2d\x3e\x69\x6e\x64\x65\x78\x29\
-\x3b\0\x63\x68\x61\x72\0\x4c\x49\x43\x45\x4e\x53\x45\0\x2e\x6d\x61\x70\x73\0\
-\x6c\x69\x63\x65\x6e\x73\x65\0\x68\x69\x64\x5f\x64\x65\x76\x69\x63\x65\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8a\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
-\0\0\0\x04\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\x64\x5f\
-\x6a\x6d\x70\x5f\x74\x61\x62\x6c\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x61\x23\0\0\0\0\
-\0\0\x18\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x0c\0\0\0\xb7\0\0\0\0\0\0\0\
-\x95\0\0\0\0\0\0\0\0\0\0\0\x0e\0\0\0\0\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\x48\0\0\
-\x01\0\0\0\x8e\0\0\0\xba\x01\0\0\x02\x50\0\0\x05\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\
-\x48\0\0\x08\0\0\0\x0f\0\0\0\xb6\x01\0\0\0\0\0\0\x1a\0\0\0\x07\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\
-\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\0\0\0\0\x1a\0\0\0\0\0\0\0\
-\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x01\0\
-\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x5f\
-\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\
+\0\0\0\0\0\xb0\x01\0\0\0\0\0\x08\x02\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x5f\0\
+\0\0\x0b\0\0\0\xec\x01\0\0\x01\0\0\x0c\x17\0\0\0\x6d\x02\0\0\0\0\0\x01\x01\0\0\
+\0\x08\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x19\0\0\0\x04\0\0\0\x04\0\0\0\x72\x02\
+\0\0\0\0\0\x0e\x1a\0\0\0\x01\0\0\0\x7a\x02\0\0\x01\0\0\x0f\x20\0\0\0\x0a\0\0\0\
+\0\0\0\0\x20\0\0\0\x80\x02\0\0\x01\0\0\x0f\x04\0\0\0\x1b\0\0\0\0\0\0\0\x04\0\0\
+\0\x88\x02\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\
+\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\
+\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\
+\x61\x6c\x75\x65\x5f\x73\x69\x7a\x65\0\x68\x69\x64\x5f\x6a\x6d\x70\x5f\x74\x61\
+\x62\x6c\x65\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\
+\x6e\x67\0\x63\x74\x78\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\
+\x66\x6d\x6f\x64\x5f\x72\x65\x74\x2f\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\
+\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\x2f\x68\x6f\x6d\x65\x2f\x62\x74\x69\x73\
+\x73\x6f\x69\x72\x2f\x53\x72\x63\x2f\x68\x69\x64\x2f\x64\x72\x69\x76\x65\x72\
+\x73\x2f\x68\x69\x64\x2f\x62\x70\x66\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\
+\x74\x73\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\x2e\x62\x70\x66\x2e\
+\x63\0\x69\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\x28\x68\x69\x64\x5f\x74\
+\x61\x69\x6c\x5f\x63\x61\x6c\x6c\x2c\x20\x73\x74\x72\x75\x63\x74\x20\x68\x69\
+\x64\x5f\x62\x70\x66\x5f\x63\x74\x78\x20\x2a\x68\x63\x74\x78\x29\0\x68\x69\x64\
+\x5f\x62\x70\x66\x5f\x63\x74\x78\0\x69\x6e\x64\x65\x78\0\x68\x69\x64\0\x61\x6c\
+\x6c\x6f\x63\x61\x74\x65\x64\x5f\x73\x69\x7a\x65\0\x72\x65\x70\x6f\x72\x74\x5f\
+\x74\x79\x70\x65\0\x5f\x5f\x75\x33\x32\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\
+\x69\x6e\x74\0\x68\x69\x64\x5f\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\x70\x65\0\
+\x48\x49\x44\x5f\x49\x4e\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\
+\x5f\x4f\x55\x54\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x46\
+\x45\x41\x54\x55\x52\x45\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x52\x45\
+\x50\x4f\x52\x54\x5f\x54\x59\x50\x45\x53\0\x72\x65\x74\x76\x61\x6c\0\x73\x69\
+\x7a\x65\0\x5f\x5f\x73\x33\x32\0\x30\x3a\x30\0\x09\x62\x70\x66\x5f\x74\x61\x69\
+\x6c\x5f\x63\x61\x6c\x6c\x28\x63\x74\x78\x2c\x20\x26\x68\x69\x64\x5f\x6a\x6d\
+\x70\x5f\x74\x61\x62\x6c\x65\x2c\x20\x68\x63\x74\x78\x2d\x3e\x69\x6e\x64\x65\
+\x78\x29\x3b\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\x5f\x73\x6c\
+\x65\x65\x70\x61\x62\x6c\x65\0\x66\x6d\x6f\x64\x5f\x72\x65\x74\x2e\x73\x2f\x5f\
+\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\x5f\
+\x73\x6c\x65\x65\x70\x61\x62\x6c\x65\0\x69\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\
+\x4f\x47\x28\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\x5f\x73\x6c\
+\x65\x65\x70\x61\x62\x6c\x65\x2c\x20\x73\x74\x72\x75\x63\x74\x20\x68\x69\x64\
+\x5f\x62\x70\x66\x5f\x63\x74\x78\x20\x2a\x68\x63\x74\x78\x29\0\x63\x68\x61\x72\
+\0\x4c\x49\x43\x45\x4e\x53\x45\0\x2e\x6d\x61\x70\x73\0\x6c\x69\x63\x65\x6e\x73\
+\x65\0\x68\x69\x64\x5f\x64\x65\x76\x69\x63\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x2b\x05\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x04\0\0\0\x04\0\0\0\
+\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\x64\x5f\x6a\x6d\x70\x5f\x74\x61\x62\
+\x6c\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x50\
+\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x18\x52\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\x85\0\0\0\x0c\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\
+\x0e\0\0\0\0\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\x48\0\0\x01\0\0\0\x8e\0\0\0\xba\x01\
+\0\0\x02\x50\0\0\x05\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\x48\0\0\x08\0\0\0\x0f\0\0\0\
+\xb6\x01\0\0\0\0\0\0\x1a\0\0\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\
+\x63\x61\x6c\x6c\0\0\0\0\0\0\0\x1a\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\
+\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x01\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\
+\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\
+\x12\0\0\0\0\0\0\x61\x23\0\0\0\0\0\0\x18\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\
+\0\0\x0c\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0\
+\x8e\0\0\0\x2d\x02\0\0\x05\x68\0\0\x01\0\0\0\x8e\0\0\0\xba\x01\0\0\x02\x70\0\0\
+\x05\0\0\0\x8e\0\0\0\x2d\x02\0\0\x05\x68\0\0\x08\0\0\0\x0f\0\0\0\xb6\x01\0\0\0\
+\0\0\0\x1a\0\0\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\
+\x6c\x5f\x73\0\0\0\0\0\x1a\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\
+\x10\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x01\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\
+\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\x5f\x73\x6c\x65\x65\x70\x61\x62\x6c\x65\0\
\0\0";
- opts.insns_sz = 1192;
- opts.insns = (void *)"\
+ static const char opts_insn[] __attribute__((__aligned__(8))) = "\
\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
-\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x11\0\0\0\0\0\x61\
+\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x14\0\0\0\0\0\x61\
\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
-\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\
-\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\
-\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\xa8\x09\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\
-\0\0\0\0\0\0\0\xa4\x09\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\
-\0\0\0\0\0\0\0\0\0\x98\x09\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
-\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\
-\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\xb7\x03\0\0\x1c\0\0\0\
-\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd7\xff\0\0\0\0\x63\x7a\x78\
-\xff\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
-\0\0\xbc\x09\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\
-\0\0\0\xb0\x09\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\
-\0\xc5\x07\xca\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\
-\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\x09\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\
-\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x0a\0\0\x18\x61\0\0\
-\0\0\0\0\0\0\0\0\x88\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
-\x38\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\
-\x60\0\0\0\0\0\0\0\0\0\0\x40\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xe0\x0a\0\0\
-\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x0a\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\0\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\
-\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x0a\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\
-\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x9c\x0a\0\0\x63\x01\0\0\0\0\0\0\x79\x60\
-\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\
-\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0a\0\0\x63\x01\0\0\0\0\0\
-\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x0b\0\0\xb7\x02\0\0\x14\0\0\0\xb7\x03\0\0\
-\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\
-\x91\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x80\x0a\0\0\x63\x70\x6c\0\0\0\0\0\
-\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\
-\0\0\0\0\0\0\0\0\x80\x0a\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\
-\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf0\x0a\0\0\x61\x01\0\0\0\0\0\0\xd5\
-\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x7f\xff\0\0\
-\0\0\x63\x7a\x80\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\
-\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\x06\x28\0\0\0\
-\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\
-\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0";
+\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x84\xff\0\0\0\0\xd5\x01\x01\0\0\
+\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x01\0\0\0\0\
+\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xbf\x70\0\0\
+\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x48\x0a\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
+\0\0\x44\x0a\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\
+\0\0\0\0\x38\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x05\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0a\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x12\0\
+\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x30\x0a\0\0\xb7\x03\0\0\x1c\0\0\0\x85\0\0\0\
+\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd4\xff\0\0\0\0\x63\x7a\x78\xff\0\0\0\0\
+\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x5c\x0a\
+\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x50\
+\x0a\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\
+\xc7\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\0\0\x18\
+\x60\0\0\0\0\0\0\0\0\0\0\x98\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0b\0\0\
+\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\x28\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xd8\x0a\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x70\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\
+\0\0\0\0\0\0\0\xe0\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x80\x0b\0\0\x7b\x01\0\0\
+\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0b\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\xa0\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\
+\0\0\0\0\0\0\0\0\0\x98\x0b\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x38\x0b\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\x3c\x0b\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x40\x0b\0\0\x7b\x01\0\0\0\0\0\0\x61\xa0\x78\
+\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x68\x0b\0\0\x63\x01\0\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\xb0\x0b\0\0\xb7\x02\0\0\x14\0\0\0\xb7\x03\0\0\x0c\0\0\
+\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x8e\xff\
+\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x20\x0b\0\0\x63\x70\x6c\0\0\0\0\0\x77\x07\
+\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\0\0\0\0\
+\0\0\0\0\x20\x0b\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\
+\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x90\x0b\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\
+\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x7c\xff\0\0\0\0\x63\
+\x7a\x80\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xc8\x0b\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\x60\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xd0\x0b\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x58\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\
+\0\0\0\0\0\0\0\x08\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0c\0\0\x7b\x01\0\0\
+\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\xb0\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x40\x0c\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0c\0\0\x7b\x01\0\0\0\0\0\0\x61\
+\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x68\x0c\0\0\x63\x01\0\0\0\0\0\0\
+\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x6c\x0c\0\0\x63\x01\0\0\0\0\
+\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x70\x0c\0\0\x7b\x01\0\0\
+\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x0c\0\0\x63\
+\x01\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xe0\x0c\0\0\xb7\x02\0\0\x1e\0\0\0\
+\xb7\x03\0\0\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\
+\0\0\xc5\x07\x45\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x50\x0c\0\0\x63\x70\
+\x6c\0\0\0\0\0\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\
+\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x50\x0c\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\
+\0\0\0\xbf\x07\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xc0\x0c\0\0\x61\x01\0\0\
+\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\
+\x33\xff\0\0\0\0\x63\x7a\x84\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\
+\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\
+\x06\x28\0\0\0\0\0\x61\xa0\x84\xff\0\0\0\0\x63\x06\x2c\0\0\0\0\0\x18\x61\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\0\0\xb7\0\0\0\0\0\
+\0\0\x95\0\0\0\0\0\0\0";
+
+ opts.ctx = (struct bpf_loader_ctx *)skel;
+ opts.data_sz = sizeof(opts_data) - 1;
+ opts.data = (void *)opts_data;
+ opts.insns_sz = sizeof(opts_insn) - 1;
+ opts.insns = (void *)opts_insn;
+
err = bpf_load_and_run(&opts);
if (err < 0)
return err;
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index e1a650f4a626..afb409a76a63 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -105,6 +105,25 @@ __weak noinline int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx)
return 0;
}
+/**
+ * hid_bpf_offload - Called when the workqueue attached to the HID device
+ * is triggered
+ *
+ * @ctx: The HID-BPF context
+ *
+ * @return 0 on success and keep processing; a negative error code to interrupt
+ * the processing of this job.
+ *
+ * Declare an %fmod_ret tracing bpf program to this function and attach this
+ * program through hid_bpf_attach_prog() to have this helper called whenever
+ * hid_bpf_schedule_delayed_work() is called.
+ */
+/* never used by the kernel but declared so we can load and attach a tracepoint */
+__weak noinline int hid_bpf_offload(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size)
{
int ret;
@@ -203,6 +222,35 @@ int hid_bpf_reconnect(struct hid_device *hdev)
return 0;
}
+static void delayed_work_cb(struct work_struct *work)
+{
+ struct hid_device *hdev = container_of(work, struct hid_device,
+ bpf.work.work);
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ },
+ };
+ int ret;
+
+ /* no program has been attached yet */
+ if (!hdev->bpf.work_initialized || hdev->bpf.destroyed)
+ return;
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_OFFLOAD, &ctx_kern);
+ if (ret < 0)
+ hid_warn_once(hdev, "error while executing HID-BPF delayed work: %d", ret);
+}
+
+static void hid_bpf_prep_worker(struct hid_device *hdev)
+{
+ if (hdev->bpf.work_initialized)
+ return;
+
+ INIT_DELAYED_WORK(&hdev->bpf.work, delayed_work_cb);
+ hdev->bpf.work_initialized = true;
+}
+
static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog,
__u32 flags)
{
@@ -215,10 +263,15 @@ static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct b
if (prog_type >= HID_BPF_PROG_TYPE_MAX)
return -EINVAL;
- if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
+ switch (prog_type) {
+ case HID_BPF_PROG_TYPE_DEVICE_EVENT:
err = hid_bpf_allocate_event_data(hdev);
if (err)
return err;
+ break;
+ case HID_BPF_PROG_TYPE_OFFLOAD:
+ hid_bpf_prep_worker(hdev);
+ break;
}
fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags);
@@ -536,6 +589,34 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf
return hid_input_report(hdev, type, buf, size, 0);
}
+
+/**
+ * hid_bpf_schedule_delayed_work - Put work task in the worqueue associated
+ * with the HID device
+ *
+ * @ctx: The HID-BPF context
+ * @delay_ms: a delay in milli seconds, or 0 for immediate execution
+ *
+ * Return: %false if @work was already on a queue, %true otherwise. If
+ * @delay is zero and @work is idle, it will be scheduled for immediate
+ * execution.
+ */
+__bpf_kfunc bool
+hid_bpf_schedule_delayed_work(struct hid_bpf_ctx *ctx, unsigned int delay_ms)
+{
+ struct hid_device *hdev;
+
+ if (!ctx)
+ return -EINVAL;
+
+ hdev = (struct hid_device *)ctx->hid; /* discard const */
+
+ if (!hdev->bpf.work_initialized) {
+ return -EINVAL;
+ }
+
+ return schedule_delayed_work(&hdev->bpf.work, msecs_to_jiffies(delay_ms));
+}
__bpf_kfunc_end_defs();
/*
@@ -544,6 +625,12 @@ __bpf_kfunc_end_defs();
*/
BTF_KFUNCS_START(hid_bpf_kfunc_ids)
BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
+BTF_ID_FLAGS(func, hid_bpf_schedule_delayed_work)
+BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_hw_output_report, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_input_report, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE)
BTF_KFUNCS_END(hid_bpf_kfunc_ids)
static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
@@ -555,7 +642,9 @@ static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
BTF_SET8_START(hid_bpf_fmodret_ids)
BTF_ID_FLAGS(func, hid_bpf_device_event)
BTF_ID_FLAGS(func, hid_bpf_rdesc_fixup)
+BTF_ID_FLAGS(func, hid_bpf_offload, KF_SLEEPABLE)
BTF_ID_FLAGS(func, __hid_bpf_tail_call)
+BTF_ID_FLAGS(func, __hid_bpf_tail_call_sleepable, KF_SLEEPABLE)
BTF_SET8_END(hid_bpf_fmodret_ids)
static const struct btf_kfunc_id_set hid_bpf_fmodret_set = {
@@ -610,6 +699,9 @@ void hid_bpf_destroy_device(struct hid_device *hdev)
/* mark the device as destroyed in bpf so we don't reattach it */
hdev->bpf.destroyed = true;
+ if (hdev->bpf.work_initialized)
+ cancel_delayed_work_sync(&hdev->bpf.work);
+
__hid_bpf_destroy_device(hdev);
}
EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c
index aa8e1c79cdf5..d401add0e2ab 100644
--- a/drivers/hid/bpf/hid_bpf_jmp_table.c
+++ b/drivers/hid/bpf/hid_bpf_jmp_table.c
@@ -59,6 +59,7 @@ static DECLARE_WORK(release_work, hid_bpf_release_progs);
BTF_ID_LIST(hid_bpf_btf_ids)
BTF_ID(func, hid_bpf_device_event) /* HID_BPF_PROG_TYPE_DEVICE_EVENT */
BTF_ID(func, hid_bpf_rdesc_fixup) /* HID_BPF_PROG_TYPE_RDESC_FIXUP */
+BTF_ID(func, hid_bpf_offload) /* HID_BPF_PROG_TYPE_OFFLOAD */
static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
{
@@ -67,6 +68,8 @@ static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
return HID_BPF_MAX_PROGS_PER_DEV;
case HID_BPF_PROG_TYPE_RDESC_FIXUP:
return 1;
+ case HID_BPF_PROG_TYPE_OFFLOAD:
+ return HID_BPF_MAX_PROGS_PER_DEV;
default:
return -EINVAL;
}
@@ -104,14 +107,30 @@ __weak noinline int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx)
return 0;
}
+__weak noinline int __hid_bpf_tail_call_sleepable(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
struct hid_bpf_ctx_kern *ctx_kern)
{
struct hid_bpf_prog_list *prog_list;
int i, idx, err = 0;
- rcu_read_lock();
- prog_list = rcu_dereference(hdev->bpf.progs[type]);
+ if (type == HID_BPF_PROG_TYPE_OFFLOAD) {
+ /*
+ * HID_BPF_PROG_TYPE_OFFLOAD can sleep, so we can not
+ * take an rcu_read_lock()
+ * Prevent concurrency by taking &hid_bpf_attach_lock
+ * instead
+ */
+ mutex_lock(&hid_bpf_attach_lock);
+ prog_list = hdev->bpf.progs[type];
+ } else {
+ rcu_read_lock();
+ prog_list = rcu_dereference(hdev->bpf.progs[type]);
+ }
if (!prog_list)
goto out_unlock;
@@ -123,7 +142,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
continue;
ctx_kern->ctx.index = idx;
- err = __hid_bpf_tail_call(&ctx_kern->ctx);
+ if (type == HID_BPF_PROG_TYPE_OFFLOAD)
+ err = __hid_bpf_tail_call_sleepable(&ctx_kern->ctx);
+ else
+ err = __hid_bpf_tail_call(&ctx_kern->ctx);
if (err < 0)
break;
if (err)
@@ -131,7 +153,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
}
out_unlock:
- rcu_read_unlock();
+ if (type == HID_BPF_PROG_TYPE_OFFLOAD)
+ mutex_unlock(&hid_bpf_attach_lock);
+ else
+ rcu_read_unlock();
return err;
}
@@ -557,6 +582,7 @@ int hid_bpf_preload_skel(void)
}
ATTACH_AND_STORE_LINK(hid_tail_call);
+ ATTACH_AND_STORE_LINK(hid_tail_call_sleepable);
return 0;
out:
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 17b08f500098..87e72ffadff0 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -5,6 +5,7 @@
#include <linux/bpf.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <uapi/linux/hid.h>
struct hid_device;
@@ -76,6 +77,7 @@ enum hid_bpf_attach_flags {
/* Following functions are tracepoints that BPF programs can attach to */
int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
+int hid_bpf_offload(struct hid_bpf_ctx *ctx);
/*
* Below is HID internal
@@ -83,6 +85,7 @@ int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
/* internal function to call eBPF programs, not to be used by anybody */
int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx);
+int __hid_bpf_tail_call_sleepable(struct hid_bpf_ctx *ctx);
#define HID_BPF_MAX_PROGS_PER_DEV 64
#define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1)
@@ -92,6 +95,7 @@ enum hid_bpf_prog_type {
HID_BPF_PROG_TYPE_UNDEF = -1,
HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */
HID_BPF_PROG_TYPE_RDESC_FIXUP,
+ HID_BPF_PROG_TYPE_OFFLOAD,
HID_BPF_PROG_TYPE_MAX,
};
@@ -129,6 +133,9 @@ struct hid_bpf {
bool destroyed; /* prevents the assignment of any progs */
spinlock_t progs_lock; /* protects RCU update of progs */
+
+ struct delayed_work work;
+ bool work_initialized;
};
/* specific HID-BPF link when a program is attached to a device */
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 8/9] selftests/hid: add test for hid_bpf_schedule_delayed_work
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
This test checks that we can actually execute in a sleepable context
the job called by hid_bpf_offload().
When an event is injected, we push it on a map of type queue and schedule
a work.
When that work kicks in, it pulls the event from the queue, and wakes
up userspace through a ring buffer.
The use of the ring buffer is there to not have sleeps in userspace
because we have no guarantees of the timing of when those jobs will be
called.
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
tools/testing/selftests/hid/hid_bpf.c | 57 ++++++++++++++++++++++
tools/testing/selftests/hid/progs/hid.c | 55 +++++++++++++++++++++
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 2 +
3 files changed, 114 insertions(+)
diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index 9ff02c737144..bb95ff90951b 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -875,6 +875,63 @@ TEST_F(hid_bpf, test_hid_user_raw_request_call)
ASSERT_EQ(args.data[1], 2);
}
+static __u8 workload_data;
+
+static int handle_event(void *ctx, void *data, size_t data_sz)
+{
+ const __u8 *e = data;
+
+ workload_data = *e;
+
+ return 0;
+}
+
+/*
+ * Call hid_bpf_schedule_delayed_work against the given uhid device,
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_schedule_work)
+{
+ const struct test_program progs[] = {
+ { .name = "hid_defer_event" },
+ { .name = "hid_offload_notify" },
+ };
+ struct ring_buffer *rb = NULL;
+ __u8 buf[10] = {0};
+ __u32* delay;
+ int err;
+
+ LOAD_PROGRAMS(progs);
+
+ /* Set up ring buffer polling */
+ rb = ring_buffer__new(bpf_map__fd(self->skel->maps.rb), handle_event, NULL, NULL);
+ ASSERT_OK_PTR(rb) TH_LOG("Failed to create ring buffer");
+ ASSERT_EQ(workload_data, 0);
+
+ delay = (__u32 *)&buf[2];
+
+ /* inject one event */
+ buf[0] = 1;
+ buf[1] = 42; /* this will be placed in the ring buffer */
+ *delay = 0;
+ uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+ err = ring_buffer__poll(rb, 100 /* timeout, ms */);
+ ASSERT_EQ(err, 1) TH_LOG("error while calling ring_buffer__poll");
+
+ ASSERT_EQ(workload_data, 42);
+
+ /* inject one another */
+ buf[0] = 1;
+ buf[1] = 53; /* this will be placed in the ring buffer */
+ *delay = 100;
+ uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+ err = ring_buffer__poll(rb, 1000 /* timeout, ms */);
+ ASSERT_EQ(err, 1) TH_LOG("error while calling ring_buffer__poll");
+ ASSERT_EQ(workload_data, 53);
+}
+
/*
* Attach hid_insert{0,1,2} to the given uhid device,
* retrieve and open the matching hidraw node,
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index f67d35def142..95a03fb0494a 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -250,3 +250,58 @@ int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
return 0;
}
+
+struct test_report {
+ __u8 data[6];
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_QUEUE);
+ __uint(max_entries, 8);
+ __type(value, struct test_report);
+} queue SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_RINGBUF);
+ __uint(max_entries, 8);
+} rb SEC(".maps");
+
+SEC("?fmod_ret.s/hid_bpf_offload")
+int BPF_PROG(hid_offload_notify, struct hid_bpf_ctx *hid_ctx)
+{
+ struct test_report buf;
+ __u8 *rb_elem;
+
+ if (bpf_map_pop_elem(&queue, &buf))
+ return 0;
+
+ rb_elem = bpf_ringbuf_reserve(&rb, sizeof(*rb_elem), 0);
+ if (!rb_elem)
+ return 0;
+
+ *rb_elem = buf.data[1];
+
+ bpf_ringbuf_submit(rb_elem, 0);
+
+ return 0;
+}
+
+SEC("?fmod_ret/hid_bpf_device_event")
+int BPF_PROG(hid_defer_event, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 6 /* size */);
+ struct test_report buf;
+ __u32 delay;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ __builtin_memcpy(&buf.data, data, 6);
+
+ delay = *(__u32 *)&data[2];
+
+ bpf_map_push_elem(&queue, &buf, BPF_ANY);
+ hid_bpf_schedule_delayed_work(hctx, delay);
+
+ return -1; /* discard the event */
+}
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index 9cd56821d0f1..a844c7e89766 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -100,5 +100,7 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
enum hid_report_type type,
__u8 *data,
size_t buf__sz) __ksym;
+extern bool hid_bpf_schedule_delayed_work(struct hid_bpf_ctx *ctx,
+ unsigned int delay_ms) __ksym;
#endif /* __HID_BPF_HELPERS_H */
--
2.43.0
^ permalink raw reply related
* [PATCH RFC bpf-next 9/9] selftests/hid: add another set of delayed work tests
From: Benjamin Tissoires @ 2024-02-09 13:26 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Jiri Kosina, Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
These ones are a little bit more complex, but allows to check whether
sleepable tracing functions can be called:
- one event is injected and then pushed into the queue map
- optionally another event gets injected in the queue map
- the events in the queue are then re-injected in the HID stack
- if there is an error, while re-injecting it, we try again 5 ms later
- ensure we can add another event in the queue or call other sleepable
kfuncs
- ensure we receive the correct events and exactly them
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
tools/testing/selftests/hid/hid_bpf.c | 117 +++++++++++++++++++++++++++++++-
tools/testing/selftests/hid/progs/hid.c | 104 ++++++++++++++++++++++++++++
2 files changed, 220 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index bb95ff90951b..cfa42d603acb 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -460,7 +460,7 @@ FIXTURE(hid_bpf) {
int hid_id;
pthread_t tid;
struct hid *skel;
- int hid_links[3]; /* max number of programs loaded in a single test */
+ int hid_links[4]; /* max number of programs loaded in a single test */
};
static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)
{
@@ -932,6 +932,121 @@ TEST_F(hid_bpf, test_hid_schedule_work)
ASSERT_EQ(workload_data, 53);
}
+/*
+ * Call hid_bpf_schedule_delayed_work against the given uhid device,
+ * ensure we can inject events (call a sleepable tracing function),
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_schedule_work_defer_events)
+{
+ const struct test_program progs[] = {
+ { .name = "hid_defer_event" },
+ { .name = "hid_offload_inject", .insert_head = 1 },
+ { .name = "hid_offload_multiply_events" },
+ { .name = "hid_offload_notify" },
+ };
+ struct ring_buffer *rb = NULL;
+ __u8 buf[10] = {0};
+ __u32* delay;
+ int err;
+
+ LOAD_PROGRAMS(progs);
+
+ /* Set up ring buffer polling */
+ rb = ring_buffer__new(bpf_map__fd(self->skel->maps.rb), handle_event, NULL, NULL);
+ ASSERT_OK_PTR(rb) TH_LOG("Failed to create ring buffer");
+ ASSERT_EQ(workload_data, 0);
+
+ delay = (__u32 *)&buf[2];
+
+ /* inject one event */
+ buf[0] = 1;
+ buf[1] = 42; /* this will be placed in the ring buffer */
+ *delay = 0;
+ uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+ err = ring_buffer__poll(rb, 100 /* timeout, ms */);
+ ASSERT_EQ(err, 1) TH_LOG("error while calling ring_buffer__poll");
+
+ ASSERT_EQ(workload_data, 42);
+
+ err = ring_buffer__poll(rb, 1000 /* timeout, ms */);
+ ASSERT_EQ(err, 1) TH_LOG("error while calling ring_buffer__poll");
+ ASSERT_EQ(workload_data, 52);
+
+ /* read twice the data from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+ ASSERT_EQ(buf[0], 2);
+ ASSERT_EQ(buf[1], 42);
+
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+ ASSERT_EQ(buf[0], 2);
+ ASSERT_EQ(buf[1], 52);
+
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, -1) TH_LOG("read_hidraw: too many events");
+}
+
+TEST_F(hid_bpf, test_hid_schedule_work_defer_events_2)
+{
+ const struct test_program progs[] = {
+ { .name = "hid_defer_multiple_events" },
+ { .name = "hid_offload_inject", .insert_head = 1 },
+ { .name = "hid_offload_hw_request" },
+ { .name = "hid_offload_notify" },
+ };
+ struct ring_buffer *rb = NULL;
+ __u8 buf[10] = {0};
+ int err;
+
+ LOAD_PROGRAMS(progs);
+
+ /* Set up ring buffer polling */
+ rb = ring_buffer__new(bpf_map__fd(self->skel->maps.rb), handle_event, NULL, NULL);
+ ASSERT_OK_PTR(rb) TH_LOG("Failed to create ring buffer");
+ ASSERT_EQ(workload_data, 0);
+
+ /* inject one event */
+ buf[0] = 1;
+ buf[1] = 47;
+ buf[2] = 50;
+ uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+ err = ring_buffer__poll(rb, 100 /* timeout, ms */);
+ ASSERT_EQ(err, 1) TH_LOG("error while calling ring_buffer__poll");
+ ASSERT_EQ(workload_data, 3);
+
+ /* read the data from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+ ASSERT_EQ(buf[0], 2);
+ ASSERT_EQ(buf[1], 3);
+ ASSERT_EQ(buf[2], 4) TH_LOG("leftovers_from_previous_test");
+
+ err = ring_buffer__poll(rb, 100 /* timeout, ms */);
+ ASSERT_EQ(err, 1) TH_LOG("error while calling ring_buffer__poll");
+ ASSERT_EQ(workload_data, 4);
+
+ /* read the data from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+ ASSERT_EQ(buf[0], 2);
+ ASSERT_EQ(buf[1], 4);
+ ASSERT_EQ(buf[2], 6);
+
+ /* read the data from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, -1) TH_LOG("read_hidraw");
+}
+
/*
* Attach hid_insert{0,1,2} to the given uhid device,
* retrieve and open the matching hidraw node,
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index 95a03fb0494a..aae8d7a0699e 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -286,6 +286,63 @@ int BPF_PROG(hid_offload_notify, struct hid_bpf_ctx *hid_ctx)
return 0;
}
+SEC("?fmod_ret.s/hid_bpf_offload")
+int BPF_PROG(hid_offload_multiply_events, struct hid_bpf_ctx *hid_ctx)
+{
+ struct test_report buf;
+ int err;
+
+ /* do not pop the event, it'll be done in hid_offload_test() when
+ * notifying user space, this also allows to retry sending it
+ * if hid_bpf_input_report fails */
+ if (bpf_map_peek_elem(&queue, &buf))
+ return 0;
+
+ buf.data[1] += 10;
+ /* inject another event to be processed */
+ if (buf.data[1] < 60)
+ bpf_map_push_elem(&queue, &buf, BPF_ANY);
+
+ return 0;
+}
+
+SEC("?fmod_ret.s/hid_bpf_offload")
+int BPF_PROG(hid_offload_inject, struct hid_bpf_ctx *hid_ctx)
+{
+ struct test_report buf;
+ int err;
+
+ /* do not pop the event, it'll be done in hid_offload_test() when
+ * notifying user space, this also allows to retry sending it
+ * if hid_bpf_input_report fails */
+ if (bpf_map_peek_elem(&queue, &buf))
+ return 0;
+
+ buf.data[0] = 2;
+
+ /* re-inject the modified event into the HID stack */
+ err = hid_bpf_input_report(hid_ctx, HID_INPUT_REPORT, buf.data, sizeof(buf.data));
+ if (err == -16 /* -EBUSY */) {
+ /*
+ * This happens when we schedule the work with a 0 delay:
+ * the thread immediately starts but the current input
+ * processing hasn't finished yet. So the semaphore is
+ * already taken, and hid_input_report returns -EBUSY
+ */
+ /* schedule another attempt */
+ hid_bpf_schedule_delayed_work(hid_ctx, 5);
+
+ /* return an error so that we don't trigger hid_offload_test()
+ * and pop the element */
+ return err;
+ }
+
+ /* call ourself once again until there is no more events in the queue */
+ hid_bpf_schedule_delayed_work(hid_ctx, 5);
+
+ return 0;
+}
+
SEC("?fmod_ret/hid_bpf_device_event")
int BPF_PROG(hid_defer_event, struct hid_bpf_ctx *hctx)
{
@@ -296,6 +353,11 @@ int BPF_PROG(hid_defer_event, struct hid_bpf_ctx *hctx)
if (!data)
return 0; /* EPERM check */
+ /* Only schedule a delayed work when reportID is 1, otherwise
+ * simply forward it to hidraw */
+ if (data[0] != 1)
+ return 0;
+
__builtin_memcpy(&buf.data, data, 6);
delay = *(__u32 *)&data[2];
@@ -305,3 +367,45 @@ int BPF_PROG(hid_defer_event, struct hid_bpf_ctx *hctx)
return -1; /* discard the event */
}
+
+SEC("?fmod_ret.s/hid_bpf_offload")
+int BPF_PROG(hid_offload_hw_request, struct hid_bpf_ctx *hid_ctx)
+{
+ struct test_report buf;
+ __u8 data[6] = {1};
+ int ret;
+
+ ret = hid_bpf_hw_request(hid_ctx,
+ data,
+ sizeof(data),
+ HID_INPUT_REPORT,
+ HID_REQ_GET_REPORT);
+
+ return 0;
+}
+SEC("?fmod_ret/hid_bpf_device_event")
+int BPF_PROG(hid_defer_multiple_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4 /* size */);
+ struct test_report buf = {
+ .data = {2, 3, 4, 5, 6, 7},
+ };
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Only schedule a delayed work when reportID is 1, otherwise
+ * simply forward it to hidraw */
+ if (data[0] != 1)
+ return 0;
+
+ bpf_map_push_elem(&queue, &buf, BPF_ANY);
+ buf.data[0] = 2;
+ buf.data[1] = 4;
+ buf.data[2] = 6;
+ bpf_map_push_elem(&queue, &buf, BPF_ANY);
+
+ hid_bpf_schedule_delayed_work(hctx, 10);
+
+ return -1; /* discard the event */
+}
--
2.43.0
^ permalink raw reply related
* Re: Suspected bug in hid-microsoft.c
From: Benjamin Tissoires @ 2024-02-09 13:47 UTC (permalink / raw)
To: Taco Jerkface; +Cc: open list:HID CORE LAYER
In-Reply-To: <CAEQPD4QEG8K7HtVaZe3g_P0=ppSeY=FH=fRbswQsV6JBpZe0DA@mail.gmail.com>
[Adding back the linux-input ML]
On Wed, Feb 7, 2024 at 6:34 AM Taco Jerkface <tacodog311@gmail.com> wrote:
>
> On Tue, Feb 6, 2024 at 8:11 AM Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
> >
> > On Tue, Feb 6, 2024 at 6:25 AM Taco Jerkface <tacodog311@gmail.com> wrote:
> > >
> > > Thanks!
> > >
> > > > 1. (easiest) tune your udev rule to also give user access to the
> > > > hidraw subsystem on this device. SDL should be able to read it
> > > > directly, and handle it properly, but this won't solve for future
> > > > users
> > >
> > > This udev rule does in fact "fix" the problem
> > >
> > > KERNELS=="*:045E:0B22.*", MODE="0666"
> >
> > Right :)
> >
> > Well you could restrict it further by using the recommendations from SDL:
> > https://github.com/libsdl-org/SDL/blob/main/src/hidapi/udev/69-hid.rules
> >
> > # HIDAPI/hidraw
> > KERNEL=="hidraw*", ATTRS{idVendor}=="045E", ATTRS{idProduct}=="0B22",
> > TAG+="uaccess"
> >
> > (not entirely sure about the capitals in vendor/product)
>
> I tried that and couldn't get it to work. My (incomplete)
> understanding is that the rule needs to match the fields from "udevadm
> info --name=/dev/hidraw1 --attribute-walk" which looks like this. The
> "KERNELS" line was the best I could find with both the vendor and
> product fields. I wildcarded the 0005 because it changed when I
> reconnected.
Yeah, so I vaguely remember that some properties are inherited from
the parents, and VendorID and ProductID might be inherited. And given
that this is a BLE device and that it's then using uhid, those
properties are not set.
TL;DR: seems like you got the correct match. You should probably use
TAG+="uaccess" instead of MODE="0666" to restrict the opening of the
device from the current user of the current session only.
>
> looking at device
> '/devices/virtual/misc/uhid/0005:045E:0B22.0005/hidraw/hidraw1':
> KERNEL=="hidraw1"
> SUBSYSTEM=="hidraw"
> DRIVER==""
> ATTR{power/control}=="auto"
> ATTR{power/runtime_active_time}=="0"
> ATTR{power/runtime_status}=="unsupported"
> ATTR{power/runtime_suspended_time}=="0"
>
> looking at parent device '/devices/virtual/misc/uhid/0005:045E:0B22.0005':
> KERNELS=="0005:045E:0B22.0005"
> SUBSYSTEMS=="hid"
> DRIVERS=="microsoft"
> ATTRS{country}=="00"
> ATTRS{power/control}=="auto"
> ATTRS{power/runtime_active_time}=="0"
> ATTRS{power/runtime_status}=="unsupported"
> ATTRS{power/runtime_suspended_time}=="0"
>
> looking at parent device '/devices/virtual/misc/uhid':
> KERNELS=="uhid"
> SUBSYSTEMS=="misc"
> DRIVERS==""
> ATTRS{power/control}=="auto"
> ATTRS{power/runtime_active_time}=="0"
>
> >
> >
> > >
> > >
> > > > 2. (no kernel compilation required) we can try to fix the report
> > > > descriptor of the device through HID-BPF. Assuming you have
> > > > CONFIG_HID_BPF enabled in your kernel, we can relatively easily change
> > > > the way the device is exported/handled by the kernel, to make it
> > > > useful hopefully
> > > > 3. (hardest IMO as you'll have to recompile your kernel for the tests)
> > > > we can try to tune hid-microsoft.c to properly export these buttons
> > > >
> > > > For 2 and 3, I'll need some events from your device with hid-recorder.
> > > > You only gave me the report descriptor, but no events which are hard
> > > > to deduce based on the long report descriptor.
> > >
> > > With the udev rule, I attached the hid-recorder output when pressing
> > > the paddles. I see the 01 02 04 08 showing up at the end of the line.
> >
> > Thanks for that. And as you can see, they are using the "Assign
> > Selection" usage, which is... new to me :)
> >
> > >
> > >
> > > > Also for 2 and 3 we need to have a BTN_* button code to use, and I
> > > > don't know which ones should be used from the top of my head. HID-BPF
> > > > would be easiest to use as we can let the user decide of it, while
> > > > we'll need to have a more formal usage in case we fix hid-microsoft.
> > >
> > > When connected with USB, evemu-record shows button names
> > > "BTN_TRIGGER_HAPPY5" "BTN_TRIGGER_HAPPY6" "BTN_TRIGGER_HAPPY7"
> > > "BTN_TRIGGER_HAPPY8". I assume these are the button codes we can use?
> > >
> > > ################################
> > > # Waiting for events #
> > > ################################
> > > E: 0.000001 0001 02c4 0001 # EV_KEY / BTN_TRIGGER_HAPPY5 1
> > > E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
> > > E: 0.143950 0001 02c4 0000 # EV_KEY / BTN_TRIGGER_HAPPY5 0
> > > E: 0.143950 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +143ms
> > > E: 6.543984 0001 02c5 0001 # EV_KEY / BTN_TRIGGER_HAPPY6 1
> > > E: 6.543984 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +6400ms
> > > E: 6.615981 0001 02c5 0000 # EV_KEY / BTN_TRIGGER_HAPPY6 0
> > > E: 6.615981 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +72ms
> > > E: 7.520034 0001 02c6 0001 # EV_KEY / BTN_TRIGGER_HAPPY7 1
> > > E: 7.520034 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +905ms
> > > E: 7.648127 0001 02c6 0000 # EV_KEY / BTN_TRIGGER_HAPPY7 0
> > > E: 7.648127 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +128ms
> > > E: 8.344035 0001 02c7 0001 # EV_KEY / BTN_TRIGGER_HAPPY8 1
> > > E: 8.344035 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +696ms
> > > E: 8.480049 0001 02c7 0000 # EV_KEY / BTN_TRIGGER_HAPPY8 0
> > > E: 8.480049 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +136ms
> > >
> >
> > Good point. Then we can easily tweak the device to use those BTN_* instead
> >
> > >
> > > >
> > > > For 1, maybe SDL (or Steam) already ships some udev rules, and
> > > > submitting a fix there would make things working for everybody.
> > > >
> > > > Anyway, depending on how much you want this to be fixed and what you
> > > > can do (is CONFIG_HID_BPF enabled in your distro? and can you
> > > > recompile a kernel module?) we can figure out the next step.
> > >
> > > Yes HID-BPF is configured in my kernel:
> > >
> > > cat /proc/config.gz | gunzip
> > > #
> > > # HID-BPF support
> > > #
> > > CONFIG_HID_BPF=y
> > > # end of HID-BPF support
> >
> > Even better, it'll be way easier for the tests :)
> >
> > I've opened a new MR with your device fix:
> > https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/32
> >
> > You should be able to head to the last job in latest pipeline (in the
> > pipeline tab) and download the artifact:
> > https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/jobs/54687597/artifacts/browse
> >
> > Then unpack and run `sudo ./install --verbose`.
> >
> > Then reconnect the device over Bluetooth, and see in evemu-record that
> > the paddles are now reporting BTN_TRIGGER_HAPPY[5-8].
> >
>
> Thanks. This does indeed work (with my udev rule still active).
\o/
>
> > I'd then be curious about 2 things:
> > - are the paddle now reporting the same events over USB and Bluetooth?
> > (is there no inversions between the BTN_TRIGGER*?, and are all the
> > buttons correctly handled?)
>
> The button reports are nearly identical now, though Bluetooth outputs
> more information.
\o/
>
> This is paddle1, paddl2, paddle3, paddle4 pressed in that order each way.
>
> USB:
> E: 0.000001 0001 02c4 0001 # EV_KEY / BTN_TRIGGER_HAPPY5 1
> E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
> E: 0.080031 0001 02c4 0000 # EV_KEY / BTN_TRIGGER_HAPPY5 0
> E: 0.080031 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +80ms
> E: 1.520025 0001 02c5 0001 # EV_KEY / BTN_TRIGGER_HAPPY6 1
> E: 1.520025 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +1440ms
> E: 1.631883 0001 02c5 0000 # EV_KEY / BTN_TRIGGER_HAPPY6 0
> E: 1.631883 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +111ms
> E: 2.183887 0001 02c6 0001 # EV_KEY / BTN_TRIGGER_HAPPY7 1
> E: 2.183887 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +552ms
> E: 2.295985 0001 02c6 0000 # EV_KEY / BTN_TRIGGER_HAPPY7 0
> E: 2.295985 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +112ms
> E: 2.800031 0001 02c7 0001 # EV_KEY / BTN_TRIGGER_HAPPY8 1
> E: 2.800031 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +505ms
> E: 2.879964 0001 02c7 0000 # EV_KEY / BTN_TRIGGER_HAPPY8 0
> E: 2.879964 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +79ms
>
> Bluetooth:
> E: 0.000001 0004 0004 589845 # EV_MSC / MSC_SCAN 589845
> E: 0.000001 0001 02c4 0001 # EV_KEY / BTN_TRIGGER_HAPPY5 1
> E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
> E: 0.033496 0004 0004 589845 # EV_MSC / MSC_SCAN 589845
> E: 0.033496 0001 02c4 0000 # EV_KEY / BTN_TRIGGER_HAPPY5 0
> E: 0.033496 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +33ms
> E: 1.726818 0004 0004 589846 # EV_MSC / MSC_SCAN 589846
> E: 1.726818 0001 02c5 0001 # EV_KEY / BTN_TRIGGER_HAPPY6 1
> E: 1.726818 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +1693ms
> E: 1.843421 0004 0004 589846 # EV_MSC / MSC_SCAN 589846
> E: 1.843421 0001 02c5 0000 # EV_KEY / BTN_TRIGGER_HAPPY6 0
> E: 1.843421 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +117ms
> E: 2.736883 0004 0004 589847 # EV_MSC / MSC_SCAN 589847
> E: 2.736883 0001 02c6 0001 # EV_KEY / BTN_TRIGGER_HAPPY7 1
> E: 2.736883 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +893ms
> E: 2.826849 0004 0004 589847 # EV_MSC / MSC_SCAN 589847
> E: 2.826849 0001 02c6 0000 # EV_KEY / BTN_TRIGGER_HAPPY7 0
> E: 2.826849 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +90ms
> E: 3.300247 0004 0004 589848 # EV_MSC / MSC_SCAN 589848
> E: 3.300247 0001 02c7 0001 # EV_KEY / BTN_TRIGGER_HAPPY8 1
> E: 3.300247 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +474ms
> E: 3.373377 0004 0004 589848 # EV_MSC / MSC_SCAN 589848
> E: 3.373377 0001 02c7 0000 # EV_KEY / BTN_TRIGGER_HAPPY8 0
> E: 3.373377 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +73ms
>
> Also via USB, evemu recognizes the controller as "Microsoft X-Box One
> Elite 2 pad". With Bluetooth it's seen as "Xbox Wireless Controller".
> This happens with or without your merge request.
This is expected and also kind of normal. We are not connecting
through the same transport, so one should at least have the "wireless"
in it. Rest is just how the device itself has those strings stored, so
we should probably just say it's fine.
>
> USB
>
> > evemu-record
> Available devices:
> /dev/input/event17: Microsoft X-Box One Elite 2 pad
>
> Bluetooth
>
> > evemu-record
> Available devices:
> /dev/input/event16: Xbox Wireless Controller
>
>
> > - does this mess up with SDL over hidraw (so keeping your udev rule in place)
>
> SDL seems to recognize the controller as 'Xbox One Elite 2 Controller'
> over both USB and Bluetooth. Though the ProductID is "000b" with USB
> and "220b" via bluetooth. Also, SDL, recognized the "hat" via USB,
> but sees them as 4 more buttons through BT. I'm using
> Grumbel/sdl-jstest.git to test. This happens with or without your MR.
Is this hat difference an issue? If so we can try to fix it, again,
and if not we can then leave it as it is.
>
> USB:
> Joystick Name: 'Xbox One Elite 2 Controller'
> Joystick GUID: 030010f85e040000000b000011050000
> Joystick Number: 0
> Number of Axes: 6
> Number of Buttons: 15
> Number of Hats: 1
> Number of Balls: 0
> GameControllerConfig:
> Name: 'Xbox One Elite 2 Controller'
> Mapping: '030010f85e040000000b000011050000,Xbox One Elite 2
> Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshould
> er:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,crc:
> f810,platform:Linux'
>
> Bluetooth:
> Joystick Name: 'Xbox One Elite 2 Controller'
> Joystick GUID: 030018dc5e040000220b000000006800
> Joystick Number: 0
> Number of Axes: 6
> Number of Buttons: 19
> Number of Hats: 0
> Number of Balls: 0
> GameControllerConfig:
> Name: 'Xbox One Elite 2 Controller'
> Mapping: '030018dc5e040000220b000000006800,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,left
> y:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18,crc:dc18,platform:Linux'
>
>
> Otherwise, no issues, Steam recognizes all buttons including paddles
> correctly (with or without your MR). But it also names the controller
> "Xbox One Elite 2 Controller" via USB and "Xbox One Controller" when
> using Bluetooth. This doesn't seem to have any effect on registering
> the paddles correctly though.
\o/
>
>
> >
> > >
> > > I've never recompiled a module before, but I've compiled lots of other
> > > stuff before. How hard can it be?
> > >
> >
> > Technically it's not hard, I'm sure there is a proper Arch howto
> > available. But it's painful because you'll have to maintain &
> > recompile your kernel until your fix gets in the standard kernel of
> > your distribution (archlinux if I'm not wrong).
> >
> > But the good point is that with HID-BPF that pain is relieved: I can
> > provide you with the binary, you can check it if you like (the loader
> > is in rust and the bpf itself is C), and then once installed you can
> > forget about it.
>
> Let's try it!
Well the more I think of it, the more I think we'll stick to the current state:
- SDL is actually fixed by the udev rule (they just prefer talk over hidraw)
- for evemu users, we have a bpf filter that works. I'll eventually
merge those in the kernel so they are automatically shipped.
So I don't really see the point of fixing a driver for the sake of
fixing it and just losing both of our time.
Thanks a lot for the quick testing.
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH] HID: Intel-ish-hid: Ishtp: Fix sensor reads after ACPI S3 suspend
From: srinivas pandruvada @ 2024-02-09 14:41 UTC (permalink / raw)
To: Even Xu, jikos, benjamin.tissoires, linux-input
Cc: linux-kernel@vger.kernel.org
In-Reply-To: <20240209065232.15486-1-even.xu@intel.com>
On Fri, 2024-02-09 at 14:52 +0800, Even Xu wrote:
> After legacy suspend/resume via ACPI S3, sensor read operation fails
> with timeout. Also, it will cause delay in resume operation as there
> will be retries on failure.
>
> This is caused by commit f645a90e8ff7 ("HID: intel-ish-hid:
> ishtp-hid-client: use helper functions for connection"), which used
> helper functions to simplify connect, reset and disconnect process.
> Also avoid freeing and allocating client buffers again during
> reconnect
> process.
>
> But there is a case, when ISH firmware resets after ACPI S3 suspend,
> ishtp bus driver frees client buffers. Since there is no realloc
> again
> during reconnect, there are no client buffers available to send
> connection
> requests to the firmware. Without successful connection to the
> firmware,
> subsequent sensor reads will timeout.
>
> To address this issue, ishtp bus driver does not free client buffers
> on
> warm reset after S3 resume. Simply add the buffers from the read list
> to free list of buffers.
>
> Fixes: f645a90e8ff7 ("HID: intel-ish-hid: ishtp-hid-client: use
> helper functions for connection")
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218442
> Signed-off-by: Even Xu <even.xu@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Hi Jiri,
This regression is introduced with 6.8-rc1, so need a pull request for
this rc cycle.
Thanks,
Srinivas
> ---
> drivers/hid/intel-ish-hid/ishtp/bus.c | 2 ++
> drivers/hid/intel-ish-hid/ishtp/client.c | 4 +++-
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c
> b/drivers/hid/intel-ish-hid/ishtp/bus.c
> index aa6cb033bb06..03d5601ce807 100644
> --- a/drivers/hid/intel-ish-hid/ishtp/bus.c
> +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
> @@ -722,6 +722,8 @@ void ishtp_bus_remove_all_clients(struct
> ishtp_device *ishtp_dev,
> spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags);
> list_for_each_entry(cl, &ishtp_dev->cl_list, link) {
> cl->state = ISHTP_CL_DISCONNECTED;
> + if (warm_reset && cl->device->reference_count)
> + continue;
>
> /*
> * Wake any pending process. The waiter would check
> dev->state
> diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c
> b/drivers/hid/intel-ish-hid/ishtp/client.c
> index 82c907f01bd3..8a7f2f6a4f86 100644
> --- a/drivers/hid/intel-ish-hid/ishtp/client.c
> +++ b/drivers/hid/intel-ish-hid/ishtp/client.c
> @@ -49,7 +49,9 @@ static void ishtp_read_list_flush(struct ishtp_cl
> *cl)
> list_for_each_entry_safe(rb, next, &cl->dev->read_list.list,
> list)
> if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) {
> list_del(&rb->list);
> - ishtp_io_rb_free(rb);
> + spin_lock(&cl->free_list_spinlock);
> + list_add_tail(&rb->list, &cl-
> >free_rb_list.list);
> + spin_unlock(&cl->free_list_spinlock);
> }
> spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags);
> }
^ permalink raw reply
* Re: [PATCH RFC bpf-next 0/9] allow HID-BPF to do device IOs
From: Toke Høiland-Jørgensen @ 2024-02-09 15:42 UTC (permalink / raw)
To: Benjamin Tissoires, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Jiri Kosina,
Benjamin Tissoires, Jonathan Corbet, Shuah Khan
Cc: bpf, linux-kernel, linux-input, linux-doc, linux-kselftest,
Benjamin Tissoires
In-Reply-To: <20240209-hid-bpf-sleepable-v1-0-4cc895b5adbd@kernel.org>
Benjamin Tissoires <bentiss@kernel.org> writes:
> [Putting this as a RFC because I'm pretty sure I'm not doing the things
> correctly at the BPF level.]
> [Also using bpf-next as the base tree as there will be conflicting
> changes otherwise]
>
> Ideally I'd like to have something similar to bpf_timers, but not
> in soft IRQ context. So I'm emulating this with a sleepable
> bpf_tail_call() (see "HID: bpf: allow to defer work in a delayed
> workqueue").
Why implement a new mechanism? Sounds like what you need is essentially
the bpf_timer functionality, just running in a different context, right?
So why not just add a flag to the timer setup that controls the callback
context? I've been toying with something similar for restarting XDP TX
for my queueing patch series (though I'm not sure if this will actually
end up being needed in the end):
https://git.kernel.org/pub/scm/linux/kernel/git/toke/linux.git/commit/?h=xdp-queueing-08&id=54bc201a358d1ac6ebfe900099315bbd0a76e862
-Toke
^ permalink raw reply
* Re: [PATCH RFC bpf-next 0/9] allow HID-BPF to do device IOs
From: Benjamin Tissoires @ 2024-02-09 16:26 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: Benjamin Tissoires, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Jiri Kosina,
Jonathan Corbet, Shuah Khan, bpf, linux-kernel, linux-input,
linux-doc, linux-kselftest
In-Reply-To: <87bk8pve2z.fsf@toke.dk>
On Fri, Feb 9, 2024 at 4:42 PM Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>
> Benjamin Tissoires <bentiss@kernel.org> writes:
>
> > [Putting this as a RFC because I'm pretty sure I'm not doing the things
> > correctly at the BPF level.]
> > [Also using bpf-next as the base tree as there will be conflicting
> > changes otherwise]
> >
> > Ideally I'd like to have something similar to bpf_timers, but not
> > in soft IRQ context. So I'm emulating this with a sleepable
> > bpf_tail_call() (see "HID: bpf: allow to defer work in a delayed
> > workqueue").
>
> Why implement a new mechanism? Sounds like what you need is essentially
> the bpf_timer functionality, just running in a different context, right?
Heh, that's exactly why I put in a RFC :)
So yes, the bpf_timer approach is cleaner, but I need it in a
workqueue, as a hrtimer in a softIRQ would prevent me to kzalloc and
wait for the device.
> So why not just add a flag to the timer setup that controls the callback
> context? I've been toying with something similar for restarting XDP TX
> for my queueing patch series (though I'm not sure if this will actually
> end up being needed in the end):
>
> https://git.kernel.org/pub/scm/linux/kernel/git/toke/linux.git/commit/?h=xdp-queueing-08&id=54bc201a358d1ac6ebfe900099315bbd0a76e862
>
Oh, nice. Good idea. But would it be OK to have a "timer-like" where
it actually defers the job in a workqueue instead of using an hrtimer?
I thought I would have to rewrite the entire bpf_timer approach
without the softIRQ, but if I can just add a new flag, that will make
things way simpler for me.
This however raises another issue if I were to use the bpf_timers: now
the HID-BPF kfuncs will not be available as they are only available to
tracing prog types. And when I tried to call them from a bpf_timer (in
softIRQ) they were not available.
Cheers,
Benjamin
^ permalink raw reply
* [PATCH v5 5/5] input/touchscreen: imagis: add support for IST3032C
From: Karel Balej @ 2024-02-09 16:34 UTC (permalink / raw)
To: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Henrik Rydberg, linux-input, devicetree,
linux-kernel
Cc: Duje Mihanović, ~postmarketos/upstreaming, phone-devel
In-Reply-To: <20240209164217.9008-1-karelb@gimli.ms.mff.cuni.cz>
From: Karel Balej <balejk@matfyz.cz>
IST3032C is a touchscreen chip used for instance in the
samsung,coreprimevelte smartphone, with which this was tested. Add the
chip specific information to the driver.
Reviewed-by: Markuss Broks <markuss.broks@gmail.com>
Signed-off-by: Karel Balej <balejk@matfyz.cz>
---
Notes:
v4:
* Change the WHOAMI definition position to preserve alphanumerical order
of the definitions.
* Add Markuss' Reviewed-by trailer.
drivers/input/touchscreen/imagis.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c
index 9af8a6332ae6..e1fafa561ee3 100644
--- a/drivers/input/touchscreen/imagis.c
+++ b/drivers/input/touchscreen/imagis.c
@@ -11,6 +11,8 @@
#include <linux/property.h>
#include <linux/regulator/consumer.h>
+#define IST3032C_WHOAMI 0x32c
+
#define IST3038B_REG_STATUS 0x20
#define IST3038B_REG_CHIPID 0x30
#define IST3038B_WHOAMI 0x30380b
@@ -363,6 +365,13 @@ static int imagis_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
+static const struct imagis_properties imagis_3032c_data = {
+ .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
+ .touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
+ .whoami_cmd = IST3038C_REG_CHIPID,
+ .whoami_val = IST3032C_WHOAMI,
+};
+
static const struct imagis_properties imagis_3038b_data = {
.interrupt_msg_cmd = IST3038B_REG_STATUS,
.touch_coord_cmd = IST3038B_REG_STATUS,
@@ -380,6 +389,7 @@ static const struct imagis_properties imagis_3038c_data = {
#ifdef CONFIG_OF
static const struct of_device_id imagis_of_match[] = {
+ { .compatible = "imagis,ist3032c", .data = &imagis_3032c_data },
{ .compatible = "imagis,ist3038b", .data = &imagis_3038b_data },
{ .compatible = "imagis,ist3038c", .data = &imagis_3038c_data },
{ },
--
2.43.0
^ permalink raw reply related
* [PATCH v5 1/5] input/touchscreen: imagis: Correct the maximum touch area value
From: Karel Balej @ 2024-02-09 16:34 UTC (permalink / raw)
To: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Henrik Rydberg, linux-input, devicetree,
linux-kernel
Cc: Duje Mihanović, ~postmarketos/upstreaming, phone-devel
In-Reply-To: <20240209164217.9008-1-karelb@gimli.ms.mff.cuni.cz>
From: Markuss Broks <markuss.broks@gmail.com>
As specified in downstream IST3038B driver and proved by testing,
the correct maximum reported value of touch area is 16.
Signed-off-by: Markuss Broks <markuss.broks@gmail.com>
Signed-off-by: Karel Balej <balejk@matfyz.cz>
---
drivers/input/touchscreen/imagis.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c
index 07111ca24455..e67fd3011027 100644
--- a/drivers/input/touchscreen/imagis.c
+++ b/drivers/input/touchscreen/imagis.c
@@ -210,7 +210,7 @@ static int imagis_init_input_dev(struct imagis_ts *ts)
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
- input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 16, 0, 0);
touchscreen_parse_properties(input_dev, true, &ts->prop);
if (!ts->prop.max_x || !ts->prop.max_y) {
--
2.43.0
^ permalink raw reply related
* [PATCH v5 2/5] dt-bindings: input/touchscreen: Add compatible for IST3038B
From: Karel Balej @ 2024-02-09 16:34 UTC (permalink / raw)
To: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Henrik Rydberg, linux-input, devicetree,
linux-kernel
Cc: Duje Mihanović, ~postmarketos/upstreaming, phone-devel
In-Reply-To: <20240209164217.9008-1-karelb@gimli.ms.mff.cuni.cz>
From: Markuss Broks <markuss.broks@gmail.com>
Imagis IST3038B is a variant (firmware?) of Imagis IST3038 IC
differing from IST3038C in its register interface. Add the
compatible for it to the IST3038C bindings.
Signed-off-by: Markuss Broks <markuss.broks@gmail.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
[balejk@matfyz.cz: elaborate chip differences in the commit message]
Signed-off-by: Karel Balej <balejk@matfyz.cz>
---
Notes:
v4:
* Mention how the chip is different in terms of the programming model in
the commit message.
* Add Conor's trailer.
.../devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
index 0d6b033fd5fb..b5372c4eae56 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
@@ -18,6 +18,7 @@ properties:
compatible:
enum:
+ - imagis,ist3038b
- imagis,ist3038c
reg:
--
2.43.0
^ permalink raw reply related
* [PATCH v5 4/5] dt-bindings: input/touchscreen: imagis: add compatible for IST3032C
From: Karel Balej @ 2024-02-09 16:34 UTC (permalink / raw)
To: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Henrik Rydberg, linux-input, devicetree,
linux-kernel
Cc: Duje Mihanović, ~postmarketos/upstreaming, phone-devel
In-Reply-To: <20240209164217.9008-1-karelb@gimli.ms.mff.cuni.cz>
From: Karel Balej <balejk@matfyz.cz>
IST3032C is a touchscreen IC which seems mostly compatible with IST3038C
except that it reports a different chip ID value.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Karel Balej <balejk@matfyz.cz>
---
Notes:
v5:
- Add Rob's trailer.
v4:
- Reword commit description to mention how this IC differs from the
already supported.
.../devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
index b5372c4eae56..2af71cbcc97d 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
@@ -18,6 +18,7 @@ properties:
compatible:
enum:
+ - imagis,ist3032c
- imagis,ist3038b
- imagis,ist3038c
--
2.43.0
^ permalink raw reply related
* [PATCH v5 0/5] input/touchscreen: imagis: add support for IST3032C
From: Karel Balej @ 2024-02-09 16:34 UTC (permalink / raw)
To: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Henrik Rydberg, linux-input, devicetree,
linux-kernel
Cc: Duje Mihanović, ~postmarketos/upstreaming, phone-devel
From: Karel Balej <balejk@matfyz.cz>
Hello,
this patch series generalizes the Imagis touchscreen driver to support
other Imagis chips, namely IST3038B and IST3032C, which use a slightly
different protocol.
The motivation for IST3032C is the samsung,coreprimevelte smartphone
with which this series has been tested. However, the support for this
device is not yet in-tree, the effort is happening at [1]. Preliminary
version of the regulator driver needed to use the touchscreen on this
phone can be found here [2].
Note that this is a prerequisite for (at least a part of) this series
[3] which among other things implements support for touch keys for
Imagis touchscreens that have it.
[1] https://lore.kernel.org/all/20240110-pxa1908-lkml-v8-0-fea768a59474@skole.hr/
[2] https://lore.kernel.org/all/20231228100208.2932-1-karelb@gimli.ms.mff.cuni.cz/
[3] https://lore.kernel.org/all/20240120-b4-imagis-keys-v2-0-d7fc16f2e106@skole.hr/
---
v5:
- Rebase to v6.8-rc3.
- v4: https://lore.kernel.org/all/20240120191940.3631-1-karelb@gimli.ms.mff.cuni.cz/
v4:
- Rebase to v6.7.
- v3: https://lore.kernel.org/all/20231202125948.10345-1-karelb@gimli.ms.mff.cuni.cz/
- Address feedback and add trailers.
v3:
- Rebase to v6.7-rc3.
- v2: https://lore.kernel.org/all/20231003133440.4696-1-karelb@gimli.ms.mff.cuni.cz/
v2:
- Do not rename the driver.
- Do not hardcode voltage required by the IST3032C.
- Use Markuss' series which generalizes the driver. Link to the original
series: https://lore.kernel.org/all/20220504152406.8730-1-markuss.broks@gmail.com/
- Separate bindings into separate patch.
- v1: https://lore.kernel.org/all/20230926173531.18715-1-balejk@matfyz.cz/
Karel Balej (2):
dt-bindings: input/touchscreen: imagis: add compatible for IST3032C
input/touchscreen: imagis: add support for IST3032C
Markuss Broks (3):
input/touchscreen: imagis: Correct the maximum touch area value
dt-bindings: input/touchscreen: Add compatible for IST3038B
input/touchscreen: imagis: Add support for Imagis IST3038B
.../input/touchscreen/imagis,ist3038c.yaml | 2 +
drivers/input/touchscreen/imagis.c | 70 +++++++++++++++----
2 files changed, 60 insertions(+), 12 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v5 3/5] input/touchscreen: imagis: Add support for Imagis IST3038B
From: Karel Balej @ 2024-02-09 16:34 UTC (permalink / raw)
To: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Henrik Rydberg, linux-input, devicetree,
linux-kernel
Cc: Duje Mihanović, ~postmarketos/upstreaming, phone-devel
In-Reply-To: <20240209164217.9008-1-karelb@gimli.ms.mff.cuni.cz>
From: Markuss Broks <markuss.broks@gmail.com>
Imagis IST3038B is another variant of Imagis IST3038 IC, which has
a different register interface from IST3038C (possibly firmware defined).
This should also work for IST3044B (though untested), however other
variants using this interface/protocol(IST3026, IST3032, IST3026B,
IST3032B) have a different format for coordinates, and they'd need
additional effort to be supported by this driver.
Signed-off-by: Markuss Broks <markuss.broks@gmail.com>
Signed-off-by: Karel Balej <balejk@matfyz.cz>
---
Notes:
v4:
* Sort the definitions in alphanumerical order.
drivers/input/touchscreen/imagis.c | 58 ++++++++++++++++++++++++------
1 file changed, 47 insertions(+), 11 deletions(-)
diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c
index e67fd3011027..9af8a6332ae6 100644
--- a/drivers/input/touchscreen/imagis.c
+++ b/drivers/input/touchscreen/imagis.c
@@ -11,9 +11,13 @@
#include <linux/property.h>
#include <linux/regulator/consumer.h>
+#define IST3038B_REG_STATUS 0x20
+#define IST3038B_REG_CHIPID 0x30
+#define IST3038B_WHOAMI 0x30380b
+
#define IST3038C_HIB_ACCESS (0x800B << 16)
#define IST3038C_DIRECT_ACCESS BIT(31)
-#define IST3038C_REG_CHIPID 0x40001000
+#define IST3038C_REG_CHIPID (0x40001000 | IST3038C_DIRECT_ACCESS)
#define IST3038C_REG_HIB_BASE 0x30000100
#define IST3038C_REG_TOUCH_STATUS (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS)
#define IST3038C_REG_TOUCH_COORD (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8)
@@ -31,8 +35,17 @@
#define IST3038C_FINGER_COUNT_SHIFT 12
#define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0)
+struct imagis_properties {
+ unsigned int interrupt_msg_cmd;
+ unsigned int touch_coord_cmd;
+ unsigned int whoami_cmd;
+ unsigned int whoami_val;
+ bool protocol_b;
+};
+
struct imagis_ts {
struct i2c_client *client;
+ const struct imagis_properties *tdata;
struct input_dev *input_dev;
struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2];
@@ -84,8 +97,7 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
int i;
int error;
- error = imagis_i2c_read_reg(ts, IST3038C_REG_INTR_MESSAGE,
- &intr_message);
+ error = imagis_i2c_read_reg(ts, ts->tdata->interrupt_msg_cmd, &intr_message);
if (error) {
dev_err(&ts->client->dev,
"failed to read the interrupt message: %d\n", error);
@@ -104,9 +116,13 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
finger_pressed = intr_message & IST3038C_FINGER_STATUS_MASK;
for (i = 0; i < finger_count; i++) {
- error = imagis_i2c_read_reg(ts,
- IST3038C_REG_TOUCH_COORD + (i * 4),
- &finger_status);
+ if (ts->tdata->protocol_b)
+ error = imagis_i2c_read_reg(ts,
+ ts->tdata->touch_coord_cmd, &finger_status);
+ else
+ error = imagis_i2c_read_reg(ts,
+ ts->tdata->touch_coord_cmd + (i * 4),
+ &finger_status);
if (error) {
dev_err(&ts->client->dev,
"failed to read coordinates for finger %d: %d\n",
@@ -261,6 +277,12 @@ static int imagis_probe(struct i2c_client *i2c)
ts->client = i2c;
+ ts->tdata = device_get_match_data(dev);
+ if (!ts->tdata) {
+ dev_err(dev, "missing chip data\n");
+ return -EINVAL;
+ }
+
error = imagis_init_regulators(ts);
if (error) {
dev_err(dev, "regulator init error: %d\n", error);
@@ -279,15 +301,13 @@ static int imagis_probe(struct i2c_client *i2c)
return error;
}
- error = imagis_i2c_read_reg(ts,
- IST3038C_REG_CHIPID | IST3038C_DIRECT_ACCESS,
- &chip_id);
+ error = imagis_i2c_read_reg(ts, ts->tdata->whoami_cmd, &chip_id);
if (error) {
dev_err(dev, "chip ID read failure: %d\n", error);
return error;
}
- if (chip_id != IST3038C_WHOAMI) {
+ if (chip_id != ts->tdata->whoami_val) {
dev_err(dev, "unknown chip ID: 0x%x\n", chip_id);
return -EINVAL;
}
@@ -343,9 +363,25 @@ static int imagis_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
+static const struct imagis_properties imagis_3038b_data = {
+ .interrupt_msg_cmd = IST3038B_REG_STATUS,
+ .touch_coord_cmd = IST3038B_REG_STATUS,
+ .whoami_cmd = IST3038B_REG_CHIPID,
+ .whoami_val = IST3038B_WHOAMI,
+ .protocol_b = true,
+};
+
+static const struct imagis_properties imagis_3038c_data = {
+ .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
+ .touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
+ .whoami_cmd = IST3038C_REG_CHIPID,
+ .whoami_val = IST3038C_WHOAMI,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id imagis_of_match[] = {
- { .compatible = "imagis,ist3038c", },
+ { .compatible = "imagis,ist3038b", .data = &imagis_3038b_data },
+ { .compatible = "imagis,ist3038c", .data = &imagis_3038c_data },
{ },
};
MODULE_DEVICE_TABLE(of, imagis_of_match);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH RFC bpf-next 0/9] allow HID-BPF to do device IOs
From: Toke Høiland-Jørgensen @ 2024-02-09 17:05 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Jiri Kosina,
Jonathan Corbet, Shuah Khan, bpf, linux-kernel, linux-input,
linux-doc, linux-kselftest
In-Reply-To: <CAO-hwJ+UeaBydN9deA8KBbgBiC_UCt6oXX-wGnNuSr8fhUrkXw@mail.gmail.com>
Benjamin Tissoires <benjamin.tissoires@redhat.com> writes:
> On Fri, Feb 9, 2024 at 4:42 PM Toke Høiland-Jørgensen <toke@redhat.com> wrote:
>>
>> Benjamin Tissoires <bentiss@kernel.org> writes:
>>
>> > [Putting this as a RFC because I'm pretty sure I'm not doing the things
>> > correctly at the BPF level.]
>> > [Also using bpf-next as the base tree as there will be conflicting
>> > changes otherwise]
>> >
>> > Ideally I'd like to have something similar to bpf_timers, but not
>> > in soft IRQ context. So I'm emulating this with a sleepable
>> > bpf_tail_call() (see "HID: bpf: allow to defer work in a delayed
>> > workqueue").
>>
>> Why implement a new mechanism? Sounds like what you need is essentially
>> the bpf_timer functionality, just running in a different context, right?
>
> Heh, that's exactly why I put in a RFC :)
>
> So yes, the bpf_timer approach is cleaner, but I need it in a
> workqueue, as a hrtimer in a softIRQ would prevent me to kzalloc and
> wait for the device.
Right, makes sense.
>> So why not just add a flag to the timer setup that controls the callback
>> context? I've been toying with something similar for restarting XDP TX
>> for my queueing patch series (though I'm not sure if this will actually
>> end up being needed in the end):
>>
>> https://git.kernel.org/pub/scm/linux/kernel/git/toke/linux.git/commit/?h=xdp-queueing-08&id=54bc201a358d1ac6ebfe900099315bbd0a76e862
>>
>
> Oh, nice. Good idea. But would it be OK to have a "timer-like" where
> it actually defers the job in a workqueue instead of using an hrtimer?
That's conceptually still a timer, though, isn't it? I.e., it's a
mechanism whereby you specify a callback and a delay, and bpf_timer
ensures that your callback is called after that delay. IMO it's totally
congruent with that API to be able to specify a different execution
context as part of the timer setup.
As for how to implement it, I suspect the easiest may be something
similar to what the patch I linked above does: keep the hrtimer, and
just have a different (kernel) callback function when the timer fires
which does an immediate schedule_work() (without the _delayed) and then
runs the BPF callback in that workqueue. I.e., keep the delay handling
the way the existing bpf_timer implementation does it, and just add an
indirection to start the workqueue in the kernel dispatch code.
> I thought I would have to rewrite the entire bpf_timer approach
> without the softIRQ, but if I can just add a new flag, that will make
> things way simpler for me.
IMO that would be fine. You may want to wait for the maintainers to
chime in before going down this route, though :)
> This however raises another issue if I were to use the bpf_timers: now
> the HID-BPF kfuncs will not be available as they are only available to
> tracing prog types. And when I tried to call them from a bpf_timer (in
> softIRQ) they were not available.
IIUC, the bpf_timer callback is just a function (subprog) from the
verifier PoV, so it is verified as whatever program type is creating the
timer. So in other words, as long as you setup the timer from inside a
tracing prog type, you should have access to all the same kfuncs, I
think?
-Toke
^ permalink raw reply
* Re: [PATCH][next] input: ti_am335x_tsc: remove redundant assignment to variable config
From: Dmitry Torokhov @ 2024-02-09 18:53 UTC (permalink / raw)
To: Colin Ian King; +Cc: linux-input, kernel-janitors, linux-kernel
In-Reply-To: <20240205215940.1851349-1-colin.i.king@gmail.com>
On Mon, Feb 05, 2024 at 09:59:40PM +0000, Colin Ian King wrote:
> The variable config is being initialized with a value that is never
> read, it is being re-assigned in the next statement. The initialization
> is redundant and can be removed.
>
> Cleans up clang scan build warning:
> drivers/input/touchscreen/ti_am335x_tsc.c:160:2: warning: Value stored
> to 'config' is never read [deadcode.DeadStores]
>
> Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
Applied, thank you.
--
Dmitry
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox