+
+static inline bool
+is_dma_configured(int16_t dev_id)
+{
+ int i;
+
+ for (i = 0; i < dma_count; i++)
+ if (dmas_id[i] == dev_id)
+ return true;
+ return false;
+}
+
+static inline int
+open_dma(const char *value)
+{
+ struct dma_for_vhost *dma_info = dma_bind;
+ char *input = strndup(value, strlen(value) + 1);
+ char *addrs = input;
+ char *ptrs[2];
+ char *start, *end, *substr;
+ int64_t vid;
+
+ struct rte_dma_info info;
+ struct rte_dma_conf dev_config = { .nb_vchans = 1 };
+ struct rte_dma_vchan_conf qconf = {
+ .direction = RTE_DMA_DIR_MEM_TO_MEM,
+ .nb_desc = DMA_RING_SIZE
+ };
+
+ int dev_id;
+ int ret = 0;
+ uint16_t i = 0;
+ char *dma_arg[RTE_MAX_VHOST_DEVICE];
+ int args_nr;
+
+ while (isblank(*addrs))
+ addrs++;
+ if (*addrs == '\0') {
+ ret = -1;
+ goto out;
+ }
+
+ /* process DMA devices within bracket. */
+ addrs++;
+ substr = strtok(addrs, ";]");
+ if (!substr) {
+ ret = -1;
+ goto out;
+ }
+
+ args_nr = rte_strsplit(substr, strlen(substr), dma_arg, RTE_MAX_VHOST_DEVICE, ',');
+ if (args_nr <= 0) {
+ ret = -1;
+ goto out;
+ }
+
+ while (i < args_nr) {
+ char *arg_temp = dma_arg[i];
+ uint8_t sub_nr;
+
+ sub_nr = rte_strsplit(arg_temp, strlen(arg_temp), ptrs, 2, '@');
+ if (sub_nr != 2) {
+ ret = -1;
+ goto out;
+ }
+
+ start = strstr(ptrs[0], "txd");
+ if (start == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ start += 3;
+ vid = strtol(start, &end, 0);
+ if (end == start) {
+ ret = -1;
+ goto out;
+ }
+
+ dev_id = rte_dma_get_dev_id_by_name(ptrs[1]);
+ if (dev_id < 0) {
+ RTE_LOG(ERR, VHOST_CONFIG, "Fail to find DMA %s.\n", ptrs[1]);
+ ret = -1;
+ goto out;
+ }
+
+ /* DMA device is already configured, so skip */
+ if (is_dma_configured(dev_id))
+ goto done;
+
+ if (rte_dma_info_get(dev_id, &info) != 0) {
+ RTE_LOG(ERR, VHOST_CONFIG, "Error with rte_dma_info_get()\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (info.max_vchans < 1) {
+ RTE_LOG(ERR, VHOST_CONFIG, "No channels available on device %d\n", dev_id);
+ ret = -1;
+ goto out;
+ }
+
+ if (rte_dma_configure(dev_id, &dev_config) != 0) {
+ RTE_LOG(ERR, VHOST_CONFIG, "Fail to configure DMA %d.\n", dev_id);
+ ret = -1;
+ goto out;
+ }
+
+ /* Check the max desc supported by DMA device */
+ rte_dma_info_get(dev_id, &info);
+ if (info.nb_vchans != 1) {
+ RTE_LOG(ERR, VHOST_CONFIG, "No configured queues reported by DMA %d.\n",
+ dev_id);
+ ret = -1;
+ goto out;
+ }
+
+ qconf.nb_desc = RTE_MIN(DMA_RING_SIZE, info.max_desc);
+
+ if (rte_dma_vchan_setup(dev_id, 0, &qconf) != 0) {
+ RTE_LOG(ERR, VHOST_CONFIG, "Fail to set up DMA %d.\n", dev_id);
+ ret = -1;
+ goto out;
+ }
+
+ if (rte_dma_start(dev_id) != 0) {
+ RTE_LOG(ERR, VHOST_CONFIG, "Fail to start DMA %u.\n", dev_id);
+ ret = -1;
+ goto out;
+ }
+
+ dmas_id[dma_count++] = dev_id;
+
+done:
+ (dma_info + vid)->dmas[VIRTIO_RXQ].dev_id = dev_id;
+ i++;
+ }
+out:
+ free(input);
+ return ret;
+}