blob: fe051f9804520c4d727bd33122a683d2bbc1d466 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/******************************************************************************
2 *
3 * <:copyright-BRCM:2016:DUAL/GPL:standard
4 *
5 * Copyright (c) 2016 Broadcom
6 * All Rights Reserved
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed
10 * to you under the terms of the GNU General Public License version 2
11 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
12 * with the following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give
15 * you permission to link this software with independent modules, and
16 * to copy and distribute the resulting executable under terms of your
17 * choice, provided that you also meet, for each linked independent
18 * module, the terms and conditions of the license of that module.
19 * An independent module is a module which is not derived from this
20 * software. The special exception does not apply to any modifications
21 * of the software.
22 *
23 * Not withstanding the above, under no circumstances may you combine
24 * this software in any way with any other Broadcom software provided
25 * under a license other than the GPL, without Broadcom's express prior
26 * written consent.
27 *
28 * :>
29 *
30 *****************************************************************************/
31
32/**
33 * @file bal_oam_util.c
34 *
35 * @brief OAM util interfaces definition used by Bal Core
36 *
37 * This file expose the APIs to the core to configure ONU via EPON OAM
38 *
39 * @addtogroup oam_util
40 */
41
42/*@{*/
43
44#include "bal_oam_util.h"
45#include <bcmolt_user_appl_epon_oam.h>
46#include <bcmolt_eon.h>
47#include <bcmolt_eon_log.h>
48#include <bcmolt_epon_oam_types.h>
49
50#define BAL_OAM_TIMEOUT_US 1000000 /* 1 second */
51
52typedef enum
53{
54 BAL_OAM_STATE_IDLE,
55 BAL_OAM_STATE_SET_OAM_RATE,
56 BAL_OAM_STATE_CLEAR_INGRESS_RULES_NETWORK_PON,
57 BAL_OAM_STATE_CLEAR_INGRESS_RULES_USER_PORT,
58 BAL_OAM_STATE_SET_BASIC_QUEUE_CONFIG,
59 BAL_OAM_STATE_ADD_INGRESS_RULES_NETWORK_PON,
60 BAL_OAM_STATE_ADD_INGRESS_RULES_USER_PORT,
61 BAL_OAM_STATE_SET_REPORT_THRESHOLDS,
62 BAL_OAM_STATE_ENABLE_USER_TRAFFIC,
63 BAL_OAM_STATE_DISABLE_USER_TRAFFIC,
64 BAL_OAM_STATE__NUM_OF,
65} bal_oam_state;
66
67typedef enum
68{
69 BAL_OAM_EVENT_ACK,
70 BAL_OAM_EVENT_TIMEOUT,
71 BAL_OAM_EVENT__NUM_OF,
72} bal_oam_event;
73
74typedef struct bal_oam_context
75{
76 TAILQ_ENTRY(bal_oam_context) next;
77 bal_oam_cb cb;
78 void *context;
79 bcmolt_devid device_id;
80 bcmolt_epon_ni epon_ni;
81 bcmos_mac_address mac;
82 bcmos_timer timer;
83 bal_oam_state state;
84} bal_oam_context;
85
86typedef struct
87{
88 bcmos_msg m;
89 bcmolt_devid device_id;
90 bcmolt_epon_ni epon_ni;
91 bcmos_mac_address mac;
92} bal_oam_timeout_msg;
93
94typedef bcmos_errno (*bal_oam_sm_cb)(bal_oam_context *context);
95
96static TAILQ_HEAD(, bal_oam_context) bal_oam_contexts = TAILQ_HEAD_INITIALIZER(bal_oam_contexts);
97
98static bal_oam_context *bal_oam_get_context(bcmolt_devid device_id, bcmolt_epon_ni epon_ni, const bcmos_mac_address *mac)
99{
100 bal_oam_context *iter;
101
102 TAILQ_FOREACH(iter, &bal_oam_contexts, next)
103 {
104 if (device_id == iter->device_id && epon_ni == iter->epon_ni && !memcmp(mac, &iter->mac, sizeof(*mac)))
105 break;
106 }
107 return iter;
108}
109
110static void bal_oam_negotiation_result_cb(void *context, const eon_link_key_t *link_key, bcmos_errno result)
111{
112 bal_oam_context *_context = context;
113
114 _context->cb(_context->context, _context->device_id, _context->epon_ni, &_context->mac, result);
115
116 bcmos_free(_context);
117}
118
119bcmos_errno bal_oam_start_oam_negotiation(bcmolt_devid device_id, bcmolt_epon_ni epon_ni, bcmos_mac_address *mac, bal_oam_cb cb, void *context)
120{
121 eon_link_key_t link_key = {};
122 bal_oam_context *_context;
123
124 link_key.device_id = device_id;
125 link_key.epon_ni = epon_ni;
126 link_key.mac_address = *mac;
127
128 _context = bcmos_calloc(sizeof(*_context));
129 _context->cb = cb;
130 _context->context = context;
131 _context->device_id = device_id;
132 _context->epon_ni = epon_ni;
133 _context->mac = *mac;
134
135 return bcmolt_user_appl_eon_start(&link_key, eon_oam_set_id_dpoe, bal_oam_negotiation_result_cb, _context, BCMOS_TRUE);
136}
137
138static void bal_oam_configure_traffic_complete(bal_oam_context *context, bcmos_errno result)
139{
140 context->cb(context->context, context->device_id, context->epon_ni, &context->mac, result);
141
142 bcmos_timer_destroy(&context->timer);
143
144 TAILQ_REMOVE(&bal_oam_contexts, context, next);
145
146 /* No need to set context->state to BAL_OAM_STATE_IDLE - it is going to be destroyed here anyway. */
147 bcmos_free(context);
148}
149
150static void bal_oam_timeout_msg_cb(bcmos_module_id module_id, bcmos_msg *msg)
151{
152 bal_oam_timeout_msg *timeout_msg = (bal_oam_timeout_msg *)msg;
153 bal_oam_context *context = bal_oam_get_context(timeout_msg->device_id, timeout_msg->epon_ni, &timeout_msg->mac);
154
155 bal_oam_configure_traffic_complete(context, BCM_ERR_TIMEOUT);
156
157 bcmos_msg_free(msg);
158}
159
160static bcmos_errno bal_oam_state_any_event_timeout(bal_oam_context *context)
161{
162 bal_oam_timeout_msg *msg;
163
164 /* We should not directly call bal_oam_configure_traffic_complete() from within timer context, because in bal_oam_configure_traffic_complete() we free the memory in which the timer
165 * resides. To overcome this, we use a message - the timer will finish executing and only then the message handler will execute. */
166 msg = bcmos_calloc(sizeof(*msg));
167 msg->device_id = context->device_id;
168 msg->epon_ni = context->epon_ni;
169 msg->mac = context->mac;
170 msg->m.handler = bal_oam_timeout_msg_cb;
171 bcmos_msg_send_to_module(BCMOS_MODULE_ID_WORKER_MGMT, &msg->m, 0);
172
173 return BCM_ERR_OK;
174}
175
176static bcmos_errno bal_oam_state_set_oam_rate_event_ack(bal_oam_context *context)
177{
178 bcmos_errno rc;
179
180 /* Clear EPON port ingress. */
181 rc = epon_oam_dpoe_clear_ingress_rules_network_pon(context->device_id, context->epon_ni, &context->mac);
182 if (rc != BCM_ERR_OK)
183 {
184 bal_oam_configure_traffic_complete(context, rc);
185 return rc;
186 }
187
188 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
189
190 context->state = BAL_OAM_STATE_CLEAR_INGRESS_RULES_NETWORK_PON;
191
192 return BCM_ERR_OK;
193}
194
195static bcmos_errno bal_oam_state_clear_ingress_rules_network_pon_event_ack(bal_oam_context *context)
196{
197 bcmos_errno rc;
198
199 /* Clear UNI port ingress rules. */
200 rc = epon_oam_dpoe_clear_ingress_rules_user_port(context->device_id, context->epon_ni, &context->mac);
201 if (rc != BCM_ERR_OK)
202 {
203 bal_oam_configure_traffic_complete(context, rc);
204 return rc;
205 }
206
207 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
208
209 context->state = BAL_OAM_STATE_CLEAR_INGRESS_RULES_USER_PORT;
210
211 return BCM_ERR_OK;
212}
213
214static bcmos_errno bal_oam_state_clear_ingress_rules_user_port_event_ack(bal_oam_context *context)
215{
216 bcmos_errno rc;
217
218 /* Set ONU queue configuration. */
219 rc = epon_oam_dpoe_set_basic_queue_config(context->device_id, context->epon_ni, &context->mac, 255, 255);
220 if (rc != BCM_ERR_OK)
221 {
222 bal_oam_configure_traffic_complete(context, rc);
223 return rc;
224 }
225
226 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
227
228 context->state = BAL_OAM_STATE_SET_BASIC_QUEUE_CONFIG;
229
230 return BCM_ERR_OK;
231}
232
233static bcmos_errno bal_oam_state_set_basic_queue_config_event_ack(bal_oam_context *context)
234{
235 bcmos_errno rc;
236
237 /* Add EPON port ingress rules */
238 rc = epon_oam_dpoe_add_ingress_rules_network_pon(context->device_id, context->epon_ni, &context->mac, DPOE_RULE_VLAN_MODE_NONE, NULL);
239 if (rc != BCM_ERR_OK)
240 {
241 bal_oam_configure_traffic_complete(context, rc);
242 return rc;
243 }
244
245 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
246
247 context->state = BAL_OAM_STATE_ADD_INGRESS_RULES_NETWORK_PON;
248
249 return BCM_ERR_OK;
250}
251
252static bcmos_errno bal_oam_state_add_ingress_rules_network_pon_event_ack(bal_oam_context *context)
253{
254 bcmos_errno rc;
255
256 /* Add UNI port ingress rules. */
257 rc = epon_oam_dpoe_add_ingress_rules_user_port(context->device_id, context->epon_ni, &context->mac, DPOE_RULE_VLAN_MODE_NONE, NULL);
258 if (rc != BCM_ERR_OK)
259 {
260 bal_oam_configure_traffic_complete(context, rc);
261 return rc;
262 }
263
264 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
265
266 context->state = BAL_OAM_STATE_ADD_INGRESS_RULES_USER_PORT;
267
268 return BCM_ERR_OK;
269}
270
271static bcmos_errno bal_oam_state_add_ingress_rules_user_port_event_ack(bal_oam_context *context)
272{
273 bcmos_errno rc;
274 bcmolt_epon_oam_queue_sets queue_sets =
275 {
276 [0] = {16256},
277 [1] = {32512},
278 [2] = {48768},
279 [3] = {65024},
280 };
281
282 /* Set ONU report thresholds. */
283 rc = epon_oam_dpoe_set_report_thresholds(context->device_id, context->epon_ni, &context->mac, 1, queue_sets, 4);
284 if (rc != BCM_ERR_OK)
285 {
286 bal_oam_configure_traffic_complete(context, rc);
287 return rc;
288 }
289
290 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
291
292 context->state = BAL_OAM_STATE_SET_REPORT_THRESHOLDS;
293
294 return BCM_ERR_OK;
295}
296
297static bcmos_errno bal_oam_state_set_report_thresholds_event_ack(bal_oam_context *context)
298{
299 bcmos_errno rc;
300
301 /* Enable user traffic. */
302 rc = epon_oam_dpoe_enable_user_traffic(context->device_id, context->epon_ni, &context->mac);
303 if (rc != BCM_ERR_OK)
304 {
305 bal_oam_configure_traffic_complete(context, rc);
306 return rc;
307 }
308
309 bcmos_timer_start(&context->timer, BAL_OAM_TIMEOUT_US);
310
311 context->state = BAL_OAM_STATE_ENABLE_USER_TRAFFIC;
312
313 return BCM_ERR_OK;
314}
315
316static bcmos_errno bal_oam_state_enable_user_traffic_event_ack(bal_oam_context *context)
317{
318 bal_oam_configure_traffic_complete(context, BCM_ERR_OK);
319
320 return BCM_ERR_OK;
321}
322
323static bcmos_errno bal_oam_state_disable_user_traffic_event_ack(bal_oam_context *context)
324{
325 bal_oam_configure_traffic_complete(context, BCM_ERR_OK);
326
327 return BCM_ERR_OK;
328}
329
330static bal_oam_sm_cb bal_oam_state_machine[BAL_OAM_STATE__NUM_OF][BAL_OAM_EVENT__NUM_OF] =
331{
332 [BAL_OAM_STATE_SET_OAM_RATE] =
333 {
334 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
335 [BAL_OAM_EVENT_ACK] = bal_oam_state_set_oam_rate_event_ack,
336 },
337 [BAL_OAM_STATE_CLEAR_INGRESS_RULES_NETWORK_PON] =
338 {
339 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
340 [BAL_OAM_EVENT_ACK] = bal_oam_state_clear_ingress_rules_network_pon_event_ack,
341 },
342 [BAL_OAM_STATE_CLEAR_INGRESS_RULES_USER_PORT] =
343 {
344 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
345 [BAL_OAM_EVENT_ACK] = bal_oam_state_clear_ingress_rules_user_port_event_ack,
346 },
347 [BAL_OAM_STATE_SET_BASIC_QUEUE_CONFIG] =
348 {
349 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
350 [BAL_OAM_EVENT_ACK] = bal_oam_state_set_basic_queue_config_event_ack,
351 },
352 [BAL_OAM_STATE_ADD_INGRESS_RULES_NETWORK_PON] =
353 {
354 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
355 [BAL_OAM_EVENT_ACK] = bal_oam_state_add_ingress_rules_network_pon_event_ack,
356 },
357 [BAL_OAM_STATE_ADD_INGRESS_RULES_USER_PORT] =
358 {
359 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
360 [BAL_OAM_EVENT_ACK] = bal_oam_state_add_ingress_rules_user_port_event_ack,
361 },
362 [BAL_OAM_STATE_SET_REPORT_THRESHOLDS] =
363 {
364 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
365 [BAL_OAM_EVENT_ACK] = bal_oam_state_set_report_thresholds_event_ack,
366 },
367 [BAL_OAM_STATE_ENABLE_USER_TRAFFIC] =
368 {
369 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
370 [BAL_OAM_EVENT_ACK] = bal_oam_state_enable_user_traffic_event_ack,
371 },
372 [BAL_OAM_STATE_DISABLE_USER_TRAFFIC] =
373 {
374 [BAL_OAM_EVENT_TIMEOUT] = bal_oam_state_any_event_timeout,
375 [BAL_OAM_EVENT_ACK] = bal_oam_state_disable_user_traffic_event_ack,
376 },
377};
378
379static void bal_oam_sm_run(bal_oam_context *context, bal_oam_event event)
380{
381 bal_oam_sm_cb cb = bal_oam_state_machine[context->state][event];
382
383 cb(context);
384}
385
386static bcmos_timer_rc bal_oam_timeout_cb(bcmos_timer *timer, long data)
387{
388 bal_oam_context *context = (bal_oam_context *)data;
389
390 bal_oam_sm_run(context, BAL_OAM_EVENT_TIMEOUT);
391
392 return BCMOS_TIMER_OK;
393}
394
395bcmos_errno bal_oam_configure_traffic(bcmolt_devid device_id, bcmolt_epon_ni epon_ni, bcmos_mac_address *mac, bcmos_bool is_enabled, bal_oam_cb cb, void *context)
396{
397 bcmos_errno rc;
398 bal_oam_context *_context;
399 bcmos_timer_parm timer_params =
400 {
401 .name = "bal_oam_timer",
402 .owner = BCMOS_MODULE_ID_WORKER_MGMT,
403 .handler = bal_oam_timeout_cb,
404 };
405
406 _context = bcmos_calloc(sizeof(*_context));
407 _context->cb = cb;
408 _context->context = context;
409 _context->device_id = device_id;
410 _context->epon_ni = epon_ni;
411 _context->mac = *mac;
412 TAILQ_INSERT_TAIL(&bal_oam_contexts, _context, next);
413
414 if (is_enabled)
415 {
416 /* Set OAM rate. */
417 rc = epon_oam_dpoe_set_oam_rate(device_id, epon_ni, mac, 10, 3);
418 }
419 else
420 {
421 /* Disable user traffic. */
422 rc = epon_oam_dpoe_disable_user_traffic(device_id, epon_ni, mac);
423 }
424 if (rc != BCM_ERR_OK)
425 {
426 bal_oam_configure_traffic_complete(_context, rc);
427 return rc;
428 }
429
430 timer_params.data = (long)_context;
431 bcmos_timer_create(&_context->timer, &timer_params);
432 bcmos_timer_start(&_context->timer, BAL_OAM_TIMEOUT_US);
433
434 if (is_enabled)
435 _context->state = BAL_OAM_STATE_SET_OAM_RATE;
436 else
437 _context->state = BAL_OAM_STATE_DISABLE_USER_TRAFFIC;
438
439 return BCM_ERR_OK;
440}
441
442/* TODO: Currently we ignore rc. But we may want to check it. */
443void bal_oam_proxy_rx_cb(bcmolt_devid device_id, bcmolt_epon_ni epon_ni, const bcmos_mac_address *mac, bcmolt_user_appl_epon_oam_rx_id id, bcmos_errno rc)
444{
445 bal_oam_context *context;
446
447 if (id != BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_SET_RESPONSE)
448 return;
449
450 /* If applying set command not from within bal_oam_configure_traffic() (for example, from BAL CLI), context might be NULL. */
451 context = bal_oam_get_context(device_id, epon_ni, mac);
452 if (!context)
453 return;
454
455 bal_oam_sm_run(context, BAL_OAM_EVENT_ACK);
456}
457
458/*@}*/
459