Commit c17a3066 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull dmaengine fixes from Vinod Koul:
 "A couple of dmaengine driver fixes for:

   - race and descriptor issue for xilinx driver

   - fix interrupt handling, wq state & cleanup, field sizes for
     completion, msix permissions for idxd driver

   - runtime pm fix for tegra driver

   - double free fix in dma_async_device_register"

* tag 'dmaengine-fix-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine:
  dmaengine: idxd: fix wq cleanup of WQCFG registers
  dmaengine: idxd: clear MSIX permission entry on shutdown
  dmaengine: plx_dma: add a missing put_device() on error path
  dmaengine: tegra20: Fix runtime PM imbalance on error
  dmaengine: Fix a double free in dma_async_device_register
  dmaengine: dw: Make it dependent to HAS_IOMEM
  dmaengine: idxd: fix wq size store permission state
  dmaengine: idxd: fix opcap sysfs attribute output
  dmaengine: idxd: fix delta_rec and crc size field for completion record
  dmaengine: idxd: Fix clobbering of SWERR overflow bit on writeback
  dmaengine: xilinx: dpdma: Fix race condition in done IRQ
  dmaengine: xilinx: dpdma: Fix descriptor issuing on video group
parents e70b911a ea9aadc0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1086,6 +1086,7 @@ static int __dma_async_device_channel_register(struct dma_device *device,
	kfree(chan->dev);
 err_free_local:
	free_percpu(chan->local);
	chan->local = NULL;
	return rc;
}

+2 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ config DW_DMAC_CORE

config DW_DMAC
	tristate "Synopsys DesignWare AHB DMA platform driver"
	depends on HAS_IOMEM
	select DW_DMAC_CORE
	help
	  Support the Synopsys DesignWare AHB DMA controller. This
@@ -18,6 +19,7 @@ config DW_DMAC
config DW_DMAC_PCI
	tristate "Synopsys DesignWare AHB DMA PCI driver"
	depends on PCI
	depends on HAS_IOMEM
	select DW_DMAC_CORE
	help
	  Support the Synopsys DesignWare AHB DMA controller on the
+54 −11
Original line number Diff line number Diff line
@@ -282,6 +282,22 @@ void idxd_wq_drain(struct idxd_wq *wq)
	idxd_cmd_exec(idxd, IDXD_CMD_DRAIN_WQ, operand, NULL);
}

void idxd_wq_reset(struct idxd_wq *wq)
{
	struct idxd_device *idxd = wq->idxd;
	struct device *dev = &idxd->pdev->dev;
	u32 operand;

	if (wq->state != IDXD_WQ_ENABLED) {
		dev_dbg(dev, "WQ %d in wrong state: %d\n", wq->id, wq->state);
		return;
	}

	operand = BIT(wq->id % 16) | ((wq->id / 16) << 16);
	idxd_cmd_exec(idxd, IDXD_CMD_RESET_WQ, operand, NULL);
	wq->state = IDXD_WQ_DISABLED;
}

int idxd_wq_map_portal(struct idxd_wq *wq)
{
	struct idxd_device *idxd = wq->idxd;
@@ -363,8 +379,6 @@ int idxd_wq_disable_pasid(struct idxd_wq *wq)
void idxd_wq_disable_cleanup(struct idxd_wq *wq)
{
	struct idxd_device *idxd = wq->idxd;
	struct device *dev = &idxd->pdev->dev;
	int i, wq_offset;

	lockdep_assert_held(&idxd->dev_lock);
	memset(wq->wqcfg, 0, idxd->wqcfg_size);
@@ -376,14 +390,6 @@ void idxd_wq_disable_cleanup(struct idxd_wq *wq)
	wq->ats_dis = 0;
	clear_bit(WQ_FLAG_DEDICATED, &wq->flags);
	memset(wq->name, 0, WQ_NAME_SIZE);

	for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
		wq_offset = WQCFG_OFFSET(idxd, wq->id, i);
		iowrite32(0, idxd->reg_base + wq_offset);
		dev_dbg(dev, "WQ[%d][%d][%#x]: %#x\n",
			wq->id, i, wq_offset,
			ioread32(idxd->reg_base + wq_offset));
	}
}

/* Device control bits */
@@ -574,6 +580,36 @@ void idxd_device_drain_pasid(struct idxd_device *idxd, int pasid)
}

/* Device configuration bits */
void idxd_msix_perm_setup(struct idxd_device *idxd)
{
	union msix_perm mperm;
	int i, msixcnt;

	msixcnt = pci_msix_vec_count(idxd->pdev);
	if (msixcnt < 0)
		return;

	mperm.bits = 0;
	mperm.pasid = idxd->pasid;
	mperm.pasid_en = device_pasid_enabled(idxd);
	for (i = 1; i < msixcnt; i++)
		iowrite32(mperm.bits, idxd->reg_base + idxd->msix_perm_offset + i * 8);
}

void idxd_msix_perm_clear(struct idxd_device *idxd)
{
	union msix_perm mperm;
	int i, msixcnt;

	msixcnt = pci_msix_vec_count(idxd->pdev);
	if (msixcnt < 0)
		return;

	mperm.bits = 0;
	for (i = 1; i < msixcnt; i++)
		iowrite32(mperm.bits, idxd->reg_base + idxd->msix_perm_offset + i * 8);
}

static void idxd_group_config_write(struct idxd_group *group)
{
	struct idxd_device *idxd = group->idxd;
@@ -642,7 +678,14 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
	if (!wq->group)
		return 0;

	memset(wq->wqcfg, 0, idxd->wqcfg_size);
	/*
	 * Instead of memset the entire shadow copy of WQCFG, copy from the hardware after
	 * wq reset. This will copy back the sticky values that are present on some devices.
	 */
	for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
		wq_offset = WQCFG_OFFSET(idxd, wq->id, i);
		wq->wqcfg->bits[i] = ioread32(idxd->reg_base + wq_offset);
	}

	/* byte 0-3 */
	wq->wqcfg->wq_size = wq->size;
+3 −0
Original line number Diff line number Diff line
@@ -316,6 +316,8 @@ void idxd_unregister_driver(void);
struct bus_type *idxd_get_bus_type(struct idxd_device *idxd);

/* device interrupt control */
void idxd_msix_perm_setup(struct idxd_device *idxd);
void idxd_msix_perm_clear(struct idxd_device *idxd);
irqreturn_t idxd_irq_handler(int vec, void *data);
irqreturn_t idxd_misc_thread(int vec, void *data);
irqreturn_t idxd_wq_thread(int irq, void *data);
@@ -341,6 +343,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq);
int idxd_wq_enable(struct idxd_wq *wq);
int idxd_wq_disable(struct idxd_wq *wq);
void idxd_wq_drain(struct idxd_wq *wq);
void idxd_wq_reset(struct idxd_wq *wq);
int idxd_wq_map_portal(struct idxd_wq *wq);
void idxd_wq_unmap_portal(struct idxd_wq *wq);
void idxd_wq_disable_cleanup(struct idxd_wq *wq);
+2 −9
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ static int idxd_setup_interrupts(struct idxd_device *idxd)
	struct idxd_irq_entry *irq_entry;
	int i, msixcnt;
	int rc = 0;
	union msix_perm mperm;

	msixcnt = pci_msix_vec_count(pdev);
	if (msixcnt < 0) {
@@ -144,14 +143,7 @@ static int idxd_setup_interrupts(struct idxd_device *idxd)
	}

	idxd_unmask_error_interrupts(idxd);

	/* Setup MSIX permission table */
	mperm.bits = 0;
	mperm.pasid = idxd->pasid;
	mperm.pasid_en = device_pasid_enabled(idxd);
	for (i = 1; i < msixcnt; i++)
		iowrite32(mperm.bits, idxd->reg_base + idxd->msix_perm_offset + i * 8);

	idxd_msix_perm_setup(idxd);
	return 0;

 err_no_irq:
@@ -510,6 +502,7 @@ static void idxd_shutdown(struct pci_dev *pdev)
		idxd_flush_work_list(irq_entry);
	}

	idxd_msix_perm_clear(idxd);
	destroy_workqueue(idxd->wq);
}

Loading