├── ctrl_handler.h ├── emapi_handler.h ├── fmapi_handler.h ├── completion.bash ├── cmd_encoder.h ├── Makefile ├── README.md ├── emapi_handler.c ├── testbench.bash ├── ctrl_handler.c ├── LICENSE ├── options.h ├── main.c ├── cmd_encoder.c └── fmapi_handler.c /ctrl_handler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file ctrl_handler.h 4 | * 5 | * @brief Header file for methods to respond to MCTP Control Messages 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Mar 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | #ifndef _CTRL_HANDLER_H 16 | #define _CTRL_HANDLER_H 17 | 18 | /* mctp_state 19 | * mctp_msg 20 | */ 21 | #include 22 | 23 | /* MACROS ====================================================================*/ 24 | 25 | /* ENUMERATIONS ==============================================================*/ 26 | 27 | /* STRUCTS ===================================================================*/ 28 | 29 | /* PROTOTYPES ================================================================*/ 30 | 31 | int ctrl_handler(struct mctp *m, struct mctp_msg *mm); 32 | 33 | /* GLOBAL VARIABLES ==========================================================*/ 34 | 35 | #endif //_CTRL_HANDLER_H 36 | -------------------------------------------------------------------------------- /emapi_handler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file emapi_handler.h 4 | * 5 | * @brief Header file for methods to respond to CXL Emulator API commands 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Mar 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | #ifndef _EMAPI_HANDLER_H 16 | #define _EMAPI_HANDLER_H 17 | 18 | /* mctp_state 19 | * mctp_msg 20 | */ 21 | #include 22 | 23 | /* MACROS ====================================================================*/ 24 | 25 | /* ENUMERATIONS ==============================================================*/ 26 | 27 | /* STRUCTS ===================================================================*/ 28 | 29 | /* PROTOTYPES ================================================================*/ 30 | 31 | int emapi_handler(struct mctp *m, struct mctp_msg *mm); 32 | 33 | /* GLOBAL VARIABLES ==========================================================*/ 34 | 35 | #endif //_EMAPI_HANDLER_H 36 | -------------------------------------------------------------------------------- /fmapi_handler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file fmapi_handler.h 4 | * 5 | * @brief Header file for methods to respond to FM API commands 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Jan 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | #ifndef _FMAPI_HANDLER_H 16 | #define _FMAPI_HANDLER_H 17 | 18 | /* mctp_state 19 | * mctp_msg 20 | */ 21 | #include 22 | 23 | /* MACROS ====================================================================*/ 24 | 25 | /* ENUMERATIONS ==============================================================*/ 26 | 27 | /* STRUCTS ===================================================================*/ 28 | 29 | /* PROTOTYPES ================================================================*/ 30 | 31 | int fmapi_handler(struct mctp *m, struct mctp_msg *mm, struct mctp_msg *req); 32 | int fmapi_update(struct mctp *m, struct mctp_action *ma); 33 | 34 | /* GLOBAL VARIABLES ==========================================================*/ 35 | 36 | extern struct cxl_switch *cxls; 37 | 38 | #endif //_FMAPI_HANDLER_H 39 | -------------------------------------------------------------------------------- /completion.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env /bin/bash 2 | 3 | _jack_completions() 4 | { 5 | local cur prev pprev 6 | 7 | cur=${COMP_WORDS[COMP_CWORD]} 8 | prev=${COMP_WORDS[COMP_CWORD-1]} 9 | 10 | if [ $COMP_CWORD -eq 1 ] ; then 11 | 12 | COMPREPLY=($(compgen -W "aer ld mctp port set show" -- $cur)) 13 | 14 | elif [ $COMP_CWORD -eq 2 ] ; then 15 | 16 | case $prev in 17 | aer) ;; 18 | ld) COMPREPLY=($(compgen -W "config mem" -- $cur)) ;; 19 | mctp) ;; 20 | port) COMPREPLY=($(compgen -W "bind config connect control disconnect unbind" -- $cur)) ;; 21 | set) COMPREPLY=($(compgen -W "ld limit qos" -- $cur)) ;; 22 | show) COMPREPLY=($(compgen -W "bos identity ld limit port qos switch vcs" -- $cur)) ;; 23 | *) ;; 24 | esac 25 | 26 | elif [ $COMP_CWORD -eq 3 ] ; then 27 | 28 | pprev=${COMP_WORDS[COMP_CWORD-2]} 29 | 30 | if [ $pprev = "set" ] ; then 31 | case $prev in 32 | ld) COMPREPLY=($(compgen -W "allocations" -- $cur)) ;; 33 | qos) COMPREPLY=($(compgen -W "allocated control limit" -- $cur)) ;; 34 | *) ;; 35 | esac 36 | elif [ $pprev = "show" ] ; then 37 | case $prev in 38 | ld) COMPREPLY=($(compgen -W "allocations info" -- $cur)) ;; 39 | qos) COMPREPLY=($(compgen -W "allocated control limit status" -- $cur)) ;; 40 | *) ;; 41 | esac 42 | fi 43 | fi 44 | } 45 | complete -F _jack_completions jack 46 | 47 | -------------------------------------------------------------------------------- /cmd_encoder.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file cmd_encoder.h 4 | * 5 | * @brief Header file for methods to convert the CLI parameters into an 6 | * FM API Request 7 | * 8 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 9 | * 10 | * @date Mar 2024 11 | * @author Barrett Edwards 12 | * 13 | */ 14 | /* INCLUDES ==================================================================*/ 15 | 16 | #ifndef _CMD_ENCODER_H 17 | #define _CMD_ENCODER_H 18 | 19 | /* mctp_state 20 | * mctp_msg 21 | */ 22 | #include 23 | 24 | /* MACROS ====================================================================*/ 25 | 26 | /* ENUMERATIONS ==============================================================*/ 27 | 28 | /* STRUCTS ===================================================================*/ 29 | 30 | /* PROTOTYPES ================================================================*/ 31 | 32 | struct mctp_action *submit_ctrl( 33 | struct mctp *m, 34 | struct mctp_ctrl_msg *msg, 35 | int retry, 36 | void *user_data, 37 | void (*fn_submitted)(struct mctp *m, struct mctp_action *a), 38 | void (*fn_completed)(struct mctp *m, struct mctp_action *a), 39 | void (*fn_failed)(struct mctp *m, struct mctp_action *a) 40 | ); 41 | 42 | struct mctp_action *submit_emapi( 43 | struct mctp *m, 44 | struct emapi_msg *msg, 45 | int retry, 46 | void *user_data, 47 | void (*fn_submitted)(struct mctp *m, struct mctp_action *a), 48 | void (*fn_completed)(struct mctp *m, struct mctp_action *a), 49 | void (*fn_failed)(struct mctp *m, struct mctp_action *a) 50 | ); 51 | 52 | struct mctp_action *submit_fmapi( 53 | struct mctp *m, 54 | struct fmapi_msg *fm, 55 | int retry, 56 | void *user_data, 57 | void (*fn_submitted)(struct mctp *m, struct mctp_action *a), 58 | void (*fn_completed)(struct mctp *m, struct mctp_action *a), 59 | void (*fn_failed)(struct mctp *m, struct mctp_action *a) 60 | ); 61 | 62 | struct mctp_action *submit_cli_request(struct mctp *m, void *user_data); 63 | 64 | /* GLOBAL VARIABLES ==========================================================*/ 65 | 66 | #endif //_CMD_ENCODER_H 67 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # ****************************************************************************** 3 | # 4 | # @file Makefile 5 | # 6 | # @brief Makefile for Jack CXL Fabric Management CLI Tool 7 | # 8 | # @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 9 | # 10 | # @date Mar 2024 11 | # @author Barrett Edwards 12 | # 13 | # ****************************************************************************** 14 | 15 | CC=gcc 16 | CFLAGS?= -g3 -O0 -Wall -Wextra 17 | MACROS?=-D JACK_VERBOSE 18 | INCLUDE_DIR?=/usr/local/include 19 | LIB_DIR?=/usr/local/lib 20 | LOCAL_INCLUDE_DIR?=./include 21 | LOCAL_LIB_DIR?=./lib 22 | INCLUDE_PATH=-I $(LOCAL_INCLUDE_DIR) -I $(INCLUDE_DIR) -I /usr/include/glib-2.0 -I /usr/lib/`uname -m`-linux-gnu/glib-2.0/include/ -I /usr/lib64/glib-2.0/include 23 | LIB_PATH=-L $(LOCAL_LIB_DIR) -L $(LIB_DIR) 24 | LIBS=-l mctp -l fmapi -l emapi -l ptrqueue -l arrayutils -l uuid -l timeutils -l cxlstate -l pciutils -l pci 25 | TARGET=jack 26 | 27 | all: $(TARGET) 28 | 29 | $(TARGET): main.c options.o ctrl_handler.o emapi_handler.o fmapi_handler.o cmd_encoder.o 30 | $(CC) $^ $(CFLAGS) $(MACROS) $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) -o $@ 31 | 32 | cmd_encoder.o: cmd_encoder.c cmd_encoder.h 33 | $(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@ 34 | 35 | fmapi_handler.o: fmapi_handler.c fmapi_handler.h 36 | $(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@ 37 | 38 | emapi_handler.o: emapi_handler.c emapi_handler.h 39 | $(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@ 40 | 41 | ctrl_handler.o: ctrl_handler.c ctrl_handler.h 42 | $(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@ 43 | 44 | options.o: options.c options.h 45 | $(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@ 46 | 47 | clean: 48 | rm -rf ./*.o ./*.a $(TARGET) 49 | 50 | doc: 51 | doxygen 52 | 53 | install: jack 54 | sudo cp $(TARGET) /usr/local/bin/ 55 | sudo cp completion.bash /etc/bash_completion.d/$(TARGET)-completion.bash 56 | 57 | uninstall: 58 | sudo rm /usr/local/bin/$(TARGET) 59 | sudo rm /etc/bash_completion.d/$(TARGET)-completion.bash 60 | 61 | # List all non file name targets as PHONY 62 | .PHONY: all clean doc install uninstall 63 | 64 | # Variables 65 | # $^ Will expand to be all the sensitivity list 66 | # $< Will expand to be the frist file in sensitivity list 67 | # $@ Will expand to be the target name (the left side of the ":" ) 68 | # -c gcc will compile but not try and link 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | Jack is a CLI tool that implements the CXL 2.0 Fabric Management API 4 | specification. It is intended to be used to configure and monitor CXL 5 | compliant hardware devices such as switches, accelerators or memory controllers. 6 | 7 | # Supported Operating System Versions 8 | 9 | - Ubuntu 23.10 10 | - Fedora 38, 39 11 | 12 | > Note: Ubuntu 22.04 is not supported. This is due to some newer PCI features that 13 | > are missing from the 5.15 Linux kernel that ships with Ubuntu 22.04. 14 | 15 | # Building 16 | 17 | 1. Install OS libraries 18 | 19 | Install the following build packages to compile the software on the following 20 | operating systems. 21 | 22 | **Ubuntu:** 23 | 24 | ```bash 25 | apt install build-essential libglib2.0-dev libyaml-dev libpci-dev 26 | ``` 27 | 28 | **Fedora:** 29 | 30 | ```bash 31 | ``` 32 | 33 | 2. Build Dependencies 34 | 35 | To clone and build dependencies run: 36 | 37 | ```bash 38 | ./builddeps.bash 39 | ``` 40 | 41 | 3. Build 42 | 43 | After building the required dependencies run: 44 | 45 | ```bash 46 | make 47 | ``` 48 | 49 | # Usage 50 | 51 | Jack connects to a target device using MCTP over TCP. When using Jack with an 52 | endpoint such as 53 | [CSE (CXL Switch Emulator)](https://github.com/JackrabbitLabs/cse), the user 54 | first starts the CSE application using a config file that defines a 55 | virtualized CXL switch environment with the following command. 56 | 57 | ```bash 58 | cse -lc config.yaml 59 | ``` 60 | 61 | Once the target endpoint is running, Jack can be used to query or configure 62 | the CXL endpoint. 63 | 64 | # Example Commands 65 | 66 | To obtain identity information about the endpoint: 67 | 68 | ```bash 69 | jack show id 70 | ``` 71 | 72 | To obtain information about the capabilities of the endpoint: 73 | 74 | ```bash 75 | jack show switch 76 | ``` 77 | 78 | To show the status of the ports of the endpoint use `show port`. This displays 79 | the devices that are connected to the endpoint. 80 | 81 | ```bash 82 | jack show port 83 | ``` 84 | 85 | To show information about what ports are connected to a Virtual CXL Switch 86 | (VCS). 87 | 88 | ```bash 89 | jack show vcs 0 90 | ``` 91 | 92 | To unbind a port (or a Logical Device) from a VCS: 93 | 94 | ```bash 95 | jack port unbind -c 0 -b 4 96 | ``` 97 | 98 | To bind a port (or a Logical Device) to a VCS: 99 | 100 | ```bash 101 | jack port bind -p 4 -l 0 -c 0 -b 4 102 | ``` 103 | 104 | -------------------------------------------------------------------------------- /emapi_handler.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file emapi_handler.c 4 | * 5 | * @brief Code file to handle EM API messages 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Mar 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | /* gettid() 16 | */ 17 | #define _GNU_SOURCE 18 | 19 | #include 20 | /* printf() 21 | */ 22 | #include 23 | 24 | /* memset() 25 | */ 26 | #include 27 | 28 | #include 29 | 30 | /* autl_prnt_buf() 31 | */ 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | /* mctp_init() 40 | * mctp_set_mh() 41 | * mctp_run() 42 | */ 43 | #include 44 | 45 | #include "options.h" 46 | 47 | /* MACROS ====================================================================*/ 48 | 49 | #ifdef JACK_VERBOSE 50 | #define INIT unsigned step = 0; 51 | #define ENTER if (opts[CLOP_VERBOSITY].u64 & JKVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__); 52 | #define STEP step++; if (opts[CLOP_VERBOSITY].u64 & JKVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step); 53 | #define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & JKVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i); 54 | #define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & JKVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i); 55 | #define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & JKVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc); 56 | #else 57 | #define ENTER 58 | #define EXIT(rc) 59 | #define STEP 60 | #define HEX32(m, i) 61 | #define INT32(m, i) 62 | #define INIT 63 | #endif // JACK_VERBOSE 64 | 65 | /* ENUMERATIONS ==============================================================*/ 66 | 67 | /* STRUCTS ===================================================================*/ 68 | 69 | /* PROTOTYPES ================================================================*/ 70 | 71 | /* GLOBAL VARIABLES ==========================================================*/ 72 | 73 | /* FUNCTIONS =================================================================*/ 74 | 75 | /** 76 | * Handler for all CXL Emulator API Opcodes 77 | * 78 | * @return 0 upon success, 1 otherwise 79 | * 80 | * STEPS 81 | * 1: Set buffer pointers 82 | * 2: Deserialize Header 83 | * 3: Verify Response 84 | * 4: Handle Opcode 85 | */ 86 | int emapi_handler(struct mctp *m, struct mctp_msg *mm) 87 | { 88 | INIT 89 | struct emapi_msg msg; 90 | struct emapi_buf *buf; 91 | int rv; 92 | 93 | ENTER 94 | 95 | // Initialize variables 96 | rv = 1; 97 | 98 | STEP // 1: Set buffer pointers 99 | buf = (struct emapi_buf*) mm->payload; 100 | 101 | STEP // 2: Deserialize Header 102 | if ( emapi_deserialize(&msg.hdr, buf->hdr, EMOB_HDR, NULL) == 0 ) 103 | goto end; 104 | 105 | STEP // 3: Verify response 106 | 107 | // Verify EM API Message Type 108 | if (msg.hdr.type != EMMT_RSP) 109 | goto end; 110 | 111 | // Check the return code 112 | if (msg.hdr.rc != EMRC_SUCCESS && msg.hdr.rc != EMRC_BACKGROUND_OP_STARTED) 113 | { 114 | printf("Error: %s\n", emrc(msg.hdr.rc)); 115 | rv = msg.hdr.rc; 116 | goto end; 117 | } 118 | 119 | STEP // 4: Handle Opcode 120 | HEX32("Opcode", msg.hdr.opcode); 121 | switch(msg.hdr.opcode) 122 | { 123 | case EMOP_EVENT: // 0x00 124 | break; 125 | 126 | case EMOP_LIST_DEV: // 0x01 127 | { 128 | unsigned i, num; 129 | 130 | num = msg.hdr.a; 131 | emapi_deserialize(&msg.obj, buf->payload, EMOB_LIST_DEV, &num); 132 | 133 | for ( i = 0 ; i < num ; i++ ) 134 | printf("%3d: %s\n", msg.obj.dev[i].id, msg.obj.dev[i].name); 135 | } 136 | break; 137 | 138 | case EMOP_CONN_DEV: // 0x02 139 | break; 140 | 141 | case EMOP_DISCON_DEV: // 0x03 142 | break; 143 | 144 | default: 145 | goto end; 146 | } 147 | 148 | rv = 0; 149 | 150 | end: 151 | 152 | // Return mctp_msg to free pool 153 | pq_push(m->msgs, mm); 154 | 155 | EXIT(rv) 156 | 157 | return rv; 158 | } 159 | -------------------------------------------------------------------------------- /testbench.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo -e \\n------------------------------------------------------------------------------ 4 | echo -e 1: Show help menu for each command \\n 5 | 6 | set -x 7 | jack 8 | 9 | jack aer 10 | jack ld 11 | jack ld cfg 12 | jack ld mem 13 | jack mctp 14 | jack port 15 | jack port bind 16 | jack port config 17 | jack port control 18 | jack port unbind 19 | jack set ld 20 | jack set ld allocations 21 | jack set qos 22 | jack set qos allocated 23 | jack set qos control 24 | jack set qos limit 25 | jack show 26 | jack show ld 27 | jack show ld allocations 28 | jack show ld info 29 | jack show port -h 30 | jack show qos 31 | jack show qos allocated 32 | jack show qos control 33 | jack show qos limit 34 | jack show qos status 35 | jack show switch -h 36 | jack show vcs -h 37 | set +x 38 | 39 | echo -e \\n------------------------------------------------------------------------------ 40 | echo -e 2: Show Commands \\n 41 | 42 | set -x 43 | jack show id 44 | jack show bos 45 | jack show limit 46 | jack show switch 47 | jack show port -a 48 | jack show vcs -a 49 | jack show ld info -p 1 50 | jack show ld allocations -p 1 51 | jack show qos status -p 1 52 | jack show qos control -p 1 53 | jack show qos allocated -p 1 54 | jack show qos limit -p 1 55 | set +x 56 | 57 | echo -e \\n------------------------------------------------------------------------------ 58 | echo -e 3: Port CXL.io CFG commands \\n 59 | 60 | set -x 61 | jack port config -p 0 -r 0 -e 0 -f 0xF 62 | jack port config -p 0 -r 0 -e 0 -f 0xF -w --data 0xa1a2a3a4 63 | jack port config -p 0 -r 0 -e 0 -f 0xF 64 | set +x 65 | 66 | echo -e \\n------------------------------------------------------------------------------ 67 | echo -e 3: LD CXL.io CFG commands \\n 68 | 69 | set -x 70 | jack ld config -p 1 -l 0 -r 0 -e 0 -f 0xF 71 | jack ld config -p 1 -l 0 -r 0 -e 0 -f 0xF -w --data 0xa1a2a3a4 72 | jack ld config -p 1 -l 0 -r 0 -e 0 -f 0xF 73 | set +x 74 | 75 | echo -e \\n------------------------------------------------------------------------------ 76 | echo -e 4: Port Control \\n 77 | 78 | set -x 79 | jack show port -p 1 80 | jack port ctrl -p 1 --assert-perst 81 | jack show port -p 1 82 | jack port ctrl -p 1 --deassert-perst 83 | jack show port -p 1 84 | set +x 85 | 86 | echo -e \\n------------------------------------------------------------------------------ 87 | echo -e 5: Port Bind/Unbind \\n 88 | 89 | set -x 90 | jack show port -p 1 91 | jack port bind -p 1 -l 0 -c 0 -b 0 92 | jack show port -p 1 93 | jack show vcs -c 0 94 | jack port unbind -c 0 -b 0 95 | jack show port -p 1 96 | jack show vcs -c 0 97 | set +x 98 | 99 | echo -e \\n------------------------------------------------------------------------------ 100 | echo -e 6: Set LD Allocations \\n 101 | 102 | set -x 103 | jack show ld allocations -p 1 104 | jack set ld allocations -p 1 --range1 0,1,2,3,4,5,6,7,8,9,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f --range2 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f 105 | jack show ld allocations -p 1 106 | set +x 107 | 108 | echo -e \\n------------------------------------------------------------------------------ 109 | echo -e 7: Set QoS Allocated \\n 110 | 111 | set -x 112 | jack show qos allocated -p 1 113 | jack set qos allocated -p 1 -f 0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf 114 | jack show qos allocated -p 1 115 | set +x 116 | 117 | echo -e \\n------------------------------------------------------------------------------ 118 | echo -e 8: Set QoS Limit \\n 119 | 120 | set -x 121 | jack show qos limit -p 1 122 | jack set qos limit -p 1 -f 0xf,0xe,0xd,0xc,0xb,0xa,9,8,7,6,5,4,3,2,1,0 123 | jack show qos limit -p 1 124 | set +x 125 | 126 | echo -e \\n------------------------------------------------------------------------------ 127 | echo -e 9: Set QoS Control \\n 128 | 129 | set -x 130 | jack show qos control -p 1 131 | jack set qos control -p 1 -m 52 -s 63 -k 18 -q 21 -i 74 132 | jack show qos control -p 1 133 | set +x 134 | 135 | echo -e \\n------------------------------------------------------------------------------ 136 | echo -e 10: AER \\n 137 | 138 | set -x 139 | jack aer -c 0 -b 0 -e 0xc1c2c3c4 -t 000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F 140 | set +x 141 | 142 | echo -e \\n------------------------------------------------------------------------------ 143 | echo -e 11: MCTP \\n 144 | 145 | set -x 146 | jack mctp --get-eid 147 | jack mctp --get-uuid 148 | jack mctp --get-type 149 | jack mctp --get-ver 0x7 150 | set +x 151 | 152 | -------------------------------------------------------------------------------- /ctrl_handler.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file ctrl_handler.c 4 | * 5 | * @brief Code file to repond to MCTP Control Messages 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Mar 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | /* gettid() 16 | */ 17 | #define _GNU_SOURCE 18 | 19 | #include 20 | 21 | /* printf() 22 | */ 23 | #include 24 | 25 | /* memset() 26 | */ 27 | #include 28 | 29 | #include 30 | 31 | /* autl_prnt_buf() 32 | */ 33 | #include 34 | 35 | #include 36 | 37 | /* struct mctp 38 | * struct mctp_msg 39 | * struct mctp_ctrl_msg 40 | */ 41 | #include 42 | 43 | #include "ctrl_handler.h" 44 | #include "options.h" 45 | 46 | /* MACROS ====================================================================*/ 47 | 48 | #ifdef JACK_VERBOSE 49 | #define INIT unsigned step = 0; 50 | #define ENTER if (m->verbose & MCTP_VERBOSE_THREADS) printf("%d:%s Enter\n", gettid(), __FUNCTION__); 51 | #define STEP step++; if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step); 52 | #define HEX32(k, i) if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, k, i); 53 | #define INT32(k, i) if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, k, i); 54 | #define ERR32(k, i) if (m->verbose & MCTP_VERBOSE_ERROR) printf("%d:%s STEP: %u ERR: %s: %d\n", gettid(), __FUNCTION__, step, k, i); 55 | #define EXIT(rc) if (m->verbose & MCTP_VERBOSE_THREADS) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc); 56 | #else 57 | #define INIT 58 | #define ENTER 59 | #define STEP 60 | #define HEX32(k, i) 61 | #define INT32(k, i) 62 | #define ERR32(k, i) 63 | #define EXIT(rc) 64 | #endif 65 | 66 | /* ENUMERATIONS ==============================================================*/ 67 | 68 | /* STRUCTS ===================================================================*/ 69 | 70 | /* PROTOTYPES ================================================================*/ 71 | 72 | /* GLOBAL VARIABLES ==========================================================*/ 73 | 74 | /* FUNCTIONS =================================================================*/ 75 | 76 | /** 77 | * Handle Responses that are MCTP Control Messages 78 | * 79 | * @return 0 upon success. Non zero otherwise. 80 | * 81 | * STEPS 82 | * 1: Set payload pointers 83 | * 2: Validate Response 84 | * 3: Handle opcode 85 | */ 86 | int ctrl_handler(struct mctp *m, struct mctp_msg *mm) 87 | { 88 | INIT 89 | struct mctp_ctrl_msg *msg; 90 | int rv; 91 | 92 | ENTER 93 | 94 | // Initialize Variables 95 | rv = 1; 96 | 97 | STEP // 1: Set payload pointers 98 | msg = (struct mctp_ctrl_msg*) mm->payload; 99 | 100 | STEP // 2: Validate Response 101 | 102 | // Check MCTP reequest bit 103 | 104 | // Check MCTP Instance ID 105 | 106 | // Check MCTP Completion Code 107 | if (msg->obj.get_eid_rsp.comp_code != MCCC_SUCCESS) 108 | { 109 | printf("Error: MCTP Control Command %s Failed: %s\n", mccm(msg->hdr.cmd), mccc(msg->obj.get_eid_rsp.comp_code)); 110 | goto end; 111 | } 112 | 113 | STEP // 3: Handle opcode 114 | switch(msg->hdr.cmd) 115 | { 116 | case MCCM_RESERVED: 117 | break; 118 | 119 | case MCCM_SET_ENDPOINT_ID: 120 | { 121 | printf("EID: 0x%02x\n", msg->obj.set_eid_rsp.eid); 122 | } 123 | break; 124 | 125 | case MCCM_GET_ENDPOINT_ID: 126 | { 127 | printf("EID: 0x%02x\n", msg->obj.get_eid_rsp.eid); 128 | } 129 | break; 130 | 131 | case MCCM_GET_ENDPOINT_UUID: 132 | { 133 | char buf[37]; 134 | 135 | memset(buf, 0, 37); 136 | 137 | // Convert UUID into String for printing 138 | uuid_unparse(msg->obj.get_uuid_rsp.uuid, buf); 139 | 140 | printf("MCTP UUID: %s\n", buf); 141 | } 142 | break; 143 | 144 | case MCCM_GET_VERSION_SUPPORT: 145 | { 146 | struct mctp_ver *mv; 147 | char buf[11]; 148 | 149 | for ( int i = 0 ; i < msg->obj.get_ver_rsp.count ; i++) 150 | { 151 | mv = &msg->obj.get_ver_rsp.versions[i]; 152 | 153 | rv = mctp_sprnt_ver(buf, (struct mctp_version*) mv); 154 | 155 | printf("[%02d] %s\n", i, buf); 156 | } 157 | } 158 | break; 159 | 160 | case MCCM_GET_MESSAGE_TYPE_SUPPORT: 161 | { 162 | for ( int i = 0 ; i < msg->obj.get_msg_type_rsp.count ; i++) 163 | printf("%02d: %d - %s\n", i, msg->obj.get_msg_type_rsp.list[i], mcmt(msg->obj.get_msg_type_rsp.list[i])); 164 | } 165 | break; 166 | 167 | case MCCM_GET_VENDOR_MESSAGE_SUPPORT: 168 | case MCCM_RESOLVE_ENDPOINT_ID: 169 | case MCCM_ALLOCATE_ENDPOINT_IDS: 170 | case MCCM_ROUTING_INFO_UPDATE: 171 | case MCCM_GET_ROUTING_TABLE_ENTRIES: 172 | case MCCM_PREPARE_ENDPOINT_DISCOVERY: 173 | case MCCM_ENDPOINT_DISCOVERY: 174 | case MCCM_DISCOVERY_NOTIFY: 175 | case MCCM_GET_NETWORK_ID: 176 | case MCCM_QUERY_HOP: 177 | case MCCM_RESOLVE_UUID: 178 | case MCCM_QUERY_RATE_LIMIT: 179 | case MCCM_REQUEST_TX_RATE_LIMIT: 180 | case MCCM_UPDATE_RATE_LIMIT: 181 | case MCCM_QUERY_SUPPORTED_INTERFACES: 182 | default: goto end; 183 | } 184 | 185 | rv = 0; 186 | 187 | end: 188 | 189 | // Return mctp_msg to free pool 190 | pq_push(m->msgs, mm); 191 | 192 | EXIT(rv) 193 | 194 | return rv; 195 | } 196 | 197 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 10 | 11 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 12 | 13 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 14 | 15 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 16 | 17 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 18 | 19 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 20 | 21 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 22 | 23 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 24 | 25 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 26 | 27 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 28 | 29 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 30 | 31 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 32 | 33 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 34 | 35 | (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and 36 | 37 | (b) You must cause any modified files to carry prominent notices stating that You changed the files; and 38 | 39 | (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 40 | 41 | (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 42 | 43 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 44 | 45 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 46 | 47 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 48 | 49 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 50 | 51 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 52 | 53 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 54 | 55 | END OF TERMS AND CONDITIONS 56 | 57 | APPENDIX: How to apply the Apache License to your work. 58 | 59 | To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. 60 | 61 | Copyright 2024 Jackrabbit-Founders-LLC 62 | 63 | Licensed under the Apache License, Version 2.0 (the "License"); 64 | you may not use this file except in compliance with the License. 65 | You may obtain a copy of the License at 66 | 67 | http://www.apache.org/licenses/LICENSE-2.0 68 | 69 | Unless required by applicable law or agreed to in writing, software 70 | distributed under the License is distributed on an "AS IS" BASIS, 71 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 72 | See the License for the specific language governing permissions and 73 | limitations under the License. 74 | -------------------------------------------------------------------------------- /options.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file options.h 4 | * 5 | * @brief Header file for CXL Fabric Management CLI options 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Jan 2024 10 | * @author Barrett Edwards 11 | * 12 | * Macro / Enumeration Prefixes (CL) 13 | * CLAP - CLI Options Parsers Enumeration (AP) 14 | * CLCM - CLI Command Opcod (CM) 15 | * CLMR - CLI Macros (MR) 16 | * CLOP - CLI Option (CL) 17 | * CLPC - Physical Port Control Opcodes (PC) 18 | * CLPU - Port Unbind Mode Options (PU) 19 | * 20 | * Standard key mapping 21 | * -h --help Display Help 22 | * -T --tcp-port Server TCP Port 23 | * -V --verbosity Set Verbosity Flag 24 | * -X --verbosity-hex Set all Verbosity Flags with hex value 25 | * -p --ppid Physical Port ID 26 | * -c --vcsid Virtual CXL Switch ID 27 | * -b --vppbid Virtual PCIe-to-PCIe Bridge ID 28 | * -a --all All of collection 29 | * -l --ldid LD-ID (for MLD devices) 30 | * -w --write Perform a Write transaction 31 | * -n --length Length 32 | * -o --offset Memory Offset 33 | * --data Write Data (up to 4 bytes) 34 | * --infile Filename for input data 35 | * --outfile Filename for output data 36 | * 37 | * Non char key mapping 38 | * 701 - usage 39 | * 702 - version 40 | * 703 - data 41 | * 704 - infile 42 | * 705 - outfile 43 | * 706 - print-options 44 | */ 45 | #ifndef _OPTIONS_H 46 | #define _OPTIONS_H 47 | 48 | /* INCLUDES ==================================================================*/ 49 | 50 | /* __u8 51 | * __u15 52 | * __u32 53 | * __u64 54 | * __s32 55 | */ 56 | #include 57 | 58 | /* MACROS ====================================================================*/ 59 | 60 | /** 61 | * CLI Macros (MR) 62 | * 63 | * These are values that don't belong in an enumeration 64 | */ 65 | #define CLMR_MAX_LD_MEM_LEN 4096 66 | #define CLMR_MAX_LD 16 67 | #define CLMR_HELP_COLUMN 30 68 | #define CLMR_MAX_HELP_WIDTH 100 69 | #define CLMR_MAX_NAME_LEN 64 70 | #define CLMR_AER_HEADER_LEN 32 71 | 72 | #define DEFAULT_SERVER_PORT 2508 73 | 74 | /* ENUMERATIONS ==============================================================*/ 75 | 76 | /** 77 | * Verbosity Options (VO) 78 | */ 79 | enum _JKVO 80 | { 81 | JKVO_GENERAL = 0, 82 | JKVO_CALLSTACK = 1, 83 | JKVO_STEPS = 2, 84 | JKVO_MAX 85 | }; 86 | 87 | /** 88 | * Verbosity Bitfield Index (VB) 89 | */ 90 | enum _JKVB 91 | { 92 | JKVB_GENERAL = (0x01 << 0), 93 | JKVB_CALLSTACK = (0x01 << 1), 94 | JKVB_STEPS = (0x01 << 2), 95 | }; 96 | 97 | /** 98 | * CLI Options Parsers Enumeration (AP) 99 | * 100 | * This enumeration identifies each argp parser. It is used to print options 101 | */ 102 | enum _CLAP 103 | { 104 | CLAP_MAIN = 0, 105 | CLAP_MCTP = 1, 106 | CLAP_SHOW = 2, 107 | CLAP_PORT = 3, 108 | CLAP_SET = 4, 109 | CLAP_LD = 5, 110 | CLAP_AER = 6, 111 | CLAP_SHOW_SWITCH = 7, 112 | CLAP_SHOW_PORT = 8, 113 | CLAP_SHOW_VCS = 9, 114 | CLAP_SHOW_QOS = 10, 115 | CLAP_SHOW_LD = 11, 116 | CLAP_PORT_BIND = 12, 117 | CLAP_PORT_UNBIND = 13, 118 | CLAP_PORT_CONFIG = 14, 119 | CLAP_PORT_CTRL = 15, 120 | CLAP_SET_LD = 16, 121 | CLAP_SET_QOS = 17, 122 | CLAP_LD_CONFIG = 18, 123 | CLAP_LD_MEM = 19, 124 | CLAP_SHOW_QOS_ALLOCATED = 20, 125 | CLAP_SHOW_QOS_CONTROL = 21, 126 | CLAP_SHOW_QOS_LIMIT = 22, 127 | CLAP_SHOW_QOS_STATUS = 23, 128 | CLAP_SHOW_LD_ALLOCATIONS = 24, 129 | CLAP_SHOW_LD_INFO = 25, 130 | CLAP_SET_LD_ALLOCATIONS = 26, 131 | CLAP_SET_QOS_ALLOCATED = 27, 132 | CLAP_SET_QOS_CONTROL = 28, 133 | CLAP_SET_QOS_LIMIT = 29, 134 | CLAP_SHOW_DEV = 30, 135 | CLAP_PORT_CONN = 31, 136 | CLAP_PORT_DISCONN = 32, 137 | CLAP_SHOW_IDENTITY = 33, 138 | CLAP_SHOW_MSG_LIMIT = 34, 139 | CLAP_SET_MSG_LIMIT = 35, 140 | CLAP_SHOW_BOS = 36, 141 | 142 | CLAP_MAX 143 | }; 144 | 145 | /** 146 | * CLI Command Opcode (CM) 147 | */ 148 | enum _CLCM 149 | { 150 | CLCM_NULL = 0, 151 | 152 | CLCM_AER = 1, 153 | 154 | CLCM_PORT_BIND = 2, 155 | CLCM_PORT_CONFIG = 3, 156 | CLCM_PORT_CTRL = 4, 157 | CLCM_PORT_UNBIND = 5, 158 | 159 | CLCM_LD_CONFIG = 6, 160 | CLCM_LD_MEM = 7, 161 | 162 | CLCM_MCTP = 8, 163 | CLCM_MCTP_GET_EID = 9, 164 | CLCM_MCTP_GET_TYPE = 10, 165 | CLCM_MCTP_GET_UUID = 11, 166 | CLCM_MCTP_GET_VER = 12, 167 | CLCM_MCTP_SET_EID = 13, 168 | 169 | CLCM_SET_LD_ALLOCATIONS = 14, 170 | CLCM_SET_QOS_ALLOCATED = 15, 171 | CLCM_SET_QOS_CONTROL = 16, 172 | CLCM_SET_QOS_LIMIT = 17, 173 | 174 | CLCM_SHOW_PORT = 18, 175 | CLCM_SHOW_LD_ALLOCATIONS= 19, 176 | CLCM_SHOW_LD_INFO = 20, 177 | CLCM_SHOW_QOS_ALLOCATED = 21, 178 | CLCM_SHOW_QOS_CONTROL = 22, 179 | CLCM_SHOW_QOS_LIMIT = 23, 180 | CLCM_SHOW_QOS_STATUS = 24, 181 | CLCM_SHOW_SWITCH = 25, 182 | CLCM_SHOW_VCS = 26, 183 | CLCM_SHOW_DEV = 27, 184 | CLCM_PORT_CONN = 28, 185 | CLCM_PORT_DISCONN = 29, 186 | CLCM_SHOW_IDENTITY = 30, 187 | CLCM_SHOW_MSG_LIMIT = 31, 188 | CLCM_SET_MSG_LIMIT = 32, 189 | CLCM_SHOW_BOS = 33, 190 | CLCM_LIST = 34, 191 | 192 | CLCM_MAX 193 | }; 194 | 195 | /** 196 | * CLI Option (OP) 197 | */ 198 | enum _CLOP 199 | { 200 | /* General CLI Options */ 201 | CLOP_VERBOSITY = 0, //!< Bit Field 202 | CLOP_TCP_PORT = 1, //!< TCP Port to connect to 203 | CLOP_CMD = 2, //!< Command to RUN 204 | CLOP_INFILE = 3, //!< Filename for input 205 | 206 | /* Hiden Options */ 207 | CLOP_PRNT_OPTS = 4, //!< Print Options Array when completed parsing 208 | 209 | /* MCTP Options */ 210 | CLOP_MCTP_EID = 5, //!< EID value for MCTP Set EID Command 211 | CLOP_MCTP_TYPE = 6, //!< Type value for MCTP Command Get Ver Command 212 | 213 | /* ID Options */ 214 | CLOP_VCSID = 7, //!< Virtual CXL Switch ID 215 | CLOP_PPID = 8, //!< Physical Port ID 216 | CLOP_VPPBID = 9, //!< Virtual Pcie-to-PCIe Bridge ID 217 | CLOP_LDID = 10, //!< Logical Device ID 218 | CLOP_ALL = 11, //!< Perform aciton on all of collection 219 | 220 | /* Port Options */ 221 | CLOP_UNBIND_MODE = 12, //!< Port Unbind Option [CLPU] 222 | CLOP_PORT_CONTROL = 13, //!< Action to perform [CLPC] 223 | 224 | /* Config & Memory Options */ 225 | CLOP_REGISTER = 14, //!< Register number 226 | CLOP_EXT_REGISTER = 15, //!< Extended Register number 227 | CLOP_FDBE = 16, //!< First Dword Byte Enable 228 | CLOP_LDBE = 17, //!< First Dword Byte Enable 229 | CLOP_WRITE = 18, //!< Perform a write transacion 230 | CLOP_OFFSET = 19, //!< Offset into a buffer address space 231 | CLOP_LEN = 20, //!< Length of data parameter 232 | 233 | /* LD Options */ 234 | CLOP_LD_RNG1 = 21, //!< LD Allocations Range1 Array 235 | CLOP_LD_RNG2 = 22, //!< LD Allocations Range2 Array 236 | 237 | /* QoS Options */ 238 | CLOP_CONGEST_ENABLE = 23, //!< Egress Port Congestion Enable 239 | CLOP_TEMP_THROTTLE = 24, //!< Temporary Throughput Reduction Enable 240 | CLOP_EGRESS_MOD_PCNT = 25, //!< Egress Moderate Percentage 241 | CLOP_EGRESS_SEV_PCNT = 26, //!< Egress Severe Percentage 242 | CLOP_BP_SAMPLE_INTVL = 27, //!< Backpressure Sample Interval 243 | CLOP_REQCMPBASIS = 28, //!< ReqCmpBasis 244 | CLOP_CCINTERVAL = 29, //!< Completion Collection Interval 245 | CLOP_QOS_ALLOCATED = 30, //!< QoS BW Allocation Fraction list 246 | CLOP_QOS_LIMIT = 31, //!< QoS BW Limit Fraction list 247 | 248 | /* AER Options */ 249 | CLOP_AER_ERROR = 32, //!< AER Error (4 Byte HEX) 250 | CLOP_AER_HEADER = 33, //!< AER TLP Header (32 Byte HEX String) 251 | 252 | CLOP_DATA = 34, //!< Immediate Data for Write transaction 253 | 254 | CLOP_OUTFILE = 35, //!< Filename for output 255 | 256 | CLOP_MCTP_VERBOSITY = 36, //!< Verbosity setting for MCTP library 257 | CLOP_DEVICE = 37, //!< Device ID 258 | CLOP_NUM = 38, //!< Number of items 259 | CLOP_LIMIT = 39, //!< Message Response Limit 260 | CLOP_TCP_ADDRESS = 40, //!< TCP Address to connect to 261 | CLOP_NO_INIT = 41, //!< Do not initialize local state at start up 262 | CLOP_MAX 263 | }; 264 | 265 | /** 266 | * Physical Port Control Opcodes (PC) 267 | * 268 | * CXL 2.0 v1.0 Table 93 269 | */ 270 | enum _CLPC 271 | { 272 | CLPC_ASSERT = 0, 273 | CLPC_DEASSERT = 1, 274 | CLPC_RESET = 2, 275 | CLPC_MAX 276 | }; 277 | 278 | /** 279 | * Port Unbind Mode Options (PU) 280 | * 281 | * CXL 2.0 v1.0 Table 101 282 | */ 283 | enum _CLPU 284 | { 285 | CLPU_WAIT = 0, 286 | CLPU_MANAGED = 1, 287 | CLPU_SURPRISE = 2, 288 | CLPU_MAX 289 | }; 290 | 291 | /* STRUCTS ===================================================================*/ 292 | 293 | /** 294 | * CLI Option Struct 295 | * 296 | * Each command line parameter is stored in one of these objects 297 | */ 298 | struct opt 299 | { 300 | int set; //!< Not set (0), set (1) 301 | __u8 u8; //!< Unsigned char value 302 | __u16 u16; //!< Unsigned long value 303 | __u32 u32; //!< Unsigned long value 304 | __u64 u64; //!< Unsigned long long value 305 | __s32 val; //!< Generic signed value 306 | __u64 num; //!< Number of items 307 | __u64 len; //!< Data Buffer Length 308 | char *str; //!< String value 309 | __u8 *buf; //!< Data buffer 310 | }; 311 | 312 | /* GLOBAL VARIABLES ==========================================================*/ 313 | 314 | /** 315 | * Global varible to store parsed CLI options 316 | */ 317 | extern struct opt *opts; 318 | 319 | /* PROTOTYPES ================================================================*/ 320 | 321 | /** 322 | * Free allocated memory by option parsing proceedure 323 | * 324 | * @return 0 upon success. Non zero otherwise 325 | */ 326 | int options_free(struct opt *opts); 327 | 328 | /** 329 | * Parse command line options 330 | */ 331 | int options_parse(int argc, char *argv[]); 332 | 333 | #endif //ifndef _OPTIONS_H 334 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file jack.c 4 | * 5 | * @brief Code file for FM API over TCP CLI 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Jan 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | /* gettid() 16 | */ 17 | #define _GNU_SOURCE 18 | #include 19 | 20 | /* printf() 21 | */ 22 | #include 23 | 24 | /* memset() 25 | */ 26 | #include 27 | 28 | /* sem_t 29 | * sem_init() 30 | * sem_timedwait() 31 | */ 32 | #include 33 | 34 | #include 35 | 36 | /* autl_prnt_buf() 37 | */ 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | /* mctp_init() 47 | * mctp_set_mh() 48 | * mctp_run() 49 | */ 50 | #include 51 | 52 | #include "ctrl_handler.h" 53 | #include "emapi_handler.h" 54 | #include "fmapi_handler.h" 55 | #include "cmd_encoder.h" 56 | #include "options.h" 57 | 58 | /* MACROS ====================================================================*/ 59 | 60 | #ifdef JACK_VERBOSE 61 | #define VERBOSE(v, m, t) ({ if(opts[CLOP_VERBOSITY].u64 & v) printf("%d:%s %s\n", t, __FUNCTION__, m ); }) 62 | #define VERBOSE_INT(v, m, t, i) ({ if(opts[CLOP_VERBOSITY].u64 & v) printf("%d:%s %s %d\n", t, __FUNCTION__, m, i); }) 63 | #define VERBOSE_STR(v, m, t, s) ({ if(opts[CLOP_VERBOSITY].u64 & v) printf("%d:%s %s %s\n", t, __FUNCTION__, m, s); }) 64 | #else 65 | #define VERBOSE(v, m, t) 66 | #define VERBOSE_INT(v, m, t, i) 67 | #define VERBOSE_STR(v, m, t, s) 68 | #endif // JACK_VERBOSE 69 | 70 | #ifdef JACK_VERBOSE 71 | #define INIT unsigned step = 0; 72 | #define ENTER if (m->verbose & MCTP_VERBOSE_THREADS) printf("%d:%s Enter\n", gettid(), __FUNCTION__); 73 | #define STEP step++; if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step); 74 | #define HEX32(k, i) if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, k, i); 75 | #define INT32(k, i) if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, k, i); 76 | #define ERR32(k, i) if (m->verbose & MCTP_VERBOSE_ERROR) printf("%d:%s STEP: %u ERR: %s: %d\n", gettid(), __FUNCTION__, step, k, i); 77 | #define EXIT(rc) if (m->verbose & MCTP_VERBOSE_THREADS) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc); 78 | #else 79 | #define INIT 80 | #define ENTER 81 | #define STEP 82 | #define HEX32(k, i) 83 | #define INT32(k, i) 84 | #define ERR32(k, i) 85 | #define EXIT(rc) 86 | #endif // JACK_VERBOSE 87 | 88 | #define JKLN_PORTS 32 89 | #define JKLN_VCSS 32 90 | #define JKLN_VPPBS 256 91 | #define JKLN_RSP_MSG_N 13 92 | 93 | /* ENUMERATIONS ==============================================================*/ 94 | 95 | /* STRUCTS ===================================================================*/ 96 | 97 | /* PROTOTYPES ================================================================*/ 98 | 99 | 100 | /* GLOBAL VARIABLES ==========================================================*/ 101 | 102 | struct cxl_switch *cxls; 103 | 104 | /* FUNCTIONS =================================================================*/ 105 | 106 | 107 | int simple_handler(struct mctp *m, struct mctp_action *ma) 108 | { 109 | m->dummy = 0; 110 | if (ma->sem != NULL) 111 | sem_post(ma->sem); 112 | return 0; 113 | } 114 | 115 | 116 | int init_switch(struct mctp *m) 117 | { 118 | INIT 119 | struct mctp_action *ma; 120 | struct cxl_port *p; 121 | struct fmapi_msg msg, sub; 122 | 123 | ENTER 124 | 125 | int rv; 126 | 127 | rv = 1; 128 | ma = NULL; 129 | 130 | STEP // 1: ISC - Identity 131 | fmapi_fill_isc_id(&msg); 132 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 133 | goto fail; 134 | fmapi_update(m, ma); 135 | 136 | STEP // 2: ISC - Set msg limit 137 | fmapi_fill_isc_set_msg_limit(&msg, JKLN_RSP_MSG_N); 138 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 139 | goto fail; 140 | 141 | STEP // 3: ISC - BOS 142 | fmapi_fill_isc_bos(&msg); 143 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 144 | goto fail; 145 | fmapi_update(m, ma); 146 | 147 | STEP // 4: PSC - Identify Switch Device 148 | fmapi_fill_psc_id(&msg); 149 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 150 | goto fail; 151 | fmapi_update(m, ma); 152 | 153 | STEP // 5: PSC - Get Port Status 154 | for ( int i = 0 ; i < cxls->num_ports ; i++) 155 | { 156 | fmapi_fill_psc_get_port(&msg, i); 157 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 158 | goto fail; 159 | fmapi_update(m, ma); 160 | } 161 | 162 | STEP // 6: VSC - Get VCS Status 163 | for ( int i = 0 ; i < cxls->num_vcss ; i++) 164 | { 165 | fmapi_fill_vsc_get_vcs(&msg, i, 0, 255); 166 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 167 | goto fail; 168 | fmapi_update(m, ma); 169 | } 170 | 171 | STEP // 7; PCI Config Space - For each port, get first 64 Bytes of config space 172 | for ( int i = 0 ; i < cxls->num_ports ; i++) 173 | { 174 | p = &cxls->ports[i]; 175 | 176 | if (!p->prsnt) 177 | continue; 178 | 179 | for ( int k = 0 ; k < 64 ; k+=4) 180 | { 181 | fmapi_fill_psc_cfg(&msg, i, k, 0, 0xF, FMCT_READ, NULL); 182 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 183 | goto fail; 184 | fmapi_update(m, ma); 185 | } 186 | } 187 | 188 | STEP // 8: MCC - For each port, if an MLD device, fetch MCC data 189 | for ( int i = 0 ; i < cxls->num_ports ; i++) 190 | { 191 | p = &cxls->ports[i]; 192 | 193 | if (p->dt != FMDT_CXL_TYPE_3_POOLED) 194 | continue; 195 | 196 | // MCC - Get Info 197 | fmapi_fill_mcc_get_info(&sub); 198 | fmapi_fill_mpc_tmc(&msg, i, MCMT_CXLCCI, &sub); 199 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 200 | goto fail; 201 | fmapi_update(m, ma); 202 | 203 | // MCC - Get LD Alloc 204 | fmapi_fill_mcc_get_alloc(&sub, 0, 0); 205 | fmapi_fill_mpc_tmc(&msg, i, MCMT_CXLCCI, &sub); 206 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 207 | goto fail; 208 | fmapi_update(m, ma); 209 | 210 | // MCC - Get QoS Control 211 | fmapi_fill_mcc_get_qos_ctrl(&sub); 212 | fmapi_fill_mpc_tmc(&msg, i, MCMT_CXLCCI, &sub); 213 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 214 | goto fail; 215 | fmapi_update(m, ma); 216 | 217 | // MCC - Get QoS BW Alloc 218 | fmapi_fill_mcc_get_qos_alloc(&sub, 0, 0); 219 | fmapi_fill_mpc_tmc(&msg, i, MCMT_CXLCCI, &sub); 220 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 221 | goto fail; 222 | fmapi_update(m, ma); 223 | 224 | // MCC - Get QoS BW Limit 225 | fmapi_fill_mcc_get_qos_limit(&sub, 0, 0); 226 | fmapi_fill_mpc_tmc(&msg, i, MCMT_CXLCCI, &sub); 227 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 228 | goto fail; 229 | fmapi_update(m, ma); 230 | 231 | // MCC- - Get QoS Status 232 | fmapi_fill_mcc_get_qos_status(&sub); 233 | fmapi_fill_mpc_tmc(&msg, i, MCMT_CXLCCI, &sub); 234 | if ( (ma = submit_fmapi(m, &msg, 0, NULL, NULL, NULL, NULL)) == NULL) 235 | goto fail; 236 | fmapi_update(m, ma); 237 | } 238 | 239 | rv = 0; 240 | 241 | goto end; 242 | 243 | fail: 244 | 245 | printf("ERR: submit_fmapi() returned NULL. rv: %d\n", rv); 246 | 247 | end: 248 | 249 | EXIT(rv) 250 | 251 | return rv; 252 | } 253 | 254 | void list(struct mctp *m) 255 | { 256 | m->dummy = 0; 257 | printf("list\n"); 258 | } 259 | 260 | /** 261 | * The Jack main run function 262 | */ 263 | void run(struct mctp *m) 264 | { 265 | struct mctp_action *ma; 266 | 267 | // Initialize variables 268 | ma = NULL; 269 | 270 | // 1: If no command then exit 271 | if ( !opts[CLOP_CMD].set ) 272 | goto end; 273 | 274 | // Initialize cached copy of remote switch state 275 | //if (opts[CLOP_NO_INIT].set == 0) 276 | // init_switch(m); 277 | 278 | if (opts[CLOP_CMD].val == CLCM_LIST) 279 | list(m); 280 | else 281 | { 282 | // Submit Request 283 | ma = submit_cli_request(m, NULL); 284 | if (ma == NULL) 285 | { 286 | printf("ma Was NULL\n"); 287 | if (errno == ETIMEDOUT) 288 | printf("CLI Submit call timed out\n"); 289 | goto end; 290 | } 291 | 292 | // Print out response 293 | switch(ma->rsp->type) 294 | { 295 | case MCMT_CXLFMAPI: fmapi_handler(m, ma->rsp, ma->req); break; 296 | case MCMT_CSE: emapi_handler(m, ma->rsp); break; 297 | case MCMT_CONTROL: ctrl_handler(m, ma->rsp); break; 298 | default: break; 299 | } 300 | } 301 | 302 | end: 303 | 304 | return; 305 | 306 | } 307 | 308 | /** 309 | * jack cli tool main function 310 | * 311 | * STEPS 312 | * 1: Parse CLI options 313 | * 2: Verify Command was requested 314 | * 3: MCTP Init 315 | * 4: Configure MCTP 316 | * 5: Run MCTP 317 | * 6: Free memory 318 | */ 319 | int main(int argc, char* argv[]) 320 | { 321 | int rv; 322 | struct mctp *m; 323 | 324 | rv = 1; 325 | 326 | // STEP 1: Parse CLI options 327 | rv = options_parse(argc,argv); 328 | if (rv != 0) 329 | { 330 | printf("Error: Parse options failed:\n"); 331 | goto end; 332 | } 333 | 334 | // Initialize global state 335 | cxls = cxls_init(JKLN_PORTS, JKLN_VCSS, JKLN_VPPBS); 336 | 337 | // Verify Command was requested 338 | if (!opts[CLOP_CMD].set) 339 | { 340 | printf("Error: No command was selected\n"); 341 | rv = 1; 342 | goto end; 343 | } 344 | 345 | // MCTP Init 346 | m = mctp_init(); 347 | if (m == NULL) 348 | { 349 | printf("Error: mctp_init() failed\n"); 350 | rv = 1; 351 | goto end; 352 | } 353 | 354 | // Configure MCTP 355 | 356 | // Set Message handler functions 357 | mctp_set_handler(m, MCMT_CXLFMAPI, simple_handler); 358 | mctp_set_handler(m, MCMT_CSE, simple_handler); 359 | mctp_set_handler(m, MCMT_CONTROL, simple_handler); 360 | 361 | // Set MCTP verbosity levels 362 | mctp_set_verbosity(m, opts[CLOP_MCTP_VERBOSITY].u64); 363 | 364 | // Run MCTP 365 | rv = mctp_run(m, opts[CLOP_TCP_PORT].u16, opts[CLOP_TCP_ADDRESS].u32, MCRM_CLIENT, 1, 1); 366 | if (rv != 0) 367 | { 368 | printf("Error: mctp_run() failed: %d\n", rv); 369 | goto stop; 370 | } 371 | 372 | // Run Jack main sequence 373 | run(m); 374 | 375 | mctp_stop(m); 376 | 377 | rv = 0; 378 | 379 | stop: 380 | 381 | // STEP 6: Free memory 382 | mctp_free(m); 383 | cxls_free(cxls); 384 | options_free(opts); 385 | 386 | return rv; 387 | 388 | end: 389 | 390 | return rv; 391 | }; 392 | 393 | -------------------------------------------------------------------------------- /cmd_encoder.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file jack.c 4 | * 5 | * @brief Code file for FM API over TCP CLI 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Jan 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | /* gettid() 16 | */ 17 | #define _GNU_SOURCE 18 | 19 | #include 20 | 21 | /* printf() 22 | */ 23 | #include 24 | 25 | /* memset() 26 | */ 27 | #include 28 | 29 | #include 30 | 31 | /* autl_prnt_buf() 32 | */ 33 | #include 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | /* mctp_init() 41 | * mctp_set_mh() 42 | * mctp_run() 43 | */ 44 | #include 45 | 46 | #include "cmd_encoder.h" 47 | #include "options.h" 48 | 49 | /* MACROS ====================================================================*/ 50 | 51 | #ifdef JACK_VERBOSE 52 | #define INIT unsigned step = 0; 53 | #define ENTER if (opts[CLOP_VERBOSITY].u64 & MCTP_VERBOSE_THREADS) printf("%d:%s Enter\n", gettid(), __FUNCTION__); 54 | #define STEP step++; if (opts[CLOP_VERBOSITY].u64 & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step); 55 | #define HEX32(k, i) if (opts[CLOP_VERBOSITY].u64 & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, k, i); 56 | #define INT32(k, i) if (opts[CLOP_VERBOSITY].u64 & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, k, i); 57 | #define ERR32(k, i) if (opts[CLOP_VERBOSITY].u64 & MCTP_VERBOSE_ERROR) printf("%d:%s STEP: %u ERR: %s: %d\n", gettid(), __FUNCTION__, step, k, i); 58 | #define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & MCTP_VERBOSE_THREADS) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc); 59 | #else 60 | #define INIT 61 | #define ENTER 62 | #define STEP 63 | #define HEX32(k, i) 64 | #define INT32(k, i) 65 | #define ERR32(k, i) 66 | #define EXIT(rc) 67 | #endif 68 | 69 | #define JKLN_CMD_TIMEOUT_SEC 10 70 | #define JKLN_CMD_TIMEOUT_NSEC 0 71 | 72 | 73 | /* ENUMERATIONS ==============================================================*/ 74 | 75 | /* STRUCTS ===================================================================*/ 76 | 77 | /* PROTOTYPES ================================================================*/ 78 | 79 | /* GLOBAL VARIABLES ==========================================================*/ 80 | 81 | /* FUNCTIONS =================================================================*/ 82 | 83 | struct mctp_action *submit_ctrl( 84 | struct mctp *m, 85 | struct mctp_ctrl_msg *msg, 86 | int retry, 87 | void *user_data, 88 | void (*fn_submitted)(struct mctp *m, struct mctp_action *a), 89 | void (*fn_completed)(struct mctp *m, struct mctp_action *a), 90 | void (*fn_failed)(struct mctp *m, struct mctp_action *a) 91 | ) 92 | { 93 | struct timespec delta; 94 | 95 | // Initialize variables 96 | delta.tv_sec = JKLN_CMD_TIMEOUT_SEC; 97 | delta.tv_nsec = JKLN_CMD_TIMEOUT_NSEC; 98 | 99 | // Set MCTP Control Header fields 100 | msg->hdr.req = 1; 101 | msg->hdr.datagram = 0; 102 | msg->hdr.inst = 0; 103 | msg->len = mctp_len_ctrl((__u8*)&msg->hdr); 104 | 105 | // Submit to MCTP library 106 | return mctp_submit( 107 | m, // struct mctp* 108 | MCMT_CONTROL, // [MCMT] 109 | msg, // void* to mctp payload 110 | msg->len+MCLN_CTRL, // Length of mctp payload 111 | retry, // Retry attempts 112 | &delta, 113 | user_data, // To keep with mctp_action 114 | fn_submitted, // fn_submitted 115 | fn_completed, // fn_completed 116 | fn_failed // fn_failed 117 | ); 118 | } 119 | 120 | struct mctp_action *submit_emapi( 121 | struct mctp *m, 122 | struct emapi_msg *msg, 123 | int retry, 124 | void *user_data, 125 | void (*fn_submitted)(struct mctp *m, struct mctp_action *a), 126 | void (*fn_completed)(struct mctp *m, struct mctp_action *a), 127 | void (*fn_failed)(struct mctp *m, struct mctp_action *a) 128 | ) 129 | { 130 | int len; 131 | struct emapi_buf buf; 132 | struct timespec delta; 133 | 134 | // Initialize variables 135 | delta.tv_sec = JKLN_CMD_TIMEOUT_SEC; 136 | delta.tv_nsec = JKLN_CMD_TIMEOUT_NSEC; 137 | 138 | // Serialize payload 139 | len = emapi_serialize((__u8*)&buf.payload, &msg->obj, emapi_emob_req(msg->hdr.opcode), NULL); 140 | 141 | // Set EM API message category as a request 142 | emapi_fill_hdr(&msg->hdr, EMMT_REQ, 0, 0, msg->hdr.opcode, len, msg->hdr.a, msg->hdr.b); 143 | 144 | // Serialize EM API Header into buffer 145 | emapi_serialize((__u8*)&buf.hdr, &msg->hdr, EMOB_HDR, NULL); 146 | 147 | // Submit to MCTP library 148 | return mctp_submit( 149 | m, // struct mctp* 150 | MCMT_CSE, // [MCMT] 151 | &buf, // void* to mctp payload 152 | msg->hdr.len + EMLN_HDR,// Length of mctp payload 153 | retry, // Retry attempts 154 | &delta, 155 | user_data, // To keep with mctp_action 156 | fn_submitted, // fn_submitted 157 | fn_completed, // fn_completed 158 | fn_failed // fn_failed 159 | ); 160 | } 161 | 162 | struct mctp_action *submit_fmapi( 163 | struct mctp *m, 164 | struct fmapi_msg *msg, 165 | int retry, 166 | void *user_data, 167 | void (*fn_submitted)(struct mctp *m, struct mctp_action *a), 168 | void (*fn_completed)(struct mctp *m, struct mctp_action *a), 169 | void (*fn_failed)(struct mctp *m, struct mctp_action *a) 170 | ) 171 | { 172 | int len; 173 | struct fmapi_buf buf; 174 | struct timespec delta; 175 | 176 | // Initialize variables 177 | delta.tv_sec = JKLN_CMD_TIMEOUT_SEC; 178 | delta.tv_nsec = JKLN_CMD_TIMEOUT_NSEC; 179 | 180 | // Serialize Object 181 | len = fmapi_serialize((__u8*)&buf.payload, &msg->obj, fmapi_fmob_req(msg->hdr.opcode)); 182 | 183 | // Fill Header 184 | fmapi_fill_hdr(&msg->hdr, FMMT_REQ, 0, msg->hdr.opcode, 0, len, 0, 0); 185 | 186 | // Serialize Header 187 | fmapi_serialize((__u8*)&buf.hdr, &msg->hdr, FMOB_HDR); 188 | 189 | // Submit to MCTP library 190 | return mctp_submit( 191 | m, // struct mctp* 192 | MCMT_CXLFMAPI, // [MCMT] 193 | &buf, // void* to mctp payload 194 | msg->hdr.len + FMLN_HDR,// Length of mctp payload 195 | retry, // Retry attempts 196 | &delta, 197 | user_data, // To keep with mctp_action 198 | fn_submitted, // fn_submitted 199 | fn_completed, // fn_completed 200 | fn_failed // fn_failed 201 | ); 202 | } 203 | 204 | /** 205 | * Prepare an MCTP Message Request from CLI Options 206 | * 207 | * @param mm struct mctp_msg* this is the message to store the request in 208 | * @return 0 upon success, non-zero otherwise 209 | * 210 | * STEPS 211 | * 1: Set buffer pointers 212 | * 3: Command switch 213 | */ 214 | struct mctp_action *submit_cli_request(struct mctp *m, void *user_data) 215 | { 216 | INIT 217 | struct mctp_action *ma; 218 | struct fmapi_msg msg, sub; 219 | struct emapi_msg em; 220 | struct mctp_ctrl_msg mc; 221 | 222 | ENTER 223 | 224 | // Initialize Variables 225 | ma = NULL; 226 | 227 | STEP // 1: Set buffer pointers 228 | 229 | STEP // 2: Handle Command 230 | switch (opts[CLOP_CMD].val) 231 | { 232 | case CLCM_NULL: 233 | goto end; 234 | 235 | case CLCM_AER: 236 | { 237 | int vcsid, vppbid; 238 | 239 | vcsid = 0; 240 | vppbid = 0; 241 | 242 | if (opts[CLOP_VCSID].set) 243 | vcsid = opts[CLOP_VCSID].u8; //!< Virtual CXL Switch ID 244 | 245 | if (opts[CLOP_VPPBID].set) 246 | vppbid = opts[CLOP_VPPBID].u8; //!< Virtual Pcie-to-PCIe Bridge ID 247 | 248 | if (!opts[CLOP_AER_ERROR].set) 249 | goto end; 250 | 251 | if (!opts[CLOP_AER_HEADER].set) //!< TLP Header to place in AER registers, as defined in the PCIe specification 252 | goto end; 253 | 254 | fmapi_fill_vsc_aer(&msg, vcsid, vppbid, opts[CLOP_AER_ERROR].u32, opts[CLOP_AER_HEADER].buf); 255 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 256 | } 257 | break; 258 | 259 | case CLCM_PORT_BIND: 260 | { 261 | int vcsid, vppbid, ppid, ldid; 262 | 263 | vcsid = 0; 264 | vppbid = 0; 265 | ppid = 0; 266 | ldid = 0xFFFF; 267 | 268 | if (opts[CLOP_VCSID].set) 269 | vcsid = opts[CLOP_VCSID].u8; //!< Virtual CXL Switch ID 270 | 271 | if (opts[CLOP_PPID].set) 272 | ppid = opts[CLOP_PPID].u8; //!< Physical Port ID 273 | 274 | if (opts[CLOP_VPPBID].set) 275 | vppbid = opts[CLOP_VPPBID].u8; //!< Virtual Pcie-to-PCIe Bridge ID 276 | 277 | if (opts[CLOP_LDID].set) 278 | ldid = opts[CLOP_LDID].u16; //!< Logical Device ID 279 | 280 | fmapi_fill_vsc_bind(&msg, vcsid, vppbid, ppid, ldid); 281 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 282 | } 283 | break; 284 | 285 | case CLCM_PORT_CONFIG: 286 | { 287 | int ppid, reg, ext, fdbe, type; 288 | 289 | ppid = 0; 290 | reg = 0; 291 | ext = 0; 292 | fdbe = 0; 293 | type = 0; 294 | 295 | if (opts[CLOP_PPID].set) 296 | ppid = opts[CLOP_PPID].u8; //!< PPB ID: Target PPB physical port 297 | 298 | if (opts[CLOP_REGISTER].set) 299 | reg = opts[CLOP_REGISTER].u8; //!< Register Number as defined in PCIe spec 300 | 301 | if (opts[CLOP_EXT_REGISTER].set) 302 | ext = opts[CLOP_EXT_REGISTER].u8; //!< Extended Register Number as defined in PCIe spec 303 | 304 | if (opts[CLOP_FDBE].set) 305 | fdbe = opts[CLOP_FDBE].u8; //!< First DWord Byte Enable as defined in PCIe spec 306 | else 307 | fdbe = 0x1; //!< First DWord Byte Enable as defined in PCIe spec 308 | 309 | if (opts[CLOP_WRITE].set) 310 | type = FMCT_WRITE; //!< Transation type [FMCT] 311 | 312 | fmapi_fill_psc_cfg(&msg, ppid, reg, ext, fdbe, type, (__u8*)&opts[CLOP_DATA].u32); 313 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 314 | } 315 | break; 316 | 317 | case CLCM_PORT_CONN: 318 | { 319 | emapi_fill_conn(&em, opts[CLOP_PPID].u8, opts[CLOP_DEVICE].u8); 320 | ma = submit_emapi(m, &em, 0, user_data, NULL, NULL, NULL); 321 | } 322 | break; 323 | 324 | case CLCM_PORT_DISCONN: 325 | { 326 | emapi_fill_disconn(&em, opts[CLOP_PPID].u8, opts[CLOP_ALL].set); 327 | ma = submit_emapi(m, &em, 0, user_data, NULL, NULL, NULL); 328 | } 329 | break; 330 | 331 | case CLCM_PORT_CTRL: 332 | { 333 | int ppid, opcode; 334 | 335 | ppid = 0; 336 | opcode = 0; 337 | 338 | if (opts[CLOP_PPID].set) 339 | ppid = opts[CLOP_PPID].u8; 340 | 341 | switch (opts[CLOP_PORT_CONTROL].val) 342 | { 343 | case CLPC_ASSERT: opcode = FMPO_ASSERT_PERST; break; 344 | case CLPC_DEASSERT: opcode = FMPO_DEASSERT_PERST; break; 345 | case CLPC_RESET: opcode = FMPO_RESET_PPB; break; 346 | default: goto end; 347 | } 348 | 349 | fmapi_fill_psc_port_ctrl(&msg, ppid, opcode); 350 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 351 | } 352 | break; 353 | 354 | case CLCM_PORT_UNBIND: 355 | { 356 | int vcsid, vppbid, option; 357 | 358 | vcsid = 0; 359 | option = 0; 360 | vppbid = 0xFFFF; 361 | 362 | // Prepare Object 363 | if (opts[CLOP_VCSID].set) 364 | vcsid = opts[CLOP_VCSID].u8; //!< Virtual CXL Switch ID 365 | 366 | if (opts[CLOP_VPPBID].set) 367 | vppbid = opts[CLOP_VPPBID].u8; //!< Virtual Pcie-to-PCIe Bridge ID 368 | 369 | if (opts[CLOP_UNBIND_MODE].set) 370 | { //!< Unbind Option [FMUB] 371 | switch(opts[CLOP_UNBIND_MODE].val) 372 | { 373 | case CLPU_WAIT: option = FMUB_WAIT; break; 374 | case CLPU_MANAGED: option = FMUB_MANAGED_HOT_REMOVE; break; 375 | case CLPU_SURPRISE: option = FMUB_SURPRISE_HOT_REMOVE; break; 376 | default: goto end; 377 | } 378 | } 379 | 380 | fmapi_fill_vsc_unbind(&msg, vcsid, vppbid, option); 381 | 382 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 383 | } 384 | break; 385 | 386 | case CLCM_LD_CONFIG: 387 | { 388 | int ppid, ldid, reg, ext, fdbe, type; 389 | 390 | ppid = 0; 391 | ldid = 0; 392 | reg = 0; 393 | ext = 0; 394 | fdbe = 1; 395 | type = FMCT_READ; 396 | 397 | // Prepare Object 398 | if (opts[CLOP_PPID].set) 399 | ppid = opts[CLOP_PPID].u8; //!< PPB ID: Target PPB physical port 400 | 401 | if (opts[CLOP_REGISTER].set) 402 | reg = opts[CLOP_REGISTER].u8; //!< Register Number as defined in PCIe spec 403 | 404 | if (opts[CLOP_EXT_REGISTER].set) 405 | ext = opts[CLOP_EXT_REGISTER].u8; //!< Extended Register Number as defined in PCIe spec 406 | 407 | if (opts[CLOP_FDBE].set) 408 | fdbe = opts[CLOP_FDBE].u8; //!< First DWord Byte Enable as defined in PCIe spec 409 | 410 | if (opts[CLOP_WRITE].set) 411 | type = FMCT_WRITE; //!< Transation type [FMCT] 412 | 413 | if (opts[CLOP_LDID].set) 414 | ldid = opts[CLOP_LDID].u16; //!< Logical Device ID 415 | 416 | fmapi_fill_mpc_cfg(&msg, ppid, ldid, reg, ext, fdbe, type, (__u8*)&opts[CLOP_DATA].u32); 417 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 418 | } 419 | break; 420 | 421 | case CLCM_LD_MEM: 422 | { 423 | int ppid, ldid, len, fdbe, ldbe, type; 424 | __u64 offset; 425 | __u8 *data; 426 | 427 | ppid = 0; 428 | ldid = 0; 429 | offset = 0; 430 | len = 0; 431 | fdbe = 0xF; //!< First DWord Byte Enable as defined in PCIe spec 432 | ldbe = 0xF; //!< First DWord Byte Enable as defined in PCIe spec 433 | type = FMCT_READ; 434 | 435 | // Prepare Object 436 | if (opts[CLOP_PPID].set) 437 | ppid = opts[CLOP_PPID].u8; //!< PPB ID: Target PPB physical port 438 | 439 | if (opts[CLOP_FDBE].set) 440 | fdbe = opts[CLOP_FDBE].u8; //!< First DWord Byte Enable as defined in PCIe spec 441 | 442 | if (opts[CLOP_LDBE].set) 443 | ldbe = opts[CLOP_LDBE].u8; //!< Last DWord Byte Enable as defined in PCIe spec 444 | 445 | if (opts[CLOP_WRITE].set) 446 | type = FMCT_WRITE; //!< Transation type [FMCT] 447 | 448 | if (opts[CLOP_LDID].set) 449 | ldid = opts[CLOP_LDID].u16; //!< Logical Device ID 450 | 451 | if (opts[CLOP_LEN].set) 452 | len = opts[CLOP_LEN].len; //!< Transaction Length in bytes, max of 4 kB 453 | 454 | if (opts[CLOP_OFFSET].set) 455 | offset = opts[CLOP_OFFSET].u64; //!< Transaction Offset into target device mem space 456 | 457 | data = (__u8*)&opts[CLOP_DATA].u32; //!< Transaction Data: Write data. Only valid for write transactions 458 | 459 | if (opts[CLOP_INFILE].set) 460 | data = opts[CLOP_INFILE].buf; //!< Transaction Data: Write data. Only valid for write transactions 461 | 462 | fmapi_fill_mpc_mem(&msg, ppid, ldid, offset, len, fdbe, ldbe, type, data); 463 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 464 | } 465 | break; 466 | 467 | case CLCM_MCTP: 468 | break; 469 | 470 | case CLCM_MCTP_GET_EID: 471 | { 472 | mctp_ctrl_fill_get_eid(&mc); 473 | ma = submit_ctrl(m, &mc, 0, user_data, NULL, NULL, NULL); 474 | } 475 | break; 476 | 477 | case CLCM_MCTP_GET_TYPE: 478 | { 479 | mctp_ctrl_fill_get_type(&mc); 480 | ma = submit_ctrl(m, &mc, 0, user_data, NULL, NULL, NULL); 481 | } 482 | break; 483 | 484 | case CLCM_MCTP_GET_UUID: 485 | { 486 | mctp_ctrl_fill_get_uuid(&mc); 487 | ma = submit_ctrl(m, &mc, 0, user_data, NULL, NULL, NULL); 488 | } 489 | break; 490 | 491 | case CLCM_MCTP_GET_VER: 492 | { 493 | mctp_ctrl_fill_get_ver(&mc, opts[CLOP_MCTP_TYPE].u8); 494 | ma = submit_ctrl(m, &mc, 0, user_data, NULL, NULL, NULL); 495 | } 496 | break; 497 | 498 | case CLCM_MCTP_SET_EID: 499 | { 500 | mctp_ctrl_fill_set_eid(&mc, opts[CLOP_MCTP_EID].u8); 501 | ma = submit_ctrl(m, &mc, 0, user_data, NULL, NULL, NULL); 502 | } 503 | break; 504 | 505 | case CLCM_SET_MSG_LIMIT: 506 | { 507 | fmapi_fill_isc_set_msg_limit(&msg, opts[CLOP_LIMIT].u8); 508 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 509 | } 510 | break; 511 | 512 | case CLCM_SET_LD_ALLOCATIONS: 513 | { 514 | int start, num; 515 | 516 | start = 0; 517 | num = opts[CLOP_LD_RNG1].num; 518 | if (opts[CLOP_LDID].set) 519 | start = opts[CLOP_LDID].u16; 520 | 521 | fmapi_fill_mcc_set_alloc(&sub, start, num, (__u64*)opts[CLOP_LD_RNG1].buf, (__u64*)opts[CLOP_LD_RNG2].buf); 522 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 523 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 524 | } 525 | break; 526 | 527 | case CLCM_SET_QOS_ALLOCATED: 528 | { 529 | int start, num; 530 | 531 | num = opts[CLOP_QOS_ALLOCATED].num; 532 | start = 0; 533 | 534 | if (opts[CLOP_LDID].set) 535 | start = opts[CLOP_LDID].u16; 536 | 537 | if (!opts[CLOP_QOS_ALLOCATED].set) 538 | goto end; 539 | 540 | fmapi_fill_mcc_set_qos_alloc(&sub, start, num, opts[CLOP_QOS_ALLOCATED].buf); 541 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 542 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 543 | } 544 | break; 545 | 546 | case CLCM_SET_QOS_CONTROL: 547 | { 548 | int epc, ttr, mod, sev, si, rcb, ci; 549 | 550 | epc = 0; 551 | ttr = 0; 552 | mod = 0; 553 | sev = 0; 554 | si = 0; 555 | rcb = 0; 556 | ci = 0; 557 | 558 | if (opts[CLOP_CONGEST_ENABLE].set) 559 | epc = 1; 560 | 561 | if (opts[CLOP_TEMP_THROTTLE].set) 562 | ttr = 1; 563 | 564 | if (opts[CLOP_EGRESS_MOD_PCNT].set) 565 | mod = opts[CLOP_EGRESS_MOD_PCNT].u8; 566 | 567 | if (opts[CLOP_EGRESS_SEV_PCNT].set) 568 | sev = opts[CLOP_EGRESS_SEV_PCNT].u8; 569 | 570 | if (opts[CLOP_BP_SAMPLE_INTVL].set) 571 | si = opts[CLOP_BP_SAMPLE_INTVL].u8; 572 | 573 | if (opts[CLOP_REQCMPBASIS].set) 574 | rcb = opts[CLOP_REQCMPBASIS].u16; 575 | 576 | if (opts[CLOP_CCINTERVAL].set) 577 | ci = opts[CLOP_CCINTERVAL].u8; 578 | 579 | fmapi_fill_mcc_set_qos_ctrl(&sub, epc, ttr, mod, sev, si, rcb, ci); 580 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 581 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 582 | } 583 | break; 584 | 585 | case CLCM_SET_QOS_LIMIT: 586 | { 587 | int start, num; 588 | 589 | num = opts[CLOP_QOS_LIMIT].num; 590 | start = 0; 591 | 592 | if (opts[CLOP_LDID].set) 593 | start = opts[CLOP_LDID].u16; 594 | 595 | if (!opts[CLOP_QOS_LIMIT].set) 596 | goto end; 597 | 598 | fmapi_fill_mcc_set_qos_limit(&sub, start, num, opts[CLOP_QOS_LIMIT].buf); 599 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 600 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 601 | } 602 | break; 603 | 604 | case CLCM_SHOW_BOS: 605 | { 606 | fmapi_fill_isc_bos(&msg); 607 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 608 | } 609 | break; 610 | 611 | case CLCM_SHOW_IDENTITY: 612 | { 613 | fmapi_fill_isc_id(&msg); 614 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 615 | } 616 | break; 617 | 618 | case CLCM_SHOW_MSG_LIMIT: 619 | { 620 | fmapi_fill_isc_get_msg_limit(&msg); 621 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 622 | } 623 | break; 624 | 625 | case CLCM_SHOW_PORT: 626 | { 627 | if (opts[CLOP_PPID].set) 628 | { 629 | if (opts[CLOP_PPID].num > 0) 630 | fmapi_fill_psc_get_ports(&msg, opts[CLOP_PPID].num, opts[CLOP_PPID].buf); 631 | else 632 | fmapi_fill_psc_get_port(&msg, opts[CLOP_PPID].u8); 633 | } 634 | else if (opts[CLOP_ALL].set) 635 | fmapi_fill_psc_get_all_ports(&msg); 636 | else 637 | goto end; 638 | 639 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 640 | } 641 | break; 642 | 643 | case CLCM_SHOW_LD_ALLOCATIONS: 644 | { 645 | fmapi_fill_mcc_get_alloc(&sub, 0, 0); 646 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 647 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 648 | } 649 | break; 650 | 651 | case CLCM_SHOW_LD_INFO: 652 | { 653 | fmapi_fill_mcc_get_info(&sub); 654 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 655 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 656 | } 657 | break; 658 | 659 | case CLCM_SHOW_QOS_ALLOCATED: 660 | { 661 | __u8 num, start; 662 | 663 | num = 255; 664 | start = 0; 665 | 666 | if (opts[CLOP_NUM].set) 667 | num = opts[CLOP_NUM].u8; 668 | 669 | if (opts[CLOP_LDID].set) 670 | start = opts[CLOP_LDID].u16; 671 | 672 | fmapi_fill_mcc_get_qos_alloc(&sub, start, num); 673 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 674 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 675 | } 676 | break; 677 | 678 | case CLCM_SHOW_QOS_CONTROL: 679 | { 680 | fmapi_fill_mcc_get_qos_ctrl(&sub); 681 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 682 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 683 | } 684 | break; 685 | 686 | case CLCM_SHOW_QOS_LIMIT: 687 | { 688 | __u8 num, start; 689 | 690 | num = 255; 691 | start = 0; 692 | 693 | if (opts[CLOP_NUM].set) 694 | num = opts[CLOP_NUM].u8; 695 | 696 | if (opts[CLOP_LDID].set) 697 | start = opts[CLOP_LDID].u16; 698 | 699 | fmapi_fill_mcc_get_qos_limit(&sub, start, num); 700 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 701 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 702 | } 703 | break; 704 | 705 | case CLCM_SHOW_QOS_STATUS: 706 | { 707 | fmapi_fill_mcc_get_qos_status(&sub); 708 | fmapi_fill_mpc_tmc(&msg, opts[CLOP_PPID].u8, MCMT_CXLCCI, &sub); 709 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 710 | } 711 | break; 712 | 713 | case CLCM_SHOW_SWITCH: 714 | { 715 | fmapi_fill_psc_id(&msg); 716 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 717 | } 718 | break; 719 | 720 | case CLCM_SHOW_DEV: 721 | { 722 | int a = 0; 723 | int b = 0; 724 | 725 | if (opts[CLOP_DEVICE].set) { 726 | a = 1; 727 | b = opts[CLOP_DEVICE].u8; 728 | } 729 | 730 | if (opts[CLOP_ALL].set) { 731 | a = 0; 732 | } 733 | 734 | emapi_fill_listdev(&em, a, b); 735 | ma = submit_emapi(m, &em, 0, user_data, NULL, NULL, NULL); 736 | } 737 | break; 738 | 739 | case CLCM_SHOW_VCS: 740 | { 741 | int vcsid = 0; 742 | 743 | if (opts[CLOP_VCSID].set) 744 | vcsid = opts[CLOP_VCSID].u8; 745 | 746 | fmapi_fill_vsc_get_vcs(&msg, vcsid, 0, 255); 747 | ma = submit_fmapi(m, &msg, 0, user_data, NULL, NULL, NULL); 748 | } 749 | break; 750 | 751 | default: 752 | goto end; 753 | } 754 | 755 | end: 756 | 757 | EXIT(0); 758 | 759 | return ma; 760 | } 761 | 762 | -------------------------------------------------------------------------------- /fmapi_handler.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | /** 3 | * @file jack.c 4 | * 5 | * @brief Code file for FM API over TCP CLI 6 | * 7 | * @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved. 8 | * 9 | * @date Jan 2024 10 | * @author Barrett Edwards 11 | * 12 | */ 13 | /* INCLUDES ==================================================================*/ 14 | 15 | /* gettid() 16 | */ 17 | #define _GNU_SOURCE 18 | 19 | #include 20 | 21 | /* printf() 22 | */ 23 | #include 24 | 25 | /* memset() 26 | */ 27 | #include 28 | 29 | #include 30 | 31 | /* autl_prnt_buf() 32 | */ 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /* mctp_init() 41 | * mctp_set_mh() 42 | * mctp_run() 43 | */ 44 | #include 45 | 46 | #include "fmapi_handler.h" 47 | #include "options.h" 48 | 49 | /* MACROS ====================================================================*/ 50 | 51 | #ifdef JACK_VERBOSE 52 | #define INIT unsigned step = 0; 53 | #define ENTER if (m->verbose & MCTP_VERBOSE_THREADS) printf("%d:%s Enter\n", gettid(), __FUNCTION__); 54 | #define STEP step++; if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step); 55 | #define HEX32(k, i) if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, k, i); 56 | #define INT32(k, i) if (m->verbose & MCTP_VERBOSE_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, k, i); 57 | #define ERR32(k, i) if (m->verbose & MCTP_VERBOSE_ERROR) printf("%d:%s STEP: %u ERR: %s: %d\n", gettid(), __FUNCTION__, step, k, i); 58 | #define EXIT(rc) if (m->verbose & MCTP_VERBOSE_THREADS) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc); 59 | #else 60 | #define INIT 61 | #define ENTER 62 | #define STEP 63 | #define HEX32(k, i) 64 | #define INT32(k, i) 65 | #define ERR32(k, i) 66 | #define EXIT(rc) 67 | #endif // JACK_VERBOSE 68 | 69 | /* ENUMERATIONS ==============================================================*/ 70 | 71 | /* STRUCTS ===================================================================*/ 72 | 73 | /* PROTOTYPES ================================================================*/ 74 | 75 | /* GLOBAL VARIABLES ==========================================================*/ 76 | 77 | /* FUNCTIONS =================================================================*/ 78 | 79 | //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 80 | //# @ Port State Type LD Ver CXL Ver MLW NLW MLS CLS Dev Speeds LTSSM Ln Flags 81 | //=== = ========== ==== == === ========== === === === === ========== ========== == ======== 82 | //0 + USP T1 - 1.1 A--------- 16 16 5.0 - 12345----- L0 0 LRPC---- 83 | //1 + DSP T3 16 2.0 AB-------- 16 8 5.0 - --345----- L0 0 --PC---- 84 | //2 + Unbound T3 - 3.0 ABC------- 16 8 5.0 - ---456---- Disabled 0 --P----- 85 | //3 - - - - - - 16 - 5.0 - ---------- Detect 0 -------- 86 | 87 | struct col 88 | { 89 | int width; 90 | char *title; 91 | }; 92 | 93 | struct col cols[] = 94 | { 95 | {3, "#"}, 96 | {1, "@"}, 97 | {10, "Port State"}, 98 | {6, "Type"}, 99 | {2, "LD"}, 100 | {3, "Ver"}, 101 | {8, "CXL Ver"}, 102 | {3, "MLW"}, 103 | {3, "NLW"}, 104 | {3, "MLS"}, 105 | {3, "CLS"}, 106 | {8, "Speeds"}, 107 | {8, "LTSSM"}, 108 | {2, "LN"}, 109 | {16, "Flags"}, 110 | {0,0} 111 | }; 112 | 113 | #define SHOW_PORT_BUF_LEN 110 114 | void print_ports(struct fmapi_psc_port_rsp *o) 115 | { 116 | int i, k; 117 | struct fmapi_psc_port_info *p; 118 | char buf[SHOW_PORT_BUF_LEN+1]; 119 | struct col *col; 120 | 121 | memset(buf, ' ', SHOW_PORT_BUF_LEN); 122 | buf[SHOW_PORT_BUF_LEN] = 0; 123 | 124 | // Print header 125 | { 126 | col = &cols[0]; 127 | i = 0; 128 | 129 | while (col->width != 0) 130 | { 131 | memcpy(&buf[i], col->title, strlen(col->title)); 132 | i += (col->width + 2); 133 | col++; 134 | } 135 | buf[i] = 0; 136 | printf("%s\n", buf); 137 | } 138 | 139 | // Reset buffer 140 | memset(buf, ' ', SHOW_PORT_BUF_LEN); 141 | 142 | // Print header line 143 | { 144 | col = &cols[0]; 145 | i = 0; 146 | 147 | while (col->width != 0) 148 | { 149 | memset(&buf[i], '-', col->width); 150 | i += (col->width + 2); 151 | col++; 152 | } 153 | buf[i] = 0; 154 | printf("%s\n", buf); 155 | } 156 | 157 | // Print port rows 158 | 159 | for ( int j = 0 ; j < o->num ; j++ ) 160 | { 161 | p = &o->list[j]; 162 | i = 0; 163 | k = 0; 164 | 165 | // Reset buffer 166 | memset(buf, ' ', SHOW_PORT_BUF_LEN); 167 | buf[SHOW_PORT_BUF_LEN] = 0; 168 | 169 | // COL 0: Port number 170 | sprintf(&buf[i], "%d", p->ppid); 171 | i += (cols[k++].width + 2); 172 | 173 | // COL 1: Present bit 174 | if (p->prsnt) 175 | buf[i] = '+'; 176 | else 177 | buf[i] = '-'; 178 | i += (cols[k++].width + 2); 179 | 180 | // COL 2: Port state 181 | //if (!p->prsnt) 182 | // sprintf(&buf[i], "-"); 183 | //else 184 | sprintf(&buf[i], "%s", fmps(p->state)); 185 | i += (cols[k++].width + 2); 186 | 187 | // COL 3: Type 188 | if (!p->prsnt) 189 | sprintf(&buf[i], "-"); 190 | else 191 | sprintf(&buf[i], "%s", fmdt(p->dt)); 192 | i += (cols[k++].width + 2); 193 | 194 | // COL 4: LD 195 | if (!p->prsnt || (p->dt != FMDT_CXL_TYPE_3 && p->dt != FMDT_CXL_TYPE_3_POOLED) ) 196 | sprintf(&buf[i], "-"); 197 | else 198 | sprintf(&buf[i], "%d", p->num_ld); 199 | i += (cols[k++].width + 2); 200 | 201 | // COL 5: Ver 202 | if (!p->prsnt) 203 | sprintf(&buf[i], "-"); 204 | else 205 | sprintf(&buf[i], "%s", fmdv(p->dv)); 206 | i += (cols[k++].width + 2); 207 | 208 | // COL 6: CXL Versions 209 | if (!p->prsnt) 210 | sprintf(&buf[i], "-"); 211 | else 212 | { 213 | char c = 'A'; 214 | for ( int v = 0 ; v < 8 ; v++ ) 215 | { 216 | if ((p->cv >> v) & 0x01) 217 | buf[i+v] = c; 218 | else 219 | buf[i+v] = ' '; 220 | c++; 221 | } 222 | } 223 | i += (cols[k++].width + 2); 224 | 225 | // COL 7: MLW 226 | sprintf(&buf[i], "%d", p->mlw); 227 | i += (cols[k++].width + 2); 228 | 229 | // COL 8: NLW 230 | if (!p->prsnt) 231 | sprintf(&buf[i], "-"); 232 | else 233 | { 234 | if (p->nlw == 0) 235 | sprintf(&buf[i], "%d", p->mlw); 236 | else 237 | sprintf(&buf[i], "%d", p->nlw); 238 | } 239 | i += (cols[k++].width + 2); 240 | 241 | // COL 9: MLS 242 | sprintf(&buf[i], "%s", fmms(p->mls)); 243 | i += (cols[k++].width + 2); 244 | 245 | // COL 10: CLS 246 | if (!p->prsnt) 247 | sprintf(&buf[i], "-"); 248 | else 249 | sprintf(&buf[i], "%s", fmms(p->cls)); 250 | i += (cols[k++].width + 2); 251 | 252 | // COL 11: Dev Speeds 253 | if (!p->prsnt) 254 | sprintf(&buf[i], "-"); 255 | else 256 | { 257 | char c = '1'; 258 | for ( int v = 0 ; v < 8 ; v++ ) 259 | { 260 | if ((p->speeds >> v) & 0x01) 261 | buf[i+v] = c; 262 | else 263 | buf[i+v] = ' '; 264 | c++; 265 | } 266 | } 267 | i += (cols[k++].width + 2); 268 | 269 | // COL 12: LTSSM 270 | if (!p->prsnt) 271 | sprintf(&buf[i], "-"); 272 | else 273 | sprintf(&buf[i], "%s", fmls(p->ltssm)); 274 | i += (cols[k++].width + 2); 275 | 276 | // COL 13: First Lane 277 | if (!p->prsnt) 278 | sprintf(&buf[i], "-"); 279 | else 280 | sprintf(&buf[i], "%d", p->lane); 281 | i += (cols[k++].width + 2); 282 | 283 | // COL 14: Flags 284 | if (p->lane_rev) 285 | buf[i+0] = 'L'; 286 | if (p->perst) 287 | buf[i+1] = 'R'; 288 | if (p->prsnt) 289 | buf[i+2] = 'P'; 290 | if (p->pwrctrl) 291 | buf[i+3] = 'W'; 292 | i += (cols[k++].width + 2); 293 | 294 | // Unset null termination zeros 295 | for ( int k = 0 ; k < SHOW_PORT_BUF_LEN ; k++) 296 | { 297 | if (buf[k] == 0) 298 | buf[k] = ' '; 299 | } 300 | buf[SHOW_PORT_BUF_LEN] = 0; 301 | 302 | printf("%s\n", buf); 303 | } 304 | } 305 | 306 | /** 307 | * Handle Responses of Tunneled CXL FM API MLD Component Command Set Messages 308 | * 309 | * @return 0 upon success. Non zero otherwise. 310 | * 311 | * STEPS 312 | * 1: Set buffer pointers 313 | * 2: Deserialize Header 314 | * 3: Verify Response 315 | * 4: Deserialize Object 316 | * 5: Handle opcode 317 | */ 318 | int cci_handler(struct mctp *m, __u8 *payload) 319 | { 320 | INIT 321 | struct fmapi_msg msg; 322 | int rv; 323 | 324 | ENTER 325 | 326 | // Initialize variables 327 | rv = 1; 328 | 329 | STEP // 1: Set buffer pointers 330 | msg.buf = (struct fmapi_buf*) payload; 331 | 332 | STEP // 2: Deserialize Header 333 | fmapi_deserialize(&msg.hdr, msg.buf->hdr, FMOB_HDR, NULL); 334 | 335 | STEP // 3: Verify Response 336 | 337 | // Verify msg category 338 | if (msg.hdr.category != FMMT_RESP) 339 | { 340 | printf("Error: Received a tunneled FM API message that was not a response: %s\n", fmmt(msg.hdr.category)); 341 | rv = 1; 342 | goto end; 343 | } 344 | 345 | // Verify msg return code 346 | if (msg.hdr.return_code != FMRC_SUCCESS && msg.hdr.return_code != FMRC_BACKGROUND_OP_STARTED) 347 | { 348 | printf("Error: %s\n", fmrc(msg.hdr.return_code)); 349 | rv = msg.hdr.return_code; 350 | goto end; 351 | } 352 | 353 | STEP // 4: Deserialize Object 354 | fmapi_deserialize(&msg.obj, msg.buf->payload, fmapi_fmob_rsp(msg.hdr.opcode), NULL); 355 | 356 | STEP // 5: Handle opcode 357 | switch(msg.hdr.opcode) 358 | { 359 | case FMOP_MCC_INFO: 360 | { 361 | struct fmapi_mcc_info_rsp *o = &msg.obj.mcc_info_rsp; 362 | double size; 363 | 364 | size = msg.obj.mcc_info_rsp.size / (double) (1024*1024*1024); 365 | 366 | printf("Memory Size : 0x%llx - %.1f GiB\n", o->size, size); 367 | printf("LD Count : %d\n", o->num); 368 | printf("QoS: Port Congestion : %d\n", o->epc); 369 | printf("QoS: Temporary BW Reduction : %d\n", o->ttr); 370 | } 371 | break; 372 | 373 | case FMOP_MCC_ALLOC_GET: 374 | { 375 | struct fmapi_mcc_alloc_get_rsp *o = &msg.obj.mcc_alloc_get_rsp; 376 | 377 | printf("Total LDs on Device: %u\n", o->total); 378 | printf("Memory Granularity : %d - %s\n", o->granularity, fmmg(o->granularity)); 379 | printf("Start LD ID of list: %u\n", o->start); 380 | printf("Num LDs in list : %u\n", o->num); 381 | printf("\n"); 382 | printf("LDID Range1 Range2\n"); 383 | printf("---- ------------------ ------------------\n"); 384 | for ( int i = 0 ; i < o->num ; i++) { 385 | printf("%4d: 0x%016llx 0x%016llx\n", i+o->start, o->list[i].rng1, o->list[i].rng2); 386 | } 387 | } 388 | break; 389 | 390 | case FMOP_MCC_ALLOC_SET: 391 | { 392 | struct fmapi_mcc_alloc_set_rsp *o = &msg.obj.mcc_alloc_set_rsp; 393 | 394 | printf("Number of LDs : %u\n", o->num); 395 | printf("Starting LD ID : %u\n", o->start); 396 | printf("\n"); 397 | printf("LDID Range1 Range2\n"); 398 | printf("---- ------------------ ------------------\n"); 399 | for ( int i = 0 ; i < o->num ; i++) { 400 | printf("%4d: 0x%016llx 0x%016llx\n", i+o->start, o->list[i].rng1, o->list[i].rng2); 401 | } 402 | } 403 | break; 404 | 405 | case FMOP_MCC_QOS_CTRL_GET: 406 | case FMOP_MCC_QOS_CTRL_SET: 407 | { 408 | struct fmapi_mcc_qos_ctrl *o = &msg.obj.mcc_qos_ctrl; 409 | 410 | printf("Port Congestion : %d\n", o->epc_en); 411 | printf("Temporary BW Reduction : %d\n", o->ttr_en); 412 | printf("Egress Moderage Pcnt : %d\n", o->egress_mod_pcnt); 413 | printf("Egress Severe Pcnt : %d\n", o->egress_sev_pcnt); 414 | printf("Backpressure Sample Interval : %d\n", o->sample_interval); 415 | printf("ReqCmpBasis : %d\n", o->rcb); 416 | printf("Completion Collection Internal : %d\n", o->comp_interval); 417 | } 418 | break; 419 | 420 | case FMOP_MCC_QOS_STAT: 421 | { 422 | struct fmapi_mcc_qos_stat_rsp *o = &msg.obj.mcc_qos_stat_rsp; 423 | 424 | printf("Backpressure Avg Pcnt : %d\n", o->bp_avg_pcnt); 425 | } 426 | break; 427 | 428 | case FMOP_MCC_QOS_BW_ALLOC_GET: 429 | case FMOP_MCC_QOS_BW_ALLOC_SET: 430 | { 431 | struct fmapi_mcc_qos_bw_alloc *o = &msg.obj.mcc_qos_bw_alloc; 432 | 433 | printf("LDID Val PCNT\n"); 434 | printf("---- ---------- ------\n"); 435 | for (int i = 0 ; i < o->num ; i++ ){ 436 | printf("%4d: %4d / 256 %5.1f%%\n", i+o->start, o->list[i], 100.0 * ((double)o->list[i])/256.0); 437 | } 438 | } 439 | break; 440 | 441 | case FMOP_MCC_QOS_BW_LIMIT_GET: 442 | case FMOP_MCC_QOS_BW_LIMIT_SET: 443 | { 444 | struct fmapi_mcc_qos_bw_limit *o = &msg.obj.mcc_qos_bw_limit; 445 | 446 | printf("LDID Val PCNT\n"); 447 | printf("---- ---------- ------\n"); 448 | for (int i = 0 ; i < o->num ; i++ ){ 449 | printf("%4d: %4d / 256 %5.1f%%\n", i+o->start, o->list[i], 100.0 * ((double)o->list[i])/256.0); 450 | } 451 | } 452 | break; 453 | 454 | default: rv = 1; break; 455 | } 456 | 457 | rv = 0; 458 | 459 | end: 460 | 461 | EXIT(rv); 462 | 463 | return rv; 464 | } 465 | 466 | /** 467 | * Handle Responses of Tunneled CXL FM API MLD Component Command Set Messages 468 | * 469 | * @return 0 upon success. Non zero otherwise. 470 | * 471 | * STEPS 472 | * 1: Set buffer pointers 473 | * 2: Deserialize Header 474 | * 3: Verify Response 475 | * 4: Deserialize Object 476 | * 5: Handle opcode 477 | */ 478 | int cci_update(struct mctp *m, unsigned ppid, __u8 *payload) 479 | { 480 | INIT 481 | struct fmapi_msg msg; 482 | struct cxl_port *p; 483 | struct cxl_mld *mld; 484 | int rv; 485 | 486 | ENTER 487 | 488 | // Initialize variables 489 | rv = 1; 490 | 491 | STEP // 1: Set buffer pointers 492 | msg.buf = (struct fmapi_buf*) payload; 493 | p = &cxls->ports[ppid]; 494 | mld = p->mld; 495 | 496 | STEP // 2: Deserialize Header 497 | fmapi_deserialize(&msg.hdr, msg.buf->hdr, FMOB_HDR, NULL); 498 | 499 | STEP // 3: Verify Response 500 | 501 | // Verify msg category 502 | if (msg.hdr.category != FMMT_RESP) 503 | { 504 | printf("Error: Received a tunneled FM API message that was not a response: %s\n", fmmt(msg.hdr.category)); 505 | rv = 1; 506 | goto end; 507 | } 508 | 509 | // Verify msg return code 510 | if (msg.hdr.return_code != FMRC_SUCCESS && msg.hdr.return_code != FMRC_BACKGROUND_OP_STARTED) 511 | { 512 | printf("Error: %s\n", fmrc(msg.hdr.return_code)); 513 | rv = msg.hdr.return_code; 514 | goto end; 515 | } 516 | 517 | STEP // 4: Deserialize Object 518 | fmapi_deserialize(&msg.obj, msg.buf->payload, fmapi_fmob_rsp(msg.hdr.opcode), NULL); 519 | 520 | STEP // 5: Handle opcode 521 | switch(msg.hdr.opcode) 522 | { 523 | case FMOP_MCC_INFO: 524 | { 525 | struct fmapi_mcc_info_rsp *o = &msg.obj.mcc_info_rsp; 526 | 527 | // Allocate memory for MLD object in the port if needed 528 | if (p->mld == NULL) 529 | { 530 | p->mld = calloc(1, sizeof(struct cxl_mld)); 531 | mld = p->mld; 532 | } 533 | mld->memory_size = o->size; 534 | mld->num = o->num; 535 | p->ld = o->num; 536 | mld->epc = o->epc; 537 | mld->ttr = o->ttr; 538 | 539 | // Allocate memory for the PCI Config Space for each LD if needed 540 | for (int i = 0 ; i < o->num ; i++) 541 | if (mld->cfgspace[i] == NULL) 542 | mld->cfgspace[i] = calloc(1, sizeof(PCLN_CFG)); 543 | } 544 | break; 545 | 546 | case FMOP_MCC_ALLOC_GET: 547 | { 548 | struct fmapi_mcc_alloc_get_rsp *o = &msg.obj.mcc_alloc_get_rsp; 549 | 550 | mld->granularity = o->granularity; 551 | for ( int i = 0 ; i < o->num ; i++ ) 552 | { 553 | mld->rng1[i+o->start] = o->list[i].rng1; 554 | mld->rng2[i+o->start] = o->list[i].rng2; 555 | } 556 | } 557 | break; 558 | 559 | case FMOP_MCC_ALLOC_SET: 560 | { 561 | struct fmapi_mcc_alloc_set_rsp *o = &msg.obj.mcc_alloc_set_rsp; 562 | 563 | for ( int i = 0 ; i < o->num ; i++) 564 | { 565 | mld->rng1[i+o->start] = o->list[i].rng1; 566 | mld->rng2[i+o->start] = o->list[i].rng2; 567 | } 568 | } 569 | break; 570 | 571 | case FMOP_MCC_QOS_CTRL_GET: 572 | case FMOP_MCC_QOS_CTRL_SET: 573 | { 574 | struct fmapi_mcc_qos_ctrl *o = &msg.obj.mcc_qos_ctrl; 575 | mld->epc_en = o->epc_en; 576 | mld->ttr_en = o->ttr_en; 577 | mld->egress_mod_pcnt = o->egress_mod_pcnt; 578 | mld->egress_sev_pcnt = o->egress_sev_pcnt; 579 | mld->sample_interval = o->sample_interval; 580 | mld->rcb = o->rcb; 581 | mld->comp_interval = o->comp_interval; 582 | } 583 | break; 584 | 585 | case FMOP_MCC_QOS_STAT: 586 | { 587 | struct fmapi_mcc_qos_stat_rsp *o = &msg.obj.mcc_qos_stat_rsp; 588 | 589 | mld->bp_avg_pcnt = o->bp_avg_pcnt; 590 | } 591 | break; 592 | 593 | case FMOP_MCC_QOS_BW_ALLOC_GET: 594 | case FMOP_MCC_QOS_BW_ALLOC_SET: 595 | { 596 | struct fmapi_mcc_qos_bw_alloc *o = &msg.obj.mcc_qos_bw_alloc; 597 | 598 | for ( int i = 0 ; i < o->num ; i++ ) 599 | mld->alloc_bw[i+o->start] = o->list[i]; 600 | } 601 | break; 602 | 603 | case FMOP_MCC_QOS_BW_LIMIT_GET: 604 | case FMOP_MCC_QOS_BW_LIMIT_SET: 605 | { 606 | struct fmapi_mcc_qos_bw_limit *o = &msg.obj.mcc_qos_bw_limit; 607 | 608 | for ( int i = 0 ; i < o->num ; i++ ) 609 | mld->bw_limit[i+o->start] = o->list[i]; 610 | } 611 | break; 612 | 613 | default: rv = 1; break; 614 | } 615 | 616 | rv = 0; 617 | 618 | end: 619 | 620 | EXIT(rv); 621 | 622 | return rv; 623 | } 624 | 625 | /** 626 | * Handle Responses to FM API Messages 627 | * 628 | * @return 0 upon success. Non zero otherwise. 629 | * 630 | * STEPS: 631 | * 1: Set buffer pointers 632 | * 2: Deserialize Request Header 633 | * 3: Deserialize Request Object 634 | * 4: Deserialize Response Header 635 | * 5: Verify Response 636 | * 6: Deserialize Response Payload using object from request 637 | * 7: Handle opcode 638 | */ 639 | int fmapi_handler(struct mctp *m, struct mctp_msg *mr, struct mctp_msg *mm) 640 | { 641 | INIT 642 | int rv; 643 | struct fmapi_msg req, rsp; 644 | 645 | ENTER 646 | 647 | // Initialize varialbes 648 | rv = 1; 649 | 650 | STEP // 1: Set buffer pointers 651 | req.buf = (struct fmapi_buf*) mm->payload; 652 | rsp.buf = (struct fmapi_buf*) mr->payload; 653 | 654 | STEP // 2: Deserialize Request Header 655 | fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL); 656 | 657 | STEP // 3: Deserialize Request Object 658 | fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL); 659 | 660 | STEP // 4: Deserialize Response Header 661 | fmapi_deserialize(&rsp.hdr, rsp.buf->hdr, FMOB_HDR, NULL); 662 | 663 | STEP // 5: Verify Response 664 | 665 | // Verify msg category 666 | if (rsp.hdr.category != FMMT_RESP) 667 | { 668 | printf("Error: Received an FM API message that was not a response: %s\n", fmmt(rsp.hdr.category)); 669 | goto end; 670 | } 671 | 672 | // Verify return code 673 | if (rsp.hdr.return_code != FMRC_SUCCESS && rsp.hdr.return_code != FMRC_BACKGROUND_OP_STARTED) 674 | { 675 | printf("Error: %s\n", fmrc(rsp.hdr.return_code)); 676 | rv = rsp.hdr.return_code; 677 | goto end; 678 | } 679 | 680 | STEP // 6: Deserialize Response Payload using object from request 681 | fmapi_deserialize(&rsp.obj, rsp.buf->payload, fmapi_fmob_rsp(rsp.hdr.opcode), &req.obj); 682 | 683 | STEP // 7: Handle opcode 684 | switch(rsp.hdr.opcode) 685 | { 686 | case FMOP_ISC_BOS: 687 | { 688 | struct fmapi_isc_bos *o = &rsp.obj.isc_bos; 689 | 690 | printf("Show Background Operation Status:\n"); 691 | printf("Background Op. Running: %d\n", o->running); 692 | printf("Percent Complete: %d%%\n", o->pcnt); 693 | printf("Command Opcode: 0x%04x - %s\n", o->opcode, fmop(rsp.hdr.opcode)); 694 | printf("Return Code: 0x%04x - %s\n", o->rc, fmrc(o->rc)); 695 | printf("Vendor Specific Status: 0x%04x\n", o->ext); 696 | } 697 | break; 698 | 699 | case FMOP_ISC_ID: 700 | { 701 | struct fmapi_isc_id_rsp *o = &rsp.obj.isc_id_rsp; 702 | 703 | printf("Show Identity:\n"); 704 | printf("PCIe Vendor ID: 0x%04x\n", o->vid); 705 | printf("PCIe Device ID: 0x%04x\n", o->did); 706 | printf("PCIe Subsystem Vendor ID: 0x%04x\n", o->svid); 707 | printf("PCIe Subsystem ID: 0x%04x\n", o->ssid); 708 | printf("SN: 0x%016llx\n", o->sn); 709 | printf("Max Msg Size n of 2^n: %d - %d B\n", o->size, 1 << o->size); 710 | } 711 | break; 712 | 713 | case FMOP_ISC_MSG_LIMIT_GET: 714 | case FMOP_ISC_MSG_LIMIT_SET: 715 | { 716 | struct fmapi_isc_msg_limit *o = &rsp.obj.isc_msg_limit; 717 | 718 | printf("Response Msg Limit (n of 2^n): %d - %d B\n", o->limit, 1 << o->limit); 719 | } 720 | break; 721 | 722 | case FMOP_PSC_ID: 723 | { 724 | struct fmapi_psc_id_rsp *o = &rsp.obj.psc_id_rsp; 725 | int active_ports, active_vcss; 726 | 727 | // Count number of active ports 728 | active_ports = 0; 729 | for ( int i = 0 ; i < 32 ; i++) 730 | for ( int k = 0 ; k < 8 ; k++ ) 731 | if ((o->active_ports[i] >> k) & 0x01) 732 | active_ports++; 733 | 734 | // Count number of active vcss 735 | active_vcss = 0; 736 | for ( int i = 0 ; i < 32 ; i++) 737 | for ( int k = 0 ; k < 8 ; k++ ) 738 | if ((o->active_vcss[i] >> k) & 0x01) 739 | active_vcss++; 740 | 741 | printf("Show Switch:\n"); 742 | printf("Ingress Port ID : %d\n", o->ingress_port); 743 | printf("Num Physical Ports : %u\n", o->num_ports); 744 | printf("Active Physical Ports : %u\n", active_ports); 745 | printf("Num VCSs : %u\n", o->num_vcss); 746 | printf("Active VCSs : %u\n", active_vcss); 747 | printf("Num VPPBs : %u\n", o->num_vppbs); 748 | printf("Num Active VPPBs : %u\n", o->active_vppbs); 749 | printf("Num HDM Decoders : %u\n", o->num_decoders); 750 | } 751 | break; 752 | 753 | case FMOP_PSC_PORT: 754 | { 755 | struct fmapi_psc_port_rsp *o = &rsp.obj.psc_port_rsp; 756 | print_ports(o); 757 | } 758 | break; 759 | 760 | case FMOP_PSC_PORT_CTRL: 761 | { 762 | // Nothing to do upon success 763 | } 764 | break; 765 | 766 | case FMOP_PSC_CFG: 767 | { 768 | struct fmapi_psc_cfg_rsp *o = &rsp.obj.psc_cfg_rsp; 769 | printf("Data: 0x%02x%02x%02x%02x\n", o->data[3], o->data[2], o->data[1], o->data[0]); 770 | } 771 | break; 772 | 773 | case FMOP_VSC_INFO: 774 | { 775 | struct fmapi_vsc_info_rsp *o = &rsp.obj.vsc_info_rsp; 776 | struct fmapi_vsc_info_blk *v; 777 | struct fmapi_vsc_ppb_stat_blk *b; 778 | int i, k; 779 | 780 | printf("Show VCS:\n"); 781 | 782 | for ( i = 0 ; i < o->num ; i++ ) 783 | { 784 | v = &o->list[i]; 785 | 786 | if ( i > 0 ) 787 | printf("\n"); 788 | 789 | printf("VCS ID : %d\n", v->vcsid); 790 | printf("State : %s\n", fmvs(v->state)); 791 | printf("USP ID : %d\n", v->uspid); 792 | printf("vPPBs : %d\n", v->num); 793 | printf("\n"); 794 | printf("vPPB PPID LDID Status\n"); 795 | printf("---- ---- ---- -----------\n"); 796 | for ( k = 0 ; k < v->num ; k++) 797 | { 798 | b = &v->list[k]; 799 | printf("%4d: ", k); 800 | switch(b->status) 801 | { 802 | case FMBS_UNBOUND: 803 | printf(" - "); 804 | printf(" - "); 805 | printf("%s", fmbs(b->status)); 806 | break; 807 | 808 | case FMBS_INPROGRESS: 809 | printf(" ? "); 810 | printf(" ? "); 811 | printf("%s", fmbs(b->status)); 812 | break; 813 | 814 | case FMBS_BOUND_PORT: 815 | printf("%4d ", b->ppid); 816 | printf(" - "); 817 | printf("%s", fmbs(b->status)); 818 | break; 819 | 820 | case FMBS_BOUND_LD: 821 | printf("%4d ", b->ppid); 822 | printf("%4d ", b->ldid); 823 | printf("%s", fmbs(b->status)); 824 | break; 825 | 826 | default: 827 | break; 828 | } 829 | printf("\n"); 830 | } 831 | } 832 | } 833 | break; 834 | 835 | case FMOP_VSC_BIND: 836 | { 837 | if (rsp.hdr.return_code == FMRC_BACKGROUND_OP_STARTED) 838 | { 839 | //printf("Bind operation started in the background\n"); 840 | } 841 | } 842 | break; 843 | 844 | case FMOP_VSC_UNBIND: 845 | { 846 | if (rsp.hdr.return_code == FMRC_BACKGROUND_OP_STARTED) 847 | { 848 | //printf("Unbind operation started in the background\n"); 849 | } 850 | } 851 | break; 852 | 853 | case FMOP_VSC_AER: 854 | break; 855 | 856 | case FMOP_MPC_TMC: 857 | { 858 | struct fmapi_mpc_tmc_rsp *o = &rsp.obj.mpc_tmc_rsp; 859 | 860 | if (o->type != MCMT_CXLCCI) 861 | { 862 | printf("Error: Tunneled command had incorrect MCTP Message Type: 0x%02x\n", o->type); 863 | goto end; 864 | } 865 | 866 | rv = cci_handler(m, o->msg); 867 | } 868 | break; 869 | 870 | case FMOP_MPC_CFG: 871 | { 872 | struct fmapi_mpc_cfg_rsp *o = &rsp.obj.mpc_cfg_rsp; 873 | printf("Data: 0x%02x%02x%02x%02x\n", o->data[0], o->data[1], o->data[2], o->data[3]); 874 | } 875 | break; 876 | 877 | case FMOP_MPC_MEM: 878 | { 879 | struct fmapi_mpc_mem_rsp *o = &rsp.obj.mpc_mem_rsp; 880 | autl_prnt_buf(o->data, o->len, 4, 0); 881 | } 882 | break; 883 | 884 | default: 885 | goto end; 886 | } 887 | 888 | rv = 0; 889 | 890 | end: 891 | 892 | // Return mctp_msg to free pool 893 | pq_push(m->msgs, mm); 894 | 895 | EXIT(rv) 896 | 897 | return rv; 898 | } 899 | 900 | /** 901 | * Update cached switch state from Responses to FM API Messages 902 | * 903 | * @return 0 upon success. Non zero otherwise. 904 | * 905 | * STEPS: 906 | * 1: Set buffer pointers 907 | * 2: Deserialize Request Header 908 | * 3: Deserialize Request Object 909 | * 4: Deserialize Response Header 910 | * 5: Verify Response 911 | * 6: Deserialize Response Payload using object from request 912 | * 7: Handle opcode 913 | */ 914 | int fmapi_update(struct mctp *m, struct mctp_action *ma) 915 | { 916 | INIT 917 | int rv; 918 | struct fmapi_msg req, rsp; 919 | 920 | ENTER 921 | 922 | // Initialize varialbes 923 | rv = 1; 924 | 925 | STEP // 1: Set buffer pointers 926 | req.buf = (struct fmapi_buf*) ma->req->payload; 927 | rsp.buf = (struct fmapi_buf*) ma->rsp->payload; 928 | 929 | STEP // 2: Deserialize Request Header 930 | fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL); 931 | 932 | STEP // 3: Deserialize Request Object 933 | fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL); 934 | 935 | STEP // 4: Deserialize Response Header 936 | fmapi_deserialize(&rsp.hdr, rsp.buf->hdr, FMOB_HDR, NULL); 937 | 938 | STEP // 5: Verify Response 939 | 940 | // Verify msg category 941 | if (rsp.hdr.category != FMMT_RESP) 942 | { 943 | printf("Error: Received an FM API message that was not a response: %s\n", fmmt(rsp.hdr.category)); 944 | goto end; 945 | } 946 | 947 | // Verify return code 948 | if (rsp.hdr.return_code != FMRC_SUCCESS && rsp.hdr.return_code != FMRC_BACKGROUND_OP_STARTED) 949 | { 950 | printf("Error: %s\n", fmrc(rsp.hdr.return_code)); 951 | rv = rsp.hdr.return_code; 952 | goto end; 953 | } 954 | 955 | STEP // 6: Deserialize Response Payload using object from request 956 | fmapi_deserialize(&rsp.obj, rsp.buf->payload, fmapi_fmob_rsp(rsp.hdr.opcode), &req.obj); 957 | 958 | STEP // 8: Obtain lock on switch state 959 | pthread_mutex_lock(&cxls->mtx); 960 | 961 | STEP // 7: Handle opcode 962 | switch(rsp.hdr.opcode) 963 | { 964 | case FMOP_ISC_BOS: 965 | { 966 | struct fmapi_isc_bos *o = &rsp.obj.isc_bos; 967 | cxls->bos_opcode = o->opcode; 968 | cxls->bos_rc = o->rc; 969 | cxls->bos_running = o->running; 970 | cxls->bos_pcnt = o->pcnt; 971 | cxls->bos_ext = o->ext; 972 | } 973 | break; 974 | 975 | case FMOP_ISC_ID: 976 | { 977 | struct fmapi_isc_id_rsp *o = &rsp.obj.isc_id_rsp; 978 | cxls->vid = o->vid; 979 | cxls->did = o->did; 980 | cxls->svid = o->svid; 981 | cxls->ssid = o->ssid; 982 | cxls->sn = o->sn; 983 | cxls->max_msg_size_n = o->size; 984 | } 985 | break; 986 | 987 | case FMOP_ISC_MSG_LIMIT_GET: 988 | case FMOP_ISC_MSG_LIMIT_SET: 989 | { 990 | struct fmapi_isc_msg_limit *o = &rsp.obj.isc_msg_limit; 991 | cxls->msg_rsp_limit_n = o->limit; 992 | } 993 | break; 994 | 995 | case FMOP_PSC_ID: 996 | { 997 | struct fmapi_psc_id_rsp *o = &rsp.obj.psc_id_rsp; 998 | cxls->ingress_port = o->ingress_port; 999 | cxls->num_ports = o->num_ports; 1000 | cxls->num_vcss = o->num_vcss; 1001 | cxls->num_vppbs = o->num_vppbs; 1002 | cxls->active_vppbs = o->active_vppbs; 1003 | cxls->num_decoders = o->num_decoders; 1004 | } 1005 | break; 1006 | 1007 | case FMOP_PSC_PORT: 1008 | { 1009 | struct fmapi_psc_port_rsp *o = &rsp.obj.psc_port_rsp; 1010 | struct fmapi_psc_port_info *x; 1011 | struct cxl_port *p; 1012 | 1013 | for ( int i = 0 ; i < o->num ; i++ ) 1014 | { 1015 | x = &o->list[i]; 1016 | p = &cxls->ports[x->ppid]; 1017 | p->state = x->state; 1018 | p->dv = x->dv; 1019 | p->dt = x->dt; 1020 | p->cv = x->cv; 1021 | p->mlw = x->mlw; 1022 | p->nlw = x->nlw; 1023 | p->speeds = x->speeds; 1024 | p->mls = x->mls; 1025 | p->cls = x->cls; 1026 | p->ltssm = x->ltssm; 1027 | p->lane = x->lane; 1028 | p->lane_rev = x->lane_rev; 1029 | p->perst = x->perst; 1030 | p->prsnt = x->prsnt; 1031 | p->pwrctrl = x->pwrctrl; 1032 | p->ld = x->num_ld; 1033 | } 1034 | } 1035 | break; 1036 | 1037 | case FMOP_PSC_PORT_CTRL: 1038 | break; 1039 | 1040 | case FMOP_PSC_CFG: 1041 | { 1042 | struct fmapi_psc_cfg_rsp *o = &rsp.obj.psc_cfg_rsp; 1043 | 1044 | if (req.obj.psc_cfg_req.type == FMCT_READ ) 1045 | { 1046 | struct cxl_port *p = &cxls->ports[req.obj.psc_cfg_req.ppid]; 1047 | unsigned reg = (req.obj.psc_cfg_req.ext << 8) | req.obj.psc_cfg_req.reg; 1048 | 1049 | if (req.obj.psc_cfg_req.fdbe & 0x01) 1050 | p->cfgspace[reg] = o->data[0]; 1051 | if (req.obj.psc_cfg_req.fdbe & 0x02) 1052 | p->cfgspace[reg] = o->data[1]; 1053 | if (req.obj.psc_cfg_req.fdbe & 0x04) 1054 | p->cfgspace[reg] = o->data[2]; 1055 | if (req.obj.psc_cfg_req.fdbe & 0x08) 1056 | p->cfgspace[reg] = o->data[3]; 1057 | } 1058 | } 1059 | break; 1060 | 1061 | case FMOP_VSC_INFO: 1062 | { 1063 | struct fmapi_vsc_info_rsp *o = &rsp.obj.vsc_info_rsp; 1064 | struct cxl_vcs *v; 1065 | struct fmapi_vsc_info_blk *x; 1066 | struct fmapi_vsc_ppb_stat_blk *b; 1067 | int i, k; 1068 | 1069 | for ( i = 0 ; i < o->num ; i++ ) 1070 | { 1071 | x = &o->list[i]; 1072 | v = &cxls->vcss[x->vcsid]; 1073 | 1074 | v->vcsid = x->vcsid; 1075 | v->state = x->state; 1076 | v->uspid = x->uspid; 1077 | v->num = x->num; 1078 | 1079 | for ( k = 0 ; k < v->num ; k++) 1080 | { 1081 | b = &x->list[k]; 1082 | v->vppbs[k].bind_status = b->status; 1083 | v->vppbs[k].ppid = b->ppid; 1084 | v->vppbs[k].ldid = b->ldid; 1085 | } 1086 | } 1087 | } 1088 | break; 1089 | 1090 | case FMOP_VSC_BIND: 1091 | break; 1092 | 1093 | case FMOP_VSC_UNBIND: 1094 | break; 1095 | 1096 | case FMOP_VSC_AER: 1097 | break; 1098 | 1099 | case FMOP_MPC_TMC: 1100 | { 1101 | struct fmapi_mpc_tmc_rsp *o = &rsp.obj.mpc_tmc_rsp; 1102 | 1103 | if (o->type != MCMT_CXLCCI) 1104 | { 1105 | printf("Error: Tunneled command had incorrect MCTP Message Type: 0x%02x\n", o->type); 1106 | goto end; 1107 | } 1108 | 1109 | rv = cci_update(m, req.obj.mpc_tmc_req.ppid, o->msg); 1110 | } 1111 | break; 1112 | 1113 | case FMOP_MPC_CFG: 1114 | { 1115 | struct fmapi_mpc_cfg_rsp *o = &rsp.obj.mpc_cfg_rsp; 1116 | 1117 | if (req.obj.mpc_cfg_req.type == FMCT_READ ) 1118 | { 1119 | struct cxl_port *p = &cxls->ports[req.obj.mpc_cfg_req.ppid]; 1120 | struct cxl_mld *m = p->mld; 1121 | unsigned ldid = req.obj.mpc_cfg_req.ldid; 1122 | unsigned reg = (req.obj.mpc_cfg_req.ext << 8) | req.obj.mpc_cfg_req.reg; 1123 | 1124 | if (req.obj.mpc_cfg_req.fdbe & 0x01) 1125 | m->cfgspace[ldid][reg] = o->data[0]; 1126 | if (req.obj.mpc_cfg_req.fdbe & 0x02) 1127 | m->cfgspace[ldid][reg] = o->data[1]; 1128 | if (req.obj.mpc_cfg_req.fdbe & 0x04) 1129 | m->cfgspace[ldid][reg] = o->data[2]; 1130 | if (req.obj.mpc_cfg_req.fdbe & 0x08) 1131 | m->cfgspace[ldid][reg] = o->data[3]; 1132 | } 1133 | } 1134 | break; 1135 | 1136 | case FMOP_MPC_MEM: 1137 | break; 1138 | 1139 | default: 1140 | goto end; 1141 | } 1142 | 1143 | rv = 0; 1144 | 1145 | end: 1146 | 1147 | STEP // Release lock on switch state 1148 | pthread_mutex_unlock(&cxls->mtx); 1149 | 1150 | // Return mctp_msg to free pool 1151 | mctp_retire(m, ma); 1152 | 1153 | EXIT(rv) 1154 | 1155 | return rv; 1156 | } 1157 | 1158 | --------------------------------------------------------------------------------