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 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 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 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}