Skip to content

Commit 8b73712

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Add page response ops support
After page requests are handled, software must respond to the device which raised the page request with the result. This is done through the iommu ops.page_response if the request was reported to outside of vendor iommu driver through iommu_report_device_fault(). This adds the VT-d implementation of page_response ops. Co-developed-by: Jacob Pan <[email protected]> Co-developed-by: Liu Yi L <[email protected]> Signed-off-by: Jacob Pan <[email protected]> Signed-off-by: Liu Yi L <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent eb8d93e commit 8b73712

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6067,6 +6067,7 @@ const struct iommu_ops intel_iommu_ops = {
60676067
.sva_bind = intel_svm_bind,
60686068
.sva_unbind = intel_svm_unbind,
60696069
.sva_get_pasid = intel_svm_get_pasid,
6070+
.page_response = intel_svm_page_response,
60706071
#endif
60716072
};
60726073

drivers/iommu/intel/svm.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,3 +1078,102 @@ int intel_svm_get_pasid(struct iommu_sva *sva)
10781078

10791079
return pasid;
10801080
}
1081+
1082+
int intel_svm_page_response(struct device *dev,
1083+
struct iommu_fault_event *evt,
1084+
struct iommu_page_response *msg)
1085+
{
1086+
struct iommu_fault_page_request *prm;
1087+
struct intel_svm_dev *sdev = NULL;
1088+
struct intel_svm *svm = NULL;
1089+
struct intel_iommu *iommu;
1090+
bool private_present;
1091+
bool pasid_present;
1092+
bool last_page;
1093+
u8 bus, devfn;
1094+
int ret = 0;
1095+
u16 sid;
1096+
1097+
if (!dev || !dev_is_pci(dev))
1098+
return -ENODEV;
1099+
1100+
iommu = device_to_iommu(dev, &bus, &devfn);
1101+
if (!iommu)
1102+
return -ENODEV;
1103+
1104+
if (!msg || !evt)
1105+
return -EINVAL;
1106+
1107+
mutex_lock(&pasid_mutex);
1108+
1109+
prm = &evt->fault.prm;
1110+
sid = PCI_DEVID(bus, devfn);
1111+
pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
1112+
private_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PRIV_DATA;
1113+
last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
1114+
1115+
if (!pasid_present) {
1116+
ret = -EINVAL;
1117+
goto out;
1118+
}
1119+
1120+
if (prm->pasid == 0 || prm->pasid >= PASID_MAX) {
1121+
ret = -EINVAL;
1122+
goto out;
1123+
}
1124+
1125+
ret = pasid_to_svm_sdev(dev, prm->pasid, &svm, &sdev);
1126+
if (ret || !sdev) {
1127+
ret = -ENODEV;
1128+
goto out;
1129+
}
1130+
1131+
/*
1132+
* For responses from userspace, need to make sure that the
1133+
* pasid has been bound to its mm.
1134+
*/
1135+
if (svm->flags & SVM_FLAG_GUEST_MODE) {
1136+
struct mm_struct *mm;
1137+
1138+
mm = get_task_mm(current);
1139+
if (!mm) {
1140+
ret = -EINVAL;
1141+
goto out;
1142+
}
1143+
1144+
if (mm != svm->mm) {
1145+
ret = -ENODEV;
1146+
mmput(mm);
1147+
goto out;
1148+
}
1149+
1150+
mmput(mm);
1151+
}
1152+
1153+
/*
1154+
* Per VT-d spec. v3.0 ch7.7, system software must respond
1155+
* with page group response if private data is present (PDP)
1156+
* or last page in group (LPIG) bit is set. This is an
1157+
* additional VT-d requirement beyond PCI ATS spec.
1158+
*/
1159+
if (last_page || private_present) {
1160+
struct qi_desc desc;
1161+
1162+
desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) |
1163+
QI_PGRP_PASID_P(pasid_present) |
1164+
QI_PGRP_PDP(private_present) |
1165+
QI_PGRP_RESP_CODE(msg->code) |
1166+
QI_PGRP_RESP_TYPE;
1167+
desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page);
1168+
desc.qw2 = 0;
1169+
desc.qw3 = 0;
1170+
if (private_present)
1171+
memcpy(&desc.qw2, prm->private_data,
1172+
sizeof(prm->private_data));
1173+
1174+
qi_submit_sync(iommu, &desc, 1, 0);
1175+
}
1176+
out:
1177+
mutex_unlock(&pasid_mutex);
1178+
return ret;
1179+
}

include/linux/intel-iommu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,9 @@ struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm,
740740
void *drvdata);
741741
void intel_svm_unbind(struct iommu_sva *handle);
742742
int intel_svm_get_pasid(struct iommu_sva *handle);
743+
int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
744+
struct iommu_page_response *msg);
745+
743746
struct svm_dev_ops;
744747

745748
struct intel_svm_dev {

0 commit comments

Comments
 (0)