2024-04-02 04:55:14 +00:00
|
|
|
/* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
|
/**
|
|
|
|
|
* @file state.c
|
2024-04-08 06:22:45 +00:00
|
|
|
cxl_ *
|
2024-04-02 04:55:14 +00:00
|
|
|
* @brief Code 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 ==================================================================*/
|
|
|
|
|
|
|
|
|
|
/* gettid()
|
|
|
|
|
*/
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
/* memset()
|
|
|
|
|
*/
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
/* printf()
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
/* malloc()
|
|
|
|
|
* free()
|
|
|
|
|
*/
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
/* errno
|
|
|
|
|
*/
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
/* mmap()
|
|
|
|
|
*/
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
2024-04-23 02:13:19 +00:00
|
|
|
#include <pci/pci.h>
|
|
|
|
|
|
2024-04-02 04:55:14 +00:00
|
|
|
/** GHashTable
|
|
|
|
|
* g_hash_table_foreach()
|
|
|
|
|
/ */
|
|
|
|
|
#include <glib-2.0/glib.h>
|
|
|
|
|
|
|
|
|
|
/* autl_prnt_buf()
|
|
|
|
|
*/
|
|
|
|
|
#include <arrayutils.h>
|
|
|
|
|
|
|
|
|
|
/* yl_obj_t
|
|
|
|
|
* ly_load()
|
|
|
|
|
* yl_free()
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
#include <yamlloader.h>
|
|
|
|
|
|
|
|
|
|
#include <fmapi.h>
|
2024-04-08 06:22:45 +00:00
|
|
|
#include <cxlstate.h>
|
2024-04-02 04:55:14 +00:00
|
|
|
#include <pciutils.h>
|
|
|
|
|
|
|
|
|
|
#include "options.h"
|
|
|
|
|
|
|
|
|
|
#include "state.h"
|
|
|
|
|
|
|
|
|
|
/* MACROS ====================================================================*/
|
|
|
|
|
|
|
|
|
|
#define MAX_STR 256
|
|
|
|
|
|
|
|
|
|
#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 ================================================================*/
|
|
|
|
|
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load_devices(struct cxl_switch *state, GHashTable *ht);
|
|
|
|
|
int state_load_emulator(struct cxl_switch *state, GHashTable *ht);
|
|
|
|
|
int state_load_ports(struct cxl_switch *state, GHashTable *ht);
|
|
|
|
|
int state_load_switch(struct cxl_switch *state, GHashTable *ht);
|
|
|
|
|
int state_load_vcss(struct cxl_switch *state, GHashTable *ht);
|
2024-04-23 02:13:19 +00:00
|
|
|
int state_load_from_pci(struct cxl_switch *state);
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
void _parse_devices(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_device(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_device_mld(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_device_pciecfg(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_device_pcicap(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_device_pciecap(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_device_port(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_emulator(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_ports(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_port(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_switch(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_vcss(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_vcs(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_vppbs(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
void _parse_vppb(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
|
|
|
|
|
|
void state_print_pcie_cfg_space(__u8 *cfgspace, unsigned indent);
|
|
|
|
|
|
|
|
|
|
/* GLOBAL VARIABLES ==========================================================*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Global pointer to CXL Switch State
|
|
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_switch *cxls;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
/* FUNCTIONS =================================================================*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load config file and update state
|
|
|
|
|
*
|
2024-04-08 06:22:45 +00:00
|
|
|
* @param state struct cxl_switch to fill
|
2024-04-02 04:55:14 +00:00
|
|
|
* @param filename char * to yaml config file to load
|
|
|
|
|
* @return Returns 0 on success, error code otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Validate inputs
|
|
|
|
|
* 2: Parse config file into hash table
|
|
|
|
|
* 3: Parse Emulator configuration
|
|
|
|
|
* 4: Parse Devices
|
|
|
|
|
* 5: Parse Switch
|
2024-04-23 02:13:19 +00:00
|
|
|
* 6: Load physical devices if in a QEMU environment
|
|
|
|
|
* 7: Parse Ports
|
|
|
|
|
* 8: Parse VCSs
|
|
|
|
|
* 9: Free memory allocated for hash table
|
2024-04-02 04:55:14 +00:00
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load(struct cxl_switch *state, char *filename)
|
2024-04-02 04:55:14 +00:00
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
|
|
|
|
GHashTable *ht;
|
|
|
|
|
char *default_file = "config.yaml";
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Validate inputs
|
|
|
|
|
if( state == NULL ) {
|
|
|
|
|
rv = EINVAL;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( filename == NULL )
|
|
|
|
|
filename = default_file;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Parse config file into hash table
|
|
|
|
|
ht = yl_load(filename);
|
|
|
|
|
if ( ht == NULL ) {
|
|
|
|
|
rv = errno;
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STEP // 3: Parse Emulator configuration
|
|
|
|
|
rv = state_load_emulator(state, ht);
|
|
|
|
|
if (rv != 0)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 4: Parse Devices
|
|
|
|
|
rv = state_load_devices(state, ht);
|
|
|
|
|
if (rv != 0)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 5: Parse Switch
|
|
|
|
|
rv = state_load_switch(state, ht);
|
|
|
|
|
if (rv != 0)
|
|
|
|
|
goto end;
|
2024-04-23 02:13:19 +00:00
|
|
|
|
|
|
|
|
STEP // 6: Load physical devices if in a QEMU environment
|
|
|
|
|
if (opts[CLOP_QEMU].set == 1)
|
|
|
|
|
{
|
|
|
|
|
rv = state_load_from_pci(state);
|
|
|
|
|
if (rv != 0)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
2024-04-02 04:55:14 +00:00
|
|
|
|
2024-04-23 02:13:19 +00:00
|
|
|
STEP // 7: Parse Ports
|
2024-04-02 04:55:14 +00:00
|
|
|
rv = state_load_ports(state, ht);
|
|
|
|
|
if (rv != 0)
|
|
|
|
|
goto end;
|
|
|
|
|
|
2024-04-23 02:13:19 +00:00
|
|
|
STEP // 8: Parse VCSs
|
2024-04-02 04:55:14 +00:00
|
|
|
rv = state_load_vcss(state, ht);
|
|
|
|
|
if (rv != 0)
|
|
|
|
|
goto end;
|
|
|
|
|
|
2024-04-23 02:13:19 +00:00
|
|
|
success:
|
|
|
|
|
|
|
|
|
|
STEP // 9: Free memory allocated for hash table
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_free(ht);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load device definitions from hash table into memory
|
|
|
|
|
*
|
|
|
|
|
* @param ht GHashTable holding contents of config.yaml file
|
|
|
|
|
* @return Returns 0 upon success. Non zero otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Obtain hash table
|
|
|
|
|
* 2: Allocate memory for devices in state
|
|
|
|
|
* 3: Parse each entry in the hash table
|
|
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load_devices(struct cxl_switch *state, GHashTable *ht)
|
2024-04-02 04:55:14 +00:00
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
|
rv = 1;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Obtain devices hash table
|
|
|
|
|
ylo = (yl_obj_t*) g_hash_table_lookup(ht, "devices");
|
|
|
|
|
if (ylo == NULL || ylo->ht == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Allocate memory for devices in state
|
2024-04-08 06:22:45 +00:00
|
|
|
state->devices = calloc(INITIAL_NUM_DEVICES, sizeof(struct cxl_device));
|
2024-04-02 04:55:14 +00:00
|
|
|
if (state->devices == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
state->len_devices = INITIAL_NUM_DEVICES;
|
|
|
|
|
|
|
|
|
|
STEP // 3: Parse each entry in the device table
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_devices, state);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load emulator configration variables from hash table into memory
|
|
|
|
|
*
|
|
|
|
|
* @param ht GHashTable holding contents of config.yaml file
|
|
|
|
|
* @return Returns 0 upon success. Non zero otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Obtain hash table
|
|
|
|
|
* 2: Parse each entry in the hash table
|
|
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load_emulator(struct cxl_switch *state, GHashTable *ht)
|
2024-04-02 04:55:14 +00:00
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
|
rv = 1;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Obtain devices hash table
|
|
|
|
|
ylo = (yl_obj_t*) g_hash_table_lookup(ht, "emulator");
|
|
|
|
|
if (ylo == NULL || ylo->ht == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Parse each entry in the device table
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_emulator, state);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-23 02:13:19 +00:00
|
|
|
/**
|
|
|
|
|
* Load ports and vcs from physical pci devices
|
|
|
|
|
*
|
|
|
|
|
* @param ht GHashTable holding contents of config.yaml file
|
|
|
|
|
* @return Returns 0 upon success. Non zero otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
*/
|
|
|
|
|
int state_load_from_pci(struct cxl_switch *state)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
|
|
|
|
|
int rv, cache, mem;
|
|
|
|
|
unsigned int num_dvsec, nr;
|
|
|
|
|
__u32 l, type, vppbid;
|
|
|
|
|
__u16 w;
|
|
|
|
|
struct pci_dev *dev, *parent;
|
|
|
|
|
struct pci_cap *cap;
|
|
|
|
|
struct cxl_port cp;
|
|
|
|
|
__u32 fillflags;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
|
rv = 1;
|
|
|
|
|
fillflags = PCI_FILL_IDENT
|
|
|
|
|
|PCI_FILL_CLASS
|
|
|
|
|
|PCI_FILL_CAPS
|
|
|
|
|
|PCI_FILL_EXT_CAPS
|
|
|
|
|
|PCI_FILL_PHYS_SLOT
|
|
|
|
|
|PCI_FILL_MODULE_ALIAS
|
|
|
|
|
|PCI_FILL_LABEL
|
|
|
|
|
|PCI_FILL_NUMA_NODE
|
|
|
|
|
|PCI_FILL_IO_FLAGS
|
|
|
|
|
|PCI_FILL_CLASS_EXT
|
|
|
|
|
|PCI_FILL_SUBSYS
|
|
|
|
|
|PCI_FILL_PARENT
|
|
|
|
|
|PCI_FILL_DRIVER;
|
|
|
|
|
|
|
|
|
|
STEP // : get pci_access ptr, init pci_access ptr, get all the devices
|
|
|
|
|
state->pacc = pci_alloc();
|
|
|
|
|
pci_init(state->pacc);
|
|
|
|
|
pci_scan_bus(state->pacc);
|
|
|
|
|
|
|
|
|
|
// STEP 3: Iiterate over all devices
|
|
|
|
|
for ( dev = state->pacc->devices ; dev ; dev = dev->next )
|
|
|
|
|
{
|
|
|
|
|
pci_fill_info(dev, PCI_FILL_CLASS);
|
|
|
|
|
|
|
|
|
|
// If this is a PCI-to-PCI Bridge then check if it is a CXL upstream port
|
|
|
|
|
if ( (dev->device_class >> 8) == 0x06 && (dev->device_class & 0x0FF) == 0x04 )
|
|
|
|
|
{
|
|
|
|
|
// Get more info about this device
|
|
|
|
|
pci_fill_info(dev, fillflags);
|
|
|
|
|
|
|
|
|
|
// Get PCI Express Capability
|
|
|
|
|
cap = pci_find_cap(dev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
|
|
|
|
|
if (cap == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Determine port type
|
|
|
|
|
w = pci_read_word(dev, cap->addr + PCI_EXP_FLAGS);
|
|
|
|
|
type = (w & PCI_EXP_FLAGS_TYPE) >> 4;
|
|
|
|
|
if (type != PCI_EXP_TYPE_UPSTREAM)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Clear the local CXL Port before filling it
|
|
|
|
|
memset(&cp, 0, sizeof(cp));
|
|
|
|
|
|
|
|
|
|
// Get max speed / width / vppbid
|
|
|
|
|
l = pci_read_long(dev, cap->addr + PCI_EXP_LNKCAP);
|
|
|
|
|
cp.mls = l & PCI_EXP_LNKCAP_SPEED;
|
|
|
|
|
cp.mlw = (l & PCI_EXP_LNKCAP_WIDTH) >> 4;
|
|
|
|
|
vppbid = l >> 24;
|
|
|
|
|
|
|
|
|
|
// Get cur speed / width
|
|
|
|
|
w = pci_read_word(dev, cap->addr + PCI_EXP_LNKSTA);
|
|
|
|
|
cp.cls = w & PCI_EXP_LNKSTA_SPEED;
|
|
|
|
|
cp.nlw = (w & PCI_EXP_LNKSTA_WIDTH) >> 4;
|
|
|
|
|
|
|
|
|
|
// If parent is NULL, then skip this device as we know nothing about it
|
|
|
|
|
parent = dev->parent;
|
|
|
|
|
if (parent == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Get all info about the parent device
|
|
|
|
|
pci_fill_info(parent, fillflags);
|
|
|
|
|
|
|
|
|
|
// Get PCI Express Capability
|
|
|
|
|
cap = pci_find_cap(parent, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
|
|
|
|
|
if (cap == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Get physical port id from Slot Number in PCI Express capability
|
|
|
|
|
l = pci_read_long(parent, cap->addr + PCI_EXP_SLTCAP);
|
|
|
|
|
cp.ppid = ((l & PCI_EXP_SLTCAP_PSN) >> 19);
|
|
|
|
|
|
|
|
|
|
// Set switch IDs based on the upstream port identifiers
|
|
|
|
|
state->vid = dev->vendor_id;
|
|
|
|
|
state->did = dev->device_id;
|
|
|
|
|
state->ssid = dev->subsys_id;
|
|
|
|
|
state->svid = dev->subsys_vendor_id;
|
|
|
|
|
state->sn = ((__u64) dev->domain_16 ) << 48
|
|
|
|
|
| ((__u64) dev->device_class ) << 32
|
|
|
|
|
| ((__u64) dev->prog_if ) << 24
|
|
|
|
|
| ((__u64) dev->bus ) << 16
|
|
|
|
|
| ((__u64) dev->dev ) << 8
|
|
|
|
|
| ((__u64) dev->func ) ;
|
|
|
|
|
|
|
|
|
|
// Set bind in vcs
|
|
|
|
|
state->vcss[0].uspid = cp.ppid;
|
|
|
|
|
state->vcss[0].state = FMVS_ENABLED;
|
|
|
|
|
state->vcss[0].vppbs[vppbid].ppid = cp.ppid;
|
|
|
|
|
state->vcss[0].vppbs[vppbid].bind_status = FMBS_BOUND_PORT;
|
|
|
|
|
state->vcss[0].vppbs[vppbid].ldid = 0;
|
|
|
|
|
|
|
|
|
|
// Fill local struct cxl_port fields
|
|
|
|
|
cp.state = FMPS_USP;
|
|
|
|
|
cp.dt = FMDT_CXL_TYPE_1;
|
|
|
|
|
cp.speeds = cp.mls;
|
|
|
|
|
cp.ltssm = FMLS_L0;
|
|
|
|
|
cp.lane = 0;
|
|
|
|
|
cp.lane_rev = 0;
|
|
|
|
|
cp.perst = 0;
|
|
|
|
|
cp.prsnt = 1;
|
|
|
|
|
cp.pwrctrl = 0;
|
|
|
|
|
cp.dev = dev;
|
|
|
|
|
cp.dv = FMDV_CXL2_0;
|
|
|
|
|
cp.cv = FMCV_CXL1_1 | FMCV_CXL2_0;
|
|
|
|
|
|
|
|
|
|
// Copy local struct cxl_port into global state
|
|
|
|
|
memcpy(&state->ports[cp.ppid], &cp, sizeof(cp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If this is a CXL device, then gather more info and the parent's info
|
|
|
|
|
else if ( (dev->device_class >> 8) == 0x05 && (dev->device_class & 0x0FF) == 0x02 )
|
|
|
|
|
{
|
|
|
|
|
// Get more info about this device
|
|
|
|
|
pci_fill_info(dev, fillflags);
|
|
|
|
|
|
|
|
|
|
// If parent is NULL, then skip this device as we know nothing about it
|
|
|
|
|
parent = dev->parent;
|
|
|
|
|
if (parent == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Get all info about the parent device
|
|
|
|
|
pci_fill_info(parent, fillflags);
|
|
|
|
|
|
|
|
|
|
// Get PCI Express Capability (Parent)
|
|
|
|
|
cap = pci_find_cap(parent, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
|
|
|
|
|
if (cap == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Determine port type (Parent)
|
|
|
|
|
w = pci_read_word(parent, cap->addr + PCI_EXP_FLAGS);
|
|
|
|
|
type = (w & PCI_EXP_FLAGS_TYPE) >> 4;
|
|
|
|
|
if ( type != PCI_EXP_TYPE_DOWNSTREAM )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Clear the local CXL Port before filling it
|
|
|
|
|
memset(&cp, 0, sizeof(cp));
|
|
|
|
|
|
|
|
|
|
// Get physical port number from SLot number in PCI Express capability (Parent)
|
|
|
|
|
l = pci_read_long(parent, cap->addr + PCI_EXP_SLTCAP);
|
|
|
|
|
cp.ppid = ((l & PCI_EXP_SLTCAP_PSN) >> 19);
|
|
|
|
|
|
|
|
|
|
// Get max speed / width / vppbid (Parent)
|
|
|
|
|
l = pci_read_long(parent, cap->addr + PCI_EXP_LNKCAP);
|
|
|
|
|
cp.mls = l & PCI_EXP_LNKCAP_SPEED;
|
|
|
|
|
cp.mlw = (l & PCI_EXP_LNKCAP_WIDTH) >> 4;
|
|
|
|
|
vppbid = l >> 24;
|
|
|
|
|
|
|
|
|
|
// Get cur speeds
|
|
|
|
|
w = pci_read_word(parent, cap->addr + PCI_EXP_LNKSTA);
|
|
|
|
|
cp.cls = w & PCI_EXP_LNKSTA_SPEED;
|
|
|
|
|
cp.nlw = (w & PCI_EXP_LNKSTA_WIDTH) >> 4;
|
|
|
|
|
|
|
|
|
|
// Get number of DVSEC Capabilities in Dev. Num returned in variable num_dvsec
|
|
|
|
|
num_dvsec = 0;
|
|
|
|
|
cap = pci_find_cap_nr(dev, PCI_EXT_CAP_ID_DVSEC, PCI_CAP_EXTENDED, &num_dvsec);
|
|
|
|
|
|
|
|
|
|
// Loop through DVSEC capabilities
|
|
|
|
|
for ( nr = 0 ; nr < num_dvsec ; nr++)
|
|
|
|
|
{
|
|
|
|
|
// Get DVSEC Capability entry number nr
|
|
|
|
|
cap = pci_find_cap_nr(dev, PCI_EXT_CAP_ID_DVSEC, PCI_CAP_EXTENDED, &nr);
|
|
|
|
|
|
|
|
|
|
// Get the DVSEC.type
|
|
|
|
|
w = pci_read_long(dev, cap->addr + PCI_DVSEC_HEADER2);
|
|
|
|
|
|
|
|
|
|
// If DVSEC.type==0, this DVSEC Capability describes device type
|
|
|
|
|
if (w == 0)
|
|
|
|
|
{
|
|
|
|
|
// Get the flags indicating what CXL protocols are supported
|
|
|
|
|
w = pci_read_word(dev, cap->addr + PCI_CXL_DEV_CAP);
|
|
|
|
|
cache = w & PCI_CXL_DEV_CAP_CACHE;
|
|
|
|
|
mem = (w & PCI_CXL_DEV_CAP_MEM) >> 2;
|
|
|
|
|
|
|
|
|
|
// Determine Device Type
|
|
|
|
|
if (cache == 1 && mem == 0) cp.dt = FMDT_CXL_TYPE_1;
|
|
|
|
|
else if (cache == 1 && mem == 1) cp.dt = FMDT_CXL_TYPE_2;
|
|
|
|
|
else if (cache == 0 && mem == 1) cp.dt = FMDT_CXL_TYPE_3;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the DVSEC Type is 9 then this is a MLD DVSEC
|
|
|
|
|
else if (w == 9)
|
|
|
|
|
{
|
|
|
|
|
// Set that this is a MLD device
|
|
|
|
|
cp.ld = pci_read_word(dev, cap->addr + PCI_CXL_MLD_NUM_LD);
|
|
|
|
|
cp.dt = FMDT_CXL_TYPE_3_POOLED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set bind in vcs
|
|
|
|
|
state->vcss[0].state = FMVS_ENABLED;
|
|
|
|
|
state->vcss[0].vppbs[vppbid].ppid = cp.ppid;
|
|
|
|
|
state->vcss[0].vppbs[vppbid].bind_status = FMBS_BOUND_PORT;
|
|
|
|
|
state->vcss[0].vppbs[vppbid].ldid = 0;
|
|
|
|
|
|
|
|
|
|
// Fill local struct cxl_port fields
|
|
|
|
|
cp.state = FMPS_DSP;
|
|
|
|
|
cp.speeds = cp.mls;
|
|
|
|
|
cp.ltssm = FMLS_L0;
|
|
|
|
|
cp.lane = 0;
|
|
|
|
|
cp.lane_rev = 0;
|
|
|
|
|
cp.perst = 0;
|
|
|
|
|
cp.prsnt = 1;
|
|
|
|
|
cp.pwrctrl = 0;
|
|
|
|
|
cp.dev = dev;
|
|
|
|
|
cp.dv = FMDV_CXL2_0;
|
|
|
|
|
cp.cv = FMCV_CXL1_1 | FMCV_CXL2_0;
|
|
|
|
|
|
|
|
|
|
// Copy local struct cxl_port into global state
|
|
|
|
|
memcpy(&state->ports[cp.ppid], &cp, sizeof(cp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-04-02 04:55:14 +00:00
|
|
|
/**
|
|
|
|
|
* Load port definitions from hash table into memory
|
|
|
|
|
*
|
|
|
|
|
* @param ht GHashTable holding contents of config.yaml file
|
|
|
|
|
* @return Returns 0 upon success. Non zero otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Initialize port state to defaults
|
|
|
|
|
* 2: Obtain hash table
|
|
|
|
|
* 3: Parse each entry in the hash table
|
|
|
|
|
* 4: Instantiate each port device
|
|
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load_ports(struct cxl_switch *state, GHashTable *ht)
|
2024-04-02 04:55:14 +00:00
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
|
|
|
|
unsigned i, k;
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_port *port;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
|
rv = 1;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Initialize port state to defaults
|
|
|
|
|
for ( i = 0 ; i < state->num_ports ; i++ )
|
|
|
|
|
{
|
|
|
|
|
port = &state->ports[i];
|
|
|
|
|
port->state = FMPS_DSP;
|
|
|
|
|
port->mlw = state->mlw;
|
|
|
|
|
port->mls = state->mls;
|
|
|
|
|
port->speeds = state->speeds;
|
|
|
|
|
port->ltssm = FMLS_L0;
|
|
|
|
|
port->lane_rev = 0;
|
|
|
|
|
port->perst = 0;
|
|
|
|
|
port->prsnt = 0;
|
|
|
|
|
port->pwrctrl = 0;
|
|
|
|
|
port->ld = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STEP // 2: Obtain hash table
|
|
|
|
|
ylo = (yl_obj_t*) g_hash_table_lookup(ht, "ports");
|
|
|
|
|
if (ylo == NULL || ylo->ht == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 3: Parse each entry in the hash table
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_ports, state->ports);
|
|
|
|
|
|
|
|
|
|
STEP // 4: Instantiate each port device
|
|
|
|
|
for ( i = 0 ; i < state->num_ports ; i++ )
|
|
|
|
|
{
|
|
|
|
|
port = &state->ports[i];
|
|
|
|
|
|
|
|
|
|
// If the port has a device name, copy values from it
|
|
|
|
|
if ( port->device_name != NULL )
|
|
|
|
|
for ( k = 0 ; k < state->num_devices ; k++ )
|
|
|
|
|
if (state->devices[k].name != NULL)
|
|
|
|
|
if ( !strcmp(state->devices[k].name, port->device_name) )
|
2024-04-08 06:22:45 +00:00
|
|
|
cxls_connect(port, &state->devices[k], cxls->dir);
|
2024-04-02 04:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load switch definitions from hash table into memory
|
|
|
|
|
*
|
|
|
|
|
* @param ht GHashTable holding contents of config.yaml file
|
|
|
|
|
* @return Returns 0 upon success. Non zero otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Obtain hash table
|
|
|
|
|
* 2: Parse each entry in the hash table
|
|
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load_switch(struct cxl_switch *state, GHashTable *ht)
|
2024-04-02 04:55:14 +00:00
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
|
rv = 1;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Obtain hash table
|
|
|
|
|
ylo = (yl_obj_t*) g_hash_table_lookup(ht, "switch");
|
|
|
|
|
if (ylo == NULL || ylo->ht == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Parse each entry in the hash table
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_switch, state);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load VCS definitions from hash table into memory
|
|
|
|
|
*
|
|
|
|
|
* @param ht GHashTable holding contents of config.yaml file
|
|
|
|
|
* @return Returns 0 upon success. Non zero otherwise
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Obtain hash table
|
|
|
|
|
* 2: Parse each entry in the hash table
|
|
|
|
|
*/
|
2024-04-08 06:22:45 +00:00
|
|
|
int state_load_vcss(struct cxl_switch *state, GHashTable *ht)
|
2024-04-02 04:55:14 +00:00
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
|
rv = 1;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Obtain hash table
|
|
|
|
|
ylo = (yl_obj_t*) g_hash_table_lookup(ht, "vcss");
|
|
|
|
|
if (ylo == NULL || ylo->ht == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Parse each entry in the hash table
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_vcss, state->vcss);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse a device entry in the hash table
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Obtain device ID from device entry
|
|
|
|
|
* 2: Check if there is space for a new device in the device table, allocate more if needed
|
|
|
|
|
* 3: Duplicate key string into state object
|
|
|
|
|
* 4: Run parse function for each entry in sub hash table
|
|
|
|
|
*/
|
|
|
|
|
void _parse_devices(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_switch *s;
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_obj_t *ylo, *ylo_did;
|
|
|
|
|
unsigned did;
|
|
|
|
|
void * ptr;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
s = (struct cxl_switch*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Key: %s\n", gettid(), __FUNCTION__, (char*) key);
|
|
|
|
|
|
|
|
|
|
STEP // 1: Obtain device ID from device entry
|
|
|
|
|
ylo_did = (yl_obj_t*) g_hash_table_lookup(ylo->ht, "did");
|
|
|
|
|
if (ylo_did == NULL || ylo_did->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
did = strtoul(ylo_did->str, NULL, 0);
|
|
|
|
|
|
|
|
|
|
STEP // 2: Check if there is space for a new device in the device table, allocate more if needed
|
|
|
|
|
if (s->num_devices >= s->len_devices)
|
|
|
|
|
{
|
|
|
|
|
// Allocate more memory
|
2024-04-08 06:22:45 +00:00
|
|
|
ptr = calloc(s->len_devices + INITIAL_NUM_DEVICES, sizeof(struct cxl_device));
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
// Copy the existing data to new buffer
|
2024-04-08 06:22:45 +00:00
|
|
|
memcpy(ptr, s->devices, s->num_devices * sizeof(struct cxl_device));
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
// free old buffer
|
|
|
|
|
free(s->devices);
|
|
|
|
|
|
|
|
|
|
// reassign new buffer to state
|
|
|
|
|
s->devices = ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STEP // 3: Duplicate key string into state object
|
|
|
|
|
s->devices[did].name = strdup(key);
|
|
|
|
|
|
|
|
|
|
STEP // 4: Run parse function for each entry in sub hash table
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_device, &s->devices[did]);
|
|
|
|
|
|
|
|
|
|
if ( (did + 1 )> s->num_devices)
|
|
|
|
|
s->num_devices = did + 1;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each device hashtable entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS
|
|
|
|
|
* 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
* 2: Call parser for each type of ntry
|
|
|
|
|
*/
|
|
|
|
|
void _parse_device(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_device *d;
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
d = (struct cxl_device*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
if (ylo->ht == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Call parser for each type of ntry
|
|
|
|
|
if (!strcmp(key, "port"))
|
|
|
|
|
{
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_device_port, d);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(key, "pcicfg"))
|
|
|
|
|
{
|
|
|
|
|
// Allocate memory for PCIe config space
|
|
|
|
|
if (d->cfgspace == NULL)
|
|
|
|
|
d->cfgspace = calloc(1, CFG_SPACE_SIZE);
|
|
|
|
|
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_device_pciecfg, d->cfgspace);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(key, "mld"))
|
|
|
|
|
{
|
|
|
|
|
// Allocate memory for MLD struct
|
|
|
|
|
if (d->mld == NULL)
|
2024-04-08 06:22:45 +00:00
|
|
|
d->mld = calloc(1, sizeof(struct cxl_mld));
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_device_mld, d->mld);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each device mld entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Assign KV pairs to state variables
|
|
|
|
|
*/
|
|
|
|
|
void _parse_device_mld(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
int rv;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_mld *mld;
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
mld = (struct cxl_mld*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if (ylo->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Assign KV pairs to state variables
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "memory_size")) mld->memory_size = strtoul(ylo->str, NULL, 16);
|
|
|
|
|
else if (!strcmp(key, "num")) mld->num = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "epc")) mld->epc = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "ttr")) mld->ttr = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "granularity")) mld->granularity = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "epc_en")) mld->epc_en = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "ttr_en")) mld->ttr_en = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "egress_mod_pcnt")) mld->egress_mod_pcnt = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "egress_sev_pcnt")) mld->egress_sev_pcnt = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "sample_interval")) mld->sample_interval = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "rcb")) mld->rcb = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "comp_interval")) mld->comp_interval = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "bp_avg_pcnt")) mld->bp_avg_pcnt = strtoul(ylo->str, NULL, 10);
|
|
|
|
|
else if (!strcmp(key, "rng1")) autl_csv_to_u64(mld->rng1, ylo->str, FM_MAX_NUM_LD, 0);
|
|
|
|
|
else if (!strcmp(key, "rng2")) autl_csv_to_u64(mld->rng2, ylo->str, FM_MAX_NUM_LD, 0);
|
|
|
|
|
else if (!strcmp(key, "alloc_bw")) autl_csv_to_u8(mld->alloc_bw, ylo->str, FM_MAX_NUM_LD, 1);
|
|
|
|
|
else if (!strcmp(key, "bw_limit")) autl_csv_to_u8(mld->bw_limit, ylo->str, FM_MAX_NUM_LD, 1);
|
|
|
|
|
else if (!strcmp(key, "mmap")) mld->mmap = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each device pci config space entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Assign KV pairs to state variables
|
|
|
|
|
* 2: Call parse function for each sub entry
|
|
|
|
|
*/
|
|
|
|
|
void _parse_device_pciecfg(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
struct pcie_cfg_hdr *ph;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
|
|
|
|
ph = (struct pcie_cfg_hdr*) user_data;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Assign KV pairs to state variables
|
|
|
|
|
if (ylo->str != NULL)
|
|
|
|
|
{
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "vendor")) ph->vendor = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "device")) ph->device = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "command")) ph->command = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "status")) ph->status = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
|
|
|
|
|
else if (!strcmp(key, "revid")) ph->rev = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "baseclass")) ph->baseclass = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "subclass")) ph->subclass = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "pi")) ph->pi = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "cacheline")) ph->cls = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
|
|
|
|
|
else if (!strcmp(key, "type")) ph->type = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "subvendor")) ph->subvendor = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "subsystem")) ph->subsystem = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else if (!strcmp(key, "intline")) ph->intline = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "intpin")) ph->intpin = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "mingnt")) ph->mingnt = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "maxlat")) ph->maxlat = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STEP // 2: Call parse function for each sub entry
|
|
|
|
|
if (ylo->ht != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(key, "cap")) {
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_device_pcicap, ph);
|
|
|
|
|
|
|
|
|
|
// Clear rsvd2 field now that we are done parsing the capabilities list
|
|
|
|
|
ph->rsvd2 = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(key, "ecap")) {
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_device_pciecap, ph);
|
|
|
|
|
|
|
|
|
|
// Clear rsvd2 field now that we are done parsing the capabilities list
|
|
|
|
|
ph->rsvd2 = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EXIT(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each device pci config space capabilities entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Find ptr to last cap in the list
|
|
|
|
|
* 3: Fill in the new capability header
|
|
|
|
|
* 4: Convert CSV string to bytes at the location after the new pci capabilities header
|
|
|
|
|
* 5: Store the offset to the next capability entry in the list in reserved field
|
|
|
|
|
*/
|
|
|
|
|
void _parse_device_pcicap(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
struct pcie_cfg_hdr *ph;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
struct pcie_cap *pc;
|
|
|
|
|
__u8 *base, *ptr;
|
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
|
|
|
|
ph = (struct pcie_cfg_hdr*) user_data;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if (ylo->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
STEP // 2: Find ptr to last cap in the list
|
|
|
|
|
/* If the cap ptr in the pci_hdr is null, then there are no capabilities in the current list
|
|
|
|
|
* Set the cap pointer to 0x40 which is the next byte after the pci_hdra
|
|
|
|
|
* And set the ptr to that byte in memory
|
|
|
|
|
*/
|
|
|
|
|
base = (__u8*) ph;
|
|
|
|
|
if (ph->cap == 0)
|
|
|
|
|
{
|
|
|
|
|
ph->cap = 0x40;
|
|
|
|
|
ptr = base + ph->cap;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Get PC pointer to first entry in table
|
|
|
|
|
pc = (struct pcie_cap*) (base + ph->cap);
|
|
|
|
|
|
|
|
|
|
// Walk the linked list until a null pointer is found in the next field
|
|
|
|
|
while (pc->next != 0)
|
|
|
|
|
pc = (struct pcie_cap*) (base + pc->next);
|
|
|
|
|
|
|
|
|
|
// Set the pointer of the next entry
|
|
|
|
|
pc->next = ph->rsvd2;
|
|
|
|
|
|
|
|
|
|
// prepare the pointer of the next extry to fill out
|
|
|
|
|
ptr = base + ph->rsvd2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STEP // 3: Fill in the new capability header
|
|
|
|
|
pc = (struct pcie_cap*) ptr;
|
|
|
|
|
pc->id = strtoul(key, NULL, 0);
|
|
|
|
|
pc->next = 0;
|
|
|
|
|
ptr += 2;
|
|
|
|
|
|
|
|
|
|
STEP // 4: Convert CSV string to bytes at the location after the new pci capabilities header
|
|
|
|
|
rv = autl_csv_to_u8(ptr, ylo->str, 128, 1);
|
|
|
|
|
|
|
|
|
|
STEP // 5: Store the offset to the next capability entry in the list in reserved field
|
|
|
|
|
ph->rsvd2 = ptr + rv - base;
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each device pci config space extended capability entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Find ptr to last cap in the list
|
|
|
|
|
*/
|
|
|
|
|
void _parse_device_pciecap(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
struct pcie_cfg_hdr *ph;
|
|
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
struct pcie_ecap *pc;
|
|
|
|
|
__u8 *base, *ptr;
|
|
|
|
|
__u32 k;
|
|
|
|
|
int rv, num;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
|
|
|
|
ph = (struct pcie_cfg_hdr*) user_data;
|
|
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if (ylo->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
STEP // 2: Find ptr to last cap in the list
|
|
|
|
|
|
|
|
|
|
// ptr to start of pci hdr
|
|
|
|
|
base = (__u8*) ph;
|
|
|
|
|
|
|
|
|
|
// Get ptr to first ecap entry
|
|
|
|
|
pc = (struct pcie_ecap*) (base + 0x100);
|
|
|
|
|
|
|
|
|
|
if (pc->id == 0) {
|
|
|
|
|
ptr = (__u8*) pc;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Walk the linked list until a null pointer is found in the next field
|
|
|
|
|
while (pc->next != 0)
|
|
|
|
|
pc = (struct pcie_ecap*) (base + pc->next);
|
|
|
|
|
|
|
|
|
|
// Set the pointer of the next entryf from saved end ptr
|
|
|
|
|
pc->next = ph->rsvd2;
|
|
|
|
|
|
|
|
|
|
// prepare the pointer of the next extry to fill out
|
|
|
|
|
ptr = base + ph->rsvd2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fill in the new capability header
|
|
|
|
|
pc = (struct pcie_ecap*) ptr;
|
|
|
|
|
k = strtoul(key, NULL, 0);
|
|
|
|
|
pc->id = k >> 4;
|
|
|
|
|
pc->ver = k & 0x0F;
|
|
|
|
|
pc->next = 0;
|
|
|
|
|
ptr += 4;
|
|
|
|
|
|
|
|
|
|
// Convert CSV string to bytes at the location after the new pci capabilities header
|
|
|
|
|
num = autl_csv_to_u8(ptr, ylo->str, 128, 1);
|
|
|
|
|
|
|
|
|
|
// Store the offset to the next capability entry in the list in reserved field
|
|
|
|
|
ph->rsvd2 = ptr + num - base;
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each device port entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Assign KV pairs to state variables
|
|
|
|
|
*/
|
|
|
|
|
void _parse_device_port(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_device *d;
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
d = (struct cxl_device*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if (ylo->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Assign KV pairs to state variables
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "dv")) d->dv = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "dt")) d->dt = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "cv")) d->cv = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "mlw")) d->mlw = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "mls")) d->mls = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "rootport")) d->rootport = strtoul(ylo->str, NULL,0);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each emulator configuration entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Assign KV pairs to state variables
|
|
|
|
|
*/
|
|
|
|
|
void _parse_emulator(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_switch *s;
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
s = (struct cxl_switch*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if (ylo->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Assign KV pairs to state variables
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "verbosity-hex")) {
|
|
|
|
|
opts[CLOP_VERBOSITY].set = 1;
|
|
|
|
|
opts[CLOP_VERBOSITY].u64 = strtoull(ylo->str, NULL, 16);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(key, "verbosity-mctp")) {
|
|
|
|
|
opts[CLOP_MCTP_VERBOSITY].set = 1;
|
|
|
|
|
opts[CLOP_MCTP_VERBOSITY].u64 = strtoull(ylo->str, NULL, 16);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(key, "tcp-port")) {
|
|
|
|
|
opts[CLOP_TCP_PORT].set = 1;
|
|
|
|
|
opts[CLOP_TCP_PORT].u16 = strtoull(ylo->str, NULL, 0);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(key, "dir"))
|
|
|
|
|
s->dir = strdup(ylo->str);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse switch entries in the hash table
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Assign KV pairs to state variables
|
|
|
|
|
*/
|
|
|
|
|
void _parse_switch(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_switch *s;
|
2024-04-02 04:55:14 +00:00
|
|
|
yl_obj_t *ylo;
|
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
s = (struct cxl_switch*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if (ylo->str == NULL)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Assign KV pairs to state variables
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "version")) s->version = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "vid")) s->vid = strtoul(ylo->str, NULL,16);
|
|
|
|
|
else if (!strcmp(key, "did")) s->did = strtoul(ylo->str, NULL,16);
|
|
|
|
|
else if (!strcmp(key, "svid")) s->svid = strtoul(ylo->str, NULL,16);
|
|
|
|
|
else if (!strcmp(key, "ssid")) s->ssid = strtoul(ylo->str, NULL,16);
|
|
|
|
|
else if (!strcmp(key, "sn")) s->sn = strtoull(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "max_msg_size_n")) s->max_msg_size_n = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "bos_running")) s->bos_running = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "bos_pcnt")) s->bos_pcnt = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "bos_opcode")) s->bos_opcode = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "bos_rc")) s->bos_rc = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "bos_ext")) s->bos_ext = strtoul(ylo->str, NULL,0);
|
|
|
|
|
else if (!strcmp(key, "msg_rsp_limit_n")) s->msg_rsp_limit_n = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "ingress_port")) s->ingress_port = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "num_decoders")) s->num_decoders = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "mlw")) s->mlw = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "speeds")) s->speeds = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
else if (!strcmp(key, "mls")) s->mls = atoi(ylo->str);
|
2024-04-23 02:13:19 +00:00
|
|
|
else if (!strcmp(key, "num_ports")) cxls_init_ports(s, atoi(ylo->str));
|
|
|
|
|
else if (!strcmp(key, "num_vcss")) cxls_init_vcss(s, atoi(ylo->str), s->num_vppbs);
|
|
|
|
|
else if (!strcmp(key, "num_vppbs")) cxls_init_vcss(s, s->num_vcss, atoi(ylo->str));
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each ports entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
* 2: Call parse function for each port
|
|
|
|
|
*/
|
|
|
|
|
void _parse_ports(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_port *ports;
|
2024-04-02 04:55:14 +00:00
|
|
|
int rv, id;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
ports = (struct cxl_port*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
if ( ylo->ht == NULL )
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Call parse function for each port
|
|
|
|
|
id = atoi(key);
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Port: %d\n", gettid(), __FUNCTION__, id);
|
|
|
|
|
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_port, &ports[id]);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each port entry in the hashtable
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Assign KV pairs to state variables
|
|
|
|
|
*/
|
|
|
|
|
void _parse_port(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_port *port;
|
2024-04-02 04:55:14 +00:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
port = (struct cxl_port*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if ( ylo->str == NULL )
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Assign KV pairs to state variables
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "device")) port->device_name = strdup(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "mlw")) port->mlw = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "mls")) port->mls = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "state")) port->state = strtoul(ylo->str, NULL, 0);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each VCS entry
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
* 2: Call parse function for each VCS
|
|
|
|
|
*/
|
|
|
|
|
void _parse_vcss(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_vcs *vcss;
|
2024-04-02 04:55:14 +00:00
|
|
|
int rv, id;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
vcss = (struct cxl_vcs*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
if ( ylo->ht == NULL )
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Call parse function for each vcs
|
|
|
|
|
id = atoi(key);
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing VCS: %d\n", gettid(), __FUNCTION__, id);
|
|
|
|
|
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_vcs, &vcss[id]);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each VCS block entry
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Assign KV pairs to state variables
|
|
|
|
|
* 2: Call parse function for vPPBs
|
|
|
|
|
*/
|
|
|
|
|
void _parse_vcs(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_vcs *vcs;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
vcs = (struct cxl_vcs*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Assign KV pairs to state variables
|
|
|
|
|
if ( ylo->str != NULL )
|
|
|
|
|
{
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "state")) vcs->state = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "uspid")) vcs->uspid = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "num_vppb")) vcs->num = atoi(ylo->str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STEP // 2: Call parse function for vPPBs
|
|
|
|
|
if (ylo->ht != NULL)
|
|
|
|
|
{
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_vppbs, vcs->vppbs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EXIT(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each vPPB entry
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
* 2: Call parse function for each vPPB
|
|
|
|
|
*/
|
|
|
|
|
void _parse_vppbs(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_vppb *vppbs;
|
2024-04-02 04:55:14 +00:00
|
|
|
int rv, id;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
vppbs = (struct cxl_vppb*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object hash table is not NULL
|
|
|
|
|
if ( ylo->ht == NULL )
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Call parse function for each vPPB
|
|
|
|
|
id = atoi(key);
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing vPPB: %d", gettid(), __FUNCTION__, id);
|
|
|
|
|
|
|
|
|
|
g_hash_table_foreach(ylo->ht, _parse_vppb, &vppbs[id]);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function to parse each vPPB block entry
|
|
|
|
|
*
|
|
|
|
|
* STEPS:
|
|
|
|
|
* 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
* 2: Assign KV pairs to state variables
|
|
|
|
|
*/
|
|
|
|
|
void _parse_vppb(gpointer key, gpointer value, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
INIT
|
|
|
|
|
yl_obj_t *ylo;
|
2024-04-08 06:22:45 +00:00
|
|
|
struct cxl_vppb *vppb;
|
2024-04-02 04:55:14 +00:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
|
|
ENTER
|
|
|
|
|
|
|
|
|
|
// Initialize varialbes
|
|
|
|
|
rv = 1;
|
|
|
|
|
ylo = (yl_obj_t*) value;
|
2024-04-08 06:22:45 +00:00
|
|
|
vppb = (struct cxl_vppb*) user_data;
|
2024-04-02 04:55:14 +00:00
|
|
|
|
|
|
|
|
STEP // 1: Verify the yaml loader object string is not NULL
|
|
|
|
|
if ( ylo->str == NULL )
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
STEP // 2: Assign KV pairs to state variables
|
|
|
|
|
|
|
|
|
|
IFV(CLVB_PARSE) printf("%d:%s Parsing Key: %s VAL: %s\n", gettid(), __FUNCTION__, (char*) key, ylo->str);
|
|
|
|
|
|
|
|
|
|
if (!strcmp(key, "bind_status")) vppb->bind_status = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "ppid")) vppb->ppid = atoi(ylo->str);
|
|
|
|
|
else if (!strcmp(key, "ldid")) vppb->ldid = atoi(ylo->str);
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
EXIT(rv)
|
|
|
|
|
}
|
|
|
|
|
|