1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
//! `embassy-net` adapter over `rpi-hal`'s USB-Ethernet drivers: a queue
//! pair for the stack
//! ([`EthernetDriver`](crate::ethernet::EthernetDriver)) and a task that
//! moves frames between those queues and the chip's bulk endpoints
//! ([`EthernetRunner`](crate::ethernet::EthernetRunner)). Build both with
//! [`new`](crate::ethernet::new).
//!
//! Generic over
//! [`EthernetAsync`](rpi_hal::usb::ethernet::EthernetAsync), so the same
//! adapter serves a Pi 2B/3B's LAN9514 and a 3B+'s LAN7800 — which are
//! different chips with nothing in common below that trait. A board that
//! names its chip can keep doing so through
//! [`crate::lan9514`], which is this module under the older spelling.
//!
//! # Why it is split in two
//!
//! `embassy_net_driver::Driver`'s `receive`/`transmit` are synchronous —
//! they return tokens and take a `Context`, so there is nowhere inside
//! them to `.await`. A `Driver` implemented directly over the chip
//! therefore could not use the driver's `async` methods at all, however
//! async those methods were; it would have to do its USB work with the
//! blocking ones, holding the executor for the length of every transfer.
//!
//! `embassy-net-driver-channel` is the way out, and the one `cyw43` and
//! friends take: the `Driver` the stack sees becomes a pair of packet
//! queues, which need no `.await` to serve, and the USB work moves into a
//! task on the far side of them, free to await as much as it likes.
//!
//! # Why two host channels
//!
//! [`new`](crate::ethernet::new) takes two `Channel`s, and the runner
//! keeps a receive parked on one for as long as the network is idle. A
//! single channel would have to be taken away from that parked receive
//! every time the stack wanted to transmit — cancelling a transfer the
//! chip may be part-way through answering, and losing the frame with it.
//! Two channels let the directions proceed independently, which is how
//! the endpoints are meant to be driven: they are separate pipes, and the
//! controller schedules eight of them.
//!
//! # What an application must provide
//!
//! The runner resolves nothing without the USB controller's interrupt.
//! On top of the wiring the crate root already asks for, an application
//! using this must enable that interrupt (`Lic::enable_usb_irq`,
//! `rpi_hal::irq::enable_irq`) and dispatch it from its `__irq_handler`
//! to `rpi_hal::usb::dwc2::on_irq`. Without it the runner's receive parks
//! forever and no frame is ever delivered.
//!
//! That is the whole of the contract. In particular there is nothing to
//! poll: the receive is interrupt-driven, so no ticker, no wake-up
//! interval, and no latency-versus-wake-ups trade for the application to
//! guess at.
//!
//! Available only with the `embassy-net-driver` feature enabled.
use ;
use join;
use ;
use embassy_net_driver_channel as ch;
use Timer;
use ;
use ;
/// How long the runner waits for the link after bringing the chip up,
/// in microseconds, before telling the stack it has one anyway.
///
/// Five seconds: auto-negotiation from a reset is two or three, and the
/// cost of overrunning is only that a board with no cable takes this long
/// to start failing DHCP — which it was going to do regardless.
const LINK_WAIT_US: u64 = 5_000_000;
/// Largest Ethernet frame the queues carry, in bytes.
///
/// Fixed here rather than taken from each driver's
/// [`Ethernet::MTU`](rpi_hal::usb::ethernet::Ethernet::MTU),
/// because `ch::State` takes it as a const generic and `E::MTU` is not
/// usable in that position on stable Rust. Every driver this adapter
/// serves declares the same 1514, and [`new`] asserts it — so the
/// constraint is checked rather than assumed, and a future chip with a
/// different frame size fails loudly here instead of quietly truncating.
///
/// It is also what makes a board able to swap one interface for another
/// under a live stack: `ch::Device<'_, MTU>` differs by this parameter, so
/// a shared value is what keeps the two interchangeable.
pub const MTU: usize = 1514;
/// The packet queues [`new`] builds a
/// [`EthernetDriver`] and [`EthernetRunner`] out of, with room for `N_RX`
/// received and `N_TX` outbound frames.
///
/// An application owns this — typically in a `StaticCell` — because both
/// halves borrow from it for as long as the network stack runs. Depth is
/// the application's call: more buffers absorb a longer burst, at one
/// [`MTU`] each.
/// The `embassy_net_driver::Driver` half — what goes to
/// `embassy_net::new`.
///
/// It is the queue pair itself, and is synchronous by design: the frames
/// it hands the stack were fetched by [`EthernetRunner`] before the stack
/// ever asked, which is the whole reason the split exists.
pub type EthernetDriver<'d> = Device;
/// The half that talks to the hardware: an endless task moving frames
/// between [`EthernetDriver`]'s queues and the chip's bulk endpoints.
///
/// Created by [`new`] and driven by [`run`](EthernetRunner::run), which an
/// application spawns as its own task.
/// What the interface should be brought up as.
///
/// The runner does the bring-up itself (see [`new`]), so anything the
/// caller used to set on the driver beforehand has to arrive here instead.
///
/// Named for the module rather than called `Config`, which would collide
/// with `embassy_net::Config` in every file that uses both — and every
/// consumer of this adapter uses both.
/// Wraps an Ethernet controller as an `embassy-net` device, returning the
/// [`EthernetDriver`] to hand to `embassy_net::new` and the
/// [`EthernetRunner`] to spawn.
///
/// **`ethernet` must be enumerated and configured but *not* started.**
/// The runner calls [`EthernetAsync::start_async`] itself, on its first
/// pass, which is why [`EthernetConfig`] exists to carry what the caller would
/// otherwise have set beforehand.
///
/// That is deliberate and worth the awkwardness of handing over an
/// unfinished thing. A driver may configure the chip's answer to an empty
/// bulk IN differently between its blocking and awaited bring-ups —
/// parking a receive needs a NAK, polling one needs the opposite — and
/// starting it with the blocking
/// [`Ethernet::start`](rpi_hal::usb::ethernet::Ethernet::start) and then
/// running it here is neither a compile error nor a failure. It is a
/// receive that never parks, so this runner spins the executor for the
/// life of the interface while every frame still arrives. Owning the
/// bring-up is what makes that unreachable rather than documented.
///
/// `rx_channel` and `tx_channel` are two host channels the runner takes
/// for itself, one per direction — see this module's documentation for
/// why it is two and not one. They are owned rather than borrowed so the
/// controller's remaining channels stay free for other endpoints (a
/// keyboard polled from another task, say) while the stack runs.
/// Puts a chip behind a queue pair somebody else built, returning the
/// runner to spawn.
///
/// [`new`] is this with the queue pair built for you, and is what a board
/// with one fixed interface wants. This exists for a board that has more
/// than one and picks between them — Ethernet if a cable is in, Wi-Fi
/// otherwise. There the [`EthernetState`] has to outlive any particular
/// choice, so it is created once, up where the choosing happens, and
/// whichever interface wins is attached to it.
///
/// That matters because the queue pair is where the stack's world ends.
/// `embassy_net::Stack` is built around the [`EthernetDriver`] half and
/// holds its sockets and buffers on that side; everything chip-specific is
/// on this one. A board that owns the pair can therefore keep one stack
/// across a change of interface, where a board that let each adapter build
/// its own would have to tear the stack down and lose every socket with
/// it.
///
/// `runner` comes from `embassy_net_driver_channel::new` with the same MAC
/// [`EthernetConfig::mac`] carries — one is what the stack answers ARP
/// with, the other is what gets programmed into the chip, and they have to
/// agree.
/// Hands every frame the chip produces to the stack's receive queue.
///
/// A transfer that yields nothing usable — an empty answer, or an error —
/// is simply asked again. The stack's recovery is the same either way, and
/// stopping the loop would take the interface down for what is routinely a
/// transient.
///
/// Both outcomes are counted rather than merely ignored; see [`rx_stats`].
async !
/// Frames [`receive_forever`] has delivered to the stack since boot.
static RX_FRAMES: AtomicU32 = new;
/// Transfers that produced no usable frame — see [`RxStats::unusable`].
static RX_UNUSABLE: AtomicU32 = new;
/// Transfers that carried more than one frame — see [`RxStats::batched`].
static RX_BATCHED: AtomicU32 = new;
/// Widest gap yet seen with no receive transfer pending, in microseconds.
static GAP_MAX_US: AtomicU32 = new;
/// Gaps wider than [`GAP_LONG_US`].
static GAP_LONG: AtomicU32 = new;
/// Gaps at least this wide are counted, not just recorded as a maximum.
///
/// A hundred microseconds is about ten frames' worth of arrival time at
/// 100 Mbit for the small frames this matters for — acknowledgements. Below
/// that a gap cannot plausibly overrun the chip; above it, it can.
const GAP_LONG_US: u64 = 100;
/// Notes one gap between a transfer completing and the next being issued.
///
/// A maximum and a count rather than a mean: the loss this measures is
/// caused by the *worst* gaps, and an average dominated by thousands of
/// microsecond-wide ones would hide exactly the outliers that matter.
/// Receive transfers that failed outright.
static RX_FAILURES: AtomicU32 = new;
/// [`error_code`] of the most recent receive failure, or [`NO_ERROR`].
static RX_LAST_ERROR: AtomicU8 = new;
/// What the receive loop has managed since boot.
///
/// Returned by [`rx_stats`].
/// What the receive loop has managed since boot.
///
/// The counterpart to [`tx_stats`], and for the same reason: a frame lost on
/// the way in is as invisible as one lost on the way out, and it is the
/// harder of the two to reason about from outside. A lost acknowledgement
/// does not lose data — it stalls the sender until its retransmission timer
/// fires, so the cost lands on a connection that is working perfectly and
/// looks it.
/// Sends every frame the stack queues.
///
/// A failed send is dropped, and the buffer released either way, or the
/// queue would wedge on the first failure. Retransmission is left to the
/// layer above, which owns a timer for it.
///
/// That dropped frame is counted rather than merely discarded — see
/// [`tx_stats`] for why a silent one is worth this much bookkeeping.
async !
/// Frames [`transmit_forever`] has handed to the chip since boot.
static TX_FRAMES: AtomicU32 = new;
/// How many of those the chip refused.
static TX_FAILURES: AtomicU32 = new;
/// [`error_code`] of the most recent failure, or [`NO_ERROR`].
static TX_LAST_ERROR: AtomicU8 = new;
/// [`TX_LAST_ERROR`] before anything has failed.
///
/// Zero rather than a variant's code so that "nothing has gone wrong" is the
/// value the counter starts at.
const NO_ERROR: u8 = 0;
/// What the transmit loop has managed since boot.
///
/// Returned by [`tx_stats`]. Counters, not a rate: an application decides
/// what interval to compare two readings over.
/// What the transmit loop has managed since boot.
///
/// Exists because a frame this adapter drops is otherwise invisible. The
/// stack is told the send succeeded, the chip never sees the frame, and the
/// only trace is the peer's retransmission timeout some hundreds of
/// milliseconds later — so the symptom presents as latency with no
/// corresponding error anywhere, which is a hard thing to go looking for
/// without a number to look at.
///
/// Cheap enough to leave enabled: three relaxed atomic operations per frame,
/// against a USB transfer.
/// Packs a [`TransferError`] into a byte, so the last one can live in an
/// atomic.
///
/// A `match` rather than a `as` cast: [`TransferError`] carries no explicit
/// discriminants, so casting would silently renumber the codes if a variant
/// were ever inserted, and a stored code would then decode as the wrong
/// error.
/// The inverse of [`error_code`]. Anything unrecognised — including
/// [`NO_ERROR`] — is `None`.
/// [`error_code`] of the failure that stopped bring-up, or [`NO_ERROR`].
static START_LAST_ERROR: AtomicU8 = new;
/// Why the interface failed to start, or `None` if it did not fail.
///
/// `Some` here and a link that never comes up are the same event seen from
/// two places. The runner attempts the bring-up once and then parks, so
/// this does not change afterwards — and unlike the receive and transmit
/// counters, a value here means the interface never carried a frame at
/// all rather than that it dropped some.
///
/// Also set, non-fatally, if the multicast filter could not be configured
/// (see [`EthernetConfig::all_multicast`]). That case leaves the interface working
/// for everything except the traffic that filter would have passed, which
/// is worth being able to tell apart from a total failure — the link state
/// is what distinguishes them.