Files
xen/tools/libs/util/libxlu_pci.c
T
Anthony PERARD 52493ec3e3 libs/util: Remove unused headers in libxlu_pci.c
libxlu_pci.c doesn't use any "xlu__cfg*()" functions and doesn't use
any of the disk parsing functions "xlu__disk*()", so all those headers
can be removed.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
2023-02-09 18:26:17 +00:00

292 lines
6.9 KiB
C

#define _GNU_SOURCE
#include <ctype.h>
#include "libxlu_internal.h"
#define XLU__PCI_ERR(_c, _x, _a...) \
if((_c) && (_c)->report) fprintf((_c)->report, _x, ##_a)
static int parse_bdf(libxl_device_pci *pci, const char *str, const char **endp)
{
const char *ptr = str;
unsigned int colons = 0;
unsigned int domain, bus, dev, func;
int n;
/* Count occurrences of ':' to detrmine presence/absence of the 'domain' */
while (isxdigit(*ptr) || *ptr == ':') {
if (*ptr == ':')
colons++;
ptr++;
}
ptr = str;
switch (colons) {
case 1:
domain = 0;
if (sscanf(ptr, "%x:%x.%n", &bus, &dev, &n) != 2)
return ERROR_INVAL;
break;
case 2:
if (sscanf(ptr, "%x:%x:%x.%n", &domain, &bus, &dev, &n) != 3)
return ERROR_INVAL;
break;
default:
return ERROR_INVAL;
}
if (domain > 0xffff || bus > 0xff || dev > 0x1f)
return ERROR_INVAL;
ptr += n;
if (*ptr == '*') {
pci->vfunc_mask = LIBXL_PCI_FUNC_ALL;
func = 0;
ptr++;
} else {
if (sscanf(ptr, "%x%n", &func, &n) != 1)
return ERROR_INVAL;
if (func > 7)
return ERROR_INVAL;
pci->vfunc_mask = 1;
ptr += n;
}
pci->domain = domain;
pci->bus = bus;
pci->dev = dev;
pci->func = func;
if (endp)
*endp = ptr;
return 0;
}
static int parse_vslot(uint32_t *vdevfnp, const char *str, const char **endp)
{
const char *ptr = str;
unsigned int val;
int n;
if (sscanf(ptr, "%x%n", &val, &n) != 1)
return ERROR_INVAL;
if (val > 0x1f)
return ERROR_INVAL;
ptr += n;
*vdevfnp = val << 3;
if (endp)
*endp = ptr;
return 0;
}
static int parse_key_val(char **keyp, char**valp, const char *str,
const char **endp)
{
const char *ptr = str;
char *key, *val;
while (*ptr != '=' && *ptr != '\0')
ptr++;
if (*ptr == '\0')
return ERROR_INVAL;
key = strndup(str, ptr - str);
if (!key)
return ERROR_NOMEM;
str = ++ptr; /* skip '=' */
while (*ptr != ',' && *ptr != '\0')
ptr++;
val = strndup(str, ptr - str);
if (!val) {
free(key);
return ERROR_NOMEM;
}
if (*ptr == ',')
ptr++;
*keyp = key;
*valp = val;
*endp = ptr;
return 0;
}
static int parse_rdm_policy(XLU_Config *cfg, libxl_rdm_reserve_policy *policy,
const char *str)
{
int ret = libxl_rdm_reserve_policy_from_string(str, policy);
if (ret)
XLU__PCI_ERR(cfg, "Unknown RDM policy: %s", str);
return ret;
}
int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pci, const char *str)
{
return parse_bdf(pci, str, NULL);
}
int xlu_pci_parse_spec_string(XLU_Config *cfg, libxl_device_pci *pci,
const char *str)
{
const char *ptr = str;
bool bdf_present = false;
bool name_present = false;
int ret;
/* Attempt to parse 'bdf' as positional parameter */
ret = parse_bdf(pci, ptr, &ptr);
if (!ret) {
bdf_present = true;
/* Check whether 'vslot' is present */
if (*ptr == '@') {
++ptr;
ret = parse_vslot(&pci->vdevfn, ptr, &ptr);
if (ret)
return ret;
}
if (*ptr == ',')
ptr++;
else if (*ptr != '\0')
return ERROR_INVAL;
}
/* Parse the rest as 'key=val' pairs */
while (*ptr != '\0') {
char *key, *val;
ret = parse_key_val(&key, &val, ptr, &ptr);
if (ret)
return ret;
if (!strcmp(key, "bdf")) {
ret = parse_bdf(pci, val, NULL);
if (!ret) bdf_present = true;
} else if (!strcmp(key, "vslot")) {
ret = parse_vslot(&pci->vdevfn, val, NULL);
} else if (!strcmp(key, "permissive")) {
pci->permissive = atoi(val);
} else if (!strcmp(key, "msitranslate")) {
pci->msitranslate = atoi(val);
} else if (!strcmp(key, "seize")) {
pci->seize= atoi(val);
} else if (!strcmp(key, "power_mgmt")) {
pci->power_mgmt = atoi(val);
} else if (!strcmp(key, "rdm_policy")) {
ret = parse_rdm_policy(cfg, &pci->rdm_policy, val);
} else if (!strcmp(key, "name")) {
name_present = true;
pci->name = strdup(val);
if (!pci->name) ret = ERROR_NOMEM;
} else {
XLU__PCI_ERR(cfg, "Unknown PCI_SPEC_STRING option: %s", key);
ret = ERROR_INVAL;
}
free(key);
free(val);
if (ret)
return ret;
}
if (!(bdf_present ^ name_present))
return ERROR_INVAL;
return 0;
}
int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str)
{
#define STATE_TYPE 0
#define STATE_RDM_STRATEGY 1
#define STATE_RESERVE_POLICY 2
#define STATE_TERMINAL 3
unsigned state = STATE_TYPE;
char *buf2, *tok, *ptr, *end;
if (NULL == (buf2 = ptr = strdup(str)))
return ERROR_NOMEM;
for (tok = ptr, end = ptr + strlen(ptr) + 1; ptr < end; ptr++) {
switch(state) {
case STATE_TYPE:
if (*ptr == '=') {
*ptr = '\0';
if (!strcmp(tok, "strategy")) {
state = STATE_RDM_STRATEGY;
} else if (!strcmp(tok, "policy")) {
state = STATE_RESERVE_POLICY;
} else {
XLU__PCI_ERR(cfg, "Unknown RDM state option: %s", tok);
goto parse_error;
}
tok = ptr + 1;
}
break;
case STATE_RDM_STRATEGY:
if (*ptr == '\0' || *ptr == ',') {
state = *ptr == ',' ? STATE_TYPE : STATE_TERMINAL;
*ptr = '\0';
if (!strcmp(tok, "host")) {
rdm->strategy = LIBXL_RDM_RESERVE_STRATEGY_HOST;
} else {
XLU__PCI_ERR(cfg, "Unknown RDM strategy option: %s", tok);
goto parse_error;
}
tok = ptr + 1;
}
break;
case STATE_RESERVE_POLICY:
if (*ptr == ',' || *ptr == '\0') {
state = *ptr == ',' ? STATE_TYPE : STATE_TERMINAL;
*ptr = '\0';
if (!parse_rdm_policy(cfg, &rdm->policy, tok))
goto parse_error;
tok = ptr + 1;
}
default:
break;
}
}
if (tok != ptr || state != STATE_TERMINAL)
goto parse_error;
free(buf2);
return 0;
parse_error:
free(buf2);
return ERROR_INVAL;
#undef STATE_TYPE
#undef STATE_RDM_STRATEGY
#undef STATE_RESERVE_POLICY
#undef STATE_TERMINAL
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/