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

iommufd: Extend IOMMU_GET_HW_INFO to report PASID capability

PASID usage requires PASID support in both device and IOMMU. Since the
iommu drivers always enable the PASID capability for the device if it
is supported, this extends the IOMMU_GET_HW_INFO to report the PASID
capability to userspace. Also, enhances the selftest accordingly.

Link: https://patch.msgid.link/r/20250321180143.8468-5-yi.l.liu@intel.com
Cc: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org> #aarch64 platform
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

authored by

Yi Liu and committed by
Jason Gunthorpe
803f9729 ad744ed5

+82 -2
+33 -1
drivers/iommu/iommufd/device.c
··· 3 3 */ 4 4 #include <linux/iommu.h> 5 5 #include <linux/iommufd.h> 6 + #include <linux/pci-ats.h> 6 7 #include <linux/slab.h> 7 8 #include <uapi/linux/iommufd.h> 8 9 ··· 1456 1455 void *data; 1457 1456 int rc; 1458 1457 1459 - if (cmd->flags || cmd->__reserved) 1458 + if (cmd->flags || cmd->__reserved[0] || cmd->__reserved[1] || 1459 + cmd->__reserved[2]) 1460 1460 return -EOPNOTSUPP; 1461 1461 1462 1462 idev = iommufd_get_device(ucmd, cmd->dev_id); ··· 1513 1511 cmd->out_capabilities = 0; 1514 1512 if (device_iommu_capable(idev->dev, IOMMU_CAP_DIRTY_TRACKING)) 1515 1513 cmd->out_capabilities |= IOMMU_HW_CAP_DIRTY_TRACKING; 1514 + 1515 + cmd->out_max_pasid_log2 = 0; 1516 + /* 1517 + * Currently, all iommu drivers enable PASID in the probe_device() 1518 + * op if iommu and device supports it. So the max_pasids stored in 1519 + * dev->iommu indicates both PASID support and enable status. A 1520 + * non-zero dev->iommu->max_pasids means PASID is supported and 1521 + * enabled. The iommufd only reports PASID capability to userspace 1522 + * if it's enabled. 1523 + */ 1524 + if (idev->dev->iommu->max_pasids) { 1525 + cmd->out_max_pasid_log2 = ilog2(idev->dev->iommu->max_pasids); 1526 + 1527 + if (dev_is_pci(idev->dev)) { 1528 + struct pci_dev *pdev = to_pci_dev(idev->dev); 1529 + int ctrl; 1530 + 1531 + ctrl = pci_pasid_status(pdev); 1532 + 1533 + WARN_ON_ONCE(ctrl < 0 || 1534 + !(ctrl & PCI_PASID_CTRL_ENABLE)); 1535 + 1536 + if (ctrl & PCI_PASID_CTRL_EXEC) 1537 + cmd->out_capabilities |= 1538 + IOMMU_HW_CAP_PCI_PASID_EXEC; 1539 + if (ctrl & PCI_PASID_CTRL_PRIV) 1540 + cmd->out_capabilities |= 1541 + IOMMU_HW_CAP_PCI_PASID_PRIV; 1542 + } 1543 + } 1516 1544 1517 1545 rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); 1518 1546 out_free:
+33
drivers/pci/ats.c
··· 538 538 return (1 << FIELD_GET(PCI_PASID_CAP_WIDTH, supported)); 539 539 } 540 540 EXPORT_SYMBOL_GPL(pci_max_pasids); 541 + 542 + /** 543 + * pci_pasid_status - Check the PASID status 544 + * @pdev: PCI device structure 545 + * 546 + * Returns a negative value when no PASID capability is present. 547 + * Otherwise the value of the control register is returned. 548 + * Status reported are: 549 + * 550 + * PCI_PASID_CTRL_ENABLE - PASID enabled 551 + * PCI_PASID_CTRL_EXEC - Execute permission enabled 552 + * PCI_PASID_CTRL_PRIV - Privileged mode enabled 553 + */ 554 + int pci_pasid_status(struct pci_dev *pdev) 555 + { 556 + int pasid; 557 + u16 ctrl; 558 + 559 + if (pdev->is_virtfn) 560 + pdev = pci_physfn(pdev); 561 + 562 + pasid = pdev->pasid_cap; 563 + if (!pasid) 564 + return -EINVAL; 565 + 566 + pci_read_config_word(pdev, pasid + PCI_PASID_CTRL, &ctrl); 567 + 568 + ctrl &= PCI_PASID_CTRL_ENABLE | PCI_PASID_CTRL_EXEC | 569 + PCI_PASID_CTRL_PRIV; 570 + 571 + return ctrl; 572 + } 573 + EXPORT_SYMBOL_GPL(pci_pasid_status); 541 574 #endif /* CONFIG_PCI_PASID */
+3
include/linux/pci-ats.h
··· 42 42 void pci_disable_pasid(struct pci_dev *pdev); 43 43 int pci_pasid_features(struct pci_dev *pdev); 44 44 int pci_max_pasids(struct pci_dev *pdev); 45 + int pci_pasid_status(struct pci_dev *pdev); 45 46 #else /* CONFIG_PCI_PASID */ 46 47 static inline int pci_enable_pasid(struct pci_dev *pdev, int features) 47 48 { return -EINVAL; } ··· 50 49 static inline int pci_pasid_features(struct pci_dev *pdev) 51 50 { return -EINVAL; } 52 51 static inline int pci_max_pasids(struct pci_dev *pdev) 52 + { return -EINVAL; } 53 + static inline int pci_pasid_status(struct pci_dev *pdev) 53 54 { return -EINVAL; } 54 55 #endif /* CONFIG_PCI_PASID */ 55 56
+13 -1
include/uapi/linux/iommufd.h
··· 612 612 * IOMMU_HWPT_GET_DIRTY_BITMAP 613 613 * IOMMU_HWPT_SET_DIRTY_TRACKING 614 614 * 615 + * @IOMMU_HW_CAP_PCI_PASID_EXEC: Execute Permission Supported, user ignores it 616 + * when the struct 617 + * iommu_hw_info::out_max_pasid_log2 is zero. 618 + * @IOMMU_HW_CAP_PCI_PASID_PRIV: Privileged Mode Supported, user ignores it 619 + * when the struct 620 + * iommu_hw_info::out_max_pasid_log2 is zero. 615 621 */ 616 622 enum iommufd_hw_capabilities { 617 623 IOMMU_HW_CAP_DIRTY_TRACKING = 1 << 0, 624 + IOMMU_HW_CAP_PCI_PASID_EXEC = 1 << 1, 625 + IOMMU_HW_CAP_PCI_PASID_PRIV = 1 << 2, 618 626 }; 619 627 620 628 /** ··· 638 630 * iommu_hw_info_type. 639 631 * @out_capabilities: Output the generic iommu capability info type as defined 640 632 * in the enum iommu_hw_capabilities. 633 + * @out_max_pasid_log2: Output the width of PASIDs. 0 means no PASID support. 634 + * PCI devices turn to out_capabilities to check if the 635 + * specific capabilities is supported or not. 641 636 * @__reserved: Must be 0 642 637 * 643 638 * Query an iommu type specific hardware information data from an iommu behind ··· 664 653 __u32 data_len; 665 654 __aligned_u64 data_uptr; 666 655 __u32 out_data_type; 667 - __u32 __reserved; 656 + __u8 out_max_pasid_log2; 657 + __u8 __reserved[3]; 668 658 __aligned_u64 out_capabilities; 669 659 }; 670 660 #define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO)