├── .clang-format-ignore ├── service_files ├── meson.build └── com.intel.peci.service ├── meson.options ├── subprojects ├── sdbusplus.wrap ├── packagefiles │ ├── boost │ │ └── meson.build │ └── boost-url │ │ └── meson.build └── boost.wrap ├── peci.pc.in ├── LICENSE ├── README.md ├── OWNERS ├── meson.build ├── dbus_raw_peci.cpp ├── .clang-format ├── peci.h ├── linux └── peci-ioctl.h ├── peci_cmds.c └── peci.c /.clang-format-ignore: -------------------------------------------------------------------------------- 1 | linux/peci-ioctl.h 2 | -------------------------------------------------------------------------------- /service_files/meson.build: -------------------------------------------------------------------------------- 1 | install_data('com.intel.peci.service', install_dir: systemd_system_unit_dir) 2 | -------------------------------------------------------------------------------- /meson.options: -------------------------------------------------------------------------------- 1 | option( 2 | 'raw-peci', 3 | type: 'feature', 4 | value: 'disabled', 5 | description: 'Build raw-peci application', 6 | ) 7 | -------------------------------------------------------------------------------- /subprojects/sdbusplus.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/openbmc/sdbusplus.git 3 | revision = HEAD 4 | 5 | [provide] 6 | sdbusplus = sdbusplus_dep 7 | -------------------------------------------------------------------------------- /subprojects/packagefiles/boost/meson.build: -------------------------------------------------------------------------------- 1 | project('boost', 'cpp', version: '1.82.0', license: 'Boost') 2 | 3 | boost_dep = declare_dependency(include_directories: include_directories('.')) 4 | -------------------------------------------------------------------------------- /subprojects/packagefiles/boost-url/meson.build: -------------------------------------------------------------------------------- 1 | project('boost-url', 'cpp', version: '0.1', license: 'Boost') 2 | 3 | boost_url_dep = declare_dependency( 4 | include_directories: include_directories('include'), 5 | ) 6 | -------------------------------------------------------------------------------- /peci.pc.in: -------------------------------------------------------------------------------- 1 | prefix="@CMAKE_INSTALL_PREFIX@" 2 | libdir="${prefix}/lib" 3 | includedir="${prefix}/include" 4 | 5 | Name: @PROJECT_NAME@ 6 | Description: PECI access library 7 | Version: @VERSION@ 8 | Cflags: -I${includedir} 9 | Libs: -L${libdir} -lpeci 10 | -------------------------------------------------------------------------------- /service_files/com.intel.peci.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Intel CPU Raw PECI interface 3 | 4 | [Service] 5 | Restart=always 6 | ExecStart=/usr/bin/raw-peci 7 | Type=dbus 8 | BusName=com.intel.peci 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /subprojects/boost.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = boost_1_82_0 3 | 4 | source_url = https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.tar.bz2 5 | source_hash = a6e1ab9b0860e6a2881dd7b21fe9f737a095e5f33a3a874afc6a345228597ee6 6 | source_filename = 1_82_0.tar.bz2 7 | 8 | patch_directory = boost 9 | 10 | [provide] 11 | boost = boost_dep 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Intel Corporation 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libpeci 2 | 3 | libpeci is a library that provides various APIs to interface with the IOCTLs 4 | provided by the PECI driver in the OpenBMC kernel. Currently available here: 5 | 6 | `https://github.com/openbmc/linux/blob/dev-5.4/include/uapi/linux/peci-ioctl.h` 7 | 8 | ## peci_cmds 9 | 10 | This repo also includes a peci_cmds command-line utility with functions that map 11 | to the libpeci APIs. It can be used to test PECI functionality across the 12 | library, driver, and hardware. 13 | 14 | ## dbus_raw_peci 15 | 16 | This repo also includes dbus_raw_peci which provides a raw-peci daemon that 17 | exposes a raw PECI interface that is accessible over D-Bus. It can be used when 18 | an application needs to send a raw PECI command without loading the full PECI 19 | library. 20 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # OWNERS 2 | # ------ 3 | # 4 | # The OWNERS file maintains the list of individuals responsible for various 5 | # parts of this repository, including code review and approval. We use the 6 | # Gerrit 'owners' plugin, which consumes this file, along with some extra 7 | # keywords for our own purposes and tooling. 8 | # 9 | # For details on the configuration used by 'owners' see: 10 | # https://gerrit.googlesource.com/plugins/owners/+/refs/heads/master/owners/src/main/resources/Documentation/config.md 11 | # 12 | # An OWNERS file must be in the root of a repository but may also be present 13 | # in any subdirectory. The contents of the subdirectory OWNERS file are 14 | # combined with parent directories unless 'inherit: false' is set. 15 | # 16 | # The owners file is YAML and has [up to] 4 top-level keywords. 17 | # * owners: A list of individuals who have approval authority on the 18 | # repository. 19 | # 20 | # * reviewers: A list of individuals who have requested review notification 21 | # on the repository. 22 | # 23 | # * matchers: A list of specific file/path matchers for granular 'owners' and 24 | # 'reviewers'. See 'owners' plugin documentation. 25 | # 26 | # * openbmc: A list of openbmc-specific meta-data about owners and reviewers. 27 | # - name: preferred name of the individual. 28 | # - email: preferred email address of the individual. 29 | # - discord: Discord nickname of the individual. 30 | # 31 | # It is expected that these 4 sections will be listed in the order above and 32 | # data within them will be kept sorted. 33 | 34 | owners: 35 | - jason.m.bills@linux.intel.com 36 | 37 | reviewers: 38 | 39 | matchers: 40 | 41 | openbmc: 42 | - name: Jason Bills 43 | email: jason.m.bills@linux.intel.com 44 | discord: jmbills 45 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'libpeci', 3 | 'c', 4 | 'cpp', 5 | version: '1.0', 6 | meson_version: '>=1.1.1', 7 | default_options: [ 8 | 'b_ndebug=if-release', 9 | 'cpp_rtti=false', 10 | 'cpp_std=c++23', 11 | 'warning_level=3', 12 | 'werror=true', 13 | ], 14 | ) 15 | 16 | if (get_option('raw-peci').allowed()) 17 | sdbusplus = dependency('sdbusplus') 18 | 19 | systemd = dependency('systemd', required: true) 20 | systemd_system_unit_dir = systemd.get_variable( 21 | pkgconfig: 'systemd_system_unit_dir', 22 | ) 23 | 24 | boost = dependency('boost', version: '>=1.82') 25 | add_project_arguments( 26 | [ 27 | '-DBOOST_ASIO_DISABLE_THREADS', 28 | '-DBOOST_ASIO_EXCEPTION_DISABLE', 29 | '-DBOOST_ASIO_NO_DEPRECATED', 30 | '-DBOOST_NO_RTTI', 31 | '-DBOOST_NO_TYPEID', 32 | ], 33 | language: 'cpp', 34 | ) 35 | endif 36 | 37 | add_project_arguments( 38 | [ 39 | '-Wcast-align', 40 | '-Wconversion', 41 | '-Wdouble-promotion', 42 | '-Wduplicated-branches', 43 | '-Wduplicated-cond', 44 | '-Wformat=2', 45 | '-Wlogical-op', 46 | '-Wsign-conversion', 47 | '-Wunused', 48 | '-Wno-unused-parameter', 49 | '-Wno-psabi', 50 | ], 51 | language: 'c', 52 | ) 53 | 54 | add_project_arguments( 55 | [ 56 | '-Wcast-align', 57 | '-Wconversion', 58 | '-Wdouble-promotion', 59 | '-Wduplicated-branches', 60 | '-Wduplicated-cond', 61 | '-Wformat=2', 62 | '-Wlogical-op', 63 | '-Wnull-dereference', 64 | '-Wsign-conversion', 65 | '-Wunused', 66 | '-Wno-psabi', 67 | '-Wno-unused-parameter', 68 | '-fno-rtti', 69 | ], 70 | language: 'cpp', 71 | ) 72 | 73 | libpeci = library( 74 | 'peci', 75 | 'peci.c', 76 | version: meson.project_version(), 77 | install: true, 78 | ) 79 | install_headers('peci.h') 80 | 81 | libpeci_dep = declare_dependency( 82 | link_with: libpeci, 83 | include_directories: include_directories('.'), 84 | ) 85 | 86 | bindir = get_option('prefix') + '/' + get_option('bindir') 87 | 88 | executable( 89 | 'peci_cmds', 90 | 'peci_cmds.c', 91 | link_with: libpeci, 92 | install: true, 93 | install_dir: bindir, 94 | ) 95 | 96 | if (get_option('raw-peci').allowed()) 97 | executable( 98 | 'raw-peci', 99 | 'dbus_raw_peci.cpp', 100 | dependencies: [boost, sdbusplus, systemd], 101 | link_with: libpeci, 102 | install: true, 103 | install_dir: bindir, 104 | ) 105 | subdir('service_files') 106 | endif 107 | 108 | import('pkgconfig').generate( 109 | libpeci, 110 | name: meson.project_name(), 111 | version: meson.project_version(), 112 | description: 'PECI utilities', 113 | ) 114 | -------------------------------------------------------------------------------- /dbus_raw_peci.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Copyright (c) 2021 Intel Corporation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | */ 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | int main() 24 | { 25 | boost::asio::io_context io; 26 | std::shared_ptr conn; 27 | std::shared_ptr server; 28 | 29 | // setup connection to dbus 30 | conn = std::make_shared(io); 31 | 32 | conn->request_name("com.intel.peci"); 33 | server = std::make_shared(conn); 34 | 35 | // Send Raw PECI Interface 36 | std::shared_ptr ifaceRawPeci = 37 | server->add_interface("/com/intel/peci", "com.intel.Protocol.PECI.Raw"); 38 | 39 | // Send a Raw PECI command 40 | ifaceRawPeci->register_method( 41 | "Send", [](const std::string& peciDev, 42 | const std::vector>& rawCmds) { 43 | peci_SetDevName(const_cast(peciDev.c_str())); 44 | // D-Bus will time out after too long, so set a deadline for when to 45 | // abort the PECI commands (at 25s, it mostly times out, at 24s it 46 | // doesn't, so use 23s to be safe) 47 | constexpr int peciTimeout = 23; 48 | std::chrono::steady_clock::time_point peciDeadline = 49 | std::chrono::steady_clock::now() + 50 | std::chrono::duration(peciTimeout); 51 | std::vector> rawResp; 52 | rawResp.resize(rawCmds.size()); 53 | for (size_t i = 0; i < rawCmds.size(); i++) 54 | { 55 | const std::vector& rawCmd = rawCmds[i]; 56 | // If the commands are taking too long, return early to avoid a 57 | // D-Bus timeout 58 | if (std::chrono::steady_clock::now() > peciDeadline) 59 | { 60 | std::cerr << peciTimeout 61 | << " second deadline reached. Aborting PECI " 62 | "commands to avoid a timeout\n"; 63 | break; 64 | } 65 | 66 | if (rawCmd.size() < 3) 67 | { 68 | peci_SetDevName(NULL); 69 | throw std::invalid_argument("Command Length too short"); 70 | } 71 | rawResp[i].resize(rawCmd[2]); 72 | peci_raw(rawCmd[0], rawCmd[2], &rawCmd[3], rawCmd[1], 73 | rawResp[i].data(), 74 | static_cast(rawResp[i].size())); 75 | } 76 | peci_SetDevName(NULL); 77 | return rawResp; 78 | }); 79 | ifaceRawPeci->initialize(); 80 | 81 | io.run(); 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: Align 10 | AlignTrailingComments: 11 | Kind: Always 12 | OverEmptyLines: 1 13 | AllowAllParametersOfDeclarationOnNextLine: true 14 | AllowShortBlocksOnASingleLine: Empty 15 | AllowShortCaseLabelsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: Empty 17 | AllowShortIfStatementsOnASingleLine: Never 18 | AllowShortLambdasOnASingleLine: true 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakBeforeMultilineStrings: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BitFieldColonSpacing: None 24 | BraceWrapping: 25 | AfterCaseLabel: true 26 | AfterClass: true 27 | AfterControlStatement: true 28 | AfterEnum: true 29 | AfterExternBlock: true 30 | AfterFunction: true 31 | AfterNamespace: true 32 | AfterObjCDeclaration: true 33 | AfterStruct: true 34 | AfterUnion: true 35 | BeforeCatch: true 36 | BeforeElse: true 37 | BeforeLambdaBody: false 38 | BeforeWhile: false 39 | IndentBraces: false 40 | SplitEmptyFunction: false 41 | SplitEmptyRecord: false 42 | SplitEmptyNamespace: false 43 | BreakAfterAttributes: Never 44 | BreakAfterReturnType: Automatic 45 | BreakBeforeBinaryOperators: None 46 | BreakBeforeBraces: Custom 47 | BreakBeforeTernaryOperators: true 48 | BreakConstructorInitializers: AfterColon 49 | BreakInheritanceList: AfterColon 50 | BreakStringLiterals: false 51 | BreakTemplateDeclarations: Yes 52 | ColumnLimit: 80 53 | CommentPragmas: '^ IWYU pragma:' 54 | CompactNamespaces: false 55 | ConstructorInitializerIndentWidth: 4 56 | ContinuationIndentWidth: 4 57 | Cpp11BracedListStyle: true 58 | DerivePointerAlignment: false 59 | DisableFormat: false 60 | FixNamespaceComments: true 61 | ForEachMacros: 62 | - foreach 63 | - Q_FOREACH 64 | - BOOST_FOREACH 65 | IncludeBlocks: Regroup 66 | IncludeCategories: 67 | - Regex: '^[<"](gtest|gmock)' 68 | Priority: 7 69 | - Regex: '^"config.h"' 70 | Priority: -1 71 | - Regex: '^".*\.h"' 72 | Priority: 1 73 | - Regex: '^".*\.hpp"' 74 | Priority: 2 75 | - Regex: '^<.*\.h>' 76 | Priority: 3 77 | - Regex: '^<.*\.hpp>' 78 | Priority: 4 79 | - Regex: '^<.*' 80 | Priority: 5 81 | - Regex: '.*' 82 | Priority: 6 83 | IndentCaseLabels: true 84 | IndentExternBlock: NoIndent 85 | IndentRequiresClause: true 86 | IndentWidth: 4 87 | IndentWrappedFunctionNames: true 88 | InsertNewlineAtEOF: true 89 | KeepEmptyLinesAtTheStartOfBlocks: false 90 | LambdaBodyIndentation: Signature 91 | LineEnding: LF 92 | MacroBlockBegin: '' 93 | MacroBlockEnd: '' 94 | MaxEmptyLinesToKeep: 1 95 | NamespaceIndentation: None 96 | ObjCBlockIndentWidth: 2 97 | ObjCSpaceAfterProperty: false 98 | ObjCSpaceBeforeProtocolList: true 99 | PackConstructorInitializers: BinPack 100 | PenaltyBreakAssignment: 25 101 | PenaltyBreakBeforeFirstCallParameter: 50 102 | PenaltyBreakComment: 300 103 | PenaltyBreakFirstLessLess: 120 104 | PenaltyBreakString: 1000 105 | PenaltyBreakTemplateDeclaration: 10 106 | PenaltyExcessCharacter: 1000000 107 | PenaltyReturnTypeOnItsOwnLine: 150 108 | PenaltyIndentedWhitespace: 1 109 | PointerAlignment: Left 110 | QualifierAlignment: Left 111 | ReferenceAlignment: Left 112 | ReflowComments: true 113 | RequiresClausePosition: OwnLine 114 | RequiresExpressionIndentation: Keyword 115 | SortIncludes: CaseSensitive 116 | SortUsingDeclarations: true 117 | SpaceAfterCStyleCast: false 118 | SpaceAfterTemplateKeyword: true 119 | SpaceBeforeAssignmentOperators: true 120 | SpaceBeforeCpp11BracedList: false 121 | SpaceBeforeCtorInitializerColon: true 122 | SpaceBeforeInheritanceColon: true 123 | SpaceBeforeParens: ControlStatements 124 | SpaceBeforeRangeBasedForLoopColon: true 125 | SpaceInEmptyParentheses: false 126 | SpacesBeforeTrailingComments: 1 127 | SpacesInAngles: Never 128 | SpacesInContainerLiterals: true 129 | SpacesInCStyleCastParentheses: false 130 | SpacesInParentheses: false 131 | SpacesInSquareBrackets: false 132 | Standard: Latest 133 | TabWidth: 4 134 | UseTab: Never 135 | ... 136 | 137 | -------------------------------------------------------------------------------- /peci.h: -------------------------------------------------------------------------------- 1 | /* 2 | // Copyright (c) 2019 Intel Corporation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | */ 16 | #pragma once 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | #endif 21 | #include 22 | #include 23 | 24 | // PECI Client Address List 25 | #define MIN_CLIENT_ADDR 0x30 26 | #define MAX_CLIENT_ADDR 0x37 27 | #define MAX_CPUS (MAX_CLIENT_ADDR - MIN_CLIENT_ADDR + 1) 28 | 29 | // PECI completion codes from peci-ioctl.h 30 | #define PECI_DEV_CC_SUCCESS 0x40 31 | #define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94 32 | 33 | typedef enum 34 | { 35 | skylake = 0x00050650, 36 | iceLake = 0x000606A0, 37 | iceLakeD = 0x000606C0, 38 | sapphireRapids = 0x000806F0, 39 | emeraldRapids = 0x000C06F0, 40 | graniteRapids = 0x000A06D0, 41 | graniteRapidsD = 0x000A06E0, 42 | sierraForest = 0x000A06F0, 43 | } CPUModel; 44 | 45 | // PECI Status Codes 46 | typedef enum 47 | { 48 | PECI_CC_SUCCESS = 0, 49 | PECI_CC_INVALID_REQ, 50 | PECI_CC_HW_ERR, 51 | PECI_CC_DRIVER_ERR, 52 | PECI_CC_CPU_NOT_PRESENT, 53 | PECI_CC_MEM_ERR, 54 | PECI_CC_TIMEOUT, 55 | } EPECIStatus; 56 | 57 | // PECI Timeout Options 58 | typedef enum 59 | { 60 | PECI_WAIT_FOREVER = -1, 61 | PECI_NO_WAIT = 0, 62 | } EPECITimeout; 63 | 64 | #define PECI_TIMEOUT_RESOLUTION_MS 10 // 10 ms 65 | #define PECI_TIMEOUT_MS 100 // 100 ms 66 | 67 | // VCU Index and Sequence Parameters 68 | #define VCU_SET_PARAM 0x0001 69 | #define VCU_READ 0x0002 70 | #define VCU_OPEN_SEQ 0x0003 71 | #define VCU_CLOSE_SEQ 0x0004 72 | #define VCU_ABORT_SEQ 0x0005 73 | #define VCU_VERSION 0x0009 74 | 75 | typedef enum 76 | { 77 | VCU_READ_LOCAL_CSR_SEQ = 0x2, 78 | VCU_READ_LOCAL_MMIO_SEQ = 0x6, 79 | VCU_EN_SECURE_DATA_SEQ = 0x14, 80 | VCU_CORE_MCA_SEQ = 0x10000, 81 | VCU_UNCORE_MCA_SEQ = 0x10000, 82 | VCU_IOT_BRKPT_SEQ = 0x10010, 83 | VCU_MBP_CONFIG_SEQ = 0x10026, 84 | VCU_PWR_MGT_SEQ = 0x1002a, 85 | VCU_CRASHDUMP_SEQ = 0x10038, 86 | VCU_ARRAY_DUMP_SEQ = 0x20000, 87 | VCU_SCAN_DUMP_SEQ = 0x20008, 88 | VCU_TOR_DUMP_SEQ = 0x30002, 89 | VCU_SQ_DUMP_SEQ = 0x30004, 90 | VCU_UNCORE_CRASHDUMP_SEQ = 0x30006, 91 | } EPECISequence; 92 | 93 | #define MBX_INDEX_VCU 128 // VCU Index 94 | 95 | typedef enum 96 | { 97 | MMIO_DWORD_OFFSET = 0x05, 98 | MMIO_QWORD_OFFSET = 0x06, 99 | } EEndPtMmioAddrType; 100 | 101 | // Find the specified PCI bus number value 102 | EPECIStatus FindBusNumber(uint8_t u8Bus, uint8_t u8Cpu, uint8_t* pu8BusValue); 103 | 104 | // Gets the temperature from the target 105 | // Expressed in signed fixed point value of 1/64 degrees celsius 106 | EPECIStatus peci_GetTemp(uint8_t target, int16_t* temperature); 107 | 108 | // Provides read access to the package configuration space within the 109 | // processor 110 | EPECIStatus peci_RdPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Value, 111 | uint8_t u8ReadLen, uint8_t* pPkgConfig, 112 | uint8_t* cc); 113 | 114 | // Provides read access to the package configuration space within the 115 | // processor in the specified domain 116 | EPECIStatus peci_RdPkgConfig_dom( 117 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Value, 118 | uint8_t u8ReadLen, uint8_t* pPkgConfig, uint8_t* cc); 119 | 120 | // Allows sequential RdPkgConfig with the provided peci file descriptor 121 | EPECIStatus peci_RdPkgConfig_seq(uint8_t target, uint8_t u8Index, 122 | uint16_t u16Value, uint8_t u8ReadLen, 123 | uint8_t* pPkgConfig, int peci_fd, uint8_t* cc); 124 | 125 | // Allows sequential RdPkgConfig with the provided peci file descriptor in 126 | // the specified domain 127 | EPECIStatus peci_RdPkgConfig_seq_dom( 128 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Value, 129 | uint8_t u8ReadLen, uint8_t* pPkgConfig, int peci_fd, uint8_t* cc); 130 | 131 | // Provides write access to the package configuration space within the 132 | // processor 133 | EPECIStatus peci_WrPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Param, 134 | uint32_t u32Value, uint8_t u8WriteLen, 135 | uint8_t* cc); 136 | 137 | // Provides write access to the package configuration space within the 138 | // processor in the specified domain 139 | EPECIStatus peci_WrPkgConfig_dom( 140 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Param, 141 | uint32_t u32Value, uint8_t u8WriteLen, uint8_t* cc); 142 | 143 | // Allows sequential WrPkgConfig with the provided peci file descriptor 144 | EPECIStatus peci_WrPkgConfig_seq(uint8_t target, uint8_t u8Index, 145 | uint16_t u16Param, uint32_t u32Value, 146 | uint8_t u8WriteLen, int peci_fd, uint8_t* cc); 147 | 148 | // Allows sequential WrPkgConfig with the provided peci file descriptor in 149 | // the specified domain 150 | EPECIStatus peci_WrPkgConfig_seq_dom( 151 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Param, 152 | uint32_t u32Value, uint8_t u8WriteLen, int peci_fd, uint8_t* cc); 153 | 154 | // Provides read access to Model Specific Registers 155 | EPECIStatus peci_RdIAMSR(uint8_t target, uint8_t threadID, uint16_t MSRAddress, 156 | uint64_t* u64MsrVal, uint8_t* cc); 157 | 158 | // Provides read access to Model Specific Registers in the specified domain 159 | EPECIStatus peci_RdIAMSR_dom(uint8_t target, uint8_t domainId, uint8_t threadID, 160 | uint16_t MSRAddress, uint64_t* u64MsrVal, 161 | uint8_t* cc); 162 | 163 | // Provides read access to PCI Configuration space 164 | EPECIStatus peci_RdPCIConfig(uint8_t target, uint8_t u8Bus, uint8_t u8Device, 165 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIReg, 166 | uint8_t* cc); 167 | 168 | // Provides read access to PCI Configuration space in the specified domain 169 | EPECIStatus peci_RdPCIConfig_dom( 170 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 171 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIReg, uint8_t* cc); 172 | 173 | // Allows sequential RdPCIConfig with the provided peci file descriptor 174 | EPECIStatus peci_RdPCIConfig_seq( 175 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 176 | uint16_t u16Reg, uint8_t* pPCIData, int peci_fd, uint8_t* cc); 177 | 178 | // Allows sequential RdPCIConfig with the provided peci file descriptor in 179 | // the specified domain 180 | EPECIStatus peci_RdPCIConfig_seq_dom( 181 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 182 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData, int peci_fd, 183 | uint8_t* cc); 184 | 185 | // Provides read access to the local PCI Configuration space 186 | EPECIStatus peci_RdPCIConfigLocal( 187 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 188 | uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, uint8_t* cc); 189 | 190 | // Provides read access to the local PCI Configuration space in the 191 | // specified domain 192 | EPECIStatus peci_RdPCIConfigLocal_dom( 193 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 194 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, 195 | uint8_t* cc); 196 | 197 | // Allows sequential RdPCIConfigLocal with the provided peci file descriptor 198 | EPECIStatus peci_RdPCIConfigLocal_seq( 199 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 200 | uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, int peci_fd, 201 | uint8_t* cc); 202 | 203 | // Allows sequential RdPCIConfigLocal with the provided peci file descriptor 204 | // in the specified domain 205 | EPECIStatus peci_RdPCIConfigLocal_seq_dom( 206 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 207 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, 208 | int peci_fd, uint8_t* cc); 209 | 210 | // Provides write access to the local PCI Configuration space 211 | EPECIStatus peci_WrPCIConfigLocal( 212 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 213 | uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, uint8_t* cc); 214 | 215 | // Provides write access to the local PCI Configuration space in the 216 | // specified domain 217 | EPECIStatus peci_WrPCIConfigLocal_dom( 218 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 219 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, 220 | uint8_t* cc); 221 | 222 | // Provides read access to PCI configuration space 223 | EPECIStatus peci_RdEndPointConfigPci( 224 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 225 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 226 | uint8_t* cc); 227 | 228 | // Provides read access to PCI configuration space in the specified domain 229 | EPECIStatus peci_RdEndPointConfigPci_dom( 230 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 231 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 232 | uint8_t* pPCIData, uint8_t* cc); 233 | 234 | // Allows sequential RdEndPointConfig to PCI Configuration space 235 | EPECIStatus peci_RdEndPointConfigPci_seq( 236 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 237 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 238 | int peci_fd, uint8_t* cc); 239 | 240 | // Allows sequential RdEndPointConfig to PCI Configuration space in the 241 | // specified domain 242 | EPECIStatus peci_RdEndPointConfigPci_seq_dom( 243 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 244 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 245 | uint8_t* pPCIData, int peci_fd, uint8_t* cc); 246 | 247 | // Provides read access to the local PCI configuration space 248 | EPECIStatus peci_RdEndPointConfigPciLocal( 249 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 250 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 251 | uint8_t* cc); 252 | 253 | // Provides read access to the local PCI configuration space in the 254 | // specified domain 255 | EPECIStatus peci_RdEndPointConfigPciLocal_dom( 256 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 257 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 258 | uint8_t* pPCIData, uint8_t* cc); 259 | 260 | // Allows sequential RdEndPointConfig to the local PCI Configuration space 261 | EPECIStatus peci_RdEndPointConfigPciLocal_seq( 262 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 263 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 264 | int peci_fd, uint8_t* cc); 265 | 266 | // Allows sequential RdEndPointConfig to the local PCI Configuration space 267 | // in the specified domain 268 | EPECIStatus peci_RdEndPointConfigPciLocal_seq_dom( 269 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 270 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 271 | uint8_t* pPCIData, int peci_fd, uint8_t* cc); 272 | 273 | // Provides read access to PCI MMIO space 274 | EPECIStatus peci_RdEndPointConfigMmio( 275 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 276 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 277 | uint8_t u8ReadLen, uint8_t* pMmioData, uint8_t* cc); 278 | 279 | // Provides read access to PCI MMIO space in the specified domain 280 | EPECIStatus peci_RdEndPointConfigMmio_dom( 281 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 282 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 283 | uint64_t u64Offset, uint8_t u8ReadLen, uint8_t* pMmioData, uint8_t* cc); 284 | 285 | // Allows sequential RdEndPointConfig to PCI MMIO space 286 | EPECIStatus peci_RdEndPointConfigMmio_seq( 287 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 288 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 289 | uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, uint8_t* cc); 290 | 291 | // Allows sequential RdEndPointConfig to PCI MMIO space in the specified 292 | // domain 293 | EPECIStatus peci_RdEndPointConfigMmio_seq_dom( 294 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 295 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 296 | uint64_t u64Offset, uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, 297 | uint8_t* cc); 298 | 299 | // Provides write access to the EP local PCI Configuration space 300 | EPECIStatus peci_WrEndPointPCIConfigLocal( 301 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 302 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, 303 | uint8_t* cc); 304 | 305 | // Provides write access to the EP local PCI Configuration space in the 306 | // specified domain 307 | EPECIStatus peci_WrEndPointPCIConfigLocal_dom( 308 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 309 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, 310 | uint32_t DataVal, uint8_t* cc); 311 | 312 | // Provides write access to the EP PCI Configuration space 313 | EPECIStatus peci_WrEndPointPCIConfig( 314 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 315 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, 316 | uint8_t* cc); 317 | 318 | // Provides write access to the EP PCI Configuration space in the specified 319 | // domain 320 | EPECIStatus peci_WrEndPointPCIConfig_dom( 321 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 322 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, 323 | uint32_t DataVal, uint8_t* cc); 324 | 325 | // Allows sequential write access to the EP PCI Configuration space 326 | EPECIStatus peci_WrEndPointConfig_seq( 327 | uint8_t target, uint8_t u8MsgType, uint8_t u8Seg, uint8_t u8Bus, 328 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, 329 | uint32_t DataVal, int peci_fd, uint8_t* cc); 330 | 331 | // Allows sequential write access to the EP PCI Configuration space in the 332 | // specified domain 333 | EPECIStatus peci_WrEndPointConfig_seq_dom( 334 | uint8_t target, uint8_t domainId, uint8_t u8MsgType, uint8_t u8Seg, 335 | uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, 336 | uint8_t DataLen, uint32_t DataVal, int peci_fd, uint8_t* cc); 337 | 338 | // Provides write access to the EP PCI MMIO space 339 | EPECIStatus peci_WrEndPointConfigMmio( 340 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 341 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 342 | uint8_t u8DataLen, uint64_t u64DataVal, uint8_t* cc); 343 | 344 | // Provides write access to the EP PCI MMIO space in the specified domain 345 | EPECIStatus peci_WrEndPointConfigMmio_dom( 346 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 347 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 348 | uint64_t u64Offset, uint8_t u8DataLen, uint64_t u64DataVal, uint8_t* cc); 349 | 350 | // Allows sequential write access to the EP PCI MMIO space 351 | EPECIStatus peci_WrEndPointConfigMmio_seq( 352 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 353 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 354 | uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, uint8_t* cc); 355 | 356 | // Allows sequential write access to the EP PCI MMIO space in the specified 357 | // domain 358 | EPECIStatus peci_WrEndPointConfigMmio_seq_dom( 359 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 360 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 361 | uint64_t u64Offset, uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, 362 | uint8_t* cc); 363 | 364 | // Provides access to the Crashdump Discovery API 365 | EPECIStatus peci_CrashDump_Discovery( 366 | uint8_t target, uint8_t subopcode, uint8_t param0, uint16_t param1, 367 | uint8_t param2, uint8_t u8ReadLen, uint8_t* pData, uint8_t* cc); 368 | 369 | // Provides access to the Crashdump Discovery API in the specified domain 370 | EPECIStatus peci_CrashDump_Discovery_dom( 371 | uint8_t target, uint8_t domainId, uint8_t subopcode, uint8_t param0, 372 | uint16_t param1, uint8_t param2, uint8_t u8ReadLen, uint8_t* pData, 373 | uint8_t* cc); 374 | 375 | // Provides access to the Crashdump GetFrame API 376 | EPECIStatus peci_CrashDump_GetFrame( 377 | uint8_t target, uint16_t param0, uint16_t param1, uint16_t param2, 378 | uint8_t u8ReadLen, uint8_t* pData, uint8_t* cc); 379 | 380 | // Provides access to the Crashdump GetFrame API in the specified domain 381 | EPECIStatus peci_CrashDump_GetFrame_dom( 382 | uint8_t target, uint8_t domainId, uint16_t param0, uint16_t param1, 383 | uint16_t param2, uint8_t u8ReadLen, uint8_t* pData, uint8_t* cc); 384 | 385 | // Provides raw PECI command access 386 | EPECIStatus peci_raw(uint8_t target, uint8_t u8ReadLen, const uint8_t* pRawCmd, 387 | const uint32_t cmdSize, uint8_t* pRawResp, 388 | uint32_t respSize); 389 | 390 | // Provides sequential raw PECI command access 391 | EPECIStatus peci_raw_seq(uint8_t target, uint8_t u8ReadLen, 392 | const uint8_t* pRawCmd, const uint32_t cmdSize, 393 | uint8_t* pRawResp, uint32_t respSize, int peci_fd); 394 | 395 | EPECIStatus peci_Lock(int* peci_fd, int timeout_ms); 396 | void peci_Unlock(int peci_fd); 397 | EPECIStatus peci_Ping(uint8_t target); 398 | EPECIStatus peci_Ping_seq(uint8_t target, int peci_fd); 399 | EPECIStatus peci_GetCPUID(const uint8_t clientAddr, CPUModel* cpuModel, 400 | uint8_t* stepping, uint8_t* cc); 401 | void peci_SetDevName(char* peci_dev); 402 | 403 | #ifdef __cplusplus 404 | } 405 | #endif 406 | -------------------------------------------------------------------------------- /linux/peci-ioctl.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2018-2020 Intel Corporation */ 3 | 4 | #ifndef __PECI_IOCTL_H 5 | #define __PECI_IOCTL_H 6 | 7 | #include 8 | #include 9 | 10 | /* The PECI client's default address of 0x30 */ 11 | #define PECI_BASE_ADDR 0x30 12 | 13 | /* Max number of CPU clients */ 14 | #define PECI_OFFSET_MAX 8 15 | 16 | /* PECI read/write data buffer size max */ 17 | #define PECI_BUFFER_SIZE 255 18 | 19 | /* Device Specific Completion Code (CC) Definition */ 20 | #define PECI_DEV_CC_SUCCESS 0x40 21 | #define PECI_DEV_CC_NEED_RETRY 0x80 22 | #define PECI_DEV_CC_OUT_OF_RESOURCE 0x81 23 | #define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82 24 | #define PECI_DEV_CC_INVALID_REQ 0x90 25 | #define PECI_DEV_CC_MCA_ERROR 0x91 26 | #define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93 27 | #define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94 28 | #define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98 29 | #define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B 30 | #define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C 31 | 32 | /* Completion Code mask to check retry needs */ 33 | #define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0 34 | 35 | #define PECI_DEV_RETRY_TIMEOUT msecs_to_jiffies(700) 36 | #define PECI_DEV_RETRY_INTERVAL_MIN_USEC 100 37 | #define PECI_DEV_RETRY_INTERVAL_MAX_USEC (128 * 1000) 38 | #define PECI_DEV_RETRY_BIT 0x01 39 | 40 | /** 41 | * enum peci_cmd - PECI client commands 42 | * @PECI_CMD_XFER: raw PECI transfer 43 | * @PECI_CMD_PING: ping, a required message for all PECI devices 44 | * @PECI_CMD_GET_DIB: get DIB (Device Info Byte) 45 | * @PECI_CMD_GET_TEMP: get maximum die temperature 46 | * @PECI_CMD_RD_PKG_CFG: read access to the PCS (Package Configuration Space) 47 | * @PECI_CMD_WR_PKG_CFG: write access to the PCS (Package Configuration Space) 48 | * @PECI_CMD_RD_IA_MSR: read access to MSRs (Model Specific Registers) 49 | * @PECI_CMD_WR_IA_MSR: write access to MSRs (Model Specific Registers) 50 | * @PECI_CMD_RD_IA_MSREX: read access to MSRs (Model Specific Registers) 51 | * @PECI_CMD_RD_PCI_CFG: sideband read access to the PCI configuration space 52 | * maintained in downstream devices external to the processor 53 | * @PECI_CMD_WR_PCI_CFG: sideband write access to the PCI configuration space 54 | * maintained in downstream devices external to the processor 55 | * @PECI_CMD_RD_PCI_CFG_LOCAL: sideband read access to the PCI configuration 56 | * space that resides within the processor 57 | * @PECI_CMD_WR_PCI_CFG_LOCAL: sideband write access to the PCI configuration 58 | * space that resides within the processor 59 | * 60 | * Available commands depend on client's PECI revision. 61 | */ 62 | enum peci_cmd { 63 | PECI_CMD_XFER = 0, 64 | PECI_CMD_PING, 65 | PECI_CMD_GET_DIB, 66 | PECI_CMD_GET_TEMP, 67 | PECI_CMD_RD_PKG_CFG, 68 | PECI_CMD_WR_PKG_CFG, 69 | PECI_CMD_RD_IA_MSR, 70 | PECI_CMD_WR_IA_MSR, 71 | PECI_CMD_RD_IA_MSREX, 72 | PECI_CMD_RD_PCI_CFG, 73 | PECI_CMD_WR_PCI_CFG, 74 | PECI_CMD_RD_PCI_CFG_LOCAL, 75 | PECI_CMD_WR_PCI_CFG_LOCAL, 76 | PECI_CMD_RD_END_PT_CFG, 77 | PECI_CMD_WR_END_PT_CFG, 78 | PECI_CMD_CRASHDUMP_DISC, 79 | PECI_CMD_CRASHDUMP_GET_FRAME, 80 | PECI_CMD_MAX 81 | }; 82 | 83 | /** 84 | * struct peci_xfer_msg - raw PECI transfer command 85 | * @addr; address of the client 86 | * @tx_len: number of data to be written in bytes 87 | * @rx_len: number of data to be read in bytes 88 | * @tx_buf: data to be written, or NULL 89 | * @rx_buf: data to be read, or NULL 90 | * 91 | * raw PECI transfer 92 | */ 93 | struct peci_xfer_msg { 94 | __u8 addr; 95 | __u8 tx_len; 96 | __u8 rx_len; 97 | __u8 padding; 98 | __u8 *tx_buf; 99 | __u8 *rx_buf; 100 | } __attribute__((__packed__)); 101 | 102 | /** 103 | * struct peci_ping_msg - ping command 104 | * @addr: address of the client 105 | * 106 | * Ping() is a required message for all PECI devices. This message is used to 107 | * enumerate devices or determine if a device has been removed, been 108 | * powered-off, etc. 109 | */ 110 | struct peci_ping_msg { 111 | __u8 addr; 112 | __u8 padding[3]; 113 | } __attribute__((__packed__)); 114 | 115 | /** 116 | * struct peci_get_dib_msg - GetDIB command 117 | * @addr: address of the client 118 | * @dib: DIB data to be read 119 | * 120 | * The processor PECI client implementation of GetDIB() includes an 8-byte 121 | * response and provides information regarding client revision number and the 122 | * number of supported domains. All processor PECI clients support the GetDIB() 123 | * command. 124 | */ 125 | struct peci_get_dib_msg { 126 | #define PECI_GET_DIB_WR_LEN 1 127 | #define PECI_GET_DIB_RD_LEN 8 128 | #define PECI_GET_DIB_CMD 0xf7 129 | 130 | __u8 addr; 131 | __u8 padding[3]; 132 | __u64 dib; 133 | } __attribute__((__packed__)); 134 | 135 | /** 136 | * struct peci_get_temp_msg - GetTemp command 137 | * @addr: address of the client 138 | * @temp_raw: raw temperature data to be read 139 | * 140 | * The GetTemp() command is used to retrieve the maximum die temperature from a 141 | * target PECI address. The temperature is used by the external thermal 142 | * management system to regulate the temperature on the die. The data is 143 | * returned as a negative value representing the number of degrees centigrade 144 | * below the maximum processor junction temperature. 145 | */ 146 | struct peci_get_temp_msg { 147 | #define PECI_GET_TEMP_WR_LEN 1 148 | #define PECI_GET_TEMP_RD_LEN 2 149 | #define PECI_GET_TEMP_CMD 0x01 150 | 151 | __u8 addr; 152 | __u8 padding; 153 | __s16 temp_raw; 154 | } __attribute__((__packed__)); 155 | 156 | /** 157 | * struct peci_rd_pkg_cfg_msg - RdPkgConfig command 158 | * @addr: address of the client 159 | * @index: encoding index for the requested service 160 | * @param: specific data being requested 161 | * @rx_len: number of data to be read in bytes 162 | * @cc: completion code 163 | * @pkg_config: package config data to be read 164 | * @domain_id: domain ID of the client 165 | * 166 | * The RdPkgConfig() command provides read access to the Package Configuration 167 | * Space (PCS) within the processor, including various power and thermal 168 | * management functions. Typical PCS read services supported by the processor 169 | * may include access to temperature data, energy status, run time information, 170 | * DIMM temperatures and so on. 171 | */ 172 | struct peci_rd_pkg_cfg_msg { 173 | #define PECI_RDPKGCFG_WRITE_LEN 5 174 | #define PECI_RDPKGCFG_READ_LEN_BASE 1 175 | #define PECI_RDPKGCFG_CMD 0xa1 176 | 177 | __u8 addr; 178 | __u8 index; 179 | #define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ 180 | #define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */ 181 | #define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ 182 | #define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ 183 | #define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ 184 | #define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ 185 | #define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */ 186 | #define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ 187 | #define PECI_MBX_INDEX_MODULE_TEMP 9 /* Module Temperature Read */ 188 | #define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ 189 | #define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ 190 | #define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ 191 | #define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ 192 | #define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ 193 | #define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ 194 | #define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ 195 | #define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ 196 | #define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ 197 | #define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ 198 | #define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ 199 | #define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ 200 | #define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ 201 | #define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */ 202 | #define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ 203 | #define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ 204 | #define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ 205 | #define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ 206 | #define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ 207 | #define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ 208 | #define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ 209 | #define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ 210 | #define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ 211 | #define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ 212 | #define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ 213 | #define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ 214 | #define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ 215 | #define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ 216 | #define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ 217 | #define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ 218 | #define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ 219 | #define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ 220 | #define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ 221 | #define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ 222 | #define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ 223 | #define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ 224 | #define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ 225 | #define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ 226 | 227 | __u16 param; 228 | /* When index is PECI_MBX_INDEX_CPU_ID */ 229 | #define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */ 230 | #define PECI_PKG_POWER_SKU_UNIT 0x0000 /* Time, Energy, Power units */ 231 | #define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ 232 | #define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ 233 | #define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ 234 | #define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ 235 | #define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ 236 | #define PECI_PKG_ID_CPU_PACKAGE 0x00ff /* CPU package ID*/ 237 | #define PECI_PKG_ID_DIMM 0x00ff /* DIMM ID*/ 238 | #define PECI_PKG_ID_PLATFORM 0x00fe /* Entire platform ID */ 239 | 240 | __u8 rx_len; 241 | __u8 cc; 242 | __u8 padding[2]; 243 | __u8 pkg_config[4]; 244 | __u8 domain_id; 245 | __u8 padding1[3]; 246 | } __attribute__((__packed__)); 247 | 248 | /** 249 | * struct peci_wr_pkg_cfg_msg - WrPkgConfig command 250 | * @addr: address of the client 251 | * @index: encoding index for the requested service 252 | * @param: specific data being requested 253 | * @tx_len: number of data to be written in bytes 254 | * @cc: completion code 255 | * @value: package config data to be written 256 | * @domain_id: domain ID of the client 257 | * 258 | * The WrPkgConfig() command provides write access to the Package Configuration 259 | * Space (PCS) within the processor, including various power and thermal 260 | * management functions. Typical PCS write services supported by the processor 261 | * may include power limiting, thermal averaging constant programming and so 262 | * on. 263 | */ 264 | struct peci_wr_pkg_cfg_msg { 265 | #define PECI_WRPKGCFG_WRITE_LEN_BASE 6 266 | #define PECI_WRPKGCFG_READ_LEN 1 267 | #define PECI_WRPKGCFG_CMD 0xa5 268 | 269 | __u8 addr; 270 | __u8 index; 271 | #define PECI_MBX_INDEX_DIMM_AMBIENT 19 272 | #define PECI_MBX_INDEX_DIMM_TEMP 24 273 | 274 | __u16 param; 275 | __u8 tx_len; 276 | __u8 cc; 277 | __u8 padding[2]; 278 | __u32 value; 279 | __u8 domain_id; 280 | __u8 padding1[3]; 281 | } __attribute__((__packed__)); 282 | 283 | /** 284 | * struct peci_rd_ia_msr_msg - RdIAMSR command 285 | * @addr: address of the client 286 | * @thread_id: ID of the specific logical processor 287 | * @address: address of MSR to read from 288 | * @cc: completion code 289 | * @value: data to be read 290 | * @domain_id: domain ID of the client 291 | * 292 | * The RdIAMSR() PECI command provides read access to Model Specific Registers 293 | * (MSRs) defined in the processor's Intel Architecture (IA). 294 | */ 295 | struct peci_rd_ia_msr_msg { 296 | #define PECI_RDIAMSR_WRITE_LEN 5 297 | #define PECI_RDIAMSR_READ_LEN 9 298 | #define PECI_RDIAMSR_CMD 0xb1 299 | 300 | __u8 addr; 301 | __u8 thread_id; 302 | __u16 address; 303 | __u8 cc; 304 | __u8 padding[3]; 305 | __u64 value; 306 | __u8 domain_id; 307 | __u8 padding1[3]; 308 | } __attribute__((__packed__)); 309 | 310 | /** 311 | * struct peci_wr_ia_msr_msg - WrIAMSR command 312 | * @addr: address of the client 313 | * @thread_id: ID of the specific logical processor 314 | * @address: address of MSR to write to 315 | * @tx_len: number of data to be written in bytes 316 | * @cc: completion code 317 | * @value: data to be written 318 | * @domain_id: domain ID of the client 319 | * 320 | * The WrIAMSR() PECI command provides write access to Model Specific Registers 321 | * (MSRs) defined in the processor's Intel Architecture (IA). 322 | */ 323 | struct peci_wr_ia_msr_msg { 324 | #define PECI_WRIAMSR_CMD 0xb5 325 | 326 | __u8 addr; 327 | __u8 thread_id; 328 | __u16 address; 329 | __u8 tx_len; 330 | __u8 cc; 331 | __u8 padding[2]; 332 | __u64 value; 333 | __u8 domain_id; 334 | __u8 padding1[3]; 335 | } __attribute__((__packed__)); 336 | 337 | /** 338 | * struct peci_rd_ia_msrex_msg - RdIAMSREX command 339 | * @addr: address of the client 340 | * @thread_id: ID of the specific logical processor 341 | * @address: address of MSR to read from 342 | * @cc: completion code 343 | * @value: data to be read 344 | * @domain_id: domain ID of the client 345 | * 346 | * The RdIAMSREX() PECI command provides read access to Model Specific 347 | * Registers (MSRs) defined in the processor's Intel Architecture (IA). 348 | * The differences between RdIAMSREX() and RdIAMSR() are that: 349 | * (1)RdIAMSR() can only read MC registers, RdIAMSREX() can read all MSRs 350 | * (2)thread_id of RdIAMSR() is u8, thread_id of RdIAMSREX() is u16 351 | */ 352 | struct peci_rd_ia_msrex_msg { 353 | #define PECI_RDIAMSREX_WRITE_LEN 6 354 | #define PECI_RDIAMSREX_READ_LEN 9 355 | #define PECI_RDIAMSREX_CMD 0xd1 356 | 357 | __u8 addr; 358 | __u8 padding0; 359 | __u16 thread_id; 360 | __u16 address; 361 | __u8 cc; 362 | __u8 padding1; 363 | __u64 value; 364 | __u8 domain_id; 365 | __u8 padding2[3]; 366 | } __attribute__((__packed__)); 367 | 368 | /** 369 | * struct peci_rd_pci_cfg_msg - RdPCIConfig command 370 | * @addr: address of the client 371 | * @bus: PCI bus number 372 | * @device: PCI device number 373 | * @function: specific function to read from 374 | * @reg: specific register to read from 375 | * @cc: completion code 376 | * @pci_config: config data to be read 377 | * @domain_id: domain ID of the client 378 | * 379 | * The RdPCIConfig() command provides sideband read access to the PCI 380 | * configuration space maintained in downstream devices external to the 381 | * processor. 382 | */ 383 | struct peci_rd_pci_cfg_msg { 384 | #define PECI_RDPCICFG_WRITE_LEN 6 385 | #define PECI_RDPCICFG_READ_LEN 5 386 | #define PECI_RDPCICFG_READ_LEN_MAX 24 387 | #define PECI_RDPCICFG_CMD 0x61 388 | 389 | __u8 addr; 390 | __u8 bus; 391 | #define PECI_PCI_BUS0_CPU0 0x00 392 | #define PECI_PCI_BUS0_CPU1 0x80 393 | #define PECI_PCI_CPUBUSNO_BUS 0x00 394 | #define PECI_PCI_CPUBUSNO_DEV 0x08 395 | #define PECI_PCI_CPUBUSNO_FUNC 0x02 396 | #define PECI_PCI_CPUBUSNO 0xcc 397 | #define PECI_PCI_CPUBUSNO_1 0xd0 398 | #define PECI_PCI_CPUBUSNO_VALID 0xd4 399 | 400 | __u8 device; 401 | __u8 function; 402 | __u16 reg; 403 | __u8 cc; 404 | __u8 padding[1]; 405 | __u8 pci_config[4]; 406 | __u8 domain_id; 407 | __u8 padding1[3]; 408 | } __attribute__((__packed__)); 409 | 410 | /** 411 | * struct peci_wr_pci_cfg_msg - WrPCIConfig command 412 | * @addr: address of the client 413 | * @bus: PCI bus number 414 | * @device: PCI device number 415 | * @function: specific function to write to 416 | * @reg: specific register to write to 417 | * @tx_len: number of data to be written in bytes 418 | * @cc: completion code 419 | * @pci_config: config data to be written 420 | * @domain_id: domain ID of the client 421 | * 422 | * The RdPCIConfig() command provides sideband write access to the PCI 423 | * configuration space maintained in downstream devices external to the 424 | * processor. 425 | */ 426 | struct peci_wr_pci_cfg_msg { 427 | #define PECI_WRPCICFG_CMD 0x65 428 | 429 | __u8 addr; 430 | __u8 bus; 431 | __u8 device; 432 | __u8 function; 433 | __u16 reg; 434 | __u8 tx_len; 435 | __u8 cc; 436 | __u8 pci_config[4]; 437 | __u8 domain_id; 438 | __u8 padding[3]; 439 | } __attribute__((__packed__)); 440 | 441 | /** 442 | * struct peci_rd_pci_cfg_local_msg - RdPCIConfigLocal command 443 | * @addr: address of the client 444 | * @bus: PCI bus number 445 | * @device: PCI device number 446 | * @function: specific function to read from 447 | * @reg: specific register to read from 448 | * @rx_len: number of data to be read in bytes 449 | * @cc: completion code 450 | * @pci_config: config data to be read 451 | * @domain_id: domain ID of the client 452 | * 453 | * The RdPCIConfigLocal() command provides sideband read access to the PCI 454 | * configuration space that resides within the processor. This includes all 455 | * processor IIO and uncore registers within the PCI configuration space. 456 | */ 457 | struct peci_rd_pci_cfg_local_msg { 458 | #define PECI_RDPCICFGLOCAL_WRITE_LEN 5 459 | #define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1 460 | #define PECI_RDPCICFGLOCAL_CMD 0xe1 461 | 462 | __u8 addr; 463 | __u8 bus; 464 | __u8 device; 465 | __u8 function; 466 | __u16 reg; 467 | __u8 rx_len; 468 | __u8 cc; 469 | __u8 pci_config[4]; 470 | __u8 domain_id; 471 | __u8 padding[3]; 472 | } __attribute__((__packed__)); 473 | 474 | /** 475 | * struct peci_wr_pci_cfg_local_msg - WrPCIConfigLocal command 476 | * @addr: address of the client 477 | * @bus: PCI bus number 478 | * @device: PCI device number 479 | * @function: specific function to read from 480 | * @reg: specific register to read from 481 | * @tx_len: number of data to be written in bytes 482 | * @cc: completion code 483 | * @value: config data to be written 484 | * @domain_id: domain ID of the client 485 | * 486 | * The WrPCIConfigLocal() command provides sideband write access to the PCI 487 | * configuration space that resides within the processor. PECI originators can 488 | * access this space even before BIOS enumeration of the system buses. 489 | */ 490 | struct peci_wr_pci_cfg_local_msg { 491 | #define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6 492 | #define PECI_WRPCICFGLOCAL_READ_LEN 1 493 | #define PECI_WRPCICFGLOCAL_CMD 0xe5 494 | 495 | __u8 addr; 496 | __u8 bus; 497 | __u8 device; 498 | __u8 function; 499 | __u16 reg; 500 | __u8 tx_len; 501 | __u8 cc; 502 | __u32 value; 503 | __u8 domain_id; 504 | __u8 padding[3]; 505 | } __attribute__((__packed__)); 506 | 507 | struct peci_rd_end_pt_cfg_msg { 508 | #define PECI_RDENDPTCFG_PCI_WRITE_LEN 12 509 | #define PECI_RDENDPTCFG_MMIO_D_WRITE_LEN 14 510 | #define PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN 18 511 | #define PECI_RDENDPTCFG_READ_LEN_BASE 1 512 | #define PECI_RDENDPTCFG_CMD 0xc1 513 | 514 | __u8 addr; 515 | __u8 msg_type; 516 | #define PECI_ENDPTCFG_TYPE_LOCAL_PCI 0x03 517 | #define PECI_ENDPTCFG_TYPE_PCI 0x04 518 | #define PECI_ENDPTCFG_TYPE_MMIO 0x05 519 | 520 | union { 521 | struct { 522 | __u8 seg; 523 | __u8 bus; 524 | __u8 device; 525 | __u8 function; 526 | __u16 reg; 527 | } pci_cfg; 528 | struct { 529 | __u8 seg; 530 | __u8 bus; 531 | __u8 device; 532 | __u8 function; 533 | __u8 bar; 534 | __u8 addr_type; 535 | #define PECI_ENDPTCFG_ADDR_TYPE_PCI 0x04 536 | #define PECI_ENDPTCFG_ADDR_TYPE_MMIO_D 0x05 537 | #define PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q 0x06 538 | 539 | __u64 offset; 540 | } mmio; 541 | } params; 542 | __u8 rx_len; 543 | __u8 cc; 544 | __u8 padding[2]; 545 | __u8 data[8]; 546 | __u8 domain_id; 547 | __u8 padding1[3]; 548 | } __attribute__((__packed__)); 549 | 550 | struct peci_wr_end_pt_cfg_msg { 551 | #define PECI_WRENDPTCFG_PCI_WRITE_LEN_BASE 13 552 | #define PECI_WRENDPTCFG_MMIO_D_WRITE_LEN_BASE 15 553 | #define PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE 19 554 | #define PECI_WRENDPTCFG_READ_LEN 1 555 | #define PECI_WRENDPTCFG_CMD 0xc5 556 | 557 | __u8 addr; 558 | __u8 msg_type; 559 | /* See msg_type in struct peci_rd_end_pt_cfg_msg */ 560 | 561 | union { 562 | struct { 563 | __u8 seg; 564 | __u8 bus; 565 | __u8 device; 566 | __u8 function; 567 | __u16 reg; 568 | } pci_cfg; 569 | struct { 570 | __u8 seg; 571 | __u8 bus; 572 | __u8 device; 573 | __u8 function; 574 | __u8 bar; 575 | __u8 addr_type; 576 | /* See addr_type in struct peci_rd_end_pt_cfg_msg */ 577 | 578 | __u64 offset; 579 | } mmio; 580 | } params; 581 | __u8 tx_len; 582 | __u8 cc; 583 | __u8 padding[2]; 584 | __u64 value; 585 | __u8 domain_id; 586 | __u8 padding1[3]; 587 | } __attribute__((__packed__)); 588 | 589 | /* Crashdump Agent */ 590 | #define PECI_CRASHDUMP_CORE 0x00 591 | #define PECI_CRASHDUMP_TOR 0x01 592 | 593 | /* Crashdump Agent Param */ 594 | #define PECI_CRASHDUMP_PAYLOAD_SIZE 0x00 595 | 596 | /* Crashdump Agent Data Param */ 597 | #define PECI_CRASHDUMP_AGENT_ID 0x00 598 | #define PECI_CRASHDUMP_AGENT_PARAM 0x01 599 | 600 | struct peci_crashdump_disc_msg { 601 | __u8 addr; 602 | __u8 subopcode; 603 | #define PECI_CRASHDUMP_ENABLED 0x00 604 | #define PECI_CRASHDUMP_NUM_AGENTS 0x01 605 | #define PECI_CRASHDUMP_AGENT_DATA 0x02 606 | 607 | __u8 cc; 608 | __u8 param0; 609 | __u16 param1; 610 | __u8 param2; 611 | __u8 rx_len; 612 | __u8 data[8]; 613 | __u8 domain_id; 614 | __u8 padding[3]; 615 | } __attribute__((__packed__)); 616 | 617 | struct peci_crashdump_get_frame_msg { 618 | #define PECI_CRASHDUMP_DISC_WRITE_LEN 9 619 | #define PECI_CRASHDUMP_DISC_READ_LEN_BASE 1 620 | #define PECI_CRASHDUMP_DISC_VERSION 0 621 | #define PECI_CRASHDUMP_DISC_OPCODE 1 622 | #define PECI_CRASHDUMP_GET_FRAME_WRITE_LEN 10 623 | #define PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE 1 624 | #define PECI_CRASHDUMP_GET_FRAME_VERSION 0 625 | #define PECI_CRASHDUMP_GET_FRAME_OPCODE 3 626 | #define PECI_CRASHDUMP_CMD 0x71 627 | 628 | __u8 addr; 629 | __u8 padding0; 630 | __u16 param0; 631 | __u16 param1; 632 | __u16 param2; 633 | __u8 rx_len; 634 | __u8 cc; 635 | __u8 padding1[2]; 636 | __u8 data[16]; 637 | __u8 domain_id; 638 | __u8 padding2[3]; 639 | } __attribute__((__packed__)); 640 | 641 | #define PECI_IOC_BASE 0xb8 642 | 643 | #define PECI_IOC_XFER \ 644 | _IOWR(PECI_IOC_BASE, PECI_CMD_XFER, struct peci_xfer_msg) 645 | 646 | #define PECI_IOC_PING \ 647 | _IOWR(PECI_IOC_BASE, PECI_CMD_PING, struct peci_ping_msg) 648 | 649 | #define PECI_IOC_GET_DIB \ 650 | _IOWR(PECI_IOC_BASE, PECI_CMD_GET_DIB, struct peci_get_dib_msg) 651 | 652 | #define PECI_IOC_GET_TEMP \ 653 | _IOWR(PECI_IOC_BASE, PECI_CMD_GET_TEMP, struct peci_get_temp_msg) 654 | 655 | #define PECI_IOC_RD_PKG_CFG \ 656 | _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PKG_CFG, struct peci_rd_pkg_cfg_msg) 657 | 658 | #define PECI_IOC_WR_PKG_CFG \ 659 | _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PKG_CFG, struct peci_wr_pkg_cfg_msg) 660 | 661 | #define PECI_IOC_RD_IA_MSR \ 662 | _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg) 663 | 664 | #define PECI_IOC_WR_IA_MSR \ 665 | _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg) 666 | 667 | #define PECI_IOC_RD_IA_MSREX \ 668 | _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSREX, struct peci_rd_ia_msrex_msg) 669 | 670 | #define PECI_IOC_RD_PCI_CFG \ 671 | _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg) 672 | 673 | #define PECI_IOC_WR_PCI_CFG \ 674 | _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg) 675 | 676 | #define PECI_IOC_RD_PCI_CFG_LOCAL \ 677 | _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \ 678 | struct peci_rd_pci_cfg_local_msg) 679 | 680 | #define PECI_IOC_WR_PCI_CFG_LOCAL \ 681 | _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG_LOCAL, \ 682 | struct peci_wr_pci_cfg_local_msg) 683 | 684 | #define PECI_IOC_RD_END_PT_CFG \ 685 | _IOWR(PECI_IOC_BASE, PECI_CMD_RD_END_PT_CFG, \ 686 | struct peci_rd_end_pt_cfg_msg) 687 | 688 | #define PECI_IOC_WR_END_PT_CFG \ 689 | _IOWR(PECI_IOC_BASE, PECI_CMD_WR_END_PT_CFG, \ 690 | struct peci_wr_end_pt_cfg_msg) 691 | 692 | #define PECI_IOC_CRASHDUMP_DISC \ 693 | _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_DISC, \ 694 | struct peci_crashdump_disc_msg) 695 | 696 | #define PECI_IOC_CRASHDUMP_GET_FRAME \ 697 | _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_GET_FRAME, \ 698 | struct peci_crashdump_get_frame_msg) 699 | 700 | #endif /* __PECI_IOCTL_H */ 701 | -------------------------------------------------------------------------------- /peci_cmds.c: -------------------------------------------------------------------------------- 1 | /* 2 | // Copyright (c) 2019 Intel Corporation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #ifndef ABS 27 | #define ABS(_v_) (((_v_) > 0) ? (_v_) : -(_v_)) 28 | #endif 29 | 30 | #define CC_COUNT 256 // CC is a byte so only has 256 possible values 31 | 32 | extern EPECIStatus peci_GetDIB(uint8_t target, uint64_t* dib); 33 | 34 | double getTimeDifference(const struct timespec begin) 35 | { 36 | double timeDiff = 0.0; 37 | struct timespec end; 38 | time_t seconds = 0; 39 | time_t nanoseconds = 0; 40 | 41 | clock_gettime(CLOCK_REALTIME, &end); 42 | seconds = end.tv_sec - begin.tv_sec; 43 | nanoseconds = end.tv_nsec - begin.tv_nsec; 44 | timeDiff = (double)seconds + (double)nanoseconds * 1e-9; 45 | 46 | return timeDiff; 47 | } 48 | 49 | void Usage(char* progname) 50 | { 51 | printf("Usage:\n"); 52 | printf("%s [-h] [-v] [-t] [-a ] [-i ] [-s ] [-l " 53 | "] " 54 | " [parameters]\n", 55 | progname); 56 | printf("Options:\n"); 57 | printf("\t%-12s%s\n", "-h", "Display this help information"); 58 | printf("\t%-12s%s\n", "-v", 59 | "Display additional information about the command"); 60 | printf("\t%-12s%s\n", "-t", "Measure request-to-response time"); 61 | printf("\t%-12s%s %lu\n", "-l ", 62 | "Loop the command the given number of times. is in the " 63 | "range 1 to", 64 | ULONG_MAX); 65 | printf("\t%-12s%s\n", "-a ", 66 | "Address of the target. Accepted values are 48-55 (0x30-0x37). " 67 | "Default is 48 (0x30)"); 68 | printf("\t%-12s%s\n", "-i ", 69 | "Domain ID of the target. Accepted values are 0-127. Default is 0"); 70 | printf("\t%-12s%s\n", "-s ", 71 | "Size of data to read or write in bytes. Accepted values are 1, 2, " 72 | "4, 8, and 16. Default is 4"); 73 | printf("\t%-12s%s\n", "-d", 74 | "Set PECI device name, for example \"-d /dev/peci-0\""); 75 | printf("Commands:\n"); 76 | printf("\t%-28s%s\n", "Ping", "Ping the target"); 77 | printf("\t%-28s%s\n", "GetTemp", "Get the temperature"); 78 | printf("\t%-28s%s\n", "GetDIB", "Get the DIB"); 79 | printf("\t%-28s%s\n", "RdPkgConfig", 80 | "Read Package Config "); 81 | printf("\t%-28s%s\n", "WrPkgConfig", 82 | "Write Package Config "); 83 | printf("\t%-28s%s\n", "RdIAMSR", "MSR Read "); 84 | printf("\t%-28s%s\n", "RdPCIConfig", "PCI Read "); 85 | printf("\t%-28s%s\n", "RdPCIConfigLocal", 86 | "Local PCI Read "); 87 | printf("\t%-28s%s\n", "WrPCIConfigLocal", 88 | "Local PCI Write "); 89 | printf("\t%-28s%s\n", "RdEndpointConfigPCILocal", 90 | "Endpoint Local PCI Config Read "); 91 | printf("\t%-28s%s\n", "WrEndpointConfigPCILocal", 92 | "Endpoint Local PCI Config Write "); 93 | printf("\t%-28s%s\n", "RdEndpointConfigPCI", 94 | "Endpoint PCI Config Read "); 95 | printf("\t%-28s%s\n", "WrEndpointConfigPCI", 96 | "Endpoint PCI Config Write "); 97 | printf("\t%-28s%s\n", "RdEndpointConfigMMIO", 98 | "Endpoint MMIO Read "); 99 | printf("\t%-28s%s\n", "WrEndpointConfigMMIO", 100 | "Endpoint MMIO Write "); 101 | printf("\t%-28s%s\n", "raw", "Raw PECI command in bytes"); 102 | printf("\n"); 103 | } 104 | 105 | static void printLoopSummary(uint32_t* ccCounts) 106 | { 107 | printf("Completion code counts:\n"); 108 | for (uint32_t i = 0; i < CC_COUNT; i++) 109 | { 110 | if (ccCounts[i]) 111 | { 112 | printf(" 0x%02x: %d\n", i, ccCounts[i]); 113 | } 114 | } 115 | } 116 | 117 | int main(int argc, char* argv[]) 118 | { 119 | int c; 120 | int i = 0; 121 | char* cmd = NULL; 122 | EPECIStatus ret = PECI_CC_SUCCESS; 123 | uint8_t address = 0x30; // use default address of 48d 124 | uint8_t domainId = 0; // use default domain ID of 0 125 | uint8_t u8Size = 4; // default to a DWORD 126 | uint32_t u32PciReadVal = 0; 127 | uint64_t u64MmioReadVal = 0; 128 | uint8_t u8Seg = 0; 129 | uint8_t u8Bar = 0; 130 | uint8_t u8AddrType = 0; 131 | uint8_t u8PciBus = 0; 132 | uint8_t u8PciDev = 0; 133 | uint8_t u8PciFunc = 0; 134 | uint16_t u16PciReg = 0; 135 | uint64_t u64Offset = 0; 136 | uint32_t u32PciWriteVal = 0; 137 | uint64_t u64MmioWriteVal = 0; 138 | uint8_t u8PkgIndex = 0; 139 | uint16_t u16PkgParam = 0; 140 | uint32_t u32PkgValue = 0; 141 | uint8_t u8MsrThread = 0; 142 | uint16_t u16MsrAddr = 0; 143 | uint64_t u64MsrVal = 0; 144 | short temperature; 145 | uint64_t dib; 146 | int index = 0; 147 | uint8_t cc = 0; 148 | bool measureTime = false; 149 | bool verbose = false; 150 | bool looped = false; 151 | uint32_t loops = 1; 152 | uint32_t loopCount = 1; 153 | uint32_t ccCounts[CC_COUNT] = {0}; 154 | struct timespec begin; 155 | double timeSpent = 0.0; 156 | double totalTimeSpent = 0.0; 157 | 158 | // 159 | // Parse arguments. 160 | // 161 | while (-1 != (c = getopt(argc, argv, "hvtl:a:i:s:d:"))) 162 | { 163 | switch (c) 164 | { 165 | case 'h': 166 | Usage(argv[0]); 167 | return 0; 168 | break; 169 | 170 | case 'v': 171 | verbose = true; 172 | break; 173 | 174 | case 't': 175 | measureTime = true; 176 | break; 177 | 178 | case 'l': 179 | looped = true; 180 | errno = 0; 181 | if (optarg != NULL) 182 | loops = (uint32_t)strtoul(optarg, NULL, 0); 183 | if (!loops || errno) 184 | { 185 | printf("ERROR: Invalid loop count\n"); 186 | if (errno) 187 | perror(""); 188 | goto ErrorExit; 189 | } 190 | loopCount = 191 | loops; // Preserve a copy for average time measurement 192 | break; 193 | 194 | case 'a': 195 | if (optarg != NULL) 196 | address = (uint8_t)strtoul(optarg, NULL, 0); 197 | if (address < MIN_CLIENT_ADDR || address > MAX_CLIENT_ADDR) 198 | { 199 | printf("ERROR: Invalid address \"0x%x\"\n", address); 200 | goto ErrorExit; 201 | } 202 | 203 | break; 204 | 205 | case 'i': 206 | if (optarg != NULL) 207 | domainId = (uint8_t)strtoul(optarg, NULL, 0); 208 | if (domainId >= 128) // Domain ID is only 7 bits 209 | { 210 | printf("ERROR: Invalid domain ID \"%d\"\n", domainId); 211 | goto ErrorExit; 212 | } 213 | break; 214 | 215 | case 's': 216 | if (optarg != NULL) 217 | u8Size = (uint8_t)strtoul(optarg, NULL, 0); 218 | if (u8Size != 1 && u8Size != 2 && u8Size != 4 && u8Size != 8 && 219 | u8Size != 16) 220 | { 221 | printf("ERROR: Invalid size \"%d\"\n", u8Size); 222 | goto ErrorExit; 223 | } 224 | break; 225 | 226 | case 'd': 227 | peci_SetDevName(optarg); 228 | break; 229 | 230 | default: 231 | printf("ERROR: Unrecognized option \"-%c\"\n", optopt); 232 | goto ErrorExit; 233 | break; 234 | } 235 | } 236 | 237 | // Get the command from the first parameter 238 | cmd = argv[optind++]; 239 | if (cmd == NULL) 240 | { 241 | Usage(argv[0]); 242 | return 0; 243 | } 244 | 245 | // Allow any case 246 | while (cmd[i]) 247 | { 248 | cmd[i] = (char)tolower((int)cmd[i]); 249 | i++; 250 | } 251 | 252 | // 253 | // Execute the command 254 | // 255 | if (verbose) 256 | { 257 | printf("PECI target[0x%x]: ", address); 258 | } 259 | 260 | if (measureTime) 261 | { 262 | if (verbose && (loopCount > 1)) 263 | { 264 | printf("Warning: Request-response time measurement with verbose " 265 | "mode can affect the time between consecutive commands in " 266 | "looped mode!\n"); 267 | } 268 | } 269 | 270 | if (strcmp(cmd, "ping") == 0) 271 | { 272 | if (verbose) 273 | { 274 | printf("Pinging ... "); 275 | } 276 | while (loops--) 277 | { 278 | clock_gettime(CLOCK_REALTIME, &begin); 279 | ret = peci_Ping(address); 280 | timeSpent = getTimeDifference(begin); 281 | if (verbose && measureTime) 282 | { 283 | printf("\nTime taken in iteration %d = %lf s\n", 284 | (loopCount - loops), timeSpent); 285 | } 286 | totalTimeSpent += timeSpent; 287 | 288 | if (verbose || loops == 0) 289 | { 290 | if (0 != ret) 291 | { 292 | printf("Failed\n"); 293 | } 294 | else 295 | { 296 | printf("Succeeded\n"); 297 | } 298 | } 299 | } 300 | } 301 | else if (strcmp(cmd, "getdib") == 0) 302 | { 303 | if (verbose) 304 | { 305 | printf("GetDIB\n"); 306 | } 307 | while (loops--) 308 | { 309 | clock_gettime(CLOCK_REALTIME, &begin); 310 | ret = peci_GetDIB(address, &dib); 311 | timeSpent = getTimeDifference(begin); 312 | if (verbose && measureTime) 313 | { 314 | printf("\nTime taken in iteration %d = %lf s\n", 315 | (loopCount - loops), timeSpent); 316 | } 317 | totalTimeSpent += timeSpent; 318 | 319 | if (verbose || loops == 0) 320 | { 321 | if (0 != ret) 322 | { 323 | printf("ERROR %d: Retrieving DIB failed\n", ret); 324 | } 325 | else 326 | { 327 | printf(" 0x%" PRIx64 "\n", dib); 328 | } 329 | } 330 | } 331 | } 332 | 333 | else if (strcmp(cmd, "gettemp") == 0) 334 | { 335 | if (verbose) 336 | { 337 | printf("GetTemp\n"); 338 | } 339 | while (loops--) 340 | { 341 | clock_gettime(CLOCK_REALTIME, &begin); 342 | ret = peci_GetTemp(address, &temperature); 343 | timeSpent = getTimeDifference(begin); 344 | if (verbose && measureTime) 345 | { 346 | printf("\nTime taken in iteration %d = %lf s\n", 347 | (loopCount - loops), timeSpent); 348 | } 349 | totalTimeSpent += timeSpent; 350 | 351 | if (verbose || loops == 0) 352 | { 353 | if (0 != ret) 354 | { 355 | printf("ERROR %d: Retrieving temperature failed\n", ret); 356 | } 357 | else 358 | { 359 | printf(" %04xh (%c%d.%02dC)\n", 360 | (int)(unsigned int)(unsigned short)temperature, 361 | (0 > temperature) ? '-' : '+', 362 | (int)((unsigned int)ABS(temperature) / 64), 363 | (int)(((unsigned int)ABS(temperature) % 64) * 100) / 364 | 64); 365 | } 366 | } 367 | } 368 | } 369 | 370 | else if (strcmp(cmd, "rdpkgconfig") == 0) 371 | { 372 | index = argc; 373 | switch (argc - optind) 374 | { 375 | case 2: 376 | u16PkgParam = (uint16_t)strtoul(argv[--index], NULL, 0); 377 | u8PkgIndex = (uint8_t)strtoul(argv[--index], NULL, 0); 378 | break; 379 | default: 380 | printf("ERROR: Unsupported arguments for Pkg Read\n"); 381 | goto ErrorExit; 382 | break; 383 | } 384 | if (verbose) 385 | { 386 | printf("Pkg Read of Index %02x Param %04x\n", u8PkgIndex, 387 | u16PkgParam); 388 | } 389 | while (loops--) 390 | { 391 | cc = 0; // reset the cc for each loop 392 | clock_gettime(CLOCK_REALTIME, &begin); 393 | ret = 394 | peci_RdPkgConfig_dom(address, domainId, u8PkgIndex, u16PkgParam, 395 | u8Size, (uint8_t*)&u32PkgValue, &cc); 396 | timeSpent = getTimeDifference(begin); 397 | if (verbose && measureTime) 398 | { 399 | printf("\nTime taken in iteration %d = %lf s\n", 400 | (loopCount - loops), timeSpent); 401 | } 402 | totalTimeSpent += timeSpent; 403 | 404 | ccCounts[cc]++; 405 | 406 | if (verbose || loops == 0) 407 | { 408 | if (0 != ret) 409 | { 410 | printf("ERROR %d: command failed\n", ret); 411 | printf(" cc:0x%02x\n", cc); 412 | } 413 | else 414 | { 415 | printf(" cc:0x%02x 0x%0*x\n", cc, u8Size * 2, 416 | u32PkgValue); 417 | } 418 | } 419 | } 420 | if (looped) 421 | { 422 | printLoopSummary(ccCounts); 423 | } 424 | } 425 | else if (strcmp(cmd, "wrpkgconfig") == 0) 426 | { 427 | index = argc; 428 | switch (argc - optind) 429 | { 430 | case 3: 431 | u32PkgValue = (uint32_t)strtoul(argv[--index], NULL, 0); 432 | u16PkgParam = (uint16_t)strtoul(argv[--index], NULL, 0); 433 | u8PkgIndex = (uint8_t)strtoul(argv[--index], NULL, 0); 434 | break; 435 | default: 436 | printf("ERROR: Unsupported arguments for Pkg Write\n"); 437 | goto ErrorExit; 438 | break; 439 | } 440 | if (verbose) 441 | { 442 | printf("Pkg Write of Index %02x Param %04x: 0x%0*x\n", u8PkgIndex, 443 | u16PkgParam, u8Size * 2, u32PkgValue); 444 | } 445 | while (loops--) 446 | { 447 | cc = 0; // reset the cc for each loop 448 | clock_gettime(CLOCK_REALTIME, &begin); 449 | ret = peci_WrPkgConfig_dom(address, domainId, u8PkgIndex, 450 | u16PkgParam, u32PkgValue, u8Size, &cc); 451 | timeSpent = getTimeDifference(begin); 452 | if (verbose && measureTime) 453 | { 454 | printf("\nTime taken in iteration %d = %lf s\n", 455 | (loopCount - loops), timeSpent); 456 | } 457 | totalTimeSpent += timeSpent; 458 | 459 | ccCounts[cc]++; 460 | 461 | if (verbose || loops == 0) 462 | { 463 | if (0 != ret) 464 | { 465 | printf("ERROR %d: command failed\n", ret); 466 | } 467 | printf(" cc:0x%02x\n", cc); 468 | } 469 | } 470 | if (looped) 471 | { 472 | printLoopSummary(ccCounts); 473 | } 474 | } 475 | else if (strcmp(cmd, "rdiamsr") == 0) 476 | { 477 | index = argc; 478 | switch (argc - optind) 479 | { 480 | case 2: 481 | u16MsrAddr = (uint16_t)strtoul(argv[--index], NULL, 0); 482 | u8MsrThread = (uint8_t)strtoul(argv[--index], NULL, 0); 483 | break; 484 | default: 485 | printf("ERROR: Unsupported arguments for MSR Read\n"); 486 | goto ErrorExit; 487 | break; 488 | } 489 | if (verbose) 490 | { 491 | printf("MSR Read of Thread %02x MSR %04x\n", u8MsrThread, 492 | u16MsrAddr); 493 | } 494 | while (loops--) 495 | { 496 | cc = 0; // reset the cc for each loop 497 | clock_gettime(CLOCK_REALTIME, &begin); 498 | ret = peci_RdIAMSR_dom(address, domainId, u8MsrThread, u16MsrAddr, 499 | &u64MsrVal, &cc); 500 | timeSpent = getTimeDifference(begin); 501 | if (verbose && measureTime) 502 | { 503 | printf("\nTime taken in iteration %d = %lf s\n", 504 | (loopCount - loops), timeSpent); 505 | } 506 | totalTimeSpent += timeSpent; 507 | 508 | ccCounts[cc]++; 509 | 510 | if (verbose || loops == 0) 511 | { 512 | if (0 != ret) 513 | { 514 | printf("ERROR %d: command failed\n", ret); 515 | printf(" cc:0x%02x\n", cc); 516 | } 517 | else 518 | { 519 | printf(" cc:0x%02x 0x%0*llx\n", cc, u8Size * 2, 520 | (unsigned long long)u64MsrVal); 521 | } 522 | } 523 | } 524 | if (looped) 525 | { 526 | printLoopSummary(ccCounts); 527 | } 528 | } 529 | else if (strcmp(cmd, "rdpciconfig") == 0) 530 | { 531 | index = argc; 532 | switch (argc - optind) 533 | { 534 | case 4: 535 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 536 | /* FALLTHROUGH */ 537 | case 3: 538 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 539 | /* FALLTHROUGH */ 540 | case 2: 541 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 542 | /* FALLTHROUGH */ 543 | case 1: 544 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 545 | break; 546 | default: 547 | printf("ERROR: Unsupported arguments for PCI Read\n"); 548 | goto ErrorExit; 549 | break; 550 | } 551 | if (verbose) 552 | { 553 | printf("PCI Read of %02x:%02x:%02x Reg %02x\n", u8PciBus, u8PciDev, 554 | u8PciFunc, u16PciReg); 555 | } 556 | while (loops--) 557 | { 558 | cc = 0; // reset the cc for each loop 559 | clock_gettime(CLOCK_REALTIME, &begin); 560 | ret = peci_RdPCIConfig_dom(address, domainId, u8PciBus, u8PciDev, 561 | u8PciFunc, u16PciReg, 562 | (uint8_t*)&u32PciReadVal, &cc); 563 | timeSpent = getTimeDifference(begin); 564 | if (verbose && measureTime) 565 | { 566 | printf("\nTime taken in iteration %d = %lf s\n", 567 | (loopCount - loops), timeSpent); 568 | } 569 | totalTimeSpent += timeSpent; 570 | 571 | ccCounts[cc]++; 572 | 573 | if (verbose || loops == 0) 574 | { 575 | if (0 != ret) 576 | { 577 | printf("ERROR %d: command failed\n", ret); 578 | printf(" cc:0x%02x\n", cc); 579 | } 580 | else 581 | { 582 | printf(" cc:0x%02x 0x%0*x\n", cc, u8Size * 2, 583 | u32PciReadVal); 584 | } 585 | } 586 | } 587 | if (looped) 588 | { 589 | printLoopSummary(ccCounts); 590 | } 591 | } 592 | else if (strcmp(cmd, "rdpciconfiglocal") == 0) 593 | { 594 | index = argc; 595 | switch (argc - optind) 596 | { 597 | case 4: 598 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 599 | /* FALLTHROUGH */ 600 | case 3: 601 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 602 | /* FALLTHROUGH */ 603 | case 2: 604 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 605 | /* FALLTHROUGH */ 606 | case 1: 607 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 608 | break; 609 | default: 610 | printf("ERROR: Unsupported arguments for Local PCI Read\n"); 611 | goto ErrorExit; 612 | break; 613 | } 614 | if (verbose) 615 | { 616 | printf("Local PCI Read of %02x:%02x:%02x Reg %02x\n", u8PciBus, 617 | u8PciDev, u8PciFunc, u16PciReg); 618 | } 619 | while (loops--) 620 | { 621 | cc = 0; // reset the cc for each loop 622 | clock_gettime(CLOCK_REALTIME, &begin); 623 | ret = peci_RdPCIConfigLocal_dom( 624 | address, domainId, u8PciBus, u8PciDev, u8PciFunc, u16PciReg, 625 | u8Size, (uint8_t*)&u32PciReadVal, &cc); 626 | ccCounts[cc]++; 627 | timeSpent = getTimeDifference(begin); 628 | if (verbose && measureTime) 629 | { 630 | printf("\nTime taken in iteration %d = %lf s\n", 631 | (loopCount - loops), timeSpent); 632 | } 633 | totalTimeSpent += timeSpent; 634 | 635 | if (verbose || loops == 0) 636 | { 637 | if (0 != ret) 638 | { 639 | printf("ERROR %d: command failed\n", ret); 640 | printf(" cc:0x%02x\n", cc); 641 | } 642 | else 643 | { 644 | printf(" cc:0x%02x 0x%0*x\n", cc, u8Size * 2, 645 | u32PciReadVal); 646 | } 647 | } 648 | } 649 | if (looped) 650 | { 651 | printLoopSummary(ccCounts); 652 | } 653 | } 654 | else if (strcmp(cmd, "wrpciconfiglocal") == 0) 655 | { 656 | index = argc; 657 | u32PciWriteVal = (uint32_t)strtoul(argv[--index], NULL, 0); 658 | switch (argc - optind) 659 | { 660 | case 5: 661 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 662 | /* FALLTHROUGH */ 663 | case 4: 664 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 665 | /* FALLTHROUGH */ 666 | case 3: 667 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 668 | /* FALLTHROUGH */ 669 | case 2: 670 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 671 | break; 672 | default: 673 | printf("ERROR: Unsupported arguments for Local PCI Write\n"); 674 | goto ErrorExit; 675 | break; 676 | } 677 | if (verbose) 678 | { 679 | printf("Local PCI Write of %02x:%02x:%02x Reg %02x: 0x%0*x\n", 680 | u8PciBus, u8PciDev, u8PciFunc, u16PciReg, u8Size * 2, 681 | u32PciWriteVal); 682 | } 683 | while (loops--) 684 | { 685 | cc = 0; // reset the cc for each loop 686 | clock_gettime(CLOCK_REALTIME, &begin); 687 | ret = peci_WrPCIConfigLocal_dom(address, domainId, u8PciBus, 688 | u8PciDev, u8PciFunc, u16PciReg, 689 | u8Size, u32PciWriteVal, &cc); 690 | timeSpent = getTimeDifference(begin); 691 | if (verbose && measureTime) 692 | { 693 | printf("\nTime taken in iteration %d = %lf s\n", 694 | (loopCount - loops), timeSpent); 695 | } 696 | totalTimeSpent += timeSpent; 697 | 698 | ccCounts[cc]++; 699 | 700 | if (verbose || loops == 0) 701 | { 702 | if (0 != ret) 703 | { 704 | printf("ERROR %d: command failed\n", ret); 705 | } 706 | printf(" cc:0x%02x\n", cc); 707 | } 708 | } 709 | if (looped) 710 | { 711 | printLoopSummary(ccCounts); 712 | } 713 | } 714 | else if (strcmp(cmd, "rdendpointconfigpcilocal") == 0) 715 | { 716 | index = argc; 717 | switch (argc - optind) 718 | { 719 | case 5: 720 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 721 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 722 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 723 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 724 | u8Seg = (uint8_t)strtoul(argv[--index], NULL, 0); 725 | break; 726 | 727 | default: 728 | printf("ERROR: Unsupported arguments for Endpoint Local PCI " 729 | "Read\n"); 730 | goto ErrorExit; 731 | } 732 | if (verbose) 733 | { 734 | printf( 735 | "Endpoint Local PCI Read of Seg:%02x %02x:%02x:%02x Reg %02x\n", 736 | u8Seg, u8PciBus, u8PciDev, u8PciFunc, u16PciReg); 737 | } 738 | while (loops--) 739 | { 740 | cc = 0; // reset the cc for each loop 741 | clock_gettime(CLOCK_REALTIME, &begin); 742 | ret = peci_RdEndPointConfigPciLocal_dom( 743 | address, domainId, u8Seg, u8PciBus, u8PciDev, u8PciFunc, 744 | u16PciReg, u8Size, (uint8_t*)&u32PciReadVal, &cc); 745 | timeSpent = getTimeDifference(begin); 746 | if (verbose && measureTime) 747 | { 748 | printf("\nTime taken in iteration %d = %lf s\n", 749 | (loopCount - loops), timeSpent); 750 | } 751 | totalTimeSpent += timeSpent; 752 | 753 | ccCounts[cc]++; 754 | 755 | if (verbose || loops == 0) 756 | { 757 | if (0 != ret) 758 | { 759 | printf("ERROR %d: command failed\n", ret); 760 | printf(" cc:0x%02x\n", cc); 761 | } 762 | else 763 | { 764 | printf(" cc:0x%02x 0x%0*x\n", cc, u8Size * 2, 765 | u32PciReadVal); 766 | } 767 | } 768 | } 769 | if (looped) 770 | { 771 | printLoopSummary(ccCounts); 772 | } 773 | } 774 | else if (strcmp(cmd, "wrendpointconfigpcilocal") == 0) 775 | { 776 | index = argc; 777 | switch (argc - optind) 778 | { 779 | case 6: 780 | u32PciWriteVal = (uint32_t)strtoul(argv[--index], NULL, 0); 781 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 782 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 783 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 784 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 785 | u8Seg = (uint8_t)strtoul(argv[--index], NULL, 0); 786 | break; 787 | 788 | default: 789 | printf("ERROR: Unsupported arguments for Endpoint Local PCI " 790 | "Write\n"); 791 | goto ErrorExit; 792 | } 793 | if (verbose) 794 | { 795 | printf("Endpoint Local PCI Write of Seg:%02x %02x:%02x:%02x Reg " 796 | "%02x: 0x%0*x\n", 797 | u8Seg, u8PciBus, u8PciDev, u8PciFunc, u16PciReg, u8Size * 2, 798 | u32PciWriteVal); 799 | } 800 | while (loops--) 801 | { 802 | cc = 0; // reset the cc for each loop 803 | clock_gettime(CLOCK_REALTIME, &begin); 804 | ret = peci_WrEndPointPCIConfigLocal_dom( 805 | address, domainId, u8Seg, u8PciBus, u8PciDev, u8PciFunc, 806 | u16PciReg, u8Size, u32PciWriteVal, &cc); 807 | timeSpent = getTimeDifference(begin); 808 | if (verbose && measureTime) 809 | { 810 | printf("\nTime taken in iteration %d = %lf s\n", 811 | (loopCount - loops), timeSpent); 812 | } 813 | totalTimeSpent += timeSpent; 814 | 815 | ccCounts[cc]++; 816 | 817 | if (verbose || loops == 0) 818 | { 819 | if (0 != ret) 820 | { 821 | printf("ERROR %d: command failed\n", ret); 822 | } 823 | printf(" cc:0x%02x\n", cc); 824 | } 825 | } 826 | if (looped) 827 | { 828 | printLoopSummary(ccCounts); 829 | } 830 | } 831 | else if (strcmp(cmd, "rdendpointconfigpci") == 0) 832 | { 833 | index = argc; 834 | switch (argc - optind) 835 | { 836 | case 5: 837 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 838 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 839 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 840 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 841 | u8Seg = (uint8_t)strtoul(argv[--index], NULL, 0); 842 | break; 843 | 844 | default: 845 | printf("ERROR: Unsupported arguments for Endpoint PCI Read\n"); 846 | goto ErrorExit; 847 | } 848 | if (verbose) 849 | { 850 | printf("Endpoint PCI Read of Seg:%02x %02x:%02x:%02x Reg %02x\n", 851 | u8Seg, u8PciBus, u8PciDev, u8PciFunc, u16PciReg); 852 | } 853 | while (loops--) 854 | { 855 | cc = 0; // reset the cc for each loop 856 | clock_gettime(CLOCK_REALTIME, &begin); 857 | ret = peci_RdEndPointConfigPci_dom( 858 | address, domainId, u8Seg, u8PciBus, u8PciDev, u8PciFunc, 859 | u16PciReg, u8Size, (uint8_t*)&u32PciReadVal, &cc); 860 | timeSpent = getTimeDifference(begin); 861 | if (verbose && measureTime) 862 | { 863 | printf("\nTime taken in iteration %d = %lf s\n", 864 | (loopCount - loops), timeSpent); 865 | } 866 | totalTimeSpent += timeSpent; 867 | 868 | ccCounts[cc]++; 869 | 870 | if (verbose || loops == 0) 871 | { 872 | if (0 != ret) 873 | { 874 | printf("ERROR %d: command failed\n", ret); 875 | printf(" cc:0x%02x\n", cc); 876 | } 877 | else 878 | { 879 | printf(" cc:0x%02x 0x%0*x\n", cc, u8Size * 2, 880 | u32PciReadVal); 881 | } 882 | } 883 | } 884 | if (looped) 885 | { 886 | printLoopSummary(ccCounts); 887 | } 888 | } 889 | else if (strcmp(cmd, "wrendpointconfigpci") == 0) 890 | { 891 | index = argc; 892 | switch (argc - optind) 893 | { 894 | case 6: 895 | u32PciWriteVal = (uint32_t)strtoul(argv[--index], NULL, 0); 896 | u16PciReg = (uint16_t)strtoul(argv[--index], NULL, 0); 897 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 898 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 899 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 900 | u8Seg = (uint8_t)strtoul(argv[--index], NULL, 0); 901 | break; 902 | 903 | default: 904 | printf("ERROR: Unsupported arguments for Endpoint PCI Write\n"); 905 | goto ErrorExit; 906 | } 907 | if (verbose) 908 | { 909 | printf("Endpoint PCI Write of Seg:%02x %02x:%02x:%02x Reg %02x: " 910 | "0x%0*x\n", 911 | u8Seg, u8PciBus, u8PciDev, u8PciFunc, u16PciReg, u8Size * 2, 912 | u32PciWriteVal); 913 | } 914 | while (loops--) 915 | { 916 | cc = 0; // reset the cc for each loop 917 | clock_gettime(CLOCK_REALTIME, &begin); 918 | ret = peci_WrEndPointPCIConfig_dom( 919 | address, domainId, u8Seg, u8PciBus, u8PciDev, u8PciFunc, 920 | u16PciReg, u8Size, u32PciWriteVal, &cc); 921 | timeSpent = getTimeDifference(begin); 922 | if (verbose && measureTime) 923 | { 924 | printf("\nTime taken in iteration %d = %lf s\n", 925 | (loopCount - loops), timeSpent); 926 | } 927 | totalTimeSpent += timeSpent; 928 | 929 | ccCounts[cc]++; 930 | 931 | if (verbose || loops == 0) 932 | { 933 | if (0 != ret) 934 | { 935 | printf("ERROR %d: command failed\n", ret); 936 | } 937 | printf(" cc:0x%02x\n", cc); 938 | } 939 | } 940 | if (looped) 941 | { 942 | printLoopSummary(ccCounts); 943 | } 944 | } 945 | else if (strcmp(cmd, "rdendpointconfigmmio") == 0) 946 | { 947 | index = argc; 948 | switch (argc - optind) 949 | { 950 | case 7: 951 | u64Offset = (uint64_t)strtoull(argv[--index], NULL, 0); 952 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 953 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 954 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 955 | u8Seg = (uint8_t)strtoul(argv[--index], NULL, 0); 956 | u8Bar = (uint8_t)strtoul(argv[--index], NULL, 0); 957 | u8AddrType = (uint8_t)strtoul(argv[--index], NULL, 0); 958 | break; 959 | 960 | default: 961 | printf("ERROR: Unsupported arguments for Endpoint MMIO Read\n"); 962 | goto ErrorExit; 963 | } 964 | if (verbose) 965 | { 966 | printf("Endpoint MMIO Read of Seg:%02x %02x:%02x:%02x AType:%02x " 967 | "Bar:%02x Offset:0x%" PRIx64 "\n", 968 | u8Seg, u8PciBus, u8PciDev, u8PciFunc, u8AddrType, u8Bar, 969 | u64Offset); 970 | } 971 | while (loops--) 972 | { 973 | cc = 0; // reset the cc for each loop 974 | clock_gettime(CLOCK_REALTIME, &begin); 975 | ret = peci_RdEndPointConfigMmio_dom( 976 | address, domainId, u8Seg, u8PciBus, u8PciDev, u8PciFunc, u8Bar, 977 | u8AddrType, u64Offset, u8Size, (uint8_t*)&u64MmioReadVal, &cc); 978 | timeSpent = getTimeDifference(begin); 979 | if (verbose && measureTime) 980 | { 981 | printf("\nTime taken in iteration %d = %lf s\n", 982 | (loopCount - loops), timeSpent); 983 | } 984 | totalTimeSpent += timeSpent; 985 | 986 | ccCounts[cc]++; 987 | 988 | if (verbose || loops == 0) 989 | { 990 | if (0 != ret) 991 | { 992 | printf("ERROR %d: command failed\n", ret); 993 | printf(" cc:0x%02x\n", cc); 994 | } 995 | else 996 | { 997 | printf(" cc:0x%02x 0x%0*" PRIx64 "\n", cc, u8Size * 2, 998 | u64MmioReadVal); 999 | } 1000 | } 1001 | } 1002 | if (looped) 1003 | { 1004 | printLoopSummary(ccCounts); 1005 | } 1006 | } 1007 | else if (strcmp(cmd, "wrendpointconfigmmio") == 0) 1008 | { 1009 | index = argc; 1010 | switch (argc - optind) 1011 | { 1012 | case 8: 1013 | u64MmioWriteVal = (uint64_t)strtoull(argv[--index], NULL, 0); 1014 | u64Offset = (uint64_t)strtoull(argv[--index], NULL, 0); 1015 | u8PciFunc = (uint8_t)strtoul(argv[--index], NULL, 0); 1016 | u8PciDev = (uint8_t)strtoul(argv[--index], NULL, 0); 1017 | u8PciBus = (uint8_t)strtoul(argv[--index], NULL, 0); 1018 | u8Seg = (uint8_t)strtoul(argv[--index], NULL, 0); 1019 | u8Bar = (uint8_t)strtoul(argv[--index], NULL, 0); 1020 | u8AddrType = (uint8_t)strtoul(argv[--index], NULL, 0); 1021 | break; 1022 | 1023 | default: 1024 | printf( 1025 | "ERROR: Unsupported arguments for Endpoint MMIO Write\n"); 1026 | goto ErrorExit; 1027 | } 1028 | if (verbose) 1029 | { 1030 | printf("Endpoint MMIO Write of Seg:%02x %02x:%02x:%02x AType:%02x " 1031 | "Bar:%02x Offset:0x%" PRIx64 ": 0x%0*" PRIx64 "\n", 1032 | u8Seg, u8PciBus, u8PciDev, u8PciFunc, u8AddrType, u8Bar, 1033 | u64Offset, u8Size * 2, u64MmioWriteVal); 1034 | } 1035 | while (loops--) 1036 | { 1037 | cc = 0; // reset the cc for each loop 1038 | clock_gettime(CLOCK_REALTIME, &begin); 1039 | ret = peci_WrEndPointConfigMmio_dom( 1040 | address, domainId, u8Seg, u8PciBus, u8PciDev, u8PciFunc, u8Bar, 1041 | u8AddrType, u64Offset, u8Size, u64MmioWriteVal, &cc); 1042 | timeSpent = getTimeDifference(begin); 1043 | if (verbose && measureTime) 1044 | { 1045 | printf("\nTime taken in iteration %d = %lf s\n", 1046 | (loopCount - loops), timeSpent); 1047 | } 1048 | totalTimeSpent += timeSpent; 1049 | 1050 | ccCounts[cc]++; 1051 | 1052 | if (verbose || loops == 0) 1053 | { 1054 | if (0 != ret) 1055 | { 1056 | printf("ERROR %d: command failed\n", ret); 1057 | } 1058 | printf(" cc:0x%02x\n", cc); 1059 | } 1060 | } 1061 | if (looped) 1062 | { 1063 | printLoopSummary(ccCounts); 1064 | } 1065 | } 1066 | else if (strcmp(cmd, "raw") == 0) 1067 | { 1068 | if ((argc - optind) < 3) 1069 | { 1070 | printf("ERROR: Unsupported arguments for raw command\n"); 1071 | goto ErrorExit; 1072 | } 1073 | 1074 | // Address is provided in the first byte of the PECI command 1075 | uint8_t rawAddr = (uint8_t)strtoul(argv[optind++], NULL, 0); 1076 | // Write length is provided in the second byte of the PECI command 1077 | uint8_t writeLength = (uint8_t)strtoul(argv[optind++], NULL, 0); 1078 | // Read length is provided in the third byte of the PECI command 1079 | uint8_t readLength = (uint8_t)strtoul(argv[optind++], NULL, 0); 1080 | 1081 | // remaining parameters should fit within write length 1082 | if ((argc - optind) > writeLength) 1083 | { 1084 | printf("ERROR: Incorrect write length for raw command\n"); 1085 | goto ErrorExit; 1086 | } 1087 | uint8_t* rawCmd = (uint8_t*)calloc(writeLength, sizeof(uint8_t)); 1088 | if (rawCmd == NULL) 1089 | { 1090 | // calloc failed, abort the sequence 1091 | printf("Raw command memory allocation failed\n"); 1092 | return 1; 1093 | } 1094 | for (i = 0; i < (argc - optind); i++) 1095 | { 1096 | rawCmd[i] = (uint8_t)strtoul(argv[i + optind], NULL, 0); 1097 | } 1098 | if (verbose) 1099 | { 1100 | printf("Raw command: %02x %02x %02x ", rawAddr, writeLength, 1101 | readLength); 1102 | for (i = 0; i < writeLength; i++) 1103 | { 1104 | printf("0x%02x ", rawCmd[i]); 1105 | } 1106 | printf("\n"); 1107 | } 1108 | 1109 | uint8_t* rawResp = (uint8_t*)calloc(readLength, sizeof(uint8_t)); 1110 | if (rawResp == NULL) 1111 | { 1112 | // calloc failed, abort the sequence 1113 | printf("Raw command memory allocation failed\n"); 1114 | free(rawCmd); 1115 | return 1; 1116 | } 1117 | while (loops--) 1118 | { 1119 | clock_gettime(CLOCK_REALTIME, &begin); 1120 | ret = peci_raw(rawAddr, readLength, rawCmd, writeLength, rawResp, 1121 | readLength); 1122 | timeSpent = getTimeDifference(begin); 1123 | if (verbose && measureTime) 1124 | { 1125 | printf("\nTime taken in iteration %d = %lf s\n", 1126 | (loopCount - loops), timeSpent); 1127 | } 1128 | totalTimeSpent += timeSpent; 1129 | 1130 | if (verbose) 1131 | { 1132 | printf(" "); 1133 | for (i = 0; i < readLength; i++) 1134 | { 1135 | printf("0x%02x ", rawResp[i]); 1136 | } 1137 | printf("\n"); 1138 | } 1139 | ccCounts[rawResp[0]]++; 1140 | } 1141 | if (!verbose) 1142 | { 1143 | if (PECI_CC_SUCCESS != ret) 1144 | { 1145 | printf("ERROR %d: command failed\n", ret); 1146 | } 1147 | printf(" "); 1148 | for (i = 0; i < readLength; i++) 1149 | { 1150 | printf("0x%02x ", rawResp[i]); 1151 | } 1152 | printf("\n"); 1153 | } 1154 | 1155 | if (looped) 1156 | { 1157 | printLoopSummary(ccCounts); 1158 | } 1159 | 1160 | free(rawCmd); 1161 | free(rawResp); 1162 | } 1163 | else 1164 | { 1165 | printf("ERROR: Unrecognized command\n"); 1166 | goto ErrorExit; 1167 | } 1168 | 1169 | if (measureTime) 1170 | { 1171 | printf("Total time taken = %lf seconds\n", totalTimeSpent); 1172 | if (loopCount > 1) 1173 | { 1174 | printf("Average time taken per command = %lf seconds\n", 1175 | totalTimeSpent / loopCount); 1176 | } 1177 | } 1178 | 1179 | return 0; 1180 | 1181 | ErrorExit: 1182 | Usage(argv[0]); 1183 | return 1; 1184 | } 1185 | -------------------------------------------------------------------------------- /peci.c: -------------------------------------------------------------------------------- 1 | /* 2 | // Copyright (c) 2019 Intel Corporation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #pragma GCC diagnostic push 26 | #pragma GCC diagnostic ignored "-Wcpp" 27 | #pragma GCC diagnostic ignored "-Wvariadic-macros" 28 | #include 29 | #pragma GCC diagnostic pop 30 | 31 | EPECIStatus peci_GetDIB_seq(uint8_t target, uint64_t* dib, int peci_fd); 32 | 33 | char* peci_device_list[2]; 34 | #define DEV_NAME_SIZE 64 35 | /*------------------------------------------------------------------------- 36 | * This function sets the name of the PECI device file to use. 37 | * If the PECI device name is null try "/dev/peci-default", 38 | * if "/dev/peci-default" does not exist, fall back to "/dev/peci-0" 39 | *------------------------------------------------------------------------*/ 40 | void peci_SetDevName(char* peci_dev) 41 | { 42 | static char peci_name_new[DEV_NAME_SIZE] = {0}; 43 | 44 | if (peci_dev) 45 | { 46 | strncpy(peci_name_new, peci_dev, sizeof(peci_name_new)); 47 | peci_name_new[DEV_NAME_SIZE - 1] = '\0'; 48 | peci_device_list[0] = peci_name_new; 49 | peci_device_list[1] = NULL; 50 | syslog(LOG_INFO, "PECI set dev name to %s\n", peci_device_list[0]); 51 | } 52 | else 53 | { 54 | peci_device_list[0] = "/dev/peci-default"; 55 | peci_device_list[1] = "/dev/peci-0"; 56 | syslog(LOG_INFO, "PECI set dev names to %s, %s\n", peci_device_list[0], 57 | peci_device_list[1]); 58 | } 59 | } 60 | 61 | /*------------------------------------------------------------------------- 62 | * This function initializes PECI device name when a shared library 63 | * is loaded, typically during program startup. 64 | *------------------------------------------------------------------------*/ 65 | static void init() __attribute__((constructor)); 66 | static void init() 67 | { 68 | // By default PECI_DEV is not defined in the environment, 69 | // so this will call peci_SetDevName(NULL) and initialize 70 | // PECI device name to defaults. 71 | peci_SetDevName(getenv("PECI_DEV")); 72 | } 73 | 74 | /*------------------------------------------------------------------------- 75 | * This function unlocks the peci interface 76 | *------------------------------------------------------------------------*/ 77 | void peci_Unlock(int peci_fd) 78 | { 79 | if (close(peci_fd) != 0) 80 | { 81 | syslog(LOG_ERR, "PECI device failed to unlock.\n"); 82 | } 83 | } 84 | 85 | /*------------------------------------------------------------------------- 86 | * This function attempts to lock the peci interface with the specified 87 | * timeout and returns a file descriptor if successful. 88 | *------------------------------------------------------------------------*/ 89 | EPECIStatus peci_Lock(int* peci_fd, int timeout_ms) 90 | { 91 | struct timespec sRequest = {0}; 92 | sRequest.tv_sec = 0; 93 | sRequest.tv_nsec = PECI_TIMEOUT_RESOLUTION_MS * 1000 * 1000; 94 | int timeout_count = 0; 95 | char* peci_device = peci_device_list[0]; 96 | 97 | if (NULL == peci_fd) 98 | { 99 | return PECI_CC_INVALID_REQ; 100 | } 101 | 102 | // Open the PECI driver with the specified timeout 103 | *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC); 104 | if (*peci_fd == -1 && errno == ENOENT && peci_device_list[1]) 105 | { 106 | peci_device = peci_device_list[1]; 107 | *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC); 108 | } 109 | switch (timeout_ms) 110 | { 111 | case PECI_NO_WAIT: 112 | break; 113 | case PECI_WAIT_FOREVER: 114 | while (-1 == *peci_fd) 115 | { 116 | nanosleep(&sRequest, NULL); 117 | *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC); 118 | } 119 | break; 120 | default: 121 | while (-1 == *peci_fd && timeout_count < timeout_ms) 122 | { 123 | nanosleep(&sRequest, NULL); 124 | timeout_count += PECI_TIMEOUT_RESOLUTION_MS; 125 | *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC); 126 | } 127 | } 128 | if (-1 == *peci_fd) 129 | { 130 | syslog(LOG_ERR, " >>> PECI Device Busy <<< \n"); 131 | return PECI_CC_DRIVER_ERR; 132 | } 133 | return PECI_CC_SUCCESS; 134 | } 135 | 136 | /*------------------------------------------------------------------------- 137 | * This function closes the peci interface 138 | *------------------------------------------------------------------------*/ 139 | static void peci_Close(int peci_fd) 140 | { 141 | peci_Unlock(peci_fd); 142 | } 143 | 144 | /*------------------------------------------------------------------------- 145 | * This function opens the peci interface and returns a file descriptor 146 | *------------------------------------------------------------------------*/ 147 | static EPECIStatus peci_Open(int* peci_fd) 148 | { 149 | if (NULL == peci_fd) 150 | { 151 | return PECI_CC_INVALID_REQ; 152 | } 153 | 154 | // Lock the PECI driver with a default timeout 155 | return peci_Lock(peci_fd, PECI_TIMEOUT_MS); 156 | } 157 | 158 | /*------------------------------------------------------------------------- 159 | * This function issues peci commands to peci driver 160 | *------------------------------------------------------------------------*/ 161 | static EPECIStatus HW_peci_issue_cmd(unsigned int cmd, char* cmdPtr, 162 | int peci_fd) 163 | { 164 | if (cmdPtr == NULL) 165 | { 166 | return PECI_CC_INVALID_REQ; 167 | } 168 | 169 | if (ioctl(peci_fd, cmd, cmdPtr) != 0) 170 | { 171 | if (errno == ETIMEDOUT) 172 | { 173 | return PECI_CC_TIMEOUT; 174 | } 175 | return PECI_CC_DRIVER_ERR; 176 | } 177 | 178 | return PECI_CC_SUCCESS; 179 | } 180 | 181 | /*------------------------------------------------------------------------- 182 | * Find the specified PCI bus number value 183 | *------------------------------------------------------------------------*/ 184 | EPECIStatus FindBusNumber(uint8_t u8Bus, uint8_t u8Cpu, uint8_t* pu8BusValue) 185 | { 186 | uint8_t u8CpuBus0[] = { 187 | PECI_PCI_BUS0_CPU0, 188 | PECI_PCI_BUS0_CPU1, 189 | }; 190 | uint8_t u8Bus0 = 0; 191 | uint8_t u8Offset = 0; 192 | EPECIStatus ret = PECI_CC_SUCCESS; 193 | uint8_t u8Reg[4] = {0}; 194 | uint8_t cc = 0; 195 | 196 | // First check for valid inputs 197 | // Check cpu and bus numbers, only support buses [5:0] 198 | if ((u8Bus > 5) || (u8Cpu >= (sizeof(u8CpuBus0) / sizeof(uint8_t))) || 199 | (pu8BusValue == NULL)) 200 | { 201 | return PECI_CC_INVALID_REQ; 202 | } 203 | 204 | // Get the Bus 0 value for the requested CPU 205 | u8Bus0 = u8CpuBus0[u8Cpu]; 206 | 207 | // Next check that the bus numbers are valid 208 | // CPUBUSNO_VALID register - Above registers valid? - B(0) D5 F0 offset 209 | // D4h 210 | ret = peci_RdPCIConfig(u8Cpu, u8Bus0, PECI_PCI_CPUBUSNO_DEV, 211 | PECI_PCI_CPUBUSNO_FUNC, PECI_PCI_CPUBUSNO_VALID, 212 | u8Reg, &cc); 213 | if (ret != PECI_CC_SUCCESS) 214 | { 215 | return ret; 216 | } 217 | // BIOS will set bit 31 of CPUBUSNO_VALID when the bus numbers are valid 218 | if ((u8Reg[3] & 0x80) == 0) 219 | { 220 | return PECI_CC_HW_ERR; 221 | } 222 | 223 | // Bus numbers are valid so read the correct offset for the requested 224 | // bus CPUBUSNO register - CPU Internal Bus Numbers [3:0] - B(0) D5 F0 225 | // offset CCh CPUBUSNO_1 register - CPU Internal Bus Numbers [5:4] - 226 | // B(0) D5 F0 offset D0h 227 | u8Offset = u8Bus <= 3 ? PECI_PCI_CPUBUSNO : PECI_PCI_CPUBUSNO_1; 228 | ret = peci_RdPCIConfig(u8Cpu, u8Bus0, PECI_PCI_CPUBUSNO_DEV, 229 | PECI_PCI_CPUBUSNO_FUNC, u8Offset, u8Reg, &cc); 230 | if (ret != PECI_CC_SUCCESS) 231 | { 232 | return ret; 233 | } 234 | 235 | // Now return the bus value for the requested bus 236 | *pu8BusValue = u8Reg[u8Bus % 4]; 237 | 238 | // Unused bus numbers are set to zero which is only valid for bus 0 239 | // so, return an error for any other bus set to zero 240 | if (*pu8BusValue == 0 && u8Bus != 0) 241 | { 242 | return PECI_CC_CPU_NOT_PRESENT; 243 | } 244 | 245 | return PECI_CC_SUCCESS; 246 | } 247 | 248 | /*------------------------------------------------------------------------- 249 | * This function checks the CPU PECI interface 250 | *------------------------------------------------------------------------*/ 251 | EPECIStatus peci_Ping(uint8_t target) 252 | { 253 | int peci_fd = -1; 254 | EPECIStatus ret = PECI_CC_SUCCESS; 255 | 256 | // The target address must be in the valid range 257 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 258 | { 259 | return PECI_CC_INVALID_REQ; 260 | } 261 | 262 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 263 | { 264 | return PECI_CC_DRIVER_ERR; 265 | } 266 | ret = peci_Ping_seq(target, peci_fd); 267 | 268 | peci_Close(peci_fd); 269 | return ret; 270 | } 271 | 272 | /*------------------------------------------------------------------------- 273 | * This function allows sequential Ping with the provided 274 | * peci file descriptor. 275 | *------------------------------------------------------------------------*/ 276 | EPECIStatus peci_Ping_seq(uint8_t target, int peci_fd) 277 | { 278 | EPECIStatus ret = PECI_CC_SUCCESS; 279 | struct peci_ping_msg cmd = {0}; 280 | 281 | // The target address must be in the valid range 282 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 283 | { 284 | return PECI_CC_INVALID_REQ; 285 | } 286 | 287 | cmd.addr = target; 288 | ret = HW_peci_issue_cmd(PECI_IOC_PING, (char*)&cmd, peci_fd); 289 | 290 | return ret; 291 | } 292 | 293 | /*------------------------------------------------------------------------- 294 | * This function gets PECI device information 295 | *------------------------------------------------------------------------*/ 296 | EPECIStatus peci_GetDIB(uint8_t target, uint64_t* dib) 297 | { 298 | int peci_fd = -1; 299 | EPECIStatus ret = PECI_CC_SUCCESS; 300 | 301 | if (dib == NULL) 302 | { 303 | return PECI_CC_INVALID_REQ; 304 | } 305 | 306 | // The target address must be in the valid range 307 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 308 | { 309 | return PECI_CC_INVALID_REQ; 310 | } 311 | 312 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 313 | { 314 | return PECI_CC_DRIVER_ERR; 315 | } 316 | ret = peci_GetDIB_seq(target, dib, peci_fd); 317 | 318 | peci_Close(peci_fd); 319 | return ret; 320 | } 321 | 322 | /*------------------------------------------------------------------------- 323 | * This function allows sequential GetDIB with the provided 324 | * peci file descriptor. 325 | *------------------------------------------------------------------------*/ 326 | EPECIStatus peci_GetDIB_seq(uint8_t target, uint64_t* dib, int peci_fd) 327 | { 328 | struct peci_get_dib_msg cmd = {0}; 329 | EPECIStatus ret = PECI_CC_SUCCESS; 330 | cmd.addr = target; 331 | 332 | if (dib == NULL) 333 | { 334 | return PECI_CC_INVALID_REQ; 335 | } 336 | 337 | // The target address must be in the valid range 338 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 339 | { 340 | return PECI_CC_INVALID_REQ; 341 | } 342 | 343 | ret = HW_peci_issue_cmd(PECI_IOC_GET_DIB, (char*)&cmd, peci_fd); 344 | 345 | if (ret == PECI_CC_SUCCESS) 346 | { 347 | *dib = cmd.dib; 348 | } 349 | 350 | return ret; 351 | } 352 | 353 | /*------------------------------------------------------------------------- 354 | * This function get PECI Thermal temperature 355 | * Expressed in signed fixed point value of 1/64 degrees celsius 356 | *------------------------------------------------------------------------*/ 357 | EPECIStatus peci_GetTemp(uint8_t target, int16_t* temperature) 358 | { 359 | int peci_fd = -1; 360 | struct peci_get_temp_msg cmd = {0}; 361 | 362 | if (temperature == NULL) 363 | { 364 | return PECI_CC_INVALID_REQ; 365 | } 366 | 367 | // The target address must be in the valid range 368 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 369 | { 370 | return PECI_CC_INVALID_REQ; 371 | } 372 | 373 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 374 | { 375 | return PECI_CC_DRIVER_ERR; 376 | } 377 | 378 | cmd.addr = target; 379 | 380 | EPECIStatus ret = 381 | HW_peci_issue_cmd(PECI_IOC_GET_TEMP, (char*)&cmd, peci_fd); 382 | 383 | if (ret == PECI_CC_SUCCESS) 384 | { 385 | *temperature = cmd.temp_raw; 386 | } 387 | 388 | peci_Close(peci_fd); 389 | 390 | return ret; 391 | } 392 | 393 | /*------------------------------------------------------------------------- 394 | * This function provides read access to the package configuration 395 | * space within the processor. 396 | *------------------------------------------------------------------------*/ 397 | EPECIStatus peci_RdPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Value, 398 | uint8_t u8ReadLen, uint8_t* pPkgConfig, 399 | uint8_t* cc) 400 | { 401 | // Default to domain ID 0 402 | return peci_RdPkgConfig_dom(target, 0, u8Index, u16Value, u8ReadLen, 403 | pPkgConfig, cc); 404 | } 405 | 406 | /*------------------------------------------------------------------------- 407 | * This function provides read access to the package configuration 408 | * space within the processor in the specified domain. 409 | *------------------------------------------------------------------------*/ 410 | EPECIStatus peci_RdPkgConfig_dom( 411 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Value, 412 | uint8_t u8ReadLen, uint8_t* pPkgConfig, uint8_t* cc) 413 | { 414 | int peci_fd = -1; 415 | EPECIStatus ret = PECI_CC_SUCCESS; 416 | 417 | if (pPkgConfig == NULL || cc == NULL) 418 | { 419 | return PECI_CC_INVALID_REQ; 420 | } 421 | 422 | // The target address must be in the valid range 423 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 424 | { 425 | return PECI_CC_INVALID_REQ; 426 | } 427 | 428 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 429 | { 430 | return PECI_CC_DRIVER_ERR; 431 | } 432 | ret = peci_RdPkgConfig_seq_dom(target, domainId, u8Index, u16Value, 433 | u8ReadLen, pPkgConfig, peci_fd, cc); 434 | 435 | peci_Close(peci_fd); 436 | return ret; 437 | } 438 | 439 | /*------------------------------------------------------------------------- 440 | * This function allows sequential RdPkgConfig with the provided 441 | * peci file descriptor. 442 | *------------------------------------------------------------------------*/ 443 | EPECIStatus peci_RdPkgConfig_seq(uint8_t target, uint8_t u8Index, 444 | uint16_t u16Value, uint8_t u8ReadLen, 445 | uint8_t* pPkgConfig, int peci_fd, uint8_t* cc) 446 | { 447 | // Default to domain ID 0 448 | return peci_RdPkgConfig_seq_dom(target, 0, u8Index, u16Value, u8ReadLen, 449 | pPkgConfig, peci_fd, cc); 450 | } 451 | 452 | /*------------------------------------------------------------------------- 453 | * This function allows sequential RdPkgConfig with the provided 454 | * peci file descriptor in the specified domain. 455 | *------------------------------------------------------------------------*/ 456 | EPECIStatus peci_RdPkgConfig_seq_dom( 457 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Value, 458 | uint8_t u8ReadLen, uint8_t* pPkgConfig, int peci_fd, uint8_t* cc) 459 | { 460 | struct peci_rd_pkg_cfg_msg cmd = {0}; 461 | EPECIStatus ret = PECI_CC_SUCCESS; 462 | 463 | if (pPkgConfig == NULL || cc == NULL) 464 | { 465 | return PECI_CC_INVALID_REQ; 466 | } 467 | 468 | // The target address must be in the valid range 469 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 470 | { 471 | return PECI_CC_INVALID_REQ; 472 | } 473 | 474 | // Per the PECI spec, the write length must be a byte, word, or dword 475 | if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4) 476 | { 477 | return PECI_CC_INVALID_REQ; 478 | } 479 | 480 | // The PECI buffer must be large enough to hold the requested data 481 | if (sizeof(cmd.pkg_config) < u8ReadLen) 482 | { 483 | return PECI_CC_INVALID_REQ; 484 | } 485 | 486 | cmd.addr = target; 487 | cmd.index = u8Index; // RdPkgConfig index 488 | cmd.param = u16Value; // Config parameter value 489 | cmd.rx_len = u8ReadLen; 490 | cmd.domain_id = domainId; 491 | 492 | ret = HW_peci_issue_cmd(PECI_IOC_RD_PKG_CFG, (char*)&cmd, peci_fd); 493 | *cc = cmd.cc; 494 | if (ret == PECI_CC_SUCCESS) 495 | { 496 | memcpy(pPkgConfig, cmd.pkg_config, u8ReadLen); 497 | } 498 | 499 | return ret; 500 | } 501 | 502 | /*------------------------------------------------------------------------- 503 | * This function provides write access to the package configuration 504 | * space within the processor 505 | *------------------------------------------------------------------------*/ 506 | EPECIStatus peci_WrPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Param, 507 | uint32_t u32Value, uint8_t u8WriteLen, uint8_t* cc) 508 | { 509 | // Default to domain ID 0 510 | return peci_WrPkgConfig_dom(target, 0, u8Index, u16Param, u32Value, 511 | u8WriteLen, cc); 512 | } 513 | 514 | /*------------------------------------------------------------------------- 515 | * This function provides write access to the package configuration 516 | * space within the processor in the specified domain 517 | *------------------------------------------------------------------------*/ 518 | EPECIStatus peci_WrPkgConfig_dom( 519 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Param, 520 | uint32_t u32Value, uint8_t u8WriteLen, uint8_t* cc) 521 | { 522 | int peci_fd = -1; 523 | EPECIStatus ret = PECI_CC_SUCCESS; 524 | 525 | if (cc == NULL) 526 | { 527 | return PECI_CC_INVALID_REQ; 528 | } 529 | 530 | // The target address must be in the valid range 531 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 532 | { 533 | return PECI_CC_INVALID_REQ; 534 | } 535 | 536 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 537 | { 538 | return PECI_CC_DRIVER_ERR; 539 | } 540 | ret = peci_WrPkgConfig_seq_dom(target, domainId, u8Index, u16Param, 541 | u32Value, u8WriteLen, peci_fd, cc); 542 | 543 | peci_Close(peci_fd); 544 | return ret; 545 | } 546 | 547 | /*------------------------------------------------------------------------- 548 | * This function allows sequential WrPkgConfig with the provided 549 | * peci file descriptor. 550 | *------------------------------------------------------------------------*/ 551 | EPECIStatus peci_WrPkgConfig_seq(uint8_t target, uint8_t u8Index, 552 | uint16_t u16Param, uint32_t u32Value, 553 | uint8_t u8WriteLen, int peci_fd, uint8_t* cc) 554 | { 555 | // Default to domain ID 0 556 | return peci_WrPkgConfig_seq_dom(target, 0, u8Index, u16Param, u32Value, 557 | u8WriteLen, peci_fd, cc); 558 | } 559 | 560 | /*------------------------------------------------------------------------- 561 | * This function allows sequential WrPkgConfig with the provided 562 | * peci file descriptor in the specified domain. 563 | *------------------------------------------------------------------------*/ 564 | EPECIStatus peci_WrPkgConfig_seq_dom( 565 | uint8_t target, uint8_t domainId, uint8_t u8Index, uint16_t u16Param, 566 | uint32_t u32Value, uint8_t u8WriteLen, int peci_fd, uint8_t* cc) 567 | { 568 | struct peci_wr_pkg_cfg_msg cmd = {0}; 569 | EPECIStatus ret = PECI_CC_SUCCESS; 570 | 571 | if (cc == NULL) 572 | { 573 | return PECI_CC_INVALID_REQ; 574 | } 575 | 576 | // The target address must be in the valid range 577 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 578 | { 579 | return PECI_CC_INVALID_REQ; 580 | } 581 | 582 | // Per the PECI spec, the write length must be a byte, word, or dword 583 | if ((u8WriteLen != 1) && (u8WriteLen != 2) && (u8WriteLen != 4)) 584 | { 585 | return PECI_CC_INVALID_REQ; 586 | } 587 | 588 | cmd.addr = target; 589 | cmd.index = u8Index; // RdPkgConfig index 590 | cmd.param = u16Param; // parameter value 591 | cmd.tx_len = u8WriteLen; 592 | cmd.value = u32Value; 593 | cmd.domain_id = domainId; 594 | 595 | ret = HW_peci_issue_cmd(PECI_IOC_WR_PKG_CFG, (char*)&cmd, peci_fd); 596 | *cc = cmd.cc; 597 | 598 | return ret; 599 | } 600 | 601 | /*------------------------------------------------------------------------- 602 | * This function provides read access to Model Specific Registers 603 | * defined in the processor doc. 604 | *------------------------------------------------------------------------*/ 605 | EPECIStatus peci_RdIAMSR(uint8_t target, uint8_t threadID, uint16_t MSRAddress, 606 | uint64_t* u64MsrVal, uint8_t* cc) 607 | { 608 | // Default to domain ID 0 609 | return peci_RdIAMSR_dom(target, 0, threadID, MSRAddress, u64MsrVal, cc); 610 | } 611 | 612 | /*------------------------------------------------------------------------- 613 | * This function provides read access to Model Specific Registers 614 | * defined in the processor doc in the specified domain. 615 | *------------------------------------------------------------------------*/ 616 | EPECIStatus peci_RdIAMSR_dom(uint8_t target, uint8_t domainId, uint8_t threadID, 617 | uint16_t MSRAddress, uint64_t* u64MsrVal, 618 | uint8_t* cc) 619 | { 620 | int peci_fd = -1; 621 | struct peci_rd_ia_msr_msg cmd = {0}; 622 | EPECIStatus ret = PECI_CC_SUCCESS; 623 | 624 | if (u64MsrVal == NULL || cc == NULL) 625 | { 626 | return PECI_CC_INVALID_REQ; 627 | } 628 | 629 | // The target address must be in the valid range 630 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 631 | { 632 | return PECI_CC_INVALID_REQ; 633 | } 634 | 635 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 636 | { 637 | return PECI_CC_DRIVER_ERR; 638 | } 639 | 640 | cmd.addr = target; 641 | cmd.thread_id = threadID; // request byte for thread ID 642 | cmd.address = MSRAddress; // MSR Address 643 | cmd.domain_id = domainId; 644 | 645 | ret = HW_peci_issue_cmd(PECI_IOC_RD_IA_MSR, (char*)&cmd, peci_fd); 646 | *cc = cmd.cc; 647 | if (ret == PECI_CC_SUCCESS) 648 | { 649 | *u64MsrVal = cmd.value; 650 | } 651 | 652 | peci_Close(peci_fd); 653 | return ret; 654 | } 655 | 656 | /*------------------------------------------------------------------------- 657 | * This function provides read access to the PCI configuration space at 658 | * the requested PCI configuration address. 659 | *------------------------------------------------------------------------*/ 660 | EPECIStatus peci_RdPCIConfig(uint8_t target, uint8_t u8Bus, uint8_t u8Device, 661 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData, 662 | uint8_t* cc) 663 | { 664 | // Default to domain ID 0 665 | return peci_RdPCIConfig_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg, 666 | pPCIData, cc); 667 | } 668 | 669 | /*------------------------------------------------------------------------- 670 | * This function provides read access to the PCI configuration space at 671 | * the requested PCI configuration address in the specified domain. 672 | *------------------------------------------------------------------------*/ 673 | EPECIStatus peci_RdPCIConfig_dom( 674 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 675 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData, uint8_t* cc) 676 | { 677 | int peci_fd = -1; 678 | EPECIStatus ret = PECI_CC_SUCCESS; 679 | 680 | if (pPCIData == NULL || cc == NULL) 681 | { 682 | return PECI_CC_INVALID_REQ; 683 | } 684 | 685 | // The target address must be in the valid range 686 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 687 | { 688 | return PECI_CC_INVALID_REQ; 689 | } 690 | 691 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 692 | { 693 | return PECI_CC_DRIVER_ERR; 694 | } 695 | ret = peci_RdPCIConfig_seq_dom(target, domainId, u8Bus, u8Device, u8Fcn, 696 | u16Reg, pPCIData, peci_fd, cc); 697 | 698 | peci_Close(peci_fd); 699 | return ret; 700 | } 701 | 702 | /*------------------------------------------------------------------------- 703 | * This function allows sequential RdPCIConfig with the provided 704 | * peci file descriptor. 705 | *------------------------------------------------------------------------*/ 706 | EPECIStatus peci_RdPCIConfig_seq( 707 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 708 | uint16_t u16Reg, uint8_t* pPCIData, int peci_fd, uint8_t* cc) 709 | { 710 | // Default to domain ID 0 711 | return peci_RdPCIConfig_seq_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg, 712 | pPCIData, peci_fd, cc); 713 | } 714 | 715 | /*------------------------------------------------------------------------- 716 | * This function allows sequential RdPCIConfig with the provided 717 | * peci file descriptor in the specified domain. 718 | *------------------------------------------------------------------------*/ 719 | EPECIStatus peci_RdPCIConfig_seq_dom( 720 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 721 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData, int peci_fd, uint8_t* cc) 722 | { 723 | struct peci_rd_pci_cfg_msg cmd = {0}; 724 | EPECIStatus ret = PECI_CC_SUCCESS; 725 | 726 | if (pPCIData == NULL || cc == NULL) 727 | { 728 | return PECI_CC_INVALID_REQ; 729 | } 730 | 731 | // The target address must be in the valid range 732 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 733 | { 734 | return PECI_CC_INVALID_REQ; 735 | } 736 | 737 | // The PECI buffer must be large enough to hold the PCI data 738 | if (sizeof(cmd.pci_config) < 4) 739 | { 740 | return PECI_CC_INVALID_REQ; 741 | } 742 | 743 | cmd.addr = target; 744 | cmd.bus = u8Bus; 745 | cmd.device = u8Device; 746 | cmd.function = u8Fcn; 747 | cmd.reg = u16Reg; 748 | cmd.domain_id = domainId; 749 | 750 | ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG, (char*)&cmd, peci_fd); 751 | *cc = cmd.cc; 752 | 753 | if (ret == PECI_CC_SUCCESS) 754 | { 755 | memcpy(pPCIData, cmd.pci_config, 4); 756 | } 757 | 758 | return ret; 759 | } 760 | 761 | /*------------------------------------------------------------------------- 762 | * This function provides read access to the local PCI configuration space 763 | *------------------------------------------------------------------------*/ 764 | EPECIStatus peci_RdPCIConfigLocal( 765 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 766 | uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, uint8_t* cc) 767 | { 768 | // Default to domain ID 0 769 | return peci_RdPCIConfigLocal_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg, 770 | u8ReadLen, pPCIReg, cc); 771 | } 772 | 773 | /*------------------------------------------------------------------------- 774 | * This function provides read access to the local PCI configuration space in 775 | * the specified domain 776 | *------------------------------------------------------------------------*/ 777 | EPECIStatus peci_RdPCIConfigLocal_dom( 778 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 779 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, 780 | uint8_t* cc) 781 | { 782 | int peci_fd = -1; 783 | EPECIStatus ret = PECI_CC_SUCCESS; 784 | 785 | if (pPCIReg == NULL || cc == NULL) 786 | { 787 | return PECI_CC_INVALID_REQ; 788 | } 789 | 790 | // The target address must be in the valid range 791 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 792 | { 793 | return PECI_CC_INVALID_REQ; 794 | } 795 | 796 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 797 | { 798 | return PECI_CC_DRIVER_ERR; 799 | } 800 | ret = 801 | peci_RdPCIConfigLocal_seq_dom(target, domainId, u8Bus, u8Device, u8Fcn, 802 | u16Reg, u8ReadLen, pPCIReg, peci_fd, cc); 803 | 804 | peci_Close(peci_fd); 805 | return ret; 806 | } 807 | 808 | /*------------------------------------------------------------------------- 809 | * This function allows sequential RdPCIConfigLocal with the provided 810 | * peci file descriptor. 811 | *------------------------------------------------------------------------*/ 812 | EPECIStatus peci_RdPCIConfigLocal_seq( 813 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 814 | uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, int peci_fd, 815 | uint8_t* cc) 816 | { 817 | // Default to domain ID 0 818 | return peci_RdPCIConfigLocal_seq_dom( 819 | target, 0, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, pPCIReg, peci_fd, 820 | cc); 821 | } 822 | 823 | /*------------------------------------------------------------------------- 824 | * This function allows sequential RdPCIConfigLocal with the provided 825 | * peci file descriptor in the specified domain. 826 | *------------------------------------------------------------------------*/ 827 | EPECIStatus peci_RdPCIConfigLocal_seq_dom( 828 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 829 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIReg, 830 | int peci_fd, uint8_t* cc) 831 | { 832 | struct peci_rd_pci_cfg_local_msg cmd = {0}; 833 | EPECIStatus ret = PECI_CC_SUCCESS; 834 | 835 | if (pPCIReg == NULL || cc == NULL) 836 | { 837 | return PECI_CC_INVALID_REQ; 838 | } 839 | 840 | // The target address must be in the valid range 841 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 842 | { 843 | return PECI_CC_INVALID_REQ; 844 | } 845 | 846 | // Per the PECI spec, the read length must be a byte, word, or dword 847 | if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4) 848 | { 849 | return PECI_CC_INVALID_REQ; 850 | } 851 | 852 | // The PECI buffer must be large enough to hold the requested data 853 | if (sizeof(cmd.pci_config) < u8ReadLen) 854 | { 855 | return PECI_CC_INVALID_REQ; 856 | } 857 | 858 | cmd.addr = target; 859 | cmd.bus = u8Bus; 860 | cmd.device = u8Device; 861 | cmd.function = u8Fcn; 862 | cmd.reg = u16Reg; 863 | cmd.rx_len = u8ReadLen; 864 | cmd.domain_id = domainId; 865 | 866 | ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG_LOCAL, (char*)&cmd, peci_fd); 867 | *cc = cmd.cc; 868 | 869 | if (ret == PECI_CC_SUCCESS) 870 | { 871 | memcpy(pPCIReg, cmd.pci_config, u8ReadLen); 872 | } 873 | 874 | return ret; 875 | } 876 | 877 | /*------------------------------------------------------------------------- 878 | * This function provides write access to the local PCI configuration space 879 | *------------------------------------------------------------------------*/ 880 | EPECIStatus peci_WrPCIConfigLocal( 881 | uint8_t target, uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, 882 | uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, uint8_t* cc) 883 | { 884 | // Default to domain ID 0 885 | return peci_WrPCIConfigLocal_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg, 886 | DataLen, DataVal, cc); 887 | } 888 | 889 | /*------------------------------------------------------------------------- 890 | * This function provides write access to the local PCI configuration space in 891 | * the specified domain 892 | *------------------------------------------------------------------------*/ 893 | EPECIStatus peci_WrPCIConfigLocal_dom( 894 | uint8_t target, uint8_t domainId, uint8_t u8Bus, uint8_t u8Device, 895 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, 896 | uint8_t* cc) 897 | { 898 | int peci_fd = -1; 899 | struct peci_wr_pci_cfg_local_msg cmd = {0}; 900 | EPECIStatus ret = PECI_CC_SUCCESS; 901 | 902 | if (cc == NULL) 903 | { 904 | return PECI_CC_INVALID_REQ; 905 | } 906 | 907 | // The target address must be in the valid range 908 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 909 | { 910 | return PECI_CC_INVALID_REQ; 911 | } 912 | 913 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 914 | { 915 | return PECI_CC_DRIVER_ERR; 916 | } 917 | 918 | // Per the PECI spec, the write length must be a byte, word, or dword 919 | if (DataLen != 1 && DataLen != 2 && DataLen != 4) 920 | { 921 | peci_Close(peci_fd); 922 | return PECI_CC_INVALID_REQ; 923 | } 924 | 925 | cmd.addr = target; 926 | cmd.bus = u8Bus; 927 | cmd.device = u8Device; 928 | cmd.function = u8Fcn; 929 | cmd.reg = u16Reg; 930 | cmd.tx_len = DataLen; 931 | cmd.value = DataVal; 932 | cmd.domain_id = domainId; 933 | 934 | ret = HW_peci_issue_cmd(PECI_IOC_WR_PCI_CFG_LOCAL, (char*)&cmd, peci_fd); 935 | *cc = cmd.cc; 936 | 937 | peci_Close(peci_fd); 938 | return ret; 939 | } 940 | 941 | /*------------------------------------------------------------------------- 942 | * This internal function is the common interface for RdEndPointConfig to PCI in 943 | * the specified domain 944 | *------------------------------------------------------------------------*/ 945 | static EPECIStatus peci_RdEndPointConfigPciCommon_dom( 946 | uint8_t target, uint8_t domainId, uint8_t u8MsgType, uint8_t u8Seg, 947 | uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, 948 | uint8_t u8ReadLen, uint8_t* pPCIData, int peci_fd, uint8_t* cc) 949 | { 950 | struct peci_rd_end_pt_cfg_msg cmd = {0}; 951 | EPECIStatus ret = PECI_CC_SUCCESS; 952 | 953 | if (pPCIData == NULL || cc == NULL) 954 | { 955 | return PECI_CC_INVALID_REQ; 956 | } 957 | 958 | // The target address must be in the valid range 959 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 960 | { 961 | return PECI_CC_INVALID_REQ; 962 | } 963 | 964 | // The PECI buffer must be large enough to hold the requested data 965 | if (sizeof(cmd.data) < u8ReadLen) 966 | { 967 | return PECI_CC_INVALID_REQ; 968 | } 969 | 970 | cmd.addr = target; 971 | cmd.msg_type = u8MsgType; 972 | cmd.params.pci_cfg.seg = u8Seg; 973 | cmd.params.pci_cfg.bus = u8Bus; 974 | cmd.params.pci_cfg.device = u8Device; 975 | cmd.params.pci_cfg.function = u8Fcn; 976 | cmd.params.pci_cfg.reg = u16Reg; 977 | cmd.rx_len = u8ReadLen; 978 | cmd.domain_id = domainId; 979 | 980 | ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd); 981 | *cc = cmd.cc; 982 | 983 | if (ret == PECI_CC_SUCCESS) 984 | { 985 | memcpy(pPCIData, cmd.data, u8ReadLen); 986 | } 987 | else 988 | { 989 | ret = PECI_CC_DRIVER_ERR; 990 | } 991 | 992 | return ret; 993 | } 994 | 995 | /*------------------------------------------------------------------------- 996 | * This function provides read access to the PCI configuration space at 997 | * the requested PCI configuration address. 998 | *------------------------------------------------------------------------*/ 999 | EPECIStatus peci_RdEndPointConfigPci( 1000 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1001 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 1002 | uint8_t* cc) 1003 | { 1004 | // Default to domain ID 0 1005 | return peci_RdEndPointConfigPci_dom(target, 0, u8Seg, u8Bus, u8Device, 1006 | u8Fcn, u16Reg, u8ReadLen, pPCIData, cc); 1007 | } 1008 | 1009 | /*------------------------------------------------------------------------- 1010 | * This function provides read access to the PCI configuration space at 1011 | * the requested PCI configuration address in the specified domain. 1012 | *------------------------------------------------------------------------*/ 1013 | EPECIStatus peci_RdEndPointConfigPci_dom( 1014 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1015 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 1016 | uint8_t* pPCIData, uint8_t* cc) 1017 | { 1018 | int peci_fd = -1; 1019 | EPECIStatus ret = PECI_CC_SUCCESS; 1020 | 1021 | if (pPCIData == NULL || cc == NULL) 1022 | { 1023 | return PECI_CC_INVALID_REQ; 1024 | } 1025 | 1026 | // The target address must be in the valid range 1027 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1028 | { 1029 | return PECI_CC_INVALID_REQ; 1030 | } 1031 | 1032 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1033 | { 1034 | return PECI_CC_DRIVER_ERR; 1035 | } 1036 | ret = peci_RdEndPointConfigPci_seq_dom( 1037 | target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, 1038 | pPCIData, peci_fd, cc); 1039 | peci_Close(peci_fd); 1040 | return ret; 1041 | } 1042 | 1043 | /*------------------------------------------------------------------------- 1044 | * This function allows sequential RdEndPointConfig to PCI with the provided 1045 | * peci file descriptor. 1046 | *------------------------------------------------------------------------*/ 1047 | EPECIStatus peci_RdEndPointConfigPci_seq( 1048 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1049 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 1050 | int peci_fd, uint8_t* cc) 1051 | { 1052 | // Default to domain ID 0 1053 | return peci_RdEndPointConfigPci_seq_dom( 1054 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, pPCIData, 1055 | peci_fd, cc); 1056 | } 1057 | 1058 | /*------------------------------------------------------------------------- 1059 | * This function allows sequential RdEndPointConfig to PCI with the provided 1060 | * peci file descriptor in the specified domain. 1061 | *------------------------------------------------------------------------*/ 1062 | EPECIStatus peci_RdEndPointConfigPci_seq_dom( 1063 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1064 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 1065 | uint8_t* pPCIData, int peci_fd, uint8_t* cc) 1066 | { 1067 | if (pPCIData == NULL || cc == NULL) 1068 | { 1069 | return PECI_CC_INVALID_REQ; 1070 | } 1071 | 1072 | // The target address must be in the valid range 1073 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1074 | { 1075 | return PECI_CC_INVALID_REQ; 1076 | } 1077 | 1078 | // Per the PECI spec, the read length must be a byte, word, or dword 1079 | if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4) 1080 | { 1081 | return PECI_CC_INVALID_REQ; 1082 | } 1083 | 1084 | return peci_RdEndPointConfigPciCommon_dom( 1085 | target, domainId, PECI_ENDPTCFG_TYPE_PCI, u8Seg, u8Bus, u8Device, u8Fcn, 1086 | u16Reg, u8ReadLen, pPCIData, peci_fd, cc); 1087 | } 1088 | 1089 | /*------------------------------------------------------------------------- 1090 | * This function provides read access to the Local PCI configuration space at 1091 | * the requested PCI configuration address. 1092 | *------------------------------------------------------------------------*/ 1093 | EPECIStatus peci_RdEndPointConfigPciLocal( 1094 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1095 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 1096 | uint8_t* cc) 1097 | { 1098 | // Default to domain ID 0 1099 | return peci_RdEndPointConfigPciLocal_dom( 1100 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, pPCIData, 1101 | cc); 1102 | } 1103 | 1104 | /*------------------------------------------------------------------------- 1105 | * This function provides read access to the Local PCI configuration space at 1106 | * the requested PCI configuration address in the specified domain. 1107 | *------------------------------------------------------------------------*/ 1108 | EPECIStatus peci_RdEndPointConfigPciLocal_dom( 1109 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1110 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 1111 | uint8_t* pPCIData, uint8_t* cc) 1112 | { 1113 | int peci_fd = -1; 1114 | EPECIStatus ret = PECI_CC_SUCCESS; 1115 | 1116 | if (pPCIData == NULL || cc == NULL) 1117 | { 1118 | return PECI_CC_INVALID_REQ; 1119 | } 1120 | 1121 | // The target address must be in the valid range 1122 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1123 | { 1124 | return PECI_CC_INVALID_REQ; 1125 | } 1126 | 1127 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1128 | { 1129 | return PECI_CC_DRIVER_ERR; 1130 | } 1131 | ret = peci_RdEndPointConfigPciLocal_seq_dom( 1132 | target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, 1133 | pPCIData, peci_fd, cc); 1134 | peci_Close(peci_fd); 1135 | return ret; 1136 | } 1137 | 1138 | /*------------------------------------------------------------------------- 1139 | * This function allows sequential RdEndPointConfig to PCI Local with the 1140 | * provided peci file descriptor. 1141 | *------------------------------------------------------------------------*/ 1142 | EPECIStatus peci_RdEndPointConfigPciLocal_seq( 1143 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1144 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, uint8_t* pPCIData, 1145 | int peci_fd, uint8_t* cc) 1146 | { 1147 | // Default to domain ID 0 1148 | return peci_RdEndPointConfigPciLocal_seq_dom( 1149 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, pPCIData, 1150 | peci_fd, cc); 1151 | } 1152 | 1153 | /*------------------------------------------------------------------------- 1154 | * This function allows sequential RdEndPointConfig to PCI Local with the 1155 | * provided peci file descriptor in the specified domain. 1156 | *------------------------------------------------------------------------*/ 1157 | EPECIStatus peci_RdEndPointConfigPciLocal_seq_dom( 1158 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1159 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen, 1160 | uint8_t* pPCIData, int peci_fd, uint8_t* cc) 1161 | { 1162 | if (pPCIData == NULL || cc == NULL) 1163 | { 1164 | return PECI_CC_INVALID_REQ; 1165 | } 1166 | 1167 | // The target address must be in the valid range 1168 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1169 | { 1170 | return PECI_CC_INVALID_REQ; 1171 | } 1172 | 1173 | // Per the PECI spec, the read length must be a byte, word, or dword 1174 | if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4) 1175 | { 1176 | return PECI_CC_INVALID_REQ; 1177 | } 1178 | 1179 | return peci_RdEndPointConfigPciCommon_dom( 1180 | target, domainId, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg, u8Bus, u8Device, 1181 | u8Fcn, u16Reg, u8ReadLen, pPCIData, peci_fd, cc); 1182 | } 1183 | 1184 | /*------------------------------------------------------------------------- 1185 | * This function provides read access to PCI MMIO space at 1186 | * the requested PCI configuration address. 1187 | *------------------------------------------------------------------------*/ 1188 | EPECIStatus peci_RdEndPointConfigMmio( 1189 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1190 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 1191 | uint8_t u8ReadLen, uint8_t* pMmioData, uint8_t* cc) 1192 | { 1193 | // Default to domain ID 0 1194 | return peci_RdEndPointConfigMmio_dom( 1195 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset, 1196 | u8ReadLen, pMmioData, cc); 1197 | } 1198 | 1199 | /*------------------------------------------------------------------------- 1200 | * This function provides read access to PCI MMIO space at 1201 | * the requested PCI configuration address in the specified domain. 1202 | *------------------------------------------------------------------------*/ 1203 | EPECIStatus peci_RdEndPointConfigMmio_dom( 1204 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1205 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 1206 | uint64_t u64Offset, uint8_t u8ReadLen, uint8_t* pMmioData, uint8_t* cc) 1207 | { 1208 | int peci_fd = -1; 1209 | EPECIStatus ret = PECI_CC_SUCCESS; 1210 | 1211 | if (pMmioData == NULL || cc == NULL) 1212 | { 1213 | return PECI_CC_INVALID_REQ; 1214 | } 1215 | 1216 | // The target address must be in the valid range 1217 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1218 | { 1219 | return PECI_CC_INVALID_REQ; 1220 | } 1221 | 1222 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1223 | { 1224 | return PECI_CC_DRIVER_ERR; 1225 | } 1226 | ret = peci_RdEndPointConfigMmio_seq_dom( 1227 | target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, 1228 | u64Offset, u8ReadLen, pMmioData, peci_fd, cc); 1229 | peci_Close(peci_fd); 1230 | return ret; 1231 | } 1232 | 1233 | /*------------------------------------------------------------------------- 1234 | * This function allows sequential RdEndPointConfig to PCI MMIO with the 1235 | * provided peci file descriptor. 1236 | *------------------------------------------------------------------------*/ 1237 | EPECIStatus peci_RdEndPointConfigMmio_seq( 1238 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1239 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 1240 | uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, uint8_t* cc) 1241 | { 1242 | // Default to domain ID 0 1243 | return peci_RdEndPointConfigMmio_seq_dom( 1244 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset, 1245 | u8ReadLen, pMmioData, peci_fd, cc); 1246 | } 1247 | 1248 | /*------------------------------------------------------------------------- 1249 | * This function allows sequential RdEndPointConfig to PCI MMIO with the 1250 | * provided peci file descriptor in the specified domain. 1251 | *------------------------------------------------------------------------*/ 1252 | EPECIStatus peci_RdEndPointConfigMmio_seq_dom( 1253 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1254 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 1255 | uint64_t u64Offset, uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, 1256 | uint8_t* cc) 1257 | { 1258 | struct peci_rd_end_pt_cfg_msg cmd = {0}; 1259 | EPECIStatus ret = PECI_CC_SUCCESS; 1260 | 1261 | if (pMmioData == NULL || cc == NULL) 1262 | { 1263 | return PECI_CC_INVALID_REQ; 1264 | } 1265 | 1266 | // The target address must be in the valid range 1267 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1268 | { 1269 | return PECI_CC_INVALID_REQ; 1270 | } 1271 | 1272 | // Per the PECI spec, the read length must be a byte, word, dword, or qword 1273 | if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4 && u8ReadLen != 8) 1274 | { 1275 | return PECI_CC_INVALID_REQ; 1276 | } 1277 | 1278 | // The PECI buffer must be large enough to hold the requested data 1279 | if (sizeof(cmd.data) < u8ReadLen) 1280 | { 1281 | return PECI_CC_INVALID_REQ; 1282 | } 1283 | 1284 | cmd.addr = target; 1285 | cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO; 1286 | cmd.params.mmio.seg = u8Seg; 1287 | cmd.params.mmio.bus = u8Bus; 1288 | cmd.params.mmio.device = u8Device; 1289 | cmd.params.mmio.function = u8Fcn; 1290 | cmd.params.mmio.bar = u8Bar; 1291 | cmd.params.mmio.addr_type = u8AddrType; 1292 | cmd.params.mmio.offset = u64Offset; 1293 | cmd.rx_len = u8ReadLen; 1294 | cmd.domain_id = domainId; 1295 | 1296 | ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd); 1297 | *cc = cmd.cc; 1298 | 1299 | if (ret == PECI_CC_SUCCESS) 1300 | { 1301 | memcpy(pMmioData, cmd.data, u8ReadLen); 1302 | } 1303 | else 1304 | { 1305 | ret = PECI_CC_DRIVER_ERR; 1306 | } 1307 | 1308 | return ret; 1309 | } 1310 | 1311 | /*------------------------------------------------------------------------- 1312 | * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with 1313 | * the provided peci file descriptor. 1314 | *------------------------------------------------------------------------*/ 1315 | EPECIStatus peci_WrEndPointConfig_seq( 1316 | uint8_t target, uint8_t u8MsgType, uint8_t u8Seg, uint8_t u8Bus, 1317 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, 1318 | uint32_t DataVal, int peci_fd, uint8_t* cc) 1319 | { 1320 | // Default to domain ID 0 1321 | return peci_WrEndPointConfig_seq_dom( 1322 | target, 0, u8MsgType, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, DataLen, 1323 | DataVal, peci_fd, cc); 1324 | } 1325 | 1326 | /*------------------------------------------------------------------------- 1327 | * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with 1328 | * the provided peci file descriptor in the specified domain. 1329 | *------------------------------------------------------------------------*/ 1330 | EPECIStatus peci_WrEndPointConfig_seq_dom( 1331 | uint8_t target, uint8_t domainId, uint8_t u8MsgType, uint8_t u8Seg, 1332 | uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, 1333 | uint8_t DataLen, uint32_t DataVal, int peci_fd, uint8_t* cc) 1334 | { 1335 | struct peci_wr_end_pt_cfg_msg cmd = {0}; 1336 | EPECIStatus ret = PECI_CC_SUCCESS; 1337 | 1338 | if (cc == NULL) 1339 | { 1340 | return PECI_CC_INVALID_REQ; 1341 | } 1342 | 1343 | // The target address must be in the valid range 1344 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1345 | { 1346 | return PECI_CC_INVALID_REQ; 1347 | } 1348 | 1349 | // Per the PECI spec, the write length must be a byte, word, or dword 1350 | if (DataLen != 1 && DataLen != 2 && DataLen != 4) 1351 | { 1352 | return PECI_CC_INVALID_REQ; 1353 | } 1354 | 1355 | cmd.addr = target; 1356 | cmd.msg_type = u8MsgType; 1357 | cmd.params.pci_cfg.seg = u8Seg; 1358 | cmd.params.pci_cfg.bus = u8Bus; 1359 | cmd.params.pci_cfg.device = u8Device; 1360 | cmd.params.pci_cfg.function = u8Fcn; 1361 | cmd.params.pci_cfg.reg = u16Reg; 1362 | cmd.tx_len = DataLen; 1363 | cmd.value = DataVal; 1364 | cmd.domain_id = domainId; 1365 | 1366 | ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd); 1367 | *cc = cmd.cc; 1368 | 1369 | return ret; 1370 | } 1371 | 1372 | /*------------------------------------------------------------------------- 1373 | * This function provides write access to the EP local PCI configuration space 1374 | *------------------------------------------------------------------------*/ 1375 | EPECIStatus peci_WrEndPointPCIConfigLocal( 1376 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1377 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, 1378 | uint8_t* cc) 1379 | { 1380 | // Default to domain ID 0 1381 | return peci_WrEndPointPCIConfigLocal_dom( 1382 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, DataLen, DataVal, cc); 1383 | } 1384 | 1385 | /*------------------------------------------------------------------------- 1386 | * This function provides write access to the EP local PCI configuration space 1387 | * in the specified domain 1388 | *------------------------------------------------------------------------*/ 1389 | EPECIStatus peci_WrEndPointPCIConfigLocal_dom( 1390 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1391 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, 1392 | uint32_t DataVal, uint8_t* cc) 1393 | { 1394 | int peci_fd = -1; 1395 | EPECIStatus ret = PECI_CC_SUCCESS; 1396 | 1397 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1398 | { 1399 | return PECI_CC_DRIVER_ERR; 1400 | } 1401 | 1402 | ret = peci_WrEndPointConfig_seq_dom( 1403 | target, domainId, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg, u8Bus, u8Device, 1404 | u8Fcn, u16Reg, DataLen, DataVal, peci_fd, cc); 1405 | peci_Close(peci_fd); 1406 | return ret; 1407 | } 1408 | 1409 | /*------------------------------------------------------------------------- 1410 | * This function provides write access to the EP local PCI configuration space 1411 | *------------------------------------------------------------------------*/ 1412 | EPECIStatus peci_WrEndPointPCIConfig( 1413 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1414 | uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, uint32_t DataVal, 1415 | uint8_t* cc) 1416 | { 1417 | // Default to domain ID 0 1418 | return peci_WrEndPointPCIConfig_dom(target, 0, u8Seg, u8Bus, u8Device, 1419 | u8Fcn, u16Reg, DataLen, DataVal, cc); 1420 | } 1421 | 1422 | /*------------------------------------------------------------------------- 1423 | * This function provides write access to the EP local PCI configuration space 1424 | * in the specified domain 1425 | *------------------------------------------------------------------------*/ 1426 | EPECIStatus peci_WrEndPointPCIConfig_dom( 1427 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1428 | uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t DataLen, 1429 | uint32_t DataVal, uint8_t* cc) 1430 | { 1431 | int peci_fd = -1; 1432 | EPECIStatus ret = PECI_CC_SUCCESS; 1433 | 1434 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1435 | { 1436 | return PECI_CC_DRIVER_ERR; 1437 | } 1438 | ret = peci_WrEndPointConfig_seq_dom( 1439 | target, domainId, PECI_ENDPTCFG_TYPE_PCI, u8Seg, u8Bus, u8Device, u8Fcn, 1440 | u16Reg, DataLen, DataVal, peci_fd, cc); 1441 | peci_Close(peci_fd); 1442 | return ret; 1443 | } 1444 | 1445 | /*------------------------------------------------------------------------- 1446 | * This function provides write access to PCI MMIO space at 1447 | * the requested PCI configuration address. 1448 | *------------------------------------------------------------------------*/ 1449 | EPECIStatus peci_WrEndPointConfigMmio( 1450 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1451 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 1452 | uint8_t u8DataLen, uint64_t u64DataVal, uint8_t* cc) 1453 | { 1454 | // Default to domain ID 0 1455 | return peci_WrEndPointConfigMmio_dom( 1456 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset, 1457 | u8DataLen, u64DataVal, cc); 1458 | } 1459 | 1460 | /*------------------------------------------------------------------------- 1461 | * This function provides write access to PCI MMIO space at 1462 | * the requested PCI configuration address in the specified domain. 1463 | *------------------------------------------------------------------------*/ 1464 | EPECIStatus peci_WrEndPointConfigMmio_dom( 1465 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1466 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 1467 | uint64_t u64Offset, uint8_t u8DataLen, uint64_t u64DataVal, uint8_t* cc) 1468 | { 1469 | int peci_fd = -1; 1470 | EPECIStatus ret = PECI_CC_SUCCESS; 1471 | 1472 | if (cc == NULL) 1473 | { 1474 | return PECI_CC_INVALID_REQ; 1475 | } 1476 | 1477 | // The target address must be in the valid range 1478 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1479 | { 1480 | return PECI_CC_INVALID_REQ; 1481 | } 1482 | 1483 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1484 | { 1485 | return PECI_CC_DRIVER_ERR; 1486 | } 1487 | ret = peci_WrEndPointConfigMmio_seq_dom( 1488 | target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, 1489 | u64Offset, u8DataLen, u64DataVal, peci_fd, cc); 1490 | peci_Close(peci_fd); 1491 | return ret; 1492 | } 1493 | 1494 | /*------------------------------------------------------------------------- 1495 | * This function allows sequential WrEndPointConfig to PCI MMIO with the 1496 | * provided peci file descriptor. 1497 | *------------------------------------------------------------------------*/ 1498 | EPECIStatus peci_WrEndPointConfigMmio_seq( 1499 | uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device, 1500 | uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset, 1501 | uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, uint8_t* cc) 1502 | { 1503 | // Default to domain ID 0 1504 | return peci_WrEndPointConfigMmio_seq_dom( 1505 | target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset, 1506 | u8DataLen, u64DataVal, peci_fd, cc); 1507 | } 1508 | 1509 | /*------------------------------------------------------------------------- 1510 | * This function allows sequential WrEndPointConfig to PCI MMIO with the 1511 | * provided peci file descriptor in the specified domain. 1512 | *------------------------------------------------------------------------*/ 1513 | EPECIStatus peci_WrEndPointConfigMmio_seq_dom( 1514 | uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus, 1515 | uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, 1516 | uint64_t u64Offset, uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, 1517 | uint8_t* cc) 1518 | { 1519 | struct peci_wr_end_pt_cfg_msg cmd = {0}; 1520 | EPECIStatus ret = PECI_CC_SUCCESS; 1521 | 1522 | if (cc == NULL) 1523 | { 1524 | return PECI_CC_INVALID_REQ; 1525 | } 1526 | 1527 | // The target address must be in the valid range 1528 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1529 | { 1530 | return PECI_CC_INVALID_REQ; 1531 | } 1532 | 1533 | // Per the PECI spec, the read length must be a byte, word, dword, or qword 1534 | if (u8DataLen != 1 && u8DataLen != 2 && u8DataLen != 4 && u8DataLen != 8) 1535 | { 1536 | return PECI_CC_INVALID_REQ; 1537 | } 1538 | 1539 | cmd.addr = target; 1540 | cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO; 1541 | cmd.params.mmio.seg = u8Seg; 1542 | cmd.params.mmio.bus = u8Bus; 1543 | cmd.params.mmio.device = u8Device; 1544 | cmd.params.mmio.function = u8Fcn; 1545 | cmd.params.mmio.bar = u8Bar; 1546 | cmd.params.mmio.addr_type = u8AddrType; 1547 | cmd.params.mmio.offset = u64Offset; 1548 | cmd.tx_len = u8DataLen; 1549 | cmd.value = u64DataVal; 1550 | cmd.domain_id = domainId; 1551 | 1552 | ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd); 1553 | *cc = cmd.cc; 1554 | 1555 | return ret; 1556 | } 1557 | 1558 | /*------------------------------------------------------------------------- 1559 | * This function provides crashdump discovery data over PECI 1560 | *------------------------------------------------------------------------*/ 1561 | EPECIStatus peci_CrashDump_Discovery( 1562 | uint8_t target, uint8_t subopcode, uint8_t param0, uint16_t param1, 1563 | uint8_t param2, uint8_t u8ReadLen, uint8_t* pData, uint8_t* cc) 1564 | { 1565 | // Default to domain ID 0 1566 | return peci_CrashDump_Discovery_dom(target, 0, subopcode, param0, param1, 1567 | param2, u8ReadLen, pData, cc); 1568 | } 1569 | 1570 | /*------------------------------------------------------------------------- 1571 | * This function provides crashdump discovery data over PECI in the specified 1572 | * domain 1573 | *------------------------------------------------------------------------*/ 1574 | EPECIStatus peci_CrashDump_Discovery_dom( 1575 | uint8_t target, uint8_t domainId, uint8_t subopcode, uint8_t param0, 1576 | uint16_t param1, uint8_t param2, uint8_t u8ReadLen, uint8_t* pData, 1577 | uint8_t* cc) 1578 | { 1579 | int peci_fd = -1; 1580 | struct peci_crashdump_disc_msg cmd = {0}; 1581 | EPECIStatus ret = PECI_CC_SUCCESS; 1582 | 1583 | if (pData == NULL || cc == NULL) 1584 | { 1585 | return PECI_CC_INVALID_REQ; 1586 | } 1587 | 1588 | // The target address must be in the valid range 1589 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1590 | { 1591 | return PECI_CC_INVALID_REQ; 1592 | } 1593 | 1594 | // Per the PECI spec, the read length must be a byte, word, or qword 1595 | if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 8) 1596 | { 1597 | return PECI_CC_INVALID_REQ; 1598 | } 1599 | 1600 | // The PECI buffer must be large enough to hold the requested data 1601 | if (sizeof(cmd.data) < u8ReadLen) 1602 | { 1603 | return PECI_CC_INVALID_REQ; 1604 | } 1605 | 1606 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1607 | { 1608 | return PECI_CC_DRIVER_ERR; 1609 | } 1610 | 1611 | cmd.addr = target; 1612 | cmd.subopcode = subopcode; 1613 | cmd.param0 = param0; 1614 | cmd.param1 = param1; 1615 | cmd.param2 = param2; 1616 | cmd.rx_len = u8ReadLen; 1617 | cmd.domain_id = domainId; 1618 | 1619 | ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_DISC, (char*)&cmd, peci_fd); 1620 | *cc = cmd.cc; 1621 | if (ret == PECI_CC_SUCCESS) 1622 | { 1623 | memcpy(pData, cmd.data, u8ReadLen); 1624 | } 1625 | else 1626 | { 1627 | ret = PECI_CC_DRIVER_ERR; 1628 | } 1629 | 1630 | peci_Close(peci_fd); 1631 | return ret; 1632 | } 1633 | 1634 | /*------------------------------------------------------------------------- 1635 | * This function provides crashdump GetFrame data over PECI 1636 | *------------------------------------------------------------------------*/ 1637 | EPECIStatus peci_CrashDump_GetFrame( 1638 | uint8_t target, uint16_t param0, uint16_t param1, uint16_t param2, 1639 | uint8_t u8ReadLen, uint8_t* pData, uint8_t* cc) 1640 | { 1641 | // Default to domain ID 0 1642 | return peci_CrashDump_GetFrame_dom(target, 0, param0, param1, param2, 1643 | u8ReadLen, pData, cc); 1644 | } 1645 | 1646 | /*------------------------------------------------------------------------- 1647 | * This function provides crashdump GetFrame data over PECI in the specified 1648 | * domain 1649 | *------------------------------------------------------------------------*/ 1650 | EPECIStatus peci_CrashDump_GetFrame_dom( 1651 | uint8_t target, uint8_t domainId, uint16_t param0, uint16_t param1, 1652 | uint16_t param2, uint8_t u8ReadLen, uint8_t* pData, uint8_t* cc) 1653 | { 1654 | int peci_fd = -1; 1655 | struct peci_crashdump_get_frame_msg cmd = {0}; 1656 | EPECIStatus ret = PECI_CC_SUCCESS; 1657 | 1658 | if (pData == NULL || cc == NULL) 1659 | { 1660 | return PECI_CC_INVALID_REQ; 1661 | } 1662 | 1663 | // The target address must be in the valid range 1664 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1665 | { 1666 | return PECI_CC_INVALID_REQ; 1667 | } 1668 | 1669 | // Per the PECI spec, the read length must be a qword or dqword 1670 | if (u8ReadLen != 8 && u8ReadLen != 16) 1671 | { 1672 | return PECI_CC_INVALID_REQ; 1673 | } 1674 | 1675 | // The PECI buffer must be large enough to hold the requested data 1676 | if (sizeof(cmd.data) < u8ReadLen) 1677 | { 1678 | return PECI_CC_INVALID_REQ; 1679 | } 1680 | 1681 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1682 | { 1683 | return PECI_CC_DRIVER_ERR; 1684 | } 1685 | 1686 | cmd.addr = target; 1687 | cmd.param0 = param0; 1688 | cmd.param1 = param1; 1689 | cmd.param2 = param2; 1690 | cmd.rx_len = u8ReadLen; 1691 | cmd.domain_id = domainId; 1692 | 1693 | ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_GET_FRAME, (char*)&cmd, peci_fd); 1694 | *cc = cmd.cc; 1695 | if (ret == PECI_CC_SUCCESS) 1696 | { 1697 | memcpy(pData, cmd.data, u8ReadLen); 1698 | } 1699 | else 1700 | { 1701 | ret = PECI_CC_DRIVER_ERR; 1702 | } 1703 | 1704 | peci_Close(peci_fd); 1705 | return ret; 1706 | } 1707 | 1708 | /*------------------------------------------------------------------------- 1709 | * This function provides raw PECI command access 1710 | *------------------------------------------------------------------------*/ 1711 | EPECIStatus peci_raw(uint8_t target, uint8_t u8ReadLen, const uint8_t* pRawCmd, 1712 | const uint32_t cmdSize, uint8_t* pRawResp, 1713 | uint32_t respSize) 1714 | { 1715 | int peci_fd = -1; 1716 | if (u8ReadLen && pRawResp == NULL) 1717 | { 1718 | return PECI_CC_INVALID_REQ; 1719 | } 1720 | 1721 | // The target address must be in the valid range 1722 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1723 | { 1724 | return PECI_CC_INVALID_REQ; 1725 | } 1726 | 1727 | if (peci_Open(&peci_fd) != PECI_CC_SUCCESS) 1728 | { 1729 | return PECI_CC_DRIVER_ERR; 1730 | } 1731 | 1732 | EPECIStatus ret = peci_raw_seq(target, u8ReadLen, pRawCmd, cmdSize, 1733 | pRawResp, respSize, peci_fd); 1734 | peci_Close(peci_fd); 1735 | return ret; 1736 | } 1737 | 1738 | /*------------------------------------------------------------------------- 1739 | * This function provides sequential raw PECI command access 1740 | *------------------------------------------------------------------------*/ 1741 | EPECIStatus peci_raw_seq(uint8_t target, uint8_t u8ReadLen, 1742 | const uint8_t* pRawCmd, const uint32_t cmdSize, 1743 | uint8_t* pRawResp, uint32_t respSize, int peci_fd) 1744 | { 1745 | struct peci_xfer_msg cmd = {0}; 1746 | uint8_t u8TxBuf[PECI_BUFFER_SIZE] = {0}; 1747 | uint8_t u8RxBuf[PECI_BUFFER_SIZE] = {0}; 1748 | EPECIStatus ret = PECI_CC_SUCCESS; 1749 | 1750 | if (u8ReadLen && pRawResp == NULL) 1751 | { 1752 | return PECI_CC_INVALID_REQ; 1753 | } 1754 | 1755 | // The target address must be in the valid range 1756 | if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR) 1757 | { 1758 | return PECI_CC_INVALID_REQ; 1759 | } 1760 | 1761 | // Check for valid buffer sizes 1762 | if (cmdSize > PECI_BUFFER_SIZE || respSize < u8ReadLen || 1763 | u8ReadLen > 1764 | (PECI_BUFFER_SIZE - 1)) // response buffer is data + 1 status byte 1765 | { 1766 | return PECI_CC_INVALID_REQ; 1767 | } 1768 | 1769 | cmd.addr = target; 1770 | cmd.tx_len = (uint8_t)cmdSize; 1771 | cmd.rx_len = u8ReadLen; 1772 | 1773 | memcpy(u8TxBuf, pRawCmd, cmdSize); 1774 | 1775 | cmd.tx_buf = u8TxBuf; 1776 | cmd.rx_buf = u8RxBuf; 1777 | ret = HW_peci_issue_cmd(PECI_IOC_XFER, (char*)&cmd, peci_fd); 1778 | 1779 | if (ret == PECI_CC_SUCCESS || ret == PECI_CC_TIMEOUT) 1780 | { 1781 | memcpy(pRawResp, u8RxBuf, u8ReadLen); 1782 | } 1783 | 1784 | return ret; 1785 | } 1786 | 1787 | /*------------------------------------------------------------------------- 1788 | * This function returns the CPUID (Model and stepping) for the given PECI 1789 | * client address 1790 | *------------------------------------------------------------------------*/ 1791 | EPECIStatus peci_GetCPUID(const uint8_t clientAddr, CPUModel* cpuModel, 1792 | uint8_t* stepping, uint8_t* cc) 1793 | { 1794 | EPECIStatus ret = PECI_CC_SUCCESS; 1795 | uint32_t cpuid = 0; 1796 | 1797 | if (cpuModel == NULL || stepping == NULL || cc == NULL) 1798 | { 1799 | return PECI_CC_INVALID_REQ; 1800 | } 1801 | 1802 | // The client address must be in the valid range 1803 | if (clientAddr < MIN_CLIENT_ADDR || clientAddr > MAX_CLIENT_ADDR) 1804 | { 1805 | return PECI_CC_INVALID_REQ; 1806 | } 1807 | 1808 | if (peci_Ping(clientAddr) != PECI_CC_SUCCESS) 1809 | { 1810 | return PECI_CC_CPU_NOT_PRESENT; 1811 | } 1812 | 1813 | ret = 1814 | peci_RdPkgConfig(clientAddr, PECI_MBX_INDEX_CPU_ID, PECI_PKG_ID_CPU_ID, 1815 | sizeof(uint32_t), (uint8_t*)&cpuid, cc); 1816 | 1817 | // Separate out the model and stepping (bits 3:0) from the CPUID 1818 | *cpuModel = cpuid & 0xFFFFFFF0; 1819 | *stepping = (uint8_t)(cpuid & 0x0000000F); 1820 | return ret; 1821 | } 1822 | --------------------------------------------------------------------------------