mana_driver/
bnic_driver.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Interface to BNIC (Basic NIC) MANA commands.
5
6use crate::gdma_driver::GdmaDriver;
7use crate::mana::ResourceArena;
8use crate::resources::Resource;
9use gdma_defs::GdmaDevId;
10use gdma_defs::GdmaQueueType;
11use gdma_defs::GdmaReqHdr;
12use gdma_defs::bnic::MANA_VTL2_ASSIGN_SERIAL_NUMBER_REQUEST_V1;
13use gdma_defs::bnic::MANA_VTL2_ASSIGN_SERIAL_NUMBER_RESPONSE_V1;
14use gdma_defs::bnic::MANA_VTL2_MOVE_FILTER_REQUEST_V2;
15use gdma_defs::bnic::MANA_VTL2_MOVE_FILTER_RESPONSE_V1;
16use gdma_defs::bnic::ManaCfgRxSteerReq;
17use gdma_defs::bnic::ManaCommandCode;
18use gdma_defs::bnic::ManaConfigVportReq;
19use gdma_defs::bnic::ManaConfigVportResp;
20use gdma_defs::bnic::ManaCreateWqobjReq;
21use gdma_defs::bnic::ManaCreateWqobjResp;
22use gdma_defs::bnic::ManaDestroyWqobjReq;
23use gdma_defs::bnic::ManaMoveFilterVTL2PrivilegedReq;
24use gdma_defs::bnic::ManaQueryDeviceCfgReq;
25use gdma_defs::bnic::ManaQueryDeviceCfgResp;
26use gdma_defs::bnic::ManaQueryFilterStateReq;
27use gdma_defs::bnic::ManaQueryFilterStateResponse;
28use gdma_defs::bnic::ManaQueryStatisticsRequest;
29use gdma_defs::bnic::ManaQueryStatisticsResponse;
30use gdma_defs::bnic::ManaQueryVportCfgReq;
31use gdma_defs::bnic::ManaQueryVportCfgResp;
32use gdma_defs::bnic::ManaSetVportSerialNo;
33use user_driver::DeviceBacking;
34use zerocopy::FromBytes;
35use zerocopy::FromZeros;
36use zerocopy::Immutable;
37use zerocopy::IntoBytes;
38use zerocopy::KnownLayout;
39
40pub struct BnicDriver<'a, T: DeviceBacking> {
41    gdma: &'a mut GdmaDriver<T>,
42    dev_id: GdmaDevId,
43}
44
45impl<'a, T: DeviceBacking> BnicDriver<'a, T> {
46    pub fn new(gdma: &'a mut GdmaDriver<T>, dev_id: GdmaDevId) -> Self {
47        Self { gdma, dev_id }
48    }
49
50    #[tracing::instrument(skip(self), level = "debug", err)]
51    pub async fn query_dev_config(&mut self) -> anyhow::Result<ManaQueryDeviceCfgResp> {
52        let resp: ManaQueryDeviceCfgResp = self
53            .gdma
54            .request(
55                ManaCommandCode::MANA_QUERY_DEV_CONFIG.0,
56                self.dev_id,
57                ManaQueryDeviceCfgReq {
58                    mn_drv_cap_flags1: 0,
59                    mn_drv_cap_flags2: 0,
60                    mn_drv_cap_flags3: 0,
61                    mn_drv_cap_flags4: 0,
62                    proto_major_ver: 1,
63                    proto_minor_ver: 0,
64                    proto_micro_ver: 0,
65                    reserved: 0,
66                },
67            )
68            .await?;
69        Ok(resp)
70    }
71
72    #[tracing::instrument(skip(self), level = "debug", err)]
73    pub async fn config_vport_tx(
74        &mut self,
75        vport: u64,
76        pdid: u32,
77        doorbell_pageid: u32,
78    ) -> anyhow::Result<ManaConfigVportResp> {
79        let resp: ManaConfigVportResp = self
80            .gdma
81            .request(
82                ManaCommandCode::MANA_CONFIG_VPORT_TX.0,
83                self.dev_id,
84                ManaConfigVportReq {
85                    vport,
86                    pdid,
87                    doorbell_pageid,
88                },
89            )
90            .await?;
91        Ok(resp)
92    }
93
94    #[tracing::instrument(skip(self, arena, config), level = "debug", err)]
95    pub async fn create_wq_obj(
96        &mut self,
97        arena: &mut ResourceArena,
98        vport: u64,
99        wq_type: GdmaQueueType,
100        config: &WqConfig,
101    ) -> anyhow::Result<ManaCreateWqobjResp> {
102        let resp: ManaCreateWqobjResp = self
103            .gdma
104            .request(
105                ManaCommandCode::MANA_CREATE_WQ_OBJ.0,
106                self.dev_id,
107                ManaCreateWqobjReq {
108                    vport,
109                    wq_type,
110                    reserved: 0,
111                    wq_gdma_region: config.wq_gdma_region,
112                    cq_gdma_region: config.cq_gdma_region,
113                    wq_size: config.wq_size,
114                    cq_size: config.cq_size,
115                    cq_moderation_ctx_id: config.cq_moderation_ctx_id,
116                    cq_parent_qid: config.eq_id,
117                },
118            )
119            .await?;
120
121        // The queues take ownership of their DMA regions.
122        arena.take_dma_region(config.wq_gdma_region);
123        arena.take_dma_region(config.cq_gdma_region);
124
125        arena.push(Resource::BnicQueue {
126            dev_id: self.dev_id,
127            wq_type,
128            wq_obj: resp.wq_obj,
129        });
130        Ok(resp)
131    }
132
133    #[tracing::instrument(skip(self), level = "debug", err)]
134    pub async fn destroy_wq_obj(
135        &mut self,
136        wq_type: GdmaQueueType,
137        wq_obj_handle: u64,
138    ) -> anyhow::Result<()> {
139        self.gdma
140            .request(
141                ManaCommandCode::MANA_DESTROY_WQ_OBJ.0,
142                self.dev_id,
143                ManaDestroyWqobjReq {
144                    wq_type,
145                    reserved: 0,
146                    wq_obj_handle,
147                },
148            )
149            .await
150    }
151
152    #[tracing::instrument(skip(self, config), level = "debug", err)]
153    pub async fn config_vport_rx(
154        &mut self,
155        vport: u64,
156        config: &RxConfig<'_>,
157    ) -> anyhow::Result<()> {
158        #[repr(C)]
159        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
160        struct Req {
161            req: ManaCfgRxSteerReq,
162            table: [u64; 128],
163        }
164
165        let mut req = Req {
166            req: ManaCfgRxSteerReq {
167                vport,
168                num_indir_entries: config.indirection_table.map_or(0, |t| t.len() as u16),
169                indir_tab_offset: (size_of::<GdmaReqHdr>() + size_of::<ManaCfgRxSteerReq>()) as u16,
170                rx_enable: config.rx_enable.into(),
171                rss_enable: config.rss_enable.into(),
172                update_default_rxobj: config.default_rxobj.is_some().into(),
173                update_hashkey: config.hash_key.is_some().into(),
174                update_indir_tab: config.indirection_table.is_some().into(),
175                reserved: 0,
176                default_rxobj: config.default_rxobj.unwrap_or(0),
177                hashkey: *config.hash_key.unwrap_or(&[0; 40]),
178            },
179            table: FromZeros::new_zeroed(),
180        };
181        if let Some(table) = config.indirection_table {
182            req.table[..table.len()].copy_from_slice(table);
183        }
184
185        self.gdma
186            .request(ManaCommandCode::MANA_CONFIG_VPORT_RX.0, self.dev_id, req)
187            .await
188    }
189
190    #[tracing::instrument(skip(self), level = "debug", err)]
191    pub async fn query_vport_config(
192        &mut self,
193        vport_index: u32,
194    ) -> anyhow::Result<ManaQueryVportCfgResp> {
195        let resp: ManaQueryVportCfgResp = self
196            .gdma
197            .request(
198                ManaCommandCode::MANA_QUERY_VPORT_CONFIG.0,
199                self.dev_id,
200                ManaQueryVportCfgReq { vport_index },
201            )
202            .await?;
203        Ok(resp)
204    }
205
206    pub async fn query_stats(
207        &mut self,
208        requested_statistics: u64,
209    ) -> anyhow::Result<ManaQueryStatisticsResponse> {
210        let resp: ManaQueryStatisticsResponse = self
211            .gdma
212            .request(
213                ManaCommandCode::MANA_QUERY_STATS.0,
214                self.dev_id,
215                ManaQueryStatisticsRequest {
216                    requested_statistics,
217                },
218            )
219            .await?;
220        Ok(resp)
221    }
222
223    pub async fn query_filter_state(
224        &mut self,
225        vport: u64,
226    ) -> anyhow::Result<ManaQueryFilterStateResponse> {
227        let resp: ManaQueryFilterStateResponse = self
228            .gdma
229            .request(
230                ManaCommandCode::MANA_VTL2_QUERY_FILTER_STATE.0,
231                self.dev_id,
232                ManaQueryFilterStateReq { vport },
233            )
234            .await?;
235        Ok(resp)
236    }
237
238    #[tracing::instrument(skip(self), level = "debug", err)]
239    pub async fn move_vport_filter(
240        &mut self,
241        vport: u64,
242        direction_to_vtl0: u8,
243    ) -> anyhow::Result<u32> {
244        let ((), activity_id) = self
245            .gdma
246            .request_version(
247                ManaCommandCode::MANA_VTL2_MOVE_FILTER.0,
248                MANA_VTL2_MOVE_FILTER_REQUEST_V2,
249                ManaCommandCode::MANA_VTL2_MOVE_FILTER.0,
250                MANA_VTL2_MOVE_FILTER_RESPONSE_V1,
251                self.dev_id,
252                ManaMoveFilterVTL2PrivilegedReq {
253                    vport,
254                    direction_to_vtl0,
255                    reserved: [0, 0, 0],
256                    reserved2: 0,
257                },
258            )
259            .await?;
260        Ok(activity_id)
261    }
262
263    #[tracing::instrument(skip(self), level = "debug", err)]
264    pub async fn set_vport_serial_no(&mut self, vport: u64, serial_no: u32) -> anyhow::Result<()> {
265        let ((), _) = self
266            .gdma
267            .request_version(
268                ManaCommandCode::MANA_VTL2_ASSIGN_SERIAL_NUMBER.0,
269                MANA_VTL2_ASSIGN_SERIAL_NUMBER_REQUEST_V1,
270                ManaCommandCode::MANA_VTL2_ASSIGN_SERIAL_NUMBER.0,
271                MANA_VTL2_ASSIGN_SERIAL_NUMBER_RESPONSE_V1,
272                self.dev_id,
273                ManaSetVportSerialNo {
274                    vport,
275                    serial_no,
276                    reserved: 0,
277                },
278            )
279            .await?;
280        Ok(())
281    }
282}
283
284/// Receive configuration for a vport.
285pub struct RxConfig<'a> {
286    /// Enable receiving packets.
287    pub rx_enable: Option<bool>,
288    /// Enable RSS.
289    pub rss_enable: Option<bool>,
290    /// The RSS hash key to set.
291    pub hash_key: Option<&'a [u8; 40]>,
292    /// The default rx obj for incoming packets that cannot be hashed (I think).
293    pub default_rxobj: Option<u64>,
294    /// The RSS indirection table.
295    pub indirection_table: Option<&'a [u64]>,
296}
297
298pub struct WqConfig {
299    pub wq_gdma_region: u64,
300    pub cq_gdma_region: u64,
301    pub wq_size: u32,
302    pub cq_size: u32,
303    pub cq_moderation_ctx_id: u32,
304    pub eq_id: u32,
305}