zynq7000_hal/eth/
embassy_net.rs

1//! Embassy-net driver for the Zynq 7000 ethernet peripheral.
2use core::sync::atomic::AtomicBool;
3
4pub use crate::eth::smoltcp::DescriptorsAndBuffers;
5use crate::eth::smoltcp::{SmoltcpRxToken, SmoltcpTxToken};
6pub use crate::eth::{EthernetId, InterruptResult};
7use embassy_sync::waitqueue::AtomicWaker;
8
9pub(crate) static TX_WAKER: AtomicWaker = AtomicWaker::new();
10pub(crate) static RX_WAKER: AtomicWaker = AtomicWaker::new();
11
12static LINK_WAKER: AtomicWaker = AtomicWaker::new();
13static LINK_STATE: AtomicBool = AtomicBool::new(false);
14
15/// This interrupt handler should be called when a Gigabit Ethernet interrupt occurs.
16///
17/// It also handles embassy-net related waking up of tasks via  wakers.
18pub fn on_interrupt(eth_id: EthernetId) -> InterruptResult {
19    super::on_interrupt(eth_id, true, true)
20}
21
22#[inline]
23pub fn link_state() -> embassy_net_driver::LinkState {
24    match LINK_STATE.load(core::sync::atomic::Ordering::Relaxed) {
25        true => embassy_net_driver::LinkState::Up,
26        false => embassy_net_driver::LinkState::Down,
27    }
28}
29
30pub fn update_link_state(new_state: embassy_net_driver::LinkState) {
31    let new_value = match new_state {
32        embassy_net_driver::LinkState::Up => true,
33        embassy_net_driver::LinkState::Down => false,
34    };
35    if LINK_STATE.swap(new_value, core::sync::atomic::Ordering::Relaxed) != new_value {
36        LINK_WAKER.wake();
37    }
38}
39
40pub struct Driver(super::smoltcp::CommonSmoltcpDriver);
41
42impl Driver {
43    pub fn new(eth: &super::Ethernet, mac_addr: [u8; 6], bufs: DescriptorsAndBuffers) -> Self {
44        let tx_burst_len = bufs.tx_burst_len();
45        Self(super::smoltcp::CommonSmoltcpDriver::new(
46            eth.id(),
47            mac_addr,
48            bufs,
49            tx_burst_len,
50        ))
51    }
52}
53
54impl embassy_net_driver::Driver for Driver {
55    type RxToken<'a>
56        = SmoltcpRxToken<'a>
57    where
58        Self: 'a;
59
60    type TxToken<'a>
61        = SmoltcpTxToken<'a>
62    where
63        Self: 'a;
64
65    fn receive(
66        &mut self,
67        cx: &mut core::task::Context,
68    ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
69        RX_WAKER.register(cx.waker());
70        TX_WAKER.register(cx.waker());
71        self.0.receive()
72    }
73
74    fn transmit(&mut self, cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> {
75        TX_WAKER.register(cx.waker());
76        self.0.transmit()
77    }
78
79    fn link_state(&mut self, cx: &mut core::task::Context) -> embassy_net_driver::LinkState {
80        LINK_WAKER.register(cx.waker());
81        link_state()
82    }
83
84    fn capabilities(&self) -> embassy_net_driver::Capabilities {
85        let mut capabilities = embassy_net_driver::Capabilities::default();
86        capabilities.max_transmission_unit = super::MTU;
87        capabilities.max_burst_size = Some(self.0.burst_size);
88        capabilities.checksum.ipv4 = embassy_net_driver::Checksum::Both;
89        capabilities.checksum.udp = embassy_net_driver::Checksum::Both;
90        capabilities.checksum.tcp = embassy_net_driver::Checksum::Both;
91        capabilities.checksum.icmpv4 = embassy_net_driver::Checksum::None;
92        capabilities.checksum.icmpv6 = embassy_net_driver::Checksum::None;
93        capabilities
94    }
95
96    fn hardware_address(&self) -> embassy_net_driver::HardwareAddress {
97        embassy_net_driver::HardwareAddress::Ethernet(self.0.mac_addr)
98    }
99}