Skip to main content

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