@@ -156,6 +156,32 @@
#define PCID_CMD_IS_ASSIGNED "is_device_assigned"
#define PCID_MSG_FIELD_RESULT "result"
+/*
+ *******************************************************************************
+ * Get device resources
+ *
+ * This command returns resource list of device
+ *
+ * Request (see other mandatory fields above):
+ * - "cmd" field of the request must be set to "resource_list".
+ * - "sbdf" SBDF of the device in format defined by PCID_SBDF_FMT.
+ *
+ * Response (see other mandatory fields above):
+ * - "resp" field of the response must be set to "resource_list".
+ * Command specific response data:
+ * +-------------+--------------+----------------------------------------------+
+ * | resources | map | key 'iomem' - list of memory regions |
+ * | | | key 'irqs' - list of irqs |
+ * +-------------+--------------+----------------------------------------------+
+ */
+#define PCID_CMD_RESOURCE_LIST "resource_list"
+/* Arguments */
+#define PCID_MSG_FIELD_DOMID "domid"
+/* Result */
+#define PCID_MSG_FIELD_RESOURCES "resources"
+#define PCID_RESULT_KEY_IOMEM "iomem"
+#define PCID_RESULT_KEY_IRQS "irqs"
+
/*
*******************************************************************************
* Reset PCI device
@@ -81,16 +81,19 @@ static int pci_handle_response(libxl__gc *gc,
LOG(DEBUG, "command: %s", command_name);
if (strcmp(command_name, PCID_CMD_LIST_ASSIGNABLE) == 0)
- ret = process_list_assignable(gc, response, result);
+ ret = process_list_assignable(gc, response, result);
else if (strcmp(command_name, PCID_CMD_MAKE_ASSIGNABLE) == 0)
*result = libxl__json_object_alloc(gc, JSON_NULL);
else if (strcmp(command_name, PCID_CMD_REVERT_ASSIGNABLE) == 0)
*result = libxl__json_object_alloc(gc, JSON_NULL);
else if (strcmp(command_name, PCID_CMD_IS_ASSIGNED) == 0)
*result = (libxl__json_object *)libxl__json_map_get(PCID_MSG_FIELD_RESULT,
- response, JSON_BOOL);
+ response, JSON_BOOL);
else if (strcmp(command_name, PCID_CMD_RESET_DEVICE) == 0)
*result = libxl__json_object_alloc(gc, JSON_NULL);
+ else if (strcmp(command_name, PCID_CMD_RESOURCE_LIST) == 0)
+ *result = (libxl__json_object *)libxl__json_map_get(PCID_MSG_FIELD_RESOURCES,
+ response, JSON_MAP);
return ret;
}
@@ -1388,14 +1391,21 @@ static void pci_add_dm_done(libxl__egc *egc,
STATE_AO_GC(pas->aodev->ao);
libxl_ctx *ctx = libxl__gc_owner(gc);
libxl_domid domid = pas->pci_domid;
- char *sysfs_path;
- FILE *f;
unsigned long long start, end, flags, size;
int irq, i;
int r;
uint32_t flag = XEN_DOMCTL_DEV_RDM_RELAXED;
uint32_t domainid = domid;
bool isstubdom = libxl_is_stubdom(ctx, domid, &domainid);
+ struct vchan_info *vchan;
+ libxl__json_object *result;
+ libxl__json_object *args;
+ const libxl__json_object *value;
+ libxl__json_object *res_obj;
+
+ vchan = pci_vchan_get_client(gc);
+ if (!vchan)
+ goto out;
/* Convenience aliases */
bool starting = pas->starting;
@@ -1404,25 +1414,27 @@ static void pci_add_dm_done(libxl__egc *egc,
libxl__ev_qmp_dispose(gc, &pas->qmp);
- if (rc) goto out;
+ args = libxl__vchan_start_args(gc);
+ libxl__vchan_arg_add_string(gc, args, PCID_MSG_FIELD_SBDF,
+ GCSPRINTF(PCID_SBDF_FMT, pci->domain,
+ pci->bus, pci->dev, pci->func));
+ libxl__vchan_arg_add_integer(gc, args, PCID_MSG_FIELD_DOMID, domid);
+
+ result = vchan_send_command(gc, vchan, PCID_CMD_RESOURCE_LIST, args);
+ if (!result)
+ goto vchan_free;
+ value = libxl__json_map_get(PCID_RESULT_KEY_IOMEM, result, JSON_ARRAY);
/* stubdomain is always running by now, even at create time */
if (isstubdom)
starting = false;
-
- sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/resource", pci->domain,
- pci->bus, pci->dev, pci->func);
- f = fopen(sysfs_path, "r");
start = end = flags = size = 0;
irq = 0;
-
- if (f == NULL) {
- LOGED(ERROR, domainid, "Couldn't open %s", sysfs_path);
- rc = ERROR_FAIL;
- goto out;
- }
for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
- if (fscanf(f, "0x%llx 0x%llx 0x%llx\n", &start, &end, &flags) != 3)
+ if ((res_obj = libxl__json_array_get(value, i)) == NULL)
+ continue;
+ const char *iomem_str = libxl__json_object_get_string(res_obj);
+ if (sscanf(iomem_str, "0x%llx 0x%llx 0x%llx\n", &start, &end, &flags) != 3)
continue;
size = end - start + 1;
if (start) {
@@ -1432,7 +1444,6 @@ static void pci_add_dm_done(libxl__egc *egc,
LOGED(ERROR, domainid,
"xc_domain_ioport_permission 0x%llx/0x%llx (error %d)",
start, size, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
@@ -1443,29 +1454,21 @@ static void pci_add_dm_done(libxl__egc *egc,
LOGED(ERROR, domainid,
"xc_domain_iomem_permission 0x%llx/0x%llx (error %d)",
start, size, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
}
}
}
- fclose(f);
if (!pci_supp_legacy_irq())
goto out_no_irq;
- sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/irq", pci->domain,
- pci->bus, pci->dev, pci->func);
- f = fopen(sysfs_path, "r");
- if (f == NULL) {
- LOGED(ERROR, domainid, "Couldn't open %s", sysfs_path);
- goto out_no_irq;
- }
- if ((fscanf(f, "%u", &irq) == 1) && irq) {
+ value = libxl__json_map_get(PCID_RESULT_KEY_IRQS, result, JSON_ARRAY);
+ if ((res_obj = libxl__json_array_get(value, i)) &&
+ (irq = libxl__json_object_get_integer(res_obj))) {
r = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
if (r < 0) {
LOGED(ERROR, domainid, "xc_physdev_map_pirq irq=%d (error=%d)",
irq, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
@@ -1473,12 +1476,10 @@ static void pci_add_dm_done(libxl__egc *egc,
if (r < 0) {
LOGED(ERROR, domainid,
"xc_domain_irq_permission irq=%d (error=%d)", irq, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
}
- fclose(f);
/* Don't restrict writes to the PCI config space from this VM */
if (pci->permissive) {
@@ -1511,6 +1512,8 @@ out_no_irq:
rc = libxl__device_pci_add_xenstore(gc, domid, pci, starting);
else
rc = 0;
+vchan_free:
+ pci_vchan_free(gc, vchan);
out:
libxl__ev_time_deregister(gc, &pas->timeout);
libxl__ev_time_deregister(gc, &pas->timeout_retries);
@@ -40,6 +40,10 @@
#define PCI_BDF "%04x:%02x:%02x.%01x"
+static int sysfs_write_bdf(libxl__gc *gc, const char * sysfs_path,
+ unsigned int domain, unsigned int bus,
+ unsigned int dev, unsigned int func);
+
struct vchan_client {
XEN_LIST_ENTRY(struct vchan_client) list;
@@ -121,6 +125,109 @@ static int process_list_assignable(libxl__gc *gc, yajl_gen gen,
return 0;
}
+static bool pci_supp_legacy_irq(void)
+{
+#ifdef CONFIG_PCI_SUPP_LEGACY_IRQ
+ return true;
+#else
+ return false;
+#endif
+}
+
+static int process_list_resources(libxl__gc *gc, yajl_gen gen,
+ char *command_name,
+ const struct libxl__json_object *request,
+ struct libxl__json_object **response)
+{
+ struct libxl__json_object *iomem =
+ libxl__json_object_alloc(gc, JSON_ARRAY);
+ struct libxl__json_object *irqs =
+ libxl__json_object_alloc(gc, JSON_ARRAY);
+ const struct libxl__json_object *json_sdbf;
+ const struct libxl__json_object *json_domid;
+ unsigned int dom, bus, dev, func;
+ libxl_domid domainid;
+ char *sysfs_path;
+ FILE *f;
+ unsigned long long start, end, flags;
+ int irq, i;
+ int rc = 0;
+ libxl__json_map_node *map_node = NULL;
+
+ json_sdbf = libxl__json_map_get(PCID_MSG_FIELD_SBDF, request, JSON_STRING);
+ if (!json_sdbf) {
+ make_error_reply(gc, gen, "No mandatory parameter 'sbdf'", command_name);
+ return ERROR_FAIL;
+ }
+ if (sscanf(libxl__json_object_get_string(json_sdbf), PCID_SBDF_FMT,
+ &dom, &bus, &dev, &func) != 4) {
+ make_error_reply(gc, gen, "Can't parse SBDF", command_name);
+ return ERROR_FAIL;
+ }
+
+ json_domid = libxl__json_map_get(PCID_MSG_FIELD_DOMID, request, JSON_INTEGER);
+ if (!json_domid) {
+ make_error_reply(gc, gen, "No mandatory parameter 'domid'", command_name);
+ return ERROR_FAIL;
+ }
+ domainid = libxl__json_object_get_integer(json_domid);
+
+ libxl__yajl_gen_asciiz(gen, PCID_MSG_FIELD_RESOURCES);
+ *response = libxl__json_object_alloc(gc, JSON_MAP);
+
+ sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/resource", dom, bus, dev, func);
+ f = fopen(sysfs_path, "r");
+ start = 0;
+ irq = 0;
+
+ if (f == NULL) {
+ LOGED(ERROR, domainid, "Couldn't open %s", sysfs_path);
+ rc = ERROR_FAIL;
+ goto out;
+ }
+ for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
+ if (fscanf(f, "0x%llx 0x%llx 0x%llx\n", &start, &end, &flags) != 3)
+ continue;
+ if (start) {
+ struct libxl__json_object *node =
+ libxl__json_object_alloc(gc, JSON_STRING);
+
+ node->u.string = GCSPRINTF("0x%llx 0x%llx 0x%llx", start, end, flags);
+ flexarray_append(iomem->u.array, node);
+ }
+ }
+ fclose(f);
+ if (!pci_supp_legacy_irq())
+ goto out_no_irq;
+ sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/irq", dom, bus, dev, func);
+ f = fopen(sysfs_path, "r");
+ if (f == NULL) {
+ LOGED(ERROR, domainid, "Couldn't open %s", sysfs_path);
+ goto out_no_irq;
+ }
+ if ((fscanf(f, "%u", &irq) == 1) && irq) {
+ struct libxl__json_object *node =
+ libxl__json_object_alloc(gc, JSON_INTEGER);
+
+ node->u.i = irq;
+ flexarray_append(irqs->u.array, node);
+ }
+ fclose(f);
+
+ GCNEW(map_node);
+ map_node->map_key = libxl__strdup(gc, PCID_RESULT_KEY_IRQS);
+ map_node->obj = irqs;
+ flexarray_append((*response)->u.map, map_node);
+out_no_irq:
+ GCNEW(map_node);
+ map_node->map_key = libxl__strdup(gc, PCID_RESULT_KEY_IOMEM);
+ map_node->obj = iomem;
+ flexarray_append((*response)->u.map, map_node);
+ rc = 0;
+out:
+ return rc;
+}
+
static int pciback_dev_is_assigned(libxl__gc *gc, unsigned int domain,
unsigned int bus, unsigned int dev,
unsigned int func)
@@ -636,6 +743,9 @@ static int pcid_handle_request(libxl__gc *gc, yajl_gen gen,
else if (strcmp(command_name, PCID_CMD_RESET_DEVICE) == 0)
ret = process_device_pci_reset(gc, gen, command_name,
request, &command_response);
+ else if (strcmp(command_name, PCID_CMD_RESOURCE_LIST) == 0)
+ ret = process_list_resources(gc, gen, command_name,
+ request, &command_response);
else {
/*
* This is an unsupported command: make a reply and proceed over
@@ -99,6 +99,14 @@ void libxl__vchan_arg_add_bool(libxl__gc *gc, libxl__json_object *args,
obj->u.b = val;
}
+void libxl__vchan_arg_add_integer(libxl__gc *gc, libxl__json_object *args,
+ char *key, int val)
+{
+ libxl__json_object *obj = libxl__vchan_arg_new(gc, JSON_INTEGER, args, key);
+
+ obj->u.i = val;
+}
+
static void reset_yajl_generator(struct vchan_state *state)
{
yajl_gen_clear(state->gen);
@@ -58,7 +58,9 @@ static inline libxl__json_object *libxl__vchan_start_args(libxl__gc *gc)
void libxl__vchan_arg_add_string(libxl__gc *gc, libxl__json_object *args,
char *key, char *val);
void libxl__vchan_arg_add_bool(libxl__gc *gc, libxl__json_object *args,
- char *key, bool val);
+ char *key, bool val);
+void libxl__vchan_arg_add_integer(libxl__gc *gc, libxl__json_object *args,
+ char *key, int val);
libxl__json_object *vchan_send_command(libxl__gc *gc, struct vchan_info *vchan,
char *cmd, libxl__json_object *args);