1use crate::event_manager::LiteXEventManager;
11use crate::litex_registers::{LiteXSoCRegisterConfiguration, Read, Write};
12use core::cell::Cell;
13use core::slice;
14use kernel::debug;
15use kernel::hil::ethernet::{EthernetAdapterDatapath, EthernetAdapterDatapathClient};
16use kernel::utilities::cells::{MapCell, 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,
51 tx_level: R::ReadOnly8,
53 tx_slot: R::ReadWrite8,
55 tx_length: R::ReadWrite16,
57 tx_ev_status: R::ReadOnly8,
59 tx_ev_pending: R::ReadWrite8,
60 tx_ev_enable: R::ReadWrite8,
61
62 preamble_crc: R::ReadWrite8,
64 preamble_errors: R::ReadOnly8,
66 crc_errors: R::ReadOnly32,
68}
69
70impl<R: LiteXSoCRegisterConfiguration> LiteEthMacRegisters<R> {
71 fn rx_ev(&self) -> LiteEthRXEV<'_, R> {
72 LiteEthRXEV::<R>::new(&self.rx_ev_status, &self.rx_ev_pending, &self.rx_ev_enable)
73 }
74
75 fn tx_ev(&self) -> LiteEthTXEV<'_, R> {
76 LiteEthTXEV::<R>::new(&self.tx_ev_status, &self.tx_ev_pending, &self.tx_ev_enable)
77 }
78}
79
80pub struct LiteEth<'a, const MAX_TX_SLOTS: usize, R: LiteXSoCRegisterConfiguration> {
81 mac_regs: StaticRef<LiteEthMacRegisters<R>>,
82 mac_memory_base: usize,
83 mac_memory_len: usize,
84 slot_size: usize,
85 rx_slots: usize,
86 tx_slots: usize,
87 client: OptionalCell<&'a dyn EthernetAdapterDatapathClient>,
88 tx_frame: TakeCell<'static, [u8]>,
89 tx_frame_info: MapCell<[(usize, u16); MAX_TX_SLOTS]>,
90 initialized: Cell<bool>,
91}
92
93impl<const MAX_TX_SLOTS: usize, R: LiteXSoCRegisterConfiguration> LiteEth<'_, MAX_TX_SLOTS, R> {
94 pub unsafe fn new(
95 mac_regs: StaticRef<LiteEthMacRegisters<R>>,
96 mac_memory_base: usize,
97 mac_memory_len: usize,
98 slot_size: usize,
99 rx_slots: usize,
100 tx_slots: usize,
101 ) -> Self {
102 LiteEth {
103 mac_regs,
104 mac_memory_base,
105 mac_memory_len,
106 slot_size,
107 rx_slots,
108 tx_slots,
109 client: OptionalCell::empty(),
110 tx_frame: TakeCell::empty(),
111 tx_frame_info: MapCell::new([(0, 0); MAX_TX_SLOTS]),
112 initialized: Cell::new(false),
113 }
114 }
115
116 pub fn initialize(&self) {
117 assert!(
124 (self.rx_slots + self.tx_slots) * self.slot_size <= self.mac_memory_len,
125 "LiteEth: slots would exceed assigned MAC memory area"
126 );
127
128 assert!(self.rx_slots > 0, "LiteEth: no RX slot");
129 assert!(self.tx_slots > 0, "LiteEth: no TX slot");
130
131 assert!(
134 MAX_TX_SLOTS >= self.tx_slots,
135 "LiteEth: MAX_TX_SLOTS ({}) must be larger or equal to tx_slots ({})",
136 MAX_TX_SLOTS,
137 self.tx_slots,
138 );
139
140 self.mac_regs.tx_ev().disable_event(LITEETH_TX_EVENT);
142
143 while self.mac_regs.rx_ev().event_pending(LITEETH_RX_EVENT) {
149 self.mac_regs.rx_ev().clear_event(LITEETH_RX_EVENT);
150 }
151 while self.mac_regs.tx_ev().event_pending(LITEETH_TX_EVENT) {
152 self.mac_regs.tx_ev().clear_event(LITEETH_TX_EVENT);
153 }
154
155 self.initialized.set(true);
156 }
157
158 unsafe fn get_slot_buffer(&self, tx: bool, slot_id: usize) -> Option<&mut [u8]> {
159 if (tx && slot_id > self.tx_slots) || (!tx && slot_id > self.rx_slots) {
160 return None;
161 }
162
163 let slots_offset = if tx {
164 self.mac_memory_base + self.slot_size * self.rx_slots
165 } else {
166 self.mac_memory_base
167 };
168
169 let slot_addr = slots_offset + slot_id * self.slot_size;
170 Some(slice::from_raw_parts_mut(
171 slot_addr as *mut u8,
172 self.slot_size,
173 ))
174 }
175
176 fn rx_interrupt(&self) {
177 let pkt_len = self.mac_regs.rx_length.get();
179
180 let slot_id: usize = self.mac_regs.rx_slot.get().into();
182
183 let slot = unsafe {
190 self.get_slot_buffer(false, slot_id)
191 .expect("LiteEth: invalid RX slot id")
192 };
193
194 self.client
196 .map(|client| client.received_frame(&slot[..(pkt_len as usize)], None));
197
198 self.mac_regs.rx_ev().clear_event(LITEETH_RX_EVENT);
201 }
202
203 fn tx_interrupt(&self) {
204 self.mac_regs.tx_ev().clear_event(LITEETH_TX_EVENT);
213
214 if self.tx_frame.is_none() {
215 debug!("LiteEth: tx interrupt called without tx_frame set");
216 }
217
218 let frame = self
220 .tx_frame
221 .take()
222 .expect("LiteEth: TakeCell empty in tx callback");
223
224 let slot_id = 0; let (frame_identifier, len) = self
227 .tx_frame_info
228 .map(|pkt_info| pkt_info[slot_id])
229 .unwrap();
230
231 self.client.map(move |client| {
232 client.transmit_frame_done(Ok(()), frame, len, frame_identifier, None)
233 });
234 }
235
236 pub fn service_interrupt(&self) {
237 while self.mac_regs.tx_ev().event_asserted(LITEETH_TX_EVENT) {
241 self.tx_interrupt();
242 }
243
244 while self.mac_regs.rx_ev().event_asserted(LITEETH_RX_EVENT) {
248 self.rx_interrupt();
249 }
250 }
251}
252
253impl<'a, const MAX_TX_SLOTS: usize, R: LiteXSoCRegisterConfiguration> EthernetAdapterDatapath<'a>
254 for LiteEth<'a, MAX_TX_SLOTS, R>
255{
256 fn set_client(&self, client: &'a dyn EthernetAdapterDatapathClient) {
257 self.client.set(client);
258 }
259
260 fn enable_receive(&self) {
261 if !self.initialized.get() {
263 panic!("LiteEth: cannot enable_receive without prior initialization!");
264 }
265
266 self.mac_regs.rx_ev().enable_event(LITEETH_RX_EVENT);
267 }
268
269 fn disable_receive(&self) {
270 self.mac_regs.rx_ev().disable_event(LITEETH_RX_EVENT);
272 }
273
274 fn transmit_frame(
280 &self,
281 frame: &'static mut [u8],
282 len: u16,
283 frame_identifier: usize,
284 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
285 if frame.len() < (len as usize) {
286 return Err((ErrorCode::INVAL, frame));
287 }
288
289 if self.tx_frame.is_some() {
290 return Err((ErrorCode::BUSY, frame));
291 }
292
293 let slot_id = 0;
295
296 let slot = unsafe { self.get_slot_buffer(true, slot_id) }.expect("LiteEth: no TX slot");
297 if slot.len() < (len as usize) {
298 return Err((ErrorCode::SIZE, frame));
299 }
300
301 self.tx_frame_info
303 .map(|pkt_info| {
304 pkt_info[slot_id] = (frame_identifier, len);
305 })
306 .unwrap();
307
308 slot[..(len as usize)].copy_from_slice(&frame[..(len as usize)]);
310
311 self.tx_frame.replace(frame);
313
314 self.mac_regs.tx_slot.set(0);
316 self.mac_regs.tx_length.set(len);
317
318 while self.mac_regs.tx_ready.get() == 0 {}
320
321 self.mac_regs.tx_ev().enable_event(LITEETH_TX_EVENT);
323
324 self.mac_regs.tx_start.set(1);
326
327 Ok(())
328 }
329}