1 /*
2  * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #ifndef __WLAN_OSIF_REQUEST_MANAGER_H__
21 #define __WLAN_OSIF_REQUEST_MANAGER_H__
22 
23 /**
24  * DOC: WLAN OSIF REQUEST MANAGER
25  *
26  * Many operations within the wlan driver occur in an asynchronous
27  * manner. Requests are received by OSIF via one of the kernel
28  * interfaces (ioctl, nl80211, virtual file system, etc.). The
29  * requests are translated to an internal format and are then passed
30  * to lower layers, usually via SME, for processing. For requests
31  * which require a response, that response comes up from the lower
32  * layers in a separate thread of execution, ultimately resulting in a
33  * call to a callback function that was provided by OSIF as part of the
34  * initial request. So a mechanism is needed to synchronize the
35  * request and response. This framework provides that mechanism.
36  *
37  * Once the framework has been initialized, the typical sequence of
38  * events is as follows:
39  *
40  * Request Thread:
41  * 1. Create a &struct osif_request_params which describes the request.
42  * 2. Call osif_request_alloc() to allocate a &struct osif_request.
43  * 3. Call osif_request_priv() to get a pointer to the private data.
44  * 4. Place any information which must be shared with the Response
45  *    Callback in the private data area.
46  * 5. Call osif_request_cookie() to get the unique cookie assigned
47  *    to the request.
48  * 6. Call the underlying request handling API, passing the cookie
49  *    as the callback's private context.
50  * 7. Call osif_request_wait_for_response() to wait for the response
51  *    (or for the request to time out).
52  * 8. Use the return status to see if the request was successful. If
53  *    it was, retrieve any response information from the private
54  *    structure and prepare a response for userspace.
55  * 9. Call osif_request_put() to relinquish access to the request.
56  * 10. Return status to the caller.
57  *
58  * Response Callback:
59  * 1. Call osif_request_get() with the provided cookie to see if the
60  *    request structure is still valid.  If it returns %NULL then
61  *    return since this means the request thread has already timed
62  *    out.
63  * 2. Call osif_request_priv() to get access to the private data area.
64  * 3. Write response data into the private data area.
65  * 4. Call osif_request_complete() to indicate that the response is
66  *    ready to be processed by the request thread.
67  * 5. Call osif_request_put() to relinquish the callback function's
68  *    reference to the request.
69  */
70 
71 /* this is opaque to clients */
72 struct osif_request;
73 
74 /**
75  * typedef osif_request_dealloc() - Private data deallocation function
76  * @priv: pointer to request private date
77  */
78 typedef void (*osif_request_dealloc)(void *priv);
79 
80 /**
81  * struct osif_request_params - OSIF request parameters
82  * @priv_size: Size of the private data area required to pass
83  *      information between the request thread and the response callback.
84  * @timeout_ms: The amount of time to wait for a response in milliseconds.
85  * @dealloc: Function to be called when the request is destroyed to
86  *      deallocate any allocations made in the private area of the
87  *      request struct. Can be %NULL if no private allocations are
88  *      made.
89  */
90 struct osif_request_params {
91 	uint32_t priv_size;
92 	uint32_t timeout_ms;
93 	osif_request_dealloc dealloc;
94 };
95 
96 /**
97  * osif_request_alloc() - Allocate a request struct
98  * @params: parameter block that specifies the attributes of the
99  *      request
100  *
101  * This function will attempt to allocate a &struct osif_request with
102  * the specified @params. If successful, the caller can then use
103  * request struct to make an asynchronous request. Once the request is
104  * no longer needed, the reference should be relinquished via a call
105  * to osif_request_put().
106  *
107  * Return: A pointer to an allocated &struct osif_request (which also
108  * contains room for the private buffer) if the allocation is
109  * successful, %NULL if the allocation fails.
110  */
111 struct osif_request *osif_request_alloc(const struct osif_request_params *params);
112 
113 /**
114  * osif_request_priv() - Get pointer to request private data
115  * @request: The request struct that contains the private data
116  *
117  * This function will return a pointer to the private data area that
118  * is part of the request struct. The caller must already have a valid
119  * reference to @request from either osif_request_alloc() or
120  * osif_request_get().
121  *
122  * Returns: pointer to the private data area. Note that this pointer
123  * will always be an offset from the input @request pointer and hence
124  * this function will never return %NULL.
125  */
126 void *osif_request_priv(struct osif_request *request);
127 
128 /**
129  * osif_request_cookie() - Get cookie of a request
130  * @request: The request struct associated with the request
131  *
132  * This function will return the unique cookie that has been assigned
133  * to the request. This cookie can subsequently be passed to
134  * osif_request_get() to retrieve the request.
135  *
136  * Note that the cookie is defined as a void pointer as it is intended
137  * to be passed as an opaque context pointer from OSIF to underlying
138  * layers when making a request, and subsequently passed back to OSIF
139  * as an opaque pointer in an asynchronous callback.
140  *
141  * Returns: The cookie assigned to the request.
142  */
143 void *osif_request_cookie(struct osif_request *request);
144 
145 /**
146  * osif_request_get() - Get a reference to a request struct
147  * @cookie: The cookie of the request struct that needs to be
148  *      referenced
149  *
150  * This function will use the cookie to determine if the associated
151  * request struct is valid, and if so, will increment the reference
152  * count of the struct. This means the caller is guaranteed that the
153  * request struct is valid and the underlying private data can be
154  * dereferenced.
155  *
156  * Returns: The pointer to the request struct associated with @cookie
157  * if the request is still valid, %NULL if the underlying request
158  * struct is no longer valid.
159  */
160 struct osif_request *osif_request_get(void *cookie);
161 
162 /**
163  * osif_request_put() - Release a reference to a request struct
164  * @request: The request struct that no longer needs to be referenced
165  *
166  * This function will decrement the reference count of the struct, and
167  * will clean up the request if this is the last reference. The caller
168  * must already have a valid reference to @request, either from
169  * osif_request_alloc() or osif_request_get().
170  *
171  * Returns: Nothing
172  */
173 void osif_request_put(struct osif_request *request);
174 
175 /**
176  * osif_request_wait_for_response() - Wait for a response
177  * @request: The request struct associated with the request
178  *
179  * This function will wait until either a response is received and
180  * communicated via osif_request_complete(), or until the request
181  * timeout period expires.
182  *
183  * Returns: 0 if a response was received, -ETIMEDOUT if the response
184  * timed out.
185  */
186 int osif_request_wait_for_response(struct osif_request *request);
187 
188 /**
189  * osif_request_complete() - Complete a request
190  * @request: The request struct associated with the request
191  *
192  * This function is used to indicate that a response has been received
193  * and that any information required by the request thread has been
194  * copied into the private data area of the request struct. This will
195  * unblock any osif_request_wait_for_response() that is pending on this
196  * @request.
197  *
198  * Returns: Nothing
199  */
200 void osif_request_complete(struct osif_request *request);
201 
202 /**
203  * osif_request_manager_init() - Initialize the OSIF Request Manager
204  *
205  * This function must be called during system initialization to
206  * initialize the OSIF Request Manager.
207  *
208  * Returns: Nothing
209  */
210 void osif_request_manager_init(void);
211 
212 /**
213  * osif_request_manager_deinit() - Deinitialize the OSIF Request Manager
214  *
215  * This function must be called during system shutdown to deinitialize
216  * the OSIF Request Manager.
217  *
218  * Returns: Nothing
219  */
220 void osif_request_manager_deinit(void);
221 
222 #endif /* __WLAN_OSIF_REQUEST_MANAGER_H__ */
223