1use crate::event_manager::LiteXEventManager;
12use crate::litex_registers::{LiteXSoCRegisterConfiguration, Read, Write};
13use core::cell::Cell;
14use core::slice;
15use kernel::debug;
16use kernel::utilities::cells::{OptionalCell, TakeCell};
17use kernel::utilities::StaticRef;
18use kernel::ErrorCode;
19
20const LITEETH_TX_EVENT: usize = 0;
23const LITEETH_RX_EVENT: usize = 0;
24
25type LiteEthRXEV<'a, R> = LiteXEventManager<
26 'a,
27 u8,
28 <R as LiteXSoCRegisterConfiguration>::ReadOnly8,
29 <R as LiteXSoCRegisterConfiguration>::ReadWrite8,
30 <R as LiteXSoCRegisterConfiguration>::ReadWrite8,
31>;
32type LiteEthTXEV<'a, R> = LiteEthRXEV<'a, R>;
33
34#[repr(C)]
35pub struct LiteEthMacRegisters<R: LiteXSoCRegisterConfiguration> {
36 rx_slot: R::ReadOnly8,
38 rx_length: R::ReadOnly32,
40 rx_errors: R::ReadOnly32,
42 rx_ev_status: R::ReadOnly8,
44 rx_ev_pending: R::ReadWrite8,
45 rx_ev_enable: R::ReadWrite8,
46
47 tx_start: R::ReadWrite8,
49 tx_ready: R::ReadOnly8,
50 tx_level: R::ReadOnly8,
51 tx_slot: R::ReadWrite8,
52 tx_length: R::ReadWrite16,
54 tx_ev_status: R::ReadOnly8,
56 tx_ev_pending: R::ReadWrite8,
57 tx_ev_enable: R::ReadWrite8,
58
59 preamble_crc: R::ReadWrite8,
61 preamble_errors: R::ReadOnly8,
63 crc_errors: R::ReadOnly32,
65}
66
67impl<R: LiteXSoCRegisterConfiguration> LiteEthMacRegisters<R> {
68 fn rx_ev(&self) -> LiteEthRXEV<'_, R> {
69 LiteEthRXEV::<R>::new(&self.rx_ev_status, &self.rx_ev_pending, &self.rx_ev_enable)
70 }
71
72 fn tx_ev(&self) -> LiteEthTXEV<'_, R> {
73 LiteEthTXEV::<R>::new(&self.tx_ev_status, &self.tx_ev_pending, &self.tx_ev_enable)
74 }
75}
76
77pub trait LiteEthClient {
78 fn tx_done(&self, rc: Result<(), ErrorCode>, packet_buffer: &'static mut [u8]);
79 fn rx_packet(&self, packet: &'static mut [u8], len: usize);
80}
81
82pub struct LiteEth<'a, R: LiteXSoCRegisterConfiguration> {
83 mac_regs: StaticRef<LiteEthMacRegisters<R>>,
84 mac_memory_base: usize,
85 mac_memory_len: usize,
86 slot_size: usize,
87 rx_slots: usize,
88 tx_slots: usize,
89 client: OptionalCell<&'a dyn LiteEthClient>,
90 tx_packet: TakeCell<'static, [u8]>,
91 rx_buffer: TakeCell<'static, [u8]>,
92 initialized: Cell<bool>,
93}
94
95impl<'a, R: LiteXSoCRegisterConfiguration> LiteEth<'a, R> {
96 pub unsafe fn new(
97 mac_regs: StaticRef<LiteEthMacRegisters<R>>,
98 mac_memory_base: usize,
99 mac_memory_len: usize,
100 slot_size: usize,
101 rx_slots: usize,
102 tx_slots: usize,
103 rx_buffer: &'static mut [u8],
104 ) -> LiteEth<'a, R> {
105 LiteEth {
106 mac_regs,
107 mac_memory_base,
108 mac_memory_len,
109 slot_size,
110 rx_slots,
111 tx_slots,
112 client: OptionalCell::empty(),
113 tx_packet: TakeCell::empty(),
114 rx_buffer: TakeCell::new(rx_buffer),
115 initialized: Cell::new(false),
116 }
117 }
118
119 pub fn set_client(&self, client: &'a dyn LiteEthClient) {
120 self.client.set(client);
121 }
122
123 pub fn initialize(&self) {
124 assert!(
132 (self.rx_slots + self.tx_slots) * self.slot_size <= self.mac_memory_len,
133 "LiteEth: slots would exceed assigned MAC memory area"
134 );
135
136 assert!(self.rx_slots > 0, "LiteEth: no RX slot");
137 assert!(self.tx_slots > 0, "LiteEth: no TX slot");
138
139 self.mac_regs.rx_ev().clear_event(LITEETH_RX_EVENT);
141 self.mac_regs.tx_ev().clear_event(LITEETH_TX_EVENT);
142
143 self.mac_regs.tx_ev().disable_event(LITEETH_TX_EVENT);
145
146 self.mac_regs.rx_ev().enable_event(LITEETH_RX_EVENT);
148
149 self.initialized.set(true);
150 }
151
152 unsafe fn get_slot_buffer(&self, tx: bool, slot_id: usize) -> Option<&mut [u8]> {
153 if (tx && slot_id > self.tx_slots) || (!tx && slot_id > self.rx_slots) {
154 return None;
155 }
156
157 let slots_offset = if tx {
158 self.mac_memory_base + self.slot_size * self.rx_slots
159 } else {
160 self.mac_memory_base
161 };
162
163 let slot_addr = slots_offset + slot_id * self.slot_size;
164 Some(slice::from_raw_parts_mut(
165 slot_addr as *mut u8,
166 self.slot_size,
167 ))
168 }
169
170 pub fn return_rx_buffer(&self, rx_buffer: &'static mut [u8]) {
171 assert!(
173 self.rx_buffer.is_none(),
174 "LiteEth: return RX buffer while one is registered"
175 );
176
177 self.rx_buffer.replace(rx_buffer);
179
180 self.mac_regs.rx_ev().enable_event(LITEETH_RX_EVENT);
183 }
184
185 fn rx_interrupt(&self) {
186 if self.rx_buffer.is_none() {
190 self.mac_regs.rx_ev().disable_event(LITEETH_RX_EVENT);
191 } else {
192 let rx_buffer = self.rx_buffer.take().unwrap();
194
195 let pkt_len = self.mac_regs.rx_length.get() as usize;
198 if pkt_len > rx_buffer.len() {
199 debug!("LiteEth: discarding ethernet packet with len {}", pkt_len);
200
201 self.mac_regs.rx_ev().clear_event(LITEETH_RX_EVENT);
203
204 self.rx_buffer.replace(rx_buffer);
206 } else {
207 let slot_id: usize = self.mac_regs.rx_slot.get().into();
209
210 let slot = unsafe {
212 self.get_slot_buffer(false, slot_id).unwrap() };
214
215 rx_buffer[..pkt_len].copy_from_slice(&slot[..pkt_len]);
217
218 self.mac_regs.rx_ev().clear_event(LITEETH_RX_EVENT);
221
222 self.client
223 .map(move |client| client.rx_packet(rx_buffer, pkt_len));
224 }
225 }
226 }
227
228 pub fn transmit(
234 &self,
235 packet: &'static mut [u8],
236 len: usize,
237 ) -> Result<(), (Result<(), ErrorCode>, &'static mut [u8])> {
238 if packet.len() < len || len > u16::MAX as usize {
239 return Err((Err(ErrorCode::INVAL), packet));
240 }
241
242 if self.tx_packet.is_some() {
243 return Err((Err(ErrorCode::BUSY), packet));
244 }
245
246 let slot = unsafe { self.get_slot_buffer(true, 0) }.unwrap(); if slot.len() < len {
248 return Err((Err(ErrorCode::SIZE), packet));
249 }
250
251 slot[..len].copy_from_slice(&packet[..len]);
253
254 self.tx_packet.replace(packet);
257
258 self.mac_regs.tx_slot.set(0);
260 self.mac_regs.tx_length.set(len as u16);
261
262 while self.mac_regs.tx_ready.get() == 0 {}
264
265 self.mac_regs.tx_ev().enable_event(LITEETH_TX_EVENT);
267
268 self.mac_regs.tx_start.set(1);
270
271 Ok(())
272 }
273
274 fn tx_interrupt(&self) {
275 self.mac_regs.tx_ev().clear_event(LITEETH_TX_EVENT);
277
278 if self.tx_packet.is_none() {
279 debug!("LiteEth: tx interrupt called without tx_packet set");
280 }
281
282 let packet = self.tx_packet.take().unwrap(); self.client
285 .map(move |client| client.tx_done(Ok(()), packet));
286 }
287
288 pub fn service_interrupt(&self) {
289 if self.mac_regs.rx_ev().event_asserted(LITEETH_RX_EVENT) {
294 self.rx_interrupt();
295 }
296
297 if self.mac_regs.tx_ev().event_asserted(LITEETH_TX_EVENT) {
298 self.tx_interrupt();
299 }
300 }
301}