| @@ -891,7 +891,14 @@ EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier); · 890 unmodified lines |
| 891 | 891 | * @data: private data passed as argument to the handler |
| 892 | 892 | * |
| 893 | 893 | * When an IOMMU fault event is received, this handler gets called with the |
| 894 | | − * fault event and data as argument. The handler should return 0 on success. |
| 894 | + * fault event and data as argument. The handler should return 0 on success. If |
| 895 | + * the fault is recoverable (IOMMU_FAULT_PAGE_REQ), the consumer should also |
| 896 | + * complete the fault by calling iommu_page_response() with one of the following |
| 897 | + * response code: |
| 898 | + * - IOMMU_PAGE_RESP_SUCCESS: retry the translation |
| 899 | + * - IOMMU_PAGE_RESP_INVALID: terminate the fault |
| 900 | + * - IOMMU_PAGE_RESP_FAILURE: terminate the fault and stop reporting |
| 901 | + * page faults if possible. |
| 895 | 902 | * |
| 896 | 903 | * Return 0 if the fault handler was installed successfully, or an error. |
| 897 | 904 | */ |
| @@ -921,6 +928,8 @@ int iommu_register_device_fault_handler(struct device *dev, · 23 unmodified lines |
| 921 | 928 | } |
| 922 | 929 | param->fault_param->handler = handler; |
| 923 | 930 | param->fault_param->data = data; |
| 931 | + mutex_init(¶m->fault_param->lock); |
| 932 | + INIT_LIST_HEAD(¶m->fault_param->faults); |
| 924 | 933 | |
| 925 | 934 | done_unlock: |
| 926 | 935 | mutex_unlock(¶m->lock); |
| @@ -951,6 +960,12 @@ int iommu_unregister_device_fault_handler(struct device *dev) · 24 unmodified lines |
| 951 | 960 | if (!param->fault_param) |
| 952 | 961 | goto unlock; |
| 953 | 962 | |
| 963 | + /* we cannot unregister handler if there are pending faults */ |
| 964 | + if (!list_empty(¶m->fault_param->faults)) { |
| 965 | + ret = -EBUSY; |
| 966 | + goto unlock; |
| 967 | + } |
| 968 | + |
| 954 | 969 | kfree(param->fault_param); |
| 955 | 970 | param->fault_param = NULL; |
| 956 | 971 | put_device(dev); |
| @@ -967,13 +982,15 @@ EXPORT_SYMBOL_GPL(iommu_unregister_device_fault_handler); · 10 unmodified lines |
| 967 | 982 | * @evt: fault event data |
| 968 | 983 | * |
| 969 | 984 | * Called by IOMMU drivers when a fault is detected, typically in a threaded IRQ |
| 970 | | − * handler. |
| 985 | + * handler. When this function fails and the fault is recoverable, it is the |
| 986 | + * caller's responsibility to complete the fault. |
| 971 | 987 | * |
| 972 | 988 | * Return 0 on success, or an error. |
| 973 | 989 | */ |
| 974 | 990 | int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt) |
| 975 | 991 | { |
| 976 | 992 | struct iommu_param *param = dev->iommu_param; |
| 993 | + struct iommu_fault_event *evt_pending = NULL; |
| 977 | 994 | struct iommu_fault_param *fparam; |
| 978 | 995 | int ret = 0; |
| 979 | 996 | |
| @@ -987,13 +1004,86 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt) · 7 unmodified lines |
| 987 | 1004 | ret = -EINVAL; |
| 988 | 1005 | goto done_unlock; |
| 989 | 1006 | } |
| 1007 | + |
| 1008 | + if (evt->fault.type == IOMMU_FAULT_PAGE_REQ && |
| 1009 | + (evt->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE)) { |
| 1010 | + evt_pending = kmemdup(evt, sizeof(struct iommu_fault_event), |
| 1011 | + GFP_KERNEL); |
| 1012 | + if (!evt_pending) { |
| 1013 | + ret = -ENOMEM; |
| 1014 | + goto done_unlock; |
| 1015 | + } |
| 1016 | + mutex_lock(&fparam->lock); |
| 1017 | + list_add_tail(&evt_pending->list, &fparam->faults); |
| 1018 | + mutex_unlock(&fparam->lock); |
| 1019 | + } |
| 1020 | + |
| 990 | 1021 | ret = fparam->handler(&evt->fault, fparam->data); |
| 1022 | + if (ret && evt_pending) { |
| 1023 | + mutex_lock(&fparam->lock); |
| 1024 | + list_del(&evt_pending->list); |
| 1025 | + mutex_unlock(&fparam->lock); |
| 1026 | + kfree(evt_pending); |
| 1027 | + } |
| 991 | 1028 | done_unlock: |
| 992 | 1029 | mutex_unlock(¶m->lock); |
| 993 | 1030 | return ret; |
| 994 | 1031 | } |
| 995 | 1032 | EXPORT_SYMBOL_GPL(iommu_report_device_fault); |
| 996 | 1033 | |
| 1034 | +int iommu_page_response(struct device *dev, |
| 1035 | + struct iommu_page_response *msg) |
| 1036 | +{ |
| 1037 | + bool pasid_valid; |
| 1038 | + int ret = -EINVAL; |
| 1039 | + struct iommu_fault_event *evt; |
| 1040 | + struct iommu_fault_page_request *prm; |
| 1041 | + struct iommu_param *param = dev->iommu_param; |
| 1042 | + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); |
| 1043 | + |
| 1044 | + if (!domain || !domain->ops->page_response) |
| 1045 | + return -ENODEV; |
| 1046 | + |
| 1047 | + if (!param || !param->fault_param) |
| 1048 | + return -EINVAL; |
| 1049 | + |
| 1050 | + if (msg->version != IOMMU_PAGE_RESP_VERSION_1 || |
| 1051 | + msg->flags & ~IOMMU_PAGE_RESP_PASID_VALID) |
| 1052 | + return -EINVAL; |
| 1053 | + |
| 1054 | + /* Only send response if there is a fault report pending */ |
| 1055 | + mutex_lock(¶m->fault_param->lock); |
| 1056 | + if (list_empty(¶m->fault_param->faults)) { |
| 1057 | + dev_warn_ratelimited(dev, "no pending PRQ, drop response\n"); |
| 1058 | + goto done_unlock; |
| 1059 | + } |
| 1060 | + /* |
| 1061 | + * Check if we have a matching page request pending to respond, |
| 1062 | + * otherwise return -EINVAL |
| 1063 | + */ |
| 1064 | + list_for_each_entry(evt, ¶m->fault_param->faults, list) { |
| 1065 | + prm = &evt->fault.prm; |
| 1066 | + pasid_valid = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; |
| 1067 | + |
| 1068 | + if ((pasid_valid && prm->pasid != msg->pasid) || |
| 1069 | + prm->grpid != msg->grpid) |
| 1070 | + continue; |
| 1071 | + |
| 1072 | + /* Sanitize the reply */ |
| 1073 | + msg->flags = pasid_valid ? IOMMU_PAGE_RESP_PASID_VALID : 0; |
| 1074 | + |
| 1075 | + ret = domain->ops->page_response(dev, evt, msg); |
| 1076 | + list_del(&evt->list); |
| 1077 | + kfree(evt); |
| 1078 | + break; |
| 1079 | + } |
| 1080 | + |
| 1081 | +done_unlock: |
| 1082 | + mutex_unlock(¶m->fault_param->lock); |
| 1083 | + return ret; |
| 1084 | +} |
| 1085 | +EXPORT_SYMBOL_GPL(iommu_page_response); |
| 1086 | + |
| 997 | 1087 | /** |
| 998 | 1088 | * iommu_group_id - Return ID for a group |
| 999 | 1089 | * @group: the group to ID |