diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/Kconfig | 25 | ||||
-rw-r--r-- | drivers/infiniband/core/Makefile | 5 | ||||
-rw-r--r-- | drivers/infiniband/core/cm.c | 5 | ||||
-rw-r--r-- | drivers/infiniband/core/mad_rmpp.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/core/sa_query.c | 30 | ||||
-rw-r--r-- | drivers/infiniband/core/ucm.c | 287 | ||||
-rw-r--r-- | drivers/infiniband/core/ucm.h | 11 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs.h | 26 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 155 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 98 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_qp.c | 45 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 |
12 files changed, 448 insertions, 245 deletions
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 32cdfb30e9b4..325d502e25cd 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig | |||
@@ -8,15 +8,26 @@ config INFINIBAND | |||
8 | any protocols you wish to use as well as drivers for your | 8 | any protocols you wish to use as well as drivers for your |
9 | InfiniBand hardware. | 9 | InfiniBand hardware. |
10 | 10 | ||
11 | config INFINIBAND_USER_VERBS | 11 | config INFINIBAND_USER_MAD |
12 | tristate "InfiniBand userspace verbs support" | 12 | tristate "InfiniBand userspace MAD support" |
13 | depends on INFINIBAND | 13 | depends on INFINIBAND |
14 | ---help--- | 14 | ---help--- |
15 | Userspace InfiniBand verbs support. This is the kernel side | 15 | Userspace InfiniBand Management Datagram (MAD) support. This |
16 | of userspace verbs, which allows userspace processes to | 16 | is the kernel side of the userspace MAD support, which allows |
17 | directly access InfiniBand hardware for fast-path | 17 | userspace processes to send and receive MADs. You will also |
18 | operations. You will also need libibverbs and a hardware | 18 | need libibumad from <http://www.openib.org>. |
19 | driver library from <http://www.openib.org>. | 19 | |
20 | config INFINIBAND_USER_ACCESS | ||
21 | tristate "InfiniBand userspace access (verbs and CM)" | ||
22 | depends on INFINIBAND | ||
23 | ---help--- | ||
24 | Userspace InfiniBand access support. This enables the | ||
25 | kernel side of userspace verbs and the userspace | ||
26 | communication manager (CM). This allows userspace processes | ||
27 | to set up connections and directly access InfiniBand | ||
28 | hardware for fast-path operations. You will also need | ||
29 | libibverbs, libibcm and a hardware driver library from | ||
30 | <http://www.openib.org>. | ||
20 | 31 | ||
21 | source "drivers/infiniband/hw/mthca/Kconfig" | 32 | source "drivers/infiniband/hw/mthca/Kconfig" |
22 | 33 | ||
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 678a7e097f32..ec3353f24b27 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ | 1 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ |
2 | ib_cm.o ib_umad.o ib_ucm.o | 2 | ib_cm.o |
3 | obj-$(CONFIG_INFINIBAND_USER_VERBS) += ib_uverbs.o | 3 | obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o |
4 | obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o | ||
4 | 5 | ||
5 | ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ | 6 | ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ |
6 | device.o fmr_pool.o cache.o | 7 | device.o fmr_pool.o cache.o |
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4de93ba274a6..54db6d4831f1 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -173,7 +173,8 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, | |||
173 | if (IS_ERR(ah)) | 173 | if (IS_ERR(ah)) |
174 | return PTR_ERR(ah); | 174 | return PTR_ERR(ah); |
175 | 175 | ||
176 | m = ib_create_send_mad(mad_agent, 1, cm_id_priv->av.pkey_index, | 176 | m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, |
177 | cm_id_priv->av.pkey_index, | ||
177 | ah, 0, sizeof(struct ib_mad_hdr), | 178 | ah, 0, sizeof(struct ib_mad_hdr), |
178 | sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), | 179 | sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), |
179 | GFP_ATOMIC); | 180 | GFP_ATOMIC); |
@@ -536,6 +537,7 @@ struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, | |||
536 | cm_id_priv->id.state = IB_CM_IDLE; | 537 | cm_id_priv->id.state = IB_CM_IDLE; |
537 | cm_id_priv->id.cm_handler = cm_handler; | 538 | cm_id_priv->id.cm_handler = cm_handler; |
538 | cm_id_priv->id.context = context; | 539 | cm_id_priv->id.context = context; |
540 | cm_id_priv->id.remote_cm_qpn = 1; | ||
539 | ret = cm_alloc_id(cm_id_priv); | 541 | ret = cm_alloc_id(cm_id_priv); |
540 | if (ret) | 542 | if (ret) |
541 | goto error; | 543 | goto error; |
@@ -1313,6 +1315,7 @@ error3: atomic_dec(&cm_id_priv->refcount); | |||
1313 | cm_deref_id(listen_cm_id_priv); | 1315 | cm_deref_id(listen_cm_id_priv); |
1314 | cm_cleanup_timewait(cm_id_priv->timewait_info); | 1316 | cm_cleanup_timewait(cm_id_priv->timewait_info); |
1315 | error2: kfree(cm_id_priv->timewait_info); | 1317 | error2: kfree(cm_id_priv->timewait_info); |
1318 | cm_id_priv->timewait_info = NULL; | ||
1316 | error1: ib_destroy_cm_id(&cm_id_priv->id); | 1319 | error1: ib_destroy_cm_id(&cm_id_priv->id); |
1317 | return ret; | 1320 | return ret; |
1318 | } | 1321 | } |
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index 43fd805e0265..2bd8b1cc57c4 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c | |||
@@ -593,7 +593,8 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) | |||
593 | rmpp_mad->rmpp_hdr.paylen_newwin = | 593 | rmpp_mad->rmpp_hdr.paylen_newwin = |
594 | cpu_to_be32(mad_send_wr->total_seg * | 594 | cpu_to_be32(mad_send_wr->total_seg * |
595 | (sizeof(struct ib_rmpp_mad) - | 595 | (sizeof(struct ib_rmpp_mad) - |
596 | offsetof(struct ib_rmpp_mad, data))); | 596 | offsetof(struct ib_rmpp_mad, data)) - |
597 | mad_send_wr->pad); | ||
597 | mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad); | 598 | mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad); |
598 | } else { | 599 | } else { |
599 | mad_send_wr->send_wr.num_sge = 2; | 600 | mad_send_wr->send_wr.num_sge = 2; |
@@ -602,6 +603,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) | |||
602 | mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) - | 603 | mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) - |
603 | mad_send_wr->data_offset; | 604 | mad_send_wr->data_offset; |
604 | mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey; | 605 | mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey; |
606 | rmpp_mad->rmpp_hdr.paylen_newwin = 0; | ||
605 | } | 607 | } |
606 | 608 | ||
607 | if (mad_send_wr->seg_num == mad_send_wr->total_seg) { | 609 | if (mad_send_wr->seg_num == mad_send_wr->total_seg) { |
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 126ac80db7b8..78de2dd1a4f2 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c | |||
@@ -113,32 +113,6 @@ static DEFINE_IDR(query_idr); | |||
113 | static spinlock_t tid_lock; | 113 | static spinlock_t tid_lock; |
114 | static u32 tid; | 114 | static u32 tid; |
115 | 115 | ||
116 | enum { | ||
117 | IB_SA_ATTR_CLASS_PORTINFO = 0x01, | ||
118 | IB_SA_ATTR_NOTICE = 0x02, | ||
119 | IB_SA_ATTR_INFORM_INFO = 0x03, | ||
120 | IB_SA_ATTR_NODE_REC = 0x11, | ||
121 | IB_SA_ATTR_PORT_INFO_REC = 0x12, | ||
122 | IB_SA_ATTR_SL2VL_REC = 0x13, | ||
123 | IB_SA_ATTR_SWITCH_REC = 0x14, | ||
124 | IB_SA_ATTR_LINEAR_FDB_REC = 0x15, | ||
125 | IB_SA_ATTR_RANDOM_FDB_REC = 0x16, | ||
126 | IB_SA_ATTR_MCAST_FDB_REC = 0x17, | ||
127 | IB_SA_ATTR_SM_INFO_REC = 0x18, | ||
128 | IB_SA_ATTR_LINK_REC = 0x20, | ||
129 | IB_SA_ATTR_GUID_INFO_REC = 0x30, | ||
130 | IB_SA_ATTR_SERVICE_REC = 0x31, | ||
131 | IB_SA_ATTR_PARTITION_REC = 0x33, | ||
132 | IB_SA_ATTR_RANGE_REC = 0x34, | ||
133 | IB_SA_ATTR_PATH_REC = 0x35, | ||
134 | IB_SA_ATTR_VL_ARB_REC = 0x36, | ||
135 | IB_SA_ATTR_MC_GROUP_REC = 0x37, | ||
136 | IB_SA_ATTR_MC_MEMBER_REC = 0x38, | ||
137 | IB_SA_ATTR_TRACE_REC = 0x39, | ||
138 | IB_SA_ATTR_MULTI_PATH_REC = 0x3a, | ||
139 | IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b | ||
140 | }; | ||
141 | |||
142 | #define PATH_REC_FIELD(field) \ | 116 | #define PATH_REC_FIELD(field) \ |
143 | .struct_offset_bytes = offsetof(struct ib_sa_path_rec, field), \ | 117 | .struct_offset_bytes = offsetof(struct ib_sa_path_rec, field), \ |
144 | .struct_size_bytes = sizeof ((struct ib_sa_path_rec *) 0)->field, \ | 118 | .struct_size_bytes = sizeof ((struct ib_sa_path_rec *) 0)->field, \ |
@@ -431,8 +405,8 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event | |||
431 | event->event == IB_EVENT_LID_CHANGE || | 405 | event->event == IB_EVENT_LID_CHANGE || |
432 | event->event == IB_EVENT_PKEY_CHANGE || | 406 | event->event == IB_EVENT_PKEY_CHANGE || |
433 | event->event == IB_EVENT_SM_CHANGE) { | 407 | event->event == IB_EVENT_SM_CHANGE) { |
434 | struct ib_sa_device *sa_dev = | 408 | struct ib_sa_device *sa_dev; |
435 | ib_get_client_data(event->device, &sa_client); | 409 | sa_dev = container_of(handler, typeof(*sa_dev), event_handler); |
436 | 410 | ||
437 | schedule_work(&sa_dev->port[event->element.port_num - | 411 | schedule_work(&sa_dev->port[event->element.port_num - |
438 | sa_dev->start_port].update_task); | 412 | sa_dev->start_port].update_task); |
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 79595826ccc7..d0f0b0a2edd3 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c | |||
@@ -72,7 +72,6 @@ enum { | |||
72 | 72 | ||
73 | static struct semaphore ctx_id_mutex; | 73 | static struct semaphore ctx_id_mutex; |
74 | static struct idr ctx_id_table; | 74 | static struct idr ctx_id_table; |
75 | static int ctx_id_rover = 0; | ||
76 | 75 | ||
77 | static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) | 76 | static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) |
78 | { | 77 | { |
@@ -97,33 +96,16 @@ static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) | |||
97 | wake_up(&ctx->wait); | 96 | wake_up(&ctx->wait); |
98 | } | 97 | } |
99 | 98 | ||
100 | static ssize_t ib_ucm_destroy_ctx(struct ib_ucm_file *file, int id) | 99 | static inline int ib_ucm_new_cm_id(int event) |
101 | { | 100 | { |
102 | struct ib_ucm_context *ctx; | 101 | return event == IB_CM_REQ_RECEIVED || event == IB_CM_SIDR_REQ_RECEIVED; |
103 | struct ib_ucm_event *uevent; | 102 | } |
104 | |||
105 | down(&ctx_id_mutex); | ||
106 | ctx = idr_find(&ctx_id_table, id); | ||
107 | if (!ctx) | ||
108 | ctx = ERR_PTR(-ENOENT); | ||
109 | else if (ctx->file != file) | ||
110 | ctx = ERR_PTR(-EINVAL); | ||
111 | else | ||
112 | idr_remove(&ctx_id_table, ctx->id); | ||
113 | up(&ctx_id_mutex); | ||
114 | |||
115 | if (IS_ERR(ctx)) | ||
116 | return PTR_ERR(ctx); | ||
117 | |||
118 | atomic_dec(&ctx->ref); | ||
119 | wait_event(ctx->wait, !atomic_read(&ctx->ref)); | ||
120 | 103 | ||
121 | /* No new events will be generated after destroying the cm_id. */ | 104 | static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx) |
122 | if (!IS_ERR(ctx->cm_id)) | 105 | { |
123 | ib_destroy_cm_id(ctx->cm_id); | 106 | struct ib_ucm_event *uevent; |
124 | 107 | ||
125 | /* Cleanup events not yet reported to the user. */ | 108 | down(&ctx->file->mutex); |
126 | down(&file->mutex); | ||
127 | list_del(&ctx->file_list); | 109 | list_del(&ctx->file_list); |
128 | while (!list_empty(&ctx->events)) { | 110 | while (!list_empty(&ctx->events)) { |
129 | 111 | ||
@@ -133,15 +115,12 @@ static ssize_t ib_ucm_destroy_ctx(struct ib_ucm_file *file, int id) | |||
133 | list_del(&uevent->ctx_list); | 115 | list_del(&uevent->ctx_list); |
134 | 116 | ||
135 | /* clear incoming connections. */ | 117 | /* clear incoming connections. */ |
136 | if (uevent->cm_id) | 118 | if (ib_ucm_new_cm_id(uevent->resp.event)) |
137 | ib_destroy_cm_id(uevent->cm_id); | 119 | ib_destroy_cm_id(uevent->cm_id); |
138 | 120 | ||
139 | kfree(uevent); | 121 | kfree(uevent); |
140 | } | 122 | } |
141 | up(&file->mutex); | 123 | up(&ctx->file->mutex); |
142 | |||
143 | kfree(ctx); | ||
144 | return 0; | ||
145 | } | 124 | } |
146 | 125 | ||
147 | static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) | 126 | static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) |
@@ -153,36 +132,31 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) | |||
153 | if (!ctx) | 132 | if (!ctx) |
154 | return NULL; | 133 | return NULL; |
155 | 134 | ||
135 | memset(ctx, 0, sizeof *ctx); | ||
156 | atomic_set(&ctx->ref, 1); | 136 | atomic_set(&ctx->ref, 1); |
157 | init_waitqueue_head(&ctx->wait); | 137 | init_waitqueue_head(&ctx->wait); |
158 | ctx->file = file; | 138 | ctx->file = file; |
159 | |||
160 | INIT_LIST_HEAD(&ctx->events); | 139 | INIT_LIST_HEAD(&ctx->events); |
161 | 140 | ||
162 | list_add_tail(&ctx->file_list, &file->ctxs); | 141 | do { |
163 | 142 | result = idr_pre_get(&ctx_id_table, GFP_KERNEL); | |
164 | ctx_id_rover = (ctx_id_rover + 1) & INT_MAX; | 143 | if (!result) |
165 | retry: | 144 | goto error; |
166 | result = idr_pre_get(&ctx_id_table, GFP_KERNEL); | ||
167 | if (!result) | ||
168 | goto error; | ||
169 | 145 | ||
170 | down(&ctx_id_mutex); | 146 | down(&ctx_id_mutex); |
171 | result = idr_get_new_above(&ctx_id_table, ctx, ctx_id_rover, &ctx->id); | 147 | result = idr_get_new(&ctx_id_table, ctx, &ctx->id); |
172 | up(&ctx_id_mutex); | 148 | up(&ctx_id_mutex); |
149 | } while (result == -EAGAIN); | ||
173 | 150 | ||
174 | if (result == -EAGAIN) | ||
175 | goto retry; | ||
176 | if (result) | 151 | if (result) |
177 | goto error; | 152 | goto error; |
178 | 153 | ||
154 | list_add_tail(&ctx->file_list, &file->ctxs); | ||
179 | ucm_dbg("Allocated CM ID <%d>\n", ctx->id); | 155 | ucm_dbg("Allocated CM ID <%d>\n", ctx->id); |
180 | |||
181 | return ctx; | 156 | return ctx; |
157 | |||
182 | error: | 158 | error: |
183 | list_del(&ctx->file_list); | ||
184 | kfree(ctx); | 159 | kfree(ctx); |
185 | |||
186 | return NULL; | 160 | return NULL; |
187 | } | 161 | } |
188 | /* | 162 | /* |
@@ -219,12 +193,9 @@ static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath, | |||
219 | kpath->packet_life_time_selector; | 193 | kpath->packet_life_time_selector; |
220 | } | 194 | } |
221 | 195 | ||
222 | static void ib_ucm_event_req_get(struct ib_ucm_context *ctx, | 196 | static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, |
223 | struct ib_ucm_req_event_resp *ureq, | ||
224 | struct ib_cm_req_event_param *kreq) | 197 | struct ib_cm_req_event_param *kreq) |
225 | { | 198 | { |
226 | ureq->listen_id = ctx->id; | ||
227 | |||
228 | ureq->remote_ca_guid = kreq->remote_ca_guid; | 199 | ureq->remote_ca_guid = kreq->remote_ca_guid; |
229 | ureq->remote_qkey = kreq->remote_qkey; | 200 | ureq->remote_qkey = kreq->remote_qkey; |
230 | ureq->remote_qpn = kreq->remote_qpn; | 201 | ureq->remote_qpn = kreq->remote_qpn; |
@@ -259,14 +230,6 @@ static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep, | |||
259 | urep->srq = krep->srq; | 230 | urep->srq = krep->srq; |
260 | } | 231 | } |
261 | 232 | ||
262 | static void ib_ucm_event_sidr_req_get(struct ib_ucm_context *ctx, | ||
263 | struct ib_ucm_sidr_req_event_resp *ureq, | ||
264 | struct ib_cm_sidr_req_event_param *kreq) | ||
265 | { | ||
266 | ureq->listen_id = ctx->id; | ||
267 | ureq->pkey = kreq->pkey; | ||
268 | } | ||
269 | |||
270 | static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep, | 233 | static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep, |
271 | struct ib_cm_sidr_rep_event_param *krep) | 234 | struct ib_cm_sidr_rep_event_param *krep) |
272 | { | 235 | { |
@@ -275,15 +238,14 @@ static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep, | |||
275 | urep->qpn = krep->qpn; | 238 | urep->qpn = krep->qpn; |
276 | }; | 239 | }; |
277 | 240 | ||
278 | static int ib_ucm_event_process(struct ib_ucm_context *ctx, | 241 | static int ib_ucm_event_process(struct ib_cm_event *evt, |
279 | struct ib_cm_event *evt, | ||
280 | struct ib_ucm_event *uvt) | 242 | struct ib_ucm_event *uvt) |
281 | { | 243 | { |
282 | void *info = NULL; | 244 | void *info = NULL; |
283 | 245 | ||
284 | switch (evt->event) { | 246 | switch (evt->event) { |
285 | case IB_CM_REQ_RECEIVED: | 247 | case IB_CM_REQ_RECEIVED: |
286 | ib_ucm_event_req_get(ctx, &uvt->resp.u.req_resp, | 248 | ib_ucm_event_req_get(&uvt->resp.u.req_resp, |
287 | &evt->param.req_rcvd); | 249 | &evt->param.req_rcvd); |
288 | uvt->data_len = IB_CM_REQ_PRIVATE_DATA_SIZE; | 250 | uvt->data_len = IB_CM_REQ_PRIVATE_DATA_SIZE; |
289 | uvt->resp.present = IB_UCM_PRES_PRIMARY; | 251 | uvt->resp.present = IB_UCM_PRES_PRIMARY; |
@@ -331,8 +293,8 @@ static int ib_ucm_event_process(struct ib_ucm_context *ctx, | |||
331 | info = evt->param.apr_rcvd.apr_info; | 293 | info = evt->param.apr_rcvd.apr_info; |
332 | break; | 294 | break; |
333 | case IB_CM_SIDR_REQ_RECEIVED: | 295 | case IB_CM_SIDR_REQ_RECEIVED: |
334 | ib_ucm_event_sidr_req_get(ctx, &uvt->resp.u.sidr_req_resp, | 296 | uvt->resp.u.sidr_req_resp.pkey = |
335 | &evt->param.sidr_req_rcvd); | 297 | evt->param.sidr_req_rcvd.pkey; |
336 | uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE; | 298 | uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE; |
337 | break; | 299 | break; |
338 | case IB_CM_SIDR_REP_RECEIVED: | 300 | case IB_CM_SIDR_REP_RECEIVED: |
@@ -378,31 +340,24 @@ static int ib_ucm_event_handler(struct ib_cm_id *cm_id, | |||
378 | struct ib_ucm_event *uevent; | 340 | struct ib_ucm_event *uevent; |
379 | struct ib_ucm_context *ctx; | 341 | struct ib_ucm_context *ctx; |
380 | int result = 0; | 342 | int result = 0; |
381 | int id; | ||
382 | 343 | ||
383 | ctx = cm_id->context; | 344 | ctx = cm_id->context; |
384 | 345 | ||
385 | if (event->event == IB_CM_REQ_RECEIVED || | ||
386 | event->event == IB_CM_SIDR_REQ_RECEIVED) | ||
387 | id = IB_UCM_CM_ID_INVALID; | ||
388 | else | ||
389 | id = ctx->id; | ||
390 | |||
391 | uevent = kmalloc(sizeof(*uevent), GFP_KERNEL); | 346 | uevent = kmalloc(sizeof(*uevent), GFP_KERNEL); |
392 | if (!uevent) | 347 | if (!uevent) |
393 | goto err1; | 348 | goto err1; |
394 | 349 | ||
395 | memset(uevent, 0, sizeof(*uevent)); | 350 | memset(uevent, 0, sizeof(*uevent)); |
396 | uevent->resp.id = id; | 351 | uevent->ctx = ctx; |
352 | uevent->cm_id = cm_id; | ||
353 | uevent->resp.uid = ctx->uid; | ||
354 | uevent->resp.id = ctx->id; | ||
397 | uevent->resp.event = event->event; | 355 | uevent->resp.event = event->event; |
398 | 356 | ||
399 | result = ib_ucm_event_process(ctx, event, uevent); | 357 | result = ib_ucm_event_process(event, uevent); |
400 | if (result) | 358 | if (result) |
401 | goto err2; | 359 | goto err2; |
402 | 360 | ||
403 | uevent->ctx = ctx; | ||
404 | uevent->cm_id = (id == IB_UCM_CM_ID_INVALID) ? cm_id : NULL; | ||
405 | |||
406 | down(&ctx->file->mutex); | 361 | down(&ctx->file->mutex); |
407 | list_add_tail(&uevent->file_list, &ctx->file->events); | 362 | list_add_tail(&uevent->file_list, &ctx->file->events); |
408 | list_add_tail(&uevent->ctx_list, &ctx->events); | 363 | list_add_tail(&uevent->ctx_list, &ctx->events); |
@@ -414,7 +369,7 @@ err2: | |||
414 | kfree(uevent); | 369 | kfree(uevent); |
415 | err1: | 370 | err1: |
416 | /* Destroy new cm_id's */ | 371 | /* Destroy new cm_id's */ |
417 | return (id == IB_UCM_CM_ID_INVALID); | 372 | return ib_ucm_new_cm_id(event->event); |
418 | } | 373 | } |
419 | 374 | ||
420 | static ssize_t ib_ucm_event(struct ib_ucm_file *file, | 375 | static ssize_t ib_ucm_event(struct ib_ucm_file *file, |
@@ -423,7 +378,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, | |||
423 | { | 378 | { |
424 | struct ib_ucm_context *ctx; | 379 | struct ib_ucm_context *ctx; |
425 | struct ib_ucm_event_get cmd; | 380 | struct ib_ucm_event_get cmd; |
426 | struct ib_ucm_event *uevent = NULL; | 381 | struct ib_ucm_event *uevent; |
427 | int result = 0; | 382 | int result = 0; |
428 | DEFINE_WAIT(wait); | 383 | DEFINE_WAIT(wait); |
429 | 384 | ||
@@ -436,7 +391,6 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, | |||
436 | * wait | 391 | * wait |
437 | */ | 392 | */ |
438 | down(&file->mutex); | 393 | down(&file->mutex); |
439 | |||
440 | while (list_empty(&file->events)) { | 394 | while (list_empty(&file->events)) { |
441 | 395 | ||
442 | if (file->filp->f_flags & O_NONBLOCK) { | 396 | if (file->filp->f_flags & O_NONBLOCK) { |
@@ -463,21 +417,18 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, | |||
463 | 417 | ||
464 | uevent = list_entry(file->events.next, struct ib_ucm_event, file_list); | 418 | uevent = list_entry(file->events.next, struct ib_ucm_event, file_list); |
465 | 419 | ||
466 | if (!uevent->cm_id) | 420 | if (ib_ucm_new_cm_id(uevent->resp.event)) { |
467 | goto user; | 421 | ctx = ib_ucm_ctx_alloc(file); |
422 | if (!ctx) { | ||
423 | result = -ENOMEM; | ||
424 | goto done; | ||
425 | } | ||
468 | 426 | ||
469 | ctx = ib_ucm_ctx_alloc(file); | 427 | ctx->cm_id = uevent->cm_id; |
470 | if (!ctx) { | 428 | ctx->cm_id->context = ctx; |
471 | result = -ENOMEM; | 429 | uevent->resp.id = ctx->id; |
472 | goto done; | ||
473 | } | 430 | } |
474 | 431 | ||
475 | ctx->cm_id = uevent->cm_id; | ||
476 | ctx->cm_id->context = ctx; | ||
477 | |||
478 | uevent->resp.id = ctx->id; | ||
479 | |||
480 | user: | ||
481 | if (copy_to_user((void __user *)(unsigned long)cmd.response, | 432 | if (copy_to_user((void __user *)(unsigned long)cmd.response, |
482 | &uevent->resp, sizeof(uevent->resp))) { | 433 | &uevent->resp, sizeof(uevent->resp))) { |
483 | result = -EFAULT; | 434 | result = -EFAULT; |
@@ -485,12 +436,10 @@ user: | |||
485 | } | 436 | } |
486 | 437 | ||
487 | if (uevent->data) { | 438 | if (uevent->data) { |
488 | |||
489 | if (cmd.data_len < uevent->data_len) { | 439 | if (cmd.data_len < uevent->data_len) { |
490 | result = -ENOMEM; | 440 | result = -ENOMEM; |
491 | goto done; | 441 | goto done; |
492 | } | 442 | } |
493 | |||
494 | if (copy_to_user((void __user *)(unsigned long)cmd.data, | 443 | if (copy_to_user((void __user *)(unsigned long)cmd.data, |
495 | uevent->data, uevent->data_len)) { | 444 | uevent->data, uevent->data_len)) { |
496 | result = -EFAULT; | 445 | result = -EFAULT; |
@@ -499,12 +448,10 @@ user: | |||
499 | } | 448 | } |
500 | 449 | ||
501 | if (uevent->info) { | 450 | if (uevent->info) { |
502 | |||
503 | if (cmd.info_len < uevent->info_len) { | 451 | if (cmd.info_len < uevent->info_len) { |
504 | result = -ENOMEM; | 452 | result = -ENOMEM; |
505 | goto done; | 453 | goto done; |
506 | } | 454 | } |
507 | |||
508 | if (copy_to_user((void __user *)(unsigned long)cmd.info, | 455 | if (copy_to_user((void __user *)(unsigned long)cmd.info, |
509 | uevent->info, uevent->info_len)) { | 456 | uevent->info, uevent->info_len)) { |
510 | result = -EFAULT; | 457 | result = -EFAULT; |
@@ -514,6 +461,7 @@ user: | |||
514 | 461 | ||
515 | list_del(&uevent->file_list); | 462 | list_del(&uevent->file_list); |
516 | list_del(&uevent->ctx_list); | 463 | list_del(&uevent->ctx_list); |
464 | uevent->ctx->events_reported++; | ||
517 | 465 | ||
518 | kfree(uevent->data); | 466 | kfree(uevent->data); |
519 | kfree(uevent->info); | 467 | kfree(uevent->info); |
@@ -545,6 +493,7 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, | |||
545 | if (!ctx) | 493 | if (!ctx) |
546 | return -ENOMEM; | 494 | return -ENOMEM; |
547 | 495 | ||
496 | ctx->uid = cmd.uid; | ||
548 | ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx); | 497 | ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx); |
549 | if (IS_ERR(ctx->cm_id)) { | 498 | if (IS_ERR(ctx->cm_id)) { |
550 | result = PTR_ERR(ctx->cm_id); | 499 | result = PTR_ERR(ctx->cm_id); |
@@ -561,7 +510,14 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, | |||
561 | return 0; | 510 | return 0; |
562 | 511 | ||
563 | err: | 512 | err: |
564 | ib_ucm_destroy_ctx(file, ctx->id); | 513 | down(&ctx_id_mutex); |
514 | idr_remove(&ctx_id_table, ctx->id); | ||
515 | up(&ctx_id_mutex); | ||
516 | |||
517 | if (!IS_ERR(ctx->cm_id)) | ||
518 | ib_destroy_cm_id(ctx->cm_id); | ||
519 | |||
520 | kfree(ctx); | ||
565 | return result; | 521 | return result; |
566 | } | 522 | } |
567 | 523 | ||
@@ -570,11 +526,44 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file, | |||
570 | int in_len, int out_len) | 526 | int in_len, int out_len) |
571 | { | 527 | { |
572 | struct ib_ucm_destroy_id cmd; | 528 | struct ib_ucm_destroy_id cmd; |
529 | struct ib_ucm_destroy_id_resp resp; | ||
530 | struct ib_ucm_context *ctx; | ||
531 | int result = 0; | ||
532 | |||
533 | if (out_len < sizeof(resp)) | ||
534 | return -ENOSPC; | ||
573 | 535 | ||
574 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) | 536 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) |
575 | return -EFAULT; | 537 | return -EFAULT; |
576 | 538 | ||
577 | return ib_ucm_destroy_ctx(file, cmd.id); | 539 | down(&ctx_id_mutex); |
540 | ctx = idr_find(&ctx_id_table, cmd.id); | ||
541 | if (!ctx) | ||
542 | ctx = ERR_PTR(-ENOENT); | ||
543 | else if (ctx->file != file) | ||
544 | ctx = ERR_PTR(-EINVAL); | ||
545 | else | ||
546 | idr_remove(&ctx_id_table, ctx->id); | ||
547 | up(&ctx_id_mutex); | ||
548 | |||
549 | if (IS_ERR(ctx)) | ||
550 | return PTR_ERR(ctx); | ||
551 | |||
552 | atomic_dec(&ctx->ref); | ||
553 | wait_event(ctx->wait, !atomic_read(&ctx->ref)); | ||
554 | |||
555 | /* No new events will be generated after destroying the cm_id. */ | ||
556 | ib_destroy_cm_id(ctx->cm_id); | ||
557 | /* Cleanup events not yet reported to the user. */ | ||
558 | ib_ucm_cleanup_events(ctx); | ||
559 | |||
560 | resp.events_reported = ctx->events_reported; | ||
561 | if (copy_to_user((void __user *)(unsigned long)cmd.response, | ||
562 | &resp, sizeof(resp))) | ||
563 | result = -EFAULT; | ||
564 | |||
565 | kfree(ctx); | ||
566 | return result; | ||
578 | } | 567 | } |
579 | 568 | ||
580 | static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, | 569 | static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, |
@@ -609,6 +598,98 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, | |||
609 | return result; | 598 | return result; |
610 | } | 599 | } |
611 | 600 | ||
601 | static void ib_ucm_copy_ah_attr(struct ib_ucm_ah_attr *dest_attr, | ||
602 | struct ib_ah_attr *src_attr) | ||
603 | { | ||
604 | memcpy(dest_attr->grh_dgid, src_attr->grh.dgid.raw, | ||
605 | sizeof src_attr->grh.dgid); | ||
606 | dest_attr->grh_flow_label = src_attr->grh.flow_label; | ||
607 | dest_attr->grh_sgid_index = src_attr->grh.sgid_index; | ||
608 | dest_attr->grh_hop_limit = src_attr->grh.hop_limit; | ||
609 | dest_attr->grh_traffic_class = src_attr->grh.traffic_class; | ||
610 | |||
611 | dest_attr->dlid = src_attr->dlid; | ||
612 | dest_attr->sl = src_attr->sl; | ||
613 | dest_attr->src_path_bits = src_attr->src_path_bits; | ||
614 | dest_attr->static_rate = src_attr->static_rate; | ||
615 | dest_attr->is_global = (src_attr->ah_flags & IB_AH_GRH); | ||
616 | dest_attr->port_num = src_attr->port_num; | ||
617 | } | ||
618 | |||
619 | static void ib_ucm_copy_qp_attr(struct ib_ucm_init_qp_attr_resp *dest_attr, | ||
620 | struct ib_qp_attr *src_attr) | ||
621 | { | ||
622 | dest_attr->cur_qp_state = src_attr->cur_qp_state; | ||
623 | dest_attr->path_mtu = src_attr->path_mtu; | ||
624 | dest_attr->path_mig_state = src_attr->path_mig_state; | ||
625 | dest_attr->qkey = src_attr->qkey; | ||
626 | dest_attr->rq_psn = src_attr->rq_psn; | ||
627 | dest_attr->sq_psn = src_attr->sq_psn; | ||
628 | dest_attr->dest_qp_num = src_attr->dest_qp_num; | ||
629 | dest_attr->qp_access_flags = src_attr->qp_access_flags; | ||
630 | |||
631 | dest_attr->max_send_wr = src_attr->cap.max_send_wr; | ||
632 | dest_attr->max_recv_wr = src_attr->cap.max_recv_wr; | ||
633 | dest_attr->max_send_sge = src_attr->cap.max_send_sge; | ||
634 | dest_attr->max_recv_sge = src_attr->cap.max_recv_sge; | ||
635 | dest_attr->max_inline_data = src_attr->cap.max_inline_data; | ||
636 | |||
637 | ib_ucm_copy_ah_attr(&dest_attr->ah_attr, &src_attr->ah_attr); | ||
638 | ib_ucm_copy_ah_attr(&dest_attr->alt_ah_attr, &src_attr->alt_ah_attr); | ||
639 | |||
640 | dest_attr->pkey_index = src_attr->pkey_index; | ||
641 | dest_attr->alt_pkey_index = src_attr->alt_pkey_index; | ||
642 | dest_attr->en_sqd_async_notify = src_attr->en_sqd_async_notify; | ||
643 | dest_attr->sq_draining = src_attr->sq_draining; | ||
644 | dest_attr->max_rd_atomic = src_attr->max_rd_atomic; | ||
645 | dest_attr->max_dest_rd_atomic = src_attr->max_dest_rd_atomic; | ||
646 | dest_attr->min_rnr_timer = src_attr->min_rnr_timer; | ||
647 | dest_attr->port_num = src_attr->port_num; | ||
648 | dest_attr->timeout = src_attr->timeout; | ||
649 | dest_attr->retry_cnt = src_attr->retry_cnt; | ||
650 | dest_attr->rnr_retry = src_attr->rnr_retry; | ||
651 | dest_attr->alt_port_num = src_attr->alt_port_num; | ||
652 | dest_attr->alt_timeout = src_attr->alt_timeout; | ||
653 | } | ||
654 | |||
655 | static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, | ||
656 | const char __user *inbuf, | ||
657 | int in_len, int out_len) | ||
658 | { | ||
659 | struct ib_ucm_init_qp_attr_resp resp; | ||
660 | struct ib_ucm_init_qp_attr cmd; | ||
661 | struct ib_ucm_context *ctx; | ||
662 | struct ib_qp_attr qp_attr; | ||
663 | int result = 0; | ||
664 | |||
665 | if (out_len < sizeof(resp)) | ||
666 | return -ENOSPC; | ||
667 | |||
668 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) | ||
669 | return -EFAULT; | ||
670 | |||
671 | ctx = ib_ucm_ctx_get(file, cmd.id); | ||
672 | if (IS_ERR(ctx)) | ||
673 | return PTR_ERR(ctx); | ||
674 | |||
675 | resp.qp_attr_mask = 0; | ||
676 | memset(&qp_attr, 0, sizeof qp_attr); | ||
677 | qp_attr.qp_state = cmd.qp_state; | ||
678 | result = ib_cm_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask); | ||
679 | if (result) | ||
680 | goto out; | ||
681 | |||
682 | ib_ucm_copy_qp_attr(&resp, &qp_attr); | ||
683 | |||
684 | if (copy_to_user((void __user *)(unsigned long)cmd.response, | ||
685 | &resp, sizeof(resp))) | ||
686 | result = -EFAULT; | ||
687 | |||
688 | out: | ||
689 | ib_ucm_ctx_put(ctx); | ||
690 | return result; | ||
691 | } | ||
692 | |||
612 | static ssize_t ib_ucm_listen(struct ib_ucm_file *file, | 693 | static ssize_t ib_ucm_listen(struct ib_ucm_file *file, |
613 | const char __user *inbuf, | 694 | const char __user *inbuf, |
614 | int in_len, int out_len) | 695 | int in_len, int out_len) |
@@ -808,6 +889,7 @@ static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file, | |||
808 | 889 | ||
809 | ctx = ib_ucm_ctx_get(file, cmd.id); | 890 | ctx = ib_ucm_ctx_get(file, cmd.id); |
810 | if (!IS_ERR(ctx)) { | 891 | if (!IS_ERR(ctx)) { |
892 | ctx->uid = cmd.uid; | ||
811 | result = ib_send_cm_rep(ctx->cm_id, ¶m); | 893 | result = ib_send_cm_rep(ctx->cm_id, ¶m); |
812 | ib_ucm_ctx_put(ctx); | 894 | ib_ucm_ctx_put(ctx); |
813 | } else | 895 | } else |
@@ -1086,6 +1168,7 @@ static ssize_t (*ucm_cmd_table[])(struct ib_ucm_file *file, | |||
1086 | [IB_USER_CM_CMD_SEND_SIDR_REQ] = ib_ucm_send_sidr_req, | 1168 | [IB_USER_CM_CMD_SEND_SIDR_REQ] = ib_ucm_send_sidr_req, |
1087 | [IB_USER_CM_CMD_SEND_SIDR_REP] = ib_ucm_send_sidr_rep, | 1169 | [IB_USER_CM_CMD_SEND_SIDR_REP] = ib_ucm_send_sidr_rep, |
1088 | [IB_USER_CM_CMD_EVENT] = ib_ucm_event, | 1170 | [IB_USER_CM_CMD_EVENT] = ib_ucm_event, |
1171 | [IB_USER_CM_CMD_INIT_QP_ATTR] = ib_ucm_init_qp_attr, | ||
1089 | }; | 1172 | }; |
1090 | 1173 | ||
1091 | static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, | 1174 | static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, |
@@ -1161,12 +1244,18 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) | |||
1161 | 1244 | ||
1162 | down(&file->mutex); | 1245 | down(&file->mutex); |
1163 | while (!list_empty(&file->ctxs)) { | 1246 | while (!list_empty(&file->ctxs)) { |
1164 | |||
1165 | ctx = list_entry(file->ctxs.next, | 1247 | ctx = list_entry(file->ctxs.next, |
1166 | struct ib_ucm_context, file_list); | 1248 | struct ib_ucm_context, file_list); |
1167 | |||
1168 | up(&file->mutex); | 1249 | up(&file->mutex); |
1169 | ib_ucm_destroy_ctx(file, ctx->id); | 1250 | |
1251 | down(&ctx_id_mutex); | ||
1252 | idr_remove(&ctx_id_table, ctx->id); | ||
1253 | up(&ctx_id_mutex); | ||
1254 | |||
1255 | ib_destroy_cm_id(ctx->cm_id); | ||
1256 | ib_ucm_cleanup_events(ctx); | ||
1257 | kfree(ctx); | ||
1258 | |||
1170 | down(&file->mutex); | 1259 | down(&file->mutex); |
1171 | } | 1260 | } |
1172 | up(&file->mutex); | 1261 | up(&file->mutex); |
diff --git a/drivers/infiniband/core/ucm.h b/drivers/infiniband/core/ucm.h index c8819b928a1b..f46f37bc1201 100644 --- a/drivers/infiniband/core/ucm.h +++ b/drivers/infiniband/core/ucm.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2005 Topspin Communications. All rights reserved. |
3 | * Copyright (c) 2005 Intel Corporation. All rights reserved. | ||
3 | * | 4 | * |
4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
@@ -43,8 +44,6 @@ | |||
43 | #include <rdma/ib_cm.h> | 44 | #include <rdma/ib_cm.h> |
44 | #include <rdma/ib_user_cm.h> | 45 | #include <rdma/ib_user_cm.h> |
45 | 46 | ||
46 | #define IB_UCM_CM_ID_INVALID 0xffffffff | ||
47 | |||
48 | struct ib_ucm_file { | 47 | struct ib_ucm_file { |
49 | struct semaphore mutex; | 48 | struct semaphore mutex; |
50 | struct file *filp; | 49 | struct file *filp; |
@@ -58,9 +57,11 @@ struct ib_ucm_context { | |||
58 | int id; | 57 | int id; |
59 | wait_queue_head_t wait; | 58 | wait_queue_head_t wait; |
60 | atomic_t ref; | 59 | atomic_t ref; |
60 | int events_reported; | ||
61 | 61 | ||
62 | struct ib_ucm_file *file; | 62 | struct ib_ucm_file *file; |
63 | struct ib_cm_id *cm_id; | 63 | struct ib_cm_id *cm_id; |
64 | __u64 uid; | ||
64 | 65 | ||
65 | struct list_head events; /* list of pending events. */ | 66 | struct list_head events; /* list of pending events. */ |
66 | struct list_head file_list; /* member in file ctx list */ | 67 | struct list_head file_list; /* member in file ctx list */ |
@@ -71,16 +72,12 @@ struct ib_ucm_event { | |||
71 | struct list_head file_list; /* member in file event list */ | 72 | struct list_head file_list; /* member in file event list */ |
72 | struct list_head ctx_list; /* member in ctx event list */ | 73 | struct list_head ctx_list; /* member in ctx event list */ |
73 | 74 | ||
75 | struct ib_cm_id *cm_id; | ||
74 | struct ib_ucm_event_resp resp; | 76 | struct ib_ucm_event_resp resp; |
75 | void *data; | 77 | void *data; |
76 | void *info; | 78 | void *info; |
77 | int data_len; | 79 | int data_len; |
78 | int info_len; | 80 | int info_len; |
79 | /* | ||
80 | * new connection identifiers needs to be saved until | ||
81 | * userspace can get a handle on them. | ||
82 | */ | ||
83 | struct ib_cm_id *cm_id; | ||
84 | }; | 81 | }; |
85 | 82 | ||
86 | #endif /* UCM_H */ | 83 | #endif /* UCM_H */ |
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 180b3d4765e4..b1897bed14ad 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
@@ -76,20 +76,28 @@ struct ib_uverbs_file { | |||
76 | struct ib_uverbs_event_file comp_file[1]; | 76 | struct ib_uverbs_event_file comp_file[1]; |
77 | }; | 77 | }; |
78 | 78 | ||
79 | struct ib_uverbs_async_event { | 79 | struct ib_uverbs_event { |
80 | struct ib_uverbs_async_event_desc desc; | 80 | union { |
81 | struct ib_uverbs_async_event_desc async; | ||
82 | struct ib_uverbs_comp_event_desc comp; | ||
83 | } desc; | ||
81 | struct list_head list; | 84 | struct list_head list; |
85 | struct list_head obj_list; | ||
86 | u32 *counter; | ||
82 | }; | 87 | }; |
83 | 88 | ||
84 | struct ib_uverbs_comp_event { | 89 | struct ib_uevent_object { |
85 | struct ib_uverbs_comp_event_desc desc; | 90 | struct ib_uobject uobject; |
86 | struct list_head list; | 91 | struct list_head event_list; |
92 | u32 events_reported; | ||
87 | }; | 93 | }; |
88 | 94 | ||
89 | struct ib_uobject_mr { | 95 | struct ib_ucq_object { |
90 | struct ib_uobject uobj; | 96 | struct ib_uobject uobject; |
91 | struct page *page_list; | 97 | struct list_head comp_list; |
92 | struct scatterlist *sg_list; | 98 | struct list_head async_list; |
99 | u32 comp_events_reported; | ||
100 | u32 async_events_reported; | ||
93 | }; | 101 | }; |
94 | 102 | ||
95 | extern struct semaphore ib_uverbs_idr_mutex; | 103 | extern struct semaphore ib_uverbs_idr_mutex; |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index ebccf9f38af9..e91ebde46481 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -590,7 +590,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
590 | struct ib_uverbs_create_cq cmd; | 590 | struct ib_uverbs_create_cq cmd; |
591 | struct ib_uverbs_create_cq_resp resp; | 591 | struct ib_uverbs_create_cq_resp resp; |
592 | struct ib_udata udata; | 592 | struct ib_udata udata; |
593 | struct ib_uobject *uobj; | 593 | struct ib_ucq_object *uobj; |
594 | struct ib_cq *cq; | 594 | struct ib_cq *cq; |
595 | int ret; | 595 | int ret; |
596 | 596 | ||
@@ -611,8 +611,12 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
611 | if (!uobj) | 611 | if (!uobj) |
612 | return -ENOMEM; | 612 | return -ENOMEM; |
613 | 613 | ||
614 | uobj->user_handle = cmd.user_handle; | 614 | uobj->uobject.user_handle = cmd.user_handle; |
615 | uobj->context = file->ucontext; | 615 | uobj->uobject.context = file->ucontext; |
616 | uobj->comp_events_reported = 0; | ||
617 | uobj->async_events_reported = 0; | ||
618 | INIT_LIST_HEAD(&uobj->comp_list); | ||
619 | INIT_LIST_HEAD(&uobj->async_list); | ||
616 | 620 | ||
617 | cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, | 621 | cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, |
618 | file->ucontext, &udata); | 622 | file->ucontext, &udata); |
@@ -622,7 +626,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
622 | } | 626 | } |
623 | 627 | ||
624 | cq->device = file->device->ib_dev; | 628 | cq->device = file->device->ib_dev; |
625 | cq->uobject = uobj; | 629 | cq->uobject = &uobj->uobject; |
626 | cq->comp_handler = ib_uverbs_comp_handler; | 630 | cq->comp_handler = ib_uverbs_comp_handler; |
627 | cq->event_handler = ib_uverbs_cq_event_handler; | 631 | cq->event_handler = ib_uverbs_cq_event_handler; |
628 | cq->cq_context = file; | 632 | cq->cq_context = file; |
@@ -635,7 +639,7 @@ retry: | |||
635 | } | 639 | } |
636 | 640 | ||
637 | down(&ib_uverbs_idr_mutex); | 641 | down(&ib_uverbs_idr_mutex); |
638 | ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id); | 642 | ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id); |
639 | up(&ib_uverbs_idr_mutex); | 643 | up(&ib_uverbs_idr_mutex); |
640 | 644 | ||
641 | if (ret == -EAGAIN) | 645 | if (ret == -EAGAIN) |
@@ -644,11 +648,11 @@ retry: | |||
644 | goto err_cq; | 648 | goto err_cq; |
645 | 649 | ||
646 | spin_lock_irq(&file->ucontext->lock); | 650 | spin_lock_irq(&file->ucontext->lock); |
647 | list_add_tail(&uobj->list, &file->ucontext->cq_list); | 651 | list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); |
648 | spin_unlock_irq(&file->ucontext->lock); | 652 | spin_unlock_irq(&file->ucontext->lock); |
649 | 653 | ||
650 | memset(&resp, 0, sizeof resp); | 654 | memset(&resp, 0, sizeof resp); |
651 | resp.cq_handle = uobj->id; | 655 | resp.cq_handle = uobj->uobject.id; |
652 | resp.cqe = cq->cqe; | 656 | resp.cqe = cq->cqe; |
653 | 657 | ||
654 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 658 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
@@ -661,11 +665,11 @@ retry: | |||
661 | 665 | ||
662 | err_list: | 666 | err_list: |
663 | spin_lock_irq(&file->ucontext->lock); | 667 | spin_lock_irq(&file->ucontext->lock); |
664 | list_del(&uobj->list); | 668 | list_del(&uobj->uobject.list); |
665 | spin_unlock_irq(&file->ucontext->lock); | 669 | spin_unlock_irq(&file->ucontext->lock); |
666 | 670 | ||
667 | down(&ib_uverbs_idr_mutex); | 671 | down(&ib_uverbs_idr_mutex); |
668 | idr_remove(&ib_uverbs_cq_idr, uobj->id); | 672 | idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); |
669 | up(&ib_uverbs_idr_mutex); | 673 | up(&ib_uverbs_idr_mutex); |
670 | 674 | ||
671 | err_cq: | 675 | err_cq: |
@@ -680,21 +684,27 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
680 | const char __user *buf, int in_len, | 684 | const char __user *buf, int in_len, |
681 | int out_len) | 685 | int out_len) |
682 | { | 686 | { |
683 | struct ib_uverbs_destroy_cq cmd; | 687 | struct ib_uverbs_destroy_cq cmd; |
684 | struct ib_cq *cq; | 688 | struct ib_uverbs_destroy_cq_resp resp; |
685 | struct ib_uobject *uobj; | 689 | struct ib_cq *cq; |
686 | int ret = -EINVAL; | 690 | struct ib_ucq_object *uobj; |
691 | struct ib_uverbs_event *evt, *tmp; | ||
692 | u64 user_handle; | ||
693 | int ret = -EINVAL; | ||
687 | 694 | ||
688 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 695 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
689 | return -EFAULT; | 696 | return -EFAULT; |
690 | 697 | ||
698 | memset(&resp, 0, sizeof resp); | ||
699 | |||
691 | down(&ib_uverbs_idr_mutex); | 700 | down(&ib_uverbs_idr_mutex); |
692 | 701 | ||
693 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | 702 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); |
694 | if (!cq || cq->uobject->context != file->ucontext) | 703 | if (!cq || cq->uobject->context != file->ucontext) |
695 | goto out; | 704 | goto out; |
696 | 705 | ||
697 | uobj = cq->uobject; | 706 | user_handle = cq->uobject->user_handle; |
707 | uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); | ||
698 | 708 | ||
699 | ret = ib_destroy_cq(cq); | 709 | ret = ib_destroy_cq(cq); |
700 | if (ret) | 710 | if (ret) |
@@ -703,11 +713,32 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
703 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); | 713 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); |
704 | 714 | ||
705 | spin_lock_irq(&file->ucontext->lock); | 715 | spin_lock_irq(&file->ucontext->lock); |
706 | list_del(&uobj->list); | 716 | list_del(&uobj->uobject.list); |
707 | spin_unlock_irq(&file->ucontext->lock); | 717 | spin_unlock_irq(&file->ucontext->lock); |
708 | 718 | ||
719 | spin_lock_irq(&file->comp_file[0].lock); | ||
720 | list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { | ||
721 | list_del(&evt->list); | ||
722 | kfree(evt); | ||
723 | } | ||
724 | spin_unlock_irq(&file->comp_file[0].lock); | ||
725 | |||
726 | spin_lock_irq(&file->async_file.lock); | ||
727 | list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { | ||
728 | list_del(&evt->list); | ||
729 | kfree(evt); | ||
730 | } | ||
731 | spin_unlock_irq(&file->async_file.lock); | ||
732 | |||
733 | resp.comp_events_reported = uobj->comp_events_reported; | ||
734 | resp.async_events_reported = uobj->async_events_reported; | ||
735 | |||
709 | kfree(uobj); | 736 | kfree(uobj); |
710 | 737 | ||
738 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
739 | &resp, sizeof resp)) | ||
740 | ret = -EFAULT; | ||
741 | |||
711 | out: | 742 | out: |
712 | up(&ib_uverbs_idr_mutex); | 743 | up(&ib_uverbs_idr_mutex); |
713 | 744 | ||
@@ -721,7 +752,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
721 | struct ib_uverbs_create_qp cmd; | 752 | struct ib_uverbs_create_qp cmd; |
722 | struct ib_uverbs_create_qp_resp resp; | 753 | struct ib_uverbs_create_qp_resp resp; |
723 | struct ib_udata udata; | 754 | struct ib_udata udata; |
724 | struct ib_uobject *uobj; | 755 | struct ib_uevent_object *uobj; |
725 | struct ib_pd *pd; | 756 | struct ib_pd *pd; |
726 | struct ib_cq *scq, *rcq; | 757 | struct ib_cq *scq, *rcq; |
727 | struct ib_srq *srq; | 758 | struct ib_srq *srq; |
@@ -772,8 +803,10 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
772 | attr.cap.max_recv_sge = cmd.max_recv_sge; | 803 | attr.cap.max_recv_sge = cmd.max_recv_sge; |
773 | attr.cap.max_inline_data = cmd.max_inline_data; | 804 | attr.cap.max_inline_data = cmd.max_inline_data; |
774 | 805 | ||
775 | uobj->user_handle = cmd.user_handle; | 806 | uobj->uobject.user_handle = cmd.user_handle; |
776 | uobj->context = file->ucontext; | 807 | uobj->uobject.context = file->ucontext; |
808 | uobj->events_reported = 0; | ||
809 | INIT_LIST_HEAD(&uobj->event_list); | ||
777 | 810 | ||
778 | qp = pd->device->create_qp(pd, &attr, &udata); | 811 | qp = pd->device->create_qp(pd, &attr, &udata); |
779 | if (IS_ERR(qp)) { | 812 | if (IS_ERR(qp)) { |
@@ -786,7 +819,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
786 | qp->send_cq = attr.send_cq; | 819 | qp->send_cq = attr.send_cq; |
787 | qp->recv_cq = attr.recv_cq; | 820 | qp->recv_cq = attr.recv_cq; |
788 | qp->srq = attr.srq; | 821 | qp->srq = attr.srq; |
789 | qp->uobject = uobj; | 822 | qp->uobject = &uobj->uobject; |
790 | qp->event_handler = attr.event_handler; | 823 | qp->event_handler = attr.event_handler; |
791 | qp->qp_context = attr.qp_context; | 824 | qp->qp_context = attr.qp_context; |
792 | qp->qp_type = attr.qp_type; | 825 | qp->qp_type = attr.qp_type; |
@@ -805,17 +838,17 @@ retry: | |||
805 | goto err_destroy; | 838 | goto err_destroy; |
806 | } | 839 | } |
807 | 840 | ||
808 | ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id); | 841 | ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uobject.id); |
809 | 842 | ||
810 | if (ret == -EAGAIN) | 843 | if (ret == -EAGAIN) |
811 | goto retry; | 844 | goto retry; |
812 | if (ret) | 845 | if (ret) |
813 | goto err_destroy; | 846 | goto err_destroy; |
814 | 847 | ||
815 | resp.qp_handle = uobj->id; | 848 | resp.qp_handle = uobj->uobject.id; |
816 | 849 | ||
817 | spin_lock_irq(&file->ucontext->lock); | 850 | spin_lock_irq(&file->ucontext->lock); |
818 | list_add_tail(&uobj->list, &file->ucontext->qp_list); | 851 | list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); |
819 | spin_unlock_irq(&file->ucontext->lock); | 852 | spin_unlock_irq(&file->ucontext->lock); |
820 | 853 | ||
821 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 854 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
@@ -830,7 +863,7 @@ retry: | |||
830 | 863 | ||
831 | err_list: | 864 | err_list: |
832 | spin_lock_irq(&file->ucontext->lock); | 865 | spin_lock_irq(&file->ucontext->lock); |
833 | list_del(&uobj->list); | 866 | list_del(&uobj->uobject.list); |
834 | spin_unlock_irq(&file->ucontext->lock); | 867 | spin_unlock_irq(&file->ucontext->lock); |
835 | 868 | ||
836 | err_destroy: | 869 | err_destroy: |
@@ -930,21 +963,25 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
930 | const char __user *buf, int in_len, | 963 | const char __user *buf, int in_len, |
931 | int out_len) | 964 | int out_len) |
932 | { | 965 | { |
933 | struct ib_uverbs_destroy_qp cmd; | 966 | struct ib_uverbs_destroy_qp cmd; |
934 | struct ib_qp *qp; | 967 | struct ib_uverbs_destroy_qp_resp resp; |
935 | struct ib_uobject *uobj; | 968 | struct ib_qp *qp; |
936 | int ret = -EINVAL; | 969 | struct ib_uevent_object *uobj; |
970 | struct ib_uverbs_event *evt, *tmp; | ||
971 | int ret = -EINVAL; | ||
937 | 972 | ||
938 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 973 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
939 | return -EFAULT; | 974 | return -EFAULT; |
940 | 975 | ||
976 | memset(&resp, 0, sizeof resp); | ||
977 | |||
941 | down(&ib_uverbs_idr_mutex); | 978 | down(&ib_uverbs_idr_mutex); |
942 | 979 | ||
943 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | 980 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); |
944 | if (!qp || qp->uobject->context != file->ucontext) | 981 | if (!qp || qp->uobject->context != file->ucontext) |
945 | goto out; | 982 | goto out; |
946 | 983 | ||
947 | uobj = qp->uobject; | 984 | uobj = container_of(qp->uobject, struct ib_uevent_object, uobject); |
948 | 985 | ||
949 | ret = ib_destroy_qp(qp); | 986 | ret = ib_destroy_qp(qp); |
950 | if (ret) | 987 | if (ret) |
@@ -953,11 +990,24 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
953 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); | 990 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); |
954 | 991 | ||
955 | spin_lock_irq(&file->ucontext->lock); | 992 | spin_lock_irq(&file->ucontext->lock); |
956 | list_del(&uobj->list); | 993 | list_del(&uobj->uobject.list); |
957 | spin_unlock_irq(&file->ucontext->lock); | 994 | spin_unlock_irq(&file->ucontext->lock); |
958 | 995 | ||
996 | spin_lock_irq(&file->async_file.lock); | ||
997 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
998 | list_del(&evt->list); | ||
999 | kfree(evt); | ||
1000 | } | ||
1001 | spin_unlock_irq(&file->async_file.lock); | ||
1002 | |||
1003 | resp.events_reported = uobj->events_reported; | ||
1004 | |||
959 | kfree(uobj); | 1005 | kfree(uobj); |
960 | 1006 | ||
1007 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
1008 | &resp, sizeof resp)) | ||
1009 | ret = -EFAULT; | ||
1010 | |||
961 | out: | 1011 | out: |
962 | up(&ib_uverbs_idr_mutex); | 1012 | up(&ib_uverbs_idr_mutex); |
963 | 1013 | ||
@@ -1015,7 +1065,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
1015 | struct ib_uverbs_create_srq cmd; | 1065 | struct ib_uverbs_create_srq cmd; |
1016 | struct ib_uverbs_create_srq_resp resp; | 1066 | struct ib_uverbs_create_srq_resp resp; |
1017 | struct ib_udata udata; | 1067 | struct ib_udata udata; |
1018 | struct ib_uobject *uobj; | 1068 | struct ib_uevent_object *uobj; |
1019 | struct ib_pd *pd; | 1069 | struct ib_pd *pd; |
1020 | struct ib_srq *srq; | 1070 | struct ib_srq *srq; |
1021 | struct ib_srq_init_attr attr; | 1071 | struct ib_srq_init_attr attr; |
@@ -1050,8 +1100,10 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
1050 | attr.attr.max_sge = cmd.max_sge; | 1100 | attr.attr.max_sge = cmd.max_sge; |
1051 | attr.attr.srq_limit = cmd.srq_limit; | 1101 | attr.attr.srq_limit = cmd.srq_limit; |
1052 | 1102 | ||
1053 | uobj->user_handle = cmd.user_handle; | 1103 | uobj->uobject.user_handle = cmd.user_handle; |
1054 | uobj->context = file->ucontext; | 1104 | uobj->uobject.context = file->ucontext; |
1105 | uobj->events_reported = 0; | ||
1106 | INIT_LIST_HEAD(&uobj->event_list); | ||
1055 | 1107 | ||
1056 | srq = pd->device->create_srq(pd, &attr, &udata); | 1108 | srq = pd->device->create_srq(pd, &attr, &udata); |
1057 | if (IS_ERR(srq)) { | 1109 | if (IS_ERR(srq)) { |
@@ -1061,7 +1113,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
1061 | 1113 | ||
1062 | srq->device = pd->device; | 1114 | srq->device = pd->device; |
1063 | srq->pd = pd; | 1115 | srq->pd = pd; |
1064 | srq->uobject = uobj; | 1116 | srq->uobject = &uobj->uobject; |
1065 | srq->event_handler = attr.event_handler; | 1117 | srq->event_handler = attr.event_handler; |
1066 | srq->srq_context = attr.srq_context; | 1118 | srq->srq_context = attr.srq_context; |
1067 | atomic_inc(&pd->usecnt); | 1119 | atomic_inc(&pd->usecnt); |
@@ -1075,17 +1127,17 @@ retry: | |||
1075 | goto err_destroy; | 1127 | goto err_destroy; |
1076 | } | 1128 | } |
1077 | 1129 | ||
1078 | ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id); | 1130 | ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->uobject.id); |
1079 | 1131 | ||
1080 | if (ret == -EAGAIN) | 1132 | if (ret == -EAGAIN) |
1081 | goto retry; | 1133 | goto retry; |
1082 | if (ret) | 1134 | if (ret) |
1083 | goto err_destroy; | 1135 | goto err_destroy; |
1084 | 1136 | ||
1085 | resp.srq_handle = uobj->id; | 1137 | resp.srq_handle = uobj->uobject.id; |
1086 | 1138 | ||
1087 | spin_lock_irq(&file->ucontext->lock); | 1139 | spin_lock_irq(&file->ucontext->lock); |
1088 | list_add_tail(&uobj->list, &file->ucontext->srq_list); | 1140 | list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); |
1089 | spin_unlock_irq(&file->ucontext->lock); | 1141 | spin_unlock_irq(&file->ucontext->lock); |
1090 | 1142 | ||
1091 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1143 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
@@ -1100,7 +1152,7 @@ retry: | |||
1100 | 1152 | ||
1101 | err_list: | 1153 | err_list: |
1102 | spin_lock_irq(&file->ucontext->lock); | 1154 | spin_lock_irq(&file->ucontext->lock); |
1103 | list_del(&uobj->list); | 1155 | list_del(&uobj->uobject.list); |
1104 | spin_unlock_irq(&file->ucontext->lock); | 1156 | spin_unlock_irq(&file->ucontext->lock); |
1105 | 1157 | ||
1106 | err_destroy: | 1158 | err_destroy: |
@@ -1149,21 +1201,25 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
1149 | const char __user *buf, int in_len, | 1201 | const char __user *buf, int in_len, |
1150 | int out_len) | 1202 | int out_len) |
1151 | { | 1203 | { |
1152 | struct ib_uverbs_destroy_srq cmd; | 1204 | struct ib_uverbs_destroy_srq cmd; |
1153 | struct ib_srq *srq; | 1205 | struct ib_uverbs_destroy_srq_resp resp; |
1154 | struct ib_uobject *uobj; | 1206 | struct ib_srq *srq; |
1155 | int ret = -EINVAL; | 1207 | struct ib_uevent_object *uobj; |
1208 | struct ib_uverbs_event *evt, *tmp; | ||
1209 | int ret = -EINVAL; | ||
1156 | 1210 | ||
1157 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1211 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
1158 | return -EFAULT; | 1212 | return -EFAULT; |
1159 | 1213 | ||
1160 | down(&ib_uverbs_idr_mutex); | 1214 | down(&ib_uverbs_idr_mutex); |
1161 | 1215 | ||
1216 | memset(&resp, 0, sizeof resp); | ||
1217 | |||
1162 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | 1218 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); |
1163 | if (!srq || srq->uobject->context != file->ucontext) | 1219 | if (!srq || srq->uobject->context != file->ucontext) |
1164 | goto out; | 1220 | goto out; |
1165 | 1221 | ||
1166 | uobj = srq->uobject; | 1222 | uobj = container_of(srq->uobject, struct ib_uevent_object, uobject); |
1167 | 1223 | ||
1168 | ret = ib_destroy_srq(srq); | 1224 | ret = ib_destroy_srq(srq); |
1169 | if (ret) | 1225 | if (ret) |
@@ -1172,11 +1228,24 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
1172 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); | 1228 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); |
1173 | 1229 | ||
1174 | spin_lock_irq(&file->ucontext->lock); | 1230 | spin_lock_irq(&file->ucontext->lock); |
1175 | list_del(&uobj->list); | 1231 | list_del(&uobj->uobject.list); |
1176 | spin_unlock_irq(&file->ucontext->lock); | 1232 | spin_unlock_irq(&file->ucontext->lock); |
1177 | 1233 | ||
1234 | spin_lock_irq(&file->async_file.lock); | ||
1235 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
1236 | list_del(&evt->list); | ||
1237 | kfree(evt); | ||
1238 | } | ||
1239 | spin_unlock_irq(&file->async_file.lock); | ||
1240 | |||
1241 | resp.events_reported = uobj->events_reported; | ||
1242 | |||
1178 | kfree(uobj); | 1243 | kfree(uobj); |
1179 | 1244 | ||
1245 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
1246 | &resp, sizeof resp)) | ||
1247 | ret = -EFAULT; | ||
1248 | |||
1180 | out: | 1249 | out: |
1181 | up(&ib_uverbs_idr_mutex); | 1250 | up(&ib_uverbs_idr_mutex); |
1182 | 1251 | ||
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 09caf5b1ef36..ce5bdb7af306 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -120,7 +120,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
120 | idr_remove(&ib_uverbs_qp_idr, uobj->id); | 120 | idr_remove(&ib_uverbs_qp_idr, uobj->id); |
121 | ib_destroy_qp(qp); | 121 | ib_destroy_qp(qp); |
122 | list_del(&uobj->list); | 122 | list_del(&uobj->list); |
123 | kfree(uobj); | 123 | kfree(container_of(uobj, struct ib_uevent_object, uobject)); |
124 | } | 124 | } |
125 | 125 | ||
126 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { | 126 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { |
@@ -128,7 +128,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
128 | idr_remove(&ib_uverbs_cq_idr, uobj->id); | 128 | idr_remove(&ib_uverbs_cq_idr, uobj->id); |
129 | ib_destroy_cq(cq); | 129 | ib_destroy_cq(cq); |
130 | list_del(&uobj->list); | 130 | list_del(&uobj->list); |
131 | kfree(uobj); | 131 | kfree(container_of(uobj, struct ib_ucq_object, uobject)); |
132 | } | 132 | } |
133 | 133 | ||
134 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { | 134 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { |
@@ -136,7 +136,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
136 | idr_remove(&ib_uverbs_srq_idr, uobj->id); | 136 | idr_remove(&ib_uverbs_srq_idr, uobj->id); |
137 | ib_destroy_srq(srq); | 137 | ib_destroy_srq(srq); |
138 | list_del(&uobj->list); | 138 | list_del(&uobj->list); |
139 | kfree(uobj); | 139 | kfree(container_of(uobj, struct ib_uevent_object, uobject)); |
140 | } | 140 | } |
141 | 141 | ||
142 | /* XXX Free MWs */ | 142 | /* XXX Free MWs */ |
@@ -182,7 +182,7 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, | |||
182 | size_t count, loff_t *pos) | 182 | size_t count, loff_t *pos) |
183 | { | 183 | { |
184 | struct ib_uverbs_event_file *file = filp->private_data; | 184 | struct ib_uverbs_event_file *file = filp->private_data; |
185 | void *event; | 185 | struct ib_uverbs_event *event; |
186 | int eventsz; | 186 | int eventsz; |
187 | int ret = 0; | 187 | int ret = 0; |
188 | 188 | ||
@@ -207,21 +207,23 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, | |||
207 | return -ENODEV; | 207 | return -ENODEV; |
208 | } | 208 | } |
209 | 209 | ||
210 | if (file->is_async) { | 210 | event = list_entry(file->event_list.next, struct ib_uverbs_event, list); |
211 | event = list_entry(file->event_list.next, | 211 | |
212 | struct ib_uverbs_async_event, list); | 212 | if (file->is_async) |
213 | eventsz = sizeof (struct ib_uverbs_async_event_desc); | 213 | eventsz = sizeof (struct ib_uverbs_async_event_desc); |
214 | } else { | 214 | else |
215 | event = list_entry(file->event_list.next, | ||
216 | struct ib_uverbs_comp_event, list); | ||
217 | eventsz = sizeof (struct ib_uverbs_comp_event_desc); | 215 | eventsz = sizeof (struct ib_uverbs_comp_event_desc); |
218 | } | ||
219 | 216 | ||
220 | if (eventsz > count) { | 217 | if (eventsz > count) { |
221 | ret = -EINVAL; | 218 | ret = -EINVAL; |
222 | event = NULL; | 219 | event = NULL; |
223 | } else | 220 | } else { |
224 | list_del(file->event_list.next); | 221 | list_del(file->event_list.next); |
222 | if (event->counter) { | ||
223 | ++(*event->counter); | ||
224 | list_del(&event->obj_list); | ||
225 | } | ||
226 | } | ||
225 | 227 | ||
226 | spin_unlock_irq(&file->lock); | 228 | spin_unlock_irq(&file->lock); |
227 | 229 | ||
@@ -257,16 +259,13 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, | |||
257 | 259 | ||
258 | static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) | 260 | static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) |
259 | { | 261 | { |
260 | struct list_head *entry, *tmp; | 262 | struct ib_uverbs_event *entry, *tmp; |
261 | 263 | ||
262 | spin_lock_irq(&file->lock); | 264 | spin_lock_irq(&file->lock); |
263 | if (file->fd != -1) { | 265 | if (file->fd != -1) { |
264 | file->fd = -1; | 266 | file->fd = -1; |
265 | list_for_each_safe(entry, tmp, &file->event_list) | 267 | list_for_each_entry_safe(entry, tmp, &file->event_list, list) |
266 | if (file->is_async) | 268 | kfree(entry); |
267 | kfree(list_entry(entry, struct ib_uverbs_async_event, list)); | ||
268 | else | ||
269 | kfree(list_entry(entry, struct ib_uverbs_comp_event, list)); | ||
270 | } | 269 | } |
271 | spin_unlock_irq(&file->lock); | 270 | spin_unlock_irq(&file->lock); |
272 | } | 271 | } |
@@ -304,18 +303,23 @@ static struct file_operations uverbs_event_fops = { | |||
304 | 303 | ||
305 | void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) | 304 | void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) |
306 | { | 305 | { |
307 | struct ib_uverbs_file *file = cq_context; | 306 | struct ib_uverbs_file *file = cq_context; |
308 | struct ib_uverbs_comp_event *entry; | 307 | struct ib_ucq_object *uobj; |
309 | unsigned long flags; | 308 | struct ib_uverbs_event *entry; |
309 | unsigned long flags; | ||
310 | 310 | ||
311 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); | 311 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); |
312 | if (!entry) | 312 | if (!entry) |
313 | return; | 313 | return; |
314 | 314 | ||
315 | entry->desc.cq_handle = cq->uobject->user_handle; | 315 | uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); |
316 | |||
317 | entry->desc.comp.cq_handle = cq->uobject->user_handle; | ||
318 | entry->counter = &uobj->comp_events_reported; | ||
316 | 319 | ||
317 | spin_lock_irqsave(&file->comp_file[0].lock, flags); | 320 | spin_lock_irqsave(&file->comp_file[0].lock, flags); |
318 | list_add_tail(&entry->list, &file->comp_file[0].event_list); | 321 | list_add_tail(&entry->list, &file->comp_file[0].event_list); |
322 | list_add_tail(&entry->obj_list, &uobj->comp_list); | ||
319 | spin_unlock_irqrestore(&file->comp_file[0].lock, flags); | 323 | spin_unlock_irqrestore(&file->comp_file[0].lock, flags); |
320 | 324 | ||
321 | wake_up_interruptible(&file->comp_file[0].poll_wait); | 325 | wake_up_interruptible(&file->comp_file[0].poll_wait); |
@@ -323,20 +327,25 @@ void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) | |||
323 | } | 327 | } |
324 | 328 | ||
325 | static void ib_uverbs_async_handler(struct ib_uverbs_file *file, | 329 | static void ib_uverbs_async_handler(struct ib_uverbs_file *file, |
326 | __u64 element, __u64 event) | 330 | __u64 element, __u64 event, |
331 | struct list_head *obj_list, | ||
332 | u32 *counter) | ||
327 | { | 333 | { |
328 | struct ib_uverbs_async_event *entry; | 334 | struct ib_uverbs_event *entry; |
329 | unsigned long flags; | 335 | unsigned long flags; |
330 | 336 | ||
331 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); | 337 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); |
332 | if (!entry) | 338 | if (!entry) |
333 | return; | 339 | return; |
334 | 340 | ||
335 | entry->desc.element = element; | 341 | entry->desc.async.element = element; |
336 | entry->desc.event_type = event; | 342 | entry->desc.async.event_type = event; |
343 | entry->counter = counter; | ||
337 | 344 | ||
338 | spin_lock_irqsave(&file->async_file.lock, flags); | 345 | spin_lock_irqsave(&file->async_file.lock, flags); |
339 | list_add_tail(&entry->list, &file->async_file.event_list); | 346 | list_add_tail(&entry->list, &file->async_file.event_list); |
347 | if (obj_list) | ||
348 | list_add_tail(&entry->obj_list, obj_list); | ||
340 | spin_unlock_irqrestore(&file->async_file.lock, flags); | 349 | spin_unlock_irqrestore(&file->async_file.lock, flags); |
341 | 350 | ||
342 | wake_up_interruptible(&file->async_file.poll_wait); | 351 | wake_up_interruptible(&file->async_file.poll_wait); |
@@ -345,23 +354,39 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, | |||
345 | 354 | ||
346 | void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) | 355 | void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) |
347 | { | 356 | { |
348 | ib_uverbs_async_handler(context_ptr, | 357 | struct ib_ucq_object *uobj; |
349 | event->element.cq->uobject->user_handle, | 358 | |
350 | event->event); | 359 | uobj = container_of(event->element.cq->uobject, |
360 | struct ib_ucq_object, uobject); | ||
361 | |||
362 | ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, | ||
363 | event->event, &uobj->async_list, | ||
364 | &uobj->async_events_reported); | ||
365 | |||
351 | } | 366 | } |
352 | 367 | ||
353 | void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) | 368 | void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) |
354 | { | 369 | { |
355 | ib_uverbs_async_handler(context_ptr, | 370 | struct ib_uevent_object *uobj; |
356 | event->element.qp->uobject->user_handle, | 371 | |
357 | event->event); | 372 | uobj = container_of(event->element.qp->uobject, |
373 | struct ib_uevent_object, uobject); | ||
374 | |||
375 | ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, | ||
376 | event->event, &uobj->event_list, | ||
377 | &uobj->events_reported); | ||
358 | } | 378 | } |
359 | 379 | ||
360 | void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) | 380 | void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) |
361 | { | 381 | { |
362 | ib_uverbs_async_handler(context_ptr, | 382 | struct ib_uevent_object *uobj; |
363 | event->element.srq->uobject->user_handle, | 383 | |
364 | event->event); | 384 | uobj = container_of(event->element.srq->uobject, |
385 | struct ib_uevent_object, uobject); | ||
386 | |||
387 | ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, | ||
388 | event->event, &uobj->event_list, | ||
389 | &uobj->events_reported); | ||
365 | } | 390 | } |
366 | 391 | ||
367 | static void ib_uverbs_event_handler(struct ib_event_handler *handler, | 392 | static void ib_uverbs_event_handler(struct ib_event_handler *handler, |
@@ -370,7 +395,8 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, | |||
370 | struct ib_uverbs_file *file = | 395 | struct ib_uverbs_file *file = |
371 | container_of(handler, struct ib_uverbs_file, event_handler); | 396 | container_of(handler, struct ib_uverbs_file, event_handler); |
372 | 397 | ||
373 | ib_uverbs_async_handler(file, event->element.port_num, event->event); | 398 | ib_uverbs_async_handler(file, event->element.port_num, event->event, |
399 | NULL, NULL); | ||
374 | } | 400 | } |
375 | 401 | ||
376 | static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, | 402 | static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, |
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 0164b84d4ec6..bcef06bf15e7 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c | |||
@@ -220,6 +220,16 @@ static void *get_send_wqe(struct mthca_qp *qp, int n) | |||
220 | (PAGE_SIZE - 1)); | 220 | (PAGE_SIZE - 1)); |
221 | } | 221 | } |
222 | 222 | ||
223 | static void mthca_wq_init(struct mthca_wq *wq) | ||
224 | { | ||
225 | spin_lock_init(&wq->lock); | ||
226 | wq->next_ind = 0; | ||
227 | wq->last_comp = wq->max - 1; | ||
228 | wq->head = 0; | ||
229 | wq->tail = 0; | ||
230 | wq->last = NULL; | ||
231 | } | ||
232 | |||
223 | void mthca_qp_event(struct mthca_dev *dev, u32 qpn, | 233 | void mthca_qp_event(struct mthca_dev *dev, u32 qpn, |
224 | enum ib_event_type event_type) | 234 | enum ib_event_type event_type) |
225 | { | 235 | { |
@@ -833,8 +843,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
833 | store_attrs(to_msqp(qp), attr, attr_mask); | 843 | store_attrs(to_msqp(qp), attr, attr_mask); |
834 | 844 | ||
835 | /* | 845 | /* |
836 | * If we are moving QP0 to RTR, bring the IB link up; if we | 846 | * If we moved QP0 to RTR, bring the IB link up; if we moved |
837 | * are moving QP0 to RESET or ERROR, bring the link back down. | 847 | * QP0 to RESET or ERROR, bring the link back down. |
838 | */ | 848 | */ |
839 | if (is_qp0(dev, qp)) { | 849 | if (is_qp0(dev, qp)) { |
840 | if (cur_state != IB_QPS_RTR && | 850 | if (cur_state != IB_QPS_RTR && |
@@ -848,6 +858,26 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
848 | mthca_CLOSE_IB(dev, to_msqp(qp)->port, &status); | 858 | mthca_CLOSE_IB(dev, to_msqp(qp)->port, &status); |
849 | } | 859 | } |
850 | 860 | ||
861 | /* | ||
862 | * If we moved a kernel QP to RESET, clean up all old CQ | ||
863 | * entries and reinitialize the QP. | ||
864 | */ | ||
865 | if (!err && new_state == IB_QPS_RESET && !qp->ibqp.uobject) { | ||
866 | mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, | ||
867 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); | ||
868 | if (qp->ibqp.send_cq != qp->ibqp.recv_cq) | ||
869 | mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, | ||
870 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); | ||
871 | |||
872 | mthca_wq_init(&qp->sq); | ||
873 | mthca_wq_init(&qp->rq); | ||
874 | |||
875 | if (mthca_is_memfree(dev)) { | ||
876 | *qp->sq.db = 0; | ||
877 | *qp->rq.db = 0; | ||
878 | } | ||
879 | } | ||
880 | |||
851 | return err; | 881 | return err; |
852 | } | 882 | } |
853 | 883 | ||
@@ -1003,16 +1033,6 @@ static void mthca_free_memfree(struct mthca_dev *dev, | |||
1003 | } | 1033 | } |
1004 | } | 1034 | } |
1005 | 1035 | ||
1006 | static void mthca_wq_init(struct mthca_wq* wq) | ||
1007 | { | ||
1008 | spin_lock_init(&wq->lock); | ||
1009 | wq->next_ind = 0; | ||
1010 | wq->last_comp = wq->max - 1; | ||
1011 | wq->head = 0; | ||
1012 | wq->tail = 0; | ||
1013 | wq->last = NULL; | ||
1014 | } | ||
1015 | |||
1016 | static int mthca_alloc_qp_common(struct mthca_dev *dev, | 1036 | static int mthca_alloc_qp_common(struct mthca_dev *dev, |
1017 | struct mthca_pd *pd, | 1037 | struct mthca_pd *pd, |
1018 | struct mthca_cq *send_cq, | 1038 | struct mthca_cq *send_cq, |
@@ -1024,6 +1044,7 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, | |||
1024 | int i; | 1044 | int i; |
1025 | 1045 | ||
1026 | atomic_set(&qp->refcount, 1); | 1046 | atomic_set(&qp->refcount, 1); |
1047 | init_waitqueue_head(&qp->wait); | ||
1027 | qp->state = IB_QPS_RESET; | 1048 | qp->state = IB_QPS_RESET; |
1028 | qp->atomic_rd_en = 0; | 1049 | qp->atomic_rd_en = 0; |
1029 | qp->resp_depth = 0; | 1050 | qp->resp_depth = 0; |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 0e8ac138e355..49d120d2b92c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -1062,6 +1062,8 @@ static void ipoib_remove_one(struct ib_device *device) | |||
1062 | ipoib_dev_cleanup(priv->dev); | 1062 | ipoib_dev_cleanup(priv->dev); |
1063 | free_netdev(priv->dev); | 1063 | free_netdev(priv->dev); |
1064 | } | 1064 | } |
1065 | |||
1066 | kfree(dev_list); | ||
1065 | } | 1067 | } |
1066 | 1068 | ||
1067 | static int __init ipoib_init_module(void) | 1069 | static int __init ipoib_init_module(void) |