diff options
author | Shani Michaeli <shanim@mellanox.com> | 2013-02-06 11:19:13 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2013-02-21 14:59:09 -0500 |
commit | 6b52a12bc3fc39053b5bac4d4927ec8d974f8f60 (patch) | |
tree | ee722399af38f19b84773e87a519b1da3d2d6268 /drivers/infiniband | |
parent | 7083e42ee2ff43a11481e0e7211ec4f9ac68cb79 (diff) |
IB/uverbs: Implement memory windows support in uverbs
The existing user/kernel uverbs API has IB_USER_VERBS_CMD_ALLOC/DEALLOC_MW.
Implement these calls, along with destroying user memory windows during
process cleanup.
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Shani Michaeli <shanim@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/uverbs.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 121 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 13 |
3 files changed, 134 insertions, 2 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 5bcb2afd3dcb..0fcd7aa26fa2 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
@@ -188,6 +188,8 @@ IB_UVERBS_DECLARE_CMD(alloc_pd); | |||
188 | IB_UVERBS_DECLARE_CMD(dealloc_pd); | 188 | IB_UVERBS_DECLARE_CMD(dealloc_pd); |
189 | IB_UVERBS_DECLARE_CMD(reg_mr); | 189 | IB_UVERBS_DECLARE_CMD(reg_mr); |
190 | IB_UVERBS_DECLARE_CMD(dereg_mr); | 190 | IB_UVERBS_DECLARE_CMD(dereg_mr); |
191 | IB_UVERBS_DECLARE_CMD(alloc_mw); | ||
192 | IB_UVERBS_DECLARE_CMD(dealloc_mw); | ||
191 | IB_UVERBS_DECLARE_CMD(create_comp_channel); | 193 | IB_UVERBS_DECLARE_CMD(create_comp_channel); |
192 | IB_UVERBS_DECLARE_CMD(create_cq); | 194 | IB_UVERBS_DECLARE_CMD(create_cq); |
193 | IB_UVERBS_DECLARE_CMD(resize_cq); | 195 | IB_UVERBS_DECLARE_CMD(resize_cq); |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 0cb0007724a2..3983a0552775 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -48,6 +48,7 @@ struct uverbs_lock_class { | |||
48 | 48 | ||
49 | static struct uverbs_lock_class pd_lock_class = { .name = "PD-uobj" }; | 49 | static struct uverbs_lock_class pd_lock_class = { .name = "PD-uobj" }; |
50 | static struct uverbs_lock_class mr_lock_class = { .name = "MR-uobj" }; | 50 | static struct uverbs_lock_class mr_lock_class = { .name = "MR-uobj" }; |
51 | static struct uverbs_lock_class mw_lock_class = { .name = "MW-uobj" }; | ||
51 | static struct uverbs_lock_class cq_lock_class = { .name = "CQ-uobj" }; | 52 | static struct uverbs_lock_class cq_lock_class = { .name = "CQ-uobj" }; |
52 | static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" }; | 53 | static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" }; |
53 | static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" }; | 54 | static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" }; |
@@ -1049,6 +1050,126 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
1049 | return in_len; | 1050 | return in_len; |
1050 | } | 1051 | } |
1051 | 1052 | ||
1053 | ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file, | ||
1054 | const char __user *buf, int in_len, | ||
1055 | int out_len) | ||
1056 | { | ||
1057 | struct ib_uverbs_alloc_mw cmd; | ||
1058 | struct ib_uverbs_alloc_mw_resp resp; | ||
1059 | struct ib_uobject *uobj; | ||
1060 | struct ib_pd *pd; | ||
1061 | struct ib_mw *mw; | ||
1062 | int ret; | ||
1063 | |||
1064 | if (out_len < sizeof(resp)) | ||
1065 | return -ENOSPC; | ||
1066 | |||
1067 | if (copy_from_user(&cmd, buf, sizeof(cmd))) | ||
1068 | return -EFAULT; | ||
1069 | |||
1070 | uobj = kmalloc(sizeof(*uobj), GFP_KERNEL); | ||
1071 | if (!uobj) | ||
1072 | return -ENOMEM; | ||
1073 | |||
1074 | init_uobj(uobj, 0, file->ucontext, &mw_lock_class); | ||
1075 | down_write(&uobj->mutex); | ||
1076 | |||
1077 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); | ||
1078 | if (!pd) { | ||
1079 | ret = -EINVAL; | ||
1080 | goto err_free; | ||
1081 | } | ||
1082 | |||
1083 | mw = pd->device->alloc_mw(pd, cmd.mw_type); | ||
1084 | if (IS_ERR(mw)) { | ||
1085 | ret = PTR_ERR(mw); | ||
1086 | goto err_put; | ||
1087 | } | ||
1088 | |||
1089 | mw->device = pd->device; | ||
1090 | mw->pd = pd; | ||
1091 | mw->uobject = uobj; | ||
1092 | atomic_inc(&pd->usecnt); | ||
1093 | |||
1094 | uobj->object = mw; | ||
1095 | ret = idr_add_uobj(&ib_uverbs_mw_idr, uobj); | ||
1096 | if (ret) | ||
1097 | goto err_unalloc; | ||
1098 | |||
1099 | memset(&resp, 0, sizeof(resp)); | ||
1100 | resp.rkey = mw->rkey; | ||
1101 | resp.mw_handle = uobj->id; | ||
1102 | |||
1103 | if (copy_to_user((void __user *)(unsigned long)cmd.response, | ||
1104 | &resp, sizeof(resp))) { | ||
1105 | ret = -EFAULT; | ||
1106 | goto err_copy; | ||
1107 | } | ||
1108 | |||
1109 | put_pd_read(pd); | ||
1110 | |||
1111 | mutex_lock(&file->mutex); | ||
1112 | list_add_tail(&uobj->list, &file->ucontext->mw_list); | ||
1113 | mutex_unlock(&file->mutex); | ||
1114 | |||
1115 | uobj->live = 1; | ||
1116 | |||
1117 | up_write(&uobj->mutex); | ||
1118 | |||
1119 | return in_len; | ||
1120 | |||
1121 | err_copy: | ||
1122 | idr_remove_uobj(&ib_uverbs_mw_idr, uobj); | ||
1123 | |||
1124 | err_unalloc: | ||
1125 | ib_dealloc_mw(mw); | ||
1126 | |||
1127 | err_put: | ||
1128 | put_pd_read(pd); | ||
1129 | |||
1130 | err_free: | ||
1131 | put_uobj_write(uobj); | ||
1132 | return ret; | ||
1133 | } | ||
1134 | |||
1135 | ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file, | ||
1136 | const char __user *buf, int in_len, | ||
1137 | int out_len) | ||
1138 | { | ||
1139 | struct ib_uverbs_dealloc_mw cmd; | ||
1140 | struct ib_mw *mw; | ||
1141 | struct ib_uobject *uobj; | ||
1142 | int ret = -EINVAL; | ||
1143 | |||
1144 | if (copy_from_user(&cmd, buf, sizeof(cmd))) | ||
1145 | return -EFAULT; | ||
1146 | |||
1147 | uobj = idr_write_uobj(&ib_uverbs_mw_idr, cmd.mw_handle, file->ucontext); | ||
1148 | if (!uobj) | ||
1149 | return -EINVAL; | ||
1150 | |||
1151 | mw = uobj->object; | ||
1152 | |||
1153 | ret = ib_dealloc_mw(mw); | ||
1154 | if (!ret) | ||
1155 | uobj->live = 0; | ||
1156 | |||
1157 | put_uobj_write(uobj); | ||
1158 | |||
1159 | if (ret) | ||
1160 | return ret; | ||
1161 | |||
1162 | idr_remove_uobj(&ib_uverbs_mw_idr, uobj); | ||
1163 | |||
1164 | mutex_lock(&file->mutex); | ||
1165 | list_del(&uobj->list); | ||
1166 | mutex_unlock(&file->mutex); | ||
1167 | |||
1168 | put_uobj(uobj); | ||
1169 | |||
1170 | return in_len; | ||
1171 | } | ||
1172 | |||
1052 | ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, | 1173 | ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, |
1053 | const char __user *buf, int in_len, | 1174 | const char __user *buf, int in_len, |
1054 | int out_len) | 1175 | int out_len) |
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 6f2ce6fa98f8..2c6f0f2ecd9d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -87,6 +87,8 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, | |||
87 | [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, | 87 | [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, |
88 | [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, | 88 | [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, |
89 | [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, | 89 | [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, |
90 | [IB_USER_VERBS_CMD_ALLOC_MW] = ib_uverbs_alloc_mw, | ||
91 | [IB_USER_VERBS_CMD_DEALLOC_MW] = ib_uverbs_dealloc_mw, | ||
90 | [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, | 92 | [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, |
91 | [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, | 93 | [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, |
92 | [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq, | 94 | [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq, |
@@ -201,6 +203,15 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
201 | kfree(uobj); | 203 | kfree(uobj); |
202 | } | 204 | } |
203 | 205 | ||
206 | /* Remove MWs before QPs, in order to support type 2A MWs. */ | ||
207 | list_for_each_entry_safe(uobj, tmp, &context->mw_list, list) { | ||
208 | struct ib_mw *mw = uobj->object; | ||
209 | |||
210 | idr_remove_uobj(&ib_uverbs_mw_idr, uobj); | ||
211 | ib_dealloc_mw(mw); | ||
212 | kfree(uobj); | ||
213 | } | ||
214 | |||
204 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { | 215 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { |
205 | struct ib_qp *qp = uobj->object; | 216 | struct ib_qp *qp = uobj->object; |
206 | struct ib_uqp_object *uqp = | 217 | struct ib_uqp_object *uqp = |
@@ -240,8 +251,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
240 | kfree(uevent); | 251 | kfree(uevent); |
241 | } | 252 | } |
242 | 253 | ||
243 | /* XXX Free MWs */ | ||
244 | |||
245 | list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { | 254 | list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { |
246 | struct ib_mr *mr = uobj->object; | 255 | struct ib_mr *mr = uobj->object; |
247 | 256 | ||