[RFCv2 PATCH 01/36] iommu: Keep track of processes and PASIDs
From: Jean-Philippe Brucker <hidden>
Date: 2017-11-09 12:16:20
Also in:
linux-acpi, linux-devicetree, linux-iommu, linux-pci
Hi Bharat, On 11/08/2017 05:50 PM, Bharat Kumar Gogada wrote:
Hi Jean,
+static struct iommu_process *
+iommu_process_alloc(struct iommu_domain *domain, struct task_struct
+*task) {
+ int err;
+ int pasid;
+ struct iommu_process *process;
+
+ if (WARN_ON(!domain->ops->process_alloc ||
!domain->ops->process_free))
+ return ERR_PTR(-ENODEV);
+
+ process = domain->ops->process_alloc(task);
+ if (IS_ERR(process))
+ return process;
+ if (!process)
+ return ERR_PTR(-ENOMEM);
+
+ process->pid = get_task_pid(task, PIDTYPE_PID);
+ process->release = domain->ops->process_free;
+ INIT_LIST_HEAD(&process->domains);
+ kref_init(&process->kref);
+
+ if (!process->pid) {
+ err = -EINVAL;
+ goto err_free_process;
+ }
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&iommu_process_lock);
+ pasid = idr_alloc_cyclic(&iommu_process_idr, process,
domain->min_pasid,
+ domain->max_pasid + 1, GFP_ATOMIC);
If EP supports only one pasid; domain->min_pasid=1 and domain->max_pasid=0.
When idr_alloc_cyclic is called it invokes idr_get_free_cmn function
where we have following condition. (Based on kernel 4.14-rc6)
if (!radix_tree_tagged(root, IDR_FREE))
start = max(start, maxindex + 1);
if (start > max)
return ERR_PTR(-ENOSPC);
Here max is being assigned zero by the time this function is invoked,
this value is based on domain->max_pasid.
This condition fails and ENOSPC is returned.
In this case even though hardware supports PASID, BIND flow fails.It should fail, since we're reserving PASID 0 for non-PASID transactions with S1DSS=0b10. In addition, the SMMUv3 specification does not allow using PASID with a single entry. See the description of S1CDMax in 5.2 Stream Table Entry: "when this field is 0, the substreams of the STE are disabled and one CD is available. (The minimum useful number of substreams is 2.) Any transaction with a SubstreamID will be terminated with an abort and a C_BAD_SUBSTREAMID event recorded."
Any reason why pasid allocation moved to idr allocations rather than bitmap allocations as in v1 patches ?
Yes, idr provides a convenient way to quickly retrieve the context associated with a PASID, when handling a fault. v1 had the allocation in a bitmap and storing in a rb-tree. By using an idr we combine both and rely on a well-tested infrastructure. Note that in the future we might need to go back to handcrafting the PASID allocation, but it will probably still be based on idr. Thanks, Jean