提交 504255f8 编写于 作者: R Roland Dreier

Merge branches 'amso1100', 'cma', 'cxgb3', 'cxgb4', 'fdr', 'ipath', 'ipoib',...

Merge branches 'amso1100', 'cma', 'cxgb3', 'cxgb4', 'fdr', 'ipath', 'ipoib', 'misc', 'mlx4', 'misc', 'nes', 'qib' and 'xrc' into for-next
...@@ -889,6 +889,8 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err) ...@@ -889,6 +889,8 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
break; break;
case IB_CM_ESTABLISHED: case IB_CM_ESTABLISHED:
spin_unlock_irq(&cm_id_priv->lock); spin_unlock_irq(&cm_id_priv->lock);
if (cm_id_priv->qp_type == IB_QPT_XRC_TGT)
break;
ib_send_cm_dreq(cm_id, NULL, 0); ib_send_cm_dreq(cm_id, NULL, 0);
goto retest; goto retest;
case IB_CM_DREQ_SENT: case IB_CM_DREQ_SENT:
...@@ -1008,7 +1010,6 @@ static void cm_format_req(struct cm_req_msg *req_msg, ...@@ -1008,7 +1010,6 @@ static void cm_format_req(struct cm_req_msg *req_msg,
req_msg->service_id = param->service_id; req_msg->service_id = param->service_id;
req_msg->local_ca_guid = cm_id_priv->id.device->node_guid; req_msg->local_ca_guid = cm_id_priv->id.device->node_guid;
cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num)); cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num));
cm_req_set_resp_res(req_msg, param->responder_resources);
cm_req_set_init_depth(req_msg, param->initiator_depth); cm_req_set_init_depth(req_msg, param->initiator_depth);
cm_req_set_remote_resp_timeout(req_msg, cm_req_set_remote_resp_timeout(req_msg,
param->remote_cm_response_timeout); param->remote_cm_response_timeout);
...@@ -1017,12 +1018,16 @@ static void cm_format_req(struct cm_req_msg *req_msg, ...@@ -1017,12 +1018,16 @@ static void cm_format_req(struct cm_req_msg *req_msg,
cm_req_set_starting_psn(req_msg, cpu_to_be32(param->starting_psn)); cm_req_set_starting_psn(req_msg, cpu_to_be32(param->starting_psn));
cm_req_set_local_resp_timeout(req_msg, cm_req_set_local_resp_timeout(req_msg,
param->local_cm_response_timeout); param->local_cm_response_timeout);
cm_req_set_retry_count(req_msg, param->retry_count);
req_msg->pkey = param->primary_path->pkey; req_msg->pkey = param->primary_path->pkey;
cm_req_set_path_mtu(req_msg, param->primary_path->mtu); cm_req_set_path_mtu(req_msg, param->primary_path->mtu);
cm_req_set_rnr_retry_count(req_msg, param->rnr_retry_count);
cm_req_set_max_cm_retries(req_msg, param->max_cm_retries); cm_req_set_max_cm_retries(req_msg, param->max_cm_retries);
if (param->qp_type != IB_QPT_XRC_INI) {
cm_req_set_resp_res(req_msg, param->responder_resources);
cm_req_set_retry_count(req_msg, param->retry_count);
cm_req_set_rnr_retry_count(req_msg, param->rnr_retry_count);
cm_req_set_srq(req_msg, param->srq); cm_req_set_srq(req_msg, param->srq);
}
if (pri_path->hop_limit <= 1) { if (pri_path->hop_limit <= 1) {
req_msg->primary_local_lid = pri_path->slid; req_msg->primary_local_lid = pri_path->slid;
...@@ -1080,7 +1085,8 @@ static int cm_validate_req_param(struct ib_cm_req_param *param) ...@@ -1080,7 +1085,8 @@ static int cm_validate_req_param(struct ib_cm_req_param *param)
if (!param->primary_path) if (!param->primary_path)
return -EINVAL; return -EINVAL;
if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC) if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC &&
param->qp_type != IB_QPT_XRC_INI)
return -EINVAL; return -EINVAL;
if (param->private_data && if (param->private_data &&
...@@ -1601,18 +1607,24 @@ static void cm_format_rep(struct cm_rep_msg *rep_msg, ...@@ -1601,18 +1607,24 @@ static void cm_format_rep(struct cm_rep_msg *rep_msg,
cm_format_mad_hdr(&rep_msg->hdr, CM_REP_ATTR_ID, cm_id_priv->tid); cm_format_mad_hdr(&rep_msg->hdr, CM_REP_ATTR_ID, cm_id_priv->tid);
rep_msg->local_comm_id = cm_id_priv->id.local_id; rep_msg->local_comm_id = cm_id_priv->id.local_id;
rep_msg->remote_comm_id = cm_id_priv->id.remote_id; rep_msg->remote_comm_id = cm_id_priv->id.remote_id;
cm_rep_set_local_qpn(rep_msg, cpu_to_be32(param->qp_num));
cm_rep_set_starting_psn(rep_msg, cpu_to_be32(param->starting_psn)); cm_rep_set_starting_psn(rep_msg, cpu_to_be32(param->starting_psn));
rep_msg->resp_resources = param->responder_resources; rep_msg->resp_resources = param->responder_resources;
rep_msg->initiator_depth = param->initiator_depth;
cm_rep_set_target_ack_delay(rep_msg, cm_rep_set_target_ack_delay(rep_msg,
cm_id_priv->av.port->cm_dev->ack_delay); cm_id_priv->av.port->cm_dev->ack_delay);
cm_rep_set_failover(rep_msg, param->failover_accepted); cm_rep_set_failover(rep_msg, param->failover_accepted);
cm_rep_set_flow_ctrl(rep_msg, param->flow_control);
cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count); cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count);
cm_rep_set_srq(rep_msg, param->srq);
rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid; rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid;
if (cm_id_priv->qp_type != IB_QPT_XRC_TGT) {
rep_msg->initiator_depth = param->initiator_depth;
cm_rep_set_flow_ctrl(rep_msg, param->flow_control);
cm_rep_set_srq(rep_msg, param->srq);
cm_rep_set_local_qpn(rep_msg, cpu_to_be32(param->qp_num));
} else {
cm_rep_set_srq(rep_msg, 1);
cm_rep_set_local_eecn(rep_msg, cpu_to_be32(param->qp_num));
}
if (param->private_data && param->private_data_len) if (param->private_data && param->private_data_len)
memcpy(rep_msg->private_data, param->private_data, memcpy(rep_msg->private_data, param->private_data,
param->private_data_len); param->private_data_len);
...@@ -1660,7 +1672,7 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, ...@@ -1660,7 +1672,7 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id,
cm_id_priv->initiator_depth = param->initiator_depth; cm_id_priv->initiator_depth = param->initiator_depth;
cm_id_priv->responder_resources = param->responder_resources; cm_id_priv->responder_resources = param->responder_resources;
cm_id_priv->rq_psn = cm_rep_get_starting_psn(rep_msg); cm_id_priv->rq_psn = cm_rep_get_starting_psn(rep_msg);
cm_id_priv->local_qpn = cm_rep_get_local_qpn(rep_msg); cm_id_priv->local_qpn = cpu_to_be32(param->qp_num & 0xFFFFFF);
out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); out: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
return ret; return ret;
...@@ -1731,7 +1743,7 @@ error: spin_unlock_irqrestore(&cm_id_priv->lock, flags); ...@@ -1731,7 +1743,7 @@ error: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
} }
EXPORT_SYMBOL(ib_send_cm_rtu); EXPORT_SYMBOL(ib_send_cm_rtu);
static void cm_format_rep_event(struct cm_work *work) static void cm_format_rep_event(struct cm_work *work, enum ib_qp_type qp_type)
{ {
struct cm_rep_msg *rep_msg; struct cm_rep_msg *rep_msg;
struct ib_cm_rep_event_param *param; struct ib_cm_rep_event_param *param;
...@@ -1740,7 +1752,7 @@ static void cm_format_rep_event(struct cm_work *work) ...@@ -1740,7 +1752,7 @@ static void cm_format_rep_event(struct cm_work *work)
param = &work->cm_event.param.rep_rcvd; param = &work->cm_event.param.rep_rcvd;
param->remote_ca_guid = rep_msg->local_ca_guid; param->remote_ca_guid = rep_msg->local_ca_guid;
param->remote_qkey = be32_to_cpu(rep_msg->local_qkey); param->remote_qkey = be32_to_cpu(rep_msg->local_qkey);
param->remote_qpn = be32_to_cpu(cm_rep_get_local_qpn(rep_msg)); param->remote_qpn = be32_to_cpu(cm_rep_get_qpn(rep_msg, qp_type));
param->starting_psn = be32_to_cpu(cm_rep_get_starting_psn(rep_msg)); param->starting_psn = be32_to_cpu(cm_rep_get_starting_psn(rep_msg));
param->responder_resources = rep_msg->initiator_depth; param->responder_resources = rep_msg->initiator_depth;
param->initiator_depth = rep_msg->resp_resources; param->initiator_depth = rep_msg->resp_resources;
...@@ -1808,7 +1820,7 @@ static int cm_rep_handler(struct cm_work *work) ...@@ -1808,7 +1820,7 @@ static int cm_rep_handler(struct cm_work *work)
return -EINVAL; return -EINVAL;
} }
cm_format_rep_event(work); cm_format_rep_event(work, cm_id_priv->qp_type);
spin_lock_irq(&cm_id_priv->lock); spin_lock_irq(&cm_id_priv->lock);
switch (cm_id_priv->id.state) { switch (cm_id_priv->id.state) {
...@@ -1823,7 +1835,7 @@ static int cm_rep_handler(struct cm_work *work) ...@@ -1823,7 +1835,7 @@ static int cm_rep_handler(struct cm_work *work)
cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id; cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid; cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg); cm_id_priv->timewait_info->remote_qpn = cm_rep_get_qpn(rep_msg, cm_id_priv->qp_type);
spin_lock(&cm.lock); spin_lock(&cm.lock);
/* Check for duplicate REP. */ /* Check for duplicate REP. */
...@@ -1850,7 +1862,7 @@ static int cm_rep_handler(struct cm_work *work) ...@@ -1850,7 +1862,7 @@ static int cm_rep_handler(struct cm_work *work)
cm_id_priv->id.state = IB_CM_REP_RCVD; cm_id_priv->id.state = IB_CM_REP_RCVD;
cm_id_priv->id.remote_id = rep_msg->local_comm_id; cm_id_priv->id.remote_id = rep_msg->local_comm_id;
cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg); cm_id_priv->remote_qpn = cm_rep_get_qpn(rep_msg, cm_id_priv->qp_type);
cm_id_priv->initiator_depth = rep_msg->resp_resources; cm_id_priv->initiator_depth = rep_msg->resp_resources;
cm_id_priv->responder_resources = rep_msg->initiator_depth; cm_id_priv->responder_resources = rep_msg->initiator_depth;
cm_id_priv->sq_psn = cm_rep_get_starting_psn(rep_msg); cm_id_priv->sq_psn = cm_rep_get_starting_psn(rep_msg);
...@@ -3492,7 +3504,8 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv, ...@@ -3492,7 +3504,8 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
qp_attr->path_mtu = cm_id_priv->path_mtu; qp_attr->path_mtu = cm_id_priv->path_mtu;
qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn); qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn);
qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn); qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn);
if (cm_id_priv->qp_type == IB_QPT_RC) { if (cm_id_priv->qp_type == IB_QPT_RC ||
cm_id_priv->qp_type == IB_QPT_XRC_TGT) {
*qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC | *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC |
IB_QP_MIN_RNR_TIMER; IB_QP_MIN_RNR_TIMER;
qp_attr->max_dest_rd_atomic = qp_attr->max_dest_rd_atomic =
...@@ -3537,15 +3550,21 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv, ...@@ -3537,15 +3550,21 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT) { if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT) {
*qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN;
qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn); qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn);
if (cm_id_priv->qp_type == IB_QPT_RC) { switch (cm_id_priv->qp_type) {
*qp_attr_mask |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | case IB_QPT_RC:
IB_QP_RNR_RETRY | case IB_QPT_XRC_INI:
*qp_attr_mask |= IB_QP_RETRY_CNT | IB_QP_RNR_RETRY |
IB_QP_MAX_QP_RD_ATOMIC; IB_QP_MAX_QP_RD_ATOMIC;
qp_attr->timeout = cm_id_priv->av.timeout;
qp_attr->retry_cnt = cm_id_priv->retry_count; qp_attr->retry_cnt = cm_id_priv->retry_count;
qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; qp_attr->rnr_retry = cm_id_priv->rnr_retry_count;
qp_attr->max_rd_atomic = qp_attr->max_rd_atomic = cm_id_priv->initiator_depth;
cm_id_priv->initiator_depth; /* fall through */
case IB_QPT_XRC_TGT:
*qp_attr_mask |= IB_QP_TIMEOUT;
qp_attr->timeout = cm_id_priv->av.timeout;
break;
default:
break;
} }
if (cm_id_priv->alt_av.ah_attr.dlid) { if (cm_id_priv->alt_av.ah_attr.dlid) {
*qp_attr_mask |= IB_QP_PATH_MIG_STATE; *qp_attr_mask |= IB_QP_PATH_MIG_STATE;
......
/* /*
* Copyright (c) 2004 Intel Corporation. All rights reserved. * Copyright (c) 2004, 2011 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004 Voltaire Corporation. All rights reserved. * Copyright (c) 2004 Voltaire Corporation. All rights reserved.
* *
...@@ -86,7 +86,7 @@ struct cm_req_msg { ...@@ -86,7 +86,7 @@ struct cm_req_msg {
__be16 pkey; __be16 pkey;
/* path MTU:4, RDC exists:1, RNR retry count:3. */ /* path MTU:4, RDC exists:1, RNR retry count:3. */
u8 offset50; u8 offset50;
/* max CM Retries:4, SRQ:1, rsvd:3 */ /* max CM Retries:4, SRQ:1, extended transport type:3 */
u8 offset51; u8 offset51;
__be16 primary_local_lid; __be16 primary_local_lid;
...@@ -175,6 +175,11 @@ static inline enum ib_qp_type cm_req_get_qp_type(struct cm_req_msg *req_msg) ...@@ -175,6 +175,11 @@ static inline enum ib_qp_type cm_req_get_qp_type(struct cm_req_msg *req_msg)
switch(transport_type) { switch(transport_type) {
case 0: return IB_QPT_RC; case 0: return IB_QPT_RC;
case 1: return IB_QPT_UC; case 1: return IB_QPT_UC;
case 3:
switch (req_msg->offset51 & 0x7) {
case 1: return IB_QPT_XRC_TGT;
default: return 0;
}
default: return 0; default: return 0;
} }
} }
...@@ -188,6 +193,12 @@ static inline void cm_req_set_qp_type(struct cm_req_msg *req_msg, ...@@ -188,6 +193,12 @@ static inline void cm_req_set_qp_type(struct cm_req_msg *req_msg,
req_msg->offset40) & req_msg->offset40) &
0xFFFFFFF9) | 0x2); 0xFFFFFFF9) | 0x2);
break; break;
case IB_QPT_XRC_INI:
req_msg->offset40 = cpu_to_be32((be32_to_cpu(
req_msg->offset40) &
0xFFFFFFF9) | 0x6);
req_msg->offset51 = (req_msg->offset51 & 0xF8) | 1;
break;
default: default:
req_msg->offset40 = cpu_to_be32(be32_to_cpu( req_msg->offset40 = cpu_to_be32(be32_to_cpu(
req_msg->offset40) & req_msg->offset40) &
...@@ -527,6 +538,23 @@ static inline void cm_rep_set_local_qpn(struct cm_rep_msg *rep_msg, __be32 qpn) ...@@ -527,6 +538,23 @@ static inline void cm_rep_set_local_qpn(struct cm_rep_msg *rep_msg, __be32 qpn)
(be32_to_cpu(rep_msg->offset12) & 0x000000FF)); (be32_to_cpu(rep_msg->offset12) & 0x000000FF));
} }
static inline __be32 cm_rep_get_local_eecn(struct cm_rep_msg *rep_msg)
{
return cpu_to_be32(be32_to_cpu(rep_msg->offset16) >> 8);
}
static inline void cm_rep_set_local_eecn(struct cm_rep_msg *rep_msg, __be32 eecn)
{
rep_msg->offset16 = cpu_to_be32((be32_to_cpu(eecn) << 8) |
(be32_to_cpu(rep_msg->offset16) & 0x000000FF));
}
static inline __be32 cm_rep_get_qpn(struct cm_rep_msg *rep_msg, enum ib_qp_type qp_type)
{
return (qp_type == IB_QPT_XRC_INI) ?
cm_rep_get_local_eecn(rep_msg) : cm_rep_get_local_qpn(rep_msg);
}
static inline __be32 cm_rep_get_starting_psn(struct cm_rep_msg *rep_msg) static inline __be32 cm_rep_get_starting_psn(struct cm_rep_msg *rep_msg)
{ {
return cpu_to_be32(be32_to_cpu(rep_msg->offset20) >> 8); return cpu_to_be32(be32_to_cpu(rep_msg->offset20) >> 8);
......
...@@ -81,6 +81,7 @@ static DEFINE_IDR(sdp_ps); ...@@ -81,6 +81,7 @@ static DEFINE_IDR(sdp_ps);
static DEFINE_IDR(tcp_ps); static DEFINE_IDR(tcp_ps);
static DEFINE_IDR(udp_ps); static DEFINE_IDR(udp_ps);
static DEFINE_IDR(ipoib_ps); static DEFINE_IDR(ipoib_ps);
static DEFINE_IDR(ib_ps);
struct cma_device { struct cma_device {
struct list_head list; struct list_head list;
...@@ -1179,6 +1180,15 @@ static void cma_set_req_event_data(struct rdma_cm_event *event, ...@@ -1179,6 +1180,15 @@ static void cma_set_req_event_data(struct rdma_cm_event *event,
event->param.conn.qp_num = req_data->remote_qpn; event->param.conn.qp_num = req_data->remote_qpn;
} }
static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event)
{
return (((ib_event->event == IB_CM_REQ_RECEIVED) ||
(ib_event->param.req_rcvd.qp_type == id->qp_type)) ||
((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) &&
(id->qp_type == IB_QPT_UD)) ||
(!id->qp_type));
}
static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
{ {
struct rdma_id_private *listen_id, *conn_id; struct rdma_id_private *listen_id, *conn_id;
...@@ -1186,13 +1196,16 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) ...@@ -1186,13 +1196,16 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
int offset, ret; int offset, ret;
listen_id = cm_id->context; listen_id = cm_id->context;
if (!cma_check_req_qp_type(&listen_id->id, ib_event))
return -EINVAL;
if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
return -ECONNABORTED; return -ECONNABORTED;
memset(&event, 0, sizeof event); memset(&event, 0, sizeof event);
offset = cma_user_data_offset(listen_id->id.ps); offset = cma_user_data_offset(listen_id->id.ps);
event.event = RDMA_CM_EVENT_CONNECT_REQUEST; event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
if (listen_id->id.qp_type == IB_QPT_UD) { if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
conn_id = cma_new_udp_id(&listen_id->id, ib_event); conn_id = cma_new_udp_id(&listen_id->id, ib_event);
event.param.ud.private_data = ib_event->private_data + offset; event.param.ud.private_data = ib_event->private_data + offset;
event.param.ud.private_data_len = event.param.ud.private_data_len =
...@@ -1328,6 +1341,8 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) ...@@ -1328,6 +1341,8 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
switch (iw_event->status) { switch (iw_event->status) {
case 0: case 0:
event.event = RDMA_CM_EVENT_ESTABLISHED; event.event = RDMA_CM_EVENT_ESTABLISHED;
event.param.conn.initiator_depth = iw_event->ird;
event.param.conn.responder_resources = iw_event->ord;
break; break;
case -ECONNRESET: case -ECONNRESET:
case -ECONNREFUSED: case -ECONNREFUSED:
...@@ -1343,6 +1358,8 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) ...@@ -1343,6 +1358,8 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
break; break;
case IW_CM_EVENT_ESTABLISHED: case IW_CM_EVENT_ESTABLISHED:
event.event = RDMA_CM_EVENT_ESTABLISHED; event.event = RDMA_CM_EVENT_ESTABLISHED;
event.param.conn.initiator_depth = iw_event->ird;
event.param.conn.responder_resources = iw_event->ord;
break; break;
default: default:
BUG_ON(1); BUG_ON(1);
...@@ -1433,8 +1450,8 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, ...@@ -1433,8 +1450,8 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
event.event = RDMA_CM_EVENT_CONNECT_REQUEST; event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
event.param.conn.private_data = iw_event->private_data; event.param.conn.private_data = iw_event->private_data;
event.param.conn.private_data_len = iw_event->private_data_len; event.param.conn.private_data_len = iw_event->private_data_len;
event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; event.param.conn.initiator_depth = iw_event->ird;
event.param.conn.responder_resources = attr.max_qp_rd_atom; event.param.conn.responder_resources = iw_event->ord;
/* /*
* Protect against the user destroying conn_id from another thread * Protect against the user destroying conn_id from another thread
...@@ -2234,6 +2251,9 @@ static int cma_get_port(struct rdma_id_private *id_priv) ...@@ -2234,6 +2251,9 @@ static int cma_get_port(struct rdma_id_private *id_priv)
case RDMA_PS_IPOIB: case RDMA_PS_IPOIB:
ps = &ipoib_ps; ps = &ipoib_ps;
break; break;
case RDMA_PS_IB:
ps = &ib_ps;
break;
default: default:
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
} }
...@@ -2569,7 +2589,7 @@ static int cma_connect_ib(struct rdma_id_private *id_priv, ...@@ -2569,7 +2589,7 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
req.service_id = cma_get_service_id(id_priv->id.ps, req.service_id = cma_get_service_id(id_priv->id.ps,
(struct sockaddr *) &route->addr.dst_addr); (struct sockaddr *) &route->addr.dst_addr);
req.qp_num = id_priv->qp_num; req.qp_num = id_priv->qp_num;
req.qp_type = IB_QPT_RC; req.qp_type = id_priv->id.qp_type;
req.starting_psn = id_priv->seq_num; req.starting_psn = id_priv->seq_num;
req.responder_resources = conn_param->responder_resources; req.responder_resources = conn_param->responder_resources;
req.initiator_depth = conn_param->initiator_depth; req.initiator_depth = conn_param->initiator_depth;
...@@ -2616,14 +2636,16 @@ static int cma_connect_iw(struct rdma_id_private *id_priv, ...@@ -2616,14 +2636,16 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
if (ret) if (ret)
goto out; goto out;
if (conn_param) {
iw_param.ord = conn_param->initiator_depth; iw_param.ord = conn_param->initiator_depth;
iw_param.ird = conn_param->responder_resources; iw_param.ird = conn_param->responder_resources;
iw_param.private_data = conn_param->private_data; iw_param.private_data = conn_param->private_data;
iw_param.private_data_len = conn_param->private_data_len; iw_param.private_data_len = conn_param->private_data_len;
if (id_priv->id.qp) iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num;
} else {
memset(&iw_param, 0, sizeof iw_param);
iw_param.qpn = id_priv->qp_num; iw_param.qpn = id_priv->qp_num;
else }
iw_param.qpn = conn_param->qp_num;
ret = iw_cm_connect(cm_id, &iw_param); ret = iw_cm_connect(cm_id, &iw_param);
out: out:
if (ret) { if (ret) {
...@@ -2765,14 +2787,20 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) ...@@ -2765,14 +2787,20 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
switch (rdma_node_get_transport(id->device->node_type)) { switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB: case RDMA_TRANSPORT_IB:
if (id->qp_type == IB_QPT_UD) if (id->qp_type == IB_QPT_UD) {
if (conn_param)
ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
conn_param->private_data, conn_param->private_data,
conn_param->private_data_len); conn_param->private_data_len);
else if (conn_param) else
ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
NULL, 0);
} else {
if (conn_param)
ret = cma_accept_ib(id_priv, conn_param); ret = cma_accept_ib(id_priv, conn_param);
else else
ret = cma_rep_recv(id_priv); ret = cma_rep_recv(id_priv);
}
break; break;
case RDMA_TRANSPORT_IWARP: case RDMA_TRANSPORT_IWARP:
ret = cma_accept_iw(id_priv, conn_param); ret = cma_accept_iw(id_priv, conn_param);
...@@ -3460,6 +3488,7 @@ static void __exit cma_cleanup(void) ...@@ -3460,6 +3488,7 @@ static void __exit cma_cleanup(void)
idr_destroy(&tcp_ps); idr_destroy(&tcp_ps);
idr_destroy(&udp_ps); idr_destroy(&udp_ps);
idr_destroy(&ipoib_ps); idr_destroy(&ipoib_ps);
idr_destroy(&ib_ps);
} }
module_init(cma_init); module_init(cma_init);
......
...@@ -1596,6 +1596,9 @@ find_mad_agent(struct ib_mad_port_private *port_priv, ...@@ -1596,6 +1596,9 @@ find_mad_agent(struct ib_mad_port_private *port_priv,
mad->mad_hdr.class_version].class; mad->mad_hdr.class_version].class;
if (!class) if (!class)
goto out; goto out;
if (convert_mgmt_class(mad->mad_hdr.mgmt_class) >=
IB_MGMT_MAX_METHODS)
goto out;
method = class->method_table[convert_mgmt_class( method = class->method_table[convert_mgmt_class(
mad->mad_hdr.mgmt_class)]; mad->mad_hdr.mgmt_class)];
if (method) if (method)
......
...@@ -185,17 +185,35 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, ...@@ -185,17 +185,35 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused,
if (ret) if (ret)
return ret; return ret;
rate = (25 * attr.active_speed) / 10;
switch (attr.active_speed) { switch (attr.active_speed) {
case 2: speed = " DDR"; break; case 2:
case 4: speed = " QDR"; break; speed = " DDR";
break;
case 4:
speed = " QDR";
break;
case 8:
speed = " FDR10";
rate = 10;
break;
case 16:
speed = " FDR";
rate = 14;
break;
case 32:
speed = " EDR";
rate = 25;
break;
} }
rate = 25 * ib_width_enum_to_int(attr.active_width) * attr.active_speed; rate *= ib_width_enum_to_int(attr.active_width);
if (rate < 0) if (rate < 0)
return -EINVAL; return -EINVAL;
return sprintf(buf, "%d%s Gb/sec (%dX%s)\n", return sprintf(buf, "%d%s Gb/sec (%dX%s)\n",
rate / 10, rate % 10 ? ".5" : "", rate, (attr.active_speed == 1) ? ".5" : "",
ib_width_enum_to_int(attr.active_width), speed); ib_width_enum_to_int(attr.active_width), speed);
} }
......
...@@ -1122,7 +1122,7 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, ...@@ -1122,7 +1122,7 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf,
if (copy_from_user(&hdr, buf, sizeof(hdr))) if (copy_from_user(&hdr, buf, sizeof(hdr)))
return -EFAULT; return -EFAULT;
if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucm_cmd_table)) if (hdr.cmd >= ARRAY_SIZE(ucm_cmd_table))
return -EINVAL; return -EINVAL;
if (hdr.in + sizeof(hdr) > len) if (hdr.in + sizeof(hdr) > len)
......
...@@ -276,7 +276,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, ...@@ -276,7 +276,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
ucma_set_event_context(ctx, event, uevent); ucma_set_event_context(ctx, event, uevent);
uevent->resp.event = event->event; uevent->resp.event = event->event;
uevent->resp.status = event->status; uevent->resp.status = event->status;
if (cm_id->ps == RDMA_PS_UDP || cm_id->ps == RDMA_PS_IPOIB) if (cm_id->qp_type == IB_QPT_UD)
ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud); ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud);
else else
ucma_copy_conn_event(&uevent->resp.param.conn, ucma_copy_conn_event(&uevent->resp.param.conn,
...@@ -377,6 +377,9 @@ static int ucma_get_qp_type(struct rdma_ucm_create_id *cmd, enum ib_qp_type *qp_ ...@@ -377,6 +377,9 @@ static int ucma_get_qp_type(struct rdma_ucm_create_id *cmd, enum ib_qp_type *qp_
case RDMA_PS_IPOIB: case RDMA_PS_IPOIB:
*qp_type = IB_QPT_UD; *qp_type = IB_QPT_UD;
return 0; return 0;
case RDMA_PS_IB:
*qp_type = cmd->qp_type;
return 0;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -1270,7 +1273,7 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf, ...@@ -1270,7 +1273,7 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf,
if (copy_from_user(&hdr, buf, sizeof(hdr))) if (copy_from_user(&hdr, buf, sizeof(hdr)))
return -EFAULT; return -EFAULT;
if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucma_cmd_table)) if (hdr.cmd >= ARRAY_SIZE(ucma_cmd_table))
return -EINVAL; return -EINVAL;
if (hdr.in + sizeof(hdr) > len) if (hdr.in + sizeof(hdr) > len)
......
...@@ -458,8 +458,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ...@@ -458,8 +458,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err; goto err;
} }
if (packet->mad.hdr.id < 0 || if (packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
...@@ -703,7 +702,7 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) ...@@ -703,7 +702,7 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
mutex_lock(&file->port->file_mutex); mutex_lock(&file->port->file_mutex);
mutex_lock(&file->mutex); mutex_lock(&file->mutex);
if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) { if (id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
......
...@@ -76,6 +76,8 @@ struct ib_uverbs_device { ...@@ -76,6 +76,8 @@ struct ib_uverbs_device {
struct ib_device *ib_dev; struct ib_device *ib_dev;
int devnum; int devnum;
struct cdev cdev; struct cdev cdev;
struct rb_root xrcd_tree;
struct mutex xrcd_tree_mutex;
}; };
struct ib_uverbs_event_file { struct ib_uverbs_event_file {
...@@ -120,6 +122,16 @@ struct ib_uevent_object { ...@@ -120,6 +122,16 @@ struct ib_uevent_object {
u32 events_reported; u32 events_reported;
}; };
struct ib_uxrcd_object {
struct ib_uobject uobject;
atomic_t refcnt;
};
struct ib_usrq_object {
struct ib_uevent_object uevent;
struct ib_uxrcd_object *uxrcd;
};
struct ib_uqp_object { struct ib_uqp_object {
struct ib_uevent_object uevent; struct ib_uevent_object uevent;
struct list_head mcast_list; struct list_head mcast_list;
...@@ -142,6 +154,7 @@ extern struct idr ib_uverbs_ah_idr; ...@@ -142,6 +154,7 @@ extern struct idr ib_uverbs_ah_idr;
extern struct idr ib_uverbs_cq_idr; extern struct idr ib_uverbs_cq_idr;
extern struct idr ib_uverbs_qp_idr; extern struct idr ib_uverbs_qp_idr;
extern struct idr ib_uverbs_srq_idr; extern struct idr ib_uverbs_srq_idr;
extern struct idr ib_uverbs_xrcd_idr;
void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
...@@ -161,6 +174,7 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); ...@@ -161,6 +174,7 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr); void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);
void ib_uverbs_event_handler(struct ib_event_handler *handler, void ib_uverbs_event_handler(struct ib_event_handler *handler,
struct ib_event *event); struct ib_event *event);
void ib_uverbs_dealloc_xrcd(struct ib_uverbs_device *dev, struct ib_xrcd *xrcd);
#define IB_UVERBS_DECLARE_CMD(name) \ #define IB_UVERBS_DECLARE_CMD(name) \
ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \ ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \
...@@ -181,6 +195,7 @@ IB_UVERBS_DECLARE_CMD(poll_cq); ...@@ -181,6 +195,7 @@ IB_UVERBS_DECLARE_CMD(poll_cq);
IB_UVERBS_DECLARE_CMD(req_notify_cq); IB_UVERBS_DECLARE_CMD(req_notify_cq);
IB_UVERBS_DECLARE_CMD(destroy_cq); IB_UVERBS_DECLARE_CMD(destroy_cq);
IB_UVERBS_DECLARE_CMD(create_qp); IB_UVERBS_DECLARE_CMD(create_qp);
IB_UVERBS_DECLARE_CMD(open_qp);
IB_UVERBS_DECLARE_CMD(query_qp); IB_UVERBS_DECLARE_CMD(query_qp);
IB_UVERBS_DECLARE_CMD(modify_qp); IB_UVERBS_DECLARE_CMD(modify_qp);
IB_UVERBS_DECLARE_CMD(destroy_qp); IB_UVERBS_DECLARE_CMD(destroy_qp);
...@@ -195,5 +210,8 @@ IB_UVERBS_DECLARE_CMD(create_srq); ...@@ -195,5 +210,8 @@ IB_UVERBS_DECLARE_CMD(create_srq);
IB_UVERBS_DECLARE_CMD(modify_srq); IB_UVERBS_DECLARE_CMD(modify_srq);
IB_UVERBS_DECLARE_CMD(query_srq); IB_UVERBS_DECLARE_CMD(query_srq);
IB_UVERBS_DECLARE_CMD(destroy_srq); IB_UVERBS_DECLARE_CMD(destroy_srq);
IB_UVERBS_DECLARE_CMD(create_xsrq);
IB_UVERBS_DECLARE_CMD(open_xrcd);
IB_UVERBS_DECLARE_CMD(close_xrcd);
#endif /* UVERBS_H */ #endif /* UVERBS_H */
...@@ -72,6 +72,7 @@ DEFINE_IDR(ib_uverbs_ah_idr); ...@@ -72,6 +72,7 @@ DEFINE_IDR(ib_uverbs_ah_idr);
DEFINE_IDR(ib_uverbs_cq_idr); DEFINE_IDR(ib_uverbs_cq_idr);
DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_qp_idr);
DEFINE_IDR(ib_uverbs_srq_idr); DEFINE_IDR(ib_uverbs_srq_idr);
DEFINE_IDR(ib_uverbs_xrcd_idr);
static DEFINE_SPINLOCK(map_lock); static DEFINE_SPINLOCK(map_lock);
static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
...@@ -107,6 +108,10 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, ...@@ -107,6 +108,10 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
[IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
[IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq, [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq,
[IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
[IB_USER_VERBS_CMD_OPEN_XRCD] = ib_uverbs_open_xrcd,
[IB_USER_VERBS_CMD_CLOSE_XRCD] = ib_uverbs_close_xrcd,
[IB_USER_VERBS_CMD_CREATE_XSRQ] = ib_uverbs_create_xsrq,
[IB_USER_VERBS_CMD_OPEN_QP] = ib_uverbs_open_qp
}; };
static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_add_one(struct ib_device *device);
...@@ -202,8 +207,12 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, ...@@ -202,8 +207,12 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
container_of(uobj, struct ib_uqp_object, uevent.uobject); container_of(uobj, struct ib_uqp_object, uevent.uobject);
idr_remove_uobj(&ib_uverbs_qp_idr, uobj); idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
if (qp != qp->real_qp) {
ib_close_qp(qp);
} else {
ib_uverbs_detach_umcast(qp, uqp); ib_uverbs_detach_umcast(qp, uqp);
ib_destroy_qp(qp); ib_destroy_qp(qp);
}
ib_uverbs_release_uevent(file, &uqp->uevent); ib_uverbs_release_uevent(file, &uqp->uevent);
kfree(uqp); kfree(uqp);
} }
...@@ -241,6 +250,18 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, ...@@ -241,6 +250,18 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
kfree(uobj); kfree(uobj);
} }
mutex_lock(&file->device->xrcd_tree_mutex);
list_for_each_entry_safe(uobj, tmp, &context->xrcd_list, list) {
struct ib_xrcd *xrcd = uobj->object;
struct ib_uxrcd_object *uxrcd =
container_of(uobj, struct ib_uxrcd_object, uobject);
idr_remove_uobj(&ib_uverbs_xrcd_idr, uobj);
ib_uverbs_dealloc_xrcd(file->device, xrcd);
kfree(uxrcd);
}
mutex_unlock(&file->device->xrcd_tree_mutex);
list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
struct ib_pd *pd = uobj->object; struct ib_pd *pd = uobj->object;
...@@ -557,8 +578,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, ...@@ -557,8 +578,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
if (hdr.in_words * 4 != count) if (hdr.in_words * 4 != count)
return -EINVAL; return -EINVAL;
if (hdr.command < 0 || if (hdr.command >= ARRAY_SIZE(uverbs_cmd_table) ||
hdr.command >= ARRAY_SIZE(uverbs_cmd_table) ||
!uverbs_cmd_table[hdr.command]) !uverbs_cmd_table[hdr.command])
return -EINVAL; return -EINVAL;
...@@ -741,6 +761,8 @@ static void ib_uverbs_add_one(struct ib_device *device) ...@@ -741,6 +761,8 @@ static void ib_uverbs_add_one(struct ib_device *device)
kref_init(&uverbs_dev->ref); kref_init(&uverbs_dev->ref);
init_completion(&uverbs_dev->comp); init_completion(&uverbs_dev->comp);
uverbs_dev->xrcd_tree = RB_ROOT;
mutex_init(&uverbs_dev->xrcd_tree_mutex);
spin_lock(&map_lock); spin_lock(&map_lock);
devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h>
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <rdma/ib_cache.h> #include <rdma/ib_cache.h>
...@@ -77,6 +78,31 @@ enum ib_rate mult_to_ib_rate(int mult) ...@@ -77,6 +78,31 @@ enum ib_rate mult_to_ib_rate(int mult)
} }
EXPORT_SYMBOL(mult_to_ib_rate); EXPORT_SYMBOL(mult_to_ib_rate);
int ib_rate_to_mbps(enum ib_rate rate)
{
switch (rate) {
case IB_RATE_2_5_GBPS: return 2500;
case IB_RATE_5_GBPS: return 5000;
case IB_RATE_10_GBPS: return 10000;
case IB_RATE_20_GBPS: return 20000;
case IB_RATE_30_GBPS: return 30000;
case IB_RATE_40_GBPS: return 40000;
case IB_RATE_60_GBPS: return 60000;
case IB_RATE_80_GBPS: return 80000;
case IB_RATE_120_GBPS: return 120000;
case IB_RATE_14_GBPS: return 14062;
case IB_RATE_56_GBPS: return 56250;
case IB_RATE_112_GBPS: return 112500;
case IB_RATE_168_GBPS: return 168750;
case IB_RATE_25_GBPS: return 25781;
case IB_RATE_100_GBPS: return 103125;
case IB_RATE_200_GBPS: return 206250;
case IB_RATE_300_GBPS: return 309375;
default: return -1;
}
}
EXPORT_SYMBOL(ib_rate_to_mbps);
enum rdma_transport_type enum rdma_transport_type
rdma_node_get_transport(enum rdma_node_type node_type) rdma_node_get_transport(enum rdma_node_type node_type)
{ {
...@@ -250,6 +276,13 @@ struct ib_srq *ib_create_srq(struct ib_pd *pd, ...@@ -250,6 +276,13 @@ struct ib_srq *ib_create_srq(struct ib_pd *pd,
srq->uobject = NULL; srq->uobject = NULL;
srq->event_handler = srq_init_attr->event_handler; srq->event_handler = srq_init_attr->event_handler;
srq->srq_context = srq_init_attr->srq_context; srq->srq_context = srq_init_attr->srq_context;
srq->srq_type = srq_init_attr->srq_type;
if (srq->srq_type == IB_SRQT_XRC) {
srq->ext.xrc.xrcd = srq_init_attr->ext.xrc.xrcd;
srq->ext.xrc.cq = srq_init_attr->ext.xrc.cq;
atomic_inc(&srq->ext.xrc.xrcd->usecnt);
atomic_inc(&srq->ext.xrc.cq->usecnt);
}
atomic_inc(&pd->usecnt); atomic_inc(&pd->usecnt);
atomic_set(&srq->usecnt, 0); atomic_set(&srq->usecnt, 0);
} }
...@@ -279,16 +312,29 @@ EXPORT_SYMBOL(ib_query_srq); ...@@ -279,16 +312,29 @@ EXPORT_SYMBOL(ib_query_srq);
int ib_destroy_srq(struct ib_srq *srq) int ib_destroy_srq(struct ib_srq *srq)
{ {
struct ib_pd *pd; struct ib_pd *pd;
enum ib_srq_type srq_type;
struct ib_xrcd *uninitialized_var(xrcd);
struct ib_cq *uninitialized_var(cq);
int ret; int ret;
if (atomic_read(&srq->usecnt)) if (atomic_read(&srq->usecnt))
return -EBUSY; return -EBUSY;
pd = srq->pd; pd = srq->pd;
srq_type = srq->srq_type;
if (srq_type == IB_SRQT_XRC) {
xrcd = srq->ext.xrc.xrcd;
cq = srq->ext.xrc.cq;
}
ret = srq->device->destroy_srq(srq); ret = srq->device->destroy_srq(srq);
if (!ret) if (!ret) {
atomic_dec(&pd->usecnt); atomic_dec(&pd->usecnt);
if (srq_type == IB_SRQT_XRC) {
atomic_dec(&xrcd->usecnt);
atomic_dec(&cq->usecnt);
}
}
return ret; return ret;
} }
...@@ -296,38 +342,133 @@ EXPORT_SYMBOL(ib_destroy_srq); ...@@ -296,38 +342,133 @@ EXPORT_SYMBOL(ib_destroy_srq);
/* Queue pairs */ /* Queue pairs */
static void __ib_shared_qp_event_handler(struct ib_event *event, void *context)
{
struct ib_qp *qp = context;
list_for_each_entry(event->element.qp, &qp->open_list, open_list)
event->element.qp->event_handler(event, event->element.qp->qp_context);
}
static void __ib_insert_xrcd_qp(struct ib_xrcd *xrcd, struct ib_qp *qp)
{
mutex_lock(&xrcd->tgt_qp_mutex);
list_add(&qp->xrcd_list, &xrcd->tgt_qp_list);
mutex_unlock(&xrcd->tgt_qp_mutex);
}
static struct ib_qp *__ib_open_qp(struct ib_qp *real_qp,
void (*event_handler)(struct ib_event *, void *),
void *qp_context)
{
struct ib_qp *qp;
unsigned long flags;
qp = kzalloc(sizeof *qp, GFP_KERNEL);
if (!qp)
return ERR_PTR(-ENOMEM);
qp->real_qp = real_qp;
atomic_inc(&real_qp->usecnt);
qp->device = real_qp->device;
qp->event_handler = event_handler;
qp->qp_context = qp_context;
qp->qp_num = real_qp->qp_num;
qp->qp_type = real_qp->qp_type;
spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
list_add(&qp->open_list, &real_qp->open_list);
spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
return qp;
}
struct ib_qp *ib_open_qp(struct ib_xrcd *xrcd,
struct ib_qp_open_attr *qp_open_attr)
{
struct ib_qp *qp, *real_qp;
if (qp_open_attr->qp_type != IB_QPT_XRC_TGT)
return ERR_PTR(-EINVAL);
qp = ERR_PTR(-EINVAL);
mutex_lock(&xrcd->tgt_qp_mutex);
list_for_each_entry(real_qp, &xrcd->tgt_qp_list, xrcd_list) {
if (real_qp->qp_num == qp_open_attr->qp_num) {
qp = __ib_open_qp(real_qp, qp_open_attr->event_handler,
qp_open_attr->qp_context);
break;
}
}
mutex_unlock(&xrcd->tgt_qp_mutex);
return qp;
}
EXPORT_SYMBOL(ib_open_qp);
struct ib_qp *ib_create_qp(struct ib_pd *pd, struct ib_qp *ib_create_qp(struct ib_pd *pd,
struct ib_qp_init_attr *qp_init_attr) struct ib_qp_init_attr *qp_init_attr)
{ {
struct ib_qp *qp; struct ib_qp *qp, *real_qp;
struct ib_device *device;
qp = pd->device->create_qp(pd, qp_init_attr, NULL); device = pd ? pd->device : qp_init_attr->xrcd->device;
qp = device->create_qp(pd, qp_init_attr, NULL);
if (!IS_ERR(qp)) { if (!IS_ERR(qp)) {
qp->device = pd->device; qp->device = device;
qp->pd = pd; qp->real_qp = qp;
qp->send_cq = qp_init_attr->send_cq;
qp->recv_cq = qp_init_attr->recv_cq;
qp->srq = qp_init_attr->srq;
qp->uobject = NULL; qp->uobject = NULL;
qp->qp_type = qp_init_attr->qp_type;
if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
qp->event_handler = __ib_shared_qp_event_handler;
qp->qp_context = qp;
qp->pd = NULL;
qp->send_cq = qp->recv_cq = NULL;
qp->srq = NULL;
qp->xrcd = qp_init_attr->xrcd;
atomic_inc(&qp_init_attr->xrcd->usecnt);
INIT_LIST_HEAD(&qp->open_list);
atomic_set(&qp->usecnt, 0);
real_qp = qp;
qp = __ib_open_qp(real_qp, qp_init_attr->event_handler,
qp_init_attr->qp_context);
if (!IS_ERR(qp))
__ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp);
else
real_qp->device->destroy_qp(real_qp);
} else {
qp->event_handler = qp_init_attr->event_handler; qp->event_handler = qp_init_attr->event_handler;
qp->qp_context = qp_init_attr->qp_context; qp->qp_context = qp_init_attr->qp_context;
qp->qp_type = qp_init_attr->qp_type; if (qp_init_attr->qp_type == IB_QPT_XRC_INI) {
atomic_inc(&pd->usecnt); qp->recv_cq = NULL;
atomic_inc(&qp_init_attr->send_cq->usecnt); qp->srq = NULL;
} else {
qp->recv_cq = qp_init_attr->recv_cq;
atomic_inc(&qp_init_attr->recv_cq->usecnt); atomic_inc(&qp_init_attr->recv_cq->usecnt);
if (qp_init_attr->srq) qp->srq = qp_init_attr->srq;
if (qp->srq)
atomic_inc(&qp_init_attr->srq->usecnt); atomic_inc(&qp_init_attr->srq->usecnt);
} }
qp->pd = pd;
qp->send_cq = qp_init_attr->send_cq;
qp->xrcd = NULL;
atomic_inc(&pd->usecnt);
atomic_inc(&qp_init_attr->send_cq->usecnt);
}
}
return qp; return qp;
} }
EXPORT_SYMBOL(ib_create_qp); EXPORT_SYMBOL(ib_create_qp);
static const struct { static const struct {
int valid; int valid;
enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETHERTYPE + 1]; enum ib_qp_attr_mask req_param[IB_QPT_MAX];
enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETHERTYPE + 1]; enum ib_qp_attr_mask opt_param[IB_QPT_MAX];
} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = { } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
[IB_QPS_RESET] = { [IB_QPS_RESET] = {
[IB_QPS_RESET] = { .valid = 1 }, [IB_QPS_RESET] = { .valid = 1 },
...@@ -343,6 +484,12 @@ static const struct { ...@@ -343,6 +484,12 @@ static const struct {
[IB_QPT_RC] = (IB_QP_PKEY_INDEX | [IB_QPT_RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT | IB_QP_PORT |
IB_QP_ACCESS_FLAGS), IB_QP_ACCESS_FLAGS),
[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
...@@ -365,6 +512,12 @@ static const struct { ...@@ -365,6 +512,12 @@ static const struct {
[IB_QPT_RC] = (IB_QP_PKEY_INDEX | [IB_QPT_RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT | IB_QP_PORT |
IB_QP_ACCESS_FLAGS), IB_QP_ACCESS_FLAGS),
[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
...@@ -384,6 +537,16 @@ static const struct { ...@@ -384,6 +537,16 @@ static const struct {
IB_QP_RQ_PSN | IB_QP_RQ_PSN |
IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC |
IB_QP_MIN_RNR_TIMER), IB_QP_MIN_RNR_TIMER),
[IB_QPT_XRC_INI] = (IB_QP_AV |
IB_QP_PATH_MTU |
IB_QP_DEST_QPN |
IB_QP_RQ_PSN),
[IB_QPT_XRC_TGT] = (IB_QP_AV |
IB_QP_PATH_MTU |
IB_QP_DEST_QPN |
IB_QP_RQ_PSN |
IB_QP_MAX_DEST_RD_ATOMIC |
IB_QP_MIN_RNR_TIMER),
}, },
.opt_param = { .opt_param = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX | [IB_QPT_UD] = (IB_QP_PKEY_INDEX |
...@@ -394,6 +557,12 @@ static const struct { ...@@ -394,6 +557,12 @@ static const struct {
[IB_QPT_RC] = (IB_QP_ALT_PATH | [IB_QPT_RC] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS | IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX), IB_QP_PKEY_INDEX),
[IB_QPT_XRC_INI] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX),
[IB_QPT_XRC_TGT] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
...@@ -414,6 +583,13 @@ static const struct { ...@@ -414,6 +583,13 @@ static const struct {
IB_QP_RNR_RETRY | IB_QP_RNR_RETRY |
IB_QP_SQ_PSN | IB_QP_SQ_PSN |
IB_QP_MAX_QP_RD_ATOMIC), IB_QP_MAX_QP_RD_ATOMIC),
[IB_QPT_XRC_INI] = (IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
IB_QP_SQ_PSN |
IB_QP_MAX_QP_RD_ATOMIC),
[IB_QPT_XRC_TGT] = (IB_QP_TIMEOUT |
IB_QP_SQ_PSN),
[IB_QPT_SMI] = IB_QP_SQ_PSN, [IB_QPT_SMI] = IB_QP_SQ_PSN,
[IB_QPT_GSI] = IB_QP_SQ_PSN, [IB_QPT_GSI] = IB_QP_SQ_PSN,
}, },
...@@ -429,6 +605,15 @@ static const struct { ...@@ -429,6 +605,15 @@ static const struct {
IB_QP_ACCESS_FLAGS | IB_QP_ACCESS_FLAGS |
IB_QP_MIN_RNR_TIMER | IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE), IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | [IB_QPT_SMI] = (IB_QP_CUR_STATE |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | [IB_QPT_GSI] = (IB_QP_CUR_STATE |
...@@ -453,6 +638,15 @@ static const struct { ...@@ -453,6 +638,15 @@ static const struct {
IB_QP_ALT_PATH | IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE | IB_QP_PATH_MIG_STATE |
IB_QP_MIN_RNR_TIMER), IB_QP_MIN_RNR_TIMER),
[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE |
IB_QP_ACCESS_FLAGS |
IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE |
IB_QP_ACCESS_FLAGS |
IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE |
IB_QP_MIN_RNR_TIMER),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | [IB_QPT_SMI] = (IB_QP_CUR_STATE |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | [IB_QPT_GSI] = (IB_QP_CUR_STATE |
...@@ -465,6 +659,8 @@ static const struct { ...@@ -465,6 +659,8 @@ static const struct {
[IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY, [IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY, [IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY, [IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_XRC_INI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_XRC_TGT] = IB_QP_EN_SQD_ASYNC_NOTIFY, /* ??? */
[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY, [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
} }
...@@ -487,6 +683,15 @@ static const struct { ...@@ -487,6 +683,15 @@ static const struct {
IB_QP_ACCESS_FLAGS | IB_QP_ACCESS_FLAGS |
IB_QP_MIN_RNR_TIMER | IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE), IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | [IB_QPT_SMI] = (IB_QP_CUR_STATE |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | [IB_QPT_GSI] = (IB_QP_CUR_STATE |
...@@ -515,6 +720,25 @@ static const struct { ...@@ -515,6 +720,25 @@ static const struct {
IB_QP_PKEY_INDEX | IB_QP_PKEY_INDEX |
IB_QP_MIN_RNR_TIMER | IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE), IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_INI] = (IB_QP_PORT |
IB_QP_AV |
IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
IB_QP_MAX_QP_RD_ATOMIC |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX |
IB_QP_PATH_MIG_STATE),
[IB_QPT_XRC_TGT] = (IB_QP_PORT |
IB_QP_AV |
IB_QP_TIMEOUT |
IB_QP_MAX_DEST_RD_ATOMIC |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX |
IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY), IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
...@@ -579,7 +803,7 @@ int ib_modify_qp(struct ib_qp *qp, ...@@ -579,7 +803,7 @@ int ib_modify_qp(struct ib_qp *qp,
struct ib_qp_attr *qp_attr, struct ib_qp_attr *qp_attr,
int qp_attr_mask) int qp_attr_mask)
{ {
return qp->device->modify_qp(qp, qp_attr, qp_attr_mask, NULL); return qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
} }
EXPORT_SYMBOL(ib_modify_qp); EXPORT_SYMBOL(ib_modify_qp);
...@@ -589,11 +813,59 @@ int ib_query_qp(struct ib_qp *qp, ...@@ -589,11 +813,59 @@ int ib_query_qp(struct ib_qp *qp,
struct ib_qp_init_attr *qp_init_attr) struct ib_qp_init_attr *qp_init_attr)
{ {
return qp->device->query_qp ? return qp->device->query_qp ?
qp->device->query_qp(qp, qp_attr, qp_attr_mask, qp_init_attr) : qp->device->query_qp(qp->real_qp, qp_attr, qp_attr_mask, qp_init_attr) :
-ENOSYS; -ENOSYS;
} }
EXPORT_SYMBOL(ib_query_qp); EXPORT_SYMBOL(ib_query_qp);
int ib_close_qp(struct ib_qp *qp)
{
struct ib_qp *real_qp;
unsigned long flags;
real_qp = qp->real_qp;
if (real_qp == qp)
return -EINVAL;
spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
list_del(&qp->open_list);
spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
atomic_dec(&real_qp->usecnt);
kfree(qp);
return 0;
}
EXPORT_SYMBOL(ib_close_qp);
static int __ib_destroy_shared_qp(struct ib_qp *qp)
{
struct ib_xrcd *xrcd;
struct ib_qp *real_qp;
int ret;
real_qp = qp->real_qp;
xrcd = real_qp->xrcd;
mutex_lock(&xrcd->tgt_qp_mutex);
ib_close_qp(qp);
if (atomic_read(&real_qp->usecnt) == 0)
list_del(&real_qp->xrcd_list);
else
real_qp = NULL;
mutex_unlock(&xrcd->tgt_qp_mutex);
if (real_qp) {
ret = ib_destroy_qp(real_qp);
if (!ret)
atomic_dec(&xrcd->usecnt);
else
__ib_insert_xrcd_qp(xrcd, real_qp);
}
return 0;
}
int ib_destroy_qp(struct ib_qp *qp) int ib_destroy_qp(struct ib_qp *qp)
{ {
struct ib_pd *pd; struct ib_pd *pd;
...@@ -601,6 +873,12 @@ int ib_destroy_qp(struct ib_qp *qp) ...@@ -601,6 +873,12 @@ int ib_destroy_qp(struct ib_qp *qp)
struct ib_srq *srq; struct ib_srq *srq;
int ret; int ret;
if (atomic_read(&qp->usecnt))
return -EBUSY;
if (qp->real_qp != qp)
return __ib_destroy_shared_qp(qp);
pd = qp->pd; pd = qp->pd;
scq = qp->send_cq; scq = qp->send_cq;
rcq = qp->recv_cq; rcq = qp->recv_cq;
...@@ -608,8 +886,11 @@ int ib_destroy_qp(struct ib_qp *qp) ...@@ -608,8 +886,11 @@ int ib_destroy_qp(struct ib_qp *qp)
ret = qp->device->destroy_qp(qp); ret = qp->device->destroy_qp(qp);
if (!ret) { if (!ret) {
if (pd)
atomic_dec(&pd->usecnt); atomic_dec(&pd->usecnt);
if (scq)
atomic_dec(&scq->usecnt); atomic_dec(&scq->usecnt);
if (rcq)
atomic_dec(&rcq->usecnt); atomic_dec(&rcq->usecnt);
if (srq) if (srq)
atomic_dec(&srq->usecnt); atomic_dec(&srq->usecnt);
...@@ -920,3 +1201,42 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) ...@@ -920,3 +1201,42 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
return qp->device->detach_mcast(qp, gid, lid); return qp->device->detach_mcast(qp, gid, lid);
} }
EXPORT_SYMBOL(ib_detach_mcast); EXPORT_SYMBOL(ib_detach_mcast);
struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
{
struct ib_xrcd *xrcd;
if (!device->alloc_xrcd)
return ERR_PTR(-ENOSYS);
xrcd = device->alloc_xrcd(device, NULL, NULL);
if (!IS_ERR(xrcd)) {
xrcd->device = device;
xrcd->inode = NULL;
atomic_set(&xrcd->usecnt, 0);
mutex_init(&xrcd->tgt_qp_mutex);
INIT_LIST_HEAD(&xrcd->tgt_qp_list);
}
return xrcd;
}
EXPORT_SYMBOL(ib_alloc_xrcd);
int ib_dealloc_xrcd(struct ib_xrcd *xrcd)
{
struct ib_qp *qp;
int ret;
if (atomic_read(&xrcd->usecnt))
return -EBUSY;
while (!list_empty(&xrcd->tgt_qp_list)) {
qp = list_entry(xrcd->tgt_qp_list.next, struct ib_qp, xrcd_list);
ret = ib_destroy_qp(qp);
if (ret)
return ret;
}
return xrcd->device->dealloc_xrcd(xrcd);
}
EXPORT_SYMBOL(ib_dealloc_xrcd);
...@@ -288,6 +288,11 @@ void c2_ae_event(struct c2_dev *c2dev, u32 mq_index) ...@@ -288,6 +288,11 @@ void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
cm_event.private_data_len = cm_event.private_data_len =
be32_to_cpu(req->private_data_length); be32_to_cpu(req->private_data_length);
cm_event.private_data = req->private_data; cm_event.private_data = req->private_data;
/*
* Until ird/ord negotiation via MPAv2 support is added, send
* max supported values
*/
cm_event.ird = cm_event.ord = 128;
if (cm_id->event_handler) if (cm_id->event_handler)
cm_id->event_handler(cm_id, &cm_event); cm_id->event_handler(cm_id, &cm_event);
......
...@@ -183,6 +183,11 @@ static void handle_vq(struct c2_dev *c2dev, u32 mq_index) ...@@ -183,6 +183,11 @@ static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
case IW_CM_EVENT_ESTABLISHED: case IW_CM_EVENT_ESTABLISHED:
c2_set_qp_state(req->qp, c2_set_qp_state(req->qp,
C2_QP_STATE_RTS); C2_QP_STATE_RTS);
/*
* Until ird/ord negotiation via MPAv2 support is added, send
* max supported values
*/
cm_event.ird = cm_event.ord = 128;
case IW_CM_EVENT_CLOSE: case IW_CM_EVENT_CLOSE:
/* /*
......
...@@ -753,6 +753,11 @@ static void connect_request_upcall(struct iwch_ep *ep) ...@@ -753,6 +753,11 @@ static void connect_request_upcall(struct iwch_ep *ep)
event.private_data_len = ep->plen; event.private_data_len = ep->plen;
event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
event.provider_data = ep; event.provider_data = ep;
/*
* Until ird/ord negotiation via MPAv2 support is added, send max
* supported values
*/
event.ird = event.ord = 8;
if (state_read(&ep->parent_ep->com) != DEAD) { if (state_read(&ep->parent_ep->com) != DEAD) {
get_ep(&ep->com); get_ep(&ep->com);
ep->parent_ep->com.cm_id->event_handler( ep->parent_ep->com.cm_id->event_handler(
...@@ -770,6 +775,11 @@ static void established_upcall(struct iwch_ep *ep) ...@@ -770,6 +775,11 @@ static void established_upcall(struct iwch_ep *ep)
PDBG("%s ep %p\n", __func__, ep); PDBG("%s ep %p\n", __func__, ep);
memset(&event, 0, sizeof(event)); memset(&event, 0, sizeof(event));
event.event = IW_CM_EVENT_ESTABLISHED; event.event = IW_CM_EVENT_ESTABLISHED;
/*
* Until ird/ord negotiation via MPAv2 support is added, send max
* supported values
*/
event.ird = event.ord = 8;
if (ep->com.cm_id) { if (ep->com.cm_id) {
PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid);
ep->com.cm_id->event_handler(ep->com.cm_id, &event); ep->com.cm_id->event_handler(ep->com.cm_id, &event);
......
...@@ -46,6 +46,7 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp, ...@@ -46,6 +46,7 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
struct ib_event event; struct ib_event event;
struct iwch_qp_attributes attrs; struct iwch_qp_attributes attrs;
struct iwch_qp *qhp; struct iwch_qp *qhp;
unsigned long flag;
spin_lock(&rnicp->lock); spin_lock(&rnicp->lock);
qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe)); qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe));
...@@ -94,7 +95,9 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp, ...@@ -94,7 +95,9 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
if (qhp->ibqp.event_handler) if (qhp->ibqp.event_handler)
(*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
if (atomic_dec_and_test(&qhp->refcnt)) if (atomic_dec_and_test(&qhp->refcnt))
wake_up(&qhp->wait); wake_up(&qhp->wait);
...@@ -107,6 +110,7 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb) ...@@ -107,6 +110,7 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
struct iwch_cq *chp; struct iwch_cq *chp;
struct iwch_qp *qhp; struct iwch_qp *qhp;
u32 cqid = RSPQ_CQID(rsp_msg); u32 cqid = RSPQ_CQID(rsp_msg);
unsigned long flag;
rnicp = (struct iwch_dev *) rdev_p->ulp; rnicp = (struct iwch_dev *) rdev_p->ulp;
spin_lock(&rnicp->lock); spin_lock(&rnicp->lock);
...@@ -170,7 +174,9 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb) ...@@ -170,7 +174,9 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
*/ */
if (qhp->ep && SQ_TYPE(rsp_msg->cqe)) if (qhp->ep && SQ_TYPE(rsp_msg->cqe))
dst_confirm(qhp->ep->dst); dst_confirm(qhp->ep->dst);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
break; break;
case TPT_ERR_STAG: case TPT_ERR_STAG:
......
...@@ -190,6 +190,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve ...@@ -190,6 +190,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
chp->rhp = rhp; chp->rhp = rhp;
chp->ibcq.cqe = 1 << chp->cq.size_log2; chp->ibcq.cqe = 1 << chp->cq.size_log2;
spin_lock_init(&chp->lock); spin_lock_init(&chp->lock);
spin_lock_init(&chp->comp_handler_lock);
atomic_set(&chp->refcnt, 1); atomic_set(&chp->refcnt, 1);
init_waitqueue_head(&chp->wait); init_waitqueue_head(&chp->wait);
if (insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid)) { if (insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid)) {
......
...@@ -103,6 +103,7 @@ struct iwch_cq { ...@@ -103,6 +103,7 @@ struct iwch_cq {
struct iwch_dev *rhp; struct iwch_dev *rhp;
struct t3_cq cq; struct t3_cq cq;
spinlock_t lock; spinlock_t lock;
spinlock_t comp_handler_lock;
atomic_t refcnt; atomic_t refcnt;
wait_queue_head_t wait; wait_queue_head_t wait;
u32 __user *user_rptr_addr; u32 __user *user_rptr_addr;
......
...@@ -822,8 +822,11 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp, ...@@ -822,8 +822,11 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count); flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock); spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&rchp->lock, *flag); spin_unlock_irqrestore(&rchp->lock, *flag);
if (flushed) if (flushed) {
spin_lock_irqsave(&rchp->comp_handler_lock, *flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
spin_unlock_irqrestore(&rchp->comp_handler_lock, *flag);
}
/* locking hierarchy: cq lock first, then qp lock. */ /* locking hierarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&schp->lock, *flag); spin_lock_irqsave(&schp->lock, *flag);
...@@ -833,8 +836,11 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp, ...@@ -833,8 +836,11 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count); flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock); spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&schp->lock, *flag); spin_unlock_irqrestore(&schp->lock, *flag);
if (flushed) if (flushed) {
spin_lock_irqsave(&schp->comp_handler_lock, *flag);
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
spin_unlock_irqrestore(&schp->comp_handler_lock, *flag);
}
/* deref */ /* deref */
if (atomic_dec_and_test(&qhp->refcnt)) if (atomic_dec_and_test(&qhp->refcnt))
...@@ -853,11 +859,15 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) ...@@ -853,11 +859,15 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
if (qhp->ibqp.uobject) { if (qhp->ibqp.uobject) {
cxio_set_wq_in_error(&qhp->wq); cxio_set_wq_in_error(&qhp->wq);
cxio_set_cq_in_error(&rchp->cq); cxio_set_cq_in_error(&rchp->cq);
spin_lock_irqsave(&rchp->comp_handler_lock, *flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
spin_unlock_irqrestore(&rchp->comp_handler_lock, *flag);
if (schp != rchp) { if (schp != rchp) {
cxio_set_cq_in_error(&schp->cq); cxio_set_cq_in_error(&schp->cq);
spin_lock_irqsave(&schp->comp_handler_lock, *flag);
(*schp->ibcq.comp_handler)(&schp->ibcq, (*schp->ibcq.comp_handler)(&schp->ibcq,
schp->ibcq.cq_context); schp->ibcq.cq_context);
spin_unlock_irqrestore(&schp->comp_handler_lock, *flag);
} }
return; return;
} }
......
此差异已折叠。
...@@ -185,7 +185,7 @@ static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq) ...@@ -185,7 +185,7 @@ static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq)
V_CQE_OPCODE(FW_RI_SEND) | V_CQE_OPCODE(FW_RI_SEND) |
V_CQE_TYPE(0) | V_CQE_TYPE(0) |
V_CQE_SWCQE(1) | V_CQE_SWCQE(1) |
V_CQE_QPID(wq->rq.qid)); V_CQE_QPID(wq->sq.qid));
cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen)); cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen));
cq->sw_queue[cq->sw_pidx] = cqe; cq->sw_queue[cq->sw_pidx] = cqe;
t4_swcq_produce(cq); t4_swcq_produce(cq);
...@@ -818,6 +818,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, ...@@ -818,6 +818,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
chp->cq.size--; /* status page */ chp->cq.size--; /* status page */
chp->ibcq.cqe = entries - 2; chp->ibcq.cqe = entries - 2;
spin_lock_init(&chp->lock); spin_lock_init(&chp->lock);
spin_lock_init(&chp->comp_handler_lock);
atomic_set(&chp->refcnt, 1); atomic_set(&chp->refcnt, 1);
init_waitqueue_head(&chp->wait); init_waitqueue_head(&chp->wait);
ret = insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid); ret = insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid);
......
...@@ -376,10 +376,8 @@ struct uld_ctx { ...@@ -376,10 +376,8 @@ struct uld_ctx {
struct c4iw_dev *dev; struct c4iw_dev *dev;
}; };
static void c4iw_remove(struct uld_ctx *ctx) static void c4iw_dealloc(struct uld_ctx *ctx)
{ {
PDBG("%s c4iw_dev %p\n", __func__, ctx->dev);
c4iw_unregister_device(ctx->dev);
c4iw_rdev_close(&ctx->dev->rdev); c4iw_rdev_close(&ctx->dev->rdev);
idr_destroy(&ctx->dev->cqidr); idr_destroy(&ctx->dev->cqidr);
idr_destroy(&ctx->dev->qpidr); idr_destroy(&ctx->dev->qpidr);
...@@ -389,11 +387,30 @@ static void c4iw_remove(struct uld_ctx *ctx) ...@@ -389,11 +387,30 @@ static void c4iw_remove(struct uld_ctx *ctx)
ctx->dev = NULL; ctx->dev = NULL;
} }
static void c4iw_remove(struct uld_ctx *ctx)
{
PDBG("%s c4iw_dev %p\n", __func__, ctx->dev);
c4iw_unregister_device(ctx->dev);
c4iw_dealloc(ctx);
}
static int rdma_supported(const struct cxgb4_lld_info *infop)
{
return infop->vr->stag.size > 0 && infop->vr->pbl.size > 0 &&
infop->vr->rq.size > 0 && infop->vr->qp.size > 0 &&
infop->vr->cq.size > 0 && infop->vr->ocq.size > 0;
}
static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
{ {
struct c4iw_dev *devp; struct c4iw_dev *devp;
int ret; int ret;
if (!rdma_supported(infop)) {
printk(KERN_INFO MOD "%s: RDMA not supported on this device.\n",
pci_name(infop->pdev));
return ERR_PTR(-ENOSYS);
}
devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp)); devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
if (!devp) { if (!devp) {
printk(KERN_ERR MOD "Cannot allocate ib device\n"); printk(KERN_ERR MOD "Cannot allocate ib device\n");
...@@ -414,7 +431,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) ...@@ -414,7 +431,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
ret = c4iw_rdev_open(&devp->rdev); ret = c4iw_rdev_open(&devp->rdev);
if (ret) { if (ret) {
mutex_unlock(&dev_mutex);
printk(KERN_ERR MOD "Unable to open CXIO rdev err %d\n", ret); printk(KERN_ERR MOD "Unable to open CXIO rdev err %d\n", ret);
ib_dealloc_device(&devp->ibdev); ib_dealloc_device(&devp->ibdev);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -519,15 +535,24 @@ static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state) ...@@ -519,15 +535,24 @@ static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
case CXGB4_STATE_UP: case CXGB4_STATE_UP:
printk(KERN_INFO MOD "%s: Up\n", pci_name(ctx->lldi.pdev)); printk(KERN_INFO MOD "%s: Up\n", pci_name(ctx->lldi.pdev));
if (!ctx->dev) { if (!ctx->dev) {
int ret = 0; int ret;
ctx->dev = c4iw_alloc(&ctx->lldi); ctx->dev = c4iw_alloc(&ctx->lldi);
if (!IS_ERR(ctx->dev)) if (IS_ERR(ctx->dev)) {
printk(KERN_ERR MOD
"%s: initialization failed: %ld\n",
pci_name(ctx->lldi.pdev),
PTR_ERR(ctx->dev));
ctx->dev = NULL;
break;
}
ret = c4iw_register_device(ctx->dev); ret = c4iw_register_device(ctx->dev);
if (IS_ERR(ctx->dev) || ret) if (ret) {
printk(KERN_ERR MOD printk(KERN_ERR MOD
"%s: RDMA registration failed: %d\n", "%s: RDMA registration failed: %d\n",
pci_name(ctx->lldi.pdev), ret); pci_name(ctx->lldi.pdev), ret);
c4iw_dealloc(ctx);
}
} }
break; break;
case CXGB4_STATE_DOWN: case CXGB4_STATE_DOWN:
......
...@@ -42,6 +42,7 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp, ...@@ -42,6 +42,7 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
{ {
struct ib_event event; struct ib_event event;
struct c4iw_qp_attributes attrs; struct c4iw_qp_attributes attrs;
unsigned long flag;
if ((qhp->attr.state == C4IW_QP_STATE_ERROR) || if ((qhp->attr.state == C4IW_QP_STATE_ERROR) ||
(qhp->attr.state == C4IW_QP_STATE_TERMINATE)) { (qhp->attr.state == C4IW_QP_STATE_TERMINATE)) {
...@@ -72,7 +73,9 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp, ...@@ -72,7 +73,9 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
if (qhp->ibqp.event_handler) if (qhp->ibqp.event_handler)
(*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
} }
void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe) void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
...@@ -183,11 +186,14 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe) ...@@ -183,11 +186,14 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid) int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid)
{ {
struct c4iw_cq *chp; struct c4iw_cq *chp;
unsigned long flag;
chp = get_chp(dev, qid); chp = get_chp(dev, qid);
if (chp) if (chp) {
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
else spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
} else
PDBG("%s unknown cqid 0x%x\n", __func__, qid); PDBG("%s unknown cqid 0x%x\n", __func__, qid);
return 0; return 0;
} }
...@@ -309,6 +309,7 @@ struct c4iw_cq { ...@@ -309,6 +309,7 @@ struct c4iw_cq {
struct c4iw_dev *rhp; struct c4iw_dev *rhp;
struct t4_cq cq; struct t4_cq cq;
spinlock_t lock; spinlock_t lock;
spinlock_t comp_handler_lock;
atomic_t refcnt; atomic_t refcnt;
wait_queue_head_t wait; wait_queue_head_t wait;
}; };
...@@ -323,6 +324,7 @@ struct c4iw_mpa_attributes { ...@@ -323,6 +324,7 @@ struct c4iw_mpa_attributes {
u8 recv_marker_enabled; u8 recv_marker_enabled;
u8 xmit_marker_enabled; u8 xmit_marker_enabled;
u8 crc_enabled; u8 crc_enabled;
u8 enhanced_rdma_conn;
u8 version; u8 version;
u8 p2p_type; u8 p2p_type;
}; };
...@@ -349,6 +351,8 @@ struct c4iw_qp_attributes { ...@@ -349,6 +351,8 @@ struct c4iw_qp_attributes {
u8 is_terminate_local; u8 is_terminate_local;
struct c4iw_mpa_attributes mpa_attr; struct c4iw_mpa_attributes mpa_attr;
struct c4iw_ep *llp_stream_handle; struct c4iw_ep *llp_stream_handle;
u8 layer_etype;
u8 ecode;
}; };
struct c4iw_qp { struct c4iw_qp {
...@@ -501,11 +505,18 @@ enum c4iw_mmid_state { ...@@ -501,11 +505,18 @@ enum c4iw_mmid_state {
#define MPA_KEY_REP "MPA ID Rep Frame" #define MPA_KEY_REP "MPA ID Rep Frame"
#define MPA_MAX_PRIVATE_DATA 256 #define MPA_MAX_PRIVATE_DATA 256
#define MPA_ENHANCED_RDMA_CONN 0x10
#define MPA_REJECT 0x20 #define MPA_REJECT 0x20
#define MPA_CRC 0x40 #define MPA_CRC 0x40
#define MPA_MARKERS 0x80 #define MPA_MARKERS 0x80
#define MPA_FLAGS_MASK 0xE0 #define MPA_FLAGS_MASK 0xE0
#define MPA_V2_PEER2PEER_MODEL 0x8000
#define MPA_V2_ZERO_LEN_FPDU_RTR 0x4000
#define MPA_V2_RDMA_WRITE_RTR 0x8000
#define MPA_V2_RDMA_READ_RTR 0x4000
#define MPA_V2_IRD_ORD_MASK 0x3FFF
#define c4iw_put_ep(ep) { \ #define c4iw_put_ep(ep) { \
PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \
ep, atomic_read(&((ep)->kref.refcount))); \ ep, atomic_read(&((ep)->kref.refcount))); \
...@@ -528,6 +539,11 @@ struct mpa_message { ...@@ -528,6 +539,11 @@ struct mpa_message {
u8 private_data[0]; u8 private_data[0];
}; };
struct mpa_v2_conn_params {
__be16 ird;
__be16 ord;
};
struct terminate_message { struct terminate_message {
u8 layer_etype; u8 layer_etype;
u8 ecode; u8 ecode;
...@@ -580,7 +596,10 @@ enum c4iw_ddp_ecodes { ...@@ -580,7 +596,10 @@ enum c4iw_ddp_ecodes {
enum c4iw_mpa_ecodes { enum c4iw_mpa_ecodes {
MPA_CRC_ERR = 0x02, MPA_CRC_ERR = 0x02,
MPA_MARKER_ERR = 0x03 MPA_MARKER_ERR = 0x03,
MPA_LOCAL_CATA = 0x05,
MPA_INSUFF_IRD = 0x06,
MPA_NOMATCH_RTR = 0x07,
}; };
enum c4iw_ep_state { enum c4iw_ep_state {
...@@ -651,6 +670,8 @@ struct c4iw_ep { ...@@ -651,6 +670,8 @@ struct c4iw_ep {
u16 txq_idx; u16 txq_idx;
u16 ctrlq_idx; u16 ctrlq_idx;
u8 tos; u8 tos;
u8 retry_with_mpa_v1;
u8 tried_with_mpa_v1;
}; };
static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id) static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id)
......
...@@ -917,6 +917,10 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe, ...@@ -917,6 +917,10 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
wqe->u.terminate.type = FW_RI_TYPE_TERMINATE; wqe->u.terminate.type = FW_RI_TYPE_TERMINATE;
wqe->u.terminate.immdlen = cpu_to_be32(sizeof *term); wqe->u.terminate.immdlen = cpu_to_be32(sizeof *term);
term = (struct terminate_message *)wqe->u.terminate.termmsg; term = (struct terminate_message *)wqe->u.terminate.termmsg;
if (qhp->attr.layer_etype == (LAYER_MPA|DDP_LLP)) {
term->layer_etype = qhp->attr.layer_etype;
term->ecode = qhp->attr.ecode;
} else
build_term_codes(err_cqe, &term->layer_etype, &term->ecode); build_term_codes(err_cqe, &term->layer_etype, &term->ecode);
c4iw_ofld_send(&qhp->rhp->rdev, skb); c4iw_ofld_send(&qhp->rhp->rdev, skb);
} }
...@@ -941,8 +945,11 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp, ...@@ -941,8 +945,11 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count); flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock); spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&rchp->lock, flag); spin_unlock_irqrestore(&rchp->lock, flag);
if (flushed) if (flushed) {
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
}
/* locking hierarchy: cq lock first, then qp lock. */ /* locking hierarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&schp->lock, flag); spin_lock_irqsave(&schp->lock, flag);
...@@ -952,13 +959,17 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp, ...@@ -952,13 +959,17 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count); flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock); spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&schp->lock, flag); spin_unlock_irqrestore(&schp->lock, flag);
if (flushed) if (flushed) {
spin_lock_irqsave(&schp->comp_handler_lock, flag);
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
}
} }
static void flush_qp(struct c4iw_qp *qhp) static void flush_qp(struct c4iw_qp *qhp)
{ {
struct c4iw_cq *rchp, *schp; struct c4iw_cq *rchp, *schp;
unsigned long flag;
rchp = get_chp(qhp->rhp, qhp->attr.rcq); rchp = get_chp(qhp->rhp, qhp->attr.rcq);
schp = get_chp(qhp->rhp, qhp->attr.scq); schp = get_chp(qhp->rhp, qhp->attr.scq);
...@@ -966,8 +977,16 @@ static void flush_qp(struct c4iw_qp *qhp) ...@@ -966,8 +977,16 @@ static void flush_qp(struct c4iw_qp *qhp)
if (qhp->ibqp.uobject) { if (qhp->ibqp.uobject) {
t4_set_wq_in_error(&qhp->wq); t4_set_wq_in_error(&qhp->wq);
t4_set_cq_in_error(&rchp->cq); t4_set_cq_in_error(&rchp->cq);
if (schp != rchp) spin_lock_irqsave(&rchp->comp_handler_lock, flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
if (schp != rchp) {
t4_set_cq_in_error(&schp->cq); t4_set_cq_in_error(&schp->cq);
spin_lock_irqsave(&schp->comp_handler_lock, flag);
(*schp->ibcq.comp_handler)(&schp->ibcq,
schp->ibcq.cq_context);
spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
}
return; return;
} }
__flush_qp(qhp, rchp, schp); __flush_qp(qhp, rchp, schp);
...@@ -1012,6 +1031,7 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, ...@@ -1012,6 +1031,7 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
static void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init) static void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init)
{ {
PDBG("%s p2p_type = %d\n", __func__, p2p_type);
memset(&init->u, 0, sizeof init->u); memset(&init->u, 0, sizeof init->u);
switch (p2p_type) { switch (p2p_type) {
case FW_RI_INIT_P2PTYPE_RDMA_WRITE: case FW_RI_INIT_P2PTYPE_RDMA_WRITE:
...@@ -1206,12 +1226,16 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, ...@@ -1206,12 +1226,16 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
disconnect = 1; disconnect = 1;
c4iw_get_ep(&qhp->ep->com); c4iw_get_ep(&qhp->ep->com);
} }
if (qhp->ibqp.uobject)
t4_set_wq_in_error(&qhp->wq);
ret = rdma_fini(rhp, qhp, ep); ret = rdma_fini(rhp, qhp, ep);
if (ret) if (ret)
goto err; goto err;
break; break;
case C4IW_QP_STATE_TERMINATE: case C4IW_QP_STATE_TERMINATE:
set_state(qhp, C4IW_QP_STATE_TERMINATE); set_state(qhp, C4IW_QP_STATE_TERMINATE);
qhp->attr.layer_etype = attrs->layer_etype;
qhp->attr.ecode = attrs->ecode;
if (qhp->ibqp.uobject) if (qhp->ibqp.uobject)
t4_set_wq_in_error(&qhp->wq); t4_set_wq_in_error(&qhp->wq);
ep = qhp->ep; ep = qhp->ep;
...@@ -1222,6 +1246,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, ...@@ -1222,6 +1246,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
break; break;
case C4IW_QP_STATE_ERROR: case C4IW_QP_STATE_ERROR:
set_state(qhp, C4IW_QP_STATE_ERROR); set_state(qhp, C4IW_QP_STATE_ERROR);
if (qhp->ibqp.uobject)
t4_set_wq_in_error(&qhp->wq);
if (!internal) { if (!internal) {
abort = 1; abort = 1;
disconnect = 1; disconnect = 1;
...@@ -1334,6 +1360,9 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) ...@@ -1334,6 +1360,9 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
rhp = qhp->rhp; rhp = qhp->rhp;
attrs.next_state = C4IW_QP_STATE_ERROR; attrs.next_state = C4IW_QP_STATE_ERROR;
if (qhp->attr.state == C4IW_QP_STATE_TERMINATE)
c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
else
c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
wait_event(qhp->wait, !qhp->ep); wait_event(qhp->wait, !qhp->ep);
......
...@@ -125,7 +125,7 @@ int ehca_create_eq(struct ehca_shca *shca, ...@@ -125,7 +125,7 @@ int ehca_create_eq(struct ehca_shca *shca,
tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca); tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
ret = ibmebus_request_irq(eq->ist, ehca_interrupt_eq, ret = ibmebus_request_irq(eq->ist, ehca_interrupt_eq,
IRQF_DISABLED, "ehca_eq", 0, "ehca_eq",
(void *)shca); (void *)shca);
if (ret < 0) if (ret < 0)
ehca_err(ib_dev, "Can't map interrupt handler."); ehca_err(ib_dev, "Can't map interrupt handler.");
...@@ -133,7 +133,7 @@ int ehca_create_eq(struct ehca_shca *shca, ...@@ -133,7 +133,7 @@ int ehca_create_eq(struct ehca_shca *shca,
tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca); tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
ret = ibmebus_request_irq(eq->ist, ehca_interrupt_neq, ret = ibmebus_request_irq(eq->ist, ehca_interrupt_neq,
IRQF_DISABLED, "ehca_neq", 0, "ehca_neq",
(void *)shca); (void *)shca);
if (ret < 0) if (ret < 0)
ehca_err(ib_dev, "Can't map interrupt handler."); ehca_err(ib_dev, "Can't map interrupt handler.");
......
...@@ -977,6 +977,9 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, ...@@ -977,6 +977,9 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
struct hcp_modify_qp_control_block *mqpcb; struct hcp_modify_qp_control_block *mqpcb;
u64 hret, update_mask; u64 hret, update_mask;
if (srq_init_attr->srq_type != IB_SRQT_BASIC)
return ERR_PTR(-ENOSYS);
/* For common attributes, internal_create_qp() takes its info /* For common attributes, internal_create_qp() takes its info
* out of qp_init_attr, so copy all common attrs there. * out of qp_init_attr, so copy all common attrs there.
*/ */
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include "ipath_kernel.h" #include "ipath_kernel.h"
......
...@@ -107,6 +107,11 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, ...@@ -107,6 +107,11 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
u32 sz; u32 sz;
struct ib_srq *ret; struct ib_srq *ret;
if (srq_init_attr->srq_type != IB_SRQT_BASIC) {
ret = ERR_PTR(-ENOSYS);
goto done;
}
if (srq_init_attr->attr.max_wr == 0) { if (srq_init_attr->attr.max_wr == 0) {
ret = ERR_PTR(-EINVAL); ret = ERR_PTR(-EINVAL);
goto done; goto done;
......
...@@ -128,6 +128,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, ...@@ -128,6 +128,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
(dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_REMOTE_INV) && (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_REMOTE_INV) &&
(dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_FAST_REG_WR)) (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_FAST_REG_WR))
props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)
props->device_cap_flags |= IB_DEVICE_XRC;
props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
0xffffff; 0xffffff;
...@@ -181,8 +183,12 @@ mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num) ...@@ -181,8 +183,12 @@ mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num)
static int ib_link_query_port(struct ib_device *ibdev, u8 port, static int ib_link_query_port(struct ib_device *ibdev, u8 port,
struct ib_port_attr *props, struct ib_port_attr *props,
struct ib_smp *in_mad,
struct ib_smp *out_mad) struct ib_smp *out_mad)
{ {
int ext_active_speed;
int err;
props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16));
props->lmc = out_mad->data[34] & 0x7; props->lmc = out_mad->data[34] & 0x7;
props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18));
...@@ -203,6 +209,39 @@ static int ib_link_query_port(struct ib_device *ibdev, u8 port, ...@@ -203,6 +209,39 @@ static int ib_link_query_port(struct ib_device *ibdev, u8 port,
props->max_vl_num = out_mad->data[37] >> 4; props->max_vl_num = out_mad->data[37] >> 4;
props->init_type_reply = out_mad->data[41] >> 4; props->init_type_reply = out_mad->data[41] >> 4;
/* Check if extended speeds (EDR/FDR/...) are supported */
if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
ext_active_speed = out_mad->data[62] >> 4;
switch (ext_active_speed) {
case 1:
props->active_speed = 16; /* FDR */
break;
case 2:
props->active_speed = 32; /* EDR */
break;
}
}
/* If reported active speed is QDR, check if is FDR-10 */
if (props->active_speed == 4) {
if (to_mdev(ibdev)->dev->caps.ext_port_cap[port] &
MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) {
init_query_mad(in_mad);
in_mad->attr_id = MLX4_ATTR_EXTENDED_PORT_INFO;
in_mad->attr_mod = cpu_to_be32(port);
err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port,
NULL, NULL, in_mad, out_mad);
if (err)
return err;
/* Checking LinkSpeedActive for FDR-10 */
if (out_mad->data[15] & 0x1)
props->active_speed = 8;
}
}
return 0; return 0;
} }
...@@ -227,7 +266,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, ...@@ -227,7 +266,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
props->pkey_tbl_len = 1; props->pkey_tbl_len = 1;
props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46));
props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48));
props->max_mtu = IB_MTU_2048; props->max_mtu = IB_MTU_4096;
props->subnet_timeout = 0; props->subnet_timeout = 0;
props->max_vl_num = out_mad->data[37] >> 4; props->max_vl_num = out_mad->data[37] >> 4;
props->init_type_reply = 0; props->init_type_reply = 0;
...@@ -274,7 +313,7 @@ static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port, ...@@ -274,7 +313,7 @@ static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
goto out; goto out;
err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ? err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ?
ib_link_query_port(ibdev, port, props, out_mad) : ib_link_query_port(ibdev, port, props, in_mad, out_mad) :
eth_link_query_port(ibdev, port, props, out_mad); eth_link_query_port(ibdev, port, props, out_mad);
out: out:
...@@ -566,6 +605,57 @@ static int mlx4_ib_dealloc_pd(struct ib_pd *pd) ...@@ -566,6 +605,57 @@ static int mlx4_ib_dealloc_pd(struct ib_pd *pd)
return 0; return 0;
} }
static struct ib_xrcd *mlx4_ib_alloc_xrcd(struct ib_device *ibdev,
struct ib_ucontext *context,
struct ib_udata *udata)
{
struct mlx4_ib_xrcd *xrcd;
int err;
if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
return ERR_PTR(-ENOSYS);
xrcd = kmalloc(sizeof *xrcd, GFP_KERNEL);
if (!xrcd)
return ERR_PTR(-ENOMEM);
err = mlx4_xrcd_alloc(to_mdev(ibdev)->dev, &xrcd->xrcdn);
if (err)
goto err1;
xrcd->pd = ib_alloc_pd(ibdev);
if (IS_ERR(xrcd->pd)) {
err = PTR_ERR(xrcd->pd);
goto err2;
}
xrcd->cq = ib_create_cq(ibdev, NULL, NULL, xrcd, 1, 0);
if (IS_ERR(xrcd->cq)) {
err = PTR_ERR(xrcd->cq);
goto err3;
}
return &xrcd->ibxrcd;
err3:
ib_dealloc_pd(xrcd->pd);
err2:
mlx4_xrcd_free(to_mdev(ibdev)->dev, xrcd->xrcdn);
err1:
kfree(xrcd);
return ERR_PTR(err);
}
static int mlx4_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
{
ib_destroy_cq(to_mxrcd(xrcd)->cq);
ib_dealloc_pd(to_mxrcd(xrcd)->pd);
mlx4_xrcd_free(to_mdev(xrcd->device)->dev, to_mxrcd(xrcd)->xrcdn);
kfree(xrcd);
return 0;
}
static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid) static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid)
{ {
struct mlx4_ib_qp *mqp = to_mqp(ibqp); struct mlx4_ib_qp *mqp = to_mqp(ibqp);
...@@ -1044,7 +1134,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ...@@ -1044,7 +1134,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
(1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
(1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
(1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) |
(1ull << IB_USER_VERBS_CMD_OPEN_QP);
ibdev->ib_dev.query_device = mlx4_ib_query_device; ibdev->ib_dev.query_device = mlx4_ib_query_device;
ibdev->ib_dev.query_port = mlx4_ib_query_port; ibdev->ib_dev.query_port = mlx4_ib_query_port;
...@@ -1093,6 +1185,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ...@@ -1093,6 +1185,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr;
ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc;
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) {
ibdev->ib_dev.alloc_xrcd = mlx4_ib_alloc_xrcd;
ibdev->ib_dev.dealloc_xrcd = mlx4_ib_dealloc_xrcd;
ibdev->ib_dev.uverbs_cmd_mask |=
(1ull << IB_USER_VERBS_CMD_OPEN_XRCD) |
(1ull << IB_USER_VERBS_CMD_CLOSE_XRCD);
}
spin_lock_init(&iboe->lock); spin_lock_init(&iboe->lock);
if (init_node_data(ibdev)) if (init_node_data(ibdev))
......
...@@ -56,6 +56,13 @@ struct mlx4_ib_pd { ...@@ -56,6 +56,13 @@ struct mlx4_ib_pd {
u32 pdn; u32 pdn;
}; };
struct mlx4_ib_xrcd {
struct ib_xrcd ibxrcd;
u32 xrcdn;
struct ib_pd *pd;
struct ib_cq *cq;
};
struct mlx4_ib_cq_buf { struct mlx4_ib_cq_buf {
struct mlx4_buf buf; struct mlx4_buf buf;
struct mlx4_mtt mtt; struct mlx4_mtt mtt;
...@@ -138,6 +145,7 @@ struct mlx4_ib_qp { ...@@ -138,6 +145,7 @@ struct mlx4_ib_qp {
struct mlx4_mtt mtt; struct mlx4_mtt mtt;
int buf_size; int buf_size;
struct mutex mutex; struct mutex mutex;
u16 xrcdn;
u32 flags; u32 flags;
u8 port; u8 port;
u8 alt_port; u8 alt_port;
...@@ -211,6 +219,11 @@ static inline struct mlx4_ib_pd *to_mpd(struct ib_pd *ibpd) ...@@ -211,6 +219,11 @@ static inline struct mlx4_ib_pd *to_mpd(struct ib_pd *ibpd)
return container_of(ibpd, struct mlx4_ib_pd, ibpd); return container_of(ibpd, struct mlx4_ib_pd, ibpd);
} }
static inline struct mlx4_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd)
{
return container_of(ibxrcd, struct mlx4_ib_xrcd, ibxrcd);
}
static inline struct mlx4_ib_cq *to_mcq(struct ib_cq *ibcq) static inline struct mlx4_ib_cq *to_mcq(struct ib_cq *ibcq)
{ {
return container_of(ibcq, struct mlx4_ib_cq, ibcq); return container_of(ibcq, struct mlx4_ib_cq, ibcq);
......
...@@ -302,15 +302,14 @@ static int send_wqe_overhead(enum ib_qp_type type, u32 flags) ...@@ -302,15 +302,14 @@ static int send_wqe_overhead(enum ib_qp_type type, u32 flags)
} }
static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
int is_user, int has_srq, struct mlx4_ib_qp *qp) int is_user, int has_rq, struct mlx4_ib_qp *qp)
{ {
/* Sanity check RQ size before proceeding */ /* Sanity check RQ size before proceeding */
if (cap->max_recv_wr > dev->dev->caps.max_wqes || if (cap->max_recv_wr > dev->dev->caps.max_wqes ||
cap->max_recv_sge > dev->dev->caps.max_rq_sg) cap->max_recv_sge > dev->dev->caps.max_rq_sg)
return -EINVAL; return -EINVAL;
if (has_srq) { if (!has_rq) {
/* QPs attached to an SRQ should have no RQ */
if (cap->max_recv_wr) if (cap->max_recv_wr)
return -EINVAL; return -EINVAL;
...@@ -463,6 +462,14 @@ static int set_user_sq_size(struct mlx4_ib_dev *dev, ...@@ -463,6 +462,14 @@ static int set_user_sq_size(struct mlx4_ib_dev *dev,
return 0; return 0;
} }
static int qp_has_rq(struct ib_qp_init_attr *attr)
{
if (attr->qp_type == IB_QPT_XRC_INI || attr->qp_type == IB_QPT_XRC_TGT)
return 0;
return !attr->srq;
}
static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
struct ib_qp_init_attr *init_attr, struct ib_qp_init_attr *init_attr,
struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp) struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp)
...@@ -479,7 +486,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -479,7 +486,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, !!init_attr->srq, qp); err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, qp_has_rq(init_attr), qp);
if (err) if (err)
goto err; goto err;
...@@ -513,7 +520,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -513,7 +520,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (err) if (err)
goto err_mtt; goto err_mtt;
if (!init_attr->srq) { if (qp_has_rq(init_attr)) {
err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context),
ucmd.db_addr, &qp->db); ucmd.db_addr, &qp->db);
if (err) if (err)
...@@ -532,7 +539,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -532,7 +539,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (err) if (err)
goto err; goto err;
if (!init_attr->srq) { if (qp_has_rq(init_attr)) {
err = mlx4_db_alloc(dev->dev, &qp->db, 0); err = mlx4_db_alloc(dev->dev, &qp->db, 0);
if (err) if (err)
goto err; goto err;
...@@ -575,6 +582,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -575,6 +582,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (err) if (err)
goto err_qpn; goto err_qpn;
if (init_attr->qp_type == IB_QPT_XRC_TGT)
qp->mqp.qpn |= (1 << 23);
/* /*
* Hardware wants QPN written in big-endian order (after * Hardware wants QPN written in big-endian order (after
* shifting) for send doorbell. Precompute this value to save * shifting) for send doorbell. Precompute this value to save
...@@ -592,9 +602,8 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -592,9 +602,8 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
err_wrid: err_wrid:
if (pd->uobject) { if (pd->uobject) {
if (!init_attr->srq) if (qp_has_rq(init_attr))
mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
&qp->db);
} else { } else {
kfree(qp->sq.wrid); kfree(qp->sq.wrid);
kfree(qp->rq.wrid); kfree(qp->rq.wrid);
...@@ -610,7 +619,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -610,7 +619,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
err_db: err_db:
if (!pd->uobject && !init_attr->srq) if (!pd->uobject && qp_has_rq(init_attr))
mlx4_db_free(dev->dev, &qp->db); mlx4_db_free(dev->dev, &qp->db);
err: err:
...@@ -671,6 +680,33 @@ static void del_gid_entries(struct mlx4_ib_qp *qp) ...@@ -671,6 +680,33 @@ static void del_gid_entries(struct mlx4_ib_qp *qp)
} }
} }
static struct mlx4_ib_pd *get_pd(struct mlx4_ib_qp *qp)
{
if (qp->ibqp.qp_type == IB_QPT_XRC_TGT)
return to_mpd(to_mxrcd(qp->ibqp.xrcd)->pd);
else
return to_mpd(qp->ibqp.pd);
}
static void get_cqs(struct mlx4_ib_qp *qp,
struct mlx4_ib_cq **send_cq, struct mlx4_ib_cq **recv_cq)
{
switch (qp->ibqp.qp_type) {
case IB_QPT_XRC_TGT:
*send_cq = to_mcq(to_mxrcd(qp->ibqp.xrcd)->cq);
*recv_cq = *send_cq;
break;
case IB_QPT_XRC_INI:
*send_cq = to_mcq(qp->ibqp.send_cq);
*recv_cq = *send_cq;
break;
default:
*send_cq = to_mcq(qp->ibqp.send_cq);
*recv_cq = to_mcq(qp->ibqp.recv_cq);
break;
}
}
static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
int is_user) int is_user)
{ {
...@@ -682,8 +718,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, ...@@ -682,8 +718,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n", printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n",
qp->mqp.qpn); qp->mqp.qpn);
send_cq = to_mcq(qp->ibqp.send_cq); get_cqs(qp, &send_cq, &recv_cq);
recv_cq = to_mcq(qp->ibqp.recv_cq);
mlx4_ib_lock_cqs(send_cq, recv_cq); mlx4_ib_lock_cqs(send_cq, recv_cq);
...@@ -706,7 +741,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, ...@@ -706,7 +741,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
mlx4_mtt_cleanup(dev->dev, &qp->mtt); mlx4_mtt_cleanup(dev->dev, &qp->mtt);
if (is_user) { if (is_user) {
if (!qp->ibqp.srq) if (qp->rq.wqe_cnt)
mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.uobject->context), mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.uobject->context),
&qp->db); &qp->db);
ib_umem_release(qp->umem); ib_umem_release(qp->umem);
...@@ -714,7 +749,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, ...@@ -714,7 +749,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
kfree(qp->sq.wrid); kfree(qp->sq.wrid);
kfree(qp->rq.wrid); kfree(qp->rq.wrid);
mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
if (!qp->ibqp.srq) if (qp->rq.wqe_cnt)
mlx4_db_free(dev->dev, &qp->db); mlx4_db_free(dev->dev, &qp->db);
} }
...@@ -725,10 +760,10 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, ...@@ -725,10 +760,10 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
struct ib_qp_init_attr *init_attr, struct ib_qp_init_attr *init_attr,
struct ib_udata *udata) struct ib_udata *udata)
{ {
struct mlx4_ib_dev *dev = to_mdev(pd->device);
struct mlx4_ib_sqp *sqp; struct mlx4_ib_sqp *sqp;
struct mlx4_ib_qp *qp; struct mlx4_ib_qp *qp;
int err; int err;
u16 xrcdn = 0;
/* /*
* We only support LSO and multicast loopback blocking, and * We only support LSO and multicast loopback blocking, and
...@@ -739,10 +774,20 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, ...@@ -739,10 +774,20 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (init_attr->create_flags && if (init_attr->create_flags &&
(pd->uobject || init_attr->qp_type != IB_QPT_UD)) (udata || init_attr->qp_type != IB_QPT_UD))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
switch (init_attr->qp_type) { switch (init_attr->qp_type) {
case IB_QPT_XRC_TGT:
pd = to_mxrcd(init_attr->xrcd)->pd;
xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
init_attr->send_cq = to_mxrcd(init_attr->xrcd)->cq;
/* fall through */
case IB_QPT_XRC_INI:
if (!(to_mdev(pd->device)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
return ERR_PTR(-ENOSYS);
init_attr->recv_cq = init_attr->send_cq;
/* fall through */
case IB_QPT_RC: case IB_QPT_RC:
case IB_QPT_UC: case IB_QPT_UC:
case IB_QPT_UD: case IB_QPT_UD:
...@@ -751,13 +796,14 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, ...@@ -751,13 +796,14 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
if (!qp) if (!qp)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = create_qp_common(dev, pd, init_attr, udata, 0, qp); err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata, 0, qp);
if (err) { if (err) {
kfree(qp); kfree(qp);
return ERR_PTR(err); return ERR_PTR(err);
} }
qp->ibqp.qp_num = qp->mqp.qpn; qp->ibqp.qp_num = qp->mqp.qpn;
qp->xrcdn = xrcdn;
break; break;
} }
...@@ -765,7 +811,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, ...@@ -765,7 +811,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
case IB_QPT_GSI: case IB_QPT_GSI:
{ {
/* Userspace is not allowed to create special QPs: */ /* Userspace is not allowed to create special QPs: */
if (pd->uobject) if (udata)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
sqp = kzalloc(sizeof *sqp, GFP_KERNEL); sqp = kzalloc(sizeof *sqp, GFP_KERNEL);
...@@ -774,8 +820,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, ...@@ -774,8 +820,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
qp = &sqp->qp; qp = &sqp->qp;
err = create_qp_common(dev, pd, init_attr, udata, err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata,
dev->dev->caps.sqp_start + to_mdev(pd->device)->dev->caps.sqp_start +
(init_attr->qp_type == IB_QPT_SMI ? 0 : 2) + (init_attr->qp_type == IB_QPT_SMI ? 0 : 2) +
init_attr->port_num - 1, init_attr->port_num - 1,
qp); qp);
...@@ -801,11 +847,13 @@ int mlx4_ib_destroy_qp(struct ib_qp *qp) ...@@ -801,11 +847,13 @@ int mlx4_ib_destroy_qp(struct ib_qp *qp)
{ {
struct mlx4_ib_dev *dev = to_mdev(qp->device); struct mlx4_ib_dev *dev = to_mdev(qp->device);
struct mlx4_ib_qp *mqp = to_mqp(qp); struct mlx4_ib_qp *mqp = to_mqp(qp);
struct mlx4_ib_pd *pd;
if (is_qp0(dev, mqp)) if (is_qp0(dev, mqp))
mlx4_CLOSE_PORT(dev->dev, mqp->port); mlx4_CLOSE_PORT(dev->dev, mqp->port);
destroy_qp_common(dev, mqp, !!qp->pd->uobject); pd = get_pd(mqp);
destroy_qp_common(dev, mqp, !!pd->ibpd.uobject);
if (is_sqp(dev, mqp)) if (is_sqp(dev, mqp))
kfree(to_msqp(mqp)); kfree(to_msqp(mqp));
...@@ -821,6 +869,8 @@ static int to_mlx4_st(enum ib_qp_type type) ...@@ -821,6 +869,8 @@ static int to_mlx4_st(enum ib_qp_type type)
case IB_QPT_RC: return MLX4_QP_ST_RC; case IB_QPT_RC: return MLX4_QP_ST_RC;
case IB_QPT_UC: return MLX4_QP_ST_UC; case IB_QPT_UC: return MLX4_QP_ST_UC;
case IB_QPT_UD: return MLX4_QP_ST_UD; case IB_QPT_UD: return MLX4_QP_ST_UD;
case IB_QPT_XRC_INI:
case IB_QPT_XRC_TGT: return MLX4_QP_ST_XRC;
case IB_QPT_SMI: case IB_QPT_SMI:
case IB_QPT_GSI: return MLX4_QP_ST_MLX; case IB_QPT_GSI: return MLX4_QP_ST_MLX;
default: return -1; default: return -1;
...@@ -959,6 +1009,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -959,6 +1009,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
{ {
struct mlx4_ib_dev *dev = to_mdev(ibqp->device); struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
struct mlx4_ib_qp *qp = to_mqp(ibqp); struct mlx4_ib_qp *qp = to_mqp(ibqp);
struct mlx4_ib_pd *pd;
struct mlx4_ib_cq *send_cq, *recv_cq;
struct mlx4_qp_context *context; struct mlx4_qp_context *context;
enum mlx4_qp_optpar optpar = 0; enum mlx4_qp_optpar optpar = 0;
int sqd_event; int sqd_event;
...@@ -1014,8 +1066,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1014,8 +1066,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3; context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3;
context->sq_size_stride |= qp->sq.wqe_shift - 4; context->sq_size_stride |= qp->sq.wqe_shift - 4;
if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
context->sq_size_stride |= !!qp->sq_no_prefetch << 7; context->sq_size_stride |= !!qp->sq_no_prefetch << 7;
context->xrcd = cpu_to_be32((u32) qp->xrcdn);
}
if (qp->ibqp.uobject) if (qp->ibqp.uobject)
context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index); context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index);
...@@ -1079,7 +1133,11 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1079,7 +1133,11 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH; optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH;
} }
context->pd = cpu_to_be32(to_mpd(ibqp->pd)->pdn); pd = get_pd(qp);
get_cqs(qp, &send_cq, &recv_cq);
context->pd = cpu_to_be32(pd->pdn);
context->cqn_send = cpu_to_be32(send_cq->mcq.cqn);
context->cqn_recv = cpu_to_be32(recv_cq->mcq.cqn);
context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28);
/* Set "fast registration enabled" for all kernel QPs */ /* Set "fast registration enabled" for all kernel QPs */
...@@ -1106,8 +1164,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1106,8 +1164,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_SQ_PSN) if (attr_mask & IB_QP_SQ_PSN)
context->next_send_psn = cpu_to_be32(attr->sq_psn); context->next_send_psn = cpu_to_be32(attr->sq_psn);
context->cqn_send = cpu_to_be32(to_mcq(ibqp->send_cq)->mcq.cqn);
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
if (attr->max_dest_rd_atomic) if (attr->max_dest_rd_atomic)
context->params2 |= context->params2 |=
...@@ -1130,8 +1186,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1130,8 +1186,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_RQ_PSN) if (attr_mask & IB_QP_RQ_PSN)
context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn); context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
context->cqn_recv = cpu_to_be32(to_mcq(ibqp->recv_cq)->mcq.cqn);
if (attr_mask & IB_QP_QKEY) { if (attr_mask & IB_QP_QKEY) {
context->qkey = cpu_to_be32(attr->qkey); context->qkey = cpu_to_be32(attr->qkey);
optpar |= MLX4_QP_OPTPAR_Q_KEY; optpar |= MLX4_QP_OPTPAR_Q_KEY;
...@@ -1140,7 +1194,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1140,7 +1194,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (ibqp->srq) if (ibqp->srq)
context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn); context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn);
if (!ibqp->srq && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
context->db_rec_addr = cpu_to_be64(qp->db.dma); context->db_rec_addr = cpu_to_be64(qp->db.dma);
if (cur_state == IB_QPS_INIT && if (cur_state == IB_QPS_INIT &&
...@@ -1225,17 +1279,17 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1225,17 +1279,17 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
* entries and reinitialize the QP. * entries and reinitialize the QP.
*/ */
if (new_state == IB_QPS_RESET && !ibqp->uobject) { if (new_state == IB_QPS_RESET && !ibqp->uobject) {
mlx4_ib_cq_clean(to_mcq(ibqp->recv_cq), qp->mqp.qpn, mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
ibqp->srq ? to_msrq(ibqp->srq): NULL); ibqp->srq ? to_msrq(ibqp->srq): NULL);
if (ibqp->send_cq != ibqp->recv_cq) if (send_cq != recv_cq)
mlx4_ib_cq_clean(to_mcq(ibqp->send_cq), qp->mqp.qpn, NULL); mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
qp->rq.head = 0; qp->rq.head = 0;
qp->rq.tail = 0; qp->rq.tail = 0;
qp->sq.head = 0; qp->sq.head = 0;
qp->sq.tail = 0; qp->sq.tail = 0;
qp->sq_next_wqe = 0; qp->sq_next_wqe = 0;
if (!ibqp->srq) if (qp->rq.wqe_cnt)
*qp->db.db = 0; *qp->db.db = 0;
} }
...@@ -1547,14 +1601,13 @@ static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg, ...@@ -1547,14 +1601,13 @@ static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg,
} }
static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
struct ib_send_wr *wr, __be16 *vlan) struct ib_send_wr *wr)
{ {
memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan; dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan;
memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6); memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6);
*vlan = dseg->vlan;
} }
static void set_mlx_icrc_seg(void *dseg) static void set_mlx_icrc_seg(void *dseg)
...@@ -1657,7 +1710,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ...@@ -1657,7 +1710,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
__be32 uninitialized_var(lso_hdr_sz); __be32 uninitialized_var(lso_hdr_sz);
__be32 blh; __be32 blh;
int i; int i;
__be16 vlan = cpu_to_be16(0xffff);
spin_lock_irqsave(&qp->sq.lock, flags); spin_lock_irqsave(&qp->sq.lock, flags);
...@@ -1761,7 +1813,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ...@@ -1761,7 +1813,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break; break;
case IB_QPT_UD: case IB_QPT_UD:
set_datagram_seg(wqe, wr, &vlan); set_datagram_seg(wqe, wr);
wqe += sizeof (struct mlx4_wqe_datagram_seg); wqe += sizeof (struct mlx4_wqe_datagram_seg);
size += sizeof (struct mlx4_wqe_datagram_seg) / 16; size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
...@@ -1824,11 +1876,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ...@@ -1824,11 +1876,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ? ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size; MLX4_WQE_CTRL_FENCE : 0) | size;
if (be16_to_cpu(vlan) < 0x1000) {
ctrl->ins_vlan = 1 << 6;
ctrl->vlan_tag = vlan;
}
/* /*
* Make sure descriptor is fully written before * Make sure descriptor is fully written before
* setting ownership bit (because HW can start * setting ownership bit (because HW can start
......
...@@ -76,6 +76,8 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, ...@@ -76,6 +76,8 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
struct mlx4_ib_srq *srq; struct mlx4_ib_srq *srq;
struct mlx4_wqe_srq_next_seg *next; struct mlx4_wqe_srq_next_seg *next;
struct mlx4_wqe_data_seg *scatter; struct mlx4_wqe_data_seg *scatter;
u32 cqn;
u16 xrcdn;
int desc_size; int desc_size;
int buf_size; int buf_size;
int err; int err;
...@@ -174,12 +176,18 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, ...@@ -174,12 +176,18 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
} }
} }
err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, &srq->mtt, cqn = (init_attr->srq_type == IB_SRQT_XRC) ?
to_mcq(init_attr->ext.xrc.cq)->mcq.cqn : 0;
xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn :
(u16) dev->dev->caps.reserved_xrcds;
err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, cqn, xrcdn, &srq->mtt,
srq->db.dma, &srq->msrq); srq->db.dma, &srq->msrq);
if (err) if (err)
goto err_wrid; goto err_wrid;
srq->msrq.event = mlx4_ib_srq_event; srq->msrq.event = mlx4_ib_srq_event;
srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
if (pd->uobject) if (pd->uobject)
if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) { if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
......
...@@ -438,6 +438,9 @@ static struct ib_srq *mthca_create_srq(struct ib_pd *pd, ...@@ -438,6 +438,9 @@ static struct ib_srq *mthca_create_srq(struct ib_pd *pd,
struct mthca_srq *srq; struct mthca_srq *srq;
int err; int err;
if (init_attr->srq_type != IB_SRQT_BASIC)
return ERR_PTR(-ENOSYS);
srq = kmalloc(sizeof *srq, GFP_KERNEL); srq = kmalloc(sizeof *srq, GFP_KERNEL);
if (!srq) if (!srq)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o
...@@ -84,7 +84,7 @@ module_param(send_first, int, 0644); ...@@ -84,7 +84,7 @@ module_param(send_first, int, 0644);
MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection"); MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
unsigned int nes_drv_opt = 0; unsigned int nes_drv_opt = NES_DRV_OPT_DISABLE_INT_MOD | NES_DRV_OPT_ENABLE_PAU;
module_param(nes_drv_opt, int, 0644); module_param(nes_drv_opt, int, 0644);
MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters"); MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
...@@ -130,9 +130,6 @@ static struct notifier_block nes_net_notifier = { ...@@ -130,9 +130,6 @@ static struct notifier_block nes_net_notifier = {
.notifier_call = nes_net_event .notifier_call = nes_net_event
}; };
/** /**
* nes_inetaddr_event * nes_inetaddr_event
*/ */
...@@ -321,6 +318,9 @@ void nes_rem_ref(struct ib_qp *ibqp) ...@@ -321,6 +318,9 @@ void nes_rem_ref(struct ib_qp *ibqp)
} }
if (atomic_dec_and_test(&nesqp->refcount)) { if (atomic_dec_and_test(&nesqp->refcount)) {
if (nesqp->pau_mode)
nes_destroy_pau_qp(nesdev, nesqp);
/* Destroy the QP */ /* Destroy the QP */
cqp_request = nes_get_cqp_request(nesdev); cqp_request = nes_get_cqp_request(nesdev);
if (cqp_request == NULL) { if (cqp_request == NULL) {
......
...@@ -102,6 +102,7 @@ ...@@ -102,6 +102,7 @@
#define NES_DRV_OPT_NO_INLINE_DATA 0x00000080 #define NES_DRV_OPT_NO_INLINE_DATA 0x00000080
#define NES_DRV_OPT_DISABLE_INT_MOD 0x00000100 #define NES_DRV_OPT_DISABLE_INT_MOD 0x00000100
#define NES_DRV_OPT_DISABLE_VIRT_WQ 0x00000200 #define NES_DRV_OPT_DISABLE_VIRT_WQ 0x00000200
#define NES_DRV_OPT_ENABLE_PAU 0x00000400
#define NES_AEQ_EVENT_TIMEOUT 2500 #define NES_AEQ_EVENT_TIMEOUT 2500
#define NES_DISCONNECT_EVENT_TIMEOUT 2000 #define NES_DISCONNECT_EVENT_TIMEOUT 2000
...@@ -128,6 +129,7 @@ ...@@ -128,6 +129,7 @@
#define NES_DBG_IW_RX 0x00020000 #define NES_DBG_IW_RX 0x00020000
#define NES_DBG_IW_TX 0x00040000 #define NES_DBG_IW_TX 0x00040000
#define NES_DBG_SHUTDOWN 0x00080000 #define NES_DBG_SHUTDOWN 0x00080000
#define NES_DBG_PAU 0x00100000
#define NES_DBG_RSVD1 0x10000000 #define NES_DBG_RSVD1 0x10000000
#define NES_DBG_RSVD2 0x20000000 #define NES_DBG_RSVD2 0x20000000
#define NES_DBG_RSVD3 0x40000000 #define NES_DBG_RSVD3 0x40000000
...@@ -162,6 +164,7 @@ do { \ ...@@ -162,6 +164,7 @@ do { \
#include "nes_context.h" #include "nes_context.h"
#include "nes_user.h" #include "nes_user.h"
#include "nes_cm.h" #include "nes_cm.h"
#include "nes_mgt.h"
extern int max_mtu; extern int max_mtu;
#define max_frame_len (max_mtu+ETH_HLEN) #define max_frame_len (max_mtu+ETH_HLEN)
...@@ -202,6 +205,8 @@ extern atomic_t cm_nodes_created; ...@@ -202,6 +205,8 @@ extern atomic_t cm_nodes_created;
extern atomic_t cm_nodes_destroyed; extern atomic_t cm_nodes_destroyed;
extern atomic_t cm_accel_dropped_pkts; extern atomic_t cm_accel_dropped_pkts;
extern atomic_t cm_resets_recvd; extern atomic_t cm_resets_recvd;
extern atomic_t pau_qps_created;
extern atomic_t pau_qps_destroyed;
extern u32 int_mod_timer_init; extern u32 int_mod_timer_init;
extern u32 int_mod_cq_depth_256; extern u32 int_mod_cq_depth_256;
...@@ -273,6 +278,14 @@ struct nes_device { ...@@ -273,6 +278,14 @@ struct nes_device {
u8 link_recheck; u8 link_recheck;
}; };
/* Receive skb private area - must fit in skb->cb area */
struct nes_rskb_cb {
u64 busaddr;
u32 maplen;
u32 seqnum;
u8 *data_start;
struct nes_qp *nesqp;
};
static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad) static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad)
{ {
...@@ -305,8 +318,8 @@ set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value) ...@@ -305,8 +318,8 @@ set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value)
static inline void static inline void
nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev) nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev)
{ {
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_CTX_LOW_IDX, cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX] = 0;
(u64)((unsigned long) &nesdev->cqp)); cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0; cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0; cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0; cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
......
此差异已折叠。
...@@ -49,6 +49,15 @@ ...@@ -49,6 +49,15 @@
#define IETF_MPA_VERSION 1 #define IETF_MPA_VERSION 1
#define IETF_MAX_PRIV_DATA_LEN 512 #define IETF_MAX_PRIV_DATA_LEN 512
#define IETF_MPA_FRAME_SIZE 20 #define IETF_MPA_FRAME_SIZE 20
#define IETF_RTR_MSG_SIZE 4
#define IETF_MPA_V2_FLAG 0x10
/* IETF RTR MSG Fields */
#define IETF_PEER_TO_PEER 0x8000
#define IETF_FLPDU_ZERO_LEN 0x4000
#define IETF_RDMA0_WRITE 0x8000
#define IETF_RDMA0_READ 0x4000
#define IETF_NO_IRD_ORD 0x3FFF
enum ietf_mpa_flags { enum ietf_mpa_flags {
IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */ IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */
...@@ -56,7 +65,7 @@ enum ietf_mpa_flags { ...@@ -56,7 +65,7 @@ enum ietf_mpa_flags {
IETF_MPA_FLAGS_REJECT = 0x20, /* Reject */ IETF_MPA_FLAGS_REJECT = 0x20, /* Reject */
}; };
struct ietf_mpa_frame { struct ietf_mpa_v1 {
u8 key[IETF_MPA_KEY_SIZE]; u8 key[IETF_MPA_KEY_SIZE];
u8 flags; u8 flags;
u8 rev; u8 rev;
...@@ -66,6 +75,20 @@ struct ietf_mpa_frame { ...@@ -66,6 +75,20 @@ struct ietf_mpa_frame {
#define ietf_mpa_req_resp_frame ietf_mpa_frame #define ietf_mpa_req_resp_frame ietf_mpa_frame
struct ietf_rtr_msg {
__be16 ctrl_ird;
__be16 ctrl_ord;
};
struct ietf_mpa_v2 {
u8 key[IETF_MPA_KEY_SIZE];
u8 flags;
u8 rev;
__be16 priv_data_len;
struct ietf_rtr_msg rtr_msg;
u8 priv_data[0];
};
struct nes_v4_quad { struct nes_v4_quad {
u32 rsvd0; u32 rsvd0;
__le32 DstIpAdrIndex; /* Only most significant 5 bits are valid */ __le32 DstIpAdrIndex; /* Only most significant 5 bits are valid */
...@@ -171,8 +194,7 @@ struct nes_timer_entry { ...@@ -171,8 +194,7 @@ struct nes_timer_entry {
#define NES_CM_DEF_SEQ2 0x18ed5740 #define NES_CM_DEF_SEQ2 0x18ed5740
#define NES_CM_DEF_LOCAL_ID2 0xb807 #define NES_CM_DEF_LOCAL_ID2 0xb807
#define MAX_CM_BUFFER (IETF_MPA_FRAME_SIZE + IETF_MAX_PRIV_DATA_LEN) #define MAX_CM_BUFFER (IETF_MPA_FRAME_SIZE + IETF_RTR_MSG_SIZE + IETF_MAX_PRIV_DATA_LEN)
typedef u32 nes_addr_t; typedef u32 nes_addr_t;
...@@ -204,6 +226,21 @@ enum nes_cm_node_state { ...@@ -204,6 +226,21 @@ enum nes_cm_node_state {
NES_CM_STATE_CLOSED NES_CM_STATE_CLOSED
}; };
enum mpa_frame_version {
IETF_MPA_V1 = 1,
IETF_MPA_V2 = 2
};
enum mpa_frame_key {
MPA_KEY_REQUEST,
MPA_KEY_REPLY
};
enum send_rdma0 {
SEND_RDMA_READ_ZERO = 1,
SEND_RDMA_WRITE_ZERO = 2
};
enum nes_tcpip_pkt_type { enum nes_tcpip_pkt_type {
NES_PKT_TYPE_UNKNOWN, NES_PKT_TYPE_UNKNOWN,
NES_PKT_TYPE_SYN, NES_PKT_TYPE_SYN,
...@@ -245,9 +282,9 @@ struct nes_cm_tcp_context { ...@@ -245,9 +282,9 @@ struct nes_cm_tcp_context {
enum nes_cm_listener_state { enum nes_cm_listener_state {
NES_CM_LISTENER_PASSIVE_STATE=1, NES_CM_LISTENER_PASSIVE_STATE = 1,
NES_CM_LISTENER_ACTIVE_STATE=2, NES_CM_LISTENER_ACTIVE_STATE = 2,
NES_CM_LISTENER_EITHER_STATE=3 NES_CM_LISTENER_EITHER_STATE = 3
}; };
struct nes_cm_listener { struct nes_cm_listener {
...@@ -284,15 +321,19 @@ struct nes_cm_node { ...@@ -284,15 +321,19 @@ struct nes_cm_node {
struct nes_cm_node *loopbackpartner; struct nes_cm_node *loopbackpartner;
struct nes_timer_entry *send_entry; struct nes_timer_entry *send_entry;
spinlock_t retrans_list_lock;
struct nes_timer_entry *recv_entry; struct nes_timer_entry *recv_entry;
spinlock_t retrans_list_lock;
enum send_rdma0 send_rdma0_op;
int send_write0;
union { union {
struct ietf_mpa_frame mpa_frame; struct ietf_mpa_v1 mpa_frame;
struct ietf_mpa_v2 mpa_v2_frame;
u8 mpa_frame_buf[MAX_CM_BUFFER]; u8 mpa_frame_buf[MAX_CM_BUFFER];
}; };
enum mpa_frame_version mpa_frame_rev;
u16 ird_size;
u16 ord_size;
u16 mpa_frame_size; u16 mpa_frame_size;
struct iw_cm_id *cm_id; struct iw_cm_id *cm_id;
struct list_head list; struct list_head list;
...@@ -399,10 +440,8 @@ struct nes_cm_ops { ...@@ -399,10 +440,8 @@ struct nes_cm_ops {
struct nes_vnic *, u16, void *, struct nes_vnic *, u16, void *,
struct nes_cm_info *); struct nes_cm_info *);
int (*close)(struct nes_cm_core *, struct nes_cm_node *); int (*close)(struct nes_cm_core *, struct nes_cm_node *);
int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *, int (*accept)(struct nes_cm_core *, struct nes_cm_node *);
struct nes_cm_node *); int (*reject)(struct nes_cm_core *, struct nes_cm_node *);
int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *,
struct nes_cm_node *);
int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *, int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
struct sk_buff *); struct sk_buff *);
int (*destroy_cm_core)(struct nes_cm_core *); int (*destroy_cm_core)(struct nes_cm_core *);
...@@ -422,5 +461,7 @@ int nes_destroy_listen(struct iw_cm_id *); ...@@ -422,5 +461,7 @@ int nes_destroy_listen(struct iw_cm_id *);
int nes_cm_recv(struct sk_buff *, struct net_device *); int nes_cm_recv(struct sk_buff *, struct net_device *);
int nes_cm_start(void); int nes_cm_start(void);
int nes_cm_stop(void); int nes_cm_stop(void);
int nes_add_ref_cm_node(struct nes_cm_node *cm_node);
int nes_rem_ref_cm_node(struct nes_cm_node *cm_node);
#endif /* NES_CM_H */ #endif /* NES_CM_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -1090,6 +1090,8 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { ...@@ -1090,6 +1090,8 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
"LRO aggregated", "LRO aggregated",
"LRO flushed", "LRO flushed",
"LRO no_desc", "LRO no_desc",
"PAU CreateQPs",
"PAU DestroyQPs",
}; };
#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) #define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset)
...@@ -1305,6 +1307,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, ...@@ -1305,6 +1307,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated; target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated;
target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed; target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed;
target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc; target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc;
target_stat_values[++index] = atomic_read(&pau_qps_created);
target_stat_values[++index] = atomic_read(&pau_qps_destroyed);
} }
/** /**
......
此差异已折叠。
...@@ -3273,6 +3273,8 @@ static int init_6120_variables(struct qib_devdata *dd) ...@@ -3273,6 +3273,8 @@ static int init_6120_variables(struct qib_devdata *dd)
/* we always allocate at least 2048 bytes for eager buffers */ /* we always allocate at least 2048 bytes for eager buffers */
ret = ib_mtu_enum_to_int(qib_ibmtu); ret = ib_mtu_enum_to_int(qib_ibmtu);
dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU; dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU;
BUG_ON(!is_power_of_2(dd->rcvegrbufsize));
dd->rcvegrbufsize_shift = ilog2(dd->rcvegrbufsize);
qib_6120_tidtemplate(dd); qib_6120_tidtemplate(dd);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册