1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* |
3 | * Copyright (c) 2019, Mellanox Technologies inc. All rights reserved. |
4 | */ |
5 | |
6 | #include <rdma/uverbs_std_types.h> |
7 | #include <rdma/uverbs_ioctl.h> |
8 | #include "rdma_core.h" |
9 | #include "uverbs.h" |
10 | |
11 | static int UVERBS_HANDLER(UVERBS_METHOD_ASYNC_EVENT_ALLOC)( |
12 | struct uverbs_attr_bundle *attrs) |
13 | { |
14 | struct ib_uobject *uobj = |
15 | uverbs_attr_get_uobject(attrs_bundle: attrs, idx: UVERBS_METHOD_ASYNC_EVENT_ALLOC); |
16 | |
17 | ib_uverbs_init_async_event_file( |
18 | container_of(uobj, struct ib_uverbs_async_event_file, uobj)); |
19 | return 0; |
20 | } |
21 | |
22 | static void uverbs_async_event_destroy_uobj(struct ib_uobject *uobj, |
23 | enum rdma_remove_reason why) |
24 | { |
25 | struct ib_uverbs_async_event_file *event_file = |
26 | container_of(uobj, struct ib_uverbs_async_event_file, uobj); |
27 | |
28 | ib_unregister_event_handler(event_handler: &event_file->event_handler); |
29 | |
30 | if (why == RDMA_REMOVE_DRIVER_REMOVE) |
31 | ib_uverbs_async_handler(async_file: event_file, element: 0, event: IB_EVENT_DEVICE_FATAL, |
32 | NULL, NULL); |
33 | } |
34 | |
35 | int uverbs_async_event_release(struct inode *inode, struct file *filp) |
36 | { |
37 | struct ib_uverbs_async_event_file *event_file; |
38 | struct ib_uobject *uobj = filp->private_data; |
39 | int ret; |
40 | |
41 | if (!uobj) |
42 | return uverbs_uobject_fd_release(inode, filp); |
43 | |
44 | event_file = |
45 | container_of(uobj, struct ib_uverbs_async_event_file, uobj); |
46 | |
47 | /* |
48 | * The async event FD has to deliver IB_EVENT_DEVICE_FATAL even after |
49 | * disassociation, so cleaning the event list must only happen after |
50 | * release. The user knows it has reached the end of the event stream |
51 | * when it sees IB_EVENT_DEVICE_FATAL. |
52 | */ |
53 | uverbs_uobject_get(uobject: uobj); |
54 | ret = uverbs_uobject_fd_release(inode, filp); |
55 | ib_uverbs_free_event_queue(event_queue: &event_file->ev_queue); |
56 | uverbs_uobject_put(uobject: uobj); |
57 | return ret; |
58 | } |
59 | |
60 | DECLARE_UVERBS_NAMED_METHOD( |
61 | UVERBS_METHOD_ASYNC_EVENT_ALLOC, |
62 | UVERBS_ATTR_FD(UVERBS_ATTR_ASYNC_EVENT_ALLOC_FD_HANDLE, |
63 | UVERBS_OBJECT_ASYNC_EVENT, |
64 | UVERBS_ACCESS_NEW, |
65 | UA_MANDATORY)); |
66 | |
67 | DECLARE_UVERBS_NAMED_OBJECT( |
68 | UVERBS_OBJECT_ASYNC_EVENT, |
69 | UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_async_event_file), |
70 | uverbs_async_event_destroy_uobj, |
71 | &uverbs_async_event_fops, |
72 | "[infinibandevent]" , |
73 | O_RDONLY), |
74 | &UVERBS_METHOD(UVERBS_METHOD_ASYNC_EVENT_ALLOC)); |
75 | |
76 | const struct uapi_definition uverbs_def_obj_async_fd[] = { |
77 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_ASYNC_EVENT), |
78 | {} |
79 | }; |
80 | |