1use core::cell::Cell;
6
7use kernel::utilities::cells::OptionalCell;
8use kernel::utilities::registers::{register_bitfields, LocalRegisterCopy};
9use kernel::ErrorCode;
10
11use super::super::devices::{VirtIODeviceDriver, VirtIODeviceType};
12use super::super::queues::split_queue::{SplitVirtqueue, SplitVirtqueueClient, VirtqueueBuffer};
13
14register_bitfields![u64,
15 VirtIONetFeatures [
16 VirtIONetFCsum OFFSET(0) NUMBITS(1),
17 VirtIONetFGuestCsum OFFSET(1) NUMBITS(1),
18 VirtIONetFCtrlGuestOffloads OFFSET(2) NUMBITS(1),
19 VirtIONetFMtu OFFSET(3) NUMBITS(1),
20 VirtIONetFMac OFFSET(5) NUMBITS(1),
21 VirtIONetFGuestTso4 OFFSET(7) NUMBITS(1),
22 VirtIONetFGuestTso6 OFFSET(8) NUMBITS(1),
23 VirtIONetFGuestEcn OFFSET(9) NUMBITS(1),
24 VirtIONetFGuestUfo OFFSET(10) NUMBITS(1),
25 VirtIONetFHostTso4 OFFSET(11) NUMBITS(1),
26 VirtIONetFHostTso6 OFFSET(12) NUMBITS(1),
27 VirtIONetFHostEcn OFFSET(13) NUMBITS(1),
28 VirtIONetFHostUfo OFFSET(14) NUMBITS(1),
29 VirtIONetFMrgRxbuf OFFSET(15) NUMBITS(1),
30 VirtIONetFStatus OFFSET(16) NUMBITS(1),
31 VirtIONetFCtrlVq OFFSET(17) NUMBITS(1),
32 VirtIONetFCtrlRx OFFSET(18) NUMBITS(1),
33 VirtIONetFCtrlVlan OFFSET(19) NUMBITS(1),
34 VirtIONetFGuestAnnounce OFFSET(21) NUMBITS(1),
35 VirtIONetFMq OFFSET(22) NUMBITS(1),
36 VirtIONetFCtrlMacAddr OFFSET(23) NUMBITS(1),
37 VirtIONetFRscExt OFFSET(61) NUMBITS(1),
40 VirtIONetFStandby OFFSET(62) NUMBITS(1),
41 ]
42];
43
44pub struct VirtIONet<'a> {
45 id: Cell<usize>,
46 rxqueue: &'a SplitVirtqueue<'static, 'static, 2>,
47 txqueue: &'a SplitVirtqueue<'static, 'static, 2>,
48 tx_header: OptionalCell<&'static mut [u8; 12]>,
49 rx_header: OptionalCell<&'static mut [u8]>,
50 rx_buffer: OptionalCell<&'static mut [u8]>,
51 client: OptionalCell<&'a dyn VirtIONetClient>,
52}
53
54impl<'a> VirtIONet<'a> {
55 pub fn new(
56 id: usize,
57 txqueue: &'a SplitVirtqueue<'static, 'static, 2>,
58 tx_header: &'static mut [u8; 12],
59 rxqueue: &'a SplitVirtqueue<'static, 'static, 2>,
60 rx_header: &'static mut [u8],
61 rx_buffer: &'static mut [u8],
62 ) -> VirtIONet<'a> {
63 txqueue.enable_used_callbacks();
64 rxqueue.enable_used_callbacks();
65
66 VirtIONet {
67 id: Cell::new(id),
68 rxqueue,
69 txqueue,
70 tx_header: OptionalCell::new(tx_header),
71 client: OptionalCell::empty(),
72 rx_header: OptionalCell::new(rx_header),
73 rx_buffer: OptionalCell::new(rx_buffer),
74 }
75 }
76
77 pub fn id(&self) -> usize {
78 self.id.get()
79 }
80
81 pub fn set_client(&self, client: &'a dyn VirtIONetClient) {
82 self.client.set(client);
83 }
84
85 pub fn enable_rx(&self) {
90 let rx_buffer = self.rx_buffer.take().unwrap();
92 let rx_buffer_len = rx_buffer.len();
93
94 let mut buffer_chain = [
95 Some(VirtqueueBuffer {
96 buf: self.rx_header.take().unwrap(),
97 len: 12,
98 device_writeable: true,
99 }),
100 Some(VirtqueueBuffer {
101 buf: rx_buffer,
102 len: rx_buffer_len,
103 device_writeable: true,
104 }),
105 ];
106
107 self.rxqueue
108 .provide_buffer_chain(&mut buffer_chain)
109 .unwrap();
110 }
111
112 pub fn return_rx_buffer(&self, buf: &'static mut [u8]) {
113 assert!(self.rx_buffer.is_none());
114 assert!(self.rx_header.is_some());
115 self.rx_buffer.replace(buf);
116
117 self.enable_rx();
119 }
120
121 pub fn send_packet(
122 &self,
123 packet: &'static mut [u8],
124 packet_len: usize,
125 ) -> Result<(), (&'static mut [u8], ErrorCode)> {
126 let mut packet_buf = Some(VirtqueueBuffer {
132 buf: packet,
133 len: packet_len,
134 device_writeable: false,
135 });
136
137 let header_buf = self
138 .tx_header
139 .take()
140 .ok_or(ErrorCode::BUSY)
141 .map_err(|ret| (packet_buf.take().unwrap().buf, ret))?;
142
143 header_buf[0] = 0; header_buf[1] = 0; header_buf[2] = 0; header_buf[3] = 0; header_buf[4] = 0; header_buf[5] = 0; header_buf[6] = 0; header_buf[7] = 0; header_buf[8] = 0; header_buf[9] = 0; header_buf[10] = 0; header_buf[11] = 0; let mut buffer_chain = [
160 Some(VirtqueueBuffer {
161 buf: header_buf,
162 len: 12,
163 device_writeable: false,
164 }),
165 packet_buf.take(),
166 ];
167
168 self.txqueue
169 .provide_buffer_chain(&mut buffer_chain)
170 .map_err(move |ret| (buffer_chain[1].take().unwrap().buf, ret))?;
171
172 Ok(())
173 }
174}
175
176impl SplitVirtqueueClient<'static> for VirtIONet<'_> {
177 fn buffer_chain_ready(
178 &self,
179 queue_number: u32,
180 buffer_chain: &mut [Option<VirtqueueBuffer<'static>>],
181 bytes_used: usize,
182 ) {
183 if queue_number == self.rxqueue.queue_number().unwrap() {
184 let rx_header = buffer_chain[0].take().expect("No header buffer").buf;
187 self.rx_header.replace(rx_header);
189
190 let rx_buffer = buffer_chain[1].take().expect("No rx content buffer").buf;
191 self.client.map(move |client| {
192 client.packet_received(self.id.get(), rx_buffer, bytes_used - 12)
193 });
194 } else if queue_number == self.txqueue.queue_number().unwrap() {
195 let header_buf = buffer_chain[0].take().expect("No header buffer").buf;
198 self.tx_header.replace(header_buf.try_into().unwrap());
199
200 let packet_buf = buffer_chain[1].take().expect("No packet buffer").buf;
201 self.client
202 .map(move |client| client.packet_sent(self.id.get(), packet_buf));
203 } else {
204 panic!("Callback from unknown queue");
205 }
206 }
207}
208
209impl VirtIODeviceDriver for VirtIONet<'_> {
210 fn negotiate_features(&self, offered_features: u64) -> Option<u64> {
211 let offered_features =
212 LocalRegisterCopy::<u64, VirtIONetFeatures::Register>::new(offered_features);
213 let mut negotiated_features = LocalRegisterCopy::<u64, VirtIONetFeatures::Register>::new(0);
214
215 if offered_features.is_set(VirtIONetFeatures::VirtIONetFMac) {
216 negotiated_features.modify(VirtIONetFeatures::VirtIONetFMac::SET);
220 } else {
221 return None;
222 }
223
224 Some(negotiated_features.get())
237 }
238
239 fn device_type(&self) -> VirtIODeviceType {
240 VirtIODeviceType::NetworkCard
241 }
242}
243
244pub trait VirtIONetClient {
245 fn packet_sent(&self, id: usize, buffer: &'static mut [u8]);
246 fn packet_received(&self, id: usize, buffer: &'static mut [u8], len: usize);
247}