blob: 83061d7b91a2efdcb6a5ea14c18f8934047d6685 [file] [log] [blame]
Tushar Mathur66506542014-04-03 22:01:40 +05301/*
2 **************************************************************************
Stephen Wangaed46332016-12-12 17:29:03 -08003 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Tushar Mathur66506542014-04-03 22:01:40 +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/*
18 * nss_tx_rx_lag.c
19 * NSS LAG Tx APIs
20 */
21
22#include <linux/if_bonding.h>
23
24#include "nss_tx_rx_common.h"
25
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +053026#define NSS_LAG_RESP_TIMEOUT 60000 /* 60 Sec */
27
28/*
29 * Private data structure of dynamic interface
30 */
31struct nss_lag_pvt {
32 struct completion complete; /* completion structure */
33 enum nss_cmn_response response; /* Message response */
34};
35
36/*
37 * nss_lag_state_callback()
38 * Call back function for nss LAG State
39 */
40void nss_lag_state_callback(void *arg, struct nss_lag_msg *nm)
41{
42 struct nss_lag_pvt *lag_msg_state = arg;
43
44 /*
45 * Unblock the sleeping function.
46 */
47 lag_msg_state->response = nm->cm.response;
48 complete(&lag_msg_state->complete);
49}
50
51/*
52 * nss_lag_verify_ifnum()
53 *
54 */
55static void nss_lag_verify_ifnum(uint32_t if_num)
56{
57 nss_assert((if_num == NSS_LAG0_INTERFACE_NUM) ||
58 (if_num == NSS_LAG1_INTERFACE_NUM) ||
59 (if_num == NSS_LAG2_INTERFACE_NUM) ||
60 (if_num == NSS_LAG3_INTERFACE_NUM));
61}
62
63/*
64 * nss_lag_get_context()
65 */
66static struct nss_ctx_instance *nss_lag_get_context(void)
67{
68 uint8_t ipv4_handler_id = nss_top_main.ipv4_handler_id;
69
70 return (struct nss_ctx_instance *)&nss_top_main.nss[ipv4_handler_id];
71}
72
Tushar Mathur66506542014-04-03 22:01:40 +053073/*
74 * nss_lag_tx()
Sol Kavycd1bd5c2014-04-04 11:09:44 -070075 * Transmit a LAG msg to the firmware.
Tushar Mathur66506542014-04-03 22:01:40 +053076 */
77nss_tx_status_t nss_lag_tx(struct nss_ctx_instance *nss_ctx, struct nss_lag_msg *msg)
78{
79 struct sk_buff *nbuf;
80 int32_t status;
81 struct nss_lag_msg *nm;
82
83 nss_info("%p: NSS LAG Tx\n", nss_ctx);
84
85 NSS_VERIFY_CTX_MAGIC(nss_ctx);
86 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
Sol Kavycd1bd5c2014-04-04 11:09:44 -070087 nss_warning("%p: LAG msg dropped as core not ready", nss_ctx);
Tushar Mathur66506542014-04-03 22:01:40 +053088 return NSS_TX_FAILURE_NOT_READY;
89 }
90
Pamidipati, Vijayb6e38842014-09-16 10:26:05 +053091 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
Tushar Mathur66506542014-04-03 22:01:40 +053092 if (unlikely(!nbuf)) {
Sundarajan Srinivasan62fee7e2015-01-22 11:13:10 -080093 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
Sol Kavycd1bd5c2014-04-04 11:09:44 -070094 nss_warning("%p: LAG msg dropped as command allocation failed", nss_ctx);
Tushar Mathur66506542014-04-03 22:01:40 +053095 return NSS_TX_FAILURE;
96 }
97
98 nm = (struct nss_lag_msg *)skb_put(nbuf, sizeof(struct nss_lag_msg));
99 memcpy(nm, msg, sizeof(struct nss_lag_msg));
100
101 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
102 if (status != NSS_CORE_STATUS_SUCCESS) {
Pamidipati, Vijayb6e38842014-09-16 10:26:05 +0530103 dev_kfree_skb_any(nbuf);
Sol Kavycd1bd5c2014-04-04 11:09:44 -0700104 nss_warning("%p: Unable to enqueue LAG msg\n", nss_ctx);
105 return NSS_TX_FAILURE;
Tushar Mathur66506542014-04-03 22:01:40 +0530106 }
Stephen Wang90c67de2016-04-26 15:15:59 -0700107 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
Tushar Mathur66506542014-04-03 22:01:40 +0530108
109 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
110 return NSS_TX_SUCCESS;
111}
112EXPORT_SYMBOL(nss_lag_tx);
Tushar Mathura3e03052014-04-07 20:17:28 +0530113
114/**
115 * nss_register_lag_if()
116 */
Gareth Williamsb52af512014-04-25 19:31:15 +0100117void *nss_register_lag_if(uint32_t if_num,
Tushar Mathura3e03052014-04-07 20:17:28 +0530118 nss_lag_callback_t lag_cb,
119 nss_lag_event_callback_t lag_ev_cb,
120 struct net_device *netdev)
121{
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530122 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800123 uint32_t features = 0;
124
Stephen Wang84e0e992016-09-07 12:31:40 -0700125 nss_assert(nss_ctx);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530126 nss_lag_verify_ifnum(if_num);
Tushar Mathura3e03052014-04-07 20:17:28 +0530127
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700128 nss_core_register_subsys_dp(nss_ctx, if_num, lag_cb, NULL, NULL, netdev, features);
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800129
Tushar Mathura3e03052014-04-07 20:17:28 +0530130 nss_top_main.lag_event_callback = lag_ev_cb;
Gareth Williamsb52af512014-04-25 19:31:15 +0100131
132 /*
133 * Return the NSS driver context for LAG (same as for ipv4 functions)
134 */
Stephen Wang84e0e992016-09-07 12:31:40 -0700135 return (void *)nss_ctx;
Tushar Mathura3e03052014-04-07 20:17:28 +0530136}
137EXPORT_SYMBOL(nss_register_lag_if);
138
139
140/**
141 * nss_unregister_lag_if()
142 */
143void nss_unregister_lag_if(uint32_t if_num)
144{
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530145 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
Stephen Wang84e0e992016-09-07 12:31:40 -0700146
147 nss_assert(nss_ctx);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530148 nss_lag_verify_ifnum(if_num);
Tushar Mathura3e03052014-04-07 20:17:28 +0530149
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700150 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800151
Tushar Mathura3e03052014-04-07 20:17:28 +0530152 nss_top_main.lag_event_callback = NULL;
153}
154EXPORT_SYMBOL(nss_unregister_lag_if);
155
156
157/**
158 * nss_lag_handler()
159 */
160void nss_lag_handler(struct nss_ctx_instance *nss_ctx,
161 struct nss_cmn_msg *ncm,
162 void *app_data)
163{
164 struct nss_lag_msg *lm = (struct nss_lag_msg *)ncm;
165 void *ctx = NULL;
166 nss_lag_event_callback_t cb;
167
168 BUG_ON(ncm->interface != NSS_LAG0_INTERFACE_NUM
Suman Ghoshcf8ed1c2015-09-07 18:57:04 +0530169 && ncm->interface != NSS_LAG1_INTERFACE_NUM
170 && ncm->interface != NSS_LAG2_INTERFACE_NUM
171 && ncm->interface != NSS_LAG3_INTERFACE_NUM);
Tushar Mathura3e03052014-04-07 20:17:28 +0530172
173 if (ncm->type >= NSS_TX_METADATA_LAG_MAX) {
174 nss_warning("%p: received invalid message %d for LAG interface", nss_ctx, ncm->type);
175 return;
176 }
177
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800178 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_lag_msg)) {
179 nss_warning("%p: invalid length for LAG message: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
Tushar Mathura3e03052014-04-07 20:17:28 +0530180 return;
181 }
182
183 /**
184 * Update the callback and app_data for NOTIFY messages.
185 * LAG sends all notify messages to the same callback.
186 */
187 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
Stephen Wangaed46332016-12-12 17:29:03 -0800188 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->lag_event_callback;
Tushar Mathura3e03052014-04-07 20:17:28 +0530189 }
190
191 /**
192 * Log failures
193 */
194 nss_core_log_msg_failures(nss_ctx, ncm);
195
196 /**
197 * Do we have a call back
198 */
199 if (!ncm->cb) {
200 return;
201 }
202
203 /**
204 * callback
205 */
206 cb = (nss_lag_event_callback_t)ncm->cb;
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530207 ctx = (void *)ncm->app_data;
Tushar Mathura3e03052014-04-07 20:17:28 +0530208
209 cb(ctx, lm);
210}
211
212
213/**
214 * nss_lag_register_handler()
215 */
216void nss_lag_register_handler(void)
217{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700218 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
219
220 nss_core_register_handler(nss_ctx, NSS_LAG0_INTERFACE_NUM, nss_lag_handler, NULL);
221 nss_core_register_handler(nss_ctx, NSS_LAG1_INTERFACE_NUM, nss_lag_handler, NULL);
222 nss_core_register_handler(nss_ctx, NSS_LAG2_INTERFACE_NUM, nss_lag_handler, NULL);
223 nss_core_register_handler(nss_ctx, NSS_LAG3_INTERFACE_NUM, nss_lag_handler, NULL);
Tushar Mathura3e03052014-04-07 20:17:28 +0530224}
225
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700226/**
227 * nss_lag_msg_init()
228 * Initialize lag message
229 */
230void nss_lag_msg_init(struct nss_lag_msg *nlm, uint16_t lag_num, uint32_t type, uint32_t len,
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530231 nss_lag_msg_callback_t cb, void *app_data)
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700232{
233 nss_cmn_msg_init(&nlm->cm, lag_num, type, len, (void *)cb, app_data);
234}
235EXPORT_SYMBOL(nss_lag_msg_init);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530236
237/**
238 * nss_lag_tx_slave_state()
239 */
240nss_tx_status_t nss_lag_tx_slave_state(uint16_t lagid, int32_t slave_ifnum,
241 enum nss_lag_state_change_ev slave_state)
242{
243 struct nss_lag_msg nm;
244 struct nss_lag_state_change *nlsc = NULL;
245 nss_tx_status_t status;
246 int ret;
247 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
248 struct nss_lag_pvt lag_msg_state;
249
250 init_completion(&lag_msg_state.complete);
251 lag_msg_state.response = false;
252
253 /*
254 * Construct a message to the NSS to update it
255 */
256 nss_lag_msg_init(&nm, lagid,
257 NSS_TX_METADATA_LAG_STATE_CHANGE,
258 sizeof(struct nss_lag_state_change),
259 nss_lag_state_callback, &lag_msg_state);
260
261 nlsc = &nm.msg.state;
262 nlsc->event = slave_state;
263 nlsc->interface = slave_ifnum;
264
265 status = nss_lag_tx(nss_ctx, &nm);
266 if (status != NSS_TX_SUCCESS) {
267 nss_warning("%p: Send LAG update failed, status: %d\n", nss_ctx,
268 status);
269 return NSS_TX_FAILURE;
270 }
271
272 /*
273 * Blocking call, wait till we get ACK for this msg.
274 */
275 ret = wait_for_completion_timeout(&lag_msg_state.complete,
276 msecs_to_jiffies(NSS_LAG_RESP_TIMEOUT));
277 if (!ret) {
278 nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
279 return NSS_TX_FAILURE;
280 }
281
282 return lag_msg_state.response;
283}
284EXPORT_SYMBOL(nss_lag_tx_slave_state);