aboutsummaryrefslogtreecommitdiff
path: root/drivers/dma/idxd/device.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org> 2020-12-17 12:52:23 -0800
committerGravatar Linus Torvalds <torvalds@linux-foundation.org> 2020-12-17 12:52:23 -0800
commit6daa90439e91bb9a71864b02f7d0af8587ea889a (patch)
treecd747a40f9aac87089d3d73de9d42c5863fe7896 /drivers/dma/idxd/device.c
parentMerge tag 'mailbox-v5.11' of git://git.linaro.org/landing-teams/working/fujit... (diff)
parentsoc: ti: k3-ringacc: Use correct error casting in k3_ringacc_dmarings_init (diff)
downloadlinux-6daa90439e91bb9a71864b02f7d0af8587ea889a.tar.gz
linux-6daa90439e91bb9a71864b02f7d0af8587ea889a.tar.bz2
linux-6daa90439e91bb9a71864b02f7d0af8587ea889a.zip
Merge tag 'dmaengine-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul: "The last dmaengine updates for this year :) This contains couple of new drivers, new device support and updates to bunch of drivers. New drivers/devices: - Qualcomm ADM driver - Qualcomm GPI driver - Allwinner A100 DMA support - Microchip Sama7g5 support - Mediatek MT8516 apdma Updates: - more updates to idxd driver and support for IAX config - runtime PM support for dw driver - TI drivers" * tag 'dmaengine-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (75 commits) soc: ti: k3-ringacc: Use correct error casting in k3_ringacc_dmarings_init dmaengine: ti: k3-udma-glue: Add support for K3 PKTDMA dmaengine: ti: k3-udma: Initial support for K3 PKTDMA dmaengine: ti: k3-udma: Add support for BCDMA channel TPL handling dmaengine: ti: k3-udma: Initial support for K3 BCDMA soc: ti: k3-ringacc: add AM64 DMA rings support. dmaengine: ti: Add support for k3 event routers dmaengine: ti: k3-psil: Add initial map for AM64 dmaengine: ti: k3-psil: Extend psil_endpoint_config for K3 PKTDMA dt-bindings: dma: ti: Add document for K3 PKTDMA dt-bindings: dma: ti: Add document for K3 BCDMA dmaengine: dmatest: Use dmaengine_get_dma_device dmaengine: doc: client: Update for dmaengine_get_dma_device() usage dmaengine: Add support for per channel coherency handling dmaengine: of-dma: Add support for optional router configuration callback dmaengine: ti: k3-udma-glue: Configure the dma_dev for rings dmaengine: ti: k3-udma-glue: Get the ringacc from udma_dev dmaengine: ti: k3-udma-glue: Add function to get device pointer for DMA API dmaengine: ti: k3-udma: Add support for second resource range from sysfw dmaengine: ti: k3-udma: Wait for peer teardown completion if supported ...
Diffstat (limited to 'drivers/dma/idxd/device.c')
-rw-r--r--drivers/dma/idxd/device.c143
1 files changed, 120 insertions, 23 deletions
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 663344987e3f..95f94a3ed6be 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -131,6 +131,8 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq)
struct idxd_device *idxd = wq->idxd;
struct device *dev = &idxd->pdev->dev;
int rc, num_descs, i;
+ int align;
+ u64 tmp;
if (wq->type != IDXD_WQT_KERNEL)
return 0;
@@ -142,14 +144,27 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq)
if (rc < 0)
return rc;
- wq->compls_size = num_descs * sizeof(struct dsa_completion_record);
- wq->compls = dma_alloc_coherent(dev, wq->compls_size,
- &wq->compls_addr, GFP_KERNEL);
- if (!wq->compls) {
+ if (idxd->type == IDXD_TYPE_DSA)
+ align = 32;
+ else if (idxd->type == IDXD_TYPE_IAX)
+ align = 64;
+ else
+ return -ENODEV;
+
+ wq->compls_size = num_descs * idxd->compl_size + align;
+ wq->compls_raw = dma_alloc_coherent(dev, wq->compls_size,
+ &wq->compls_addr_raw, GFP_KERNEL);
+ if (!wq->compls_raw) {
rc = -ENOMEM;
goto fail_alloc_compls;
}
+ /* Adjust alignment */
+ wq->compls_addr = (wq->compls_addr_raw + (align - 1)) & ~(align - 1);
+ tmp = (u64)wq->compls_raw;
+ tmp = (tmp + (align - 1)) & ~(align - 1);
+ wq->compls = (struct dsa_completion_record *)tmp;
+
rc = alloc_descs(wq, num_descs);
if (rc < 0)
goto fail_alloc_descs;
@@ -163,9 +178,11 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq)
struct idxd_desc *desc = wq->descs[i];
desc->hw = wq->hw_descs[i];
- desc->completion = &wq->compls[i];
- desc->compl_dma = wq->compls_addr +
- sizeof(struct dsa_completion_record) * i;
+ if (idxd->type == IDXD_TYPE_DSA)
+ desc->completion = &wq->compls[i];
+ else if (idxd->type == IDXD_TYPE_IAX)
+ desc->iax_completion = &wq->iax_compls[i];
+ desc->compl_dma = wq->compls_addr + idxd->compl_size * i;
desc->id = i;
desc->wq = wq;
desc->cpu = -1;
@@ -178,7 +195,8 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq)
fail_sbitmap_init:
free_descs(wq);
fail_alloc_descs:
- dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
+ dma_free_coherent(dev, wq->compls_size, wq->compls_raw,
+ wq->compls_addr_raw);
fail_alloc_compls:
free_hw_descs(wq);
return rc;
@@ -193,7 +211,8 @@ void idxd_wq_free_resources(struct idxd_wq *wq)
free_hw_descs(wq);
free_descs(wq);
- dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
+ dma_free_coherent(dev, wq->compls_size, wq->compls_raw,
+ wq->compls_addr_raw);
sbitmap_queue_free(&wq->sbq);
}
@@ -273,10 +292,9 @@ int idxd_wq_map_portal(struct idxd_wq *wq)
start = pci_resource_start(pdev, IDXD_WQ_BAR);
start += idxd_get_wq_portal_full_offset(wq->id, IDXD_PORTAL_LIMITED);
- wq->dportal = devm_ioremap(dev, start, IDXD_PORTAL_SIZE);
- if (!wq->dportal)
+ wq->portal = devm_ioremap(dev, start, IDXD_PORTAL_SIZE);
+ if (!wq->portal)
return -ENOMEM;
- dev_dbg(dev, "wq %d portal mapped at %p\n", wq->id, wq->dportal);
return 0;
}
@@ -285,7 +303,61 @@ void idxd_wq_unmap_portal(struct idxd_wq *wq)
{
struct device *dev = &wq->idxd->pdev->dev;
- devm_iounmap(dev, wq->dportal);
+ devm_iounmap(dev, wq->portal);
+}
+
+int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid)
+{
+ struct idxd_device *idxd = wq->idxd;
+ int rc;
+ union wqcfg wqcfg;
+ unsigned int offset;
+ unsigned long flags;
+
+ rc = idxd_wq_disable(wq);
+ if (rc < 0)
+ return rc;
+
+ offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PASID_IDX);
+ spin_lock_irqsave(&idxd->dev_lock, flags);
+ wqcfg.bits[WQCFG_PASID_IDX] = ioread32(idxd->reg_base + offset);
+ wqcfg.pasid_en = 1;
+ wqcfg.pasid = pasid;
+ iowrite32(wqcfg.bits[WQCFG_PASID_IDX], idxd->reg_base + offset);
+ spin_unlock_irqrestore(&idxd->dev_lock, flags);
+
+ rc = idxd_wq_enable(wq);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+int idxd_wq_disable_pasid(struct idxd_wq *wq)
+{
+ struct idxd_device *idxd = wq->idxd;
+ int rc;
+ union wqcfg wqcfg;
+ unsigned int offset;
+ unsigned long flags;
+
+ rc = idxd_wq_disable(wq);
+ if (rc < 0)
+ return rc;
+
+ offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PASID_IDX);
+ spin_lock_irqsave(&idxd->dev_lock, flags);
+ wqcfg.bits[WQCFG_PASID_IDX] = ioread32(idxd->reg_base + offset);
+ wqcfg.pasid_en = 0;
+ wqcfg.pasid = 0;
+ iowrite32(wqcfg.bits[WQCFG_PASID_IDX], idxd->reg_base + offset);
+ spin_unlock_irqrestore(&idxd->dev_lock, flags);
+
+ rc = idxd_wq_enable(wq);
+ if (rc < 0)
+ return rc;
+
+ return 0;
}
void idxd_wq_disable_cleanup(struct idxd_wq *wq)
@@ -301,6 +373,7 @@ void idxd_wq_disable_cleanup(struct idxd_wq *wq)
wq->group = NULL;
wq->threshold = 0;
wq->priority = 0;
+ wq->ats_dis = 0;
clear_bit(WQ_FLAG_DEDICATED, &wq->flags);
memset(wq->name, 0, WQ_NAME_SIZE);
@@ -468,6 +541,17 @@ void idxd_device_reset(struct idxd_device *idxd)
spin_unlock_irqrestore(&idxd->dev_lock, flags);
}
+void idxd_device_drain_pasid(struct idxd_device *idxd, int pasid)
+{
+ struct device *dev = &idxd->pdev->dev;
+ u32 operand;
+
+ operand = pasid;
+ dev_dbg(dev, "cmd: %u operand: %#x\n", IDXD_CMD_DRAIN_PASID, operand);
+ idxd_cmd_exec(idxd, IDXD_CMD_DRAIN_PASID, operand, NULL);
+ dev_dbg(dev, "pasid %d drained\n", pasid);
+}
+
/* Device configuration bits */
static void idxd_group_config_write(struct idxd_group *group)
{
@@ -479,24 +563,22 @@ static void idxd_group_config_write(struct idxd_group *group)
dev_dbg(dev, "Writing group %d cfg registers\n", group->id);
/* setup GRPWQCFG */
- for (i = 0; i < 4; i++) {
- grpcfg_offset = idxd->grpcfg_offset +
- group->id * 64 + i * sizeof(u64);
- iowrite64(group->grpcfg.wqs[i],
- idxd->reg_base + grpcfg_offset);
+ for (i = 0; i < GRPWQCFG_STRIDES; i++) {
+ grpcfg_offset = GRPWQCFG_OFFSET(idxd, group->id, i);
+ iowrite64(group->grpcfg.wqs[i], idxd->reg_base + grpcfg_offset);
dev_dbg(dev, "GRPCFG wq[%d:%d: %#x]: %#llx\n",
group->id, i, grpcfg_offset,
ioread64(idxd->reg_base + grpcfg_offset));
}
/* setup GRPENGCFG */
- grpcfg_offset = idxd->grpcfg_offset + group->id * 64 + 32;
+ grpcfg_offset = GRPENGCFG_OFFSET(idxd, group->id);
iowrite64(group->grpcfg.engines, idxd->reg_base + grpcfg_offset);
dev_dbg(dev, "GRPCFG engs[%d: %#x]: %#llx\n", group->id,
grpcfg_offset, ioread64(idxd->reg_base + grpcfg_offset));
/* setup GRPFLAGS */
- grpcfg_offset = idxd->grpcfg_offset + group->id * 64 + 40;
+ grpcfg_offset = GRPFLGCFG_OFFSET(idxd, group->id);
iowrite32(group->grpcfg.flags.bits, idxd->reg_base + grpcfg_offset);
dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#x\n",
group->id, grpcfg_offset,
@@ -554,9 +636,24 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
/* byte 8-11 */
wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL);
- wq->wqcfg->mode = 1;
+ if (wq_dedicated(wq))
+ wq->wqcfg->mode = 1;
+
+ if (device_pasid_enabled(idxd)) {
+ wq->wqcfg->pasid_en = 1;
+ if (wq->type == IDXD_WQT_KERNEL && wq_dedicated(wq))
+ wq->wqcfg->pasid = idxd->pasid;
+ }
+
wq->wqcfg->priority = wq->priority;
+ if (idxd->hw.gen_cap.block_on_fault &&
+ test_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags))
+ wq->wqcfg->bof = 1;
+
+ if (idxd->hw.wq_cap.wq_ats_support)
+ wq->wqcfg->wq_ats_disable = wq->ats_dis;
+
/* bytes 12-15 */
wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes);
wq->wqcfg->max_batch_shift = ilog2(wq->max_batch_size);
@@ -664,8 +761,8 @@ static int idxd_wqs_setup(struct idxd_device *idxd)
if (!wq->size)
continue;
- if (!wq_dedicated(wq)) {
- dev_warn(dev, "No shared workqueue support.\n");
+ if (wq_shared(wq) && !device_swq_supported(idxd)) {
+ dev_warn(dev, "No shared wq support but configured.\n");
return -EINVAL;
}