Release candidate
This commit is contained in:
parent
a1db8a3a1b
commit
7d9fa84cb5
76
Makefile
Normal file
76
Makefile
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# ******************************************************************************
|
||||||
|
#
|
||||||
|
# @file Makefile
|
||||||
|
#
|
||||||
|
# @brief Makefile for CXL Switch Endpoint Application
|
||||||
|
#
|
||||||
|
# @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
#
|
||||||
|
# @date Mar 2024
|
||||||
|
# @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
#
|
||||||
|
# ******************************************************************************
|
||||||
|
|
||||||
|
CC=gcc
|
||||||
|
CFLAGS= -g3 -O0 -Wall -Wextra
|
||||||
|
MACROS=-D CSE_VERBOSE
|
||||||
|
INCLUDE_DIR=/usr/local/include
|
||||||
|
LIB_DIR=/usr/local/lib
|
||||||
|
INCLUDE_PATH=-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
|
||||||
|
LIB_PATH=-L $(LIB_DIR)
|
||||||
|
LIBS=-l yamlloader -l yaml -l glib-2.0 -l mctp -l uuid -l ptrqueue -l fmapi -l emapi -l arrayutils -l pciutils -l timeutils -l pci
|
||||||
|
TARGET=cse
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): main.c options.o state.o signals.o emapi_handler.o fmapi_handler.o fmapi_isc_handler.o fmapi_psc_handler.o fmapi_vsc_handler.o fmapi_mpc_handler.o fmapi_mcc_handler.o
|
||||||
|
$(CC) $^ $(CFLAGS) $(MACROS) $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) -o $@
|
||||||
|
|
||||||
|
emapi_handler.o: emapi_handler.c emapi_handler.h
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
fmapi_mcc_handler.o: fmapi_mcc_handler.c
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
fmapi_mpc_handler.o: fmapi_mpc_handler.c
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
fmapi_vsc_handler.o: fmapi_vsc_handler.c
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
fmapi_psc_handler.o: fmapi_psc_handler.c
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
fmapi_isc_handler.o: fmapi_isc_handler.c
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
fmapi_handler.o: fmapi_handler.c fmapi_handler.h
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
signals.o: signals.c signals.h
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
options.o: options.c options.h
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
state.o: state.c state.h
|
||||||
|
$(CC) -c $< $(CFLAGS) $(MACROS) $(INCLUDE_PATH) -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf ./*.o ./*.a $(TARGET)
|
||||||
|
|
||||||
|
doc:
|
||||||
|
doxygen
|
||||||
|
|
||||||
|
install: $(TARGET)
|
||||||
|
sudo cp $(TARGET) /usr/local/bin/
|
||||||
|
|
||||||
|
# List all non file name targets as PHONY
|
||||||
|
.PHONY: all clean doc install
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
# $^ Will expand to be all the sensitivity list
|
||||||
|
# $< Will expand to be the frist file in sensitivity list
|
||||||
|
# $@ Will expand to be the target name (the left side of the ":" )
|
||||||
|
# -c gcc will compile but not try and link
|
||||||
23
README.md
23
README.md
@ -1,3 +1,22 @@
|
|||||||
# CSE-release
|
# Install
|
||||||
|
|
||||||
CXL Switch Emulator
|
Install the following Linux Packages:
|
||||||
|
|
||||||
|
- libyaml libyaml-dev doxygen uuid-dev pciutils-dev
|
||||||
|
|
||||||
|
Clone the following repositories from code.jrlabs.io
|
||||||
|
|
||||||
|
- JackrabbitLabs/array_utils.git
|
||||||
|
- JackrabbitLabs/ptr_queue.git
|
||||||
|
- JackrabbitLabs/duplex_queue.git
|
||||||
|
- JackrabbitLabs/yaml_loader.git
|
||||||
|
- JackrabbitLabs/mctp.git
|
||||||
|
- JackrabbitLabs/fmapi.git
|
||||||
|
- JackrabbitLabs/cse.git
|
||||||
|
- JackrabbitLabs/jack.git
|
||||||
|
|
||||||
|
On each repository perform the following commands (in order listed above)
|
||||||
|
|
||||||
|
- make
|
||||||
|
- make install
|
||||||
|
|
||||||
|
|||||||
584
config.yaml
Normal file
584
config.yaml
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
---
|
||||||
|
devices:
|
||||||
|
cpu_5x16_1.1:
|
||||||
|
did: 0
|
||||||
|
port:
|
||||||
|
dv: 1 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 2 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x1 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 16
|
||||||
|
mls: 5
|
||||||
|
rootport: 1
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x1001
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x00
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0000
|
||||||
|
cpu_5x16_2.0:
|
||||||
|
did: 1
|
||||||
|
port:
|
||||||
|
dv: 2 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 2 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x3 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 16
|
||||||
|
mls: 5
|
||||||
|
rootport: 1
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x1002
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x00
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0001
|
||||||
|
mld_5x8_1.1_4G:
|
||||||
|
did: 2
|
||||||
|
port:
|
||||||
|
dv: 1 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x1 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 8
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x2001
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x10 # CXL 2.0 Compliant Device
|
||||||
|
subclass: 0x02 # 0x02=CXL Device
|
||||||
|
baseclass: 0x05 # 0x05=Memory Controller
|
||||||
|
cacheline: 0x10 # number of 4B values. 0x10=64B
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0002
|
||||||
|
intline: 0
|
||||||
|
intpin: 0
|
||||||
|
mingnt: 0
|
||||||
|
maxlat: 0
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "02,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
mmap: 1
|
||||||
|
memory_size: 0x100000000 # 4GB
|
||||||
|
num: 4
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 0 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12"
|
||||||
|
rng2: "3,7,11,15"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "64,64,64,64"
|
||||||
|
bw_limit: "ff,ff,ff,ff"
|
||||||
|
mld_5x8_1.1_64G:
|
||||||
|
did: 3
|
||||||
|
port:
|
||||||
|
dv: 1 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x1 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 8
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x3001
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0006
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "06,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
memory_size: 0x1000000000 # 64GB
|
||||||
|
num: 16
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 2 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60"
|
||||||
|
rng2: "4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16"
|
||||||
|
bw_limit: "ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff"
|
||||||
|
mld_5x8_2.0_4G:
|
||||||
|
did: 4
|
||||||
|
port:
|
||||||
|
dv: 2 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x3 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 8
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x2003
|
||||||
|
revid: 0
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0004
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "04,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
mmap: 1
|
||||||
|
memory_size: 0x100000000 # 4GB
|
||||||
|
num: 4
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 0 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12"
|
||||||
|
rng2: "3,7,11,15"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "64,64,64,64"
|
||||||
|
bw_limit: "ff,ff,ff,ff"
|
||||||
|
mld_5x8_2.0_64G:
|
||||||
|
did: 5
|
||||||
|
port:
|
||||||
|
dv: 2 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x3 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 8
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x3003
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0008
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "08,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
memory_size: 0x1000000000 # 64GB
|
||||||
|
num: 16
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 2 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60"
|
||||||
|
rng2: "4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16"
|
||||||
|
bw_limit: "ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff"
|
||||||
|
mld_5x16_1.1_4G:
|
||||||
|
did: 6
|
||||||
|
port:
|
||||||
|
dv: 1 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x1 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 16
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x2002
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0003
|
||||||
|
intline: 0
|
||||||
|
intpin: 0
|
||||||
|
mingnt: 0
|
||||||
|
maxlat: 0
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "03,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
mmap: 1
|
||||||
|
memory_size: 0x100000000 # 4GB
|
||||||
|
num: 4
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 0 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12"
|
||||||
|
rng2: "3,7,11,15"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "64,64,64,64"
|
||||||
|
bw_limit: "ff,ff,ff,ff"
|
||||||
|
mld_5x16_1.1_64G:
|
||||||
|
did: 7
|
||||||
|
port:
|
||||||
|
dv: 1 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x1 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 16
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x3002
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0007
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "07,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
memory_size: 0x1000000000 # 64GB
|
||||||
|
num: 16
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 2 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60"
|
||||||
|
rng2: "4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16"
|
||||||
|
bw_limit: "ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff"
|
||||||
|
mld_5x16_2.0_4G:
|
||||||
|
did: 8
|
||||||
|
port:
|
||||||
|
dv: 2 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x3 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 16
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x2004
|
||||||
|
revid: 0
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0005
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "05,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
mmap: 1
|
||||||
|
memory_size: 0x100000000 # 4GB
|
||||||
|
num: 4
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 0 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12"
|
||||||
|
rng2: "3,7,11,15"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "64,64,64,64"
|
||||||
|
bw_limit: "ff,ff,ff,ff"
|
||||||
|
mld_5x16_2.0_64G:
|
||||||
|
did: 9
|
||||||
|
port:
|
||||||
|
dv: 2 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 5 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x3 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 16
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x3004
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x10
|
||||||
|
subclass: 0x02
|
||||||
|
baseclass: 0x05
|
||||||
|
cacheline: 0x10
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x0009
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "09,00,00,00,00,00,00,00"
|
||||||
|
mld:
|
||||||
|
memory_size: 0x1000000000 # 64GB
|
||||||
|
num: 16
|
||||||
|
epc: 1
|
||||||
|
ttr: 1
|
||||||
|
granularity: 2 # 0=256MB, 1=512MB, 2=1GB
|
||||||
|
rng1: "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60"
|
||||||
|
rng2: "4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64"
|
||||||
|
epc_en: 1
|
||||||
|
ttr_en: 1
|
||||||
|
egress_mod_pcnt: 10
|
||||||
|
egress_sev_pcnt: 25
|
||||||
|
sample_interval: 8
|
||||||
|
req_cmp_basis: 0
|
||||||
|
comp_interval: 64
|
||||||
|
bp_avg_pcnt: 42
|
||||||
|
alloc_bw: "16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16"
|
||||||
|
bw_limit: "ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff"
|
||||||
|
sld_5x8_1.1_4G:
|
||||||
|
did: 10
|
||||||
|
port:
|
||||||
|
dv: 1 # 0=NC, 1=CXL1.1, 2=CXL2.0
|
||||||
|
dt: 4 # 0=NC, 1=PCIe, 2=CXLT1, 3=CXLT2, 4=CXLT3, 5=CXLT3 Pooled, 6=switch
|
||||||
|
cv: 0x1 # bit0=CXL1.1, bit1=CXL 2.0
|
||||||
|
mlw: 8
|
||||||
|
mls: 5
|
||||||
|
pcicfg:
|
||||||
|
vendor: 0x1aed
|
||||||
|
device: 0x4001
|
||||||
|
command: 0x0506
|
||||||
|
status: 0x0010
|
||||||
|
revid: 0
|
||||||
|
pi: 0x00 # 0=Vendor Specific 0x10=CXL 2.0 Compliant Device
|
||||||
|
subclass: 0x02 # 0x02=CXL Device
|
||||||
|
baseclass: 0x05 # 0x05=Memory Controller
|
||||||
|
cacheline: 0x10 # number of 4B values. 0x10=64B
|
||||||
|
type: 0x0
|
||||||
|
subvendor: 0x1aed
|
||||||
|
subsystem: 0x000A
|
||||||
|
intline: 0
|
||||||
|
intpin: 0
|
||||||
|
mingnt: 0
|
||||||
|
maxlat: 0
|
||||||
|
cap:
|
||||||
|
0x01: "03,00,00,00,00,00"
|
||||||
|
0x05: "8A,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"
|
||||||
|
ecap:
|
||||||
|
0x00030: "02,00,00,00,00,00,00,00"
|
||||||
|
---
|
||||||
|
emulator:
|
||||||
|
# verbosity-hex: 0x70
|
||||||
|
# verbosity-mctp: 0x00
|
||||||
|
tcp-port: 2508
|
||||||
|
dir: "/cxl" # mount -t tmpfs -o size=32G,mode=1777 cxl /cxl
|
||||||
|
---
|
||||||
|
switch:
|
||||||
|
vid: 0xa1a2
|
||||||
|
did: 0xb1b2
|
||||||
|
svid: 0xc1c2
|
||||||
|
ssid: 0xd1d2
|
||||||
|
sn: 0xa1a2a3a4a5a6a7a8
|
||||||
|
max_msg_size_n: 13
|
||||||
|
msg_rsp_limit_n: 13
|
||||||
|
bos_running: 0
|
||||||
|
bos_pcnt: 0
|
||||||
|
bos_opcode: 0
|
||||||
|
bos_rc: 0
|
||||||
|
bos_ext: 0
|
||||||
|
ingress_port: 1
|
||||||
|
num_ports: 32
|
||||||
|
num_vcss: 4
|
||||||
|
num_vppbs: 32
|
||||||
|
num_decoders: 32
|
||||||
|
mlw: 16
|
||||||
|
speeds: 0x30
|
||||||
|
mls: 5
|
||||||
|
---
|
||||||
|
ports:
|
||||||
|
0:
|
||||||
|
device: "cpu_5x16_2.0"
|
||||||
|
1:
|
||||||
|
device: "mld_5x8_2.0_4G"
|
||||||
|
2:
|
||||||
|
device: "mld_5x8_2.0_4G"
|
||||||
|
3:
|
||||||
|
device: "mld_5x16_2.0_64G"
|
||||||
|
4:
|
||||||
|
device: "mld_5x16_2.0_64G"
|
||||||
|
8:
|
||||||
|
state: 4
|
||||||
|
# device: "cpu_5x16_2.0"
|
||||||
|
9:
|
||||||
|
# device: "mld_5x8_1.1_4G"
|
||||||
|
10:
|
||||||
|
# device: "mld_5x16_1.1_4G"
|
||||||
|
11:
|
||||||
|
# device: "mld_5x8_2.0_4G"
|
||||||
|
12:
|
||||||
|
# device: "mld_5x16_2.0_4G"
|
||||||
|
16:
|
||||||
|
mlw: 8
|
||||||
|
state: 4
|
||||||
|
# device: "cpu_5x16_2.0"
|
||||||
|
17:
|
||||||
|
mlw: 8
|
||||||
|
# device: "mld_5x8_1.1_4G"
|
||||||
|
18:
|
||||||
|
mlw: 8
|
||||||
|
# device: "mld_5x16_1.1_4G"
|
||||||
|
19:
|
||||||
|
mlw: 8
|
||||||
|
# device: "mld_5x8_2.0_4G"
|
||||||
|
20:
|
||||||
|
mlw: 8
|
||||||
|
# device: "mld_5x16_2.0_4G"
|
||||||
|
21:
|
||||||
|
mlw: 8
|
||||||
|
22:
|
||||||
|
mlw: 8
|
||||||
|
23:
|
||||||
|
mlw: 8
|
||||||
|
24:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
state: 4
|
||||||
|
25:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
26:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
27:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
28:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
29:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
30:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
31:
|
||||||
|
mlw: 8
|
||||||
|
mls: 6
|
||||||
|
speeds: 0x70
|
||||||
|
---
|
||||||
|
vcss:
|
||||||
|
0:
|
||||||
|
state: 1
|
||||||
|
uspid: 0
|
||||||
|
num_vppb: 8
|
||||||
|
vppbs:
|
||||||
|
0:
|
||||||
|
bind_status: 2 # 0=Unbound, 1=Inprogress, 2=Bound Physical, 3=Bound LD
|
||||||
|
ppid: 0
|
||||||
|
ldid: 0
|
||||||
|
1:
|
||||||
|
bind_status: 3 # 0=Unbound, 1=Inprogress, 2=Bound Physical, 3=Bound LD
|
||||||
|
ppid: 1
|
||||||
|
ldid: 0
|
||||||
|
2:
|
||||||
|
bind_status: 3 # 0=Unbound, 1=Inprogress, 2=Bound Physical, 3=Bound LD
|
||||||
|
ppid: 2
|
||||||
|
ldid: 0
|
||||||
|
3:
|
||||||
|
bind_status: 3 # 0=Unbound, 1=Inprogress, 2=Bound Physical, 3=Bound LD
|
||||||
|
ppid: 3
|
||||||
|
ldid: 0
|
||||||
|
4:
|
||||||
|
bind_status: 3 # 0=Unbound, 1=Inprogress, 2=Bound Physical, 3=Bound LD
|
||||||
|
ppid: 4
|
||||||
|
ldid: 0
|
||||||
|
1:
|
||||||
|
state: 1
|
||||||
|
uspid: 8
|
||||||
|
num_vppb: 8
|
||||||
|
2:
|
||||||
|
state: 1
|
||||||
|
uspid: 16
|
||||||
|
num_vppb: 8
|
||||||
|
3:
|
||||||
|
state: 1
|
||||||
|
uspid: 24
|
||||||
|
num_vppb: 8
|
||||||
207
cse.c
Normal file
207
cse.c
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/**
|
||||||
|
* @file cse.c
|
||||||
|
*
|
||||||
|
* @brief Code file for entry point CXL Switch Emulator
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <barrett@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
#include "emapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cse main
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 0: Parse CLI options
|
||||||
|
* 1: Register Signal Handlers
|
||||||
|
* 2: Initialize global state array
|
||||||
|
* 3: Load state file
|
||||||
|
* 4: Print the state
|
||||||
|
* 5: MCTP Init
|
||||||
|
* 6: Run MCTP
|
||||||
|
* 7: While loop
|
||||||
|
* 8: Stop MCTP
|
||||||
|
* 9: Free memory
|
||||||
|
*/
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
int rv;
|
||||||
|
struct mctp *m;
|
||||||
|
|
||||||
|
// Initialize varaibles
|
||||||
|
stop_requested = 0;
|
||||||
|
rv = 1;
|
||||||
|
|
||||||
|
// 0: Parse CLI options
|
||||||
|
rv = options_parse(argc,argv);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
printf("Error: Parse options failed: %d\n", rv);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 1: Register Signal Handlers
|
||||||
|
signals_register();
|
||||||
|
|
||||||
|
STEP // 2: Initialize global state array
|
||||||
|
cxl_state = state_init(32, 32, 256);
|
||||||
|
if (cxl_state == NULL)
|
||||||
|
{
|
||||||
|
printf("Error: state init failed \n");
|
||||||
|
goto end_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 3: Load state file
|
||||||
|
if (opts[CLOP_CONFIG_FILE].set)
|
||||||
|
{
|
||||||
|
rv = state_load(cxl_state, opts[CLOP_CONFIG_FILE].str);
|
||||||
|
if (rv < 0)
|
||||||
|
{
|
||||||
|
printf("Error: state load config file failed \n");
|
||||||
|
goto end_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 5: Print the state
|
||||||
|
if (opts[CLOP_PRINT_STATE].set)
|
||||||
|
state_print(cxl_state);
|
||||||
|
|
||||||
|
STEP // 6: MCTP Init
|
||||||
|
m = mctp_init();
|
||||||
|
if (m == NULL)
|
||||||
|
goto end_state;
|
||||||
|
|
||||||
|
// Set supported MCTP Message Versions
|
||||||
|
mctp_set_version(m, MCMT_CXLFMAPI, 0xF2,0xF1,0xFF,0x00);
|
||||||
|
mctp_set_version(m, MCMT_CXLCCI, 0xF2,0xF1,0xFF,0x00);
|
||||||
|
|
||||||
|
// Set Message handler functions
|
||||||
|
mctp_set_handler(m, MCMT_CXLFMAPI, fmapi_handler);
|
||||||
|
mctp_set_handler(m, MCMT_CSE, emapi_handler);
|
||||||
|
|
||||||
|
// Set MCTP verbosity levels
|
||||||
|
mctp_set_verbosity(m, opts[CLOP_MCTP_VERBOSITY].u64);
|
||||||
|
|
||||||
|
STEP // 7: Run MCTP
|
||||||
|
rv = mctp_run(m, opts[CLOP_TCP_PORT].u16, MCRM_SERVER, 1, 1);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
switch (rv)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
printf("Socket create failed\n");
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
printf("Socket bind failed\n");
|
||||||
|
break;
|
||||||
|
case -3:
|
||||||
|
printf("Socket connect failed");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("Could not create Connection Handler Thread\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("MCTP threads failed to start\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto end_mctp;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 8: While loop
|
||||||
|
while ( stop_requested == 0 )
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 9: Stop MCTP
|
||||||
|
mctp_stop(m);
|
||||||
|
|
||||||
|
end_mctp:
|
||||||
|
|
||||||
|
mctp_free(m);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end_state:
|
||||||
|
|
||||||
|
state_free(cxl_state);
|
||||||
|
|
||||||
|
end_options:
|
||||||
|
|
||||||
|
options_free(opts);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rv)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
};
|
||||||
|
|
||||||
696
emapi_handler.c
Normal file
696
emapi_handler.c
Normal file
@ -0,0 +1,696 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file emapi_handler.c
|
||||||
|
*
|
||||||
|
* @brief Code file for methods to respond to CXL Emulator API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Feb 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* struct timespec
|
||||||
|
* timespec_get()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
#include <ptrqueue.h>
|
||||||
|
#include <timeutils.h>
|
||||||
|
#include <emapi.h>
|
||||||
|
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "emapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
#define ISO_TIME_BUF_LEN 32
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
static int emop_conn_dev (struct mctp *m, struct mctp_action *ma);
|
||||||
|
static int emop_disconn_dev(struct mctp *m, struct mctp_action *ma);
|
||||||
|
static int emop_list_dev (struct mctp *m, struct mctp_action *ma);
|
||||||
|
static int emop_unsupported(struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for all CXL Emulator API Opcodes
|
||||||
|
*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Deserialize Header
|
||||||
|
* 2: Verify EM API Message Type
|
||||||
|
* 3: Handle Opcode
|
||||||
|
*/
|
||||||
|
int emapi_handler(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
struct emapi_hdr hdr;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
// Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
|
||||||
|
STEP // 1: Deserialize Header
|
||||||
|
if ( emapi_deserialize(&hdr, ma->req->payload, EMOB_HDR, NULL) == 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 2: Verify EM API Message Type
|
||||||
|
if (hdr.type != EMMT_REQ)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 3: Handle Opcode
|
||||||
|
HEX32("Opcode", hdr.opcode);
|
||||||
|
switch(hdr.opcode)
|
||||||
|
{
|
||||||
|
case EMOP_EVENT: // 0x00
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EMOP_LIST_DEV: // 0x01
|
||||||
|
rv = emop_list_dev(m, ma);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EMOP_CONN_DEV: // 0x02
|
||||||
|
rv = emop_conn_dev(m, ma);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EMOP_DISCON_DEV: // 0x03
|
||||||
|
rv = emop_disconn_dev(m, ma);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
rv = emop_unsupported(m, ma);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
ma->completion_code = 1;
|
||||||
|
pq_push(m->acq, ma);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rv)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for EM API Connect Device Command
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
static int emop_conn_dev(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct emapi_msg reqm, rspm;
|
||||||
|
struct emapi_buf *reqb, *rspb;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
__u8 ppid, dev;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
reqb = (struct emapi_buf*) ma->req->payload;
|
||||||
|
rspb = (struct emapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( emapi_deserialize(&reqm.hdr, reqb->hdr, EMOB_HDR, NULL) <= 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( emapi_deserialize(&reqm.obj, reqb->payload, emapi_emob_req(reqm.hdr.opcode), NULL) < 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
ppid = reqm.hdr.a;
|
||||||
|
dev = reqm.hdr.b;
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: EM API Connect Device. PPID: %d Device: %d\n", now, ppid, dev);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: PPID out of range. PPID: %d Total: %d\n", now, ppid, cxl_state->num_ports);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev >= cxl_state->num_devices)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Device ID out of range. Device ID: %d Total: %d\n", now, dev, cxl_state->num_devices);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cxl_state->devices[dev].name == NULL)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Device is NULL. Device ID: %d\n", now, dev);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Connecting Device %d to PPID %d\n", now, dev, ppid);
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
state_connect_device(&cxl_state->ports[ppid], &cxl_state->devices[dev]);
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = emapi_serialize(rspb->payload, &rspm.obj, emapi_emob_rsp(reqm.hdr.opcode), NULL);
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = EMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if(len < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = emapi_fill_hdr(&rspm.hdr, EMMT_RSP, reqm.hdr.tag, rc, reqm.hdr.opcode, len, 0, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
emapi_serialize(rspb->hdr, &rspm.hdr, EMOB_HDR, NULL);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
ma->completion_code = 1;
|
||||||
|
pq_push(m->acq, ma);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for EM API Disconnect Device Command
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
static int emop_disconn_dev(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct emapi_msg reqm, rspm;
|
||||||
|
struct emapi_buf *reqb, *rspb;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
__u8 ppid, all, start, end, i;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
STEP // 4: Set buffer pointers
|
||||||
|
reqb = (struct emapi_buf*) ma->req->payload;
|
||||||
|
rspb = (struct emapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( emapi_deserialize(&reqm.hdr, reqb->hdr, EMOB_HDR, NULL) <= 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( emapi_deserialize(&reqm.obj, reqb->payload, emapi_emob_req(reqm.hdr.opcode), NULL) < 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
ppid = reqm.hdr.a;
|
||||||
|
all = reqm.hdr.b;
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: EM API Disconnect Device. PPID: %d All: %d\n", now, ppid, all);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (all) {
|
||||||
|
start = 0;
|
||||||
|
end = cxl_state->num_ports;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
start = ppid;
|
||||||
|
end = ppid+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: PPID out of range. PPID: %d Total: %d\n", now, ppid, cxl_state->num_ports);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
for ( i = start ; i < end ; i++ )
|
||||||
|
{
|
||||||
|
// Validate if port is connected
|
||||||
|
if (cxl_state->ports[i].prsnt == 1)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Disconnecting PPID %d\n", now, i);
|
||||||
|
|
||||||
|
// Perform disconnect
|
||||||
|
state_disconnect_device(&cxl_state->ports[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = emapi_serialize(rspb->payload, &rspm.obj, emapi_emob_rsp(reqm.hdr.opcode), NULL);
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = EMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = emapi_fill_hdr(&rspm.hdr, EMMT_RSP, reqm.hdr.tag, rc, reqm.hdr.opcode, len, 0, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
emapi_serialize(rspb->hdr, &rspm.hdr, EMOB_HDR, NULL);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
ma->completion_code = 1;
|
||||||
|
pq_push(m->acq, ma);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for EM API List Devices Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
static int emop_list_dev(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct emapi_msg reqm, rspm;
|
||||||
|
struct emapi_buf *reqb, *rspb;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
unsigned i, count;
|
||||||
|
__u8 num_requested, start_num;
|
||||||
|
struct cse_device *d;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
STEP // 4: Set buffer pointers
|
||||||
|
reqb = (struct emapi_buf*) ma->req->payload;
|
||||||
|
rspb = (struct emapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( emapi_deserialize(&reqm.hdr, reqb->hdr, EMOB_HDR, NULL) <= 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( emapi_deserialize(&reqm.obj, reqb->payload, emapi_emob_req(reqm.hdr.opcode), NULL) < 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
num_requested = reqm.hdr.a;
|
||||||
|
start_num = reqm.hdr.b;
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: EM API list Devices. Start: %d Num: %d\n", now, start_num, num_requested);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (num_requested == 0)
|
||||||
|
num_requested = (cxl_state->num_devices - start_num);
|
||||||
|
|
||||||
|
if (start_num >= cxl_state->num_devices)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Start num out of range. Start: %d Total: %d\n", now, start_num, num_requested);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (start_num + num_requested) >= cxl_state->num_devices)
|
||||||
|
num_requested = (cxl_state->num_devices - start_num);
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Responding with %d devices\n", now, num_requested);
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
for ( i = 0 ; i < num_requested ; i++ )
|
||||||
|
{
|
||||||
|
d = &cxl_state->devices[start_num + i];
|
||||||
|
|
||||||
|
// Serialize the id number
|
||||||
|
rspb->payload[len+0] = start_num + i;
|
||||||
|
|
||||||
|
// Serialize the name string
|
||||||
|
if (d->name != NULL )
|
||||||
|
{
|
||||||
|
rspb->payload[len+1] = strlen(d->name) + 1;
|
||||||
|
memcpy(&rspb->payload[len+2], d->name, rspb->payload[len+1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rspb->payload[len+1] = 0;
|
||||||
|
|
||||||
|
len += (2 + rspb->payload[len+1]);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = EMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = emapi_fill_hdr(&rspm.hdr, EMMT_RSP, reqm.hdr.tag, rc, reqm.hdr.opcode, len, count, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
emapi_serialize(rspb->hdr, &rspm.hdr, EMOB_HDR, NULL);
|
||||||
|
|
||||||
|
STEP // 17: Push response mctp_msg onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
ma->completion_code = 1;
|
||||||
|
pq_push(m->acq, ma);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for EM API List Devices Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
static int emop_unsupported(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct emapi_msg reqm, rspm;
|
||||||
|
struct emapi_buf *reqb, *rspb;
|
||||||
|
unsigned rc;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
rc = EMRC_UNSUPPORTED;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
STEP // 4: Set buffer pointers
|
||||||
|
reqb = (struct emapi_buf*) ma->req->payload;
|
||||||
|
rspb = (struct emapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( emapi_deserialize(&reqm.hdr, reqb->hdr, EMOB_HDR, NULL) <= 0 )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s ERR: Unsupported Opcode: 0x%04x\n", now, reqm.hdr.opcode);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = emapi_fill_hdr(&rspm.hdr, EMMT_RSP, reqm.hdr.tag, rc, reqm.hdr.opcode, 0, 0, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
emapi_serialize(rspb->hdr, &rspm.hdr, EMOB_HDR, NULL);
|
||||||
|
|
||||||
|
STEP // 17: Push response mctp_msg onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
ma->completion_code = 1;
|
||||||
|
pq_push(m->acq, ma);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
35
emapi_handler.h
Normal file
35
emapi_handler.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file emapi_handler.h
|
||||||
|
*
|
||||||
|
* @brief Header file for methods to respond to CXL Emulator API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Feb 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
#ifndef _EMAPI_HANDLER_H
|
||||||
|
#define _EMAPI_HANDLER_H
|
||||||
|
|
||||||
|
/* mctp_state
|
||||||
|
* mctp_msg
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
int emapi_handler(struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
#endif //_EMAPI_HANDLER_H
|
||||||
168
fmapi_handler.c
Normal file
168
fmapi_handler.c
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file fmapi_handler.c
|
||||||
|
*
|
||||||
|
* @brief Code file for methods to respond to FM API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* struct timespec
|
||||||
|
* timespec_get()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
#include <ptrqueue.h>
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include <fmapi.h>
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
int fmop_isc_bos (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_isc_id (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_isc_msg_limit_get (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_isc_msg_limit_set (struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
int fmop_mpc_cfg (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_mpc_mem (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_mpc_tmc (struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
int fmop_psc_cfg (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_psc_id (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_psc_port (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_psc_port_ctrl (struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
int fmop_vsc_aer (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_vsc_bind (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_vsc_info (struct mctp *m, struct mctp_action *ma);
|
||||||
|
int fmop_vsc_unbind (struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for all FM API Opcodes
|
||||||
|
*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Deserialize Header
|
||||||
|
* 2: Verify FM API Message Category
|
||||||
|
* 3: Handle Opcode
|
||||||
|
*/
|
||||||
|
int fmapi_handler(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
struct fmapi_hdr hdr;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
// Initialize variables
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
STEP // 1: Deserialize FM API Header
|
||||||
|
rv = fmapi_deserialize(&hdr, ma->req->payload, FMOB_HDR, NULL);
|
||||||
|
if (rv <= 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 2: Verify FM API Message Category
|
||||||
|
if (hdr.category != FMMT_REQ)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Handle Opcode
|
||||||
|
HEX32("Opcode", hdr.opcode);
|
||||||
|
switch(hdr.opcode)
|
||||||
|
{
|
||||||
|
case FMOP_ISC_BOS: rv = fmop_isc_bos(m, ma); break;
|
||||||
|
case FMOP_ISC_ID: rv = fmop_isc_id(m, ma); break;
|
||||||
|
case FMOP_ISC_MSG_LIMIT_GET: rv = fmop_isc_msg_limit_get(m, ma); break;
|
||||||
|
case FMOP_ISC_MSG_LIMIT_SET: rv = fmop_isc_msg_limit_set(m, ma); break;
|
||||||
|
case FMOP_PSC_ID: rv = fmop_psc_id(m, ma); break;
|
||||||
|
case FMOP_PSC_PORT: rv = fmop_psc_port(m, ma); break;
|
||||||
|
case FMOP_PSC_PORT_CTRL: rv = fmop_psc_port_ctrl(m, ma); break;
|
||||||
|
case FMOP_PSC_CFG: rv = fmop_psc_cfg(m, ma); break;
|
||||||
|
case FMOP_VSC_INFO: rv = fmop_vsc_info(m, ma); break;
|
||||||
|
case FMOP_VSC_BIND: rv = fmop_vsc_bind(m, ma); break;
|
||||||
|
case FMOP_VSC_UNBIND: rv = fmop_vsc_unbind(m, ma); break;
|
||||||
|
case FMOP_VSC_AER: rv = fmop_vsc_aer(m, ma); break;
|
||||||
|
case FMOP_MPC_TMC: rv = fmop_mpc_tmc(m, ma); break;
|
||||||
|
case FMOP_MPC_CFG: rv = fmop_mpc_cfg(m, ma); break;
|
||||||
|
case FMOP_MPC_MEM: rv = fmop_mpc_mem(m, ma); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
// If subhandler fails, check in mctp_action
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
ma->completion_code = 1;
|
||||||
|
pq_push(m->acq, ma);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXIT(rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
}
|
||||||
35
fmapi_handler.h
Normal file
35
fmapi_handler.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file fmapi_handler.h
|
||||||
|
*
|
||||||
|
* @brief Header file for methods to respond to FM API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
#ifndef _FMAPI_HANDLER_H
|
||||||
|
#define _FMAPI_HANDLER_H
|
||||||
|
|
||||||
|
/* mctp_state
|
||||||
|
* mctp_msg
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
int fmapi_handler(struct mctp *m, struct mctp_action *ma);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
#endif //_FMAPI_HANDLER_H
|
||||||
541
fmapi_isc_handler.c
Normal file
541
fmapi_isc_handler.c
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file fmapi_isc_handler.c
|
||||||
|
*
|
||||||
|
* @brief Code file for methods to respond to FM API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* struct timespec
|
||||||
|
* timespec_get()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
#include <ptrqueue.h>
|
||||||
|
#include <timeutils.h>
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include <fmapi.h>
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
#define ISO_TIME_BUF_LEN 32
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API ISC Background Operation Status Opcode (0002h)
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_isc_bos(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API ISC Background Operation Status\n", now);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
rsp.obj.isc_bos.running = cxl_state->bos_running;
|
||||||
|
rsp.obj.isc_bos.pcnt = cxl_state->bos_pcnt;
|
||||||
|
rsp.obj.isc_bos.opcode = cxl_state->bos_opcode;
|
||||||
|
rsp.obj.isc_bos.rc = cxl_state->bos_rc;
|
||||||
|
rsp.obj.isc_bos.ext = cxl_state->bos_ext;
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
//send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API ISC Identify Opcode (0001h)
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_isc_id(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
STEP // 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API ISC Identify\n", now);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
rsp.obj.isc_id_rsp.vid = cxl_state->vid;
|
||||||
|
rsp.obj.isc_id_rsp.did = cxl_state->did;
|
||||||
|
rsp.obj.isc_id_rsp.svid = cxl_state->svid;
|
||||||
|
rsp.obj.isc_id_rsp.ssid = cxl_state->ssid;
|
||||||
|
rsp.obj.isc_id_rsp.sn = cxl_state->sn;
|
||||||
|
rsp.obj.isc_id_rsp.size = cxl_state->max_msg_size_n;
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
//send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API ISC Get Response Message Limit Opcode (0003h)
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_isc_msg_limit_get(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API ISC Get Response Message Limit\n", now);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
rsp.obj.isc_msg_limit.limit = cxl_state->msg_rsp_limit_n;
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
//send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API ISC Set Response Message Limit Opcode (0004h)
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_isc_msg_limit_set(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API ISC Set Response Message Limit\n", now);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (req.obj.isc_msg_limit.limit < 8 || req.obj.isc_msg_limit.limit > 20)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested Message Response Limit outside allowed values. Requested: %d min: 8 max: 20\n", now, req.obj.isc_msg_limit.limit);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
cxl_state->msg_rsp_limit_n = req.obj.isc_msg_limit.limit;
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
rsp.obj.isc_msg_limit.limit = cxl_state->msg_rsp_limit_n;
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
1095
fmapi_mcc_handler.c
Normal file
1095
fmapi_mcc_handler.c
Normal file
File diff suppressed because it is too large
Load Diff
662
fmapi_mpc_handler.c
Normal file
662
fmapi_mpc_handler.c
Normal file
@ -0,0 +1,662 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file fmapi_mpc_handler.c
|
||||||
|
*
|
||||||
|
* @brief Code file for methods to respond to FM API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* struct timespec
|
||||||
|
* timespec_get()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
#include <ptrqueue.h>
|
||||||
|
#include <timeutils.h>
|
||||||
|
#include <arrayutils.h>
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include <fmapi.h>
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
#define ISO_TIME_BUF_LEN 32
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
int fmop_mcc_get_ld_alloc (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_get_qos_alloc (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_get_qos_ctrl (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_get_qos_limit (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_get_qos_stat (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_info (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_set_ld_alloc (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_set_qos_alloc (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_set_qos_ctrl (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
int fmop_mcc_set_qos_limit (struct port *p, struct fmapi_msg *req, struct fmapi_msg *rsp);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API MPC LD CXL.io Configuration Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_mpc_cfg(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct port *p;
|
||||||
|
__u16 reg;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API MPC LD CXL.io Config. PPID: %d LDID: %d\n", now, req.obj.mpc_cfg_req.ppid, req.obj.mpc_cfg_req.ldid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
// Validate port number
|
||||||
|
if (req.obj.mpc_cfg_req.ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Invalid Port number requested. PPID: %d\n", now, req.obj.mpc_cfg_req.ppid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[req.obj.mpc_cfg_req.ppid];
|
||||||
|
|
||||||
|
// Validate port is not bound
|
||||||
|
//if ( !(p->state == FMPS_DISABLED) )
|
||||||
|
//{
|
||||||
|
// IFV(CLVB_ERRORS) printf("%s ERR: Port is in a bound state. PPID: %d State: %s\n", now, req.obj.mpc_cfg_req.ppid, fmps(p->state));
|
||||||
|
// goto send;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Validate device attached to port is an MLD port
|
||||||
|
if ( !(p->dt == FMDT_CXL_TYPE_3 || p->dt == FMDT_CXL_TYPE_3_POOLED) )
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Port is not Type 3 device: Type: %s\n", now, fmdt(p->dt));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate LDID
|
||||||
|
if (req.obj.mpc_cfg_req.ldid >= p->ld)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested LD ID exceeds supported LD count of specified port. Requested LDID: %d\n", now, req.obj.mpc_cfg_req.ldid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
switch (req.obj.mpc_cfg_req.type)
|
||||||
|
{
|
||||||
|
case FMCT_READ: // 0x00
|
||||||
|
{
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Performing CXL.io Read on PPID: %d LDID: %d\n", now, req.obj.mpc_cfg_req.ppid, req.obj.mpc_cfg_req.ldid);
|
||||||
|
|
||||||
|
reg = (req.obj.mpc_cfg_req.ext << 8) | req.obj.mpc_cfg_req.reg;
|
||||||
|
|
||||||
|
rsp.obj.mpc_cfg_rsp.data[0] = 0;
|
||||||
|
rsp.obj.mpc_cfg_rsp.data[1] = 0;
|
||||||
|
rsp.obj.mpc_cfg_rsp.data[2] = 0;
|
||||||
|
rsp.obj.mpc_cfg_rsp.data[3] = 0;
|
||||||
|
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x01) rsp.obj.mpc_cfg_rsp.data[0] = p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+0];
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x02) rsp.obj.mpc_cfg_rsp.data[1] = p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+1];
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x04) rsp.obj.mpc_cfg_rsp.data[2] = p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+2];
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x08) rsp.obj.mpc_cfg_rsp.data[3] = p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+3];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FMCT_WRITE: // 0x01
|
||||||
|
{
|
||||||
|
HEX32("Write Data", *((int*)req.obj.mpc_cfg_req.data));
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Performing CXL.io Write on PPID: %d LDID: %d\n", now, req.obj.mpc_cfg_req.ppid, req.obj.mpc_cfg_req.ldid);
|
||||||
|
|
||||||
|
reg = (req.obj.mpc_cfg_req.ext << 8) | req.obj.mpc_cfg_req.reg;
|
||||||
|
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x01) p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+0] = req.obj.mpc_cfg_req.data[0];
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x02) p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+1] = req.obj.mpc_cfg_req.data[1];
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x04) p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+2] = req.obj.mpc_cfg_req.data[2];
|
||||||
|
if (req.obj.mpc_cfg_req.fdbe & 0x08) p->mld->cfgspace[req.obj.mpc_cfg_req.ldid][reg+3] = req.obj.mpc_cfg_req.data[3];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Invalid Action\n", now);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API MPC LD CXL.io Memory Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_mpc_mem(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct port *p;
|
||||||
|
__u64 base, max, ld_size, granularity;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API MPC LD CXL.io Mem. PPID: %d LDID: %d\n", now, req.obj.mpc_mem_req.ppid, req.obj.mpc_mem_req.ldid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
// Validate port number
|
||||||
|
if (req.obj.mpc_mem_req.ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Invalid Port number requested. PPID: %d\n", now, req.obj.mpc_mem_req.ppid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[req.obj.mpc_mem_req.ppid];
|
||||||
|
|
||||||
|
// Validate port is not bound
|
||||||
|
//if ( !(p->state == FMPS_DISABLED) )
|
||||||
|
//{
|
||||||
|
// IFV(CLVB_ERRORS) printf("%s ERR: Port is in a bound state: %s PPID: %d\n", now, fmps(p->state), req.obj.mpc_mem_req.ppid);
|
||||||
|
// goto send;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Validate device attached to port is an MLD port
|
||||||
|
if ( !(p->dt == FMDT_CXL_TYPE_3 || p->dt == FMDT_CXL_TYPE_3_POOLED) )
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Port is not Type 3 device. Requested Type: %s\n", now, fmdt(p->dt));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate LDID
|
||||||
|
if (req.obj.mpc_mem_req.ldid >= p->ld)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested LD ID exceeds supported LD count of specified port. LDID: %d\n", now, req.obj.mpc_mem_req.ldid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate memory backed file is mmaped
|
||||||
|
if (p->mld == NULL || p->mld->memspace == NULL)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested port does not have memory space on the specified port. Port: %d\n", now, p->ppid);
|
||||||
|
|
||||||
|
rc = FMRC_UNSUPPORTED;
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate offset & length
|
||||||
|
if (req.obj.mpc_mem_req.len > 4096)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested length exceeds maximum length supported (4096B). Requested Len: %d\n", now, req.obj.mpc_mem_req.len);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get granularity in bytes
|
||||||
|
granularity = 1024*1024;
|
||||||
|
switch (p->mld->granularity)
|
||||||
|
{
|
||||||
|
case FMMG_256MB: granularity *= 256; break;
|
||||||
|
case FMMG_512MB: granularity *= 512; break;
|
||||||
|
case FMMG_1GB: granularity *= 1024; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute size of requested LD
|
||||||
|
base = granularity * p->mld->rng1[req.obj.mpc_mem_req.ldid]; // base is the byte offset into the memspace
|
||||||
|
max = granularity * (p->mld->rng2[req.obj.mpc_mem_req.ldid] + 1); // max is the byte offset start of the next LD in the memspace
|
||||||
|
ld_size = max - base; // ld size in bytes
|
||||||
|
|
||||||
|
// Verify requested offset + len does not exceed the end of the LD
|
||||||
|
if ( (req.obj.mpc_mem_req.offset + req.obj.mpc_mem_req.len) >= ld_size)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested offset + length exceeds maximum size of LD. LD Max size (Bytes): %llu. Requested up to Byte: %llu\n", now, ld_size, req.obj.mpc_mem_req.offset + req.obj.mpc_mem_req.len);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
switch (req.obj.mpc_mem_req.type)
|
||||||
|
{
|
||||||
|
case FMCT_READ: // 0x00
|
||||||
|
INT32("Request Len", req.obj.mpc_mem_req.len);
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Performing CXL.io MEM Read on PPID: %d LDID: %d\n", now, req.obj.mpc_mem_req.ppid, req.obj.mpc_mem_req.ldid);
|
||||||
|
|
||||||
|
rsp.obj.mpc_mem_rsp.len = req.obj.mpc_mem_req.len;
|
||||||
|
memcpy(rsp.obj.mpc_mem_rsp.data, &p->mld->memspace[base + req.obj.mpc_mem_req.offset], req.obj.mpc_mem_req.len);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FMCT_WRITE: // 0x01
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Performing CXL.io MEM Write on PPID: %d LDID: %d\n", now, req.obj.mpc_mem_req.ppid, req.obj.mpc_mem_req.ldid);
|
||||||
|
|
||||||
|
memcpy(&p->mld->memspace[base + req.obj.mpc_mem_req.offset], req.obj.mpc_mem_req.data, req.obj.mpc_mem_req.len);
|
||||||
|
|
||||||
|
autl_prnt_buf(req.obj.mpc_mem_req.data, req.obj.mpc_mem_req.len, 4, 0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API MPC Tunnel Management Command Opcode
|
||||||
|
*
|
||||||
|
* @param hdr fmapi_hdr*
|
||||||
|
* @param src __u8* to Request FM API Message Payload in serialized form
|
||||||
|
* @param dst __u8* to Respnse FM API Message Payload in serialized form
|
||||||
|
* @return 1 to send reponse back to requestor, 0 to not send it
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Deserialize FM API Request Payload
|
||||||
|
* 2: Validate port number
|
||||||
|
* 3: Validate device attached to port is an MLD port
|
||||||
|
* 4: Confirm MCTP Message Type
|
||||||
|
* 5: Extract FM API HDR and switch on mesage opcode
|
||||||
|
* 6: Verify FM API Message is a request
|
||||||
|
* 7: Deserialize payload into buffer
|
||||||
|
* 8: Perform Requested Action
|
||||||
|
* 9: Serialize FM API Payload
|
||||||
|
* 10: Fill Response FM API HDR
|
||||||
|
* 11: Serialize FM API Header
|
||||||
|
* 12: Set MCTP Type
|
||||||
|
* 13: Serialize FM API Response Payload
|
||||||
|
* 14: Set return code
|
||||||
|
*/
|
||||||
|
int fmop_mpc_tmc(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct port *p;
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API MPC Tunneled Management Command. PPID: %d\n", now, req.obj.mpc_tmc_req.ppid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
// Validate MCTP Message Type
|
||||||
|
if (req.obj.mpc_tmc_req.type != MCMT_CXLCCI)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Tunneled command did not have a CXL CCI MCTP Type code. Tunneled MCTP Type code: %d\n", now, req.obj.mpc_tmc_req.type);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate port number
|
||||||
|
if (req.obj.mpc_tmc_req.ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s Invalid Port number requested. PPID: %d\n", now, req.obj.mpc_tmc_req.ppid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[req.obj.mpc_tmc_req.ppid];
|
||||||
|
|
||||||
|
// Validate device attached to port is an MLD port
|
||||||
|
if ( !(p->dt == FMDT_CXL_TYPE_3 || p->dt == FMDT_CXL_TYPE_3_POOLED) )
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s Port is not Type 3 device. Type: %s\n", now, fmdt(p->dt));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
{
|
||||||
|
struct fmapi_msg src, dst;
|
||||||
|
|
||||||
|
// Configure Buffer pointers
|
||||||
|
src.buf = (struct fmapi_buf*) req.obj.mpc_tmc_req.msg;
|
||||||
|
dst.buf = (struct fmapi_buf*) rsp.obj.mpc_tmc_rsp.msg;
|
||||||
|
|
||||||
|
// Deserialize Sub Header
|
||||||
|
fmapi_deserialize(&src.hdr, src.buf->hdr, FMOB_HDR, 0);
|
||||||
|
|
||||||
|
// Verify sub message is a request
|
||||||
|
if (src.hdr.category != FMMT_REQ)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Tunneled FM API Message Category is not a request. Tunneled FM API Message Category: %d\n", now, src.hdr.category);
|
||||||
|
|
||||||
|
// Fill Sub Header
|
||||||
|
len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, src.hdr.tag, src.hdr.opcode, 0, 0, FMRC_INVALID_INPUT, 0);
|
||||||
|
|
||||||
|
// Serialize Sub Header
|
||||||
|
fmapi_serialize(dst.buf->hdr, &dst.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
goto sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Opcode
|
||||||
|
switch (src.hdr.opcode)
|
||||||
|
{
|
||||||
|
case FMOP_MCC_INFO: len = fmop_mcc_info (p, &src, &dst); break; // 0x5400
|
||||||
|
case FMOP_MCC_ALLOC_GET: len = fmop_mcc_get_ld_alloc (p, &src, &dst); break; // 0x5401
|
||||||
|
case FMOP_MCC_ALLOC_SET: len = fmop_mcc_set_ld_alloc (p, &src, &dst); break; // 0x5402
|
||||||
|
case FMOP_MCC_QOS_CTRL_GET: len = fmop_mcc_get_qos_ctrl (p, &src, &dst); break; // 0x5403
|
||||||
|
case FMOP_MCC_QOS_CTRL_SET: len = fmop_mcc_set_qos_ctrl (p, &src, &dst); break; // 0x5404
|
||||||
|
case FMOP_MCC_QOS_STAT: len = fmop_mcc_get_qos_stat (p, &src, &dst); break; // 0x5405
|
||||||
|
case FMOP_MCC_QOS_BW_ALLOC_GET: len = fmop_mcc_get_qos_alloc(p, &src, &dst); break; // 0x5406
|
||||||
|
case FMOP_MCC_QOS_BW_ALLOC_SET: len = fmop_mcc_set_qos_alloc(p, &src, &dst); break; // 0x5407
|
||||||
|
case FMOP_MCC_QOS_BW_LIMIT_GET: len = fmop_mcc_get_qos_limit(p, &src, &dst); break; // 0x5408
|
||||||
|
case FMOP_MCC_QOS_BW_LIMIT_SET: len = fmop_mcc_set_qos_limit(p, &src, &dst); break; // 0x5409
|
||||||
|
default:
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Tunneled FM API Mesage has an invalid opcode. Tunneled FM API Message Opcode %d\n", now, src.hdr.opcode);
|
||||||
|
|
||||||
|
// Fill Sub Header
|
||||||
|
len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, src.hdr.tag, src.hdr.opcode, 0, 0, FMRC_UNSUPPORTED, 0);
|
||||||
|
|
||||||
|
// Serialize Sub Header
|
||||||
|
fmapi_serialize(dst.buf->hdr, &dst.hdr, FMOB_HDR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub:
|
||||||
|
|
||||||
|
// Fill Response Object
|
||||||
|
rsp.obj.mpc_tmc_rsp.len = len;
|
||||||
|
rsp.obj.mpc_tmc_rsp.type = req.obj.mpc_tmc_req.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
624
fmapi_psc_handler.c
Normal file
624
fmapi_psc_handler.c
Normal file
@ -0,0 +1,624 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file fmapi_psc_handler.c
|
||||||
|
*
|
||||||
|
* @brief Code file for methods to respond to FM API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* struct timespec
|
||||||
|
* timespec_get()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
#include <ptrqueue.h>
|
||||||
|
#include <timeutils.h>
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include <fmapi.h>
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
#define ISO_TIME_BUF_LEN 32
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API PSC CXL.io Configuration Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_psc_cfg(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct port *p;
|
||||||
|
__u16 reg;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API PSC CXL.io Config. PPID: %d\n", now, req.obj.psc_cfg_req.ppid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (req.obj.psc_cfg_req.ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested PPDI exceeds number of ports present. Requested PPID: %d Present: %d\n", now, req.obj.psc_cfg_req.ppid, cxl_state->num_ports);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[req.obj.psc_cfg_req.ppid];
|
||||||
|
|
||||||
|
// Validate port is not bound or is an MLD port
|
||||||
|
//if ( !(p->state == FMPS_DISABLED || p->ld > 0) )
|
||||||
|
//{
|
||||||
|
// IFV(CLVB_ERRORS) printf("%s Port is not unbound or is not an MLD Port. PPID: %d Port State: %s Num LD: %d\n", now, req.obj.psc_cfg_req.ppid, fmps(p->state), p->ld);
|
||||||
|
// goto send;
|
||||||
|
//}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
switch (req.obj.psc_cfg_req.type)
|
||||||
|
{
|
||||||
|
case FMCT_READ: // 0x00
|
||||||
|
{
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Performing CXL.io Read on PPID: %d\n", now, req.obj.psc_cfg_req.ppid);
|
||||||
|
|
||||||
|
reg = (req.obj.psc_cfg_req.ext << 8) | req.obj.psc_cfg_req.reg;
|
||||||
|
|
||||||
|
rsp.obj.psc_cfg_rsp.data[0] = 0;
|
||||||
|
rsp.obj.psc_cfg_rsp.data[1] = 0;
|
||||||
|
rsp.obj.psc_cfg_rsp.data[2] = 0;
|
||||||
|
rsp.obj.psc_cfg_rsp.data[3] = 0;
|
||||||
|
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x01) rsp.obj.psc_cfg_rsp.data[0] = p->cfgspace[reg+0];
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x02) rsp.obj.psc_cfg_rsp.data[1] = p->cfgspace[reg+1];
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x04) rsp.obj.psc_cfg_rsp.data[2] = p->cfgspace[reg+2];
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x08) rsp.obj.psc_cfg_rsp.data[3] = p->cfgspace[reg+3];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FMCT_WRITE: // 0x01
|
||||||
|
{
|
||||||
|
HEX32("Write Data", *((int*)req.obj.psc_cfg_req.data));
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Performing CXL.io Write on PPID: %d\n", now, req.obj.psc_cfg_req.ppid);
|
||||||
|
|
||||||
|
reg = (req.obj.psc_cfg_req.ext << 8) | req.obj.psc_cfg_req.reg;
|
||||||
|
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x01) p->cfgspace[reg+0] = req.obj.psc_cfg_req.data[0];
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x02) p->cfgspace[reg+1] = req.obj.psc_cfg_req.data[1];
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x04) p->cfgspace[reg+2] = req.obj.psc_cfg_req.data[2];
|
||||||
|
if (req.obj.psc_cfg_req.fdbe & 0x08) p->cfgspace[reg+3] = req.obj.psc_cfg_req.data[3];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API PSC Identify Switch Device Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_psc_id(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API PSC Identify Switch Device\n", now);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
state_conv_identity(cxl_state, &rsp.obj.psc_id_rsp);
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
//send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API PSC Get Physical Port State Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_psc_port(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
__u8 id;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API PSC Get Physical Port Status. Num: %d\n", now, req.obj.psc_port_req.num);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
for ( i = 0, rsp.obj.psc_port_rsp.num = 0 ; i < req.obj.psc_port_req.num ; i++ )
|
||||||
|
{
|
||||||
|
id = req.obj.psc_port_req.ports[i];
|
||||||
|
|
||||||
|
// Validate portid
|
||||||
|
if (id >= cxl_state->num_ports)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Copy the data
|
||||||
|
state_conv_port_info(&cxl_state->ports[id], &rsp.obj.psc_port_rsp.list[i]);
|
||||||
|
rsp.obj.psc_port_rsp.num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
//send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API PSC Physical Port Control Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_psc_port_ctrl(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct port *p;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API PSC Physical Port Control. PPID: %d Opcode: %d\n", now, req.obj.psc_port_ctrl_req.ppid, req.obj.psc_port_ctrl_req.opcode);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (req.obj.psc_port_ctrl_req.ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested PPID exceeds number of ports present. Requested PPID: %d Present: %d\n", now, req.obj.psc_port_ctrl_req.ppid, cxl_state->num_ports);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[req.obj.psc_port_ctrl_req.ppid];
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
switch (req.obj.psc_port_ctrl_req.opcode)
|
||||||
|
{
|
||||||
|
case FMPO_ASSERT_PERST: // 0x00
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Asserting PERST on PPID: %d\n", now, req.obj.psc_port_ctrl_req.ppid);
|
||||||
|
|
||||||
|
p->perst = 0x1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FMPO_DEASSERT_PERST: // 0x01
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Deasserting PERST on PPID: %d\n", now, req.obj.psc_port_ctrl_req.ppid);
|
||||||
|
|
||||||
|
p->perst = 0x0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FMPO_RESET_PPB: // 0x02
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Resetting PPID: %d\n", now, req.obj.psc_port_ctrl_req.ppid);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Invalid port control action Opcode. Opcode: 0x%04x\n", now, req.obj.psc_port_ctrl_req.opcode);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
739
fmapi_vsc_handler.c
Normal file
739
fmapi_vsc_handler.c
Normal file
@ -0,0 +1,739 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file fmapi_vsc_handler.c
|
||||||
|
*
|
||||||
|
* @brief Code file for methods to respond to FM API commands
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* struct timespec
|
||||||
|
* timespec_get()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
#include <ptrqueue.h>
|
||||||
|
#include <timeutils.h>
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include <fmapi.h>
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
#define ISO_TIME_BUF_LEN 32
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API VSC Generate AER Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_vsc_aer(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct vcs *v;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API VSC Generate AER Event. VCSID: %d vPPBID: %d\n", now, req.obj.vsc_aer_req.vcsid, req.obj.vsc_aer_req.vppbid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
if (req.obj.vsc_aer_req.vcsid >= cxl_state->num_vcss)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested VCSID exceeds number of VCSs present. Requested VCSID: %d Present: %d\n", now, req.obj.vsc_aer_req.vcsid, cxl_state->num_vcss);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
v = &cxl_state->vcss[req.obj.vsc_aer_req.vcsid];
|
||||||
|
|
||||||
|
// Validate vppbid
|
||||||
|
if (req.obj.vsc_aer_req.vppbid >= v->num)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Requested vPPBID exceeds number of vPPBs present in requested VCS. Requested vPPBID: %d Present: %d\n", now, req.obj.vsc_aer_req.vppbid, v->num);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Generating AER on VSCID: %d vPPBID: %d Error: 0x%08x\n", now, req.obj.vsc_aer_req.vcsid, req.obj.vsc_aer_req.vppbid, req.obj.vsc_aer_req.error_type);
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API VSC Bind Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_vsc_bind(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct vcs *v;
|
||||||
|
struct vppb *b;
|
||||||
|
struct port *p;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API VSC Bind vPPB. VCSID: %d vPPBID: %d PPID: %d LDID: 0x%04x\n", now, req.obj.vsc_bind_req.vcsid, req.obj.vsc_bind_req.vppbid, req.obj.vsc_bind_req.ppid, req.obj.vsc_bind_req.ldid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
// Validate vcsid
|
||||||
|
if (req.obj.vsc_bind_req.vcsid >= cxl_state->num_vcss)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: VCS ID out of range. VCSID: %d\n", now, req.obj.vsc_bind_req.vcsid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
v = &cxl_state->vcss[req.obj.vsc_bind_req.vcsid];
|
||||||
|
|
||||||
|
// Validate vppbid
|
||||||
|
if (req.obj.vsc_bind_req.vppbid >= cxl_state->vcss[req.obj.vsc_bind_req.vcsid].num)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: vPPB ID out of range. vPPBID: %d\n", now, req.obj.vsc_bind_req.vppbid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
b = &v->vppbs[req.obj.vsc_bind_req.vppbid];
|
||||||
|
|
||||||
|
// Validate port id
|
||||||
|
if (req.obj.vsc_bind_req.ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: PPID ID out of range. PPID: %d\n", now, req.obj.vsc_bind_req.ppid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[req.obj.vsc_bind_req.ppid];
|
||||||
|
|
||||||
|
// Check bindability to this port
|
||||||
|
|
||||||
|
// Check state of port
|
||||||
|
if (p->state == FMPS_DISABLED)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Port is in a disabled state. PPID: %d State: %s\n", now, req.obj.vsc_bind_req.ppid, fmps(p->state));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an LD is specified, check if the port is connected to a Type-3 Devices
|
||||||
|
if (req.obj.vsc_bind_req.ldid != 0xFFFF && !(p->dt == FMDT_CXL_TYPE_3 || p->dt == FMDT_CXL_TYPE_3_POOLED) )
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Bind to an MLD LD requested and specified port is not attached to a Type 3 Device\n", now);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If port is an MLD port, an LDID must be specified
|
||||||
|
if (p->ld > 0 && req.obj.vsc_bind_req.ldid == 0xFFFF)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Cannot bind to the physical port of an MLD device\n", now);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an LD is specified, check if the port can support multiple LDs
|
||||||
|
if (req.obj.vsc_bind_req.ldid != 0xFFFF && p->ld == 0)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Specified port does not support multiple Logical Devices: \n", now);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if vPPB is aleady bound
|
||||||
|
if (b->bind_status != FMBS_UNBOUND)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Specified vPPB is not available to be bound. vPPBID: %d STATUS: %s\n", now, req.obj.vsc_bind_req.vppbid, fmbs(b->bind_status));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Binding VCSID: %d vPPBID: %d PPID: %d LDID: 0x%04x\n", now, req.obj.vsc_bind_req.vcsid, req.obj.vsc_bind_req.vppbid, req.obj.vsc_bind_req.ppid, req.obj.vsc_bind_req.ldid);
|
||||||
|
|
||||||
|
if (req.obj.vsc_bind_req.ldid != 0xFFFF)
|
||||||
|
{
|
||||||
|
b->bind_status = FMBS_BOUND_LD;
|
||||||
|
b->ppid = req.obj.vsc_bind_req.ppid;
|
||||||
|
b->ldid = req.obj.vsc_bind_req.ldid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b->bind_status = FMBS_BOUND_PORT;
|
||||||
|
b->ppid = req.obj.vsc_bind_req.ppid;
|
||||||
|
b->ldid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 6: Set port state to be a downstream port
|
||||||
|
p->state = FMPS_DSP;
|
||||||
|
|
||||||
|
// Update Background Operation Status
|
||||||
|
cxl_state->bos_running = 0;
|
||||||
|
cxl_state->bos_pcnt = 100;
|
||||||
|
cxl_state->bos_opcode = req.hdr.opcode;
|
||||||
|
cxl_state->bos_rc = FMRC_SUCCESS;
|
||||||
|
cxl_state->bos_ext = 0;
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_BACKGROUND_OP_STARTED;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API VSC Get Virtual CXL Switch Info Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_vsc_info(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct vcs *v;
|
||||||
|
unsigned i, k, stop, vppbid_start, vppbid_limit;
|
||||||
|
struct fmapi_vsc_info_blk *blk;
|
||||||
|
__u8 id;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API VSC Get Virtual Switch Info. Num: %d\n", now, req.obj.vsc_info_req.num);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
rsp.obj.vsc_info_rsp.num = 0;
|
||||||
|
vppbid_start = req.obj.vsc_info_req.vppbid_start;
|
||||||
|
vppbid_limit = req.obj.vsc_info_req.vppbid_limit;
|
||||||
|
for ( i = 0 ; i < req.obj.vsc_info_req.num ; i++ )
|
||||||
|
{
|
||||||
|
id = req.obj.vsc_info_req.vcss[i];
|
||||||
|
|
||||||
|
// Break, if we have reached the maximum number of VCS entities that can be returned
|
||||||
|
if (i >= FM_MAX_VCS_PER_RSP)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Skip VCS IDs that exceed current size
|
||||||
|
if (id >= cxl_state->num_vcss)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get pointers to objects to copy
|
||||||
|
v = &cxl_state->vcss[id]; // The struct vcs to copy from
|
||||||
|
blk = &rsp.obj.vsc_info_rsp.list[i]; // The struct fmapi_vcs_info_blk to copy into
|
||||||
|
|
||||||
|
// Zero out destination
|
||||||
|
memset(blk, 0, sizeof(*blk));
|
||||||
|
|
||||||
|
// Copy information
|
||||||
|
blk->vcsid = v->vcsid; // Virtual CXL Switch ID
|
||||||
|
blk->state = v->state; // VCS State [FMVS]
|
||||||
|
blk->uspid = v->uspid; // USP ID. Upstream physical port ID
|
||||||
|
blk->total = v->num; // Total Number of vPPBs in the VCS.
|
||||||
|
blk->num = 0; // The number vppb blks returned in this object
|
||||||
|
|
||||||
|
// Determine number of vPPB entires to return
|
||||||
|
stop = v->num;
|
||||||
|
if ( vppbid_limit < (stop - vppbid_start) )
|
||||||
|
stop = vppbid_start + vppbid_limit;
|
||||||
|
|
||||||
|
// Variable array of PPB Status Blocks
|
||||||
|
for ( k = vppbid_start ; k < stop ; k++ ) {
|
||||||
|
blk->list[k].status = v->vppbs[k].bind_status;
|
||||||
|
blk->list[k].ppid = v->vppbs[k].ppid;
|
||||||
|
blk->list[k].ldid = v->vppbs[k].ldid;
|
||||||
|
blk->num++;
|
||||||
|
}
|
||||||
|
rsp.obj.vsc_info_rsp.num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_SUCCESS;
|
||||||
|
|
||||||
|
//send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for FM API VSC Unbind Opcode
|
||||||
|
*
|
||||||
|
* @param m struct mctp*
|
||||||
|
* @param mm struct mctp_msg*
|
||||||
|
* @return 0 upon success, 1 otherwise
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Checkout Response mctp_msg buffer
|
||||||
|
* 3: Fill Response MCTP Header
|
||||||
|
* 4: Set buffer pointers
|
||||||
|
* 5: Deserialize Request Header
|
||||||
|
* 6: Deserialize Request Object
|
||||||
|
* 7: Extract parameters
|
||||||
|
* 8: Obtain lock on switch state
|
||||||
|
* 9: Validate Inputs
|
||||||
|
* 10: Perform Action
|
||||||
|
* 11: Prepare Response Object
|
||||||
|
* 12: Serialize Response Object
|
||||||
|
* 13: Set return code
|
||||||
|
* 14: Release lock on switch state
|
||||||
|
* 15: Fill Response Header
|
||||||
|
* 16: Serialize Header
|
||||||
|
* 17: Push Response mctp_msg onto Transmit Message Queue
|
||||||
|
* 18: Checkin mctp_msgs
|
||||||
|
*/
|
||||||
|
int fmop_vsc_unbind(struct mctp *m, struct mctp_action *ma)
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
char now[ISO_TIME_BUF_LEN];
|
||||||
|
struct fmapi_msg req, rsp;
|
||||||
|
|
||||||
|
unsigned rc;
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
struct vcs *v;
|
||||||
|
struct vppb *b;
|
||||||
|
struct port *p;
|
||||||
|
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
STEP // 1: Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
len = 0;
|
||||||
|
rc = FMRC_INVALID_INPUT;
|
||||||
|
isotime(now, ISO_TIME_BUF_LEN);
|
||||||
|
|
||||||
|
STEP // 2: Get response mctp_msg buffer
|
||||||
|
ma->rsp = pq_pop(m->msgs, 1);
|
||||||
|
if (ma->rsp == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 3: Fill Response MCTP Header: dst, src, owner, tag, and type
|
||||||
|
mctp_fill_msg_hdr(ma->rsp, ma->req->src, m->state.eid, 0, ma->req->tag);
|
||||||
|
ma->rsp->type = ma->req->type;
|
||||||
|
|
||||||
|
// 4: Set buffer pointers
|
||||||
|
req.buf = (struct fmapi_buf*) ma->req->payload;
|
||||||
|
rsp.buf = (struct fmapi_buf*) ma->rsp->payload;
|
||||||
|
|
||||||
|
STEP // 5: Deserialize Request Header
|
||||||
|
if ( fmapi_deserialize(&req.hdr, req.buf->hdr, FMOB_HDR, NULL) <= 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 6: Deserialize Request Object
|
||||||
|
if ( fmapi_deserialize(&req.obj, req.buf->payload, fmapi_fmob_req(req.hdr.opcode), NULL) < 0 )
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 7: Extract parameters
|
||||||
|
|
||||||
|
IFV(CLVB_COMMANDS) printf("%s CMD: FM API VSC Unbind vPPB. VCSID: %d vPPBID: %d\n", now, req.obj.vsc_unbind_req.vcsid, req.obj.vsc_unbind_req.vppbid);
|
||||||
|
|
||||||
|
STEP // 8: Obtain lock on switch state
|
||||||
|
pthread_mutex_lock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
STEP // 9: Validate Inputs
|
||||||
|
|
||||||
|
// Validate vcsid
|
||||||
|
if (req.obj.vsc_unbind_req.vcsid >= cxl_state->num_vcss)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: VCS ID out of range. VCSID: %d\n", now, req.obj.vsc_unbind_req.vcsid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
v = &cxl_state->vcss[req.obj.vsc_unbind_req.vcsid];
|
||||||
|
|
||||||
|
// Validate vppbid
|
||||||
|
if (req.obj.vsc_unbind_req.vppbid >= cxl_state->vcss[req.obj.vsc_unbind_req.vcsid].num)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: vPPB ID out of range. vPPBID: %d\n", now, req.obj.vsc_unbind_req.vppbid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
b = &v->vppbs[req.obj.vsc_unbind_req.vppbid];
|
||||||
|
|
||||||
|
// Validate bind status of vppb
|
||||||
|
if (b->bind_status == FMBS_UNBOUND || b->bind_status == FMBS_INPROGRESS)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: vPPB was not bound. vPPBID %d\n", now, req.obj.vsc_unbind_req.vppbid);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate port id that the vppb was bound to
|
||||||
|
if (b->ppid >= cxl_state->num_ports)
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: PPID of bound port out of range. PPID: %d\n", now, b->ppid);
|
||||||
|
b->bind_status = FMBS_UNBOUND;
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
p = &cxl_state->ports[b->ppid];
|
||||||
|
|
||||||
|
// Check bindability to this port
|
||||||
|
|
||||||
|
// Check state of port
|
||||||
|
if ( !(p->state == FMPS_BINDING || p->state == FMPS_UNBINDING || p->state == FMPS_USP || p->state == FMPS_DSP) )
|
||||||
|
{
|
||||||
|
IFV(CLVB_ERRORS) printf("%s ERR: Port is not in a bound state. PPID: %d State: %s\n", now, b->ppid, fmps(p->state));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 10: Perform Action
|
||||||
|
|
||||||
|
IFV(CLVB_ACTIONS) printf("%s ACT: Unbinding VCSID: %d vPPBID: %d\n", now, req.obj.vsc_unbind_req.vcsid, req.obj.vsc_unbind_req.vppbid);
|
||||||
|
|
||||||
|
b->bind_status = FMBS_UNBOUND;
|
||||||
|
b->ppid = 0;
|
||||||
|
b->ldid = 0;
|
||||||
|
|
||||||
|
// Update Background Operation Status
|
||||||
|
cxl_state->bos_running = 0;
|
||||||
|
cxl_state->bos_pcnt = 100;
|
||||||
|
cxl_state->bos_opcode = req.hdr.opcode;
|
||||||
|
cxl_state->bos_rc = FMRC_SUCCESS;
|
||||||
|
cxl_state->bos_ext = 0;
|
||||||
|
|
||||||
|
STEP // 11: Prepare Response Object
|
||||||
|
|
||||||
|
STEP // 12: Serialize Response Object
|
||||||
|
len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode));
|
||||||
|
|
||||||
|
STEP // 13: Set return code
|
||||||
|
rc = FMRC_BACKGROUND_OP_STARTED;
|
||||||
|
|
||||||
|
send:
|
||||||
|
|
||||||
|
STEP // 14: Release lock on switch state
|
||||||
|
pthread_mutex_unlock(&cxl_state->mtx);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
STEP // 15: Fill Response Header
|
||||||
|
ma->rsp->len = fmapi_fill_hdr(&rsp.hdr, FMMT_RESP, req.hdr.tag, req.hdr.opcode, 0, len, rc, 0);
|
||||||
|
|
||||||
|
STEP // 16: Serialize Header
|
||||||
|
fmapi_serialize(rsp.buf->hdr, &rsp.hdr, FMOB_HDR);
|
||||||
|
|
||||||
|
STEP // 17: Push mctp_action onto queue
|
||||||
|
pq_push(m->tmq, ma);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rc)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
207
main.c
Normal file
207
main.c
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file cse.c
|
||||||
|
*
|
||||||
|
* @brief Code file for entry point CXL Switch Emulator
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
/* mctp_init()
|
||||||
|
* mctp_set_mh()
|
||||||
|
* mctp_run()
|
||||||
|
*/
|
||||||
|
#include <mctp.h>
|
||||||
|
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "fmapi_handler.h"
|
||||||
|
#include "emapi_handler.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cse main
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 0: Parse CLI options
|
||||||
|
* 1: Register Signal Handlers
|
||||||
|
* 2: Initialize global state array
|
||||||
|
* 3: Load state file
|
||||||
|
* 4: Print the state
|
||||||
|
* 5: MCTP Init
|
||||||
|
* 6: Run MCTP
|
||||||
|
* 7: While loop
|
||||||
|
* 8: Stop MCTP
|
||||||
|
* 9: Free memory
|
||||||
|
*/
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
INIT
|
||||||
|
int rv;
|
||||||
|
struct mctp *m;
|
||||||
|
|
||||||
|
// Initialize varaibles
|
||||||
|
stop_requested = 0;
|
||||||
|
rv = 1;
|
||||||
|
|
||||||
|
// 0: Parse CLI options
|
||||||
|
rv = options_parse(argc,argv);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
printf("Error: Parse options failed: %d\n", rv);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 1: Register Signal Handlers
|
||||||
|
signals_register();
|
||||||
|
|
||||||
|
STEP // 2: Initialize global state array
|
||||||
|
cxl_state = state_init(32, 32, 256);
|
||||||
|
if (cxl_state == NULL)
|
||||||
|
{
|
||||||
|
printf("Error: state init failed \n");
|
||||||
|
goto end_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 3: Load state file
|
||||||
|
if (opts[CLOP_CONFIG_FILE].set)
|
||||||
|
{
|
||||||
|
rv = state_load(cxl_state, opts[CLOP_CONFIG_FILE].str);
|
||||||
|
if (rv < 0)
|
||||||
|
{
|
||||||
|
printf("Error: state load config file failed \n");
|
||||||
|
goto end_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 4: Print the state
|
||||||
|
if (opts[CLOP_PRINT_STATE].set)
|
||||||
|
state_print(cxl_state);
|
||||||
|
|
||||||
|
STEP // 5: MCTP Init
|
||||||
|
m = mctp_init();
|
||||||
|
if (m == NULL)
|
||||||
|
goto end_state;
|
||||||
|
|
||||||
|
// Set supported MCTP Message Versions
|
||||||
|
mctp_set_version(m, MCMT_CXLFMAPI, 0xF2,0xF1,0xFF,0x00);
|
||||||
|
mctp_set_version(m, MCMT_CXLCCI, 0xF2,0xF1,0xFF,0x00);
|
||||||
|
|
||||||
|
// Set Message handler functions
|
||||||
|
mctp_set_handler(m, MCMT_CXLFMAPI, fmapi_handler);
|
||||||
|
mctp_set_handler(m, MCMT_CSE, emapi_handler);
|
||||||
|
|
||||||
|
// Set MCTP verbosity levels
|
||||||
|
mctp_set_verbosity(m, opts[CLOP_MCTP_VERBOSITY].u64);
|
||||||
|
|
||||||
|
STEP // 6: Run MCTP
|
||||||
|
rv = mctp_run(m, opts[CLOP_TCP_PORT].u16, opts[CLOP_TCP_ADDRESS].u32, MCRM_SERVER, 1, 1);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
switch (rv)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
printf("Socket create failed\n");
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
printf("Socket bind failed\n");
|
||||||
|
break;
|
||||||
|
case -3:
|
||||||
|
printf("Socket connect failed");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("Could not create Connection Handler Thread\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("MCTP threads failed to start\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto end_mctp;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 7: While loop
|
||||||
|
while ( stop_requested == 0 )
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
STEP // 8: Stop MCTP
|
||||||
|
mctp_stop(m);
|
||||||
|
|
||||||
|
end_mctp:
|
||||||
|
|
||||||
|
mctp_free(m);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end_state:
|
||||||
|
|
||||||
|
state_free(cxl_state);
|
||||||
|
|
||||||
|
end_options:
|
||||||
|
|
||||||
|
options_free(opts);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
EXIT(rv)
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
};
|
||||||
|
|
||||||
717
options.c
Normal file
717
options.c
Normal file
@ -0,0 +1,717 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file options.c
|
||||||
|
*
|
||||||
|
* @brief Code file for cli options parsing using argp/argz library
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* memset()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* free()
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* inet_pton()
|
||||||
|
*/
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* struct argp
|
||||||
|
* struct argp_state
|
||||||
|
* argp_parse()
|
||||||
|
*/
|
||||||
|
#include <argp.h>
|
||||||
|
|
||||||
|
/* autl_prnt_buf()
|
||||||
|
*/
|
||||||
|
#include <arrayutils.h>
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
static int pr_main(int key, char *arg, struct argp_state *state);
|
||||||
|
static void print_help();
|
||||||
|
static void print_options(struct argp_option *o);
|
||||||
|
static void print_options_array(struct opt *o);
|
||||||
|
static void print_usage(struct argp_option *o);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global char pointer to dynamically store the name of the application
|
||||||
|
*
|
||||||
|
* This is allocated and stored when parse_options() is called
|
||||||
|
*/
|
||||||
|
static char *app_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String representation of CLOP Enumeration
|
||||||
|
*/
|
||||||
|
char *STR_CLOP[] = {
|
||||||
|
"VERBOSITY",
|
||||||
|
"MCTP_VERBOSITY",
|
||||||
|
"PRINT_STATE",
|
||||||
|
"PRINT_OPTIONS",
|
||||||
|
"CONFIG_FILE",
|
||||||
|
"TCP_PORT"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String representation of CLVO Enumeration
|
||||||
|
*/
|
||||||
|
char *STR_CLVO[] = {
|
||||||
|
"General verbose output", // CVSO_GENERAL = 0
|
||||||
|
"Call Stack", // CVSO_CALLSTACK = 1
|
||||||
|
"STEPS", // CVSO_STEPS = 2
|
||||||
|
"Parsing", // CVSO_PARSE = 3
|
||||||
|
"Actions", // CVSO_ACTIONS = 4
|
||||||
|
"Commands", // CVSO_COMMANDS = 5
|
||||||
|
"Errors" // CVSO_ERRORS = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options array that stores all parsed optioons
|
||||||
|
*/
|
||||||
|
struct opt *opts = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global string used by argp to print version with --version
|
||||||
|
*/
|
||||||
|
const char *argp_program_version = "version 0.1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global string used by argp when printing the help message
|
||||||
|
*/
|
||||||
|
const char *argp_program_bug_address = "code@jrlabs.io";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aray of argp_option structs to define the CLI options
|
||||||
|
*
|
||||||
|
* Non character options
|
||||||
|
* 701 - verbosity-options
|
||||||
|
* 702 - verbosity-hex
|
||||||
|
* 703 - verbosity-mctp
|
||||||
|
*/
|
||||||
|
struct argp_option ao_main[] =
|
||||||
|
{
|
||||||
|
{0,0,0,0, "File Options",1},
|
||||||
|
{"config", 'c', "FILE", 0, "File name of CXL switch config file", 0},
|
||||||
|
{0,0,0,0, "Networking Options",2},
|
||||||
|
{"tcp-port", 'P', "INT", 0, "Server TCP Port", 0},
|
||||||
|
{"tcp-address", 'T', "INT", 0, "Server TCP Address", 0}
|
||||||
|
,
|
||||||
|
{0,0,0,0, "Verbosity Options",8},
|
||||||
|
{"print-options", 706, NULL, OPTION_HIDDEN, "Print the initial State", 0},
|
||||||
|
{"state", 's', NULL, OPTION_HIDDEN, "Print the initial State", 0},
|
||||||
|
{"log", 'l', NULL, 0, "Emit Log output", 0} ,
|
||||||
|
{"verbose", 'v', NULL, 0, "Verbose output", 0} ,
|
||||||
|
{"verbosity", 'V', "INT", 0, "Set Verbosity Option", 0},
|
||||||
|
{"verbosity-hex", 'X', "HEX", 0, "Set Verbosity Bitfield (in hex)", 0},
|
||||||
|
{"verbosity-mctp", 'Z', "HEX", OPTION_HIDDEN, "MCTP Verbosity Bitfield (in hex)", 0},
|
||||||
|
{"options", 707, NULL, 0, "Print list of verbosity flags", 0},
|
||||||
|
{0,0,0,0, "Help Options", 9},
|
||||||
|
{"help", 'h', NULL, 0, "Display Help", 0},
|
||||||
|
{"usage", 701, NULL, 0, "Display Usage", 0},
|
||||||
|
{"version", 702, NULL, 0, "Display Version", 0},
|
||||||
|
{0,0,0,0,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options that are passed to argp
|
||||||
|
*/
|
||||||
|
struct argp argp =
|
||||||
|
{
|
||||||
|
ao_main, // An array of argp_option structures
|
||||||
|
pr_main, // Function to call when parsing each option
|
||||||
|
NULL, // Help text "ARG1 ARG2" that is displayed after usage eg: Usage: argp.out [OPTION...] ARG1 ARG2
|
||||||
|
NULL, // User help text at top of --help output
|
||||||
|
NULL, // A vector of argp_children structures
|
||||||
|
NULL, // A function to filter the output of help messages
|
||||||
|
NULL // String domain used to translate strings in argp library
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a string representation of CLI Option Names [CLOP]
|
||||||
|
*
|
||||||
|
* @param u CLI Option Enumeration value [CLOP]
|
||||||
|
*/
|
||||||
|
char *clop(int u)
|
||||||
|
{
|
||||||
|
if (u >= CLOP_MAX)
|
||||||
|
return NULL;
|
||||||
|
return STR_CLOP[u];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse function called by parse args for each parameter passed in on the command line
|
||||||
|
*
|
||||||
|
* @detail This function is called by parse_argp() for each option encoutered
|
||||||
|
* @return 0 success, non-zero to indicate a problem
|
||||||
|
*
|
||||||
|
* STEPS:
|
||||||
|
* 1: Get a pointer to thearguments object for argz
|
||||||
|
* 2: Handle each option based on the key
|
||||||
|
*/
|
||||||
|
static int pr_main (
|
||||||
|
int key, // short name for the option e.g. 'd' or a number
|
||||||
|
char *arg, // pointer to string entered after the key
|
||||||
|
struct argp_state *state // State that is available to each call to this function
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct opt *o;
|
||||||
|
int rv, i;
|
||||||
|
|
||||||
|
// STEP 2: Handle each option based on the key
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
// config
|
||||||
|
case 'c':
|
||||||
|
o = &opts[CLOP_CONFIG_FILE];
|
||||||
|
o->set = 1;
|
||||||
|
o->str = strndup(arg, CLMR_MAX_ARG_STR_LEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// help
|
||||||
|
case 'h':
|
||||||
|
print_help();
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// log
|
||||||
|
case 'l':
|
||||||
|
o = &opts[CLOP_VERBOSITY];
|
||||||
|
o->set = 1;
|
||||||
|
|
||||||
|
o->u64 |= CLVB_ACTIONS;
|
||||||
|
o->u64 |= CLVB_COMMANDS;
|
||||||
|
o->u64 |= CLVB_ERRORS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// tcp-port
|
||||||
|
case 'P':
|
||||||
|
o = &opts[CLOP_TCP_PORT];
|
||||||
|
o->set = 1;
|
||||||
|
o->u16 = strtoul(arg, NULL, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TCP Address
|
||||||
|
case 'T':
|
||||||
|
o = &opts[CLOP_TCP_ADDRESS];
|
||||||
|
o->set = 1;
|
||||||
|
rv = inet_pton(AF_INET, arg, &o->u32);
|
||||||
|
if (rv != 1)
|
||||||
|
{
|
||||||
|
printf("Invalid TCP IP Address\n");
|
||||||
|
exit(rv);
|
||||||
|
}
|
||||||
|
rv = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// state
|
||||||
|
case 's':
|
||||||
|
o = &opts[CLOP_PRINT_STATE];
|
||||||
|
o->set = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// verbose
|
||||||
|
case 'v':
|
||||||
|
o = &opts[CLOP_VERBOSITY];
|
||||||
|
o->set = 1;
|
||||||
|
|
||||||
|
// Set General Verbosity bit
|
||||||
|
o->u64 |= CLVO_GENERAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// verbosity
|
||||||
|
case 'V':
|
||||||
|
o = &opts[CLOP_VERBOSITY];
|
||||||
|
o->set = 1;
|
||||||
|
i = atoi(arg);
|
||||||
|
|
||||||
|
// Validate Option
|
||||||
|
if ( ( i < 0 ) || ( i >= CLVO_MAX ) ) {
|
||||||
|
printf("Error: Invalid Verbosity option");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the verbosity bit
|
||||||
|
o->u64 |= (0x01 << i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// verbosity-hex
|
||||||
|
case 'X':
|
||||||
|
o = &opts[CLOP_VERBOSITY];
|
||||||
|
o->set = 1;
|
||||||
|
o->u64 = strtoul(arg, NULL, 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// verbosity-mctp
|
||||||
|
case 'Z':
|
||||||
|
o = &opts[CLOP_MCTP_VERBOSITY];
|
||||||
|
o->set = 1;
|
||||||
|
o->u64 = strtoul(arg, NULL, 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// usage
|
||||||
|
case 701:
|
||||||
|
print_usage(ao_main);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// version
|
||||||
|
case 702:
|
||||||
|
printf("%s\n", argp_program_version);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// options
|
||||||
|
case 706:
|
||||||
|
o = &opts[CLOP_PRINT_OPTS];
|
||||||
|
o->set = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// options
|
||||||
|
case 707:
|
||||||
|
printf("Verbosity options:\n");
|
||||||
|
for ( i = 0 ; i < CLVO_MAX ; i++)
|
||||||
|
printf("%2d: %s\n", i, STR_CLVO[i]);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Called for non option parameter
|
||||||
|
case ARGP_KEY_ARG:
|
||||||
|
argp_failure (state, 1, 0, "too many arguments");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Last call. Verify parameters. Fill in missing values
|
||||||
|
case ARGP_KEY_END:
|
||||||
|
|
||||||
|
// Set default port if not specified
|
||||||
|
if (!opts[CLOP_TCP_PORT].set) {
|
||||||
|
opts[CLOP_TCP_PORT].set = 1;
|
||||||
|
opts[CLOP_TCP_PORT].u16 = CLMR_DEFAULT_SERVER_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print options if requested
|
||||||
|
if (opts[CLOP_PRINT_OPTS].set)
|
||||||
|
print_options_array(opts);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the Help output
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Print the Global Header Statement
|
||||||
|
* 2: Print usage
|
||||||
|
* 3: Print level header and flagged options
|
||||||
|
*/
|
||||||
|
static void print_help()
|
||||||
|
{
|
||||||
|
// STEP 1: Print the Global Header Statement
|
||||||
|
printf("CXL Switch Emulator\n");
|
||||||
|
|
||||||
|
printf("\n\
|
||||||
|
Usage: %s <options>\n", app_name);
|
||||||
|
print_options(ao_main);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the command line flag options to the screen as part of help output
|
||||||
|
*
|
||||||
|
* @param o the menu level [CLAP] enum
|
||||||
|
*/
|
||||||
|
static void print_options(struct argp_option *o)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
while (o->doc != NULL)
|
||||||
|
{
|
||||||
|
// Break if this is the ending NULL entry
|
||||||
|
if ( !o->name && !o->key && !o->arg && !o->flags && !o->doc && !o->group )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Skip Hidden Options
|
||||||
|
if (o->flags & OPTION_HIDDEN) {
|
||||||
|
o++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if this is a section heading
|
||||||
|
else if ( !o->name && !o->key && !o->arg && !o->flags && o->doc)
|
||||||
|
printf("\n %s:\n", o->doc);
|
||||||
|
|
||||||
|
// Print normal option entry
|
||||||
|
else {
|
||||||
|
|
||||||
|
// IF this option has a single character key, print the key, else print spaces
|
||||||
|
if (isalnum(o->key))
|
||||||
|
printf(" -%c, ", o->key);
|
||||||
|
else
|
||||||
|
printf(" ");
|
||||||
|
len = 6;
|
||||||
|
|
||||||
|
// If this option has a long name, print the long name
|
||||||
|
if (o->name) {
|
||||||
|
printf("--%s", o->name);
|
||||||
|
len += strlen(o->name) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this option has an arg type, print the type
|
||||||
|
if (o->arg) {
|
||||||
|
printf("=%s", o->arg);
|
||||||
|
len += strlen(o->arg) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print remaining spaces up to description column
|
||||||
|
for ( int i = 0 ; i < CLMR_HELP_COLUMN - len ; i++ )
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
// Print description of this option
|
||||||
|
printf("%s\n", o->doc);
|
||||||
|
}
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug function to print out the options array at the end of parsing
|
||||||
|
*/
|
||||||
|
static void print_options_array(struct opt *o)
|
||||||
|
{
|
||||||
|
int i, len, maxlen;
|
||||||
|
|
||||||
|
maxlen = 0;
|
||||||
|
|
||||||
|
// Find max length of CLOP String
|
||||||
|
for (i = 0 ; i < CLOP_MAX ; i++) {
|
||||||
|
len = strlen(clop(i));
|
||||||
|
if (len > maxlen)
|
||||||
|
maxlen = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print Header
|
||||||
|
printf("##"); // index
|
||||||
|
printf(" Name"); // OP Name
|
||||||
|
for (int k = 5 ; k <= maxlen ; k++) // Spaces
|
||||||
|
printf(" ");
|
||||||
|
printf(" S"); // Set
|
||||||
|
printf(" u8"); // u8
|
||||||
|
printf(" u16"); // u16
|
||||||
|
printf(" u32"); // u32
|
||||||
|
printf(" u64"); // u64
|
||||||
|
printf(" val"); // val
|
||||||
|
printf(" num"); // num
|
||||||
|
printf(" len"); // len
|
||||||
|
printf(" str"); // str
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Print each entry
|
||||||
|
for (i = 0 ; i < CLOP_MAX ; i++) {
|
||||||
|
// index
|
||||||
|
printf("%02d", i);
|
||||||
|
|
||||||
|
// OP Name
|
||||||
|
printf(" %s", clop(i));
|
||||||
|
|
||||||
|
// Spaces
|
||||||
|
for (int k = strlen(clop(i)) ; k < maxlen ; k++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
printf(" %d", o[i].set); // Set
|
||||||
|
printf(" 0x%02x", o[i].u8); // u8
|
||||||
|
printf(" 0x%04x", o[i].u16); // u16
|
||||||
|
printf(" 0x%08x", o[i].u32); // u32
|
||||||
|
printf(" 0x%016llx", o[i].u64); // u64
|
||||||
|
printf(" 0x%04x", o[i].val); // val
|
||||||
|
printf(" 0x%016llx", o[i].num); // num
|
||||||
|
printf(" 0x%016llx", o[i].len); // len
|
||||||
|
|
||||||
|
if (o[i].str)
|
||||||
|
printf(" %s", o[i].str);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (o[i].len > 0)
|
||||||
|
autl_prnt_buf(o[i].buf, o[i].len, 4, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the usage information for a option level
|
||||||
|
*
|
||||||
|
* @param option Menu item from enum [CLAP]
|
||||||
|
* @param o struct argp_option* to the string data to pull from
|
||||||
|
* STEPS:
|
||||||
|
* 1: Initialize variables
|
||||||
|
* 2: Generate header text
|
||||||
|
* 3: Count the number of short options with no argument
|
||||||
|
* 4: If there is at least one short option with no arg, append short options with no argument here
|
||||||
|
* 5: Append short options with arguments
|
||||||
|
* 6: Append long options
|
||||||
|
* 7: Find index of last space before character 80
|
||||||
|
* 8: Loop through usage buffer and break it up into smaller chunks
|
||||||
|
*/
|
||||||
|
static void print_usage(struct argp_option *o)
|
||||||
|
{
|
||||||
|
int hdr_len, buf_len, num, i, index;
|
||||||
|
char buf[4096];
|
||||||
|
char str[4096];
|
||||||
|
char *ptr;
|
||||||
|
struct argp_option *original;
|
||||||
|
|
||||||
|
// STEP 1: Initialize variables
|
||||||
|
num = 0;
|
||||||
|
index = 0;
|
||||||
|
hdr_len = 0;
|
||||||
|
buf_len = 1;
|
||||||
|
memset(buf, 0, 4096);
|
||||||
|
memset(str, 0, 4096);
|
||||||
|
original = o;
|
||||||
|
ptr = buf;
|
||||||
|
|
||||||
|
// STEP 2: Generate header text
|
||||||
|
sprintf(str, "Usage: %s ", app_name);
|
||||||
|
hdr_len = strlen(str);
|
||||||
|
|
||||||
|
// STEP 3: Count the number of short options with no argument
|
||||||
|
while ( !( !o->name && !o->key && !o->arg && !o->flags && !o->doc && !o->group ) )
|
||||||
|
{
|
||||||
|
if (isalnum(o->key) && !o->arg)
|
||||||
|
num++;
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset pointer
|
||||||
|
o = original;
|
||||||
|
|
||||||
|
// STEP 4: If there is at least one short option with no arg, append short options with no argument here
|
||||||
|
if ( num > 0 )
|
||||||
|
{
|
||||||
|
// Add Leader [-
|
||||||
|
sprintf(&buf[buf_len], "[-");
|
||||||
|
buf_len += 2;
|
||||||
|
|
||||||
|
// Add each key character
|
||||||
|
while ( !( !o->name && !o->key && !o->arg && !o->flags && !o->doc && !o->group ) )
|
||||||
|
{
|
||||||
|
// If this option has a single character key, print the key, else print spaces
|
||||||
|
if (isalnum(o->key) && !o->arg) {
|
||||||
|
sprintf(&buf[buf_len], "%c", o->key);
|
||||||
|
buf_len += 1;
|
||||||
|
}
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add trailing ]
|
||||||
|
sprintf(&buf[buf_len], "] ");
|
||||||
|
buf_len += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset pointer
|
||||||
|
o = original;
|
||||||
|
|
||||||
|
// STEP 5: Append short options with arguments
|
||||||
|
while ( !( !o->name && !o->key && !o->arg && !o->flags && !o->doc && !o->group ) )
|
||||||
|
{
|
||||||
|
// If this option has a single character key and an arg
|
||||||
|
if (isalnum(o->key) && o->arg) {
|
||||||
|
sprintf(&buf[buf_len], "[-%c=%s] ", o->key, o->arg);
|
||||||
|
buf_len += 6;
|
||||||
|
buf_len += strlen(o->arg);
|
||||||
|
}
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset pointer
|
||||||
|
o = original;
|
||||||
|
|
||||||
|
// STEP 6: Append long options
|
||||||
|
while ( !( !o->name && !o->key && !o->arg && !o->flags && !o->doc && !o->group ) )
|
||||||
|
{
|
||||||
|
// If this option has a long name, print the long name
|
||||||
|
if (o->name)
|
||||||
|
{
|
||||||
|
sprintf(&buf[buf_len], "[--%s", o->name);
|
||||||
|
buf_len += strlen(o->name) + 3;
|
||||||
|
|
||||||
|
// If this option has an arg type, print the type
|
||||||
|
if (o->arg)
|
||||||
|
{
|
||||||
|
sprintf(&buf[buf_len], "=%s", o->arg);
|
||||||
|
buf_len += strlen(o->arg) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add trailing ]
|
||||||
|
sprintf(&buf[buf_len], "] ");
|
||||||
|
buf_len += 2;
|
||||||
|
}
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 7: Find index of last space before character 80
|
||||||
|
index = 0;
|
||||||
|
for ( i = 1 ; i < (CLMR_MAX_HELP_WIDTH-hdr_len) ; i++ ) {
|
||||||
|
if (ptr[i] == ' ')
|
||||||
|
index = i;
|
||||||
|
if (ptr[i]==0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 8: Loop through usage buffer and break it up into smaller chunks
|
||||||
|
while (index != 0)
|
||||||
|
{
|
||||||
|
// Copy the line of the buffer into str
|
||||||
|
memcpy(&str[hdr_len], &ptr[1], index-1);
|
||||||
|
|
||||||
|
// Set the next char after the string to 0
|
||||||
|
str[hdr_len+index-1] = 0;
|
||||||
|
|
||||||
|
// Print the merged string
|
||||||
|
printf("%s\n", str);
|
||||||
|
|
||||||
|
// Clear the header portion of the print str
|
||||||
|
memset(str, ' ', hdr_len);
|
||||||
|
|
||||||
|
// Advance buffer
|
||||||
|
ptr = &ptr[index];
|
||||||
|
|
||||||
|
// Find index of last space before character 80
|
||||||
|
index = 0;
|
||||||
|
for ( i = 1 ; i < (CLMR_MAX_HELP_WIDTH-hdr_len) ; i++ ) {
|
||||||
|
if (ptr[i] == ' ')
|
||||||
|
index = i;
|
||||||
|
if (ptr[i]==0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free allocated memory by option parsing proceedure
|
||||||
|
*
|
||||||
|
* @return 0 upon success. Non zero otherwise
|
||||||
|
*/
|
||||||
|
int options_free(struct opt *opts)
|
||||||
|
{
|
||||||
|
struct opt *o;
|
||||||
|
int i, rv;
|
||||||
|
|
||||||
|
rv = 1;
|
||||||
|
|
||||||
|
// Free app_name
|
||||||
|
if (app_name != NULL)
|
||||||
|
free(app_name);
|
||||||
|
app_name = NULL;
|
||||||
|
|
||||||
|
// Verify inputs
|
||||||
|
if (opts == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
// For each option in the array, free any allocated memory in the option
|
||||||
|
for ( i = 0 ; i < CLOP_MAX ; i++ )
|
||||||
|
{
|
||||||
|
o = &opts[i];
|
||||||
|
|
||||||
|
// Free buf field
|
||||||
|
if (o->buf)
|
||||||
|
free(o->buf);
|
||||||
|
o->buf = NULL;
|
||||||
|
|
||||||
|
// Free str field
|
||||||
|
if (o->str)
|
||||||
|
free(o->str);
|
||||||
|
o->str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free options array
|
||||||
|
free(opts);
|
||||||
|
opts = NULL;
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the command line options
|
||||||
|
*
|
||||||
|
* @param argc int representing the number of cli parameters
|
||||||
|
* @param argv char** of cli parameter strings
|
||||||
|
* @return Returns 0 on success, error code on error
|
||||||
|
*
|
||||||
|
* STEPS
|
||||||
|
* 1: Zero out global options array
|
||||||
|
* 2: Zero out arguments array for argz use
|
||||||
|
* 3: Parse arguments
|
||||||
|
* 4: argz allocates some memory that needs to be freed after parsing
|
||||||
|
*/
|
||||||
|
int options_parse(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int rv, len;
|
||||||
|
|
||||||
|
// Initialize variables
|
||||||
|
rv = 1;
|
||||||
|
|
||||||
|
// STEP 1: Store app name in global variable
|
||||||
|
len = strnlen(argv[0], CLMR_MAX_NAME_LEN);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
app_name = malloc(len+1);
|
||||||
|
if (app_name == NULL)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!strncmp("./", argv[0], 2))
|
||||||
|
memcpy(app_name, &argv[0][2], len-1);
|
||||||
|
else
|
||||||
|
memcpy(app_name, argv[0], len+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 2: Allocate and clear memory for options array
|
||||||
|
opts = calloc(CLOP_MAX, sizeof(struct opt));
|
||||||
|
if (opts == NULL)
|
||||||
|
goto end_name;
|
||||||
|
|
||||||
|
// STEP 3: Parse arguments
|
||||||
|
rv = argp_parse(&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
end_name:
|
||||||
|
|
||||||
|
free(app_name);
|
||||||
|
|
||||||
|
end:
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
140
options.h
Normal file
140
options.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file options.h
|
||||||
|
*
|
||||||
|
* @brief Header file for cli options parsing using argp/argz library
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
* Macro / Enumeration Prefixes (CL)
|
||||||
|
* CLOP - CLI Option (OP)
|
||||||
|
* CLVB - CLI Verbosity Bit Field (VB)
|
||||||
|
* CLVO - CLI Verbosity Options (VO)
|
||||||
|
*
|
||||||
|
* Standard key mapping
|
||||||
|
* -h --help Display Help
|
||||||
|
* -T --tcp-port Server TCP Port
|
||||||
|
* -V --verbosity Set Verbosity Flag
|
||||||
|
* -X --verbosity-hex Set all Verbosity Flags with hex value
|
||||||
|
*
|
||||||
|
* Non char key mapping
|
||||||
|
* 701 - usage
|
||||||
|
* 702 - version
|
||||||
|
* 703 - data
|
||||||
|
* 704 - infile
|
||||||
|
* 705 - outfile
|
||||||
|
* 706 - print-options
|
||||||
|
* 707 - options
|
||||||
|
*/
|
||||||
|
#ifndef _OPTIONS_H
|
||||||
|
#define _OPTIONS_H
|
||||||
|
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#define CLMR_DEFAULT_SERVER_PORT 2508
|
||||||
|
#define CLMR_MAX_NAME_LEN 64
|
||||||
|
#define CLMR_HELP_COLUMN 30
|
||||||
|
#define CLMR_MAX_HELP_WIDTH 100
|
||||||
|
#define CLMR_MAX_ARG_STR_LEN 256
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI Verbosity Options (VO)
|
||||||
|
*/
|
||||||
|
enum _CLVO
|
||||||
|
{
|
||||||
|
CLVO_GENERAL = 0,
|
||||||
|
CLVO_CALLSTACK = 1,
|
||||||
|
CLVO_STEPS = 2,
|
||||||
|
CLVO_PARSE = 3,
|
||||||
|
CLVO_ACTIONS = 4,
|
||||||
|
CLVO_COMMANDS = 5,
|
||||||
|
CLVO_ERRORS = 6,
|
||||||
|
CLVO_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI Verbosity Bit Field (VB)
|
||||||
|
*/
|
||||||
|
enum _CLVB
|
||||||
|
{
|
||||||
|
CLVB_GENERAL = (0x01 << 0),
|
||||||
|
CLVB_CALLSTACK = (0x01 << 1),
|
||||||
|
CLVB_STEPS = (0x01 << 2),
|
||||||
|
CLVB_PARSE = (0x01 << 3),
|
||||||
|
CLVB_ACTIONS = (0x01 << 4),
|
||||||
|
CLVB_COMMANDS = (0x01 << 5),
|
||||||
|
CLVB_ERRORS = (0x01 << 6),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI Option (OP)
|
||||||
|
*/
|
||||||
|
enum _CLOP
|
||||||
|
{
|
||||||
|
CLOP_VERBOSITY, //!< Verbosity level bitfield <u64>
|
||||||
|
CLOP_MCTP_VERBOSITY, //!< MCTP Library Verbosity level: Bitfield <u64>
|
||||||
|
CLOP_PRINT_STATE, //!< Print the state <set>
|
||||||
|
CLOP_PRINT_OPTS, //!< Print CLI options to console <set>
|
||||||
|
CLOP_CONFIG_FILE, //!< File to load CXL Switch configuration data <str>
|
||||||
|
CLOP_TCP_PORT, //!< TCP Port to listen on for connections <u16>
|
||||||
|
CLOP_TCP_ADDRESS, //!< TCP Address to listen on for connections <u32>
|
||||||
|
CLOP_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI Option Struct
|
||||||
|
*
|
||||||
|
* Each command line parameter is stored in one of these objects
|
||||||
|
*/
|
||||||
|
struct opt
|
||||||
|
{
|
||||||
|
int set; //!< Not set (0), set (1)
|
||||||
|
__u8 u8; //!< Unsigned char value
|
||||||
|
__u16 u16; //!< Unsigned long value
|
||||||
|
__u32 u32; //!< Unsigned long value
|
||||||
|
__u64 u64; //!< Unsigned long long value
|
||||||
|
__s32 val; //!< Generic signed value
|
||||||
|
__u64 num; //!< Number of items
|
||||||
|
__u64 len; //!< Data Buffer Length
|
||||||
|
char *str; //!< String value
|
||||||
|
__u8 *buf; //!< Data buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of options from args parse
|
||||||
|
*/
|
||||||
|
extern struct opt *opts;
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
char *clop(int u);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free allocated memory by option parsing proceedure
|
||||||
|
*
|
||||||
|
* @return 0 upon success. Non zero otherwise
|
||||||
|
*/
|
||||||
|
int options_free(struct opt *opts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse command line options
|
||||||
|
*/
|
||||||
|
int options_parse(int argc, char *argv[]);
|
||||||
|
|
||||||
|
#endif //ifndef _OPTIONS_H
|
||||||
98
signals.c
Normal file
98
signals.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file signals.c
|
||||||
|
*
|
||||||
|
* @brief Code file for signal handling functions
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* gettid()
|
||||||
|
*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* printf()
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* signal()
|
||||||
|
*/
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
/* strsignal()
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#ifdef CSE_VERBOSE
|
||||||
|
#define INIT unsigned step = 0;
|
||||||
|
#define ENTER if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Enter\n", gettid(), __FUNCTION__);
|
||||||
|
#define STEP step++; if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u\n", gettid(), __FUNCTION__, step);
|
||||||
|
#define HEX32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: 0x%x\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define INT32(m, i) if (opts[CLOP_VERBOSITY].u64 & CLVB_STEPS) printf("%d:%s STEP: %u %s: %d\n", gettid(), __FUNCTION__, step, m, i);
|
||||||
|
#define EXIT(rc) if (opts[CLOP_VERBOSITY].u64 & CLVB_CALLSTACK) printf("%d:%s Exit: %d\n", gettid(), __FUNCTION__,rc);
|
||||||
|
#else
|
||||||
|
#define ENTER
|
||||||
|
#define EXIT(rc)
|
||||||
|
#define STEP
|
||||||
|
#define HEX32(m, i)
|
||||||
|
#define INT32(m, i)
|
||||||
|
#define INIT
|
||||||
|
#endif // CSE_VERBOSE
|
||||||
|
|
||||||
|
#define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u)
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global variable used for the signal handlers to tell the main loop to stop
|
||||||
|
*/
|
||||||
|
int stop_requested = 0;
|
||||||
|
|
||||||
|
/* FUNCTIONS =================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register signal handlers
|
||||||
|
*/
|
||||||
|
void signals_register()
|
||||||
|
{
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
signal(SIGINT, signals_sigint);
|
||||||
|
|
||||||
|
EXIT(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for SIGINT (CTRL-C)
|
||||||
|
*/
|
||||||
|
void signals_sigint(int sig)
|
||||||
|
{
|
||||||
|
ENTER
|
||||||
|
|
||||||
|
IFV(CLVB_CALLSTACK) printf("Caught Signal: %d - %s\n", sig, strsignal(sig));
|
||||||
|
|
||||||
|
stop_requested = 1;
|
||||||
|
|
||||||
|
EXIT(0)
|
||||||
|
}
|
||||||
|
|
||||||
40
signals.h
Normal file
40
signals.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file signals.h
|
||||||
|
*
|
||||||
|
* @brief Header file for signal handling functions
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef _SIGNALS_H
|
||||||
|
#define _SIGNALS_H
|
||||||
|
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register signal handlers
|
||||||
|
*/
|
||||||
|
void signals_register();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for SIGINT (CTRL-C)
|
||||||
|
*/
|
||||||
|
void signals_sigint(int sig);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
extern int stop_requested;
|
||||||
|
|
||||||
|
#endif //ifndef _SIGNALS_H
|
||||||
242
state.h
Normal file
242
state.h
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
/**
|
||||||
|
* @file state.h
|
||||||
|
*
|
||||||
|
* @brief Header file to manage the CXL switch state
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2024 Jackrabbit Founders LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* @date Jan 2024
|
||||||
|
* @author Barrett Edwards <code@jrlabs.io>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* INCLUDES ==================================================================*/
|
||||||
|
|
||||||
|
#ifndef _STATE_H
|
||||||
|
#define _STATE_H
|
||||||
|
|
||||||
|
/* __u8
|
||||||
|
* __u16
|
||||||
|
*/
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* pthread_mutex_t
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <fmapi.h>
|
||||||
|
|
||||||
|
/* MACROS ====================================================================*/
|
||||||
|
|
||||||
|
#define MAX_LD 16
|
||||||
|
#define MAX_PORTS 256
|
||||||
|
#define MAX_VCSS MAX_PORTS
|
||||||
|
#define MAX_VPPBS_PER_VCS 256
|
||||||
|
#define MAX_VPPBS MAX_PORTS * MAX_LD
|
||||||
|
|
||||||
|
#define MAX_INDENT 32
|
||||||
|
#define INDENT 2
|
||||||
|
#define CFG_SPACE_SIZE 4096
|
||||||
|
#define MAX_FILE_NAME_LEN 256
|
||||||
|
|
||||||
|
#define INITIAL_NUM_DEVICES 32
|
||||||
|
|
||||||
|
/* ENUMERATIONS ==============================================================*/
|
||||||
|
|
||||||
|
/* STRUCTS ===================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi Logical Device Object*
|
||||||
|
*
|
||||||
|
* This device aggregates all the descriptors for a CXL MLD Logical Device
|
||||||
|
*
|
||||||
|
* CXL 2.0 v1.0 Table 111,112,113,116,117,118,119
|
||||||
|
*/
|
||||||
|
struct mld {
|
||||||
|
|
||||||
|
/* LD Info: Table 111*/
|
||||||
|
__u64 memory_size; //!< Total device memory capacity
|
||||||
|
__u16 num; //!< Number of Logical Devices supported
|
||||||
|
__u8 epc; //!< Egress Port Congestion Supported
|
||||||
|
__u8 ttr; //!< Temporary Throughput Reduction Supported
|
||||||
|
|
||||||
|
/* LD Allocations: Table 112,113 */
|
||||||
|
__u8 granularity; //!< Memory Granularity [FMMG]
|
||||||
|
__u64 rng1[FM_MAX_NUM_LD]; //!< Range 1 Allocation Multiplier
|
||||||
|
__u64 rng2[FM_MAX_NUM_LD]; //!< Range 2 Allocation Multiplier
|
||||||
|
|
||||||
|
/* LD QoS Control parameters: Table 116*/
|
||||||
|
__u8 epc_en; //!< QoS Telem: Egress Port Congestion Enable. Bitfield [FMQT]
|
||||||
|
__u8 ttr_en; //!< QoS Telem: Temporary Throuhput Reduction Enable. Bitfield [FMQT]
|
||||||
|
__u8 egress_mod_pcnt; //!< Egress Moderate Percentage: Threshold in percent for Egress Port Congestion mechanism to indicate moderate congestion. Valid range is 1-100. Default is 10.
|
||||||
|
__u8 egress_sev_pcnt; //!< Egress Severe Percentage: Threshold in percent for Egress Port Congestion mechanism to indicate severe congestion. Valid range is 1-100. Default is 25
|
||||||
|
__u8 sample_interval; //!< Backpressure Sample Interval: Interval in ns for Egress Port Congestion mechanism to take samples. Valid range is 0-15. Default is 8 (800 ns of history). Value of 0 disables the mechanism.
|
||||||
|
__u16 rcb; //!< ReqCmpBasis. Estimated maximum sustained sum of requests and recent responses across the entire device, serving as the basis for QoS Limit Fraction. Valid range is 0-65,535. Value of 0 disables the mechanism. Default is 0.
|
||||||
|
__u8 comp_interval; //!< Completion Collection Interval: Interval in ns for Completion Counting mechanism to collect the number of transmitted responses in a single counter. Valid range is 0-255. Default is 64
|
||||||
|
|
||||||
|
/* LD QoS Status: Table 117*/
|
||||||
|
__u8 bp_avg_pcnt; //!< Backpressure Average Percentage: Current snapshot of the measured Egress Port average congestion. Table 117
|
||||||
|
|
||||||
|
/* LD QoS Allocated BW Fractions: Table 118 */
|
||||||
|
__u8 alloc_bw[FM_MAX_NUM_LD];
|
||||||
|
|
||||||
|
/* LD QoS BW Limit Fractions: Table 119 */
|
||||||
|
__u8 bw_limit[FM_MAX_NUM_LD];
|
||||||
|
|
||||||
|
__u8 *cfgspace[FM_MAX_NUM_LD]; //!< Buffers representing PCIe config space for each logical device
|
||||||
|
|
||||||
|
__u8 mmap; //!< Direction to mmap a file for the memory space
|
||||||
|
char *file; //!< Filename for mmaped file
|
||||||
|
__u8 *memspace; //!< Buffer representing memory space for entire logical device
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual PCIe-to-PCIe Bridge Object
|
||||||
|
*
|
||||||
|
* CXL 2.0 v1.0 Table 99
|
||||||
|
*/
|
||||||
|
struct vppb {
|
||||||
|
__u16 vppbid; //!< Index of this vPPB in the state->vppbs[] array
|
||||||
|
__u8 bind_status; //!< PBB Binding Status [FMBS]
|
||||||
|
__u8 ppid; //!< Physical port number of bound port
|
||||||
|
__u16 ldid; //!< ID of LD bound to port from MLD on associated physical port
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual CXL Switch Object
|
||||||
|
*
|
||||||
|
* CXL 2.0 v1.0 Table 99
|
||||||
|
*/
|
||||||
|
struct vcs {
|
||||||
|
__u8 vcsid; //!< VCS ID - Index of this vcs in the state->vcss[] array
|
||||||
|
__u8 state; //!< Virtual CXL switch State [FMVS]
|
||||||
|
__u8 uspid; //!< USP Physical Port ID
|
||||||
|
__u8 num; //!< Number of vPPBs
|
||||||
|
|
||||||
|
//!< Array of pointers to vPPB objects
|
||||||
|
struct vppb vppbs[MAX_VPPBS_PER_VCS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CXL Switch Port Object
|
||||||
|
*
|
||||||
|
* CXL 2.0 v1.0 Table 92
|
||||||
|
*/
|
||||||
|
struct port {
|
||||||
|
__u8 ppid; //!< Port ID - Index of this port in the state->ports[] array
|
||||||
|
__u8 state; //!< Current Port Configuration State [FMPS]
|
||||||
|
__u8 dv; //!< Connected Device CXL version [FMDV]
|
||||||
|
__u8 dt; //!< Connected device type [FMDT]
|
||||||
|
__u8 cv; //!< Connected CXL version bitmask [FMVC]
|
||||||
|
__u8 mlw; //!< Max Link Width. Integer number of lanes (1,2,4,8,16)
|
||||||
|
__u8 nlw; //!< Negotiated Link Width [FMNW]
|
||||||
|
__u8 speeds; //!< Supported Link Speeds Vector [FMSS]
|
||||||
|
__u8 mls; //!< Maximum Link Speed [FMMS]
|
||||||
|
__u8 cls; //!< Current Link Speed [FMMS]
|
||||||
|
__u8 ltssm; //!< LTSSM State [FMLS]
|
||||||
|
__u8 lane; //!< First negotiated lane number (Integer lane number)
|
||||||
|
|
||||||
|
/** Link State Flags [FMLF] [FMLO] */
|
||||||
|
__u8 lane_rev; //!< Lane reversal state. 0=standard, 1=rev [FMLO]
|
||||||
|
__u8 perst; //!< PCIe Reset State PERST#
|
||||||
|
__u8 prsnt; //!< Port Presence pin state PRSNT#
|
||||||
|
__u8 pwrctrl; //!< Power Control State (PWR_CTRL)
|
||||||
|
|
||||||
|
__u8 ld; //!< Additional supported LD Count (beyond 1)
|
||||||
|
__u8 *cfgspace; //!< Buffer representing PCIe config space
|
||||||
|
struct mld *mld; //!< State for MLD
|
||||||
|
char *device_name; //!< Name of device used to populate this port
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cse_device
|
||||||
|
{
|
||||||
|
char *name; //!< Name of device
|
||||||
|
__u8 rootport; //!< Root Port Device. 1=root, 2=endpoint
|
||||||
|
__u8 dv; //!< Connected Device CXL version [FMDV]
|
||||||
|
__u8 dt; //!< Connected device type [FMDT]
|
||||||
|
__u8 cv; //!< Connected CXL version bitmask [FMVC]
|
||||||
|
__u8 mlw; //!< Maximum Link Width. Integer number of lanes (1,2,4,8,16)
|
||||||
|
__u8 mls; //!< Maximum Link Speed [FMMS]
|
||||||
|
__u8 *cfgspace; //!< Buffer representing PCIe config space
|
||||||
|
struct mld *mld; //!< MLD info if this is an MLD
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CXL Switch State Identify Information
|
||||||
|
*
|
||||||
|
* CXL 2.0 v1 Table 89
|
||||||
|
*/
|
||||||
|
struct cxl_switch_state {
|
||||||
|
__u8 version; //!< Device Management Version
|
||||||
|
|
||||||
|
__u16 vid; //!< PCIe Vendor ID
|
||||||
|
__u16 did; //!< PCIe Device ID
|
||||||
|
__u16 svid; //!< PCIe Subsystem Vendor ID
|
||||||
|
__u16 ssid; //!< PCIe Subsystem ID
|
||||||
|
__u64 sn; //!< Device Serial Number
|
||||||
|
__u8 max_msg_size_n; //!< Max fmapi msg size. 2^n
|
||||||
|
|
||||||
|
__u8 msg_rsp_limit_n; //!< Message Response Limit n of 2^n
|
||||||
|
|
||||||
|
__u8 bos_running; //!< Background operation status 0=none, 1=running
|
||||||
|
__u8 bos_pcnt; //!< Background operation percent complete [0-100]
|
||||||
|
__u16 bos_opcode; //!< Background operation opcode
|
||||||
|
__u16 bos_rc; //!< Background operation return code
|
||||||
|
__u16 bos_ext; //!< Background operation Extended Vendor Status
|
||||||
|
|
||||||
|
__u8 ingress_port; //!< Ingress Port ID
|
||||||
|
__u8 num_ports; //!< Total number of physical ports
|
||||||
|
__u8 num_vcss; //!< Max number of VCSs
|
||||||
|
__u16 num_vppbs; //!< Max number of vPPBs
|
||||||
|
__u16 active_vppbs; //!< Number of active vPPBs
|
||||||
|
__u8 num_decoders; //!< Number of HDM decoders available per USP
|
||||||
|
|
||||||
|
struct port *ports; //!< array of Port objects
|
||||||
|
struct vcs *vcss; //!< array of VCS objects
|
||||||
|
|
||||||
|
struct cse_device *devices; //!< array of device definitions
|
||||||
|
__u16 len_devices; //!< Number of entries supported in devices array
|
||||||
|
__u16 num_devices; //!< Number of entries in devices array
|
||||||
|
|
||||||
|
/* Port defaults */
|
||||||
|
__u8 mlw; //!< Max Link Width. Integer number of lanes (1,2,4,8,16)
|
||||||
|
__u8 speeds; //!< Supported Link Speeds Vector [FMSS]
|
||||||
|
__u8 mls; //!< Maximum Link Speed [FMMS]
|
||||||
|
char *dir; //!< Filepath to directory for instantiated memory
|
||||||
|
|
||||||
|
pthread_mutex_t mtx; //!< Mutex to control access to this object
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* PROTOTYPES ================================================================*/
|
||||||
|
|
||||||
|
struct cxl_switch_state *state_init(unsigned ports, unsigned vcss, unsigned vppbs);
|
||||||
|
int state_load(struct cxl_switch_state *s, char *filename);
|
||||||
|
void state_free(struct cxl_switch_state *s);
|
||||||
|
|
||||||
|
int state_connect_device(struct port *p, struct cse_device *d);
|
||||||
|
int state_disconnect_device(struct port *p);
|
||||||
|
|
||||||
|
/* Conversion Functions */
|
||||||
|
void state_conv_identity(struct cxl_switch_state *src, struct fmapi_psc_id_rsp *dst);
|
||||||
|
void state_conv_port_info(struct port *src, struct fmapi_psc_port_info *dst);
|
||||||
|
void state_conv_vcs_info(struct vcs *src, struct fmapi_vsc_info_blk *dst);
|
||||||
|
|
||||||
|
/* Print Functions */
|
||||||
|
void state_print(struct cxl_switch_state *s);
|
||||||
|
void state_print_identity(struct cxl_switch_state *s, unsigned indent);
|
||||||
|
void state_print_ports(struct cxl_switch_state *s, unsigned indent);
|
||||||
|
void state_print_port(struct port *p, unsigned indent);
|
||||||
|
void state_print_vcss(struct cxl_switch_state *s, unsigned indent);
|
||||||
|
void state_print_vcs(struct vcs *v, unsigned indent);
|
||||||
|
void state_print_vppb(struct vppb *b, unsigned indent);
|
||||||
|
void state_print_mld(struct mld *mld, unsigned indent);
|
||||||
|
|
||||||
|
void state_print_devices(struct cxl_switch_state *s);
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ==========================================================*/
|
||||||
|
|
||||||
|
extern struct cxl_switch_state *cxl_state;
|
||||||
|
|
||||||
|
#endif //ifndef _STATE_H
|
||||||
Loading…
Reference in New Issue
Block a user