InfiniBand/RDMA updates for 3.15-rc4:

- cxgb4 hardware driver fixes
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJTYuHPAAoJEENa44ZhAt0hmHQP/2KKs001nv2MvjfUbn/VHxdq
 5Hv/zlONa68QGYWxvA//tEvqUlbVr19gkBlbIwJ+SZ75BbsnoeeI27HEEiRzFX5t
 rQs+KnK7CYifDfzezfU1Ls8xjVhJfqQ09R6gwrcFutgM51bCIOl6AUxKk51MmdV4
 d14XqWph8xPt5vs3hH6mzM9e1D9fBDJvkbAreT/sF4/broNFtBaHWe06fp7l7up/
 lAG2Ynt6Uhc8HzfOFMY92uFk16QY+yGoUw64M9fYISx1smJUsVvEKyF3j0GJNbVt
 yR6qlHVMmzsI/dlQcB5x8XK9vX+jWq685C/MZ4ooeZwcVeT2qM2nT/gwVhsDYUNp
 2D1vtiHbj8xNB87VdkVy5fQqcR61/gjX73NK/1qh/mul9GsekbTXfxDEcwMQV+Fn
 FMZNXms3iF35Wy7UkdI6fXgb+3Oq/FSADAyY0ntl9TLXg1Z4qpz6G6UxML6kznEN
 gNdQZxK+MKA16hPIdfKY8acTluPnG8K7tmy5G3zlVVAbLMvGhAE+M+cZATqRFZlC
 gddxtXE7j5eSfYwwl+wgbRP09HRmnHInQs2PUI2Vy5L7vIZAuqlQ9GW56FFhnGJh
 PEgQErUJf0NnnD86y1odxlvbdBTd94iElKhRRxwWEhPSvLb+ZeueDqZeqQUcobYw
 tXislPDdtLkZmOohOH+i
 =Y+Sv
 -----END PGP SIGNATURE-----

Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband

Pull infiniband/rdma fixes from Roland Dreier:
 "cxgb4 hardware driver fixes"

* tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband:
  RDMA/cxgb4: Update Kconfig to include Chelsio T5 adapter
  RDMA/cxgb4: Only allow kernel db ringing for T4 devs
  RDMA/cxgb4: Force T5 connections to use TAHOE congestion control
  RDMA/cxgb4: Fix endpoint mutex deadlocks
This commit is contained in:
Linus Torvalds 2014-05-01 17:52:42 -07:00
commit b7270cce7d
5 changed files with 55 additions and 18 deletions

View File

@ -1,10 +1,10 @@
config INFINIBAND_CXGB4 config INFINIBAND_CXGB4
tristate "Chelsio T4 RDMA Driver" tristate "Chelsio T4/T5 RDMA Driver"
depends on CHELSIO_T4 && INET && (IPV6 || IPV6=n) depends on CHELSIO_T4 && INET && (IPV6 || IPV6=n)
select GENERIC_ALLOCATOR select GENERIC_ALLOCATOR
---help--- ---help---
This is an iWARP/RDMA driver for the Chelsio T4 1GbE and This is an iWARP/RDMA driver for the Chelsio T4 and T5
10GbE adapters. 1GbE, 10GbE adapters and T5 40GbE adapter.
For general information about Chelsio and our products, visit For general information about Chelsio and our products, visit
our website at <http://www.chelsio.com>. our website at <http://www.chelsio.com>.

View File

@ -587,6 +587,10 @@ static int send_connect(struct c4iw_ep *ep)
opt2 |= SACK_EN(1); opt2 |= SACK_EN(1);
if (wscale && enable_tcp_window_scaling) if (wscale && enable_tcp_window_scaling)
opt2 |= WND_SCALE_EN(1); opt2 |= WND_SCALE_EN(1);
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
opt2 |= T5_OPT_2_VALID;
opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
}
t4_set_arp_err_handler(skb, NULL, act_open_req_arp_failure); t4_set_arp_err_handler(skb, NULL, act_open_req_arp_failure);
if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) { if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
@ -996,7 +1000,7 @@ static void close_complete_upcall(struct c4iw_ep *ep, int status)
static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp) static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
{ {
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
state_set(&ep->com, ABORTING); __state_set(&ep->com, ABORTING);
set_bit(ABORT_CONN, &ep->com.history); set_bit(ABORT_CONN, &ep->com.history);
return send_abort(ep, skb, gfp); return send_abort(ep, skb, gfp);
} }
@ -1154,7 +1158,7 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)
return credits; return credits;
} }
static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) static int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
{ {
struct mpa_message *mpa; struct mpa_message *mpa;
struct mpa_v2_conn_params *mpa_v2_params; struct mpa_v2_conn_params *mpa_v2_params;
@ -1164,6 +1168,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
struct c4iw_qp_attributes attrs; struct c4iw_qp_attributes attrs;
enum c4iw_qp_attr_mask mask; enum c4iw_qp_attr_mask mask;
int err; int err;
int disconnect = 0;
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
@ -1173,7 +1178,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
* will abort the connection. * will abort the connection.
*/ */
if (stop_ep_timer(ep)) if (stop_ep_timer(ep))
return; return 0;
/* /*
* If we get more than the supported amount of private data * If we get more than the supported amount of private data
@ -1195,7 +1200,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
* if we don't even have the mpa message, then bail. * if we don't even have the mpa message, then bail.
*/ */
if (ep->mpa_pkt_len < sizeof(*mpa)) if (ep->mpa_pkt_len < sizeof(*mpa))
return; return 0;
mpa = (struct mpa_message *) ep->mpa_pkt; mpa = (struct mpa_message *) ep->mpa_pkt;
/* Validate MPA header. */ /* Validate MPA header. */
@ -1235,7 +1240,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
* We'll continue process when more data arrives. * We'll continue process when more data arrives.
*/ */
if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
return; return 0;
if (mpa->flags & MPA_REJECT) { if (mpa->flags & MPA_REJECT) {
err = -ECONNREFUSED; err = -ECONNREFUSED;
@ -1337,9 +1342,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
attrs.layer_etype = LAYER_MPA | DDP_LLP; attrs.layer_etype = LAYER_MPA | DDP_LLP;
attrs.ecode = MPA_NOMATCH_RTR; attrs.ecode = MPA_NOMATCH_RTR;
attrs.next_state = C4IW_QP_STATE_TERMINATE; attrs.next_state = C4IW_QP_STATE_TERMINATE;
attrs.send_term = 1;
err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
err = -ENOMEM; err = -ENOMEM;
disconnect = 1;
goto out; goto out;
} }
@ -1355,9 +1362,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
attrs.layer_etype = LAYER_MPA | DDP_LLP; attrs.layer_etype = LAYER_MPA | DDP_LLP;
attrs.ecode = MPA_INSUFF_IRD; attrs.ecode = MPA_INSUFF_IRD;
attrs.next_state = C4IW_QP_STATE_TERMINATE; attrs.next_state = C4IW_QP_STATE_TERMINATE;
attrs.send_term = 1;
err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
err = -ENOMEM; err = -ENOMEM;
disconnect = 1;
goto out; goto out;
} }
goto out; goto out;
@ -1366,7 +1375,7 @@ err:
send_abort(ep, skb, GFP_KERNEL); send_abort(ep, skb, GFP_KERNEL);
out: out:
connect_reply_upcall(ep, err); connect_reply_upcall(ep, err);
return; return disconnect;
} }
static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
@ -1524,6 +1533,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
unsigned int tid = GET_TID(hdr); unsigned int tid = GET_TID(hdr);
struct tid_info *t = dev->rdev.lldi.tids; struct tid_info *t = dev->rdev.lldi.tids;
__u8 status = hdr->status; __u8 status = hdr->status;
int disconnect = 0;
ep = lookup_tid(t, tid); ep = lookup_tid(t, tid);
if (!ep) if (!ep)
@ -1539,7 +1549,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
switch (ep->com.state) { switch (ep->com.state) {
case MPA_REQ_SENT: case MPA_REQ_SENT:
ep->rcv_seq += dlen; ep->rcv_seq += dlen;
process_mpa_reply(ep, skb); disconnect = process_mpa_reply(ep, skb);
break; break;
case MPA_REQ_WAIT: case MPA_REQ_WAIT:
ep->rcv_seq += dlen; ep->rcv_seq += dlen;
@ -1555,13 +1565,16 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
ep->com.state, ep->hwtid, status); ep->com.state, ep->hwtid, status);
attrs.next_state = C4IW_QP_STATE_TERMINATE; attrs.next_state = C4IW_QP_STATE_TERMINATE;
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
disconnect = 1;
break; break;
} }
default: default:
break; break;
} }
mutex_unlock(&ep->com.mutex); mutex_unlock(&ep->com.mutex);
if (disconnect)
c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
return 0; return 0;
} }
@ -2009,6 +2022,10 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
if (tcph->ece && tcph->cwr) if (tcph->ece && tcph->cwr)
opt2 |= CCTRL_ECN(1); opt2 |= CCTRL_ECN(1);
} }
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
opt2 |= T5_OPT_2_VALID;
opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
}
rpl = cplhdr(skb); rpl = cplhdr(skb);
INIT_TP_WR(rpl, ep->hwtid); INIT_TP_WR(rpl, ep->hwtid);
@ -3482,9 +3499,9 @@ static void process_timeout(struct c4iw_ep *ep)
__func__, ep, ep->hwtid, ep->com.state); __func__, ep, ep->hwtid, ep->com.state);
abort = 0; abort = 0;
} }
mutex_unlock(&ep->com.mutex);
if (abort) if (abort)
abort_connection(ep, NULL, GFP_KERNEL); abort_connection(ep, NULL, GFP_KERNEL);
mutex_unlock(&ep->com.mutex);
c4iw_put_ep(&ep->com); c4iw_put_ep(&ep->com);
} }

View File

@ -435,6 +435,7 @@ struct c4iw_qp_attributes {
u8 ecode; u8 ecode;
u16 sq_db_inc; u16 sq_db_inc;
u16 rq_db_inc; u16 rq_db_inc;
u8 send_term;
}; };
struct c4iw_qp { struct c4iw_qp {

View File

@ -1388,11 +1388,12 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
qhp->attr.layer_etype = attrs->layer_etype; qhp->attr.layer_etype = attrs->layer_etype;
qhp->attr.ecode = attrs->ecode; qhp->attr.ecode = attrs->ecode;
ep = qhp->ep; ep = qhp->ep;
disconnect = 1; if (!internal) {
c4iw_get_ep(&qhp->ep->com); c4iw_get_ep(&qhp->ep->com);
if (!internal)
terminate = 1; terminate = 1;
else { disconnect = 1;
} else {
terminate = qhp->attr.send_term;
ret = rdma_fini(rhp, qhp, ep); ret = rdma_fini(rhp, qhp, ep);
if (ret) if (ret)
goto err; goto err;
@ -1776,11 +1777,15 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
/* /*
* Use SQ_PSN and RQ_PSN to pass in IDX_INC values for * Use SQ_PSN and RQ_PSN to pass in IDX_INC values for
* ringing the queue db when we're in DB_FULL mode. * ringing the queue db when we're in DB_FULL mode.
* Only allow this on T4 devices.
*/ */
attrs.sq_db_inc = attr->sq_psn; attrs.sq_db_inc = attr->sq_psn;
attrs.rq_db_inc = attr->rq_psn; attrs.rq_db_inc = attr->rq_psn;
mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0; mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0;
mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0; mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0;
if (is_t5(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) &&
(mask & (C4IW_QP_ATTR_SQ_DB|C4IW_QP_ATTR_RQ_DB)))
return -EINVAL;
return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0); return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0);
} }

View File

@ -836,4 +836,18 @@ struct ulptx_idata {
#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE) #define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U) #define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U)
enum { /* TCP congestion control algorithms */
CONG_ALG_RENO,
CONG_ALG_TAHOE,
CONG_ALG_NEWRENO,
CONG_ALG_HIGHSPEED
};
#define S_CONG_CNTRL 14
#define M_CONG_CNTRL 0x3
#define V_CONG_CNTRL(x) ((x) << S_CONG_CNTRL)
#define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL)
#define T5_OPT_2_VALID (1 << 31)
#endif /* _T4FW_RI_API_H_ */ #endif /* _T4FW_RI_API_H_ */