blob: 65971248683f7aaab93cc0903afeff297cd4d0c1 [file] [log] [blame]
Sylvain Munautbc9f5c42020-09-14 10:22:29 +02001/*
2 * e1.c
3 *
4 * Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
5 * SPDX-License-Identifier: GPL-3.0-or-later
6 */
7
8#include <stdint.h>
9#include <stdbool.h>
10#include <string.h>
11
12#include "config.h"
13#include "console.h"
14#include "e1.h"
Harald Weltef74dad72020-12-15 23:32:53 +010015#include "e1_hw.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020016
17#include "dma.h"
18#include "led.h" // FIXME
Sylvain Munaut3da51512022-01-03 22:12:59 +010019#include "utils.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020020
21
Sylvain Munaut2c0c1362022-01-03 18:48:08 +010022// HW access
23// ---------
24
Sylvain Munaut3da51512022-01-03 22:12:59 +010025static volatile struct e1_core * const e1_regs_base = (void *)(E1_CORE_BASE);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020026static volatile uint8_t * const e1_data = (void *)(E1_DATA_BASE);
27
Sylvain Munaut2c0c1362022-01-03 18:48:08 +010028
29// Helpers
30// -------
31
Sylvain Munaut35856a12022-01-03 18:45:53 +010032static unsigned int
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020033e1_data_ofs(int mf, int frame, int ts)
34{
35 return (mf << 9) | (frame << 5) | ts;
36}
37
Sylvain Munaut35856a12022-01-03 18:45:53 +010038static volatile uint8_t *
Harald Weltea59ef2b2020-12-14 17:02:13 +010039e1_data_ptr(int mf, int frame, int ts)
40{
41 return &e1_data[e1_data_ofs(mf, frame, ts)];
42}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020043
Sylvain Munaut2c0c1362022-01-03 18:48:08 +010044
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020045// FIFOs
46// -----
47/* Note: FIFO works at 'frame' level (i.e. 32 bytes) */
48
49struct e1_fifo {
50 /* Buffer zone associated with the FIFO */
51 unsigned int base;
52 unsigned int mask;
53
54 /* Pointers / Levels */
55 unsigned int wptr[2]; /* 0=committed 1=allocated */
56 unsigned int rptr[2]; /* 0=discared 1=peeked */
57};
58
59 /* Utils */
60static void
Sylvain Munaut29d82092022-01-10 12:44:53 +010061e1f_init(struct e1_fifo *fifo, unsigned int base, unsigned int len)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020062{
63 memset(fifo, 0x00, sizeof(struct e1_fifo));
64 fifo->base = base;
65 fifo->mask = len - 1;
66}
67
Sylvain Munaut29d82092022-01-10 12:44:53 +010068static void
69e1f_reset(struct e1_fifo *fifo)
70{
71 fifo->wptr[0] = fifo->wptr[1] = 0;
72 fifo->rptr[0] = fifo->rptr[1] = 0;
73}
74
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020075static unsigned int
76e1f_allocd_frames(struct e1_fifo *fifo)
77{
78 /* Number of frames that are allocated (i.e. where we can't write to) */
79 return (fifo->wptr[1] - fifo->rptr[0]) & fifo->mask;
80}
81
82static unsigned int
83e1f_valid_frames(struct e1_fifo *fifo)
84{
85 /* Number of valid frames */
86 return (fifo->wptr[0] - fifo->rptr[0]) & fifo->mask;
87}
88
89static unsigned int
90e1f_unseen_frames(struct e1_fifo *fifo)
91{
92 /* Number of valid frames that haven't been peeked yet */
93 return (fifo->wptr[0] - fifo->rptr[1]) & fifo->mask;
94}
95
96static unsigned int
97e1f_free_frames(struct e1_fifo *fifo)
98{
99 /* Number of frames that aren't allocated */
100 return (fifo->rptr[0] - fifo->wptr[1] - 1) & fifo->mask;
101}
102
103static unsigned int
104e1f_ofs_to_dma(unsigned int ofs)
105{
106 /* DMA address are 32-bits word address. Offsets are 32 byte address */
107 return (ofs << 3);
108}
109
110static unsigned int
111e1f_ofs_to_mf(unsigned int ofs)
112{
113 /* E1 Buffer Descriptors are always multiframe aligned */
114 return (ofs >> 4);
115}
116
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200117 /* Debug */
118static void
119e1f_debug(struct e1_fifo *fifo, const char *name)
120{
121 unsigned int la, lv, lu, lf;
122
123 la = e1f_allocd_frames(fifo);
124 lv = e1f_valid_frames(fifo);
125 lu = e1f_unseen_frames(fifo);
126 lf = e1f_free_frames(fifo);
127
128 printf("%s: R: %u / %u | W: %u / %u | A:%u V:%u U:%u F:%u\n",
129 name,
130 fifo->rptr[0], fifo->rptr[1], fifo->wptr[0], fifo->wptr[1],
131 la, lv, lu, lf
132 );
133}
134
135 /* Frame level read/write */
136static unsigned int
137e1f_frame_write(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
138{
139 unsigned int lf, le;
140
141 lf = e1f_free_frames(fifo);
142 le = fifo->mask - fifo->wptr[0] + 1;
143
144 if (max_frames > le)
145 max_frames = le;
146 if (max_frames > lf)
147 max_frames = lf;
148
149 *ofs = fifo->base + fifo->wptr[0];
150 fifo->wptr[1] = fifo->wptr[0] = (fifo->wptr[0] + max_frames) & fifo->mask;
151
152 return max_frames;
153}
154
155static unsigned int
Sylvain Munautde20fb72020-10-29 13:24:50 +0100156e1f_frame_read(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200157{
158 unsigned int lu, le;
159
160 lu = e1f_unseen_frames(fifo);
161 le = fifo->mask - fifo->rptr[1] + 1;
162
163 if (max_frames > le)
164 max_frames = le;
165 if (max_frames > lu)
166 max_frames = lu;
167
168 *ofs = fifo->base + fifo->rptr[1];
169 fifo->rptr[0] = fifo->rptr[1] = (fifo->rptr[1] + max_frames) & fifo->mask;
170
171 return max_frames;
172}
173
174
175 /* MultiFrame level split read/write */
176static bool
177e1f_multiframe_write_prepare(struct e1_fifo *fifo, unsigned int *ofs)
178{
179 unsigned int lf;
180
181 lf = e1f_free_frames(fifo);
182 if (lf < 16)
183 return false;
184
185 *ofs = fifo->base + fifo->wptr[1];
186 fifo->wptr[1] = (fifo->wptr[1] + 16) & fifo->mask;
187
188 return true;
189}
190
191static void
192e1f_multiframe_write_commit(struct e1_fifo *fifo)
193{
194 fifo->wptr[0] = (fifo->wptr[0] + 16) & fifo->mask;
195}
196
197static bool
198e1f_multiframe_read_peek(struct e1_fifo *fifo, unsigned int *ofs)
199{
200 unsigned int lu;
201
202 lu = e1f_unseen_frames(fifo);
203 if (lu < 16)
204 return false;
205
206 *ofs = fifo->base + fifo->rptr[1];
207 fifo->rptr[1] = (fifo->rptr[1] + 16) & fifo->mask;
208
209 return true;
210}
211
212static void
213e1f_multiframe_read_discard(struct e1_fifo *fifo)
214{
215 fifo->rptr[0] = (fifo->rptr[0] + 16) & fifo->mask;
216}
217
218static void
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100219e1f_multiframe_empty_tail(struct e1_fifo *fifo)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200220{
221 fifo->rptr[0] = fifo->rptr[1] = (fifo->wptr[0] & ~15);
222}
223
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100224static void
225e1f_multiframe_empty_head(struct e1_fifo *fifo)
226{
227 fifo->wptr[0] = fifo->wptr[1] = ((fifo->rptr[1] + 15) & ~15);
228}
229
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200230
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200231// Main logic
232// ----------
233
234enum e1_pipe_state {
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100235 IDLE = 0, /* not running */
236 STARTING = 1, /* after e1_start(), waiting for priming */
237 RUN = 2, /* normal operation */
238 RECOVER = 3, /* after underflow, overflow or alignment error */
239 SHUTDOWN = 4, /* after e1_stop(), waiting for shutdown */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200240};
241
Sylvain Munaut3da51512022-01-03 22:12:59 +0100242struct e1_state {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200243 struct {
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100244 struct {
245 uint32_t cfg;
246 uint32_t val;
247 } cr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200248 struct e1_fifo fifo;
249 int in_flight;
250 enum e1_pipe_state state;
251 } rx;
252
253 struct {
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100254 struct {
255 uint32_t cfg;
256 uint32_t val;
257 } cr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200258 struct e1_fifo fifo;
259 int in_flight;
260 enum e1_pipe_state state;
261 } tx;
Sylvain Munaut2c0c1362022-01-03 18:48:08 +0100262
Harald Welte805f2cf2020-12-14 17:31:03 +0100263 struct e1_error_count errors;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100264};
265
266static struct e1_state g_e1[2];
267
268
269static volatile struct e1_core *
270_get_regs(int port)
271{
272 if ((port < 0) || (port > 1))
273 panic("_get_regs invalid port %d", port);
274 return &e1_regs_base[port];
275}
276
277static struct e1_state *
278_get_state(int port)
279{
280 if ((port < 0) || (port > 1))
281 panic("_get_state invalid port %d", port);
282 return &g_e1[port];
283}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200284
285
Sylvain Munaute9fe0dc2022-01-10 12:26:20 +0100286#define RXCR_PERMITTED ( \
287 E1_RX_CR_MODE_MASK )
288
289#define TXCR_PERMITTED ( \
290 E1_TX_CR_MODE_MASK | \
291 E1_TX_CR_TICK_MASK | \
292 E1_TX_CR_ALARM | \
293 E1_TX_CR_LOOPBACK | \
294 E1_TX_CR_LOOPBACK_CROSS )
295
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100296static void
297_e1_update_cr_val(int port)
298{
299 struct e1_state *e1 = _get_state(port);
300
301 /* RX */
302 if (e1->rx.state == IDLE) {
303 /* "Off" state: Force MFA mode to detect remote side */
304 e1->rx.cr.val = (e1->rx.cr.cfg & ~E1_RX_CR_MODE_MASK) | E1_RX_CR_ENABLE | E1_RX_CR_MODE_MFA;
305 } else {
306 /* "On state: Enabled + User config */
307 e1->rx.cr.val = e1->rx.cr.cfg | E1_RX_CR_ENABLE;
308 }
309
310 /* TX */
311 if (e1->tx.state == IDLE) {
312 /* "Off" state: We TX only OIS */
313 e1->tx.cr.val = (e1->tx.cr.cfg & ~(E1_TX_CR_MODE_MASK | E1_TX_CR_ALARM)) | E1_TX_CR_ENABLE | E1_TX_CR_MODE_TRSP;
314 } else {
315 /* "On state: Enabled + User config */
316 e1->tx.cr.val = e1->tx.cr.cfg | E1_TX_CR_ENABLE;
317 }
318}
319
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200320void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100321e1_init(int port, uint16_t rx_cr, uint16_t tx_cr)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200322{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100323 volatile struct e1_core *e1_regs = _get_regs(port);
324 struct e1_state *e1 = _get_state(port);
325
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200326 /* Global state init */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100327 memset(e1, 0x00, sizeof(struct e1_state));
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200328
Sylvain Munaut29d82092022-01-10 12:44:53 +0100329 /* Initialize FIFOs */
330 e1f_init(&e1->rx.fifo, (512 * port) + 0, 256);
331 e1f_init(&e1->tx.fifo, (512 * port) + 256, 256);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200332
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100333 /* Flow state */
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100334 e1->rx.state = IDLE;
335 e1->tx.state = IDLE;
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100336
337 /* Set config registers */
338 e1->rx.cr.cfg = rx_cr & RXCR_PERMITTED;
339 e1->tx.cr.cfg = tx_cr & TXCR_PERMITTED;
340
341 _e1_update_cr_val(port);
342
343 e1_regs->rx.csr = e1->rx.cr.val;
344 e1_regs->tx.csr = e1->tx.cr.val;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200345}
346
Harald Welte6add0aa2020-12-16 00:02:11 +0100347void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100348e1_rx_config(int port, uint16_t cr)
Harald Welte6add0aa2020-12-16 00:02:11 +0100349{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100350 volatile struct e1_core *e1_regs = _get_regs(port);
351 struct e1_state *e1 = _get_state(port);
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100352 e1->rx.cr.cfg = cr & RXCR_PERMITTED;
353 _e1_update_cr_val(port);
354 e1_regs->rx.csr = e1->rx.cr.val;
Harald Welte6add0aa2020-12-16 00:02:11 +0100355}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200356
Sylvain Munaut4fd71552022-01-10 12:28:28 +0100357void
358e1_tx_config(int port, uint16_t cr)
359{
360 volatile struct e1_core *e1_regs = _get_regs(port);
361 struct e1_state *e1 = _get_state(port);
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100362 e1->tx.cr.cfg = cr & TXCR_PERMITTED;
363 _e1_update_cr_val(port);
364 e1_regs->tx.csr = e1->tx.cr.val;
Sylvain Munaut4fd71552022-01-10 12:28:28 +0100365}
366
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100367void
368e1_start(int port)
369{
370 volatile struct e1_core *e1_regs = _get_regs(port);
371 struct e1_state *e1 = _get_state(port);
372
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100373 /* RX */
374 switch (e1->rx.state) {
375 case IDLE:
376 /* We're idle, clear fifo and normal start */
377 e1f_reset(&e1->rx.fifo);
378 e1->rx.state = STARTING;
379 break;
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100380
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100381 case SHUTDOWN:
382 /* Shutdown is pending, go to recover which is basically
383 * a shutdown with auto-restart */
384 e1->rx.state = RECOVER;
385 break;
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100386
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100387 default:
388 /* Huh ... hope for the best */
389 printf("[!] E1 RX start while not stopped ...\n");
390 }
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100391
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100392 /* TX */
393 switch (e1->tx.state) {
394 case IDLE:
395 /* We're idle, clear fifo and normal start */
396 e1f_reset(&e1->tx.fifo);
397 e1->tx.state = STARTING;
398 break;
399
400 case SHUTDOWN:
401 /* Shutdown is pending, go to recover which is basically
402 * a shutdown with auto-restart */
403 e1->tx.state = RECOVER;
404
405 /* We also prune any pending data in FIFO that's not
406 * already queued to hw */
407 e1f_multiframe_empty_head(&e1->rx.fifo);
408 break;
409
410 default:
411 /* Huh ... hope for the best */
412 printf("[!] E1 TX start while not stopped ...\n");
413 }
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100414
415 /* Update CRs */
416 _e1_update_cr_val(port);
417
418 e1_regs->rx.csr = e1->rx.cr.val | E1_RX_CR_OVFL_CLR;
419 e1_regs->tx.csr = e1->tx.cr.val | E1_TX_CR_UNFL_CLR;
420}
421
422void
423e1_stop(int port)
424{
425 struct e1_state *e1 = _get_state(port);
426
427 /* Flow state */
428 e1->rx.state = SHUTDOWN;
429 e1->tx.state = SHUTDOWN;
430
431 /* Nothing else to do, e1_poll will stop submitting data and
432 * transition to IDLE when everything in-flight is done */
433}
434
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200435unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100436e1_rx_need_data(int port, unsigned int usb_addr, unsigned int max_frames, unsigned int *pos)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200437{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100438 struct e1_state *e1 = _get_state(port);
Harald Welte51baa362022-01-01 15:22:25 +0100439 bool rai_received = false;
440 bool rai_possible = false;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200441 unsigned int ofs;
442 int tot_frames = 0;
Harald Welte51baa362022-01-01 15:22:25 +0100443 int n_frames, i;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200444
445 while (max_frames) {
446 /* Get some data from the FIFO */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100447 n_frames = e1f_frame_read(&e1->rx.fifo, &ofs, max_frames);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200448 if (!n_frames)
449 break;
450
Harald Weltedaff4f62020-12-14 17:39:23 +0100451 /* Give pos */
452 if (pos) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100453 *pos = ofs & e1->rx.fifo.mask;
Harald Weltedaff4f62020-12-14 17:39:23 +0100454 pos = NULL;
455 }
456
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200457 /* Copy from FIFO to USB */
458 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), false, NULL, NULL);
459
460 /* Prepare Next */
461 usb_addr += n_frames * (32 / 4);
462 max_frames -= n_frames;
463 tot_frames += n_frames;
464
Harald Welte51baa362022-01-01 15:22:25 +0100465 /* While DMA is running: Determine if remote end indicates any alarms */
466 for (i = 0; i < n_frames; i++) {
467 unsigned int frame_nr = ofs + i;
468 /* A bit is present in every odd frame TS0 */
469 if (frame_nr & 1) {
470 uint8_t ts0 = *e1_data_ptr(0, ofs + i, 0);
471 rai_possible = true;
472 if (ts0 & 0x20) {
473 rai_received = true;
474 break;
475 }
476 }
477 }
478
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200479 /* Wait for DMA completion */
480 while (dma_poll());
481 }
482
Harald Welte51baa362022-01-01 15:22:25 +0100483 if (rai_possible) {
484 if (rai_received) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100485 e1->errors.flags |= E1_ERR_F_RAI;
486 e1_platform_led_set(port, E1P_LED_YELLOW, E1P_LED_ST_ON);
Harald Welte51baa362022-01-01 15:22:25 +0100487 } else {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100488 e1->errors.flags &= ~E1_ERR_F_RAI;
489 e1_platform_led_set(port, E1P_LED_YELLOW, E1P_LED_ST_OFF);
Harald Welte51baa362022-01-01 15:22:25 +0100490 }
491 }
492
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200493 return tot_frames;
494}
495
496unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100497e1_tx_feed_data(int port, unsigned int usb_addr, unsigned int frames)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200498{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100499 struct e1_state *e1 = _get_state(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200500 unsigned int ofs;
501 int n_frames;
502
503 while (frames) {
504 /* Get some space in FIFO */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100505 n_frames = e1f_frame_write(&e1->tx.fifo, &ofs, frames);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200506 if (!n_frames) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100507 printf("[!] TX FIFO Overflow (port=%d, req=%d, done=%d)\n", port, frames, n_frames);
508 e1f_debug(&e1->tx.fifo, "TX");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200509 break;
510 }
511
512 /* Copy from USB to FIFO */
513 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), true, NULL, NULL);
514
515 /* Prepare next */
516 usb_addr += n_frames * (32 / 4);
517 frames -= n_frames;
518
519 /* Wait for DMA completion */
520 while (dma_poll());
521 }
522
523 return frames;
524}
525
526unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100527e1_rx_level(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200528{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100529 struct e1_state *e1 = _get_state(port);
530 return e1f_valid_frames(&e1->rx.fifo);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200531}
532
Sylvain Munaut4fd71552022-01-10 12:28:28 +0100533unsigned int
534e1_tx_level(int port)
535{
536 struct e1_state *e1 = _get_state(port);
537 return e1f_valid_frames(&e1->tx.fifo);
538}
539
Harald Welte805f2cf2020-12-14 17:31:03 +0100540const struct e1_error_count *
Sylvain Munaut3da51512022-01-03 22:12:59 +0100541e1_get_error_count(int port)
Harald Welte805f2cf2020-12-14 17:31:03 +0100542{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100543 struct e1_state *e1 = _get_state(port);
544 return &e1->errors;
Harald Welte805f2cf2020-12-14 17:31:03 +0100545}
546
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200547void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100548e1_poll(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200549{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100550 volatile struct e1_core *e1_regs = _get_regs(port);
551 struct e1_state *e1 = _get_state(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200552 uint32_t bd;
553 unsigned int ofs;
554
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200555 /* HACK: LED link status */
Harald Welte52765672020-12-15 18:35:42 +0100556 if (e1_regs->rx.csr & E1_RX_SR_ALIGNED) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100557 e1_platform_led_set(port, E1P_LED_GREEN, E1P_LED_ST_ON);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200558 led_color(0, 48, 0);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100559 e1->errors.flags &= ~(E1_ERR_F_LOS|E1_ERR_F_ALIGN_ERR);
Harald Welte52765672020-12-15 18:35:42 +0100560 } else {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100561 e1_platform_led_set(port, E1P_LED_GREEN, E1P_LED_ST_BLINK);
Sylvain Munautd6737bb2022-01-06 22:00:50 +0100562 e1_platform_led_set(port, E1P_LED_YELLOW, E1P_LED_ST_OFF);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200563 led_color(48, 0, 0);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100564 e1->errors.flags |= E1_ERR_F_ALIGN_ERR;
Harald Welte805f2cf2020-12-14 17:31:03 +0100565 /* TODO: completely off if rx tick counter not incrementing */
Harald Welte52765672020-12-15 18:35:42 +0100566 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200567
Sylvain Munaute98c0332022-01-10 12:46:49 +0100568 /* Active ? */
569 if ((e1->rx.state == IDLE) && (e1->tx.state == IDLE))
570 return;
571
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200572 /* Recover any done TX BD */
573 while ( (bd = e1_regs->tx.bd) & E1_BD_VALID ) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100574 e1f_multiframe_read_discard(&e1->tx.fifo);
575 e1->tx.in_flight--;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200576 }
577
578 /* Recover any done RX BD */
579 while ( (bd = e1_regs->rx.bd) & E1_BD_VALID ) {
580 /* FIXME: CRC status ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100581 e1f_multiframe_write_commit(&e1->rx.fifo);
Harald Welte805f2cf2020-12-14 17:31:03 +0100582 if ((bd & (E1_BD_CRC0 | E1_BD_CRC1)) != (E1_BD_CRC0 | E1_BD_CRC1)) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100583 printf("[!] E1 crc err (port=%d, bd=%03x)\n", port, bd);
584 e1->errors.crc++;
Harald Welte805f2cf2020-12-14 17:31:03 +0100585 }
Sylvain Munaut3da51512022-01-03 22:12:59 +0100586 e1->rx.in_flight--;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200587 }
588
589 /* Boot procedure */
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100590 if (e1->tx.state == STARTING) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100591 if (e1f_unseen_frames(&e1->tx.fifo) < (16 * 5))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200592 return;
593 /* HACK: LED flow status */
594 led_blink(true, 200, 1000);
595 led_breathe(true, 100, 200);
596 }
597
598 /* Handle RX */
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100599 /* Bypass if OFF */
600 if (e1->rx.state == IDLE)
601 goto done_rx;
602
603 /* Shutdown */
604 if (e1->rx.state == SHUTDOWN) {
605 if (e1->rx.in_flight == 0) {
606 e1->rx.state = IDLE;
607 _e1_update_cr_val(port);
608 e1_regs->rx.csr = e1->rx.cr.val;
609 }
610 goto done_rx;
611 }
612
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200613 /* Misalign ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100614 if (e1->rx.state == RUN) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200615 if (!(e1_regs->rx.csr & E1_RX_SR_ALIGNED)) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100616 printf("[!] E1 rx misalign (port=%d)\n", port);
617 e1->rx.state = RECOVER;
618 e1->errors.align++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200619 }
620 }
621
622 /* Overflow ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100623 if (e1->rx.state == RUN) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200624 if (e1_regs->rx.csr & E1_RX_SR_OVFL) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100625 printf("[!] E1 overflow (port=%d, inf=%d)\n", port, e1->rx.in_flight);
626 e1->rx.state = RECOVER;
627 e1->errors.ovfl++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200628 }
629 }
630
631 /* Recover ready ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100632 if (e1->rx.state == RECOVER) {
633 if (e1->rx.in_flight != 0)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200634 goto done_rx;
Sylvain Munautd8f33aa2022-01-13 13:17:54 +0100635 e1f_multiframe_empty_tail(&e1->rx.fifo);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200636 }
637
638 /* Fill new RX BD */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100639 while (e1->rx.in_flight < 4) {
640 if (!e1f_multiframe_write_prepare(&e1->rx.fifo, &ofs))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200641 break;
642 e1_regs->rx.bd = e1f_ofs_to_mf(ofs);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100643 e1->rx.in_flight++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200644 }
645
646 /* Clear overflow if needed */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100647 if (e1->rx.state != RUN) {
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100648 e1_regs->rx.csr = e1->rx.cr.val | E1_RX_CR_OVFL_CLR;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100649 e1->rx.state = RUN;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200650 }
651done_rx:
652
653 /* Handle TX */
Sylvain Munaut0cc16132022-01-10 13:26:15 +0100654 /* Bypass if OFF */
655 if (e1->tx.state == IDLE)
656 return;
657
658 /* Shutdown */
659 if (e1->tx.state == SHUTDOWN) {
660 if (e1->tx.in_flight == 0) {
661 e1->tx.state = IDLE;
662 _e1_update_cr_val(port);
663 e1_regs->tx.csr = e1->tx.cr.val;
664 }
665 return;
666 }
667
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200668 /* Underflow ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100669 if (e1->tx.state == RUN) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200670 if (e1_regs->tx.csr & E1_TX_SR_UNFL) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100671 printf("[!] E1 underflow (port=%d, inf=%d)\n", port, e1->tx.in_flight);
672 e1->tx.state = RECOVER;
673 e1->errors.unfl++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200674 }
675 }
676
677 /* Recover ready ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100678 if (e1->tx.state == RECOVER) {
679 if (e1f_unseen_frames(&e1->tx.fifo) < (16 * 5))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200680 return;
681 }
682
683 /* Fill new TX BD */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100684 while (e1->tx.in_flight < 4) {
685 if (!e1f_multiframe_read_peek(&e1->tx.fifo, &ofs))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200686 break;
687 e1_regs->tx.bd = e1f_ofs_to_mf(ofs);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100688 e1->tx.in_flight++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200689 }
690
691 /* Clear underflow if needed */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100692 if (e1->tx.state != RUN) {
Sylvain Munaut9410bdf2022-01-10 13:18:19 +0100693 e1_regs->tx.csr = e1->tx.cr.val | E1_TX_CR_UNFL_CLR;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100694 e1->tx.state = RUN;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200695 }
696}
697
698void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100699e1_debug_print(int port, bool data)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200700{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100701 volatile struct e1_core *e1_regs = _get_regs(port);
702 struct e1_state *e1 = _get_state(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200703 volatile uint8_t *p;
704
Sylvain Munaut3da51512022-01-03 22:12:59 +0100705 printf("E1 port %d\n", port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200706 printf("CSR: Rx %04x / Tx %04x\n", e1_regs->rx.csr, e1_regs->tx.csr);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100707 printf("InF: Rx %d / Tx %d\n", e1->rx.in_flight, e1->tx.in_flight);
708 printf("Sta: Rx %d / Tx %d\n", e1->rx.state, e1->tx.state);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200709
Sylvain Munaut3da51512022-01-03 22:12:59 +0100710 e1f_debug(&e1->rx.fifo, "Rx FIFO");
711 e1f_debug(&e1->tx.fifo, "Tx FIFO");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200712
713 if (data) {
714 puts("\nE1 Data\n");
715 for (int f=0; f<16; f++) {
716 p = e1_data_ptr(0, f, 0);
717 for (int ts=0; ts<32; ts++)
718 printf(" %02x", p[ts]);
719 printf("\n");
720 }
721 }
722}