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