1use arbitrary_int::{u2, u3};
7pub use zynq7000::eth::MdcClockDivisor;
8use zynq7000::eth::{
9 BurstLength, DmaRxBufSize, GEM_0_BASE_ADDR, GEM_1_BASE_ADDR, InterruptControl, InterruptStatus,
10 MmioEthernet, RxStatus, TxStatus,
11};
12
13pub use ll::{ClockConfig, ClockDivSet, Duplex, EthernetLowLevel, Speed};
14
15pub mod embassy_net;
16pub mod ll;
17pub mod mdio;
18pub mod rx_descr;
19pub mod smoltcp;
20pub mod tx_descr;
21
22pub const MTU: usize = 1536;
23pub const MAX_MDC_SPEED: Hertz = Hertz::from_raw(2_500_000);
24
25#[repr(C, align(32))]
26#[derive(Debug, Clone, Copy)]
27pub struct AlignedBuffer(pub [u8; MTU]);
28
29#[cfg(not(feature = "7z010-7z007s-clg225"))]
30use crate::gpio::mio::{
31 Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27,
32};
33use crate::{
34 clocks::ArmClocks,
35 eth::ll::ClockDivisors,
36 gpio::{
37 IoPeriphPin,
38 mio::{
39 Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39,
40 Mio52, Mio53, MioPin, MuxConfig, Pin,
41 },
42 },
43 time::Hertz,
44};
45
46pub const MUX_CONF_PHY: MuxConfig = MuxConfig::new_with_l0();
47pub const MUX_CONF_MDIO: MuxConfig = MuxConfig::new_with_l3(u3::new(0b100));
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum EthernetId {
51 Eth0 = 0,
52 Eth1 = 1,
53}
54
55impl EthernetId {
56 pub const unsafe fn steal_regs(&self) -> zynq7000::eth::MmioEthernet<'static> {
62 unsafe {
63 match self {
64 EthernetId::Eth0 => zynq7000::eth::Ethernet::new_mmio_fixed_0(),
65 EthernetId::Eth1 => zynq7000::eth::Ethernet::new_mmio_fixed_1(),
66 }
67 }
68 }
69
70 pub fn clk_config_regs(
71 &self,
72 slcr: &mut zynq7000::slcr::MmioSlcr<'static>,
73 ) -> (
74 *mut zynq7000::slcr::clocks::GigEthClockControl,
75 *mut zynq7000::slcr::clocks::GigEthRclkControl,
76 ) {
77 match self {
78 EthernetId::Eth0 => (
79 slcr.clk_ctrl().pointer_to_gem_0_clk_ctrl(),
80 slcr.clk_ctrl().pointer_to_gem_0_rclk_ctrl(),
81 ),
82 EthernetId::Eth1 => (
83 slcr.clk_ctrl().pointer_to_gem_1_clk_ctrl(),
84 slcr.clk_ctrl().pointer_to_gem_1_rclk_ctrl(),
85 ),
86 }
87 }
88}
89
90pub trait PsEthernet {
91 fn reg_block(&self) -> MmioEthernet<'static>;
92 fn id(&self) -> Option<EthernetId>;
93}
94
95impl PsEthernet for MmioEthernet<'static> {
96 #[inline]
97 fn reg_block(&self) -> MmioEthernet<'static> {
98 unsafe { self.clone() }
99 }
100
101 #[inline]
102 fn id(&self) -> Option<EthernetId> {
103 let base_addr = unsafe { self.ptr() } as usize;
104 if base_addr == GEM_0_BASE_ADDR {
105 return Some(EthernetId::Eth0);
106 } else if base_addr == GEM_1_BASE_ADDR {
107 return Some(EthernetId::Eth1);
108 }
109 None
110 }
111}
112
113pub trait TxClockPin: MioPin {
114 const ETH_ID: EthernetId;
115}
116pub trait TxControlPin: MioPin {
117 const ETH_ID: EthernetId;
118}
119pub trait TxData0Pin: MioPin {
120 const ETH_ID: EthernetId;
121}
122pub trait TxData1Pin: MioPin {
123 const ETH_ID: EthernetId;
124}
125pub trait TxData2Pin: MioPin {
126 const ETH_ID: EthernetId;
127}
128pub trait TxData3Pin: MioPin {
129 const ETH_ID: EthernetId;
130}
131pub trait RxClockPin: MioPin {
132 const ETH_ID: EthernetId;
133}
134pub trait RxControlPin: MioPin {
135 const ETH_ID: EthernetId;
136}
137pub trait RxData0Pin: MioPin {
138 const ETH_ID: EthernetId;
139}
140pub trait RxData1Pin: MioPin {
141 const ETH_ID: EthernetId;
142}
143pub trait RxData2Pin: MioPin {
144 const ETH_ID: EthernetId;
145}
146pub trait RxData3Pin: MioPin {
147 const ETH_ID: EthernetId;
148}
149
150pub trait MdClockPin: MioPin {}
151pub trait MdIoPin: MioPin {}
152
153impl MdClockPin for Pin<Mio52> {}
154impl MdIoPin for Pin<Mio53> {}
155
156#[cfg(not(feature = "7z010-7z007s-clg225"))]
157impl TxClockPin for Pin<Mio16> {
158 const ETH_ID: EthernetId = EthernetId::Eth0;
159}
160#[cfg(not(feature = "7z010-7z007s-clg225"))]
161impl TxControlPin for Pin<Mio21> {
162 const ETH_ID: EthernetId = EthernetId::Eth0;
163}
164#[cfg(not(feature = "7z010-7z007s-clg225"))]
165impl TxData0Pin for Pin<Mio17> {
166 const ETH_ID: EthernetId = EthernetId::Eth0;
167}
168#[cfg(not(feature = "7z010-7z007s-clg225"))]
169impl TxData1Pin for Pin<Mio18> {
170 const ETH_ID: EthernetId = EthernetId::Eth0;
171}
172#[cfg(not(feature = "7z010-7z007s-clg225"))]
173impl TxData2Pin for Pin<Mio19> {
174 const ETH_ID: EthernetId = EthernetId::Eth0;
175}
176#[cfg(not(feature = "7z010-7z007s-clg225"))]
177impl TxData3Pin for Pin<Mio20> {
178 const ETH_ID: EthernetId = EthernetId::Eth0;
179}
180#[cfg(not(feature = "7z010-7z007s-clg225"))]
181impl RxClockPin for Pin<Mio22> {
182 const ETH_ID: EthernetId = EthernetId::Eth0;
183}
184#[cfg(not(feature = "7z010-7z007s-clg225"))]
185impl RxControlPin for Pin<Mio27> {
186 const ETH_ID: EthernetId = EthernetId::Eth0;
187}
188#[cfg(not(feature = "7z010-7z007s-clg225"))]
189impl RxData0Pin for Pin<Mio23> {
190 const ETH_ID: EthernetId = EthernetId::Eth0;
191}
192#[cfg(not(feature = "7z010-7z007s-clg225"))]
193impl RxData1Pin for Pin<Mio24> {
194 const ETH_ID: EthernetId = EthernetId::Eth0;
195}
196#[cfg(not(feature = "7z010-7z007s-clg225"))]
197impl RxData2Pin for Pin<Mio25> {
198 const ETH_ID: EthernetId = EthernetId::Eth0;
199}
200#[cfg(not(feature = "7z010-7z007s-clg225"))]
201impl RxData3Pin for Pin<Mio26> {
202 const ETH_ID: EthernetId = EthernetId::Eth0;
203}
204
205impl TxClockPin for Pin<Mio28> {
206 const ETH_ID: EthernetId = EthernetId::Eth1;
207}
208impl TxControlPin for Pin<Mio33> {
209 const ETH_ID: EthernetId = EthernetId::Eth1;
210}
211impl TxData0Pin for Pin<Mio29> {
212 const ETH_ID: EthernetId = EthernetId::Eth1;
213}
214impl TxData1Pin for Pin<Mio30> {
215 const ETH_ID: EthernetId = EthernetId::Eth1;
216}
217impl TxData2Pin for Pin<Mio31> {
218 const ETH_ID: EthernetId = EthernetId::Eth1;
219}
220impl TxData3Pin for Pin<Mio32> {
221 const ETH_ID: EthernetId = EthernetId::Eth1;
222}
223impl RxClockPin for Pin<Mio34> {
224 const ETH_ID: EthernetId = EthernetId::Eth1;
225}
226impl RxControlPin for Pin<Mio39> {
227 const ETH_ID: EthernetId = EthernetId::Eth1;
228}
229impl RxData0Pin for Pin<Mio35> {
230 const ETH_ID: EthernetId = EthernetId::Eth1;
231}
232impl RxData1Pin for Pin<Mio36> {
233 const ETH_ID: EthernetId = EthernetId::Eth1;
234}
235impl RxData2Pin for Pin<Mio37> {
236 const ETH_ID: EthernetId = EthernetId::Eth1;
237}
238impl RxData3Pin for Pin<Mio38> {
239 const ETH_ID: EthernetId = EthernetId::Eth1;
240}
241
242pub fn calculate_mdc_clk_div(arm_clks: &ArmClocks) -> Option<MdcClockDivisor> {
245 let div = arm_clks.cpu_1x_clk().raw().div_ceil(MAX_MDC_SPEED.raw());
246 match div {
247 0..8 => Some(MdcClockDivisor::Div8),
248 8..16 => Some(MdcClockDivisor::Div16),
249 16..32 => Some(MdcClockDivisor::Div32),
250 32..48 => Some(MdcClockDivisor::Div48),
251 48..64 => Some(MdcClockDivisor::Div64),
252 64..96 => Some(MdcClockDivisor::Div96),
253 96..128 => Some(MdcClockDivisor::Div128),
254 128..224 => Some(MdcClockDivisor::Div224),
255 _ => None,
258 }
259}
260
261#[derive(Debug, Clone, Copy)]
262pub struct EthernetConfig {
263 pub clk_config_1000_mbps: ClockConfig,
264 pub mdc_clk_div: MdcClockDivisor,
265 pub mac_address: [u8; 6],
266}
267
268impl EthernetConfig {
269 pub fn new(
271 clk_config_1000_mbps: ClockConfig,
272 mdc_clk_div: MdcClockDivisor,
273 mac_address: [u8; 6],
274 ) -> Self {
275 Self {
276 clk_config_1000_mbps,
277 mdc_clk_div,
278 mac_address,
279 }
280 }
281}
282
283pub struct Ethernet {
285 ll: ll::EthernetLowLevel,
286 mdio: mdio::Mdio,
287 current_speed: Speed,
288 current_duplex: Duplex,
289 current_clk_divs: ClockDivisors,
290}
291
292const IRQ_CONTROL: InterruptControl = InterruptControl::builder()
293 .with_tsu_sec_incr(false)
294 .with_partner_pg_rx(false)
295 .with_auto_negotiation_complete(false)
296 .with_external_interrupt(false)
297 .with_pause_transmitted(false)
298 .with_pause_time_zero(false)
299 .with_pause_with_non_zero_quantum(false)
300 .with_hresp_not_ok(true)
301 .with_rx_overrun(true)
302 .with_link_changed(false)
303 .with_frame_sent(true)
304 .with_tx_frame_corruption_ahb_error(true)
305 .with_tx_retry_limit_reached_or_late_collision(true)
306 .with_tx_descr_read_when_used(true)
307 .with_rx_descr_read_when_used(true)
308 .with_frame_received(true)
309 .with_mgmt_frame_sent(false)
310 .build();
311
312const IRQ_CLEAR_ALL: InterruptStatus = InterruptStatus::builder()
313 .with_tsu_sec_incr(true)
314 .with_partner_pg_rx(true)
315 .with_auto_negotiation_complete(true)
316 .with_external_interrupt(true)
317 .with_pause_transmitted(true)
318 .with_pause_time_zero(true)
319 .with_pause_with_non_zero_quantum(true)
320 .with_hresp_not_ok(true)
321 .with_rx_overrun(true)
322 .with_link_changed(true)
323 .with_frame_sent(true)
324 .with_tx_retry_limit_reached_or_late_collision(true)
325 .with_tx_descr_read_when_used(true)
326 .with_rx_descr_read_when_used(true)
327 .with_frame_received(true)
328 .with_mgmt_frame_sent(true)
329 .build();
330
331impl Ethernet {
332 #[allow(clippy::too_many_arguments)]
335 pub fn new_with_mio<
336 TxClock: TxClockPin,
337 TxControl: TxControlPin,
338 TxData0: TxData0Pin,
339 TxData1: TxData1Pin,
340 TxData2: TxData2Pin,
341 TxData3: TxData3Pin,
342 RxClock: RxClockPin,
343 RxControl: RxControlPin,
344 RxData0: RxData0Pin,
345 RxData1: RxData1Pin,
346 RxData2: RxData2Pin,
347 RxData3: RxData3Pin,
348 MdClock: MdClockPin,
349 MdIo: MdIoPin,
350 >(
351 mut ll: ll::EthernetLowLevel,
352 config: EthernetConfig,
353 tx_clk: TxClock,
354 tx_ctrl: TxControl,
355 tx_data: (TxData0, TxData1, TxData2, TxData3),
356 rx_clk: RxClock,
357 rx_ctrl: RxControl,
358 rx_data: (RxData0, RxData1, RxData2, RxData3),
359 md_pins: Option<(MdClock, MdIo)>,
360 ) -> Self {
361 Self::common_init(&mut ll, config.mac_address);
362 let tx_mio_config = zynq7000::slcr::mio::Config::builder()
363 .with_disable_hstl_rcvr(true)
364 .with_pullup(true)
365 .with_io_type(zynq7000::slcr::mio::IoType::Hstl)
366 .with_speed(zynq7000::slcr::mio::Speed::FastCmosEdge)
367 .with_l3_sel(MUX_CONF_PHY.l3_sel())
368 .with_l2_sel(MUX_CONF_PHY.l2_sel())
369 .with_l1_sel(MUX_CONF_PHY.l1_sel())
370 .with_l0_sel(MUX_CONF_PHY.l0_sel())
371 .with_tri_enable(false)
372 .build();
373 let rx_mio_config = zynq7000::slcr::mio::Config::builder()
374 .with_disable_hstl_rcvr(false)
375 .with_pullup(true)
376 .with_io_type(zynq7000::slcr::mio::IoType::Hstl)
377 .with_speed(zynq7000::slcr::mio::Speed::FastCmosEdge)
378 .with_l3_sel(MUX_CONF_PHY.l3_sel())
379 .with_l2_sel(MUX_CONF_PHY.l2_sel())
380 .with_l1_sel(MUX_CONF_PHY.l1_sel())
381 .with_l0_sel(MUX_CONF_PHY.l0_sel())
382 .with_tri_enable(true)
385 .build();
387 unsafe {
388 crate::slcr::Slcr::with(|slcr_mut| {
389 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
390 tx_clk,
391 slcr_mut,
392 tx_mio_config,
393 );
394 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
395 tx_ctrl,
396 slcr_mut,
397 tx_mio_config,
398 );
399 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
400 tx_data.0,
401 slcr_mut,
402 tx_mio_config,
403 );
404 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
405 tx_data.1,
406 slcr_mut,
407 tx_mio_config,
408 );
409 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
410 tx_data.2,
411 slcr_mut,
412 tx_mio_config,
413 );
414 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
415 tx_data.3,
416 slcr_mut,
417 tx_mio_config,
418 );
419 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
420 rx_clk,
421 slcr_mut,
422 rx_mio_config,
423 );
424 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
425 rx_ctrl,
426 slcr_mut,
427 rx_mio_config,
428 );
429 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
430 rx_data.0,
431 slcr_mut,
432 rx_mio_config,
433 );
434 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
435 rx_data.1,
436 slcr_mut,
437 rx_mio_config,
438 );
439 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
440 rx_data.2,
441 slcr_mut,
442 rx_mio_config,
443 );
444 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
445 rx_data.3,
446 slcr_mut,
447 rx_mio_config,
448 );
449 if let Some((md_clk, md_io)) = md_pins {
450 let md_mio_config = zynq7000::slcr::mio::Config::builder()
451 .with_disable_hstl_rcvr(false)
452 .with_pullup(true)
453 .with_io_type(zynq7000::slcr::mio::IoType::LvCmos18)
454 .with_speed(zynq7000::slcr::mio::Speed::SlowCmosEdge)
455 .with_l3_sel(MUX_CONF_MDIO.l3_sel())
456 .with_l2_sel(MUX_CONF_MDIO.l2_sel())
457 .with_l1_sel(MUX_CONF_MDIO.l1_sel())
458 .with_l0_sel(MUX_CONF_MDIO.l0_sel())
459 .with_tri_enable(false)
460 .build();
461 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
462 md_clk,
463 slcr_mut,
464 md_mio_config,
465 );
466 IoPeriphPin::new_with_full_config_and_unlocked_slcr(
467 md_io,
468 slcr_mut,
469 md_mio_config,
470 );
471 }
472 slcr_mut.gpiob().modify_ctrl(|mut ctrl| {
474 ctrl.set_vref_en(true);
475 ctrl
476 });
477 });
478 }
479 ll.configure_clock(config.clk_config_1000_mbps, true);
480 let mut mdio = mdio::Mdio::new(&ll, true);
481 mdio.configure_clock_div(config.mdc_clk_div);
482 ll.regs.modify_net_ctrl(|mut val| {
483 val.set_management_port_enable(true);
484 val
485 });
486 let mut eth = Ethernet {
487 ll,
488 mdio,
489 current_speed: Speed::Mbps1000,
490 current_duplex: Duplex::Full,
491 current_clk_divs: config.clk_config_1000_mbps.divs,
492 };
493 eth.set_rx_buf_descriptor_base_address(0);
494 eth.set_tx_buf_descriptor_base_address(0);
495 eth
496 }
497
498 pub fn new(mut ll: EthernetLowLevel, config: EthernetConfig) -> Self {
499 Self::common_init(&mut ll, config.mac_address);
500 ll.configure_clock(config.clk_config_1000_mbps, true);
501 let mut mdio = mdio::Mdio::new(&ll, true);
502 mdio.configure_clock_div(config.mdc_clk_div);
503 Ethernet {
504 ll,
505 mdio,
506 current_speed: Speed::Mbps1000,
507 current_duplex: Duplex::Full,
508 current_clk_divs: config.clk_config_1000_mbps.divs,
509 }
510 }
511
512 pub fn start(&mut self) {
516 self.clear_interrupts();
517 self.enable_interrupts();
518 self.ll.regs.modify_net_ctrl(|mut val| {
519 val.set_tx_enable(true);
520 val.set_rx_enable(true);
521 val
522 });
523 }
524
525 #[inline]
527 pub fn speed(&self) -> Speed {
528 self.current_speed
529 }
530
531 #[inline]
533 pub fn duplex(&self) -> Duplex {
534 self.current_duplex
535 }
536
537 pub fn reset(&mut self) {
538 self.ll.reset(3);
539 self.ll.initialize(false);
541 }
542
543 fn common_init(ll: &mut EthernetLowLevel, mac_address: [u8; 6]) {
544 ll.enable_peripheral_clock();
545 ll.reset(3);
546 ll.initialize(true);
547 ll.set_speed_and_duplex(Speed::Mbps1000, Duplex::Full);
550 let macaddr_msbs = (u32::from(mac_address[5]) << 8) | u32::from(mac_address[4]);
551 let macaddr_lsbs = (u32::from(mac_address[3]) << 24)
552 | (u32::from(mac_address[2]) << 16)
553 | (u32::from(mac_address[1]) << 8)
554 | u32::from(mac_address[0]);
555 ll.regs.write_addr1_low(macaddr_lsbs);
559 ll.regs.write_addr1_high(macaddr_msbs);
560 ll.regs.modify_net_cfg(|mut val| {
561 val.set_rx_enable_1536(true);
562 val.set_rx_checksum_enable(true);
563 val.set_no_broadcast(false);
564 val
566 });
567 ll.regs.modify_dma_cfg(|mut val| {
568 val.set_rx_packet_buf_size_sel(u2::new(0b11));
569 val.set_tx_packet_buf_size_sel(true);
570 val.set_chksum_offload_enable(true);
571 val.set_burst_length(BurstLength::Incr16.reg_value());
572 val.set_dma_rx_ahb_buf_size_sel(DmaRxBufSize::new((MTU >> 6) as u8).unwrap());
575 val.set_endian_swap_mgmt_descriptor(zynq7000::eth::AhbEndianess::Little);
576 val.set_endian_swap_packet_data(zynq7000::eth::AhbEndianess::Little);
577 val
578 });
579 }
580
581 #[inline]
582 pub fn clear_interrupts(&mut self) {
583 self.ll.regs.write_interrupt_status(IRQ_CLEAR_ALL);
584 }
585
586 #[inline]
587 pub fn enable_interrupts(&mut self) {
588 self.ll.regs.write_interrupt_enable(IRQ_CONTROL);
589 }
590
591 #[inline]
592 pub fn disable_interrupts(&mut self) {
593 self.ll.regs.write_interrupt_disable(IRQ_CONTROL);
594 }
595
596 #[inline]
597 pub fn ll(&mut self) -> &mut EthernetLowLevel {
598 &mut self.ll
599 }
600
601 #[inline]
602 pub fn regs(&mut self) -> &MmioEthernet<'static> {
603 &self.ll.regs
604 }
605
606 #[inline]
607 pub fn mdio(&mut self) -> &mdio::Mdio {
608 &self.mdio
609 }
610
611 pub fn mdio_mut(&mut self) -> &mut mdio::Mdio {
612 &mut self.mdio
613 }
614
615 #[inline]
616 pub fn regs_mut(&mut self) -> &mut MmioEthernet<'static> {
617 &mut self.ll.regs
618 }
619
620 pub fn configure_clock_and_speed_duplex(
623 &mut self,
624 speed: Speed,
625 duplex: Duplex,
626 clk_collection: &ClockDivSet,
627 ) {
628 if speed == self.current_speed
629 && duplex == self.current_duplex
630 && *clk_collection.clk_divs_for_speed(speed) == self.current_clk_divs
631 {
632 return;
634 }
635 self.ll.set_tx_rx_enable(false, false);
636 self.ll
637 .configure_clock_and_speed_duplex(speed, duplex, clk_collection);
638 self.ll.set_tx_rx_enable(true, true);
639 }
640
641 delegate::delegate! {
642 to self.ll {
643 #[inline]
644 pub const fn id(&self) -> EthernetId;
645
646 #[inline]
647 pub fn set_rx_buf_descriptor_base_address(&mut self, addr: u32);
648
649 #[inline]
650 pub fn set_tx_buf_descriptor_base_address(&mut self, addr: u32);
651
652 #[inline]
653 pub fn set_tx_rx_enable(&mut self, tx_enable: bool, rx_enable: bool);
654 }
655 }
656}
657
658mod shared {
659 #[bitbybit::bitenum(u1, exhaustive = true)]
660 #[derive(Debug, PartialEq, Eq)]
661 pub enum Ownership {
662 Hardware = 0,
663 Software = 1,
664 }
665}
666
667#[derive(Debug, Clone, Copy, Default)]
669pub struct EthErrors {
670 pub rx_overrun: bool,
675 pub hresp_error: bool,
678 pub tx_frame_corruption_ahb_error: bool,
681 pub tx_late_collision: bool,
684 pub tx_retry_limit_reached: bool,
691}
692
693#[derive(Debug, Clone, Copy, Default)]
694pub struct InterruptResult {
695 pub frame_received: bool,
696 pub frame_sent: bool,
697 pub rx_descr_read_when_used: bool,
700 pub tx_descr_read_when_used: bool,
703 pub errors: EthErrors,
705}
706
707impl InterruptResult {
708 #[inline]
709 pub fn has_errors(&self) -> bool {
710 self.errors.rx_overrun
711 || self.errors.hresp_error
712 || self.errors.tx_frame_corruption_ahb_error
713 || self.errors.tx_late_collision
714 || self.errors.tx_retry_limit_reached
715 }
716}
717
718pub(crate) fn on_interrupt(
720 eth_id: EthernetId,
721 wake_embassy_tx: bool,
722 wake_embassy_rx: bool,
723) -> InterruptResult {
724 let mut eth_regs = unsafe { eth_id.steal_regs() };
725 let status = eth_regs.read_interrupt_status();
726 let mut clear = InterruptStatus::new_with_raw_value(0);
727 let mut tx_status_clear = TxStatus::new_with_raw_value(0);
728 let mut rx_status_clear = RxStatus::new_with_raw_value(0);
729 let mut disable = InterruptControl::new_with_raw_value(0);
730 let mut result = InterruptResult::default();
731
732 if status.frame_sent() {
733 if wake_embassy_tx {
734 embassy_net::TX_WAKER.wake();
735 }
736 result.frame_sent = true;
737 tx_status_clear.set_complete(true);
738 clear.set_frame_sent(true);
739 }
740 if status.frame_received() {
741 if wake_embassy_rx {
742 embassy_net::RX_WAKER.wake();
743 }
744 result.frame_received = true;
745 clear.set_frame_received(true);
746 }
747 if status.hresp_not_ok() {
748 result.errors.hresp_error = true;
749 clear.set_hresp_not_ok(true);
750 tx_status_clear.set_hresp_not_ok(true);
751 rx_status_clear.set_hresp_not_ok(true);
752 }
753 if status.tx_retry_limit_reached_or_late_collision() {
754 let tx_status = eth_regs.read_tx_status();
755 if tx_status.late_collision() {
756 result.errors.tx_late_collision = true;
757 tx_status_clear.set_late_collision(true);
758 } else {
759 result.errors.tx_retry_limit_reached = true;
760 tx_status_clear.set_retry_limit_reached(true);
761 }
762 tx_status_clear.set_collision(true);
764 clear.set_tx_retry_limit_reached_or_late_collision(true);
765 }
766 if status.tx_descr_read_when_used() {
767 result.tx_descr_read_when_used = true;
768 clear.set_tx_descr_read_when_used(true);
770 tx_status_clear.set_read_when_used(true);
771 }
772 if status.tx_frame_corruption_ahb_error() {
773 result.errors.tx_frame_corruption_ahb_error = true;
774 tx_status_clear.set_frame_corruption_ahb_error(true);
776 }
777 if status.rx_descr_read_when_used() {
778 result.rx_descr_read_when_used = true;
779 rx_status_clear.set_buf_not_available(true);
781 clear.set_rx_descr_read_when_used(true);
782 }
783 if status.rx_overrun() {
784 if wake_embassy_rx {
785 embassy_net::RX_WAKER.wake();
786 }
787 result.errors.rx_overrun = true;
788 rx_status_clear.set_overrun(true);
789 disable.set_rx_overrun(true);
790 clear.set_rx_overrun(true);
791 }
792 eth_regs.write_interrupt_status(clear);
793 eth_regs.write_interrupt_disable(disable);
794 eth_regs.write_tx_status(tx_status_clear);
795 eth_regs.write_rx_status(rx_status_clear);
796 result
797}