@@ -46,32 +46,22 @@ pub(crate) struct NetDevCfg {
46
46
pub features : virtio:: net:: F ,
47
47
}
48
48
49
- pub struct CtrlQueue ( Option < VirtQueue > ) ;
50
-
51
- impl CtrlQueue {
52
- pub fn new ( vq : Option < VirtQueue > ) -> Self {
53
- CtrlQueue ( vq)
54
- }
55
- }
56
-
57
49
pub struct RxQueues {
58
50
vqs : Vec < VirtQueue > ,
59
51
packet_size : u32 ,
60
52
}
61
53
62
54
impl RxQueues {
63
55
pub fn new ( vqs : Vec < VirtQueue > , dev_cfg : & NetDevCfg ) -> Self {
64
- // See Virtio specification v1.1 - 5.1.6.3.1
56
+ // See Virtio specification v1.1 - 5.1.6.3.1 and 5.1.4.2
65
57
//
66
- let packet_size = if dev_cfg. features . contains ( virtio:: net:: F :: MRG_RXBUF ) {
58
+ #[ allow( clippy:: decimal_literal_representation) ]
59
+ let packet_size = if dev_cfg. features . contains ( virtio:: net:: F :: MTU ) {
60
+ 65550
61
+ } else if dev_cfg. features . contains ( virtio:: net:: F :: MRG_RXBUF ) {
67
62
1514
68
- } else if dev_cfg. features . contains ( virtio:: net:: F :: GUEST_TSO4 )
69
- || dev_cfg. features . contains ( virtio:: net:: F :: GUEST_TSO6 )
70
- || dev_cfg. features . contains ( virtio:: net:: F :: GUEST_UFO )
71
- {
72
- dev_cfg. raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( ) . into ( )
73
63
} else {
74
- 1514
64
+ dev_cfg . raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( ) . into ( )
75
65
} ;
76
66
77
67
Self { vqs, packet_size }
@@ -196,27 +186,32 @@ impl TxQueues {
196
186
}
197
187
}
198
188
189
+ pub ( crate ) struct Uninit ;
190
+ pub ( crate ) struct Init {
191
+ pub ( super ) ctrl_vq : Option < VirtQueue > ,
192
+ pub ( super ) recv_vqs : RxQueues ,
193
+ pub ( super ) send_vqs : TxQueues ,
194
+ }
195
+
199
196
/// Virtio network driver struct.
200
197
///
201
198
/// Struct allows to control devices virtqueues as also
202
199
/// the device itself.
203
- pub ( crate ) struct VirtioNetDriver {
200
+ pub ( crate ) struct VirtioNetDriver < T = Init > {
204
201
pub ( super ) dev_cfg : NetDevCfg ,
205
202
pub ( super ) com_cfg : ComCfg ,
206
203
pub ( super ) isr_stat : IsrStatus ,
207
204
pub ( super ) notif_cfg : NotifCfg ,
208
205
209
- pub ( super ) ctrl_vq : CtrlQueue ,
210
- pub ( super ) recv_vqs : RxQueues ,
211
- pub ( super ) send_vqs : TxQueues ,
206
+ pub ( super ) inner : T ,
212
207
213
208
pub ( super ) num_vqs : u16 ,
214
209
pub ( super ) mtu : u16 ,
215
210
pub ( super ) irq : InterruptLine ,
216
211
pub ( super ) checksums : ChecksumCapabilities ,
217
212
}
218
213
219
- impl NetworkDriver for VirtioNetDriver {
214
+ impl NetworkDriver for VirtioNetDriver < Init > {
220
215
/// Returns the mac address of the device.
221
216
/// If VIRTIO_NET_F_MAC is not set, the function panics currently!
222
217
fn get_mac_address ( & self ) -> [ u8 ; 6 ] {
@@ -240,7 +235,7 @@ impl NetworkDriver for VirtioNetDriver {
240
235
241
236
#[ allow( dead_code) ]
242
237
fn has_packet ( & self ) -> bool {
243
- self . recv_vqs . has_packet ( )
238
+ self . inner . recv_vqs . has_packet ( )
244
239
}
245
240
246
241
/// Provides smoltcp a slice to copy the IP packet and transfer the packet
@@ -251,9 +246,9 @@ impl NetworkDriver for VirtioNetDriver {
251
246
{
252
247
// We need to poll to get the queue to remove elements from the table and make space for
253
248
// what we are about to add
254
- self . send_vqs . poll ( ) ;
249
+ self . inner . send_vqs . poll ( ) ;
255
250
256
- assert ! ( len < usize :: try_from( self . send_vqs. packet_length) . unwrap( ) ) ;
251
+ assert ! ( len < usize :: try_from( self . inner . send_vqs. packet_length) . unwrap( ) ) ;
257
252
let mut packet = Vec :: with_capacity_in ( len, DeviceAlloc ) ;
258
253
let result = unsafe {
259
254
let result = f ( packet. spare_capacity_mut ( ) . assume_init_mut ( ) ) ;
@@ -302,7 +297,7 @@ impl NetworkDriver for VirtioNetDriver {
302
297
)
303
298
. unwrap ( ) ;
304
299
305
- self . send_vqs . vqs [ 0 ]
300
+ self . inner . send_vqs . vqs [ 0 ]
306
301
. dispatch ( buff_tkn, false , BufferType :: Direct )
307
302
. unwrap ( ) ;
308
303
@@ -311,7 +306,7 @@ impl NetworkDriver for VirtioNetDriver {
311
306
312
307
fn receive_packet ( & mut self ) -> Option < ( RxToken , TxToken ) > {
313
308
let mut receive_single_packet = || {
314
- let mut buffer_tkn = self . recv_vqs . get_next ( ) ?;
309
+ let mut buffer_tkn = self . inner . recv_vqs . get_next ( ) ?;
315
310
RxQueues :: post_processing ( & mut buffer_tkn)
316
311
. inspect_err ( |vnet_err| warn ! ( "Post processing failed. Err: {vnet_err:?}" ) )
317
312
. ok ( ) ?;
@@ -338,9 +333,9 @@ impl NetworkDriver for VirtioNetDriver {
338
333
}
339
334
340
335
fill_queue (
341
- & mut self . recv_vqs . vqs [ 0 ] ,
336
+ & mut self . inner . recv_vqs . vqs [ 0 ] ,
342
337
num_buffers,
343
- self . recv_vqs . packet_size ,
338
+ self . inner . recv_vqs . packet_size ,
344
339
) ;
345
340
346
341
Some ( ( RxToken :: new ( combined_packets) , TxToken :: new ( ) ) )
@@ -373,7 +368,7 @@ impl NetworkDriver for VirtioNetDriver {
373
368
}
374
369
}
375
370
376
- impl Driver for VirtioNetDriver {
371
+ impl Driver for VirtioNetDriver < Init > {
377
372
fn get_interrupt_number ( & self ) -> InterruptLine {
378
373
self . irq
379
374
}
@@ -384,17 +379,12 @@ impl Driver for VirtioNetDriver {
384
379
}
385
380
386
381
// Backend-independent interface for Virtio network driver
387
- impl VirtioNetDriver {
382
+ impl VirtioNetDriver < Init > {
388
383
#[ cfg( feature = "pci" ) ]
389
384
pub fn get_dev_id ( & self ) -> u16 {
390
385
self . dev_cfg . dev_id
391
386
}
392
387
393
- #[ cfg( feature = "pci" ) ]
394
- pub fn set_failed ( & mut self ) {
395
- self . com_cfg . set_failed ( ) ;
396
- }
397
-
398
388
/// Returns the current status of the device, if VIRTIO_NET_F_STATUS
399
389
/// has been negotiated. Otherwise assumes an active device.
400
390
#[ cfg( not( feature = "pci" ) ) ]
@@ -458,21 +448,23 @@ impl VirtioNetDriver {
458
448
pub fn disable_interrupts ( & mut self ) {
459
449
// For send and receive queues?
460
450
// Only for receive? Because send is off anyway?
461
- self . recv_vqs . disable_notifs ( ) ;
451
+ self . inner . recv_vqs . disable_notifs ( ) ;
462
452
}
463
453
464
454
pub fn enable_interrupts ( & mut self ) {
465
455
// For send and receive queues?
466
456
// Only for receive? Because send is off anyway?
467
- self . recv_vqs . enable_notifs ( ) ;
457
+ self . inner . recv_vqs . enable_notifs ( ) ;
468
458
}
459
+ }
469
460
461
+ impl VirtioNetDriver < Uninit > {
470
462
/// Initializes the device in adherence to specification. Returns Some(VirtioNetError)
471
463
/// upon failure and None in case everything worked as expected.
472
464
///
473
465
/// See Virtio specification v1.1. - 3.1.1.
474
466
/// and v1.1. - 5.1.5
475
- pub fn init_dev ( & mut self ) -> Result < ( ) , VirtioNetError > {
467
+ pub fn init_dev ( mut self ) -> Result < VirtioNetDriver < Init > , VirtioNetError > {
476
468
// Reset
477
469
self . com_cfg . reset_dev ( ) ;
478
470
@@ -598,7 +590,13 @@ impl VirtioNetDriver {
598
590
return Err ( VirtioNetError :: FailFeatureNeg ( self . dev_cfg . dev_id ) ) ;
599
591
}
600
592
601
- self . dev_spec_init ( ) ?;
593
+ let mut inner = Init {
594
+ ctrl_vq : None ,
595
+ recv_vqs : RxQueues :: new ( Vec :: new ( ) , & self . dev_cfg ) ,
596
+ send_vqs : TxQueues :: new ( Vec :: new ( ) , & self . dev_cfg ) ,
597
+ } ;
598
+
599
+ self . dev_spec_init ( & mut inner) ?;
602
600
info ! (
603
601
"Device specific initialization for Virtio network device {:x} finished" ,
604
602
self . dev_cfg. dev_id
@@ -625,7 +623,17 @@ impl VirtioNetDriver {
625
623
self . mtu = self . dev_cfg . raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( ) ;
626
624
}
627
625
628
- Ok ( ( ) )
626
+ Ok ( VirtioNetDriver {
627
+ dev_cfg : self . dev_cfg ,
628
+ com_cfg : self . com_cfg ,
629
+ isr_stat : self . isr_stat ,
630
+ notif_cfg : self . notif_cfg ,
631
+ inner,
632
+ num_vqs : self . num_vqs ,
633
+ mtu : self . mtu ,
634
+ irq : self . irq ,
635
+ checksums : self . checksums ,
636
+ } )
629
637
}
630
638
631
639
/// Negotiates a subset of features, understood and wanted by both the OS
@@ -655,14 +663,14 @@ impl VirtioNetDriver {
655
663
}
656
664
657
665
/// Device Specific initialization according to Virtio specifictation v1.1. - 5.1.5
658
- fn dev_spec_init ( & mut self ) -> Result < ( ) , VirtioNetError > {
659
- self . virtqueue_init ( ) ?;
666
+ fn dev_spec_init ( & mut self , inner : & mut Init ) -> Result < ( ) , VirtioNetError > {
667
+ self . virtqueue_init ( inner ) ?;
660
668
info ! ( "Network driver successfully initialized virtqueues." ) ;
661
669
662
670
// Add a control if feature is negotiated
663
671
if self . dev_cfg . features . contains ( virtio:: net:: F :: CTRL_VQ ) {
664
- if self . dev_cfg . features . contains ( virtio:: net:: F :: RING_PACKED ) {
665
- self . ctrl_vq = CtrlQueue ( Some ( VirtQueue :: Packed (
672
+ let mut ctrl_vq = if self . dev_cfg . features . contains ( virtio:: net:: F :: RING_PACKED ) {
673
+ VirtQueue :: Packed (
666
674
PackedVq :: new (
667
675
& mut self . com_cfg ,
668
676
& self . notif_cfg ,
@@ -671,9 +679,9 @@ impl VirtioNetDriver {
671
679
self . dev_cfg . features . into ( ) ,
672
680
)
673
681
. unwrap ( ) ,
674
- ) ) ) ;
682
+ )
675
683
} else {
676
- self . ctrl_vq = CtrlQueue ( Some ( VirtQueue :: Split (
684
+ VirtQueue :: Split (
677
685
SplitVq :: new (
678
686
& mut self . com_cfg ,
679
687
& self . notif_cfg ,
@@ -682,17 +690,18 @@ impl VirtioNetDriver {
682
690
self . dev_cfg . features . into ( ) ,
683
691
)
684
692
. unwrap ( ) ,
685
- ) ) ) ;
686
- }
693
+ )
694
+ } ;
687
695
688
- self . ctrl_vq . 0 . as_mut ( ) . unwrap ( ) . enable_notifs ( ) ;
696
+ ctrl_vq. enable_notifs ( ) ;
697
+ inner. ctrl_vq = Some ( ctrl_vq) ;
689
698
}
690
699
691
700
Ok ( ( ) )
692
701
}
693
702
694
703
/// Initialize virtqueues via the queue interface and populates receiving queues
695
- fn virtqueue_init ( & mut self ) -> Result < ( ) , VirtioNetError > {
704
+ fn virtqueue_init ( & mut self , inner : & mut Init ) -> Result < ( ) , VirtioNetError > {
696
705
// We are assuming here, that the device single source of truth is the
697
706
// device specific configuration. Hence we do NOT check if
698
707
//
@@ -749,7 +758,7 @@ impl VirtioNetDriver {
749
758
// Interrupt for receiving packets is wanted
750
759
vq. enable_notifs ( ) ;
751
760
752
- self . recv_vqs . add ( VirtQueue :: Packed ( vq) ) ;
761
+ inner . recv_vqs . add ( VirtQueue :: Packed ( vq) ) ;
753
762
754
763
let mut vq = PackedVq :: new (
755
764
& mut self . com_cfg ,
@@ -762,7 +771,7 @@ impl VirtioNetDriver {
762
771
// Interrupt for communicating that a sended packet left, is not needed
763
772
vq. disable_notifs ( ) ;
764
773
765
- self . send_vqs . add ( VirtQueue :: Packed ( vq) ) ;
774
+ inner . send_vqs . add ( VirtQueue :: Packed ( vq) ) ;
766
775
} else {
767
776
let mut vq = SplitVq :: new (
768
777
& mut self . com_cfg ,
@@ -775,7 +784,7 @@ impl VirtioNetDriver {
775
784
// Interrupt for receiving packets is wanted
776
785
vq. enable_notifs ( ) ;
777
786
778
- self . recv_vqs . add ( VirtQueue :: Split ( vq) ) ;
787
+ inner . recv_vqs . add ( VirtQueue :: Split ( vq) ) ;
779
788
780
789
let mut vq = SplitVq :: new (
781
790
& mut self . com_cfg ,
@@ -788,7 +797,7 @@ impl VirtioNetDriver {
788
797
// Interrupt for communicating that a sended packet left, is not needed
789
798
vq. disable_notifs ( ) ;
790
799
791
- self . send_vqs . add ( VirtQueue :: Split ( vq) ) ;
800
+ inner . send_vqs . add ( VirtQueue :: Split ( vq) ) ;
792
801
}
793
802
}
794
803
0 commit comments