Skip to main content

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