luwen_if/
interface.rs

1// SPDX-FileCopyrightText: © 2023 Tenstorrent Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::chip::{eth_addr::EthAddr, ChipInterface};
5use std::fs;
6
7#[derive(Debug)]
8pub enum FnNoc {
9    Read {
10        noc_id: u8,
11        x: u32,
12        y: u32,
13        addr: u64,
14        data: *mut u8,
15        len: u64,
16    },
17    Write {
18        noc_id: u8,
19        x: u32,
20        y: u32,
21        addr: u64,
22        data: *const u8,
23        len: u64,
24    },
25    Broadcast {
26        noc_id: u8,
27        addr: u64,
28        data: *const u8,
29        len: u64,
30    },
31}
32
33#[derive(Debug)]
34pub struct FnRemote {
35    pub addr: EthAddr,
36    pub rw: FnNoc,
37}
38
39#[derive(Debug)]
40pub enum FnAxi {
41    Read {
42        addr: u32,
43        data: *mut u8,
44        len: u32,
45    },
46    Write {
47        addr: u32,
48        data: *const u8,
49        len: u32,
50    },
51}
52
53#[derive(Clone, Debug)]
54pub struct DeviceInfo {
55    pub interface_id: u32,
56
57    pub domain: u16,
58    pub bus: u16,
59    pub slot: u16,
60    pub function: u16,
61
62    pub vendor: u16,
63    pub device_id: u16,
64    pub bar_size: u64,
65}
66
67impl DeviceInfo {
68    /// Return the sysfs path for the PCIe device.
69    fn pcie_base_path(&self) -> String {
70        let domain = format!("{:04x}", self.domain);
71        let bus = format!("{:02x}", self.bus);
72        let slot = format!("{:02x}", self.slot);
73        let function = format!("{:01x}", self.function);
74        format!(
75            "/sys/bus/pci/devices/{}:{}:{}.{}/",
76            domain, bus, slot, function
77        )
78    }
79
80    /// Return link width; valid values of `s` are "current" and "max".
81    fn pcie_link_width(&self, s: &str) -> u32 {
82        let base_path = self.pcie_base_path();
83        let path = format!("{}{}{}", &base_path, s, "_link_width");
84        let width = fs::read_to_string(path)
85            .map(|s| s.trim().to_string())
86            .unwrap();
87        width.parse::<u32>().unwrap()
88    }
89
90    /// Return link gen; valid values of `s` are "current" and "max".
91    fn pcie_link_gen(&self, s: &str) -> i32 {
92        let base_path = self.pcie_base_path();
93        let path = format!("{}{}{}", &base_path, s, "_link_speed");
94        let speed = fs::read_to_string(path)
95            .map(|s| s.trim().to_string())
96            .unwrap();
97        match speed.split_whitespace().next().unwrap_or("") {
98            "2.5" => 1,
99            "5.0" => 2,
100            "8.0" => 3,
101            "16.0" => 4,
102            "32.0" => 5,
103            "64.0" => 6,
104            _ => -1,
105        }
106    }
107
108    /// Return the current PCIe link width.
109    pub fn pcie_current_link_width(&self) -> u32 {
110        self.pcie_link_width("current")
111    }
112
113    /// Return the current PCIe link generation.
114    pub fn pcie_current_link_gen(&self) -> i32 {
115        self.pcie_link_gen("current")
116    }
117
118    /// Return the maximum PCIe link width.
119    pub fn pcie_max_link_width(&self) -> u32 {
120        self.pcie_link_width("max")
121    }
122
123    /// Return the maximum PCIe link generation.
124    pub fn pcie_max_link_gen(&self) -> i32 {
125        self.pcie_link_gen("max")
126    }
127}
128
129#[derive(Debug)]
130pub enum FnDriver {
131    DeviceInfo(*mut Option<DeviceInfo>),
132}
133
134#[derive(Debug)]
135pub enum FnOptions {
136    Driver(FnDriver),
137    Axi(FnAxi),
138    Noc(FnNoc),
139    Eth(FnRemote),
140}
141
142#[derive(Clone)]
143pub struct CallbackStorage<T: Clone + Send> {
144    pub callback: fn(&T, FnOptions) -> Result<(), Box<dyn std::error::Error>>,
145    pub user_data: T,
146}
147
148impl<T: Clone + Send> CallbackStorage<T> {
149    pub fn new(
150        callback: fn(&T, FnOptions) -> Result<(), Box<dyn std::error::Error>>,
151        user_data: T,
152    ) -> Self {
153        Self {
154            callback,
155            user_data,
156        }
157    }
158}
159
160impl<T: Clone + Send + 'static> ChipInterface for CallbackStorage<T> {
161    fn get_device_info(&self) -> Result<Option<DeviceInfo>, Box<dyn std::error::Error>> {
162        let mut driver_info = None;
163        (self.callback)(
164            &self.user_data,
165            FnOptions::Driver(FnDriver::DeviceInfo((&mut driver_info) as *mut _)),
166        )?;
167
168        Ok(driver_info)
169    }
170
171    fn axi_read(&self, addr: u32, data: &mut [u8]) -> Result<(), Box<dyn std::error::Error>> {
172        (self.callback)(
173            &self.user_data,
174            FnOptions::Axi(FnAxi::Read {
175                addr,
176                data: data.as_mut_ptr(),
177                len: data.len() as u32,
178            }),
179        )
180    }
181
182    fn axi_write(&self, addr: u32, data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
183        (self.callback)(
184            &self.user_data,
185            FnOptions::Axi(FnAxi::Write {
186                addr,
187                data: data.as_ptr(),
188                len: data.len() as u32,
189            }),
190        )
191    }
192
193    fn noc_read(
194        &self,
195        noc_id: u8,
196        x: u8,
197        y: u8,
198        addr: u64,
199        data: &mut [u8],
200    ) -> Result<(), Box<dyn std::error::Error>> {
201        (self.callback)(
202            &self.user_data,
203            FnOptions::Noc(FnNoc::Read {
204                noc_id,
205                x: x as u32,
206                y: y as u32,
207                addr: addr as u64,
208                data: data.as_mut_ptr(),
209                len: data.len() as u64,
210            }),
211        )
212    }
213
214    fn noc_write(
215        &self,
216        noc_id: u8,
217        x: u8,
218        y: u8,
219        addr: u64,
220        data: &[u8],
221    ) -> Result<(), Box<dyn std::error::Error>> {
222        (self.callback)(
223            &self.user_data,
224            FnOptions::Noc(FnNoc::Write {
225                noc_id,
226                x: x as u32,
227                y: y as u32,
228                addr,
229                data: data.as_ptr(),
230                len: data.len() as u64,
231            }),
232        )
233    }
234
235    fn noc_broadcast(
236        &self,
237        noc_id: u8,
238        addr: u64,
239        data: &[u8],
240    ) -> Result<(), Box<dyn std::error::Error>> {
241        (self.callback)(
242            &self.user_data,
243            FnOptions::Noc(FnNoc::Broadcast {
244                noc_id,
245                addr: addr as u64,
246                data: data.as_ptr(),
247                len: data.len() as u64,
248            }),
249        )
250    }
251
252    fn eth_noc_read(
253        &self,
254        eth_addr: EthAddr,
255        noc_id: u8,
256        x: u8,
257        y: u8,
258        addr: u64,
259        data: &mut [u8],
260    ) -> Result<(), Box<dyn std::error::Error>> {
261        (self.callback)(
262            &self.user_data,
263            FnOptions::Eth(FnRemote {
264                addr: eth_addr,
265                rw: FnNoc::Read {
266                    noc_id,
267                    x: x as u32,
268                    y: y as u32,
269                    addr: addr as u64,
270                    data: data.as_mut_ptr(),
271                    len: data.len() as u64,
272                },
273            }),
274        )
275    }
276
277    fn eth_noc_write(
278        &self,
279        eth_addr: EthAddr,
280        noc_id: u8,
281        x: u8,
282        y: u8,
283        addr: u64,
284        data: &[u8],
285    ) -> Result<(), Box<dyn std::error::Error>> {
286        (self.callback)(
287            &self.user_data,
288            FnOptions::Eth(FnRemote {
289                addr: eth_addr,
290                rw: FnNoc::Write {
291                    noc_id,
292                    x: x as u32,
293                    y: y as u32,
294                    addr: addr as u64,
295                    data: data.as_ptr(),
296                    len: data.len() as u64,
297                },
298            }),
299        )
300    }
301
302    fn eth_noc_broadcast(
303        &self,
304        eth_addr: EthAddr,
305        noc_id: u8,
306        addr: u64,
307        data: &[u8],
308    ) -> Result<(), Box<dyn std::error::Error>> {
309        (self.callback)(
310            &self.user_data,
311            FnOptions::Eth(FnRemote {
312                addr: eth_addr,
313                rw: FnNoc::Broadcast {
314                    noc_id,
315                    addr: addr as u64,
316                    data: data.as_ptr(),
317                    len: data.len() as u64,
318                },
319            }),
320        )
321    }
322
323    fn as_any(&self) -> &dyn std::any::Any {
324        self
325    }
326}