blob: a9feea0b5c2d3f05d1e7acae5f042df109d0a024 [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
61e1f_reset(struct e1_fifo *fifo, unsigned int base, unsigned int len)
62{
63 memset(fifo, 0x00, sizeof(struct e1_fifo));
64 fifo->base = base;
65 fifo->mask = len - 1;
66}
67
68static unsigned int
69e1f_allocd_frames(struct e1_fifo *fifo)
70{
71 /* Number of frames that are allocated (i.e. where we can't write to) */
72 return (fifo->wptr[1] - fifo->rptr[0]) & fifo->mask;
73}
74
75static unsigned int
76e1f_valid_frames(struct e1_fifo *fifo)
77{
78 /* Number of valid frames */
79 return (fifo->wptr[0] - fifo->rptr[0]) & fifo->mask;
80}
81
82static unsigned int
83e1f_unseen_frames(struct e1_fifo *fifo)
84{
85 /* Number of valid frames that haven't been peeked yet */
86 return (fifo->wptr[0] - fifo->rptr[1]) & fifo->mask;
87}
88
89static unsigned int
90e1f_free_frames(struct e1_fifo *fifo)
91{
92 /* Number of frames that aren't allocated */
93 return (fifo->rptr[0] - fifo->wptr[1] - 1) & fifo->mask;
94}
95
96static unsigned int
97e1f_ofs_to_dma(unsigned int ofs)
98{
99 /* DMA address are 32-bits word address. Offsets are 32 byte address */
100 return (ofs << 3);
101}
102
103static unsigned int
104e1f_ofs_to_mf(unsigned int ofs)
105{
106 /* E1 Buffer Descriptors are always multiframe aligned */
107 return (ofs >> 4);
108}
109
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200110 /* Debug */
111static void
112e1f_debug(struct e1_fifo *fifo, const char *name)
113{
114 unsigned int la, lv, lu, lf;
115
116 la = e1f_allocd_frames(fifo);
117 lv = e1f_valid_frames(fifo);
118 lu = e1f_unseen_frames(fifo);
119 lf = e1f_free_frames(fifo);
120
121 printf("%s: R: %u / %u | W: %u / %u | A:%u V:%u U:%u F:%u\n",
122 name,
123 fifo->rptr[0], fifo->rptr[1], fifo->wptr[0], fifo->wptr[1],
124 la, lv, lu, lf
125 );
126}
127
128 /* Frame level read/write */
129static unsigned int
130e1f_frame_write(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
131{
132 unsigned int lf, le;
133
134 lf = e1f_free_frames(fifo);
135 le = fifo->mask - fifo->wptr[0] + 1;
136
137 if (max_frames > le)
138 max_frames = le;
139 if (max_frames > lf)
140 max_frames = lf;
141
142 *ofs = fifo->base + fifo->wptr[0];
143 fifo->wptr[1] = fifo->wptr[0] = (fifo->wptr[0] + max_frames) & fifo->mask;
144
145 return max_frames;
146}
147
148static unsigned int
Sylvain Munautde20fb72020-10-29 13:24:50 +0100149e1f_frame_read(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200150{
151 unsigned int lu, le;
152
153 lu = e1f_unseen_frames(fifo);
154 le = fifo->mask - fifo->rptr[1] + 1;
155
156 if (max_frames > le)
157 max_frames = le;
158 if (max_frames > lu)
159 max_frames = lu;
160
161 *ofs = fifo->base + fifo->rptr[1];
162 fifo->rptr[0] = fifo->rptr[1] = (fifo->rptr[1] + max_frames) & fifo->mask;
163
164 return max_frames;
165}
166
167
168 /* MultiFrame level split read/write */
169static bool
170e1f_multiframe_write_prepare(struct e1_fifo *fifo, unsigned int *ofs)
171{
172 unsigned int lf;
173
174 lf = e1f_free_frames(fifo);
175 if (lf < 16)
176 return false;
177
178 *ofs = fifo->base + fifo->wptr[1];
179 fifo->wptr[1] = (fifo->wptr[1] + 16) & fifo->mask;
180
181 return true;
182}
183
184static void
185e1f_multiframe_write_commit(struct e1_fifo *fifo)
186{
187 fifo->wptr[0] = (fifo->wptr[0] + 16) & fifo->mask;
188}
189
190static bool
191e1f_multiframe_read_peek(struct e1_fifo *fifo, unsigned int *ofs)
192{
193 unsigned int lu;
194
195 lu = e1f_unseen_frames(fifo);
196 if (lu < 16)
197 return false;
198
199 *ofs = fifo->base + fifo->rptr[1];
200 fifo->rptr[1] = (fifo->rptr[1] + 16) & fifo->mask;
201
202 return true;
203}
204
205static void
206e1f_multiframe_read_discard(struct e1_fifo *fifo)
207{
208 fifo->rptr[0] = (fifo->rptr[0] + 16) & fifo->mask;
209}
210
211static void
212e1f_multiframe_empty(struct e1_fifo *fifo)
213{
214 fifo->rptr[0] = fifo->rptr[1] = (fifo->wptr[0] & ~15);
215}
216
217
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200218// Main logic
219// ----------
220
221enum e1_pipe_state {
Harald Welte30fc5602020-12-14 15:56:28 +0100222 IDLE = 0, /* not yet initialized */
223 BOOT = 1, /* after e1_init(), regiters are programmed */
224 RUN = 2, /* normal operation */
225 RECOVER = 3, /* after underflow, overflow or alignment error */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200226};
227
Sylvain Munaut3da51512022-01-03 22:12:59 +0100228struct e1_state {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200229 struct {
230 uint32_t cr;
231 struct e1_fifo fifo;
232 int in_flight;
233 enum e1_pipe_state state;
234 } rx;
235
236 struct {
237 uint32_t cr;
238 struct e1_fifo fifo;
239 int in_flight;
240 enum e1_pipe_state state;
241 } tx;
Sylvain Munaut2c0c1362022-01-03 18:48:08 +0100242
Harald Welte805f2cf2020-12-14 17:31:03 +0100243 struct e1_error_count errors;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100244};
245
246static struct e1_state g_e1[2];
247
248
249static volatile struct e1_core *
250_get_regs(int port)
251{
252 if ((port < 0) || (port > 1))
253 panic("_get_regs invalid port %d", port);
254 return &e1_regs_base[port];
255}
256
257static struct e1_state *
258_get_state(int port)
259{
260 if ((port < 0) || (port > 1))
261 panic("_get_state invalid port %d", port);
262 return &g_e1[port];
263}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200264
265
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200266void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100267e1_init(int port, uint16_t rx_cr, uint16_t tx_cr)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200268{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100269 volatile struct e1_core *e1_regs = _get_regs(port);
270 struct e1_state *e1 = _get_state(port);
271
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200272 /* Global state init */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100273 memset(e1, 0x00, sizeof(struct e1_state));
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200274
275 /* Reset FIFOs */
Sylvain Munaut2de84f82022-01-06 08:12:04 +0100276 e1f_reset(&e1->rx.fifo, (512 * port) + 0, 256);
277 e1f_reset(&e1->tx.fifo, (512 * port) + 256, 256);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200278
279 /* Enable Rx */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100280 e1->rx.cr = E1_RX_CR_ENABLE | rx_cr;
281 e1_regs->rx.csr = E1_RX_CR_OVFL_CLR | e1->rx.cr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200282
283 /* Enable Tx */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100284 e1->tx.cr = E1_TX_CR_ENABLE | tx_cr;
285 e1_regs->tx.csr = E1_TX_CR_UNFL_CLR | e1->tx.cr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200286
287 /* State */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100288 e1->rx.state = BOOT;
289 e1->tx.state = BOOT;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200290}
291
Harald Welte6add0aa2020-12-16 00:02:11 +0100292#define TXCR_PERMITTED ( \
Sylvain Munautab75c942022-01-10 12:22:41 +0100293 E1_TX_CR_MODE_MASK | \
294 E1_TX_CR_TICK_MASK | \
295 E1_TX_CR_ALARM | \
Harald Welte6add0aa2020-12-16 00:02:11 +0100296 E1_TX_CR_LOOPBACK | \
Sylvain Munautab75c942022-01-10 12:22:41 +0100297 E1_TX_CR_LOOPBACK_CROSS )
Harald Welte6add0aa2020-12-16 00:02:11 +0100298
299void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100300e1_tx_config(int port, uint16_t cr)
Harald Welte6add0aa2020-12-16 00:02:11 +0100301{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100302 volatile struct e1_core *e1_regs = _get_regs(port);
303 struct e1_state *e1 = _get_state(port);
304 e1->tx.cr = (e1->tx.cr & ~TXCR_PERMITTED) | (cr & TXCR_PERMITTED);
305 e1_regs->tx.csr = e1->tx.cr;
Harald Welte6add0aa2020-12-16 00:02:11 +0100306}
307
308#define RXCR_PERMITTED ( \
Sylvain Munautab75c942022-01-10 12:22:41 +0100309 E1_RX_CR_MODE_MASK )
Harald Welte6add0aa2020-12-16 00:02:11 +0100310
311void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100312e1_rx_config(int port, uint16_t cr)
Harald Welte6add0aa2020-12-16 00:02:11 +0100313{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100314 volatile struct e1_core *e1_regs = _get_regs(port);
315 struct e1_state *e1 = _get_state(port);
316 e1->rx.cr = (e1->rx.cr & ~RXCR_PERMITTED) | (cr & RXCR_PERMITTED);
317 e1_regs->rx.csr = e1->rx.cr;
Harald Welte6add0aa2020-12-16 00:02:11 +0100318}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200319
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200320unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100321e1_rx_need_data(int port, unsigned int usb_addr, unsigned int max_frames, unsigned int *pos)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200322{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100323 struct e1_state *e1 = _get_state(port);
Harald Welte51baa362022-01-01 15:22:25 +0100324 bool rai_received = false;
325 bool rai_possible = false;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200326 unsigned int ofs;
327 int tot_frames = 0;
Harald Welte51baa362022-01-01 15:22:25 +0100328 int n_frames, i;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200329
330 while (max_frames) {
331 /* Get some data from the FIFO */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100332 n_frames = e1f_frame_read(&e1->rx.fifo, &ofs, max_frames);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200333 if (!n_frames)
334 break;
335
Harald Weltedaff4f62020-12-14 17:39:23 +0100336 /* Give pos */
337 if (pos) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100338 *pos = ofs & e1->rx.fifo.mask;
Harald Weltedaff4f62020-12-14 17:39:23 +0100339 pos = NULL;
340 }
341
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200342 /* Copy from FIFO to USB */
343 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), false, NULL, NULL);
344
345 /* Prepare Next */
346 usb_addr += n_frames * (32 / 4);
347 max_frames -= n_frames;
348 tot_frames += n_frames;
349
Harald Welte51baa362022-01-01 15:22:25 +0100350 /* While DMA is running: Determine if remote end indicates any alarms */
351 for (i = 0; i < n_frames; i++) {
352 unsigned int frame_nr = ofs + i;
353 /* A bit is present in every odd frame TS0 */
354 if (frame_nr & 1) {
355 uint8_t ts0 = *e1_data_ptr(0, ofs + i, 0);
356 rai_possible = true;
357 if (ts0 & 0x20) {
358 rai_received = true;
359 break;
360 }
361 }
362 }
363
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200364 /* Wait for DMA completion */
365 while (dma_poll());
366 }
367
Harald Welte51baa362022-01-01 15:22:25 +0100368 if (rai_possible) {
369 if (rai_received) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100370 e1->errors.flags |= E1_ERR_F_RAI;
371 e1_platform_led_set(port, E1P_LED_YELLOW, E1P_LED_ST_ON);
Harald Welte51baa362022-01-01 15:22:25 +0100372 } else {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100373 e1->errors.flags &= ~E1_ERR_F_RAI;
374 e1_platform_led_set(port, E1P_LED_YELLOW, E1P_LED_ST_OFF);
Harald Welte51baa362022-01-01 15:22:25 +0100375 }
376 }
377
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200378 return tot_frames;
379}
380
381unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100382e1_tx_feed_data(int port, unsigned int usb_addr, unsigned int frames)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200383{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100384 struct e1_state *e1 = _get_state(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200385 unsigned int ofs;
386 int n_frames;
387
388 while (frames) {
389 /* Get some space in FIFO */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100390 n_frames = e1f_frame_write(&e1->tx.fifo, &ofs, frames);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200391 if (!n_frames) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100392 printf("[!] TX FIFO Overflow (port=%d, req=%d, done=%d)\n", port, frames, n_frames);
393 e1f_debug(&e1->tx.fifo, "TX");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200394 break;
395 }
396
397 /* Copy from USB to FIFO */
398 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), true, NULL, NULL);
399
400 /* Prepare next */
401 usb_addr += n_frames * (32 / 4);
402 frames -= n_frames;
403
404 /* Wait for DMA completion */
405 while (dma_poll());
406 }
407
408 return frames;
409}
410
411unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100412e1_tx_level(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200413{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100414 struct e1_state *e1 = _get_state(port);
415 return e1f_valid_frames(&e1->tx.fifo);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200416}
417
418unsigned int
Sylvain Munaut3da51512022-01-03 22:12:59 +0100419e1_rx_level(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200420{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100421 struct e1_state *e1 = _get_state(port);
422 return e1f_valid_frames(&e1->rx.fifo);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200423}
424
Harald Welte805f2cf2020-12-14 17:31:03 +0100425const struct e1_error_count *
Sylvain Munaut3da51512022-01-03 22:12:59 +0100426e1_get_error_count(int port)
Harald Welte805f2cf2020-12-14 17:31:03 +0100427{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100428 struct e1_state *e1 = _get_state(port);
429 return &e1->errors;
Harald Welte805f2cf2020-12-14 17:31:03 +0100430}
431
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200432void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100433e1_poll(int port)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200434{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100435 volatile struct e1_core *e1_regs = _get_regs(port);
436 struct e1_state *e1 = _get_state(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200437 uint32_t bd;
438 unsigned int ofs;
439
440 /* Active ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100441 if ((e1->rx.state == IDLE) && (e1->tx.state == IDLE))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200442 return;
443
444 /* HACK: LED link status */
Harald Welte52765672020-12-15 18:35:42 +0100445 if (e1_regs->rx.csr & E1_RX_SR_ALIGNED) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100446 e1_platform_led_set(port, E1P_LED_GREEN, E1P_LED_ST_ON);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200447 led_color(0, 48, 0);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100448 e1->errors.flags &= ~(E1_ERR_F_LOS|E1_ERR_F_ALIGN_ERR);
Harald Welte52765672020-12-15 18:35:42 +0100449 } else {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100450 e1_platform_led_set(port, E1P_LED_GREEN, E1P_LED_ST_BLINK);
Sylvain Munautd6737bb2022-01-06 22:00:50 +0100451 e1_platform_led_set(port, E1P_LED_YELLOW, E1P_LED_ST_OFF);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200452 led_color(48, 0, 0);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100453 e1->errors.flags |= E1_ERR_F_ALIGN_ERR;
Harald Welte805f2cf2020-12-14 17:31:03 +0100454 /* TODO: completely off if rx tick counter not incrementing */
Harald Welte52765672020-12-15 18:35:42 +0100455 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200456
457 /* Recover any done TX BD */
458 while ( (bd = e1_regs->tx.bd) & E1_BD_VALID ) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100459 e1f_multiframe_read_discard(&e1->tx.fifo);
460 e1->tx.in_flight--;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200461 }
462
463 /* Recover any done RX BD */
464 while ( (bd = e1_regs->rx.bd) & E1_BD_VALID ) {
465 /* FIXME: CRC status ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100466 e1f_multiframe_write_commit(&e1->rx.fifo);
Harald Welte805f2cf2020-12-14 17:31:03 +0100467 if ((bd & (E1_BD_CRC0 | E1_BD_CRC1)) != (E1_BD_CRC0 | E1_BD_CRC1)) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100468 printf("[!] E1 crc err (port=%d, bd=%03x)\n", port, bd);
469 e1->errors.crc++;
Harald Welte805f2cf2020-12-14 17:31:03 +0100470 }
Sylvain Munaut3da51512022-01-03 22:12:59 +0100471 e1->rx.in_flight--;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200472 }
473
474 /* Boot procedure */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100475 if (e1->tx.state == BOOT) {
476 if (e1f_unseen_frames(&e1->tx.fifo) < (16 * 5))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200477 return;
478 /* HACK: LED flow status */
479 led_blink(true, 200, 1000);
480 led_breathe(true, 100, 200);
481 }
482
483 /* Handle RX */
484 /* Misalign ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100485 if (e1->rx.state == RUN) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200486 if (!(e1_regs->rx.csr & E1_RX_SR_ALIGNED)) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100487 printf("[!] E1 rx misalign (port=%d)\n", port);
488 e1->rx.state = RECOVER;
489 e1->errors.align++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200490 }
491 }
492
493 /* Overflow ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100494 if (e1->rx.state == RUN) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200495 if (e1_regs->rx.csr & E1_RX_SR_OVFL) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100496 printf("[!] E1 overflow (port=%d, inf=%d)\n", port, e1->rx.in_flight);
497 e1->rx.state = RECOVER;
498 e1->errors.ovfl++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200499 }
500 }
501
502 /* Recover ready ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100503 if (e1->rx.state == RECOVER) {
504 if (e1->rx.in_flight != 0)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200505 goto done_rx;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100506 e1f_multiframe_empty(&e1->rx.fifo);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200507 }
508
509 /* Fill new RX BD */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100510 while (e1->rx.in_flight < 4) {
511 if (!e1f_multiframe_write_prepare(&e1->rx.fifo, &ofs))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200512 break;
513 e1_regs->rx.bd = e1f_ofs_to_mf(ofs);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100514 e1->rx.in_flight++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200515 }
516
517 /* Clear overflow if needed */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100518 if (e1->rx.state != RUN) {
519 e1_regs->rx.csr = e1->rx.cr | E1_RX_CR_OVFL_CLR;
520 e1->rx.state = RUN;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200521 }
522done_rx:
523
524 /* Handle TX */
525 /* Underflow ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100526 if (e1->tx.state == RUN) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200527 if (e1_regs->tx.csr & E1_TX_SR_UNFL) {
Sylvain Munaut3da51512022-01-03 22:12:59 +0100528 printf("[!] E1 underflow (port=%d, inf=%d)\n", port, e1->tx.in_flight);
529 e1->tx.state = RECOVER;
530 e1->errors.unfl++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200531 }
532 }
533
534 /* Recover ready ? */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100535 if (e1->tx.state == RECOVER) {
536 if (e1f_unseen_frames(&e1->tx.fifo) < (16 * 5))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200537 return;
538 }
539
540 /* Fill new TX BD */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100541 while (e1->tx.in_flight < 4) {
542 if (!e1f_multiframe_read_peek(&e1->tx.fifo, &ofs))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200543 break;
544 e1_regs->tx.bd = e1f_ofs_to_mf(ofs);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100545 e1->tx.in_flight++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200546 }
547
548 /* Clear underflow if needed */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100549 if (e1->tx.state != RUN) {
550 e1_regs->tx.csr = e1->tx.cr | E1_TX_CR_UNFL_CLR;
551 e1->tx.state = RUN;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200552 }
553}
554
555void
Sylvain Munaut3da51512022-01-03 22:12:59 +0100556e1_debug_print(int port, bool data)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200557{
Sylvain Munaut3da51512022-01-03 22:12:59 +0100558 volatile struct e1_core *e1_regs = _get_regs(port);
559 struct e1_state *e1 = _get_state(port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200560 volatile uint8_t *p;
561
Sylvain Munaut3da51512022-01-03 22:12:59 +0100562 printf("E1 port %d\n", port);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200563 printf("CSR: Rx %04x / Tx %04x\n", e1_regs->rx.csr, e1_regs->tx.csr);
Sylvain Munaut3da51512022-01-03 22:12:59 +0100564 printf("InF: Rx %d / Tx %d\n", e1->rx.in_flight, e1->tx.in_flight);
565 printf("Sta: Rx %d / Tx %d\n", e1->rx.state, e1->tx.state);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200566
Sylvain Munaut3da51512022-01-03 22:12:59 +0100567 e1f_debug(&e1->rx.fifo, "Rx FIFO");
568 e1f_debug(&e1->tx.fifo, "Tx FIFO");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200569
570 if (data) {
571 puts("\nE1 Data\n");
572 for (int f=0; f<16; f++) {
573 p = e1_data_ptr(0, f, 0);
574 for (int ts=0; ts<32; ts++)
575 printf(" %02x", p[ts]);
576 printf("\n");
577 }
578 }
579}