@@ -628,6 +628,15 @@ enum iommufd_hw_capabilities {
IOMMU_HW_CAP_PCI_PASID_PRIV = 1 << 2,
};
+/**
+ * enum iommufd_hw_info_flags - Flags for iommu_hw_info
+ * @IOMMU_HW_INFO_FLAG_INPUT_TYPE: If set, @data_type carries an input type for
+ * user space to request for a specific info
+ */
+enum iommufd_hw_info_flags {
+ IOMMU_HW_INFO_FLAG_INPUT_TYPE = 1 << 0,
+};
+
/**
* struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO)
* @size: sizeof(struct iommu_hw_info)
@@ -637,8 +646,11 @@ enum iommufd_hw_capabilities {
* data that kernel supports
* @data_uptr: User pointer to a user-space buffer used by the kernel to fill
* the iommu type specific hardware information data
- * @out_data_type: Output the iommu hardware info type as defined in the enum
- * iommu_hw_info_type.
+ * @data_type: Output the iommu hardware info type as defined in the enum
+ * iommu_hw_info_type. If IOMMU_HW_INFO_FLAG_INPUT_TYPE is set, an
+ * input type via @data_type will be valid, requesting for the info
+ * data to the given type. Otherwise, any input value carried via
+ * @data_type will be seen as IOMMU_HW_INFO_TYPE_DEFAULT
* @out_capabilities: Output the generic iommu capability info type as defined
* in the enum iommu_hw_capabilities.
* @out_max_pasid_log2: Output the width of PASIDs. 0 means no PASID support.
@@ -657,8 +669,8 @@ enum iommufd_hw_capabilities {
* user buffer is larger than the data that kernel has. Otherwise, kernel only
* fills the buffer using the given length in @data_len. If the ioctl succeeds,
* @data_len will be updated to the length that kernel actually supports,
- * @out_data_type will be filled to decode the data filled in the buffer
- * pointed by @data_uptr. Input @data_len == zero is allowed.
+ * @data_type will be filled to decode the data filled in the buffer pointed by
+ * @data_uptr. Input @data_len == zero is allowed.
*/
struct iommu_hw_info {
__u32 size;
@@ -666,7 +678,7 @@ struct iommu_hw_info {
__u32 dev_id;
__u32 data_len;
__aligned_u64 data_uptr;
- __u32 out_data_type;
+ __u32 data_type;
__u8 out_max_pasid_log2;
__u8 __reserved[3];
__aligned_u64 out_capabilities;
@@ -1352,6 +1352,7 @@ EXPORT_SYMBOL_NS_GPL(iommufd_access_rw, "IOMMUFD");
int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
{
+ const u32 SUPPORTED_FLAGS = IOMMU_HW_INFO_FLAG_INPUT_TYPE;
struct iommu_hw_info *cmd = ucmd->cmd;
void __user *user_ptr = u64_to_user_ptr(cmd->data_uptr);
const struct iommu_ops *ops;
@@ -1361,12 +1362,14 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
void *data;
int rc;
- if (cmd->flags || cmd->__reserved[0] || cmd->__reserved[1] ||
- cmd->__reserved[2])
+ if (cmd->flags & ~SUPPORTED_FLAGS)
+ return -EOPNOTSUPP;
+ if (cmd->__reserved[0] || cmd->__reserved[1] || cmd->__reserved[2])
return -EOPNOTSUPP;
/* Clear the type field since drivers don't support a random input */
- cmd->out_data_type = IOMMU_HW_INFO_TYPE_DEFAULT;
+ if (!(cmd->flags & IOMMU_HW_INFO_FLAG_INPUT_TYPE))
+ cmd->data_type = IOMMU_HW_INFO_TYPE_DEFAULT;
idev = iommufd_get_device(ucmd, cmd->dev_id);
if (IS_ERR(idev))
@@ -1374,7 +1377,7 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
ops = dev_iommu_ops(idev->dev);
if (ops->hw_info) {
- data = ops->hw_info(idev->dev, &data_len, &cmd->out_data_type);
+ data = ops->hw_info(idev->dev, &data_len, &cmd->data_type);
if (IS_ERR(data)) {
rc = PTR_ERR(data);
goto out_put;
@@ -1384,13 +1387,12 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
* drivers that have hw_info callback should have a unique
* iommu_hw_info_type.
*/
- if (WARN_ON_ONCE(cmd->out_data_type ==
- IOMMU_HW_INFO_TYPE_NONE)) {
+ if (WARN_ON_ONCE(cmd->data_type == IOMMU_HW_INFO_TYPE_NONE)) {
rc = -ENODEV;
goto out_free;
}
} else {
- cmd->out_data_type = IOMMU_HW_INFO_TYPE_NONE;
+ cmd->data_type = IOMMU_HW_INFO_TYPE_NONE;
data_len = 0;
data = NULL;
}
The iommu_hw_info can output via the out_data_type field the vendor data type from a driver, but this only allows driver to report one data type. Now, with SMMUv3 having a Tegra241 CMDQV implementation, it has two sets of types and data structs to report. One way to support that is to use the same type field bidirectionally. Rename "out_data_type" to simply "data_type", to allow an input for user space to request for a specific type and to get the corresponding data. For backward compatibility, since the ioctl handler has never checked an input value, add a new IOMMU_HW_INFO_FLAG_INPUT_TYPE to switch between the old output-only field and the new bidirectional field. Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> --- include/uapi/linux/iommufd.h | 22 +++++++++++++++++----- drivers/iommu/iommufd/device.c | 16 +++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-)