Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/hid: add wq test for hid_bpf_input_report()

Now that bpf_wq is available, we can write a test with it. Having
hid_bpf_input_report() waiting for the device means that we can
directly call it, and we get that event when the device is ready.

Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-10-cfd60fb6c79f@kernel.org
Acked-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

+126
+38
tools/testing/selftests/hid/hid_bpf.c
··· 1131 1131 } 1132 1132 1133 1133 /* 1134 + * Attach hid_multiply_event_wq to the given uhid device, 1135 + * retrieve and open the matching hidraw node, 1136 + * inject one event in the uhid device, 1137 + * check that the program sees it and can add extra data 1138 + */ 1139 + TEST_F(hid_bpf, test_multiply_events_wq) 1140 + { 1141 + const struct test_program progs[] = { 1142 + { .name = "hid_test_multiply_events_wq" }, 1143 + }; 1144 + __u8 buf[10] = {0}; 1145 + int err; 1146 + 1147 + LOAD_PROGRAMS(progs); 1148 + 1149 + /* inject one event */ 1150 + buf[0] = 1; 1151 + buf[1] = 42; 1152 + uhid_send_event(_metadata, self->uhid_fd, buf, 6); 1153 + 1154 + /* read the data from hidraw */ 1155 + memset(buf, 0, sizeof(buf)); 1156 + err = read(self->hidraw_fd, buf, sizeof(buf)); 1157 + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 1158 + ASSERT_EQ(buf[0], 1); 1159 + ASSERT_EQ(buf[1], 47); 1160 + 1161 + usleep(100000); 1162 + 1163 + /* read the data from hidraw */ 1164 + memset(buf, 0, sizeof(buf)); 1165 + err = read(self->hidraw_fd, buf, sizeof(buf)); 1166 + ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); 1167 + ASSERT_EQ(buf[0], 2); 1168 + ASSERT_EQ(buf[1], 3); 1169 + } 1170 + 1171 + /* 1134 1172 * Attach hid_insert{0,1,2} to the given uhid device, 1135 1173 * retrieve and open the matching hidraw node, 1136 1174 * inject one event in the uhid device,
+79
tools/testing/selftests/hid/progs/hid.c
··· 443 443 struct hid_bpf_ops test_infinite_loop_output_report = { 444 444 .hid_hw_output_report = (void *)hid_test_infinite_loop_output_report, 445 445 }; 446 + 447 + struct elem { 448 + struct bpf_wq work; 449 + }; 450 + 451 + struct { 452 + __uint(type, BPF_MAP_TYPE_HASH); 453 + __uint(max_entries, 1); 454 + __type(key, int); 455 + __type(value, struct elem); 456 + } hmap SEC(".maps"); 457 + 458 + static int wq_cb_sleepable(void *map, int *key, struct bpf_wq *work) 459 + { 460 + __u8 buf[9] = {2, 3, 4, 5, 6, 7, 8, 9, 10}; 461 + struct hid_bpf_ctx *hid_ctx; 462 + 463 + hid_ctx = hid_bpf_allocate_context(*key); 464 + if (!hid_ctx) 465 + return 0; /* EPERM check */ 466 + 467 + hid_bpf_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf)); 468 + 469 + hid_bpf_release_context(hid_ctx); 470 + 471 + return 0; 472 + } 473 + 474 + static int test_inject_input_report_callback(int *key) 475 + { 476 + struct elem init = {}, *val; 477 + struct bpf_wq *wq; 478 + 479 + if (bpf_map_update_elem(&hmap, key, &init, 0)) 480 + return -1; 481 + 482 + val = bpf_map_lookup_elem(&hmap, key); 483 + if (!val) 484 + return -2; 485 + 486 + wq = &val->work; 487 + if (bpf_wq_init(wq, &hmap, 0) != 0) 488 + return -3; 489 + 490 + if (bpf_wq_set_callback(wq, wq_cb_sleepable, 0)) 491 + return -4; 492 + 493 + if (bpf_wq_start(wq, 0)) 494 + return -5; 495 + 496 + return 0; 497 + } 498 + 499 + SEC("?struct_ops/hid_device_event") 500 + int BPF_PROG(hid_test_multiply_events_wq, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) 501 + { 502 + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */); 503 + int hid = hid_ctx->hid->id; 504 + int ret; 505 + 506 + if (!data) 507 + return 0; /* EPERM check */ 508 + 509 + if (data[0] != 1) 510 + return 0; 511 + 512 + ret = test_inject_input_report_callback(&hid); 513 + if (ret) 514 + return ret; 515 + 516 + data[1] += 5; 517 + 518 + return 0; 519 + } 520 + 521 + SEC(".struct_ops.link") 522 + struct hid_bpf_ops test_multiply_events_wq = { 523 + .hid_device_event = (void *)hid_test_multiply_events_wq, 524 + };
+9
tools/testing/selftests/hid/progs/hid_bpf_helpers.h
··· 90 90 __u8 *data, 91 91 size_t buf__sz) __ksym; 92 92 93 + /* bpf_wq implementation */ 94 + extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym; 95 + extern int bpf_wq_start(struct bpf_wq *wq, unsigned int flags) __weak __ksym; 96 + extern int bpf_wq_set_callback_impl(struct bpf_wq *wq, 97 + int (callback_fn)(void *map, int *key, struct bpf_wq *wq), 98 + unsigned int flags__k, void *aux__ign) __ksym; 99 + #define bpf_wq_set_callback(timer, cb, flags) \ 100 + bpf_wq_set_callback_impl(timer, cb, flags, NULL) 101 + 93 102 #endif /* __HID_BPF_HELPERS_H */