mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
libxl: Add interface for querying hypervisor about PCI topology
.. and use this new interface to display it along with CPU topology and NUMA information when 'xl info -n' command is issued The output will look like ... cpu_topology : cpu: core socket node 0: 0 0 0 ... device topology : device node 0000:00:00.0 0 0000:00:01.0 0 ... Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
e47d65dc63
commit
e78e8b9bb6
11 files changed
+246
-7
No files matched your search
@@ -1249,6 +1249,7 @@ typedef xen_sysctl_physinfo_t xc_physinfo_t;
|
||||
typedef xen_sysctl_cputopo_t xc_cputopo_t;
|
||||
typedef xen_sysctl_numainfo_t xc_numainfo_t;
|
||||
typedef xen_sysctl_meminfo_t xc_meminfo_t;
|
||||
typedef xen_sysctl_pcitopoinfo_t xc_pcitopoinfo_t;
|
||||
|
||||
typedef uint32_t xc_cpu_to_node_t;
|
||||
typedef uint32_t xc_cpu_to_socket_t;
|
||||
@@ -1262,6 +1263,8 @@ int xc_cputopoinfo(xc_interface *xch, unsigned *max_cpus,
|
||||
xc_cputopo_t *cputopo);
|
||||
int xc_numainfo(xc_interface *xch, unsigned *max_nodes,
|
||||
xc_meminfo_t *meminfo, uint32_t *distance);
|
||||
int xc_pcitopoinfo(xc_interface *xch, unsigned num_devs,
|
||||
physdev_pci_device_t *devs, uint32_t *nodes);
|
||||
|
||||
int xc_sched_id(xc_interface *xch,
|
||||
int *sched_id);
|
||||
|
||||
@@ -264,6 +264,45 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xc_pcitopoinfo(xc_interface *xch, unsigned num_devs,
|
||||
physdev_pci_device_t *devs,
|
||||
uint32_t *nodes)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned processed = 0;
|
||||
DECLARE_SYSCTL;
|
||||
DECLARE_HYPERCALL_BOUNCE(devs, num_devs * sizeof(*devs),
|
||||
XC_HYPERCALL_BUFFER_BOUNCE_IN);
|
||||
DECLARE_HYPERCALL_BOUNCE(nodes, num_devs* sizeof(*nodes),
|
||||
XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
|
||||
|
||||
if ( (ret = xc_hypercall_bounce_pre(xch, devs)) )
|
||||
goto out;
|
||||
if ( (ret = xc_hypercall_bounce_pre(xch, nodes)) )
|
||||
goto out;
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_pcitopoinfo;
|
||||
|
||||
while ( processed < num_devs )
|
||||
{
|
||||
sysctl.u.pcitopoinfo.num_devs = num_devs - processed;
|
||||
set_xen_guest_handle_offset(sysctl.u.pcitopoinfo.devs, devs,
|
||||
processed);
|
||||
set_xen_guest_handle_offset(sysctl.u.pcitopoinfo.nodes, nodes,
|
||||
processed);
|
||||
|
||||
if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
|
||||
break;
|
||||
|
||||
processed += sysctl.u.pcitopoinfo.num_devs;
|
||||
}
|
||||
|
||||
out:
|
||||
xc_hypercall_bounce_post(xch, devs);
|
||||
xc_hypercall_bounce_post(xch, nodes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xc_sched_id(xc_interface *xch,
|
||||
int *sched_id)
|
||||
|
||||
@@ -5139,6 +5139,51 @@ libxl_cputopology *libxl_get_cpu_topology(libxl_ctx *ctx, int *nb_cpu_out)
|
||||
return ret;
|
||||
}
|
||||
|
||||
libxl_pcitopology *libxl_get_pci_topology(libxl_ctx *ctx, int *num_devs)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
physdev_pci_device_t *devs;
|
||||
uint32_t *nodes;
|
||||
libxl_pcitopology *ret = NULL;
|
||||
int i, rc;
|
||||
|
||||
*num_devs = libxl__pci_numdevs(gc);
|
||||
if (*num_devs < 0) {
|
||||
LOG(ERROR, "Unable to determine number of PCI devices, rc %d",
|
||||
*num_devs);
|
||||
goto out;
|
||||
}
|
||||
|
||||
devs = libxl__zalloc(gc, sizeof(*devs) * *num_devs);
|
||||
nodes = libxl__zalloc(gc, sizeof(*nodes) * *num_devs);
|
||||
|
||||
rc = libxl__pci_topology_init(gc, devs, *num_devs);
|
||||
if (rc) {
|
||||
LOG(ERROR, "Cannot initialize PCI hypercall structure, rc %d", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (xc_pcitopoinfo(ctx->xch, *num_devs, devs, nodes) != 0) {
|
||||
LOGE(ERROR, "PCI topology info hypercall failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = libxl__zalloc(NOGC, sizeof(libxl_pcitopology) * *num_devs);
|
||||
|
||||
for (i = 0; i < *num_devs; i++) {
|
||||
ret[i].seg = devs[i].seg;
|
||||
ret[i].bus = devs[i].bus;
|
||||
ret[i].devfn = devs[i].devfn;
|
||||
ret[i].node = ((nodes[i] == XEN_INVALID_NODE_ID) ||
|
||||
(nodes[i] == XEN_INVALID_DEV)) ?
|
||||
LIBXL_PCITOPOLOGY_INVALID_ENTRY : nodes[i];
|
||||
}
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
libxl_numainfo *libxl_get_numainfo(libxl_ctx *ctx, int *nr)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
|
||||
@@ -760,6 +760,14 @@ void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, libxl_mac *src);
|
||||
#define LIBXL_HAVE_PSR_MBM 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* LIBXL_HAVE_PCITOPOLOGY
|
||||
*
|
||||
* If this is defined, then interface to query hypervisor about PCI device
|
||||
* topology is available.
|
||||
*/
|
||||
#define LIBXL_HAVE_PCITOPOLOGY 1
|
||||
|
||||
typedef char **libxl_string_list;
|
||||
void libxl_string_list_dispose(libxl_string_list *sl);
|
||||
int libxl_string_list_length(const libxl_string_list *sl);
|
||||
@@ -1152,6 +1160,10 @@ void libxl_vminfo_list_free(libxl_vminfo *list, int nb_vm);
|
||||
libxl_cputopology *libxl_get_cpu_topology(libxl_ctx *ctx, int *nb_cpu_out);
|
||||
void libxl_cputopology_list_free(libxl_cputopology *, int nb_cpu);
|
||||
|
||||
#define LIBXL_PCITOPOLOGY_INVALID_ENTRY (~(uint32_t)0)
|
||||
libxl_pcitopology *libxl_get_pci_topology(libxl_ctx *ctx, int *num_devs);
|
||||
void libxl_pcitopology_list_free(libxl_pcitopology *, int num_devs);
|
||||
|
||||
#define LIBXL_NUMAINFO_INVALID_ENTRY (~(uint32_t)0)
|
||||
libxl_numainfo *libxl_get_numainfo(libxl_ctx *ctx, int *nr);
|
||||
void libxl_numainfo_list_free(libxl_numainfo *, int nr);
|
||||
|
||||
@@ -131,3 +131,15 @@ libxl_device_model_version libxl__default_device_model(libxl__gc *gc)
|
||||
{
|
||||
return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
|
||||
}
|
||||
|
||||
int libxl__pci_numdevs(libxl__gc *gc)
|
||||
{
|
||||
return ERROR_NI;
|
||||
}
|
||||
|
||||
int libxl__pci_topology_init(libxl__gc *gc,
|
||||
physdev_pci_device_t *devs,
|
||||
int num_devs)
|
||||
{
|
||||
return ERROR_NI;
|
||||
}
|
||||
@@ -1196,6 +1196,11 @@ _hidden int libxl__try_phy_backend(mode_t st_mode);
|
||||
|
||||
_hidden char *libxl__devid_to_localdev(libxl__gc *gc, int devid);
|
||||
|
||||
_hidden int libxl__pci_numdevs(libxl__gc *gc);
|
||||
_hidden int libxl__pci_topology_init(libxl__gc *gc,
|
||||
physdev_pci_device_t *devs,
|
||||
int num_devs);
|
||||
|
||||
/* from libxl_pci */
|
||||
|
||||
_hidden int libxl__device_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcidev, int starting);
|
||||
|
||||
@@ -279,3 +279,73 @@ libxl_device_model_version libxl__default_device_model(libxl__gc *gc)
|
||||
{
|
||||
return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
|
||||
}
|
||||
|
||||
int libxl__pci_numdevs(libxl__gc *gc)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int num_devs = 0;
|
||||
|
||||
dir = opendir("/sys/bus/pci/devices");
|
||||
if (!dir) {
|
||||
LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir))) {
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
num_devs++;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return num_devs;
|
||||
}
|
||||
|
||||
int libxl__pci_topology_init(libxl__gc *gc,
|
||||
physdev_pci_device_t *devs,
|
||||
int num_devs)
|
||||
{
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int i, err = 0;
|
||||
|
||||
dir = opendir("/sys/bus/pci/devices");
|
||||
if (!dir) {
|
||||
LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while ((entry = readdir(dir))) {
|
||||
unsigned int dom, bus, dev, func;
|
||||
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (i == num_devs) {
|
||||
LOG(ERROR, "Too many devices");
|
||||
err = ERROR_FAIL;
|
||||
errno = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4) {
|
||||
LOGE(ERROR, "Error processing /sys/bus/pci/devices");
|
||||
err = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
devs[i].seg = dom;
|
||||
devs[i].bus = bus;
|
||||
devs[i].devfn = ((dev & 0x1f) << 3) | (func & 7);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
out:
|
||||
closedir(dir);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -95,3 +95,15 @@ libxl_device_model_version libxl__default_device_model(libxl__gc *gc)
|
||||
{
|
||||
return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
|
||||
}
|
||||
|
||||
int libxl__pci_numdevs(libxl__gc *gc)
|
||||
{
|
||||
return ERROR_NI;
|
||||
}
|
||||
|
||||
int libxl__pci_topology_init(libxl__gc *gc,
|
||||
physdev_pci_device_t *devs,
|
||||
int num_devs)
|
||||
{
|
||||
return ERROR_NI;
|
||||
}
|
||||
@@ -657,6 +657,13 @@ libxl_cputopology = Struct("cputopology", [
|
||||
("node", uint32),
|
||||
], dir=DIR_OUT)
|
||||
|
||||
libxl_pcitopology = Struct("pcitopology", [
|
||||
("seg", uint16),
|
||||
("bus", uint8),
|
||||
("devfn", uint8),
|
||||
("node", uint32),
|
||||
], dir=DIR_OUT)
|
||||
|
||||
libxl_sched_credit_params = Struct("sched_credit_params", [
|
||||
("tslice_ms", integer),
|
||||
("ratelimit_us", integer),
|
||||
|
||||
@@ -952,6 +952,14 @@ void libxl_cputopology_list_free(libxl_cputopology *list, int nr)
|
||||
free(list);
|
||||
}
|
||||
|
||||
void libxl_pcitopology_list_free(libxl_pcitopology *list, int nr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nr; i++)
|
||||
libxl_pcitopology_dispose(&list[i]);
|
||||
free(list);
|
||||
}
|
||||
|
||||
void libxl_numainfo_list_free(libxl_numainfo *list, int nr)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -5420,12 +5420,15 @@ static void output_numainfo(void)
|
||||
|
||||
static void output_topologyinfo(void)
|
||||
{
|
||||
libxl_cputopology *info;
|
||||
libxl_cputopology *cpuinfo;
|
||||
int i, nr;
|
||||
libxl_pcitopology *pciinfo;
|
||||
int valid_devs;
|
||||
|
||||
info = libxl_get_cpu_topology(ctx, &nr);
|
||||
if (info == NULL) {
|
||||
fprintf(stderr, "libxl_get_topologyinfo failed.\n");
|
||||
|
||||
cpuinfo = libxl_get_cpu_topology(ctx, &nr);
|
||||
if (cpuinfo == NULL) {
|
||||
fprintf(stderr, "libxl_get_cpu_topology failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5433,12 +5436,35 @@ static void output_topologyinfo(void)
|
||||
printf("cpu: core socket node\n");
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (info[i].core != LIBXL_CPUTOPOLOGY_INVALID_ENTRY)
|
||||
if (cpuinfo[i].core != LIBXL_CPUTOPOLOGY_INVALID_ENTRY)
|
||||
printf("%3d: %4d %4d %4d\n", i,
|
||||
info[i].core, info[i].socket, info[i].node);
|
||||
cpuinfo[i].core, cpuinfo[i].socket, cpuinfo[i].node);
|
||||
}
|
||||
|
||||
libxl_cputopology_list_free(info, nr);
|
||||
libxl_cputopology_list_free(cpuinfo, nr);
|
||||
|
||||
pciinfo = libxl_get_pci_topology(ctx, &nr);
|
||||
if (pciinfo == NULL) {
|
||||
fprintf(stderr, "libxl_get_pci_topology failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("device topology :\n");
|
||||
printf("device node\n");
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (pciinfo[i].node != LIBXL_PCITOPOLOGY_INVALID_ENTRY) {
|
||||
printf("%04x:%02x:%02x.%01x %d\n", pciinfo[i].seg,
|
||||
pciinfo[i].bus,
|
||||
((pciinfo[i].devfn >> 3) & 0x1f), (pciinfo[i].devfn & 7),
|
||||
pciinfo[i].node);
|
||||
valid_devs++;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_devs == 0)
|
||||
printf("No device topology data available\n");
|
||||
|
||||
libxl_pcitopology_list_free(pciinfo, nr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||