Skip to main content

eth_intel/e1000/
mod.rs

1extern crate alloc;
2
3use alloc::boxed::Box;
4use core::mem::size_of;
5
6use dma_api::{CoherentArray, DeviceDma, DmaOp};
7use mmio_api::{Mmio, MmioAddr, MmioOp};
8use rdif_eth::{DmaBuffer, Event, IRxQueue, ITxQueue, Interface, NetError, QueueConfig};
9
10use crate::err::{Error, Result};
11
12mod descriptor;
13mod registers;
14
15use descriptor::{RxDesc, TxDesc};
16use registers::*;
17
18const QUEUE_SIZE: usize = 256;
19const QUEUE_ID0: usize = 0;
20const MAX_PACKET: usize = 2048;
21
22pub struct E1000 {
23    regs: Regs,
24    _mmio: Mmio,
25    dma: DeviceDma,
26    mac: [u8; 6],
27    irq_enabled: bool,
28    tx_created: bool,
29    rx_created: bool,
30}
31
32impl E1000 {
33    pub fn check_vid_did(vid: u16, did: u16) -> bool {
34        vid == 0x8086 && [0x100e, 0x100f].contains(&did)
35    }
36
37    pub fn new(
38        bar_addr: impl Into<MmioAddr>,
39        bar_size: usize,
40        dma_mask: u64,
41        dma_op: &'static dyn DmaOp,
42        mmio_op: &'static dyn MmioOp,
43    ) -> Result<Self> {
44        mmio_api::init(mmio_op);
45        let mmio = mmio_api::ioremap(bar_addr.into(), bar_size)?;
46        let regs = Regs::new(mmio.as_nonnull_ptr());
47        let dma = DeviceDma::new_legacy(dma_mask, dma_op);
48
49        regs.reset();
50        regs.disable_all_irq();
51
52        // CTRL.SLU: set link up in software for basic bring-up.
53        regs.write(CTRL, regs.read(CTRL) | (1 << 6));
54
55        let mac = regs.mac_addr();
56
57        Ok(Self {
58            regs,
59            _mmio: mmio,
60            dma,
61            mac,
62            irq_enabled: false,
63            tx_created: false,
64            rx_created: false,
65        })
66    }
67}
68
69impl rdif_eth::DriverGeneric for E1000 {
70    fn name(&self) -> &str {
71        "eth-intel-e1000"
72    }
73}
74
75impl Interface for E1000 {
76    fn mac_address(&self) -> [u8; 6] {
77        self.mac
78    }
79
80    fn create_tx_queue(&mut self) -> Option<Box<dyn ITxQueue>> {
81        if self.tx_created {
82            return None;
83        }
84
85        let desc = self
86            .dma
87            .coherent_array_zero_with_align::<TxDesc>(QUEUE_SIZE, 16)
88            .ok()?;
89
90        let desc_base = desc.dma_addr().as_u64();
91
92        self.regs.write(TDBAL, desc_base as u32);
93        self.regs.write(TDBAH, (desc_base >> 32) as u32);
94        self.regs
95            .write(TDLEN, (QUEUE_SIZE * size_of::<TxDesc>()) as u32);
96        self.regs.write(TDH, 0);
97        self.regs.write(TDT, 0);
98
99        // TCTL.EN + TCTL.PSP + CT + COLD, typical minimal values.
100        self.regs
101            .write(TCTL, (1 << 1) | (1 << 3) | (0x10 << 4) | (0x40 << 12));
102        self.regs.write(TIPG, 10 | (8 << 10) | (6 << 20));
103
104        let queue = E1000TxQueue {
105            regs: self.regs,
106            desc,
107            dma_mask: self.dma.dma_mask(),
108            bus_addrs: [None; QUEUE_SIZE],
109            next_submit: 0,
110            next_reclaim: 0,
111        };
112
113        self.tx_created = true;
114        Some(Box::new(queue))
115    }
116
117    fn create_rx_queue(&mut self) -> Option<Box<dyn IRxQueue>> {
118        if self.rx_created {
119            return None;
120        }
121
122        let desc = self
123            .dma
124            .coherent_array_zero_with_align::<RxDesc>(QUEUE_SIZE, 16)
125            .ok()?;
126
127        let desc_base = desc.dma_addr().as_u64();
128
129        self.regs.write(RDBAL, desc_base as u32);
130        self.regs.write(RDBAH, (desc_base >> 32) as u32);
131        self.regs
132            .write(RDLEN, (QUEUE_SIZE * size_of::<RxDesc>()) as u32);
133        self.regs.write(RDH, 0);
134        self.regs.write(RDT, 0);
135
136        // RCTL.EN + BAM + SECRC (2048-byte buffer mode).
137        self.regs.write(RCTL, (1 << 1) | (1 << 15) | (1 << 26));
138
139        let queue = E1000RxQueue {
140            regs: self.regs,
141            desc,
142            dma_mask: self.dma.dma_mask(),
143            bus_addrs: [None; QUEUE_SIZE],
144            next_submit: 0,
145            next_reclaim: 0,
146        };
147
148        self.rx_created = true;
149        Some(Box::new(queue))
150    }
151
152    fn enable_irq(&mut self) {
153        self.regs.enable_default_irq();
154        self.irq_enabled = true;
155    }
156
157    fn disable_irq(&mut self) {
158        self.regs.disable_all_irq();
159        self.irq_enabled = false;
160    }
161
162    fn is_irq_enabled(&self) -> bool {
163        self.irq_enabled
164    }
165
166    fn handle_irq(&mut self) -> Event {
167        e1000_irq_event(self.regs.read(ICR))
168    }
169
170    fn take_irq_handler(&mut self) -> Option<rdif_eth::BIrqHandler> {
171        Some(Box::new(E1000IrqHandler { regs: self.regs }))
172    }
173}
174
175struct E1000IrqHandler {
176    regs: Regs,
177}
178
179impl rdif_eth::IrqHandler for E1000IrqHandler {
180    fn handle_irq(&mut self) -> Event {
181        e1000_irq_event(self.regs.read(ICR))
182    }
183}
184
185fn e1000_irq_event(icr: u32) -> Event {
186    let mut ev = Event::none();
187
188    if icr & (1 << 0) != 0 {
189        ev.tx_queue.insert(QUEUE_ID0);
190    }
191    if icr & (1 << 7) != 0 {
192        ev.rx_queue.insert(QUEUE_ID0);
193    }
194
195    ev
196}
197
198struct E1000TxQueue {
199    regs: Regs,
200    desc: CoherentArray<TxDesc>,
201    dma_mask: u64,
202    bus_addrs: [Option<u64>; QUEUE_SIZE],
203    next_submit: usize,
204    next_reclaim: usize,
205}
206
207impl ITxQueue for E1000TxQueue {
208    fn id(&self) -> usize {
209        QUEUE_ID0
210    }
211
212    fn config(&self) -> QueueConfig {
213        QueueConfig {
214            dma_mask: self.dma_mask,
215            align: 16,
216            buf_size: MAX_PACKET,
217            ring_size: QUEUE_SIZE,
218        }
219    }
220
221    fn submit(&mut self, buffer: DmaBuffer) -> core::result::Result<(), NetError> {
222        if buffer.len > MAX_PACKET {
223            return Err(NetError::Other(Box::new(Error::InvalidArgument(
224                "tx packet too large",
225            ))));
226        }
227
228        let idx = self.next_submit;
229        let next = (idx + 1) % QUEUE_SIZE;
230        let hw_head = self.regs.read(TDH) as usize;
231
232        if next == hw_head {
233            return Err(NetError::Retry);
234        }
235
236        self.desc
237            .set_cpu(idx, TxDesc::new(buffer.bus_addr, buffer.len as u16));
238        self.bus_addrs[idx] = Some(buffer.bus_addr);
239        self.next_submit = next;
240        self.regs.write(TDT, next as u32);
241
242        Ok(())
243    }
244
245    fn reclaim(&mut self) -> Option<u64> {
246        let idx = self.next_reclaim;
247        let desc = self.desc.read_cpu(idx)?;
248        if !desc.is_done() {
249            return None;
250        }
251
252        self.next_reclaim = (idx + 1) % QUEUE_SIZE;
253        self.bus_addrs[idx].take()
254    }
255}
256
257struct E1000RxQueue {
258    regs: Regs,
259    desc: CoherentArray<RxDesc>,
260    dma_mask: u64,
261    bus_addrs: [Option<u64>; QUEUE_SIZE],
262    next_submit: usize,
263    next_reclaim: usize,
264}
265
266impl IRxQueue for E1000RxQueue {
267    fn id(&self) -> usize {
268        QUEUE_ID0
269    }
270
271    fn config(&self) -> QueueConfig {
272        QueueConfig {
273            dma_mask: self.dma_mask,
274            align: 16,
275            buf_size: MAX_PACKET,
276            ring_size: QUEUE_SIZE,
277        }
278    }
279
280    fn submit(&mut self, buffer: DmaBuffer) -> core::result::Result<(), NetError> {
281        if buffer.len > MAX_PACKET {
282            return Err(NetError::Other(Box::new(Error::InvalidArgument(
283                "rx buffer too large",
284            ))));
285        }
286
287        let idx = self.next_submit;
288        let next = (idx + 1) % QUEUE_SIZE;
289        let hw_head = self.regs.read(RDH) as usize;
290
291        if next == hw_head {
292            return Err(NetError::Retry);
293        }
294
295        self.desc.set_cpu(idx, RxDesc::new(buffer.bus_addr));
296        self.bus_addrs[idx] = Some(buffer.bus_addr);
297        self.next_submit = next;
298        self.regs.write(RDT, next as u32);
299
300        Ok(())
301    }
302
303    fn reclaim(&mut self) -> Option<(u64, usize)> {
304        let idx = self.next_reclaim;
305        let desc = self.desc.read_cpu(idx)?;
306        if !desc.is_done() {
307            return None;
308        }
309
310        self.next_reclaim = (idx + 1) % QUEUE_SIZE;
311        self.bus_addrs[idx]
312            .take()
313            .map(|bus_addr| (bus_addr, desc.length as usize))
314    }
315}