diff options
| -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 | ||||
| -rw-r--r-- | include/rdma/ib_cm.h | 1 | ||||
| -rw-r--r-- | include/rdma/ib_mad.h | 21 | ||||
| -rw-r--r-- | include/rdma/ib_sa.h | 31 | ||||
| -rw-r--r-- | include/rdma/ib_user_cm.h | 72 | ||||
| -rw-r--r-- | include/rdma/ib_user_verbs.h | 21 |
17 files changed, 589 insertions, 250 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) |
diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 77fe9039209b..5308683c8c41 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h | |||
| @@ -290,6 +290,7 @@ struct ib_cm_id { | |||
| 290 | enum ib_cm_lap_state lap_state; /* internal CM/debug use */ | 290 | enum ib_cm_lap_state lap_state; /* internal CM/debug use */ |
| 291 | __be32 local_id; | 291 | __be32 local_id; |
| 292 | __be32 remote_id; | 292 | __be32 remote_id; |
| 293 | u32 remote_cm_qpn; /* 1 unless redirected */ | ||
| 293 | }; | 294 | }; |
| 294 | 295 | ||
| 295 | /** | 296 | /** |
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index fc6b1c18ffc6..53184a38fdf6 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h | |||
| @@ -173,6 +173,27 @@ struct ib_vendor_mad { | |||
| 173 | u8 data[216]; | 173 | u8 data[216]; |
| 174 | }; | 174 | }; |
| 175 | 175 | ||
| 176 | struct ib_class_port_info | ||
| 177 | { | ||
| 178 | u8 base_version; | ||
| 179 | u8 class_version; | ||
| 180 | __be16 capability_mask; | ||
| 181 | u8 reserved[3]; | ||
| 182 | u8 resp_time_value; | ||
| 183 | u8 redirect_gid[16]; | ||
| 184 | __be32 redirect_tcslfl; | ||
| 185 | __be16 redirect_lid; | ||
| 186 | __be16 redirect_pkey; | ||
| 187 | __be32 redirect_qp; | ||
| 188 | __be32 redirect_qkey; | ||
| 189 | u8 trap_gid[16]; | ||
| 190 | __be32 trap_tcslfl; | ||
| 191 | __be16 trap_lid; | ||
| 192 | __be16 trap_pkey; | ||
| 193 | __be32 trap_hlqp; | ||
| 194 | __be32 trap_qkey; | ||
| 195 | }; | ||
| 196 | |||
| 176 | /** | 197 | /** |
| 177 | * ib_mad_send_buf - MAD data buffer and work request for sends. | 198 | * ib_mad_send_buf - MAD data buffer and work request for sends. |
| 178 | * @mad: References an allocated MAD data buffer. The size of the data | 199 | * @mad: References an allocated MAD data buffer. The size of the data |
diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index c022edfc49da..a7555c800ecf 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h | |||
| @@ -46,7 +46,36 @@ enum { | |||
| 46 | 46 | ||
| 47 | IB_SA_METHOD_GET_TABLE = 0x12, | 47 | IB_SA_METHOD_GET_TABLE = 0x12, |
| 48 | IB_SA_METHOD_GET_TABLE_RESP = 0x92, | 48 | IB_SA_METHOD_GET_TABLE_RESP = 0x92, |
| 49 | IB_SA_METHOD_DELETE = 0x15 | 49 | IB_SA_METHOD_DELETE = 0x15, |
| 50 | IB_SA_METHOD_DELETE_RESP = 0x95, | ||
| 51 | IB_SA_METHOD_GET_MULTI = 0x14, | ||
| 52 | IB_SA_METHOD_GET_MULTI_RESP = 0x94, | ||
| 53 | IB_SA_METHOD_GET_TRACE_TBL = 0x13 | ||
| 54 | }; | ||
| 55 | |||
| 56 | enum { | ||
| 57 | IB_SA_ATTR_CLASS_PORTINFO = 0x01, | ||
| 58 | IB_SA_ATTR_NOTICE = 0x02, | ||
| 59 | IB_SA_ATTR_INFORM_INFO = 0x03, | ||
| 60 | IB_SA_ATTR_NODE_REC = 0x11, | ||
| 61 | IB_SA_ATTR_PORT_INFO_REC = 0x12, | ||
| 62 | IB_SA_ATTR_SL2VL_REC = 0x13, | ||
| 63 | IB_SA_ATTR_SWITCH_REC = 0x14, | ||
| 64 | IB_SA_ATTR_LINEAR_FDB_REC = 0x15, | ||
| 65 | IB_SA_ATTR_RANDOM_FDB_REC = 0x16, | ||
| 66 | IB_SA_ATTR_MCAST_FDB_REC = 0x17, | ||
| 67 | IB_SA_ATTR_SM_INFO_REC = 0x18, | ||
| 68 | IB_SA_ATTR_LINK_REC = 0x20, | ||
| 69 | IB_SA_ATTR_GUID_INFO_REC = 0x30, | ||
| 70 | IB_SA_ATTR_SERVICE_REC = 0x31, | ||
| 71 | IB_SA_ATTR_PARTITION_REC = 0x33, | ||
| 72 | IB_SA_ATTR_PATH_REC = 0x35, | ||
| 73 | IB_SA_ATTR_VL_ARB_REC = 0x36, | ||
| 74 | IB_SA_ATTR_MC_MEMBER_REC = 0x38, | ||
| 75 | IB_SA_ATTR_TRACE_REC = 0x39, | ||
| 76 | IB_SA_ATTR_MULTI_PATH_REC = 0x3a, | ||
| 77 | IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b, | ||
| 78 | IB_SA_ATTR_INFORM_INFO_REC = 0xf3 | ||
| 50 | }; | 79 | }; |
| 51 | 80 | ||
| 52 | enum ib_sa_selector { | 81 | enum ib_sa_selector { |
diff --git a/include/rdma/ib_user_cm.h b/include/rdma/ib_user_cm.h index 72182d16778b..e4d1654276ad 100644 --- a/include/rdma/ib_user_cm.h +++ b/include/rdma/ib_user_cm.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 |
| @@ -37,7 +38,7 @@ | |||
| 37 | 38 | ||
| 38 | #include <linux/types.h> | 39 | #include <linux/types.h> |
| 39 | 40 | ||
| 40 | #define IB_USER_CM_ABI_VERSION 1 | 41 | #define IB_USER_CM_ABI_VERSION 2 |
| 41 | 42 | ||
| 42 | enum { | 43 | enum { |
| 43 | IB_USER_CM_CMD_CREATE_ID, | 44 | IB_USER_CM_CMD_CREATE_ID, |
| @@ -60,6 +61,7 @@ enum { | |||
| 60 | IB_USER_CM_CMD_SEND_SIDR_REP, | 61 | IB_USER_CM_CMD_SEND_SIDR_REP, |
| 61 | 62 | ||
| 62 | IB_USER_CM_CMD_EVENT, | 63 | IB_USER_CM_CMD_EVENT, |
| 64 | IB_USER_CM_CMD_INIT_QP_ATTR, | ||
| 63 | }; | 65 | }; |
| 64 | /* | 66 | /* |
| 65 | * command ABI structures. | 67 | * command ABI structures. |
| @@ -71,6 +73,7 @@ struct ib_ucm_cmd_hdr { | |||
| 71 | }; | 73 | }; |
| 72 | 74 | ||
| 73 | struct ib_ucm_create_id { | 75 | struct ib_ucm_create_id { |
| 76 | __u64 uid; | ||
| 74 | __u64 response; | 77 | __u64 response; |
| 75 | }; | 78 | }; |
| 76 | 79 | ||
| @@ -79,9 +82,14 @@ struct ib_ucm_create_id_resp { | |||
| 79 | }; | 82 | }; |
| 80 | 83 | ||
| 81 | struct ib_ucm_destroy_id { | 84 | struct ib_ucm_destroy_id { |
| 85 | __u64 response; | ||
| 82 | __u32 id; | 86 | __u32 id; |
| 83 | }; | 87 | }; |
| 84 | 88 | ||
| 89 | struct ib_ucm_destroy_id_resp { | ||
| 90 | __u32 events_reported; | ||
| 91 | }; | ||
| 92 | |||
| 85 | struct ib_ucm_attr_id { | 93 | struct ib_ucm_attr_id { |
| 86 | __u64 response; | 94 | __u64 response; |
| 87 | __u32 id; | 95 | __u32 id; |
| @@ -94,6 +102,64 @@ struct ib_ucm_attr_id_resp { | |||
| 94 | __be32 remote_id; | 102 | __be32 remote_id; |
| 95 | }; | 103 | }; |
| 96 | 104 | ||
| 105 | struct ib_ucm_init_qp_attr { | ||
| 106 | __u64 response; | ||
| 107 | __u32 id; | ||
| 108 | __u32 qp_state; | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct ib_ucm_ah_attr { | ||
| 112 | __u8 grh_dgid[16]; | ||
| 113 | __u32 grh_flow_label; | ||
| 114 | __u16 dlid; | ||
| 115 | __u16 reserved; | ||
| 116 | __u8 grh_sgid_index; | ||
| 117 | __u8 grh_hop_limit; | ||
| 118 | __u8 grh_traffic_class; | ||
| 119 | __u8 sl; | ||
| 120 | __u8 src_path_bits; | ||
| 121 | __u8 static_rate; | ||
| 122 | __u8 is_global; | ||
| 123 | __u8 port_num; | ||
| 124 | }; | ||
| 125 | |||
| 126 | struct ib_ucm_init_qp_attr_resp { | ||
| 127 | __u32 qp_attr_mask; | ||
| 128 | __u32 qp_state; | ||
| 129 | __u32 cur_qp_state; | ||
| 130 | __u32 path_mtu; | ||
| 131 | __u32 path_mig_state; | ||
| 132 | __u32 qkey; | ||
| 133 | __u32 rq_psn; | ||
| 134 | __u32 sq_psn; | ||
| 135 | __u32 dest_qp_num; | ||
| 136 | __u32 qp_access_flags; | ||
| 137 | |||
| 138 | struct ib_ucm_ah_attr ah_attr; | ||
| 139 | struct ib_ucm_ah_attr alt_ah_attr; | ||
| 140 | |||
| 141 | /* ib_qp_cap */ | ||
| 142 | __u32 max_send_wr; | ||
| 143 | __u32 max_recv_wr; | ||
| 144 | __u32 max_send_sge; | ||
| 145 | __u32 max_recv_sge; | ||
| 146 | __u32 max_inline_data; | ||
| 147 | |||
| 148 | __u16 pkey_index; | ||
| 149 | __u16 alt_pkey_index; | ||
| 150 | __u8 en_sqd_async_notify; | ||
| 151 | __u8 sq_draining; | ||
| 152 | __u8 max_rd_atomic; | ||
| 153 | __u8 max_dest_rd_atomic; | ||
| 154 | __u8 min_rnr_timer; | ||
| 155 | __u8 port_num; | ||
| 156 | __u8 timeout; | ||
| 157 | __u8 retry_cnt; | ||
| 158 | __u8 rnr_retry; | ||
| 159 | __u8 alt_port_num; | ||
| 160 | __u8 alt_timeout; | ||
| 161 | }; | ||
| 162 | |||
| 97 | struct ib_ucm_listen { | 163 | struct ib_ucm_listen { |
| 98 | __be64 service_id; | 164 | __be64 service_id; |
| 99 | __be64 service_mask; | 165 | __be64 service_mask; |
| @@ -157,6 +223,7 @@ struct ib_ucm_req { | |||
| 157 | }; | 223 | }; |
| 158 | 224 | ||
| 159 | struct ib_ucm_rep { | 225 | struct ib_ucm_rep { |
| 226 | __u64 uid; | ||
| 160 | __u64 data; | 227 | __u64 data; |
| 161 | __u32 id; | 228 | __u32 id; |
| 162 | __u32 qpn; | 229 | __u32 qpn; |
| @@ -232,7 +299,6 @@ struct ib_ucm_event_get { | |||
| 232 | }; | 299 | }; |
| 233 | 300 | ||
| 234 | struct ib_ucm_req_event_resp { | 301 | struct ib_ucm_req_event_resp { |
| 235 | __u32 listen_id; | ||
| 236 | /* device */ | 302 | /* device */ |
| 237 | /* port */ | 303 | /* port */ |
| 238 | struct ib_ucm_path_rec primary_path; | 304 | struct ib_ucm_path_rec primary_path; |
| @@ -287,7 +353,6 @@ struct ib_ucm_apr_event_resp { | |||
| 287 | }; | 353 | }; |
| 288 | 354 | ||
| 289 | struct ib_ucm_sidr_req_event_resp { | 355 | struct ib_ucm_sidr_req_event_resp { |
| 290 | __u32 listen_id; | ||
| 291 | /* device */ | 356 | /* device */ |
| 292 | /* port */ | 357 | /* port */ |
| 293 | __u16 pkey; | 358 | __u16 pkey; |
| @@ -307,6 +372,7 @@ struct ib_ucm_sidr_rep_event_resp { | |||
| 307 | #define IB_UCM_PRES_ALTERNATE 0x08 | 372 | #define IB_UCM_PRES_ALTERNATE 0x08 |
| 308 | 373 | ||
| 309 | struct ib_ucm_event_resp { | 374 | struct ib_ucm_event_resp { |
| 375 | __u64 uid; | ||
| 310 | __u32 id; | 376 | __u32 id; |
| 311 | __u32 event; | 377 | __u32 event; |
| 312 | __u32 present; | 378 | __u32 present; |
diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index 7ebb01c8f996..fd85725391a4 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h | |||
| @@ -42,7 +42,7 @@ | |||
| 42 | * Increment this value if any changes that break userspace ABI | 42 | * Increment this value if any changes that break userspace ABI |
| 43 | * compatibility are made. | 43 | * compatibility are made. |
| 44 | */ | 44 | */ |
| 45 | #define IB_USER_VERBS_ABI_VERSION 1 | 45 | #define IB_USER_VERBS_ABI_VERSION 2 |
| 46 | 46 | ||
| 47 | enum { | 47 | enum { |
| 48 | IB_USER_VERBS_CMD_QUERY_PARAMS, | 48 | IB_USER_VERBS_CMD_QUERY_PARAMS, |
| @@ -292,7 +292,14 @@ struct ib_uverbs_create_cq_resp { | |||
| 292 | }; | 292 | }; |
| 293 | 293 | ||
| 294 | struct ib_uverbs_destroy_cq { | 294 | struct ib_uverbs_destroy_cq { |
| 295 | __u64 response; | ||
| 295 | __u32 cq_handle; | 296 | __u32 cq_handle; |
| 297 | __u32 reserved; | ||
| 298 | }; | ||
| 299 | |||
| 300 | struct ib_uverbs_destroy_cq_resp { | ||
| 301 | __u32 comp_events_reported; | ||
| 302 | __u32 async_events_reported; | ||
| 296 | }; | 303 | }; |
| 297 | 304 | ||
| 298 | struct ib_uverbs_create_qp { | 305 | struct ib_uverbs_create_qp { |
| @@ -372,7 +379,13 @@ struct ib_uverbs_modify_qp_resp { | |||
| 372 | }; | 379 | }; |
| 373 | 380 | ||
| 374 | struct ib_uverbs_destroy_qp { | 381 | struct ib_uverbs_destroy_qp { |
| 382 | __u64 response; | ||
| 375 | __u32 qp_handle; | 383 | __u32 qp_handle; |
| 384 | __u32 reserved; | ||
| 385 | }; | ||
| 386 | |||
| 387 | struct ib_uverbs_destroy_qp_resp { | ||
| 388 | __u32 events_reported; | ||
| 376 | }; | 389 | }; |
| 377 | 390 | ||
| 378 | struct ib_uverbs_attach_mcast { | 391 | struct ib_uverbs_attach_mcast { |
| @@ -416,7 +429,13 @@ struct ib_uverbs_modify_srq { | |||
| 416 | }; | 429 | }; |
| 417 | 430 | ||
| 418 | struct ib_uverbs_destroy_srq { | 431 | struct ib_uverbs_destroy_srq { |
| 432 | __u64 response; | ||
| 419 | __u32 srq_handle; | 433 | __u32 srq_handle; |
| 434 | __u32 reserved; | ||
| 435 | }; | ||
| 436 | |||
| 437 | struct ib_uverbs_destroy_srq_resp { | ||
| 438 | __u32 events_reported; | ||
| 420 | }; | 439 | }; |
| 421 | 440 | ||
| 422 | #endif /* IB_USER_VERBS_H */ | 441 | #endif /* IB_USER_VERBS_H */ |
