blob: 23aa0daf8d60231a526bd2e63c4e6488f6755a72 [file] [log] [blame]
Tushar Mathur66506542014-04-03 22:01:40 +05301/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2014-2018, 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{
Stephen Wang3e2dbd12018-03-14 17:28:17 -070079 struct nss_cmn_msg *ncm = &msg->cm;
Tushar Mathur66506542014-04-03 22:01:40 +053080
Stephen Wang3e2dbd12018-03-14 17:28:17 -070081 /*
82 * Sanity check the message
83 */
84 nss_lag_verify_ifnum(ncm->interface);
Tushar Mathur66506542014-04-03 22:01:40 +053085
Stephen Wang3e2dbd12018-03-14 17:28:17 -070086 if (ncm->type > NSS_TX_METADATA_LAG_MAX) {
87 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
Tushar Mathur66506542014-04-03 22:01:40 +053088 return NSS_TX_FAILURE;
89 }
90
Stephen Wang3e2dbd12018-03-14 17:28:17 -070091 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Tushar Mathur66506542014-04-03 22:01:40 +053092}
93EXPORT_SYMBOL(nss_lag_tx);
Tushar Mathura3e03052014-04-07 20:17:28 +053094
95/**
96 * nss_register_lag_if()
97 */
Gareth Williamsb52af512014-04-25 19:31:15 +010098void *nss_register_lag_if(uint32_t if_num,
Tushar Mathura3e03052014-04-07 20:17:28 +053099 nss_lag_callback_t lag_cb,
100 nss_lag_event_callback_t lag_ev_cb,
101 struct net_device *netdev)
102{
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530103 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800104 uint32_t features = 0;
105
Stephen Wang84e0e992016-09-07 12:31:40 -0700106 nss_assert(nss_ctx);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530107 nss_lag_verify_ifnum(if_num);
Tushar Mathura3e03052014-04-07 20:17:28 +0530108
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700109 nss_core_register_subsys_dp(nss_ctx, if_num, lag_cb, NULL, NULL, netdev, features);
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800110
Tushar Mathura3e03052014-04-07 20:17:28 +0530111 nss_top_main.lag_event_callback = lag_ev_cb;
Gareth Williamsb52af512014-04-25 19:31:15 +0100112
113 /*
114 * Return the NSS driver context for LAG (same as for ipv4 functions)
115 */
Stephen Wang84e0e992016-09-07 12:31:40 -0700116 return (void *)nss_ctx;
Tushar Mathura3e03052014-04-07 20:17:28 +0530117}
118EXPORT_SYMBOL(nss_register_lag_if);
119
120
121/**
122 * nss_unregister_lag_if()
123 */
124void nss_unregister_lag_if(uint32_t if_num)
125{
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530126 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
Stephen Wang84e0e992016-09-07 12:31:40 -0700127
128 nss_assert(nss_ctx);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530129 nss_lag_verify_ifnum(if_num);
Tushar Mathura3e03052014-04-07 20:17:28 +0530130
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700131 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800132
Tushar Mathura3e03052014-04-07 20:17:28 +0530133 nss_top_main.lag_event_callback = NULL;
134}
135EXPORT_SYMBOL(nss_unregister_lag_if);
136
137
138/**
139 * nss_lag_handler()
140 */
141void nss_lag_handler(struct nss_ctx_instance *nss_ctx,
142 struct nss_cmn_msg *ncm,
143 void *app_data)
144{
145 struct nss_lag_msg *lm = (struct nss_lag_msg *)ncm;
146 void *ctx = NULL;
147 nss_lag_event_callback_t cb;
148
149 BUG_ON(ncm->interface != NSS_LAG0_INTERFACE_NUM
Suman Ghoshcf8ed1c2015-09-07 18:57:04 +0530150 && ncm->interface != NSS_LAG1_INTERFACE_NUM
151 && ncm->interface != NSS_LAG2_INTERFACE_NUM
152 && ncm->interface != NSS_LAG3_INTERFACE_NUM);
Tushar Mathura3e03052014-04-07 20:17:28 +0530153
154 if (ncm->type >= NSS_TX_METADATA_LAG_MAX) {
155 nss_warning("%p: received invalid message %d for LAG interface", nss_ctx, ncm->type);
156 return;
157 }
158
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800159 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_lag_msg)) {
160 nss_warning("%p: invalid length for LAG message: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
Tushar Mathura3e03052014-04-07 20:17:28 +0530161 return;
162 }
163
164 /**
165 * Update the callback and app_data for NOTIFY messages.
166 * LAG sends all notify messages to the same callback.
167 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +0530168 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Stephen Wangaed46332016-12-12 17:29:03 -0800169 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->lag_event_callback;
Tushar Mathura3e03052014-04-07 20:17:28 +0530170 }
171
172 /**
173 * Log failures
174 */
175 nss_core_log_msg_failures(nss_ctx, ncm);
176
177 /**
178 * Do we have a call back
179 */
180 if (!ncm->cb) {
181 return;
182 }
183
184 /**
185 * callback
186 */
187 cb = (nss_lag_event_callback_t)ncm->cb;
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530188 ctx = (void *)ncm->app_data;
Tushar Mathura3e03052014-04-07 20:17:28 +0530189
190 cb(ctx, lm);
191}
192
193
194/**
195 * nss_lag_register_handler()
196 */
197void nss_lag_register_handler(void)
198{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700199 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
200
201 nss_core_register_handler(nss_ctx, NSS_LAG0_INTERFACE_NUM, nss_lag_handler, NULL);
202 nss_core_register_handler(nss_ctx, NSS_LAG1_INTERFACE_NUM, nss_lag_handler, NULL);
203 nss_core_register_handler(nss_ctx, NSS_LAG2_INTERFACE_NUM, nss_lag_handler, NULL);
204 nss_core_register_handler(nss_ctx, NSS_LAG3_INTERFACE_NUM, nss_lag_handler, NULL);
Tushar Mathura3e03052014-04-07 20:17:28 +0530205}
206
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700207/**
208 * nss_lag_msg_init()
209 * Initialize lag message
210 */
211void 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 +0530212 nss_lag_msg_callback_t cb, void *app_data)
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700213{
214 nss_cmn_msg_init(&nlm->cm, lag_num, type, len, (void *)cb, app_data);
215}
216EXPORT_SYMBOL(nss_lag_msg_init);
Bhaskar Valaboju76988ef2017-02-20 19:51:49 +0530217
218/**
219 * nss_lag_tx_slave_state()
220 */
221nss_tx_status_t nss_lag_tx_slave_state(uint16_t lagid, int32_t slave_ifnum,
222 enum nss_lag_state_change_ev slave_state)
223{
224 struct nss_lag_msg nm;
225 struct nss_lag_state_change *nlsc = NULL;
226 nss_tx_status_t status;
227 int ret;
228 struct nss_ctx_instance *nss_ctx = nss_lag_get_context();
229 struct nss_lag_pvt lag_msg_state;
230
231 init_completion(&lag_msg_state.complete);
232 lag_msg_state.response = false;
233
234 /*
235 * Construct a message to the NSS to update it
236 */
237 nss_lag_msg_init(&nm, lagid,
238 NSS_TX_METADATA_LAG_STATE_CHANGE,
239 sizeof(struct nss_lag_state_change),
240 nss_lag_state_callback, &lag_msg_state);
241
242 nlsc = &nm.msg.state;
243 nlsc->event = slave_state;
244 nlsc->interface = slave_ifnum;
245
246 status = nss_lag_tx(nss_ctx, &nm);
247 if (status != NSS_TX_SUCCESS) {
248 nss_warning("%p: Send LAG update failed, status: %d\n", nss_ctx,
249 status);
250 return NSS_TX_FAILURE;
251 }
252
253 /*
254 * Blocking call, wait till we get ACK for this msg.
255 */
256 ret = wait_for_completion_timeout(&lag_msg_state.complete,
257 msecs_to_jiffies(NSS_LAG_RESP_TIMEOUT));
258 if (!ret) {
259 nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
260 return NSS_TX_FAILURE;
261 }
262
263 return lag_msg_state.response;
264}
265EXPORT_SYMBOL(nss_lag_tx_slave_state);