blob: b73e65088724dc19127471fb007ca0a68d46a3a1 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30/*
31 * bcmtr_mux.c
32 *
33 * Transport Multiplexer
34 * - PCIe/in-band channel multiplexer
35 * - locally/remotely - terminated message multiplexer
36 * - autonomous messages de-multiplexer
37 */
38#include <bcmos_system.h>
39#include <bcmolt_msg.h>
40#include <bcmolt_buf.h>
41#include <bcmolt_msg_pack.h>
42#include <bcmtr_header.h>
43#include <bcmolt_tr_mux.h>
44#ifdef IN_BAND
45#include <bcmtr_inband.h>
46#else
47#include <bcmtr_pcie.h>
48#include <bcmolt_llpcie.h>
49#include <bcmolt_fld.h>
50#include <bcm_fld_common.h>
51#include <bcmtr_pcie_sw_queue.h>
52#endif
53#include <bcmolt_api.h>
54#include <bcmolt_model_types.h>
55#include <bcmolt_model_ids.h>
56
57#define BCMTRMUX_MAX_TX_DELAY 500 /* max transmit delay (us) */
58#define BCMTRMUX_MAX_RX_DELAY 5000 /* max receive delay (us) */
59
60#ifdef __KERNEL__
61#define BCMTRMUX_LOG printk
62#else
63#define BCMTRMUX_LOG BCMOS_TRACE_INFO
64#endif
65
66/* Channel registration info */
67typedef struct
68{
69 f_bcmtr_rx_handler rx;
70 void *data;
71} bcmtrmux_rx_info;
72
73typedef struct
74{
75 f_bcmtr_local_rx_handler rx;
76 void *data;
77} bcmtrmux_local_rx_info;
78
79/* Registration arrays */
80static bcmtrmux_rx_info bcmtrmux_rx_info_array[BCMTR_MAX_OLTS][BCMTRMUX_MAX_CHANNELS];
81static bcmtrmux_local_rx_info bcmtrmux_local_rx_info_array[BCMTR_MAX_OLTS];
82static bcmtrmux_channel bcmtrmux_auto_channels[BCMTR_MAX_OLTS][BCMTR_MAX_INSTANCES][BCMOLT_OBJ_ID__NUM_OF];
83static bcmtrmux_channel bcmtrmux_proxy_channels[BCMTR_MAX_OLTS][BCMTR_MAX_INSTANCES][BCMOLT_OBJ_ID__NUM_OF];
84static bcmos_bool bcmtr_mux_connected[BCMTR_MAX_OLTS];
85static bcmos_bool bcmtr_mux_terminated[BCMTR_MAX_OLTS];
86static bcmos_bool bcmtrmux_dev_ctrl_intercept[BCMTR_MAX_OLTS][BCMOLT_GROUP_ID__NUM_OF];
87
88#ifndef IN_BAND
89
90/* Number of registered high-priority channels */
91static bcmtrmux_channel num_urgent_channels[BCMTR_MAX_OLTS];
92
93/* Receive semaphore */
94static bcmos_sem bcmtrmux_rx_lock[BCMTR_MAX_OLTS];
95
96#endif
97
98/* Statistics */
99static bcmtrmux_stat bcmtrmux_stat_array[BCMTR_MAX_OLTS];
100
101/* Receive tasks */
102static bcmos_task bcmtrmux_rx_task[BCMTR_MAX_OLTS];
103
104/* Registration protection */
105static bcmos_fastlock bcmtrmux_lock;
106
107static void bcmtrmux_rx_auto_proxy(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data);
108static void bcmtrmux_rx_local(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data);
109
110static bcmtrmux_msg_filter_cb_t bcmtrmux_msg_filter_cb;
111
112/* discard packet for which there is no registration */
113static void bcmtrmux_rx_discard(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data)
114{
115 uint32_t *counter = (uint32_t *)data;
116 ++(*counter);
117 bcmos_buf_free(buf);
118}
119
120/* discard unpacked message for which there is no registration */
121static void bcmtrmux_local_rx_discard(bcmolt_devid device, bcmolt_msg *msg, void *data)
122{
123 uint32_t *counter = (uint32_t *)data;
124 ++(*counter);
125 bcmolt_msg_free(msg);
126}
127
128/* Find free channel. returns channel id >= 0 or BCMTRMUX_MAX_CHANNELS if no free channels */
129static int bcmtrmux_channel_get_free(bcmolt_devid device)
130{
131 int i;
132 /* Start from BCMTRMUX_CHANNEL_FIRST_FREE. Channel 0 is reserved for indications/proxy , Channel 1 is for Keep Alive*/
133 for (i=BCMTRMUX_CHANNEL_FIRST_FREE; i<BCMTRMUX_FIRST_URGENT_CHANNEL; i++)
134 {
135 if (bcmtrmux_rx_info_array[device][i].rx == bcmtrmux_rx_discard)
136 break;
137 }
138 return i;
139}
140
141#ifndef IN_BAND
142/* PCIe Receive handler */
143static int _bcmtrmux_pcie_rx_handler(long device)
144{
145 bcmos_errno rc;
146 bcmos_buf *buf;
147 uint32_t nbuf[BCMTR_PCIE_PRTY__NUM_OF] = {};
148 uint8_t ch;
149
150 BUG_ON(device >= BCMTR_MAX_OLTS);
151
152 BCMTRMUX_LOG("rx_task(%ld) - started\n", device);
153
154 /* Enable rx interrupt */
155
156 while (1)
157 {
158 bcmtr_pcie_rxint_enable(device);
159 bcmos_sem_wait(&bcmtrmux_rx_lock[device], BCMTRMUX_MAX_RX_DELAY);
160
161 if (!bcmtr_mux_connected[device])
162 {
163 break;
164 }
165 /* Wait for receive */
166 do
167 {
168 buf = NULL;
169 rc = bcmtr_swq_receive(device, BCMTR_PCIE_PRTY_NORMAL, &ch, &buf);
170 if (rc)
171 {
172 /* If DMA is not shared with urgent service, poll RXQ here,
173 * don't wait for interrupt
174 */
175 if (rc == BCM_ERR_QUEUE_EMPTY && !num_urgent_channels[device])
176 {
177 bcmtr_pcie_rxint_disable(device);
178 bcmtr_swq_rx_poll(device, nbuf);
179 bcmtrmux_stat_array[device].rx_poll_normal += nbuf[BCMTR_PCIE_PRTY_NORMAL];
180 }
181 /* Wait for interrupt or semaphore timeout */
182 break;
183 }
184 bcmtrmux_rx_from_line((bcmolt_devid)device, (bcmtrmux_channel)ch, buf);
185 } while (bcmtr_mux_connected[device]);
186 }
187 BCMTRMUX_LOG("rx_task(%ld) - terminated\n", device);
188 bcmtr_mux_terminated[device] = BCMOS_TRUE;
189
190 return 0;
191}
192
193static void bcmtrmux_rx_irq(bcmolt_devid device)
194{
195 bcmos_buf *buf;
196 uint8_t ch;
197 uint32_t nbuf[BCMTR_PCIE_PRTY__NUM_OF] = {};
198
199 bcmtr_pcie_rxint_disable(device);
200 bcmtr_pcie_rxint_clear(device);
201 bcmtr_swq_rx_poll(device, nbuf);
202
203 /* Got some packets. Deliver high priority from interrupt level */
204 if (nbuf[BCMTR_PCIE_PRTY_URGENT])
205 {
206 bcmtrmux_stat_array[device].rx_poll_urgent += nbuf[BCMTR_PCIE_PRTY_URGENT];
207 while (bcmtr_swq_receive(device, BCMTR_PCIE_PRTY_URGENT, &ch, &buf) == BCM_ERR_OK)
208 {
209 bcmtrmux_rx_from_line(device, ch, buf);
210 }
211 }
212
213 /* Check normal priority */
214 if (nbuf[BCMTR_PCIE_PRTY_NORMAL])
215 {
216 bcmtrmux_stat_array[device].rx_poll_normal += nbuf[BCMTR_PCIE_PRTY_NORMAL];
217 bcmos_sem_post(&bcmtrmux_rx_lock[device]);
218 }
219
220 /* Enable rx interrupt */
221 bcmtr_pcie_rxint_enable(device);
222
223 return;
224}
225
226/* Tx confirmation interrupt handler.
227 * Used only if there are urgent channels
228 */
229static void bcmtrmux_tx_irq(bcmolt_devid device)
230{
231 /* Disable and clear transmit completion interrupts */
232 bcmtr_pcie_txint_disable(device);
233 bcmtr_pcie_txint_clear(device);
234 /* Submit buffers pending in sw queue to the h/w queue */
235 bcmtr_swq_tx_submit(device);
236 /* Re-enable tx completion interrupt */
237 bcmtr_pcie_txint_enable(device);
238 return;
239}
240
241/* Init PCIE transport */
242static bcmos_errno bcmtrmux_pcie_init(bcmolt_devid device, uint32_t txq_size, uint32_t rxq_size)
243{
244 uint32_t pcie_cookie[BCMOS_ROUND_UP(PCIE_OPAQUE_DATA_SIZE, sizeof(uint32_t))/sizeof(uint32_t)];
245 bcmtr_pcie_pre_connect_cfg cfg;
246 bcm_ll_dev_info ll_info;
247 int niter = 0;
248 bcmos_errno err;
249 bcmos_bool status;
250
251#ifndef SIMULATION_BUILD
252 err = bcm_ll_pcie_query(device, &ll_info);
253 if (err)
254 {
255 BCMOS_TRACE_RETURN(err, "bcm_ll_pcie_query() failed\n");
256 }
257#endif
258
259 BCMTRMUX_LOG("Waiting for BCM68620 application\n");
260 bcm_fld_set_rings_size(device, txq_size, rxq_size);
261 status = bcm_fld_test_device_bootrecord_flag(device);
262
263 /* Wait for embedded handshake. BCMTR_PCIE_START_TIMEOUT is in ms */
264 for (niter = 0;
265 niter < BCMTR_PCIE_START_TIMEOUT / 10 && !(status = bcm_fld_test_device_bootrecord_flag(device));
266 niter++)
267 {
268 bcmos_usleep(10000);
269 }
270 if (!status)
271 {
272 BCMOS_TRACE_RETURN(BCM_ERR_IO, "BCM68620 application timeout\n");
273 }
274
275 err = bcm_fld_get_device_bootrecord(device, pcie_cookie);
276 if (err != BCM_ERR_OK)
277 {
278 BCMOS_TRACE_RETURN(err, "bcm_fld_get_device_bootrecord() failed\n");
279 }
280
281 /* set host prm bit - indicate host ready to send/receive DMA */
282 bcm_fld_clear_device_bootrecord_flag(device);
283
284 cfg.txq_size = txq_size; /* Transmit queue size */
285 cfg.rxq_size = rxq_size; /* Receive queue size */
286 cfg.max_mtu = BCMTR_MAX_MTU_SIZE; /* Max MTU size */
287 cfg.pcie_reg_base = ll_info.soc_regs_base;
288 cfg.ddr_win_base = ll_info.soc_ddr_base;
289 cfg.rx_irq = ll_info.irq;
290
291 err = bcmtr_pcie_pre_connect(device, &cfg, (bcmtr_pcie_opaque_data *)pcie_cookie);
292 if (err)
293 {
294 BCMOS_TRACE_RETURN(err, "bcmtr_pcie_pre_connect() failed\n");
295 }
296
297 err = bcmtr_pcie_connect(device,(bcmtr_pcie_opaque_data *)pcie_cookie);
298 if (err)
299 {
300 BCMOS_TRACE_RETURN(err, "bcmtr_pcie_connect() failed\n");
301 }
302
303 bcm_fld_set_host_bootrecord_flag(device);
304
305 /* Wait for embedded handshake. BCMTR_PCIE_CONNECT_TIMEOUT is in ms */
306 for (niter = 0;
307 niter < BCMTR_PCIE_CONNECT_TIMEOUT / 10 && (status = bcm_fld_test_host_bootrecord_flag(device));
308 niter++)
309 {
310 bcmos_usleep(10000);
311 }
312 if (status)
313 {
314 BCMOS_TRACE_RETURN(BCM_ERR_IO, "BCM68620 connect timeout\n");
315 }
316
317 BCMTRMUX_LOG("PCI transport: initialized\n");
318
319 return BCM_ERR_OK;
320}
321
322#else /* #ifndef IN_BAND */
323
324/* IN-BAND receive handler */
325static int _bcmtrmux_ib_rx_handler(long device)
326{
327 bcmos_errno rc;
328 bcmos_buf *buf;
329 uint8_t ch;
330
331 BUG_ON(device >= BCMTR_MAX_OLTS);
332
333 BCMTRMUX_LOG("rx_task(%ld) - started\n", device);
334
335 while (bcmtr_mux_connected[device])
336 {
337 /* Wait for receive */
338 buf = NULL;
339 rc = bcmtr_ib_receive(device, &ch, &buf);
340 if (rc == BCM_ERR_OK)
341 {
342 bcmtrmux_rx_from_line((bcmolt_devid)device, (bcmtrmux_channel)ch, buf);
343 }
344 }
345
346 BCMTRMUX_LOG("rx_task(%ld) - terminated\n", device);
347 bcmtr_mux_terminated[device] = BCMOS_TRUE;
348
349 return 0;
350}
351
352static bcmos_errno bcmtrmux_ib_connect(bcmolt_devid device, bcmos_ipv4_address ip_address, uint16_t udp_port)
353{
354 bcmos_errno rc;
355
356 rc = bcmtr_ib_connect((uint8_t)device, ip_address, udp_port);
357 if (rc)
358 {
359 BCMTRMUX_LOG("%s: Failed to connect. Error %d\n", __FUNCTION__, rc);
360 return rc;
361 }
362 return rc;
363}
364
365#endif /* #ifndef IN_BAND */
366
367
368/** Initialize mux service
369 * \returns: 0 in case of success or error code < 0
370 */
371bcmos_errno bcmtrmux_init(bcmtrmux_msg_filter_cb_t msg_filter_cb)
372{
373 static bcmos_bool initialized = BCMOS_FALSE;
374 int i, j;
375 bcmos_errno rc;
376
377 bcmtrmux_msg_filter_cb = msg_filter_cb;
378
379 BCMTRMUX_LOG("Initialising transport MUX subsystem\n");
380 if (initialized)
381 {
382 return BCM_ERR_ALREADY;
383 }
384
385 for (i=0; i<BCMTR_MAX_OLTS; i++)
386 {
387 for (j=0; j<BCMTRMUX_MAX_CHANNELS; j++)
388 {
389 bcmtrmux_rx_info_array[i][j].rx = bcmtrmux_rx_discard;
390 bcmtrmux_rx_info_array[i][j].data = &bcmtrmux_stat_array[i].rx_disc_remote;
391 }
392 bcmtrmux_rx_info_array[i][BCMTRMUX_CHANNEL_AUTO_PROXY].rx = bcmtrmux_rx_auto_proxy;
393 bcmtrmux_rx_info_array[i][BCMTRMUX_CHANNEL_AUTO_PROXY].data = NULL;
394 bcmtrmux_rx_info_array[i][BCMTRMUX_CHANNEL_DEV_CONTROL].rx = bcmtrmux_rx_local;
395 bcmtrmux_rx_info_array[i][BCMTRMUX_CHANNEL_DEV_CONTROL].data = NULL;
396 for (j=0; j<BCMTR_MAX_INSTANCES; j++)
397 {
398 bcmolt_obj_id k;
399 for (k=0; k<BCMOLT_OBJ_ID__NUM_OF; k++)
400 {
401 bcmtrmux_auto_channels[i][j][k] = BCMTRMUX_MAX_CHANNELS;
402 bcmtrmux_proxy_channels[i][j][k] = BCMTRMUX_MAX_CHANNELS;
403 }
404 }
405 bcmtrmux_local_rx_info_array[i].rx = bcmtrmux_local_rx_discard;
406 bcmtrmux_local_rx_info_array[i].data = &bcmtrmux_stat_array[i].tx_disc_local;
407 }
408
409 bcmos_fastlock_init(&bcmtrmux_lock, 0);
410
411 /*Don't initialize at this time for User Space dev ctrl,
412 don't have enough information*/
413#ifndef IN_BAND
414 rc = bcmtr_pcie_init(BCMTR_MAX_OLTS);
415 if (rc)
416 {
417 BCMOS_TRACE_RETURN(rc, "bcmtr_pcie_init() failed\n");
418 }
419
420 rc = bcmtr_swq_init();
421 if (rc)
422 {
423 BCMOS_TRACE_RETURN(rc, "bcmtr_swq_init() failed\n");
424 }
425
426 /* Register rx callback in PCIe driver */
427 bcmtr_pcie_rx_irq_cblk_register(bcmtrmux_rx_irq);
428 bcmtr_pcie_tx_irq_cblk_register(bcmtrmux_tx_irq);
429#else
430
431 rc = bcmtr_ib_init();
432 if (rc)
433 {
434 BCMOS_TRACE_RETURN(rc, "bcmtr_ib_init() failed\n");
435 }
436
437#endif /* #ifndef IN_BAND */
438
439 BCMTRMUX_LOG("Transport MUX init done\n");
440
441 return rc;
442}
443
444/** Notify mux driver that low-level transport connection is ready
445 * \returns: 0 in case of success or error code < 0
446 */
447#ifdef IN_BAND
448bcmos_errno bcmtrmux_connect(bcmolt_devid device, bcmos_ipv4_address ip_address, uint16_t udp_port)
449#else
450bcmos_errno bcmtrmux_connect(bcmolt_devid device, uint32_t txq_size, uint32_t rxq_size)
451#endif
452{
453 static char task_name[BCMTR_MAX_OLTS][16];
454 bcmos_task_parm taskp = {};
455 bcmos_errno rc;
456
457 if (bcmtr_mux_connected[device])
458 {
459 return BCM_ERR_ALREADY;
460 }
461
462 snprintf(task_name[device], sizeof(task_name[device]), "bcmtr_rx%d", device);
463 taskp.data = (long)device;
464 taskp.name = task_name[device];
465
466#ifdef IN_BAND
467 rc = bcmtrmux_ib_connect(device, ip_address, udp_port);
468 if (rc)
469 {
470 BCMTRMUX_LOG("%s: Failed to init inband device. Error %d\n", __FUNCTION__, rc);
471 return rc;
472 }
473 taskp.handler = _bcmtrmux_ib_rx_handler;
474#else
475 rc = bcmos_sem_create(&bcmtrmux_rx_lock[device], 0, 0, NULL);
476 if (rc)
477 {
478 BCMTRMUX_LOG("%s: Failed to create rx lock. Error %d\n", __FUNCTION__, rc);
479 return rc;
480 }
481
482 /* Initialize low-level PCIe transport */
483 rc = bcmtrmux_pcie_init(device, txq_size, rxq_size);
484 if (rc)
485 {
486 bcmos_sem_destroy(&bcmtrmux_rx_lock[device]);
487 BCMTRMUX_LOG("%s: Failed to init low-level PCIe transport. Error %d\n", __FUNCTION__, rc);
488 return rc;
489 }
490 taskp.handler = _bcmtrmux_pcie_rx_handler;
491
492 rc = bcmtr_swq_device_init(device);
493 if (rc)
494 {
495 bcmos_sem_destroy(&bcmtrmux_rx_lock[device]);
496 BCMTRMUX_LOG("%s: Failed to init pcie_swq. Error %d\n", __FUNCTION__, rc);
497 return rc;
498 }
499
500#endif
501 bcmtr_mux_connected[device] = BCMOS_TRUE;
502 bcmtr_mux_terminated[device] = BCMOS_FALSE;
503
504 rc = bcmos_task_create(&bcmtrmux_rx_task[device], &taskp);
505 if (rc)
506 {
507#ifndef IN_BAND
508 bcmos_sem_destroy(&bcmtrmux_rx_lock[device]);
509#endif
510 bcmtr_mux_connected[device] = BCMOS_FALSE;
511 BCMTRMUX_LOG("%s: Failed to create rx task. Error %d\n", __FUNCTION__, rc);
512 return rc;
513 }
514
515 return BCM_ERR_OK;
516}
517
518/** Notify mux driver that low-level transport connection is disconnected
519 * \returns: 0 in case of success or error code < 0
520 */
521bcmos_errno bcmtrmux_disconnect(bcmolt_devid device)
522{
523 if (!bcmtr_mux_connected[device])
524 {
525 return BCM_ERR_ALREADY;
526 }
527 bcmtr_mux_connected[device] = BCMOS_FALSE;
528#ifdef IN_BAND
529 bcmtr_ib_disconnect((uint8_t)device);
530#else
531 bcmos_sem_post(&bcmtrmux_rx_lock[device]);
532#endif
533 while (!bcmtr_mux_terminated[device])
534 {
535 bcmos_usleep(10000);
536 }
537 bcmos_task_destroy(&bcmtrmux_rx_task[device]);
538#ifndef IN_BAND
539 bcmos_sem_destroy(&bcmtrmux_rx_lock[device]);
540 bcmtr_swq_device_exit(device);
541 bcmtr_pcie_disconnect((uint8_t)device);
542#endif
543 return BCM_ERR_OK;
544}
545
546/** Cleanup and exit
547 */
548void bcmtrmux_exit(void)
549{
550 int i;
551
552 BCMTRMUX_LOG("Cleaning up transport MUX subsystem\n");
553#ifndef IN_BAND
554 bcmtr_swq_exit();
555 bcmtr_pcie_rx_irq_cblk_unregister();
556 bcmtr_pcie_tx_irq_cblk_unregister();
557#endif
558 /* kill receive tasks */
559 for (i=0; i<BCMTR_MAX_OLTS; i++)
560 {
561 bcmtrmux_disconnect((bcmolt_devid)i);
562 }
563#ifdef IN_BAND
564 bcmtr_ib_exit();
565#else
566 bcmtr_pcie_exit();
567#endif
568 BCMTRMUX_LOG("Transport MUX cleanup done\n");
569}
570
571/** Register PCIe channel owner */
572bcmos_errno bcmtrmux_channel_register(bcmolt_devid device, bcmtrmux_channel *channel,
573 f_bcmtr_rx_handler rx, void *data)
574{
575 bcmtrmux_channel ch;
576 long flags;
577
578 if ((unsigned)device >= BCMTR_MAX_OLTS || !channel || !rx)
579 {
580 return BCM_ERR_PARM;
581 }
582 ch = *channel;
583
584 flags = bcmos_fastlock_lock(&bcmtrmux_lock);
585
586 if (ch == BCMTRMUX_CHANNEL_AUTO_ASSIGN)
587 {
588 /* Auto-assign free channel */
589 ch = (bcmtrmux_channel)bcmtrmux_channel_get_free(device);
590 if (ch >= BCMTRMUX_MAX_CHANNELS)
591 {
592 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
593 return BCM_ERR_NORES;
594 }
595 }
596
597 /* Make sure that channel is valid and not busy */
598 if ((unsigned)ch >= BCMTRMUX_MAX_CHANNELS)
599 {
600 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
601 return BCM_ERR_PARM;
602 }
603 if (bcmtrmux_rx_info_array[device][ch].rx != bcmtrmux_rx_discard)
604 {
605 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
606 return BCM_ERR_ALREADY;
607 }
608
609 /* Assign channel */
610 bcmtrmux_rx_info_array[device][ch].rx = rx;
611 bcmtrmux_rx_info_array[device][ch].data = data;
612
613#ifndef IN_BAND
614 /* Urgent channels are not supported for IN-BAND management */
615 if (ch >= BCMTRMUX_FIRST_URGENT_CHANNEL)
616 {
617 /* We use transmit confirmation interrupt to kick transmission
618 * if PCI bus is shared between high and low-priority channels
619 */
620 if (!num_urgent_channels[device])
621 bcmtr_pcie_txint_enable(device);
622 ++num_urgent_channels[device];
623 }
624#endif
625
626 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
627
628 *channel = ch;
629
630 return BCM_ERR_OK;
631}
632
633
634/** Release PCIe channel allocated by bcmtrmux_channel_register()
635 *
636 * \param[in] device Maple device index
637 * \param[in] channel
638 * \returns: 0 in case of success or error code < 0
639 */
640bcmos_errno bcmtrmux_channel_unregister(bcmolt_devid device, bcmtrmux_channel channel)
641{
642 long flags;
643
644 if ((unsigned)device >= BCMTR_MAX_OLTS || (unsigned)channel >= BCMTRMUX_MAX_CHANNELS)
645 {
646 return BCM_ERR_PARM;
647 }
648
649 flags = bcmos_fastlock_lock(&bcmtrmux_lock);
650
651 if (bcmtrmux_rx_info_array[device][channel].rx == bcmtrmux_rx_discard)
652 {
653 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
654 return BCM_ERR_NOENT;
655 }
656
657 bcmtrmux_rx_info_array[device][channel].rx = bcmtrmux_rx_discard;
658 bcmtrmux_rx_info_array[device][channel].data = &bcmtrmux_stat_array[device].rx_disc_remote;
659
660#ifndef IN_BAND
661 /* Urgent channels are not supported for IN-BAND management */
662 if (channel >= BCMTRMUX_FIRST_URGENT_CHANNEL)
663 {
664 --num_urgent_channels[device];
665 /* If PCI bus is not shared between normal and urgent channels,
666 * transmit confirmation mechanism is not needed
667 */
668 if (!num_urgent_channels[device])
669 bcmtr_pcie_txint_disable(device);
670 }
671#endif
672
673 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
674
675 return BCM_ERR_OK;
676}
677
678/*
679 * Local termination handler
680 */
681
682/* Register local termination handler. */
683bcmos_errno bcmtrmux_local_handler_register(bcmolt_devid device, f_bcmtr_local_rx_handler rx, void *data)
684{
685 long flags;
686
687 if ((unsigned)device >= BCMTR_MAX_OLTS || !rx)
688 {
689 return BCM_ERR_PARM;
690 }
691 flags = bcmos_fastlock_lock(&bcmtrmux_lock);
692 if (bcmtrmux_local_rx_info_array[device].rx != bcmtrmux_local_rx_discard)
693 {
694 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
695 return BCM_ERR_ALREADY;
696 }
697 bcmtrmux_local_rx_info_array[device].rx = rx;
698 bcmtrmux_local_rx_info_array[device].data = data;
699 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
700 return BCM_ERR_OK;
701}
702
703
704/* Unregister local termination handler registered by bcmtrmux_local_handler_register() */
705bcmos_errno bcmtrmux_local_handler_unregister(bcmolt_devid device)
706{
707 long flags;
708
709 if ((unsigned)device >= BCMTR_MAX_OLTS)
710 {
711 return BCM_ERR_PARM;
712 }
713 flags = bcmos_fastlock_lock(&bcmtrmux_lock);
714 if (bcmtrmux_local_rx_info_array[device].rx == bcmtrmux_local_rx_discard)
715 {
716 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
717 return BCM_ERR_NOENT;
718 }
719 bcmtrmux_local_rx_info_array[device].data = &bcmtrmux_stat_array[device].tx_disc_local;
720 bcmtrmux_local_rx_info_array[device].rx = bcmtrmux_local_rx_discard;
721 bcmos_fastlock_unlock(&bcmtrmux_lock, flags);
722 return BCM_ERR_OK;
723}
724
725/* Deliver message to local destination */
726static bcmos_bool bcmtrmux_deliver_to_local(bcmolt_devid device, bcmtrmux_channel channel, bcmos_buf *buf, bcmtr_hdr *hdr)
727{
728 bcmtrmux_local_rx_info *rx_info;
729 bcmolt_msg *msg = NULL;
730 bcmolt_buf ubuf;
731 bcmos_errno err;
732
733 /* Unpack */
734 bcmolt_buf_init(&ubuf, bcmos_buf_length(buf), bcmos_buf_data(buf), BCMTR_BUF_ENDIAN);
735 bcmolt_buf_skip(&ubuf, BCMTR_HDR_SIZE);
736 err = bcmolt_msg_unpack(&ubuf, &msg);
737 bcmos_buf_free(buf);
738 if (err < 0)
739 {
740 BCMOS_TRACE_ERR("Message unpack error %s (%d)\n", bcmos_strerror(err), err);
741 ++bcmtrmux_stat_array[device].tx_disc_local;
742 return BCMOS_TRUE;
743 }
744 msg->corr_tag = hdr->corr_tag;
745 msg->subch = (bcmolt_subchannel)channel;
746 ++bcmtrmux_stat_array[device].tx_local;
747
748 rx_info = &bcmtrmux_local_rx_info_array[device];
749 rx_info->rx(device, msg, rx_info->data);
750 return BCMOS_TRUE;
751}
752
753/* send to line with repetitive attempts if pcie buffer is full */
754static void bcmtrmux_send_to_line(bcmolt_devid device, bcmtrmux_channel channel, bcmos_buf *buf)
755{
756 bcmos_errno rc;
757
758#ifdef IN_BAND
759 rc = bcmtr_ib_send((uint8_t)device, (uint8_t)channel, buf);
760#else
761 rc = bcmtr_swq_send((uint8_t)device, channel, buf);
762#endif
763 if (rc != BCM_ERR_OK)
764 {
765 /* Failed */
766 ++bcmtrmux_stat_array[device].tx_disc_remote;
767 bcmos_buf_free(buf);
768 }
769}
770
771/* Receive message from host application */
772void bcmtrmux_rx_from_host(bcmolt_devid device, bcmtrmux_channel channel, bcmos_buf *buf)
773{
774 bcmtr_hdr hdr;
775 bcmolt_obj_id obj;
776 bcmolt_mgt_group group;
777 uint16_t subgroup;
778 bcmos_errno rc;
779
780 /* Validate parameters */
781 BUG_ON((unsigned)device >= BCMTR_MAX_OLTS);
782 BUG_ON((unsigned)channel >= BCMTRMUX_MAX_CHANNELS);
783
784 /* Peek in transport header. It contains enough info to decide what to do with the message */
785 bcmtr_header_unpack(bcmos_buf_data(buf), &hdr);
786
787 rc = bcmolt_group_id_split(hdr.msg_id, &obj, &group, &subgroup);
788 if (rc)
789 {
790 BCMOS_TRACE_ERR("Can't decode group_id %u. Error %s (%d)\n", hdr.msg_id, bcmos_strerror(rc), rc);
791 ++bcmtrmux_stat_array[device].tx_disc_remote;
792 bcmos_buf_free(buf);
793 return;
794 }
795
796 /* Filter auto/proxy (un)registration.
797 * This message is terminated here.
798 */
799 if (hdr.auto_proxy_reg || hdr.auto_proxy_unreg)
800 {
801 bcmtrmux_channel *p_ch = (group == BCMOLT_MGT_GROUP_AUTO) ?
802 &bcmtrmux_auto_channels[device][hdr.instance][obj] : &bcmtrmux_proxy_channels[device][hdr.instance][obj];
803
804 bcmos_buf_free(buf);
805
806 /* Sanity check */
807 if (hdr.instance >= BCMTR_MAX_INSTANCES || obj >= BCMOLT_OBJ_ID__NUM_OF)
808 {
809 BCMOS_TRACE_ERR("Instance %u or object %d is insane\n", hdr.instance, obj);
810 return;
811 }
812
813 /* Do not override bcmolt_dev_ctrl filters */
814 if (*p_ch != BCMTRMUX_CHANNEL_DEV_CONTROL)
815 {
816 *p_ch = hdr.auto_proxy_reg ? channel : BCMTRMUX_MAX_CHANNELS;
817 }
818
819 return;
820 }
821
822 /* Filter message that should go to local destination (device control) */
823 if (bcmtrmux_msg_filter_cb && bcmtrmux_msg_filter_cb(device, obj, group, subgroup) == BCMTRMUX_DEST_LOCAL)
824 {
825 if (bcmtrmux_deliver_to_local(device, channel, buf, &hdr) == BCMOS_TRUE)
826 return;
827 }
828
829 /* Handle Remote message */
830 ++bcmtrmux_stat_array[device].tx_remote;
831 bcmtrmux_send_to_line(device, channel, buf);
832}
833
834
835/* Receive packet from the line or local control process.
836 * Parameters are expected to be checked beforehand.
837 * The function de-muxes
838 * - replies based on channel
839 * - autonomous/proxy messages based on registration info
840 */
841static void bcmtrmux_rx(bcmolt_devid device, bcmtrmux_channel channel, bcmos_buf *buf)
842{
843 bcmtrmux_rx_info *rx_info;
844 rx_info = &bcmtrmux_rx_info_array[device][channel];
845 rx_info->rx(device, buf, channel, rx_info->data);
846}
847
848
849/* Receive packet from PCIe interface */
850void bcmtrmux_rx_from_line(bcmolt_devid device, bcmtrmux_channel channel, bcmos_buf *buf)
851{
852 BUG_ON((unsigned)device >= BCMTR_MAX_OLTS);
853
854 if ((unsigned)channel >= BCMTRMUX_MAX_CHANNELS)
855 {
856 ++bcmtrmux_stat_array[device].rx_disc_inv_ch;
857 bcmos_buf_free(buf);
858 return;
859 }
860
861 ++bcmtrmux_stat_array[device].rx_remote;
862
863 bcmtrmux_rx(device, channel, buf);
864}
865
866/* Handle message received via Auto/Proxy channel */
867static void bcmtrmux_rx_auto_proxy(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data)
868{
869 bcmtr_hdr hdr;
870 bcmolt_obj_id obj;
871 bcmolt_mgt_group group;
872 uint16_t subgroup;
873 bcmos_errno rc;
874
875 /* Peek in transport header. It contains enough info to decide what to do with the message */
876 bcmtr_header_unpack(bcmos_buf_data(buf), &hdr);
877
878 rc = bcmolt_group_id_split(hdr.msg_id, &obj, &group, &subgroup);
879 if (rc)
880 {
881 BCMOS_TRACE_ERR("Can't decode group_id %u. Error %s (%d)\n", hdr.msg_id, bcmos_strerror(rc), rc);
882 ++bcmtrmux_stat_array[device].rx_disc_auto;
883 bcmos_buf_free(buf);
884 return;
885 }
886
887 /* Sanity check */
888 if (hdr.instance >= BCMTR_MAX_INSTANCES || obj >= BCMOLT_OBJ_ID__NUM_OF)
889 {
890 BCMOS_TRACE_ERR("Instance %u or object %d is insane\n", hdr.instance, obj);
891 ++bcmtrmux_stat_array[device].rx_disc_auto;
892 bcmos_buf_free(buf);
893 return;
894 }
895
896 /* Dispatch based on object id */
897 /* Handle dev_ctrl intercept */
898 if (bcmtrmux_dev_ctrl_intercept[device][hdr.msg_id])
899 {
900 channel = BCMTRMUX_CHANNEL_DEV_CONTROL;
901 }
902 else
903 {
904 channel = (group == BCMOLT_MGT_GROUP_AUTO) ?
905 bcmtrmux_auto_channels[device][hdr.instance][obj] : bcmtrmux_proxy_channels[device][hdr.instance][obj];
906 }
907
908 /* If no registration - discard */
909 if (channel >= BCMTRMUX_MAX_CHANNELS)
910 {
911 ++bcmtrmux_stat_array[device].rx_disc_auto;
912 bcmos_buf_free(buf);
913 return;
914 }
915 bcmtrmux_rx(device, channel, buf);
916}
917
918/* Handle message received via DEV_CONTROL channel */
919static void bcmtrmux_rx_local(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data)
920{
921 bcmtrmux_local_rx_info *rx_info;
922 bcmtr_hdr hdr;
923 bcmolt_buf ubuf;
924 bcmolt_msg *msg = NULL;
925 bcmos_errno err;
926
927 bcmtr_header_unpack(bcmos_buf_data(buf), &hdr);
928
929 bcmolt_buf_init(&ubuf, bcmos_buf_length(buf), bcmos_buf_data(buf), BCMTR_BUF_ENDIAN);
930 bcmolt_buf_skip(&ubuf, BCMTR_HDR_SIZE);
931 err = bcmolt_msg_unpack(&ubuf, &msg);
932 bcmos_buf_free(buf);
933 if (err < 0)
934 {
935 BCMOS_TRACE_ERR("Message unpack error %s (%d)\n", bcmos_strerror(err), err);
936 ++bcmtrmux_stat_array[device].rx_disc_remote;
937 return;
938 }
939
940 msg->corr_tag = hdr.corr_tag;
941 msg->subch = (bcmolt_subchannel)channel;
942 ++bcmtrmux_stat_array[device].rx_local;
943
944 rx_info = &bcmtrmux_local_rx_info_array[device];
945 rx_info->rx(device, msg, rx_info->data);
946}
947
948static bcmos_errno bcmtrmux_msg_pack(bcmolt_devid device, bcmolt_msg *msg, bcmos_buf **p_buf)
949{
950 int32_t len = bcmolt_msg_get_packed_length(msg);
951 bcmos_buf *buf;
952 bcmolt_buf ubuf;
953 bcmos_errno rc = BCM_ERR_OK;
954 bcmtr_hdr thdr = {};
955
956 if (len < 0)
957 {
958 BCMOS_TRACE_ERR("Can't calculate packet length. Error %s (%d)\n", bcmos_strerror(rc), len);
959 return BCM_ERR_PARM;
960 }
961 rc = bcmtr_header_fill(msg, &thdr);
962 if (rc)
963 {
964 BCMOS_TRACE_ERR("Can't create transport header. Error %s (%d)\n", bcmos_strerror(rc), rc);
965 return BCM_ERR_PARM;
966 }
967
968 len += BCMTR_HDR_SIZE;
969 buf = bcmos_buf_alloc(len);
970 if (!buf)
971 {
972 BCMOS_TRACE_ERR("Can't allocate packet buffer\n");
973 return BCM_ERR_NOMEM;
974 }
975 bcmolt_buf_init(&ubuf, len, bcmos_buf_data(buf), BCMTR_BUF_ENDIAN);
976 bcmolt_buf_skip(&ubuf, BCMTR_HDR_SIZE);
977
978 /* Pack transport header */
979 bcmtr_header_pack(&thdr, ubuf.start);
980
981 /* Pack message */
982 rc = bcmolt_msg_pack(msg, &ubuf);
983 if (rc)
984 {
985 BCMOS_TRACE_ERR("Message pack failed. Error %s (%d)\n", bcmos_strerror(rc), rc);
986 bcmos_buf_free(buf);
987 return BCM_ERR_PARM;
988 }
989 bcmos_buf_length_set(buf, len);
990
991 *p_buf = buf;
992
993 return BCM_ERR_OK;
994}
995
996/* Send packet from local control process to the host application */
997bcmos_errno bcmtrmux_control_to_host(bcmolt_devid device, bcmolt_msg *msg)
998{
999 bcmtrmux_channel channel = (bcmtrmux_channel)msg->subch;
1000 bcmos_buf *buf;
1001 bcmos_errno rc;
1002
1003 BUG_ON((unsigned)channel >= BCMTRMUX_MAX_CHANNELS);
1004 BUG_ON((unsigned)device >= BCMTR_MAX_OLTS);
1005
1006 ++bcmtrmux_stat_array[device].control_to_host;
1007
1008 rc = bcmtrmux_msg_pack(device, msg, &buf);
1009 if (rc)
1010 {
1011 return rc;
1012 }
1013 bcmtrmux_rx(device, channel, buf);
1014 return BCM_ERR_OK;
1015}
1016
1017/* Send packet from local control process to the embedded system */
1018bcmos_errno bcmtrmux_control_to_line(bcmolt_devid device, bcmolt_msg *msg)
1019{
1020 bcmos_buf *buf;
1021 bcmos_errno err;
1022
1023 BUG_ON((unsigned)device >= BCMTR_MAX_OLTS);
1024
1025 ++bcmtrmux_stat_array[device].control_to_line;
1026
1027 err = bcmtrmux_msg_pack(device, msg, &buf);
1028 if (err)
1029 {
1030 return err;
1031 }
1032
1033 bcmtrmux_send_to_line(device, BCMTRMUX_CHANNEL_DEV_CONTROL, buf);
1034
1035 return err;
1036}
1037
1038/* Register message for intercept by bcmolt_dev_ctrl */
1039bcmos_errno bcmtrmux_control_auto_intercept_filter(bcmolt_devid device, bcmolt_obj_id object, uint16_t subgroup)
1040{
1041 bcmos_errno err;
1042 bcmolt_group_id msg_id;
1043
1044 if ((unsigned)device >= BCMTR_MAX_OLTS)
1045 {
1046 return BCM_ERR_PARM;
1047 }
1048 err = bcmolt_group_id_combine(object, BCMOLT_MGT_GROUP_AUTO, subgroup, &msg_id);
1049 if (err)
1050 {
1051 BCMOS_TRACE_ERR("Can't identify operation %d for object %d. Error %s (%d)\n",
1052 (int)subgroup, (int)object, bcmos_strerror(err), err);
1053 return err;
1054 }
1055 bcmtrmux_dev_ctrl_intercept[device][msg_id] = BCMOS_TRUE;
1056 return BCM_ERR_OK;
1057}
1058
1059
1060/** Get transport mux statistics.
1061 *
1062 * \param[in] device Maple device index
1063 * \param[out] stat Statistics
1064 * \returns: 0 in case of success or error code < 0
1065 */
1066bcmos_errno bcmtrmux_stat_get(bcmolt_devid device, bcmtrmux_stat *stat)
1067{
1068 if ((unsigned)device >= BCMTR_MAX_OLTS || !stat)
1069 {
1070 return BCM_ERR_PARM;
1071 }
1072 *stat = bcmtrmux_stat_array[device];
1073 return BCM_ERR_OK;
1074}
1075
1076#ifdef __KERNEL__
1077
1078EXPORT_SYMBOL(bcmtrmux_init);
1079EXPORT_SYMBOL(bcmtrmux_connect);
1080EXPORT_SYMBOL(bcmtrmux_disconnect);
1081EXPORT_SYMBOL(bcmtrmux_channel_register);
1082EXPORT_SYMBOL(bcmtrmux_channel_unregister);
1083EXPORT_SYMBOL(bcmtrmux_local_handler_register);
1084EXPORT_SYMBOL(bcmtrmux_local_handler_unregister);
1085EXPORT_SYMBOL(bcmtrmux_rx_from_host);
1086EXPORT_SYMBOL(bcmtrmux_rx_from_line);
1087EXPORT_SYMBOL(bcmtrmux_control_to_host);
1088EXPORT_SYMBOL(bcmtrmux_control_to_line);
1089EXPORT_SYMBOL(bcmtrmux_control_auto_intercept_filter);
1090EXPORT_SYMBOL(bcmtrmux_stat_get);
1091
1092#endif