Merge tag 'dmaengine-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul...
[linux-2.6-microblaze.git] / drivers / dma / idxd / dma.c
index 77439b6..e0f056c 100644 (file)
@@ -69,7 +69,11 @@ static inline void idxd_prep_desc_common(struct idxd_wq *wq,
        hw->src_addr = addr_f1;
        hw->dst_addr = addr_f2;
        hw->xfer_size = len;
-       hw->priv = !!(wq->type == IDXD_WQT_KERNEL);
+       /*
+        * For dedicated WQ, this field is ignored and HW will use the WQCFG.priv
+        * field instead. This field should be set to 1 for kernel descriptors.
+        */
+       hw->priv = 1;
        hw->completion_addr = compl;
 }
 
@@ -149,10 +153,8 @@ static dma_cookie_t idxd_dma_tx_submit(struct dma_async_tx_descriptor *tx)
        cookie = dma_cookie_assign(tx);
 
        rc = idxd_submit_desc(wq, desc);
-       if (rc < 0) {
-               idxd_free_desc(wq, desc);
+       if (rc < 0)
                return rc;
-       }
 
        return cookie;
 }
@@ -245,7 +247,7 @@ int idxd_register_dma_channel(struct idxd_wq *wq)
 
        wq->idxd_chan = idxd_chan;
        idxd_chan->wq = wq;
-       get_device(&wq->conf_dev);
+       get_device(wq_confdev(wq));
 
        return 0;
 }
@@ -260,5 +262,87 @@ void idxd_unregister_dma_channel(struct idxd_wq *wq)
        list_del(&chan->device_node);
        kfree(wq->idxd_chan);
        wq->idxd_chan = NULL;
-       put_device(&wq->conf_dev);
+       put_device(wq_confdev(wq));
 }
+
+static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev)
+{
+       struct device *dev = &idxd_dev->conf_dev;
+       struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev);
+       struct idxd_device *idxd = wq->idxd;
+       int rc;
+
+       if (idxd->state != IDXD_DEV_ENABLED)
+               return -ENXIO;
+
+       mutex_lock(&wq->wq_lock);
+       wq->type = IDXD_WQT_KERNEL;
+       rc = __drv_enable_wq(wq);
+       if (rc < 0) {
+               dev_dbg(dev, "Enable wq %d failed: %d\n", wq->id, rc);
+               rc = -ENXIO;
+               goto err;
+       }
+
+       rc = idxd_wq_alloc_resources(wq);
+       if (rc < 0) {
+               idxd->cmd_status = IDXD_SCMD_WQ_RES_ALLOC_ERR;
+               dev_dbg(dev, "WQ resource alloc failed\n");
+               goto err_res_alloc;
+       }
+
+       rc = idxd_wq_init_percpu_ref(wq);
+       if (rc < 0) {
+               idxd->cmd_status = IDXD_SCMD_PERCPU_ERR;
+               dev_dbg(dev, "percpu_ref setup failed\n");
+               goto err_ref;
+       }
+
+       rc = idxd_register_dma_channel(wq);
+       if (rc < 0) {
+               idxd->cmd_status = IDXD_SCMD_DMA_CHAN_ERR;
+               dev_dbg(dev, "Failed to register dma channel\n");
+               goto err_dma;
+       }
+
+       idxd->cmd_status = 0;
+       mutex_unlock(&wq->wq_lock);
+       return 0;
+
+err_dma:
+       idxd_wq_quiesce(wq);
+err_ref:
+       idxd_wq_free_resources(wq);
+err_res_alloc:
+       __drv_disable_wq(wq);
+err:
+       wq->type = IDXD_WQT_NONE;
+       mutex_unlock(&wq->wq_lock);
+       return rc;
+}
+
+static void idxd_dmaengine_drv_remove(struct idxd_dev *idxd_dev)
+{
+       struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev);
+
+       mutex_lock(&wq->wq_lock);
+       idxd_wq_quiesce(wq);
+       idxd_unregister_dma_channel(wq);
+       __drv_disable_wq(wq);
+       idxd_wq_free_resources(wq);
+       wq->type = IDXD_WQT_NONE;
+       mutex_unlock(&wq->wq_lock);
+}
+
+static enum idxd_dev_type dev_types[] = {
+       IDXD_DEV_WQ,
+       IDXD_DEV_NONE,
+};
+
+struct idxd_device_driver idxd_dmaengine_drv = {
+       .probe = idxd_dmaengine_drv_probe,
+       .remove = idxd_dmaengine_drv_remove,
+       .name = "dmaengine",
+       .type = dev_types,
+};
+EXPORT_SYMBOL_GPL(idxd_dmaengine_drv);