blob: b1bdd150be01fe2f4603b660fcc143fe6bd431aa [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
Stephen Wang84e0e992016-09-07 12:31:40 -0700128 nss_ctx->subsys_dp_register[if_num].ndev = netdev;
129 nss_ctx->subsys_dp_register[if_num].cb = lag_cb;
130 nss_ctx->subsys_dp_register[if_num].app_data = NULL;
131 nss_ctx->subsys_dp_register[if_num].features = features;
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800132
Tushar Mathura3e03052014-04-07 20:17:28 +0530133 nss_top_main.lag_event_callback = lag_ev_cb;
Gareth Williamsb52af512014-04-25 19:31:15 +0100134
135 /*
136 * Return the NSS driver context for LAG (same as for ipv4 functions)
137 */
Stephen Wang84e0e992016-09-07 12:31:40 -0700138 return (void *)nss_ctx;
Tushar Mathura3e03052014-04-07 20:17:28 +0530139}
140EXPORT_SYMBOL(nss_register_lag_if);
141
142
143/**
144 * nss_unregister_lag_if()
145 */
146void nss_unregister_lag_if(uint32_t if_num)
147{
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530148 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
Stephen Wang84e0e992016-09-07 12:31:40 -0700149
150 nss_assert(nss_ctx);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530151 nss_lag_verify_ifnum(if_num);
Tushar Mathura3e03052014-04-07 20:17:28 +0530152
Stephen Wang84e0e992016-09-07 12:31:40 -0700153 nss_ctx->subsys_dp_register[if_num].cb = NULL;
154 nss_ctx->subsys_dp_register[if_num].ndev = NULL;
155 nss_ctx->subsys_dp_register[if_num].app_data = NULL;
156 nss_ctx->subsys_dp_register[if_num].features = 0;
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800157
Tushar Mathura3e03052014-04-07 20:17:28 +0530158 nss_top_main.lag_event_callback = NULL;
159}
160EXPORT_SYMBOL(nss_unregister_lag_if);
161
162
163/**
164 * nss_lag_handler()
165 */
166void nss_lag_handler(struct nss_ctx_instance *nss_ctx,
167 struct nss_cmn_msg *ncm,
168 void *app_data)
169{
170 struct nss_lag_msg *lm = (struct nss_lag_msg *)ncm;
171 void *ctx = NULL;
172 nss_lag_event_callback_t cb;
173
174 BUG_ON(ncm->interface != NSS_LAG0_INTERFACE_NUM
Suman Ghoshcf8ed1c2015-09-07 18:57:04 +0530175 && ncm->interface != NSS_LAG1_INTERFACE_NUM
176 && ncm->interface != NSS_LAG2_INTERFACE_NUM
177 && ncm->interface != NSS_LAG3_INTERFACE_NUM);
Tushar Mathura3e03052014-04-07 20:17:28 +0530178
179 if (ncm->type >= NSS_TX_METADATA_LAG_MAX) {
180 nss_warning("%p: received invalid message %d for LAG interface", nss_ctx, ncm->type);
181 return;
182 }
183
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800184 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_lag_msg)) {
185 nss_warning("%p: invalid length for LAG message: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
Tushar Mathura3e03052014-04-07 20:17:28 +0530186 return;
187 }
188
189 /**
190 * Update the callback and app_data for NOTIFY messages.
191 * LAG sends all notify messages to the same callback.
192 */
193 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
Stephen Wangaed46332016-12-12 17:29:03 -0800194 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->lag_event_callback;
Tushar Mathura3e03052014-04-07 20:17:28 +0530195 }
196
197 /**
198 * Log failures
199 */
200 nss_core_log_msg_failures(nss_ctx, ncm);
201
202 /**
203 * Do we have a call back
204 */
205 if (!ncm->cb) {
206 return;
207 }
208
209 /**
210 * callback
211 */
212 cb = (nss_lag_event_callback_t)ncm->cb;
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530213 ctx = (void *)ncm->app_data;
Tushar Mathura3e03052014-04-07 20:17:28 +0530214
215 cb(ctx, lm);
216}
217
218
219/**
220 * nss_lag_register_handler()
221 */
222void nss_lag_register_handler(void)
223{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700224 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
225
226 nss_core_register_handler(nss_ctx, NSS_LAG0_INTERFACE_NUM, nss_lag_handler, NULL);
227 nss_core_register_handler(nss_ctx, NSS_LAG1_INTERFACE_NUM, nss_lag_handler, NULL);
228 nss_core_register_handler(nss_ctx, NSS_LAG2_INTERFACE_NUM, nss_lag_handler, NULL);
229 nss_core_register_handler(nss_ctx, NSS_LAG3_INTERFACE_NUM, nss_lag_handler, NULL);
Tushar Mathura3e03052014-04-07 20:17:28 +0530230}
231
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700232/**
233 * nss_lag_msg_init()
234 * Initialize lag message
235 */
236void 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 +0530237 nss_lag_msg_callback_t cb, void *app_data)
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700238{
239 nss_cmn_msg_init(&nlm->cm, lag_num, type, len, (void *)cb, app_data);
240}
241EXPORT_SYMBOL(nss_lag_msg_init);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530242
243/**
244 * nss_lag_tx_slave_state()
245 */
246nss_tx_status_t nss_lag_tx_slave_state(uint16_t lagid, int32_t slave_ifnum,
247 enum nss_lag_state_change_ev slave_state)
248{
249 struct nss_lag_msg nm;
250 struct nss_lag_state_change *nlsc = NULL;
251 nss_tx_status_t status;
252 int ret;
253 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
254 struct nss_lag_pvt lag_msg_state;
255
256 init_completion(&lag_msg_state.complete);
257 lag_msg_state.response = false;
258
259 /*
260 * Construct a message to the NSS to update it
261 */
262 nss_lag_msg_init(&nm, lagid,
263 NSS_TX_METADATA_LAG_STATE_CHANGE,
264 sizeof(struct nss_lag_state_change),
265 nss_lag_state_callback, &lag_msg_state);
266
267 nlsc = &nm.msg.state;
268 nlsc->event = slave_state;
269 nlsc->interface = slave_ifnum;
270
271 status = nss_lag_tx(nss_ctx, &nm);
272 if (status != NSS_TX_SUCCESS) {
273 nss_warning("%p: Send LAG update failed, status: %d\n", nss_ctx,
274 status);
275 return NSS_TX_FAILURE;
276 }
277
278 /*
279 * Blocking call, wait till we get ACK for this msg.
280 */
281 ret = wait_for_completion_timeout(&lag_msg_state.complete,
282 msecs_to_jiffies(NSS_LAG_RESP_TIMEOUT));
283 if (!ret) {
284 nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
285 return NSS_TX_FAILURE;
286 }
287
288 return lag_msg_state.response;
289}
290EXPORT_SYMBOL(nss_lag_tx_slave_state);
291