@@ -80,6 +80,25 @@
#define PCID_SBDF_FMT "%04x:%02x:%02x.%01x"
+/*
+ *******************************************************************************
+ * List assignable devices
+ *
+ * This command lists PCI devices that can be passed through to a guest domain.
+ *
+ * Request (see other mandatory fields above):
+ * - "cmd" field of the request must be set to "list_assignable".
+ *
+ * Response (see other mandatory fields above):
+ * - "resp" field of the response must be set to "list_assignable".
+ * Command specific response data:
+ * +-------------+--------------+----------------------------------------------+
+ * | devices | list | List of of pci_device objects |
+ * +-------------+--------------+----------------------------------------------+
+ */
+#define PCID_CMD_LIST_ASSIGNABLE "list_assignable"
+#define PCID_MSG_FIELD_DEVICES "devices"
+
int libxl_pcid_process(libxl_ctx *ctx);
#endif /* XEN_PCID_H */
@@ -29,6 +29,18 @@
#define PCI_BDF_XSPATH "%04x-%02x-%02x-%01x"
#define PCI_PT_QDEV_ID "pci-pt-%02x_%02x.%01x"
+static int process_list_assignable(libxl__gc *gc,
+ const libxl__json_object *response,
+ libxl__json_object **result)
+{
+ *result = (libxl__json_object *)libxl__json_map_get(PCID_MSG_FIELD_DEVICES,
+ response, JSON_ARRAY);
+ if (!*result)
+ return ERROR_INVAL;
+
+ return 0;
+}
+
static int pci_handle_response(libxl__gc *gc,
const libxl__json_object *response,
libxl__json_object **result)
@@ -68,6 +80,9 @@ static int pci_handle_response(libxl__gc *gc,
command_name = command_obj->u.string;
LOG(DEBUG, "command: %s", command_name);
+ if (strcmp(command_name, PCID_CMD_LIST_ASSIGNABLE) == 0)
+ ret = process_list_assignable(gc, response, result);
+
return ret;
}
@@ -124,8 +139,7 @@ static char *pci_prepare_request(libxl__gc *gc, yajl_gen gen, char *cmd,
return request;
}
-struct vchan_info *pci_vchan_get_client(libxl__gc *gc);
-struct vchan_info *pci_vchan_get_client(libxl__gc *gc)
+static struct vchan_info *pci_vchan_get_client(libxl__gc *gc)
{
struct vchan_info *vchan;
@@ -147,8 +161,7 @@ out:
return vchan;
}
-void pci_vchan_free(libxl__gc *gc, struct vchan_info *vchan);
-void pci_vchan_free(libxl__gc *gc, struct vchan_info *vchan)
+static void pci_vchan_free(libxl__gc *gc, struct vchan_info *vchan)
{
vchan_fini_one(gc, vchan->state);
}
@@ -561,26 +574,29 @@ libxl_device_pci *libxl_device_pci_assignable_list(libxl_ctx *ctx, int *num)
{
GC_INIT(ctx);
libxl_device_pci *pcis = NULL, *new;
- struct dirent *de;
- DIR *dir;
+ struct vchan_info *vchan;
+ libxl__json_object *result, *dev_obj;
+ int i;
*num = 0;
- dir = opendir(SYSFS_PCIBACK_DRIVER);
- if (NULL == dir) {
- if (errno == ENOENT) {
- LOG(ERROR, "Looks like pciback driver not loaded");
- } else {
- LOGE(ERROR, "Couldn't open %s", SYSFS_PCIBACK_DRIVER);
- }
+ vchan = pci_vchan_get_client(gc);
+ if (!vchan)
goto out;
- }
- while((de = readdir(dir))) {
+ result = vchan_send_command(gc, vchan, PCID_CMD_LIST_ASSIGNABLE, NULL);
+ if (!result)
+ goto vchan_free;
+
+ for (i = 0; (dev_obj = libxl__json_array_get(result, i)); i++) {
+ const char *sbdf_str = libxl__json_object_get_string(dev_obj);
unsigned int dom, bus, dev, func;
- char *name;
+ const char *name;
+
+ if (!sbdf_str)
+ continue;
- if (sscanf(de->d_name, PCI_BDF, &dom, &bus, &dev, &func) != 4)
+ if (sscanf(sbdf_str, PCID_SBDF_FMT, &dom, &bus, &dev, &func) != 4)
continue;
new = realloc(pcis, ((*num) + 1) * sizeof(*new));
@@ -602,7 +618,9 @@ libxl_device_pci *libxl_device_pci_assignable_list(libxl_ctx *ctx, int *num)
(*num)++;
}
- closedir(dir);
+vchan_free:
+ pci_vchan_free(gc, vchan);
+
out:
GC_FREE;
return pcis;
@@ -84,6 +84,41 @@ static int make_error_reply(libxl__gc *gc, yajl_gen gen, char *desc,
return 0;
}
+static int process_list_assignable(libxl__gc *gc, yajl_gen gen,
+ char *command_name,
+ const struct libxl__json_object *request,
+ struct libxl__json_object **response)
+{
+ struct dirent *de;
+ DIR *dir = NULL;
+
+ dir = opendir(SYSFS_PCI_DEV);
+ if (dir == NULL) {
+ make_error_reply(gc, gen, strerror(errno), command_name);
+ return ERROR_FAIL;
+ }
+
+ libxl__yajl_gen_asciiz(gen, PCID_MSG_FIELD_DEVICES);
+
+ *response = libxl__json_object_alloc(gc, JSON_ARRAY);
+
+ while ((de = readdir(dir))) {
+ unsigned int dom, bus, dev, func;
+
+ if (sscanf(de->d_name, PCID_SBDF_FMT, &dom, &bus, &dev, &func) != 4)
+ continue;
+
+ struct libxl__json_object *node =
+ libxl__json_object_alloc(gc, JSON_STRING);
+ node->u.string = de->d_name;
+ flexarray_append((*response)->u.array, node);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
static int pcid_handle_request(libxl__gc *gc, yajl_gen gen,
const libxl__json_object *request)
{
@@ -104,14 +139,19 @@ static int pcid_handle_request(libxl__gc *gc, yajl_gen gen,
command_name = command_obj->u.string;
- /*
- * This is an unsupported command: make a reply and proceed over
- * the error path.
- */
- ret = make_error_reply(gc, gen, "Unsupported command",
- command_name);
- if (!ret)
- ret = ERROR_NOTFOUND;
+ if (strcmp(command_name, PCID_CMD_LIST_ASSIGNABLE) == 0)
+ ret = process_list_assignable(gc, gen, command_name,
+ request, &command_response);
+ else {
+ /*
+ * This is an unsupported command: make a reply and proceed over
+ * the error path.
+ */
+ ret = make_error_reply(gc, gen, "Unsupported command",
+ command_name);
+ if (!ret)
+ ret = ERROR_NOTFOUND;
+ }
if (ret) {
/*