blob: 8703d31e2e667d706791e993456721e14e887dd9 [file] [log] [blame]
Jackson Bockusc2a4e682017-06-23 11:59:29 -07001/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
Jackson Bockusc2a4e682017-06-23 11:59:29 -07004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
17/*
18 * @file nss_project.h
19 * NSS project APIs.
20 */
21#include "nss_tx_rx_common.h"
22
23static int nss_project_wt_stats_enable;
24
25/*
26 * nss_project_free_wt_stats()
27 * Frees a number of allocated worker thread statistics.
28 */
29static void nss_project_free_wt_stats(struct nss_worker_thread_stats *wt_stats, int num_alloc)
30{
31 int i;
32
33 if (!wt_stats) {
34 return;
35 }
36
37 for (i = 0; i < num_alloc; i++) {
38 kfree(wt_stats[i].irq_stats);
39 }
40 kfree(wt_stats);
41}
42
43/*
44 * nss_project_alloc_wt_stats()
45 * Allocates worker thread stats for a given number of threads and IRQs.
46 */
47static struct nss_worker_thread_stats *nss_project_alloc_wt_stats(uint32_t thread_count, uint32_t irq_count)
48{
49 struct nss_worker_thread_stats *wt_stats;
50 int i;
51
52 wt_stats = kzalloc(thread_count * sizeof(struct nss_worker_thread_stats), GFP_ATOMIC);
53 if (unlikely(!wt_stats)) {
54 return NULL;
55 }
56
57 for (i = 0; i < thread_count; i++) {
58 wt_stats[i].irq_stats =
59 kzalloc(irq_count * sizeof(struct nss_project_irq_stats), GFP_ATOMIC);
60 if (unlikely(!wt_stats[i].irq_stats)) {
61 nss_project_free_wt_stats(wt_stats, i);
62 return NULL;
63 }
64 }
65
66 return wt_stats;
67}
68
69/*
70 * nss_project_wt_stats_enable_callback()
71 * Callback function for wt stats enable messages
72 */
73static void nss_project_wt_stats_enable_callback(void *app_data, struct nss_project_msg *msg)
74{
75 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)app_data;
76 struct nss_project_msg_wt_stats_enable *stats_enable = &msg->msg.wt_stats_enable;
77 struct nss_worker_thread_stats *stats_temp;
78
79 NSS_VERIFY_CTX_MAGIC(nss_ctx);
80 if (msg->cm.response != NSS_CMN_RESPONSE_ACK) {
81 return;
82 }
83
84 nss_info("%p: Received response ACK for worker thread stats enable msg.\n", nss_ctx);
85
86 /*
87 * If statistics have already been allocated, nothing else to do.
88 */
89 if (nss_ctx->wt_stats) {
90 return;
91 }
92
93 stats_temp = nss_project_alloc_wt_stats(stats_enable->worker_thread_count,
94 stats_enable->irq_count);
95 if (unlikely(!stats_temp)) {
96 nss_warning("%p: Unable to allocate worker thread statistics.\n", nss_ctx);
97 return;
98 }
99
100 spin_lock_bh(&nss_ctx->nss_top->stats_lock);
101 nss_ctx->wt_stats = stats_temp;
102 nss_ctx->worker_thread_count = stats_enable->worker_thread_count;
103 nss_ctx->irq_count = stats_enable->irq_count;
104 spin_unlock_bh(&nss_ctx->nss_top->stats_lock);
105}
106
107/*
108 * nss_project_wt_stats_send_enable()
109 * Sends message to firmware to enable or disable worker_thread statistics collection.
110 */
111static nss_tx_status_t nss_project_wt_stats_send_enable(struct nss_ctx_instance *nss_ctx, bool enable)
112{
113 struct nss_project_msg *npm;
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700114 struct nss_cmn_msg *ncm;
115 nss_tx_status_t ret;
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700116
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700117 npm = kzalloc(sizeof(*npm), GFP_KERNEL);
118 if (!npm) {
119 nss_warning("%p: Failed to allocate buffer for message\n", nss_ctx);
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700120 return NSS_TX_FAILURE;
121 }
122
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700123 /*
124 * Populate the message
125 */
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700126 ncm = &npm->cm;
127 nss_cmn_msg_init(ncm, NSS_PROJECT_INTERFACE,
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700128 NSS_PROJECT_MSG_WT_STATS_ENABLE,
129 sizeof(struct nss_project_msg_wt_stats_enable),
130 (void *)nss_project_wt_stats_enable_callback,
131 (void *)nss_ctx);
132 npm->msg.wt_stats_enable.enable = enable;
133
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700134 ret = nss_core_send_cmd(nss_ctx, npm, sizeof(*npm), NSS_NBUF_PAYLOAD_SIZE);
135 kfree(npm);
136 return ret;
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700137}
138
139/*
140 * nss_project_wt_stats_update()
141 * Updates stored statistics with the data found in the notify.
142 */
143static void nss_project_wt_stats_update(struct nss_ctx_instance *nss_ctx,
144 struct nss_project_msg_wt_stats_notify *stats_notify)
145{
146 struct nss_worker_thread_stats *wt_stats;
147 int i;
148
149 if (unlikely(!nss_ctx->wt_stats)) {
150 nss_warning("%p: Worker thread statistics not yet allocated.\n", nss_ctx);
151 return;
152 }
153
154 if (unlikely(stats_notify->threadno >= nss_ctx->worker_thread_count)) {
155 nss_warning("%p: Invalid WT number %d\n", nss_ctx, stats_notify->threadno);
156 return;
157 }
158
159 if (unlikely(stats_notify->stats_written > NSS_PROJECT_IRQS_PER_MESSAGE)) {
160 nss_warning("%p: Invalid worker thread stats written count %d\n",
161 nss_ctx, stats_notify->stats_written);
162 return;
163 }
164
165 wt_stats = &(nss_ctx->wt_stats[stats_notify->threadno]);
166
167 if (unlikely(!wt_stats->irq_stats)) {
168 nss_warning("%p: Worker thread statistics not allocated for thread %d\n",
169 nss_ctx, stats_notify->threadno);
170 return;
171 }
172
173 spin_lock_bh(&nss_ctx->nss_top->stats_lock);
174 for (i = 0; i < stats_notify->stats_written; ++i) {
175 int irq = stats_notify->stats[i].irq;
176 if (unlikely(irq >= nss_ctx->irq_count)) {
177 nss_warning("%p: Invalid IRQ number %d\n", nss_ctx, irq);
178 continue;
179 }
180
181 wt_stats->irq_stats[irq] = stats_notify->stats[i];
182 }
183 spin_unlock_bh(&nss_ctx->nss_top->stats_lock);
184}
185
186/*
187 * nss_project_msg_handler()
188 * Handles metadata messages on the project interface.
189 */
190static void nss_project_msg_handler(struct nss_ctx_instance *nss_ctx,
191 struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
192{
193 struct nss_project_msg *npm = (struct nss_project_msg *)ncm;
194 nss_project_msg_callback_t cb;
195
196 /*
197 * Sanity checks on message
198 */
199 if (npm->cm.type >= NSS_PROJECT_MSG_MAX) {
200 nss_warning("%p: message type out of range: %d\n", nss_ctx, npm->cm.type);
201 return;
202 }
203
204 if (nss_cmn_get_msg_len(&(npm->cm)) > sizeof(struct nss_project_msg)) {
205 nss_warning("%p: message length is invalid: %d\n", nss_ctx, nss_cmn_get_msg_len(&(npm->cm)));
206 return;
207 }
208
209 switch (npm->cm.type) {
210 case NSS_PROJECT_MSG_WT_STATS_NOTIFY:
211 nss_project_wt_stats_update(nss_ctx, &(npm->msg.wt_stats_notify));
212 return;
213 }
214
215 nss_core_log_msg_failures(nss_ctx, ncm);
216
217 if (!ncm->cb) {
218 return;
219 }
220
221 cb = (nss_project_msg_callback_t)ncm->cb;
222 cb((void *)nss_ctx, npm);
223}
224
225/*
226 * nss_project_wt_stats_handler()
227 * Sysctl handler for wt_stats.
228 *
229 * Uses proc_dointvec to process data. For a write operation, also sends worker
230 * thread stats enable messages containing the new value to each NSS core.
231 */
232static int nss_project_wt_stats_handler(struct ctl_table *ctl, int write,
233 void __user *buffer, size_t *lenp, loff_t *ppos)
234{
235 int ret;
236 int i;
237
238 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
239
240 /*
241 * In case of error, stop now.
242 */
243 if (ret) {
244 return ret;
245 }
246
247 /*
248 * No additional behavior necessary for a read operation.
249 */
250 if (!write) {
251 return ret;
252 }
253
254 /*
255 * If a value was written, send a message containing that value to each
256 * NSS core.
257 */
Suman Ghosh9f7b3702018-09-21 19:51:40 +0530258 for (i = 0; i < nss_top_main.num_nss; ++i) {
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700259 nss_project_wt_stats_send_enable(&(nss_top_main.nss[i]),
260 nss_project_wt_stats_enable);
261 }
262 return ret;
263
264}
265
266/*
267 * Tree of ctl_tables used to put the wt_stats proc node in the correct place in
268 * the file system. Allows the command $ echo 1 > proc/sys/dev/nss/project/wt_stats
269 * to enable worker thread statistics (echoing 0 into the same target will disable).
270 */
271static struct ctl_table nss_project_table[] = {
272 {
273 .procname = "wt_stats",
274 .data = &nss_project_wt_stats_enable,
275 .maxlen = sizeof(int),
276 .mode = 0644,
277 .proc_handler = &nss_project_wt_stats_handler,
278 },
279 { }
280};
281
282static struct ctl_table nss_project_dir[] = {
283 {
284 .procname = "project",
285 .mode = 0555,
286 .child = nss_project_table,
287 },
288 { }
289};
290
291static struct ctl_table nss_project_root_dir[] = {
292 {
293 .procname = "nss",
294 .mode = 0555,
295 .child = nss_project_dir,
296 },
297 { }
298};
299
300static struct ctl_table nss_project_root[] = {
301 {
302 .procname = "dev",
303 .mode = 0555,
304 .child = nss_project_root_dir,
305 },
306 { }
307};
308
309static struct ctl_table_header *nss_project_header;
310
311/*
312 * nss_project_register_sysctl()
313 * Registers any sysctl handlers for the project.
314 */
315void nss_project_register_sysctl(void)
316{
317 nss_project_header = register_sysctl_table(nss_project_root);
318}
319
320/*
321 * nss_project_unregister_sysctl()
322 * De-registers any sysctl handlers for the project.
323 */
324void nss_project_unregister_sysctl(void)
325{
326 if (nss_project_header) {
327 unregister_sysctl_table(nss_project_header);
328 }
329}
330
331/*
332 * nss_project_register_handler()
333 * Registers the handler for NSS->HLOS messages
334 */
335void nss_project_register_handler(struct nss_ctx_instance *nss_ctx)
336{
337 nss_core_register_handler(nss_ctx, NSS_PROJECT_INTERFACE, nss_project_msg_handler, NULL);
338}