Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: idxd: fix setting up priv mode for dwq

DSA spec says WQ priv bit is 0 if the Privileged Mode Enable field of the
PCI Express PASID capability is 0 and pasid is enabled. Make sure that the
WQCFG priv field is set correctly according to usage type. Reject config if
setting up kernel WQ type and no support. Also add the correct priv setup
for a descriptor.

Fixes: 484f910e93b4 ("dmaengine: idxd: fix wq config registers offset programming")
Cc: Ramesh Thomas <ramesh.thomas@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/162939084657.903168.14160019185148244596.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Dave Jiang and committed by
Vinod Koul
d8071323 aac6c0f9

+35 -2
+1
drivers/dma/Kconfig
··· 285 285 tristate "Intel Data Accelerators support" 286 286 depends on PCI && X86_64 && !UML 287 287 depends on PCI_MSI 288 + depends on PCI_PASID 288 289 depends on SBITMAP 289 290 select DMA_ENGINE 290 291 help
+28 -1
drivers/dma/idxd/device.c
··· 818 818 return 0; 819 819 } 820 820 821 + static bool idxd_device_pasid_priv_enabled(struct idxd_device *idxd) 822 + { 823 + struct pci_dev *pdev = idxd->pdev; 824 + 825 + if (pdev->pasid_enabled && (pdev->pasid_features & PCI_PASID_CAP_PRIV)) 826 + return true; 827 + return false; 828 + } 829 + 821 830 static int idxd_wq_config_write(struct idxd_wq *wq) 822 831 { 823 832 struct idxd_device *idxd = wq->idxd; ··· 859 850 wq->wqcfg->wq_thresh = wq->threshold; 860 851 861 852 /* byte 8-11 */ 862 - wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL); 863 853 if (wq_dedicated(wq)) 864 854 wq->wqcfg->mode = 1; 865 855 ··· 866 858 wq->wqcfg->pasid_en = 1; 867 859 if (wq->type == IDXD_WQT_KERNEL && wq_dedicated(wq)) 868 860 wq->wqcfg->pasid = idxd->pasid; 861 + } 862 + 863 + /* 864 + * Here the priv bit is set depending on the WQ type. priv = 1 if the 865 + * WQ type is kernel to indicate privileged access. This setting only 866 + * matters for dedicated WQ. According to the DSA spec: 867 + * If the WQ is in dedicated mode, WQ PASID Enable is 1, and the 868 + * Privileged Mode Enable field of the PCI Express PASID capability 869 + * is 0, this field must be 0. 870 + * 871 + * In the case of a dedicated kernel WQ that is not able to support 872 + * the PASID cap, then the configuration will be rejected. 873 + */ 874 + wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL); 875 + if (wq_dedicated(wq) && wq->wqcfg->pasid_en && 876 + !idxd_device_pasid_priv_enabled(idxd) && 877 + wq->type == IDXD_WQT_KERNEL) { 878 + idxd->cmd_status = IDXD_SCMD_WQ_NO_PRIV; 879 + return -EOPNOTSUPP; 869 880 } 870 881 871 882 wq->wqcfg->priority = wq->priority;
+5 -1
drivers/dma/idxd/dma.c
··· 69 69 hw->src_addr = addr_f1; 70 70 hw->dst_addr = addr_f2; 71 71 hw->xfer_size = len; 72 - hw->priv = !!(wq->type == IDXD_WQT_KERNEL); 72 + /* 73 + * For dedicated WQ, this field is ignored and HW will use the WQCFG.priv 74 + * field instead. This field should be set to 1 for kernel descriptors. 75 + */ 76 + hw->priv = 1; 73 77 hw->completion_addr = compl; 74 78 } 75 79
+1
include/uapi/linux/idxd.h
··· 27 27 IDXD_SCMD_WQ_NO_SWQ_SUPPORT = 0x800c0000, 28 28 IDXD_SCMD_WQ_NONE_CONFIGURED = 0x800d0000, 29 29 IDXD_SCMD_WQ_NO_SIZE = 0x800e0000, 30 + IDXD_SCMD_WQ_NO_PRIV = 0x800f0000, 30 31 }; 31 32 32 33 #define IDXD_SCMD_SOFTERR_MASK 0x80000000