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(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        let mut ev = Event::none();
168        let icr = self.regs.read(ICR);
169
170        if icr & (1 << 0) != 0 {
171            ev.tx_queue.insert(QUEUE_ID0);
172        }
173        if icr & (1 << 7) != 0 {
174            ev.rx_queue.insert(QUEUE_ID0);
175        }
176
177        ev
178    }
179}
180
181struct E1000TxQueue {
182    regs: Regs,
183    desc: CoherentArray<TxDesc>,
184    dma_mask: u64,
185    bus_addrs: [Option<u64>; QUEUE_SIZE],
186    next_submit: usize,
187    next_reclaim: usize,
188}
189
190impl ITxQueue for E1000TxQueue {
191    fn id(&self) -> usize {
192        QUEUE_ID0
193    }
194
195    fn config(&self) -> QueueConfig {
196        QueueConfig {
197            dma_mask: self.dma_mask,
198            align: 16,
199            buf_size: MAX_PACKET,
200            ring_size: QUEUE_SIZE,
201        }
202    }
203
204    fn submit(&mut self, buffer: DmaBuffer) -> core::result::Result<(), NetError> {
205        if buffer.len > MAX_PACKET {
206            return Err(NetError::Other(Box::new(Error::InvalidArgument(
207                "tx packet too large",
208            ))));
209        }
210
211        let idx = self.next_submit;
212        let next = (idx + 1) % QUEUE_SIZE;
213        let hw_head = self.regs.read(TDH) as usize;
214
215        if next == hw_head {
216            return Err(NetError::Retry);
217        }
218
219        self.desc
220            .set_cpu(idx, TxDesc::new(buffer.bus_addr, buffer.len as u16));
221        self.bus_addrs[idx] = Some(buffer.bus_addr);
222        self.next_submit = next;
223        self.regs.write(TDT, next as u32);
224
225        Ok(())
226    }
227
228    fn reclaim(&mut self) -> Option<u64> {
229        let idx = self.next_reclaim;
230        let desc = self.desc.read_cpu(idx)?;
231        if !desc.is_done() {
232            return None;
233        }
234
235        self.next_reclaim = (idx + 1) % QUEUE_SIZE;
236        self.bus_addrs[idx].take()
237    }
238}
239
240struct E1000RxQueue {
241    regs: Regs,
242    desc: CoherentArray<RxDesc>,
243    dma_mask: u64,
244    bus_addrs: [Option<u64>; QUEUE_SIZE],
245    next_submit: usize,
246    next_reclaim: usize,
247}
248
249impl IRxQueue for E1000RxQueue {
250    fn id(&self) -> usize {
251        QUEUE_ID0
252    }
253
254    fn config(&self) -> QueueConfig {
255        QueueConfig {
256            dma_mask: self.dma_mask,
257            align: 16,
258            buf_size: MAX_PACKET,
259            ring_size: QUEUE_SIZE,
260        }
261    }
262
263    fn submit(&mut self, buffer: DmaBuffer) -> core::result::Result<(), NetError> {
264        if buffer.len > MAX_PACKET {
265            return Err(NetError::Other(Box::new(Error::InvalidArgument(
266                "rx buffer too large",
267            ))));
268        }
269
270        let idx = self.next_submit;
271        let next = (idx + 1) % QUEUE_SIZE;
272        let hw_head = self.regs.read(RDH) as usize;
273
274        if next == hw_head {
275            return Err(NetError::Retry);
276        }
277
278        self.desc.set_cpu(idx, RxDesc::new(buffer.bus_addr));
279        self.bus_addrs[idx] = Some(buffer.bus_addr);
280        self.next_submit = next;
281        self.regs.write(RDT, next as u32);
282
283        Ok(())
284    }
285
286    fn reclaim(&mut self) -> Option<(u64, usize)> {
287        let idx = self.next_reclaim;
288        let desc = self.desc.read_cpu(idx)?;
289        if !desc.is_done() {
290            return None;
291        }
292
293        self.next_reclaim = (idx + 1) % QUEUE_SIZE;
294        self.bus_addrs[idx]
295            .take()
296            .map(|bus_addr| (bus_addr, desc.length as usize))
297    }
298}