blob: b81c4548f825191a258c7d77eb405c25d3919c0c [file] [log] [blame]
Amit Gupta316729b2016-08-12 12:21:15 +05301/*
2 **************************************************************************
Thomas Wufc4d9fd2017-03-22 10:15:30 -07003 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Amit Gupta316729b2016-08-12 12:21:15 +05304 * 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#include "nss_ppe.h"
Yu Huang8c107082017-07-24 14:58:26 -070018#include "nss_ppe_stats.h"
Amit Gupta79c1c202017-06-30 15:28:13 +053019
Amit Guptacb1696b2017-11-13 13:09:06 +053020struct nss_ppe_stats_debug nss_ppe_debug_stats;
21
Amit Gupta316729b2016-08-12 12:21:15 +053022/*
23 * nss_ppe_verify_ifnum()
24 * Verify PPE interface number.
25 */
26static inline bool nss_ppe_verify_ifnum(int if_num)
27{
28 return nss_is_dynamic_interface(if_num) || (if_num == NSS_PPE_INTERFACE);
29}
30
31/*
Amit Gupta1263b082017-07-06 14:22:57 +053032 * nss_ppe_callback()
33 * Callback to handle the completion of NSS->HLOS messages.
34 */
35static void nss_ppe_callback(void *app_data, struct nss_ppe_msg *npm)
36{
37 nss_ppe_msg_callback_t callback = (nss_ppe_msg_callback_t)ppe_pvt.cb;
38 void *data = ppe_pvt.app_data;
39
40 ppe_pvt.response = NSS_TX_SUCCESS;
41 ppe_pvt.cb = NULL;
42 ppe_pvt.app_data = NULL;
43
44 if (npm->cm.response != NSS_CMN_RESPONSE_ACK) {
45 nss_warning("ppe error response %d\n", npm->cm.response);
46 ppe_pvt.response = npm->cm.response;
47 }
48
49 if (callback) {
50 callback(data, npm);
51 }
52 complete(&ppe_pvt.complete);
53}
54
55/*
56 * nss_ppe_tx_msg()
57 * Transmit a ppe message to NSSFW
58 */
59nss_tx_status_t nss_ppe_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_ppe_msg *msg)
60{
61 struct nss_ppe_msg *nm;
62 struct nss_cmn_msg *ncm = &msg->cm;
63 struct sk_buff *nbuf;
64 int32_t status;
65
66 NSS_VERIFY_CTX_MAGIC(nss_ctx);
67 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
68 nss_warning("%p: ppe msg dropped as core not ready\n", nss_ctx);
69 return NSS_TX_FAILURE_NOT_READY;
70 }
71
72 /*
73 * Sanity check the message
74 */
75 if (ncm->type >= NSS_PPE_MSG_MAX) {
76 nss_warning("%p: message type out of range: %d\n", nss_ctx, ncm->type);
77 return NSS_TX_FAILURE;
78 }
79
80 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_ppe_msg)) {
81 nss_warning("%p: message length is invalid: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
82 return NSS_TX_FAILURE;
83 }
84
85 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
86 if (unlikely(!nbuf)) {
87 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
88 nss_warning("%p: msg dropped as command allocation failed\n", nss_ctx);
89 return NSS_TX_FAILURE;
90 }
91
92 /*
93 * Copy the message to our skb
94 */
95 nm = (struct nss_ppe_msg *)skb_put(nbuf, sizeof(struct nss_ppe_msg));
96 memcpy(nm, msg, sizeof(struct nss_ppe_msg));
97
98 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
99 if (status != NSS_CORE_STATUS_SUCCESS) {
100 dev_kfree_skb_any(nbuf);
101 nss_warning("%p: Unable to enqueue 'ppe message'\n", nss_ctx);
102 return NSS_TX_FAILURE;
103 }
104
105 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
106
107 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
108 return NSS_TX_SUCCESS;
109}
110EXPORT_SYMBOL(nss_ppe_tx_msg);
111
112/*
113 * nss_ppe_tx_msg_sync()
114 * Transmit a ppe message to NSS firmware synchronously.
115 */
116nss_tx_status_t nss_ppe_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_ppe_msg *npm)
117{
118 nss_tx_status_t status;
119 int ret = 0;
120
121 down(&ppe_pvt.sem);
122 ppe_pvt.cb = (void *)npm->cm.cb;
123 ppe_pvt.app_data = (void *)npm->cm.app_data;
124
125 npm->cm.cb = (nss_ptr_t)nss_ppe_callback;
126 npm->cm.app_data = (nss_ptr_t)NULL;
127
128 status = nss_ppe_tx_msg(nss_ctx, npm);
129 if (status != NSS_TX_SUCCESS) {
130 nss_warning("%p: ppe_tx_msg failed\n", nss_ctx);
131 up(&ppe_pvt.sem);
132 return status;
133 }
134
135 ret = wait_for_completion_timeout(&ppe_pvt.complete, msecs_to_jiffies(NSS_PPE_TX_TIMEOUT));
136 if (!ret) {
137 nss_warning("%p: ppe msg tx failed due to timeout\n", nss_ctx);
138 ppe_pvt.response = NSS_TX_FAILURE;
139 }
140
141 status = ppe_pvt.response;
142 up(&ppe_pvt.sem);
143 return status;
144}
145EXPORT_SYMBOL(nss_ppe_tx_msg_sync);
146
147/*
148 * nss_ppe_get_context()
149 * Get NSS context instance for ppe
150 */
151struct nss_ctx_instance *nss_ppe_get_context(void)
152{
153 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.ppe_handler_id];
154}
155EXPORT_SYMBOL(nss_ppe_get_context);
156
157/*
158 * nss_ppe_msg_init()
159 * Initialize nss_ppe_msg.
160 */
161void nss_ppe_msg_init(struct nss_ppe_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
162{
163 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
164}
165EXPORT_SYMBOL(nss_ppe_msg_init);
166
167/*
168 * nss_ppe_tx_l2_exception_msg
169 * API to send vsi assign message to NSS FW
170 */
171nss_tx_status_t nss_ppe_tx_l2_exception_msg(uint32_t if_num, bool exception_enable)
172{
173 struct nss_ctx_instance *nss_ctx = nss_ppe_get_context();
174 struct nss_ppe_msg npm;
175
176 if (!nss_ctx) {
177 nss_warning("Can't get nss context\n");
178 return NSS_TX_FAILURE;
179 }
180
181 if (!nss_ppe_verify_ifnum(if_num)) {
182 nss_warning("%p: invalid interface %d\n", nss_ctx, if_num);
183 return NSS_TX_FAILURE;
184 }
185
186 nss_ppe_msg_init(&npm, if_num, NSS_PPE_MSG_L2_EXCEPTION,
187 sizeof(struct nss_ppe_l2_exception_msg), NULL, NULL);
188
189 npm.msg.l2_exception.l2_exception_enable = exception_enable;
190
191 return nss_ppe_tx_msg_sync(nss_ctx, &npm);
192}
193EXPORT_SYMBOL(nss_ppe_tx_l2_exception_msg);
194
195/*
Amit Gupta316729b2016-08-12 12:21:15 +0530196 * nss_ppe_handler()
Amit Gupta1263b082017-07-06 14:22:57 +0530197 * Handle NSS -> HLOS messages for ppe
Amit Gupta316729b2016-08-12 12:21:15 +0530198 */
199static void nss_ppe_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
200{
201 struct nss_ppe_msg *msg = (struct nss_ppe_msg *)ncm;
Amit Gupta1263b082017-07-06 14:22:57 +0530202 void *ctx;
Amit Gupta316729b2016-08-12 12:21:15 +0530203
Amit Gupta1263b082017-07-06 14:22:57 +0530204 nss_ppe_msg_callback_t cb;
205
206 nss_trace("nss_ctx: %p ppe msg: %p\n", nss_ctx, msg);
Amit Gupta316729b2016-08-12 12:21:15 +0530207 BUG_ON(!nss_ppe_verify_ifnum(ncm->interface));
208
209 /*
210 * Is this a valid request/response packet?
211 */
212 if (ncm->type >= NSS_PPE_MSG_MAX) {
Amit Gupta1263b082017-07-06 14:22:57 +0530213 nss_warning("%p: received invalid message %d for PPE interface\n", nss_ctx, ncm->type);
Amit Gupta316729b2016-08-12 12:21:15 +0530214 return;
215 }
216
217 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_ppe_msg)) {
Amit Gupta1263b082017-07-06 14:22:57 +0530218 nss_warning("%p: Length of message is greater than required: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
Amit Gupta316729b2016-08-12 12:21:15 +0530219 return;
220 }
221
222 switch (msg->cm.type) {
223 case NSS_PPE_MSG_SYNC_STATS:
224 /*
225 * session debug stats embeded in session stats msg
226 */
227 nss_ppe_stats_sync(nss_ctx, &msg->msg.stats, ncm->interface);
Amit Gupta1263b082017-07-06 14:22:57 +0530228 return;
Amit Gupta316729b2016-08-12 12:21:15 +0530229 }
Amit Gupta316729b2016-08-12 12:21:15 +0530230
Amit Gupta1263b082017-07-06 14:22:57 +0530231 /*
232 * Log failures
233 */
234 nss_core_log_msg_failures(nss_ctx, ncm);
235
236 /*
237 * Do we have a call back
238 */
239 if (!ncm->cb) {
240 return;
241 }
242
243 /*
244 * callback
245 */
246 cb = (nss_ppe_msg_callback_t)ncm->cb;
247 ctx = (void *)ncm->app_data;
248
249 cb(ctx, msg);
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700250}
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700251
252/*
Amit Gupta316729b2016-08-12 12:21:15 +0530253 * nss_ppe_register_handler()
254 * debugfs stats msg handler received on static ppe interface
255 *
256 * TODO: Export API so that others can also read PPE stats.
257 */
258void nss_ppe_register_handler(void)
259{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700260 struct nss_ctx_instance *nss_ctx = nss_ppe_get_context();
261
262 nss_core_register_handler(nss_ctx, NSS_PPE_INTERFACE, nss_ppe_handler, NULL);
Yu Huang8c107082017-07-24 14:58:26 -0700263
264 nss_ppe_stats_dentry_create();
Amit Gupta316729b2016-08-12 12:21:15 +0530265}
266
267/*
268 * nss_ppe_free()
269 * Uninitialize PPE base
270 */
271void nss_ppe_free(void)
272{
273 /*
274 * Check if PPE base is already uninitialized.
275 */
276 if (!ppe_pvt.ppe_base) {
277 return;
278 }
279
280 /*
281 * Unmap PPE base address
282 */
283 iounmap(ppe_pvt.ppe_base);
284 ppe_pvt.ppe_base = NULL;
285
286 spin_lock_bh(&nss_ppe_stats_lock);
287 nss_ppe_debug_stats.valid = false;
288 nss_ppe_debug_stats.if_num = 0;
289 nss_ppe_debug_stats.if_index = 0;
290 spin_unlock_bh(&nss_ppe_stats_lock);
291}
292
293/*
294 * nss_ppe_init()
295 * Initialize PPE base
296 */
297void nss_ppe_init(void)
298{
299 /*
300 * Check if PPE base is already initialized.
301 */
302 if (ppe_pvt.ppe_base) {
303 return;
304 }
305
306 /*
307 * Get the PPE base address
308 */
309 ppe_pvt.ppe_base = ioremap_nocache(PPE_BASE_ADDR, PPE_REG_SIZE);
310 if (!ppe_pvt.ppe_base) {
311 nss_warning("DRV can't get PPE base address\n");
312 return;
313 }
314
315 spin_lock_bh(&nss_ppe_stats_lock);
316 nss_ppe_debug_stats.valid = true;
317 nss_ppe_debug_stats.if_num = 0;
318 nss_ppe_debug_stats.if_index = 0;
319 spin_unlock_bh(&nss_ppe_stats_lock);
Amit Gupta1263b082017-07-06 14:22:57 +0530320
321 sema_init(&ppe_pvt.sem, 1);
322 init_completion(&ppe_pvt.complete);
Amit Gupta316729b2016-08-12 12:21:15 +0530323}