···88 any protocols you wish to use as well as drivers for your99 InfiniBand hardware.10101111-config INFINIBAND_USER_VERBS1212- tristate "InfiniBand userspace verbs support"1111+config INFINIBAND_USER_MAD1212+ tristate "InfiniBand userspace MAD support"1313 depends on INFINIBAND1414 ---help---1515- Userspace InfiniBand verbs support. This is the kernel side1616- of userspace verbs, which allows userspace processes to1717- directly access InfiniBand hardware for fast-path1818- operations. You will also need libibverbs and a hardware1919- driver library from <http://www.openib.org>.1515+ Userspace InfiniBand Management Datagram (MAD) support. This1616+ is the kernel side of the userspace MAD support, which allows1717+ userspace processes to send and receive MADs. You will also 1818+ need libibumad from <http://www.openib.org>.1919+2020+config INFINIBAND_USER_ACCESS2121+ tristate "InfiniBand userspace access (verbs and CM)"2222+ depends on INFINIBAND2323+ ---help---2424+ Userspace InfiniBand access support. This enables the2525+ kernel side of userspace verbs and the userspace2626+ communication manager (CM). This allows userspace processes2727+ to set up connections and directly access InfiniBand2828+ hardware for fast-path operations. You will also need2929+ libibverbs, libibcm and a hardware driver library from3030+ <http://www.openib.org>.20312132source "drivers/infiniband/hw/mthca/Kconfig"2233
···72727373static struct semaphore ctx_id_mutex;7474static struct idr ctx_id_table;7575-static int ctx_id_rover = 0;76757776static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id)7877{···9697 wake_up(&ctx->wait);9798}98999999-static ssize_t ib_ucm_destroy_ctx(struct ib_ucm_file *file, int id)100100+static inline int ib_ucm_new_cm_id(int event)100101{101101- struct ib_ucm_context *ctx;102102+ return event == IB_CM_REQ_RECEIVED || event == IB_CM_SIDR_REQ_RECEIVED;103103+}104104+105105+static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx)106106+{102107 struct ib_ucm_event *uevent;103108104104- down(&ctx_id_mutex);105105- ctx = idr_find(&ctx_id_table, id);106106- if (!ctx)107107- ctx = ERR_PTR(-ENOENT);108108- else if (ctx->file != file)109109- ctx = ERR_PTR(-EINVAL);110110- else111111- idr_remove(&ctx_id_table, ctx->id);112112- up(&ctx_id_mutex);113113-114114- if (IS_ERR(ctx))115115- return PTR_ERR(ctx);116116-117117- atomic_dec(&ctx->ref);118118- wait_event(ctx->wait, !atomic_read(&ctx->ref));119119-120120- /* No new events will be generated after destroying the cm_id. */121121- if (!IS_ERR(ctx->cm_id))122122- ib_destroy_cm_id(ctx->cm_id);123123-124124- /* Cleanup events not yet reported to the user. */125125- down(&file->mutex);109109+ down(&ctx->file->mutex);126110 list_del(&ctx->file_list);127111 while (!list_empty(&ctx->events)) {128112···115133 list_del(&uevent->ctx_list);116134117135 /* clear incoming connections. */118118- if (uevent->cm_id)136136+ if (ib_ucm_new_cm_id(uevent->resp.event))119137 ib_destroy_cm_id(uevent->cm_id);120138121139 kfree(uevent);122140 }123123- up(&file->mutex);124124-125125- kfree(ctx);126126- return 0;141141+ up(&ctx->file->mutex);127142}128143129144static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)···132153 if (!ctx)133154 return NULL;134155156156+ memset(ctx, 0, sizeof *ctx);135157 atomic_set(&ctx->ref, 1);136158 init_waitqueue_head(&ctx->wait);137159 ctx->file = file;138138-139160 INIT_LIST_HEAD(&ctx->events);140161141141- list_add_tail(&ctx->file_list, &file->ctxs);162162+ do {163163+ result = idr_pre_get(&ctx_id_table, GFP_KERNEL);164164+ if (!result)165165+ goto error;142166143143- ctx_id_rover = (ctx_id_rover + 1) & INT_MAX;144144-retry:145145- result = idr_pre_get(&ctx_id_table, GFP_KERNEL);146146- if (!result)147147- goto error;167167+ down(&ctx_id_mutex);168168+ result = idr_get_new(&ctx_id_table, ctx, &ctx->id);169169+ up(&ctx_id_mutex);170170+ } while (result == -EAGAIN);148171149149- down(&ctx_id_mutex);150150- result = idr_get_new_above(&ctx_id_table, ctx, ctx_id_rover, &ctx->id);151151- up(&ctx_id_mutex);152152-153153- if (result == -EAGAIN)154154- goto retry;155172 if (result)156173 goto error;157174175175+ list_add_tail(&ctx->file_list, &file->ctxs);158176 ucm_dbg("Allocated CM ID <%d>\n", ctx->id);159159-160177 return ctx;161161-error:162162- list_del(&ctx->file_list);163163- kfree(ctx);164178179179+error:180180+ kfree(ctx);165181 return NULL;166182}167183/*···193219 kpath->packet_life_time_selector;194220}195221196196-static void ib_ucm_event_req_get(struct ib_ucm_context *ctx,197197- struct ib_ucm_req_event_resp *ureq,222222+static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq,198223 struct ib_cm_req_event_param *kreq)199224{200200- ureq->listen_id = ctx->id;201201-202225 ureq->remote_ca_guid = kreq->remote_ca_guid;203226 ureq->remote_qkey = kreq->remote_qkey;204227 ureq->remote_qpn = kreq->remote_qpn;···230259 urep->srq = krep->srq;231260}232261233233-static void ib_ucm_event_sidr_req_get(struct ib_ucm_context *ctx,234234- struct ib_ucm_sidr_req_event_resp *ureq,235235- struct ib_cm_sidr_req_event_param *kreq)236236-{237237- ureq->listen_id = ctx->id;238238- ureq->pkey = kreq->pkey;239239-}240240-241262static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep,242263 struct ib_cm_sidr_rep_event_param *krep)243264{···238275 urep->qpn = krep->qpn;239276};240277241241-static int ib_ucm_event_process(struct ib_ucm_context *ctx,242242- struct ib_cm_event *evt,278278+static int ib_ucm_event_process(struct ib_cm_event *evt,243279 struct ib_ucm_event *uvt)244280{245281 void *info = NULL;246282247283 switch (evt->event) {248284 case IB_CM_REQ_RECEIVED:249249- ib_ucm_event_req_get(ctx, &uvt->resp.u.req_resp,285285+ ib_ucm_event_req_get(&uvt->resp.u.req_resp,250286 &evt->param.req_rcvd);251287 uvt->data_len = IB_CM_REQ_PRIVATE_DATA_SIZE;252288 uvt->resp.present = IB_UCM_PRES_PRIMARY;···293331 info = evt->param.apr_rcvd.apr_info;294332 break;295333 case IB_CM_SIDR_REQ_RECEIVED:296296- ib_ucm_event_sidr_req_get(ctx, &uvt->resp.u.sidr_req_resp,297297- &evt->param.sidr_req_rcvd);334334+ uvt->resp.u.sidr_req_resp.pkey = 335335+ evt->param.sidr_req_rcvd.pkey;298336 uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE;299337 break;300338 case IB_CM_SIDR_REP_RECEIVED:···340378 struct ib_ucm_event *uevent;341379 struct ib_ucm_context *ctx;342380 int result = 0;343343- int id;344381345382 ctx = cm_id->context;346346-347347- if (event->event == IB_CM_REQ_RECEIVED ||348348- event->event == IB_CM_SIDR_REQ_RECEIVED)349349- id = IB_UCM_CM_ID_INVALID;350350- else351351- id = ctx->id;352383353384 uevent = kmalloc(sizeof(*uevent), GFP_KERNEL);354385 if (!uevent)355386 goto err1;356387357388 memset(uevent, 0, sizeof(*uevent));358358- uevent->resp.id = id;389389+ uevent->ctx = ctx;390390+ uevent->cm_id = cm_id;391391+ uevent->resp.uid = ctx->uid;392392+ uevent->resp.id = ctx->id;359393 uevent->resp.event = event->event;360394361361- result = ib_ucm_event_process(ctx, event, uevent);395395+ result = ib_ucm_event_process(event, uevent);362396 if (result)363397 goto err2;364364-365365- uevent->ctx = ctx;366366- uevent->cm_id = (id == IB_UCM_CM_ID_INVALID) ? cm_id : NULL;367398368399 down(&ctx->file->mutex);369400 list_add_tail(&uevent->file_list, &ctx->file->events);···369414 kfree(uevent);370415err1:371416 /* Destroy new cm_id's */372372- return (id == IB_UCM_CM_ID_INVALID);417417+ return ib_ucm_new_cm_id(event->event);373418}374419375420static ssize_t ib_ucm_event(struct ib_ucm_file *file,···378423{379424 struct ib_ucm_context *ctx;380425 struct ib_ucm_event_get cmd;381381- struct ib_ucm_event *uevent = NULL;426426+ struct ib_ucm_event *uevent;382427 int result = 0;383428 DEFINE_WAIT(wait);384429···391436 * wait392437 */393438 down(&file->mutex);394394-395439 while (list_empty(&file->events)) {396440397441 if (file->filp->f_flags & O_NONBLOCK) {···417463418464 uevent = list_entry(file->events.next, struct ib_ucm_event, file_list);419465420420- if (!uevent->cm_id)421421- goto user;466466+ if (ib_ucm_new_cm_id(uevent->resp.event)) {467467+ ctx = ib_ucm_ctx_alloc(file);468468+ if (!ctx) {469469+ result = -ENOMEM;470470+ goto done;471471+ }422472423423- ctx = ib_ucm_ctx_alloc(file);424424- if (!ctx) {425425- result = -ENOMEM;426426- goto done;473473+ ctx->cm_id = uevent->cm_id;474474+ ctx->cm_id->context = ctx;475475+ uevent->resp.id = ctx->id;427476 }428477429429- ctx->cm_id = uevent->cm_id;430430- ctx->cm_id->context = ctx;431431-432432- uevent->resp.id = ctx->id;433433-434434-user:435478 if (copy_to_user((void __user *)(unsigned long)cmd.response,436479 &uevent->resp, sizeof(uevent->resp))) {437480 result = -EFAULT;···436485 }437486438487 if (uevent->data) {439439-440488 if (cmd.data_len < uevent->data_len) {441489 result = -ENOMEM;442490 goto done;443491 }444444-445492 if (copy_to_user((void __user *)(unsigned long)cmd.data,446493 uevent->data, uevent->data_len)) {447494 result = -EFAULT;···448499 }449500450501 if (uevent->info) {451451-452502 if (cmd.info_len < uevent->info_len) {453503 result = -ENOMEM;454504 goto done;455505 }456456-457506 if (copy_to_user((void __user *)(unsigned long)cmd.info,458507 uevent->info, uevent->info_len)) {459508 result = -EFAULT;···461514462515 list_del(&uevent->file_list);463516 list_del(&uevent->ctx_list);517517+ uevent->ctx->events_reported++;464518465519 kfree(uevent->data);466520 kfree(uevent->info);···493545 if (!ctx)494546 return -ENOMEM;495547548548+ ctx->uid = cmd.uid;496549 ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx);497550 if (IS_ERR(ctx->cm_id)) {498551 result = PTR_ERR(ctx->cm_id);···510561 return 0;511562512563err:513513- ib_ucm_destroy_ctx(file, ctx->id);564564+ down(&ctx_id_mutex);565565+ idr_remove(&ctx_id_table, ctx->id);566566+ up(&ctx_id_mutex);567567+568568+ if (!IS_ERR(ctx->cm_id))569569+ ib_destroy_cm_id(ctx->cm_id);570570+571571+ kfree(ctx);514572 return result;515573}516574···526570 int in_len, int out_len)527571{528572 struct ib_ucm_destroy_id cmd;573573+ struct ib_ucm_destroy_id_resp resp;574574+ struct ib_ucm_context *ctx;575575+ int result = 0;576576+577577+ if (out_len < sizeof(resp))578578+ return -ENOSPC;529579530580 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))531581 return -EFAULT;532582533533- return ib_ucm_destroy_ctx(file, cmd.id);583583+ down(&ctx_id_mutex);584584+ ctx = idr_find(&ctx_id_table, cmd.id);585585+ if (!ctx)586586+ ctx = ERR_PTR(-ENOENT);587587+ else if (ctx->file != file)588588+ ctx = ERR_PTR(-EINVAL);589589+ else590590+ idr_remove(&ctx_id_table, ctx->id);591591+ up(&ctx_id_mutex);592592+593593+ if (IS_ERR(ctx))594594+ return PTR_ERR(ctx);595595+596596+ atomic_dec(&ctx->ref);597597+ wait_event(ctx->wait, !atomic_read(&ctx->ref));598598+599599+ /* No new events will be generated after destroying the cm_id. */600600+ ib_destroy_cm_id(ctx->cm_id);601601+ /* Cleanup events not yet reported to the user. */602602+ ib_ucm_cleanup_events(ctx);603603+604604+ resp.events_reported = ctx->events_reported;605605+ if (copy_to_user((void __user *)(unsigned long)cmd.response,606606+ &resp, sizeof(resp)))607607+ result = -EFAULT;608608+609609+ kfree(ctx);610610+ return result;534611}535612536613static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,···594605 &resp, sizeof(resp)))595606 result = -EFAULT;596607608608+ ib_ucm_ctx_put(ctx);609609+ return result;610610+}611611+612612+static void ib_ucm_copy_ah_attr(struct ib_ucm_ah_attr *dest_attr,613613+ struct ib_ah_attr *src_attr)614614+{615615+ memcpy(dest_attr->grh_dgid, src_attr->grh.dgid.raw,616616+ sizeof src_attr->grh.dgid);617617+ dest_attr->grh_flow_label = src_attr->grh.flow_label;618618+ dest_attr->grh_sgid_index = src_attr->grh.sgid_index;619619+ dest_attr->grh_hop_limit = src_attr->grh.hop_limit;620620+ dest_attr->grh_traffic_class = src_attr->grh.traffic_class;621621+622622+ dest_attr->dlid = src_attr->dlid;623623+ dest_attr->sl = src_attr->sl;624624+ dest_attr->src_path_bits = src_attr->src_path_bits;625625+ dest_attr->static_rate = src_attr->static_rate;626626+ dest_attr->is_global = (src_attr->ah_flags & IB_AH_GRH);627627+ dest_attr->port_num = src_attr->port_num;628628+}629629+630630+static void ib_ucm_copy_qp_attr(struct ib_ucm_init_qp_attr_resp *dest_attr,631631+ struct ib_qp_attr *src_attr)632632+{633633+ dest_attr->cur_qp_state = src_attr->cur_qp_state;634634+ dest_attr->path_mtu = src_attr->path_mtu;635635+ dest_attr->path_mig_state = src_attr->path_mig_state;636636+ dest_attr->qkey = src_attr->qkey;637637+ dest_attr->rq_psn = src_attr->rq_psn;638638+ dest_attr->sq_psn = src_attr->sq_psn;639639+ dest_attr->dest_qp_num = src_attr->dest_qp_num;640640+ dest_attr->qp_access_flags = src_attr->qp_access_flags;641641+642642+ dest_attr->max_send_wr = src_attr->cap.max_send_wr;643643+ dest_attr->max_recv_wr = src_attr->cap.max_recv_wr;644644+ dest_attr->max_send_sge = src_attr->cap.max_send_sge;645645+ dest_attr->max_recv_sge = src_attr->cap.max_recv_sge;646646+ dest_attr->max_inline_data = src_attr->cap.max_inline_data;647647+648648+ ib_ucm_copy_ah_attr(&dest_attr->ah_attr, &src_attr->ah_attr);649649+ ib_ucm_copy_ah_attr(&dest_attr->alt_ah_attr, &src_attr->alt_ah_attr);650650+651651+ dest_attr->pkey_index = src_attr->pkey_index;652652+ dest_attr->alt_pkey_index = src_attr->alt_pkey_index;653653+ dest_attr->en_sqd_async_notify = src_attr->en_sqd_async_notify;654654+ dest_attr->sq_draining = src_attr->sq_draining;655655+ dest_attr->max_rd_atomic = src_attr->max_rd_atomic;656656+ dest_attr->max_dest_rd_atomic = src_attr->max_dest_rd_atomic;657657+ dest_attr->min_rnr_timer = src_attr->min_rnr_timer;658658+ dest_attr->port_num = src_attr->port_num;659659+ dest_attr->timeout = src_attr->timeout;660660+ dest_attr->retry_cnt = src_attr->retry_cnt;661661+ dest_attr->rnr_retry = src_attr->rnr_retry;662662+ dest_attr->alt_port_num = src_attr->alt_port_num;663663+ dest_attr->alt_timeout = src_attr->alt_timeout;664664+}665665+666666+static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file,667667+ const char __user *inbuf,668668+ int in_len, int out_len)669669+{670670+ struct ib_ucm_init_qp_attr_resp resp;671671+ struct ib_ucm_init_qp_attr cmd;672672+ struct ib_ucm_context *ctx;673673+ struct ib_qp_attr qp_attr;674674+ int result = 0;675675+676676+ if (out_len < sizeof(resp))677677+ return -ENOSPC;678678+679679+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))680680+ return -EFAULT;681681+682682+ ctx = ib_ucm_ctx_get(file, cmd.id);683683+ if (IS_ERR(ctx))684684+ return PTR_ERR(ctx);685685+686686+ resp.qp_attr_mask = 0;687687+ memset(&qp_attr, 0, sizeof qp_attr);688688+ qp_attr.qp_state = cmd.qp_state;689689+ result = ib_cm_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask);690690+ if (result)691691+ goto out;692692+693693+ ib_ucm_copy_qp_attr(&resp, &qp_attr);694694+695695+ if (copy_to_user((void __user *)(unsigned long)cmd.response,696696+ &resp, sizeof(resp)))697697+ result = -EFAULT;698698+699699+out:597700 ib_ucm_ctx_put(ctx);598701 return result;599702}···889808890809 ctx = ib_ucm_ctx_get(file, cmd.id);891810 if (!IS_ERR(ctx)) {811811+ ctx->uid = cmd.uid;892812 result = ib_send_cm_rep(ctx->cm_id, ¶m);893813 ib_ucm_ctx_put(ctx);894814 } else···11681086 [IB_USER_CM_CMD_SEND_SIDR_REQ] = ib_ucm_send_sidr_req,11691087 [IB_USER_CM_CMD_SEND_SIDR_REP] = ib_ucm_send_sidr_rep,11701088 [IB_USER_CM_CMD_EVENT] = ib_ucm_event,10891089+ [IB_USER_CM_CMD_INIT_QP_ATTR] = ib_ucm_init_qp_attr,11711090};1172109111731092static ssize_t ib_ucm_write(struct file *filp, const char __user *buf,···1244116112451162 down(&file->mutex);12461163 while (!list_empty(&file->ctxs)) {12471247-12481164 ctx = list_entry(file->ctxs.next,12491165 struct ib_ucm_context, file_list);12501250-12511166 up(&file->mutex);12521252- ib_ucm_destroy_ctx(file, ctx->id);11671167+11681168+ down(&ctx_id_mutex);11691169+ idr_remove(&ctx_id_table, ctx->id);11701170+ up(&ctx_id_mutex);11711171+11721172+ ib_destroy_cm_id(ctx->cm_id);11731173+ ib_ucm_cleanup_events(ctx);11741174+ kfree(ctx);11751175+12531176 down(&file->mutex);12541177 }12551178 up(&file->mutex);
+4-7
drivers/infiniband/core/ucm.h
···11/*22 * Copyright (c) 2005 Topspin Communications. All rights reserved.33+ * Copyright (c) 2005 Intel Corporation. All rights reserved.34 *45 * This software is available to you under a choice of one of two56 * licenses. You may choose to be licensed under the terms of the GNU···4443#include <rdma/ib_cm.h>4544#include <rdma/ib_user_cm.h>46454747-#define IB_UCM_CM_ID_INVALID 0xffffffff4848-4946struct ib_ucm_file {5047 struct semaphore mutex;5148 struct file *filp;···5758 int id;5859 wait_queue_head_t wait;5960 atomic_t ref;6161+ int events_reported;60626163 struct ib_ucm_file *file;6264 struct ib_cm_id *cm_id;6565+ __u64 uid;63666467 struct list_head events; /* list of pending events. */6568 struct list_head file_list; /* member in file ctx list */···7271 struct list_head file_list; /* member in file event list */7372 struct list_head ctx_list; /* member in ctx event list */74737474+ struct ib_cm_id *cm_id;7575 struct ib_ucm_event_resp resp;7676 void *data;7777 void *info;7878 int data_len;7979 int info_len;8080- /*8181- * new connection identifiers needs to be saved until8282- * userspace can get a handle on them.8383- */8484- struct ib_cm_id *cm_id;8580};86818782#endif /* UCM_H */