Skip to main content

luwen_api/chip/init/
mod.rs

1// SPDX-FileCopyrightText: © 2023 Tenstorrent Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::convert::Infallible;
5
6use crate::{error::PlatformError, ChipImpl};
7
8use status::InitStatus;
9
10pub mod status;
11
12pub enum CallReason<'a> {
13    NewChip,
14    NotNew,
15    InitWait(&'a InitStatus),
16    ChipInitCompleted(&'a InitStatus),
17}
18
19#[allow(dead_code)]
20pub struct ChipDetectState<'a> {
21    pub chip: &'a dyn ChipImpl,
22    pub call: CallReason<'a>,
23}
24
25#[derive(thiserror::Error)]
26pub enum InitError<E> {
27    #[error(transparent)]
28    PlatformError(#[from] PlatformError),
29
30    CallbackError(E),
31}
32
33impl From<InitError<Infallible>> for PlatformError {
34    fn from(val: InitError<Infallible>) -> Self {
35        match val {
36            InitError::PlatformError(err) => err,
37            InitError::CallbackError(_) => unreachable!(),
38        }
39    }
40}
41
42/// This function will wait for the chip to be initialized.
43/// It will return Ok(true) if the chip initialized successfully.
44/// It will return Ok(false) if the chip failed to initialize, but we can continue running.
45///     - This is only possible if allow_failure is true.
46/// An Err(..) will be returned if the chip failed to initialize and we cannot continue running the chip detection sequence.
47///     - In the case that allow_failure is false, Ok(true) will be returned as an error.
48///
49/// This component makes a callback available which allows the init status to be updated if there
50/// is someone/something monitoring the init progress. The initial/driving purpose of this is to
51/// track the progress on the command line.
52pub fn wait_for_init<E>(
53    chip: &mut impl ChipImpl,
54    callback: &mut impl FnMut(ChipDetectState) -> Result<(), E>,
55    allow_failure: bool,
56    noc_safe: bool,
57) -> Result<InitStatus, InitError<E>> {
58    // We want to make sure that we always call the callback at least once so that the caller can mark the chip presence.
59    callback(ChipDetectState {
60        chip,
61        call: CallReason::NewChip,
62    })
63    .map_err(|v| InitError::CallbackError(v))?;
64
65    let mut status = InitStatus::new_unknown();
66    status.init_options.noc_safe = noc_safe;
67    loop {
68        match chip.update_init_state(&mut status)? {
69            super::ChipInitResult::NoError => {
70                // No error, we don't have to do anything.
71            }
72            super::ChipInitResult::ErrorContinue(error, bt_tracker) => {
73                // Hit an error, cannot continue to initialize the current chip,
74                // but we can continue to initialize other chips (assuming we are allowing failures).
75                if !allow_failure {
76                    Err(PlatformError::Generic(
77                        format!("Chip initialization failed: {error} \n{status}"),
78                        crate::error::BtWrapper(bt_tracker),
79                    ))?;
80                } else {
81                    callback(ChipDetectState {
82                        chip,
83                        call: CallReason::ChipInitCompleted(&status),
84                    })
85                    .map_err(InitError::CallbackError)?;
86                    return Ok(status);
87                }
88            }
89            super::ChipInitResult::ErrorAbort(error, bt_tracker) => {
90                Err(PlatformError::Generic(
91                    format!("Chip initialization failed (aborted): {error} \n{status}"),
92                    crate::error::BtWrapper(bt_tracker),
93                ))?;
94            }
95        }
96
97        let call = if !status.init_complete() {
98            CallReason::InitWait(&status)
99        } else {
100            // Yes, this also returns a result that we are ignoring.
101            // But we are always going to return right after this anyway.
102            callback(ChipDetectState {
103                chip,
104                call: CallReason::ChipInitCompleted(&status),
105            })
106            .map_err(InitError::CallbackError)?;
107            if status.has_error() {
108                Err(PlatformError::Generic(
109                    format!("Chip initialization failed:\n{status} "),
110                    crate::error::BtWrapper::capture(),
111                ))?;
112            }
113
114            return Ok(status);
115        };
116
117        callback(ChipDetectState { chip, call }).map_err(InitError::CallbackError)?;
118    }
119}