diff --git a/src/include/utils/vm_args.hpp b/src/include/utils/vm_args.hpp index b6707d23..8396f3a0 100644 --- a/src/include/utils/vm_args.hpp +++ b/src/include/utils/vm_args.hpp @@ -121,6 +121,7 @@ bool parse_options(int argc, char *argv[], ParsedArgs& parsed_args) { std::cout << " version - Show version information" << std::endl; std::cout << " help - Show this help message" << std::endl; std::cout << " port - Show the default server port" << std::endl; + std::cout << " validate - Validate the NPU stack" << std::endl; std::cout << std::endl; std::cout << general << std::endl; std::cout << "Examples:" << std::endl; @@ -166,6 +167,7 @@ bool parse_options(int argc, char *argv[], ParsedArgs& parsed_args) { std::cout << " version - Show version information" << std::endl; std::cout << " help - Show this help message" << std::endl; std::cout << " port - Show the default server port" << std::endl; + std::cout << " validate - Validate the NPU stack" << std::endl; std::cout << std::endl; std::cout << general << std::endl; std::cout << "Examples:" << std::endl; diff --git a/src/src/main.cpp b/src/src/main.cpp index 696a65e6..17ea37b7 100644 --- a/src/src/main.cpp +++ b/src/src/main.cpp @@ -27,6 +27,17 @@ #include #include "benchmarking.hpp" +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include "npu_utils/amdxdna_accel.h" +#endif + #include "AutoModel/automodel.hpp" #ifndef _WIN32 @@ -218,6 +229,84 @@ std::string get_models_directory() { #endif } +static bool sanity_check_npu_stack(bool quiet) { +#ifndef _WIN32 + // Check kernel version + struct utsname u_name; + if (uname(&u_name) != 0) { + if (!quiet) + perror("Failed to get kernel version"); + return false; + } + int major, minor; + sscanf(u_name.release, "%d.%d", &major, &minor); + bool kernel_ok = (major > 6) || (major == 6 && minor >= 14); + if (!kernel_ok) { + header_print("ERROR", "Kernel version incompatible with this version of FLM. Please update your kernel!"); + return false; + } + if (!quiet) { + header_print("Linux", "Kernel Version: " << u_name.release); + } + + // Check firmware version of all AMD devices + bool all_fw_ok = true; + bool amd_device_found = false; + + for (int i = 0; i < 16; ++i) { + std::string dev_name = "/dev/accel/accel" + std::to_string(i); + int fd = open(dev_name.c_str(), O_RDWR); + + if (fd < 0) { + if (errno == ENOENT) + break; + continue; + } + + amdxdna_drm_query_firmware_version query_fw_version; + amdxdna_drm_get_info get_info = { + .param = DRM_AMDXDNA_QUERY_FIRMWARE_VERSION, + .buffer_size = sizeof(amdxdna_drm_query_firmware_version), + .buffer = (unsigned long)&query_fw_version, + }; + + int ret = ioctl(fd, DRM_IOCTL_AMDXDNA_GET_INFO, &get_info); + close(fd); + if (ret < 0) { + // ENOTTY means it's not an AMD device, just ignore it. + if (errno != ENOTTY) { + if (!quiet) { + std::cout << "Error code: " << ret << " on " << dev_name << std::endl; + perror("Failed to get firmware version"); + } + } + continue; + } + + amd_device_found = true; + + if (!quiet) { + header_print("Linux", "Found AMD NPU at " + dev_name); + header_print("Linux", "NPU FW Version: " << query_fw_version.major << "." << query_fw_version.minor << "." << query_fw_version.patch << "." << query_fw_version.build); + } + + bool fw_ok = (query_fw_version.major > 1 || (query_fw_version.major == 1 && query_fw_version.minor >= 1)); + if (!fw_ok) { + all_fw_ok = false; + header_print("ERROR", "NPU firmware version on " + dev_name + " is incompatible. Please update NPU firmware!"); + } + } + + if (!amd_device_found && !quiet) { + header_print("ERROR", "No AMD NPU device found."); + } + + return amd_device_found && kernel_ok && all_fw_ok; +#else + return true; +#endif +} + ///@brief main function ///@param argc the number of arguments ///@param argv the arguments @@ -278,6 +367,7 @@ int main(int argc, char* argv[]) { bool cors = parsed_args.cors; bool asr = parsed_args.asr; bool embed = parsed_args.embed; + bool stable_stack = false; // Set process priority to high for better performance #ifdef _WIN32 @@ -320,9 +410,12 @@ int main(int argc, char* argv[]) { header_print("FLM", "Allowing high priority tasks to preempt FLM!"); } + stable_stack = sanity_check_npu_stack(command != "validate"); + if (command == "validate") + return stable_stack ? 0 : 1; try { - + // Load the model list with the models directory as the base ModelDownloader downloader(availble_models);