Commit 5723cc34 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull dmaengine fixes from Vinod Koul:
 "This has a bunch of idxd driver fixes, dmatest revert and bunch of
  smaller driver fixes:

   - a bunch of idxd potential mem leak fixes

   - dmatest revert for waiting for interrupt fix as that causes issue

   - a couple of ti k3 udma fixes for locking and cap_mask

   - mediatek deadlock fix and unused variable cleanup fix"

* tag 'dmaengine-fix-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine:
  dmaengine: mediatek: drop unused variable
  dmaengine: fsl-edma: Fix return code for unhandled interrupts
  dmaengine: mediatek: Fix a possible deadlock error in mtk_cqdma_tx_status()
  dmaengine: idxd: Fix ->poll() return value
  dmaengine: idxd: Refactor remove call with idxd_cleanup() helper
  dmaengine: idxd: Add missing idxd cleanup to fix memory leak in remove call
  dmaengine: idxd: fix memory leak in error handling path of idxd_pci_probe
  dmaengine: idxd: fix memory leak in error handling path of idxd_alloc
  dmaengine: idxd: Add missing cleanups in cleanup internals
  dmaengine: idxd: Add missing cleanup for early error out in idxd_setup_internals
  dmaengine: idxd: fix memory leak in error handling path of idxd_setup_groups
  dmaengine: idxd: fix memory leak in error handling path of idxd_setup_engines
  dmaengine: idxd: fix memory leak in error handling path of idxd_setup_wqs
  dmaengine: ptdma: Move variable condition check to the first place and remove redundancy
  dmaengine: idxd: Fix allowing write() from different address spaces
  dmaengine: ti: k3-udma: Add missing locking
  dmaengine: ti: k3-udma: Use cap_mask directly from dma_device structure instead of a local copy
  dmaengine: Revert "dmaengine: dmatest: Fix dmatest waiting less when interrupted"
  dmaengine: idxd: cdev: Fix uninitialized use of sva in idxd_cdev_open
parents 21eeefe7 811d6a92
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -342,6 +342,9 @@ static void pt_cmd_callback_work(void *data, int err)
	struct pt_dma_chan *chan;
	unsigned long flags;

	if (!desc)
		return;

	dma_chan = desc->vd.tx.chan;
	chan = to_pt_chan(dma_chan);

@@ -355,7 +358,6 @@ static void pt_cmd_callback_work(void *data, int err)
		desc->status = DMA_ERROR;

	spin_lock_irqsave(&chan->vc.lock, flags);
	if (desc) {
	if (desc->status != DMA_COMPLETE) {
		if (desc->status != DMA_ERROR)
			desc->status = DMA_COMPLETE;
@@ -365,7 +367,6 @@ static void pt_cmd_callback_work(void *data, int err)
	} else {
		tx_desc = NULL;
	}
	}
	spin_unlock_irqrestore(&chan->vc.lock, flags);

	if (tx_desc) {
+3 −3
Original line number Diff line number Diff line
@@ -841,7 +841,7 @@ static int dmatest_func(void *data)
		} else {
			dma_async_issue_pending(chan);

			wait_event_timeout(thread->done_wait,
			wait_event_freezable_timeout(thread->done_wait,
					done->done,
					msecs_to_jiffies(params->timeout));

+1 −1
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ static irqreturn_t fsl_edma3_tx_handler(int irq, void *dev_id)

	intr = edma_readl_chreg(fsl_chan, ch_int);
	if (!intr)
		return IRQ_HANDLED;
		return IRQ_NONE;

	edma_writel_chreg(fsl_chan, 1, ch_int);

+11 −2
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
	struct idxd_wq *wq;
	struct device *dev, *fdev;
	int rc = 0;
	struct iommu_sva *sva;
	struct iommu_sva *sva = NULL;
	unsigned int pasid;
	struct idxd_cdev *idxd_cdev;

@@ -317,7 +317,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
	if (device_user_pasid_enabled(idxd))
		idxd_xa_pasid_remove(ctx);
failed_get_pasid:
	if (device_user_pasid_enabled(idxd))
	if (device_user_pasid_enabled(idxd) && !IS_ERR_OR_NULL(sva))
		iommu_sva_unbind_device(sva);
failed:
	mutex_unlock(&wq->wq_lock);
@@ -407,6 +407,9 @@ static int idxd_cdev_mmap(struct file *filp, struct vm_area_struct *vma)
	if (!idxd->user_submission_safe && !capable(CAP_SYS_RAWIO))
		return -EPERM;

	if (current->mm != ctx->mm)
		return -EPERM;

	rc = check_vma(wq, vma, __func__);
	if (rc < 0)
		return rc;
@@ -473,6 +476,9 @@ static ssize_t idxd_cdev_write(struct file *filp, const char __user *buf, size_t
	ssize_t written = 0;
	int i;

	if (current->mm != ctx->mm)
		return -EPERM;

	for (i = 0; i < len/sizeof(struct dsa_hw_desc); i++) {
		int rc = idxd_submit_user_descriptor(ctx, udesc + i);

@@ -493,6 +499,9 @@ static __poll_t idxd_cdev_poll(struct file *filp,
	struct idxd_device *idxd = wq->idxd;
	__poll_t out = 0;

	if (current->mm != ctx->mm)
		return POLLNVAL;

	poll_wait(filp, &wq->err_queue, wait);
	spin_lock(&idxd->dev_lock);
	if (idxd->sw_err.valid)
+113 −46
Original line number Diff line number Diff line
@@ -155,6 +155,25 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd)
	pci_free_irq_vectors(pdev);
}

static void idxd_clean_wqs(struct idxd_device *idxd)
{
	struct idxd_wq *wq;
	struct device *conf_dev;
	int i;

	for (i = 0; i < idxd->max_wqs; i++) {
		wq = idxd->wqs[i];
		if (idxd->hw.wq_cap.op_config)
			bitmap_free(wq->opcap_bmap);
		kfree(wq->wqcfg);
		conf_dev = wq_confdev(wq);
		put_device(conf_dev);
		kfree(wq);
	}
	bitmap_free(idxd->wq_enable_map);
	kfree(idxd->wqs);
}

static int idxd_setup_wqs(struct idxd_device *idxd)
{
	struct device *dev = &idxd->pdev->dev;
@@ -169,8 +188,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)

	idxd->wq_enable_map = bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL, dev_to_node(dev));
	if (!idxd->wq_enable_map) {
		kfree(idxd->wqs);
		return -ENOMEM;
		rc = -ENOMEM;
		goto err_bitmap;
	}

	for (i = 0; i < idxd->max_wqs; i++) {
@@ -189,10 +208,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
		conf_dev->bus = &dsa_bus_type;
		conf_dev->type = &idxd_wq_device_type;
		rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id);
		if (rc < 0) {
			put_device(conf_dev);
		if (rc < 0)
			goto err;
		}

		mutex_init(&wq->wq_lock);
		init_waitqueue_head(&wq->err_queue);
@@ -203,7 +220,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
		wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
		wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
		if (!wq->wqcfg) {
			put_device(conf_dev);
			rc = -ENOMEM;
			goto err;
		}
@@ -211,9 +227,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
		if (idxd->hw.wq_cap.op_config) {
			wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
			if (!wq->opcap_bmap) {
				put_device(conf_dev);
				rc = -ENOMEM;
				goto err;
				goto err_opcap_bmap;
			}
			bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS);
		}
@@ -224,15 +239,46 @@ static int idxd_setup_wqs(struct idxd_device *idxd)

	return 0;

err_opcap_bmap:
	kfree(wq->wqcfg);

err:
	put_device(conf_dev);
	kfree(wq);

	while (--i >= 0) {
		wq = idxd->wqs[i];
		if (idxd->hw.wq_cap.op_config)
			bitmap_free(wq->opcap_bmap);
		kfree(wq->wqcfg);
		conf_dev = wq_confdev(wq);
		put_device(conf_dev);
		kfree(wq);

	}
	bitmap_free(idxd->wq_enable_map);

err_bitmap:
	kfree(idxd->wqs);

	return rc;
}

static void idxd_clean_engines(struct idxd_device *idxd)
{
	struct idxd_engine *engine;
	struct device *conf_dev;
	int i;

	for (i = 0; i < idxd->max_engines; i++) {
		engine = idxd->engines[i];
		conf_dev = engine_confdev(engine);
		put_device(conf_dev);
		kfree(engine);
	}
	kfree(idxd->engines);
}

static int idxd_setup_engines(struct idxd_device *idxd)
{
	struct idxd_engine *engine;
@@ -263,6 +309,7 @@ static int idxd_setup_engines(struct idxd_device *idxd)
		rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id);
		if (rc < 0) {
			put_device(conf_dev);
			kfree(engine);
			goto err;
		}

@@ -276,10 +323,26 @@ static int idxd_setup_engines(struct idxd_device *idxd)
		engine = idxd->engines[i];
		conf_dev = engine_confdev(engine);
		put_device(conf_dev);
		kfree(engine);
	}
	kfree(idxd->engines);

	return rc;
}

static void idxd_clean_groups(struct idxd_device *idxd)
{
	struct idxd_group *group;
	int i;

	for (i = 0; i < idxd->max_groups; i++) {
		group = idxd->groups[i];
		put_device(group_confdev(group));
		kfree(group);
	}
	kfree(idxd->groups);
}

static int idxd_setup_groups(struct idxd_device *idxd)
{
	struct device *dev = &idxd->pdev->dev;
@@ -310,6 +373,7 @@ static int idxd_setup_groups(struct idxd_device *idxd)
		rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id);
		if (rc < 0) {
			put_device(conf_dev);
			kfree(group);
			goto err;
		}

@@ -334,20 +398,18 @@ static int idxd_setup_groups(struct idxd_device *idxd)
	while (--i >= 0) {
		group = idxd->groups[i];
		put_device(group_confdev(group));
		kfree(group);
	}
	kfree(idxd->groups);

	return rc;
}

static void idxd_cleanup_internals(struct idxd_device *idxd)
{
	int i;

	for (i = 0; i < idxd->max_groups; i++)
		put_device(group_confdev(idxd->groups[i]));
	for (i = 0; i < idxd->max_engines; i++)
		put_device(engine_confdev(idxd->engines[i]));
	for (i = 0; i < idxd->max_wqs; i++)
		put_device(wq_confdev(idxd->wqs[i]));
	idxd_clean_groups(idxd);
	idxd_clean_engines(idxd);
	idxd_clean_wqs(idxd);
	destroy_workqueue(idxd->wq);
}

@@ -390,7 +452,7 @@ static int idxd_init_evl(struct idxd_device *idxd)
static int idxd_setup_internals(struct idxd_device *idxd)
{
	struct device *dev = &idxd->pdev->dev;
	int rc, i;
	int rc;

	init_waitqueue_head(&idxd->cmd_waitq);

@@ -421,14 +483,11 @@ static int idxd_setup_internals(struct idxd_device *idxd)
 err_evl:
	destroy_workqueue(idxd->wq);
 err_wkq_create:
	for (i = 0; i < idxd->max_groups; i++)
		put_device(group_confdev(idxd->groups[i]));
	idxd_clean_groups(idxd);
 err_group:
	for (i = 0; i < idxd->max_engines; i++)
		put_device(engine_confdev(idxd->engines[i]));
	idxd_clean_engines(idxd);
 err_engine:
	for (i = 0; i < idxd->max_wqs; i++)
		put_device(wq_confdev(idxd->wqs[i]));
	idxd_clean_wqs(idxd);
 err_wqs:
	return rc;
}
@@ -528,6 +587,17 @@ static void idxd_read_caps(struct idxd_device *idxd)
		idxd->hw.iaa_cap.bits = ioread64(idxd->reg_base + IDXD_IAACAP_OFFSET);
}

static void idxd_free(struct idxd_device *idxd)
{
	if (!idxd)
		return;

	put_device(idxd_confdev(idxd));
	bitmap_free(idxd->opcap_bmap);
	ida_free(&idxd_ida, idxd->id);
	kfree(idxd);
}

static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data)
{
	struct device *dev = &pdev->dev;
@@ -545,28 +615,34 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d
	idxd_dev_set_type(&idxd->idxd_dev, idxd->data->type);
	idxd->id = ida_alloc(&idxd_ida, GFP_KERNEL);
	if (idxd->id < 0)
		return NULL;
		goto err_ida;

	idxd->opcap_bmap = bitmap_zalloc_node(IDXD_MAX_OPCAP_BITS, GFP_KERNEL, dev_to_node(dev));
	if (!idxd->opcap_bmap) {
		ida_free(&idxd_ida, idxd->id);
		return NULL;
	}
	if (!idxd->opcap_bmap)
		goto err_opcap;

	device_initialize(conf_dev);
	conf_dev->parent = dev;
	conf_dev->bus = &dsa_bus_type;
	conf_dev->type = idxd->data->dev_type;
	rc = dev_set_name(conf_dev, "%s%d", idxd->data->name_prefix, idxd->id);
	if (rc < 0) {
		put_device(conf_dev);
		return NULL;
	}
	if (rc < 0)
		goto err_name;

	spin_lock_init(&idxd->dev_lock);
	spin_lock_init(&idxd->cmd_lock);

	return idxd;

err_name:
	put_device(conf_dev);
	bitmap_free(idxd->opcap_bmap);
err_opcap:
	ida_free(&idxd_ida, idxd->id);
err_ida:
	kfree(idxd);

	return NULL;
}

static int idxd_enable_system_pasid(struct idxd_device *idxd)
@@ -1190,7 +1266,7 @@ int idxd_pci_probe_alloc(struct idxd_device *idxd, struct pci_dev *pdev,
 err:
	pci_iounmap(pdev, idxd->reg_base);
 err_iomap:
	put_device(idxd_confdev(idxd));
	idxd_free(idxd);
 err_idxd_alloc:
	pci_disable_device(pdev);
	return rc;
@@ -1232,7 +1308,6 @@ static void idxd_shutdown(struct pci_dev *pdev)
static void idxd_remove(struct pci_dev *pdev)
{
	struct idxd_device *idxd = pci_get_drvdata(pdev);
	struct idxd_irq_entry *irq_entry;

	idxd_unregister_devices(idxd);
	/*
@@ -1245,20 +1320,12 @@ static void idxd_remove(struct pci_dev *pdev)
	get_device(idxd_confdev(idxd));
	device_unregister(idxd_confdev(idxd));
	idxd_shutdown(pdev);
	if (device_pasid_enabled(idxd))
		idxd_disable_system_pasid(idxd);
	idxd_device_remove_debugfs(idxd);

	irq_entry = idxd_get_ie(idxd, 0);
	free_irq(irq_entry->vector, irq_entry);
	pci_free_irq_vectors(pdev);
	idxd_cleanup(idxd);
	pci_iounmap(pdev, idxd->reg_base);
	if (device_user_pasid_enabled(idxd))
		idxd_disable_sva(pdev);
	pci_disable_device(pdev);
	destroy_workqueue(idxd->wq);
	perfmon_pmu_remove(idxd);
	put_device(idxd_confdev(idxd));
	idxd_free(idxd);
	pci_disable_device(pdev);
}

static struct pci_driver idxd_pci_driver = {
Loading