Commit 38137a51 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull infiniband/rdma updates from Roland Dreier:

 - mostly cxgb4 fixes unblocked by the merge of some prerequisites via
   the net tree

 - drop deprecated MSI-X API use.

 - a couple other miscellaneous things.

* tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband:
  RDMA/cxgb4: Fix over-dereference when terminating
  RDMA/cxgb4: Use uninitialized_var()
  RDMA/cxgb4: Add missing debug stats
  RDMA/cxgb4: Initialize reserved fields in a FW work request
  RDMA/cxgb4: Use pr_warn_ratelimited
  RDMA/cxgb4: Max fastreg depth depends on DSGL support
  RDMA/cxgb4: SQ flush fix
  RDMA/cxgb4: rmb() after reading valid gen bit
  RDMA/cxgb4: Endpoint timeout fixes
  RDMA/cxgb4: Use the BAR2/WC path for kernel QPs and T5 devices
  IB/mlx5: Add block multicast loopback support
  IB/mthca: Use pci_enable_msix_exact() instead of pci_enable_msix()
  IB/qib: Use pci_enable_msix_range() instead of pci_enable_msix()
parents 64ee9f32 5ae2866f
...@@ -173,12 +173,15 @@ static void start_ep_timer(struct c4iw_ep *ep) ...@@ -173,12 +173,15 @@ static void start_ep_timer(struct c4iw_ep *ep)
add_timer(&ep->timer); add_timer(&ep->timer);
} }
static void stop_ep_timer(struct c4iw_ep *ep) static int stop_ep_timer(struct c4iw_ep *ep)
{ {
PDBG("%s ep %p stopping\n", __func__, ep); PDBG("%s ep %p stopping\n", __func__, ep);
del_timer_sync(&ep->timer); del_timer_sync(&ep->timer);
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
c4iw_put_ep(&ep->com); c4iw_put_ep(&ep->com);
return 0;
}
return 1;
} }
static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb, static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb,
...@@ -1165,12 +1168,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) ...@@ -1165,12 +1168,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
/* /*
* Stop mpa timer. If it expired, then the state has * Stop mpa timer. If it expired, then
* changed and we bail since ep_timeout already aborted * we ignore the MPA reply. process_timeout()
* the connection. * will abort the connection.
*/ */
stop_ep_timer(ep); if (stop_ep_timer(ep))
if (ep->com.state != MPA_REQ_SENT)
return; return;
/* /*
...@@ -1375,15 +1377,12 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) ...@@ -1375,15 +1377,12 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
if (ep->com.state != MPA_REQ_WAIT)
return;
/* /*
* If we get more than the supported amount of private data * If we get more than the supported amount of private data
* then we must fail this connection. * then we must fail this connection.
*/ */
if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) { if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) {
stop_ep_timer(ep); (void)stop_ep_timer(ep);
abort_connection(ep, skb, GFP_KERNEL); abort_connection(ep, skb, GFP_KERNEL);
return; return;
} }
...@@ -1413,13 +1412,13 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) ...@@ -1413,13 +1412,13 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
if (mpa->revision > mpa_rev) { if (mpa->revision > mpa_rev) {
printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d," printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d,"
" Received = %d\n", __func__, mpa_rev, mpa->revision); " Received = %d\n", __func__, mpa_rev, mpa->revision);
stop_ep_timer(ep); (void)stop_ep_timer(ep);
abort_connection(ep, skb, GFP_KERNEL); abort_connection(ep, skb, GFP_KERNEL);
return; return;
} }
if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) { if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) {
stop_ep_timer(ep); (void)stop_ep_timer(ep);
abort_connection(ep, skb, GFP_KERNEL); abort_connection(ep, skb, GFP_KERNEL);
return; return;
} }
...@@ -1430,7 +1429,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) ...@@ -1430,7 +1429,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
* Fail if there's too much private data. * Fail if there's too much private data.
*/ */
if (plen > MPA_MAX_PRIVATE_DATA) { if (plen > MPA_MAX_PRIVATE_DATA) {
stop_ep_timer(ep); (void)stop_ep_timer(ep);
abort_connection(ep, skb, GFP_KERNEL); abort_connection(ep, skb, GFP_KERNEL);
return; return;
} }
...@@ -1439,7 +1438,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) ...@@ -1439,7 +1438,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
* If plen does not account for pkt size * If plen does not account for pkt size
*/ */
if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
stop_ep_timer(ep); (void)stop_ep_timer(ep);
abort_connection(ep, skb, GFP_KERNEL); abort_connection(ep, skb, GFP_KERNEL);
return; return;
} }
...@@ -1496,18 +1495,24 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) ...@@ -1496,18 +1495,24 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version, ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,
ep->mpa_attr.p2p_type); ep->mpa_attr.p2p_type);
__state_set(&ep->com, MPA_REQ_RCVD); /*
stop_ep_timer(ep); * If the endpoint timer already expired, then we ignore
* the start request. process_timeout() will abort
/* drive upcall */ * the connection.
mutex_lock(&ep->parent_ep->com.mutex); */
if (ep->parent_ep->com.state != DEAD) { if (!stop_ep_timer(ep)) {
if (connect_request_upcall(ep)) __state_set(&ep->com, MPA_REQ_RCVD);
/* drive upcall */
mutex_lock(&ep->parent_ep->com.mutex);
if (ep->parent_ep->com.state != DEAD) {
if (connect_request_upcall(ep))
abort_connection(ep, skb, GFP_KERNEL);
} else {
abort_connection(ep, skb, GFP_KERNEL); abort_connection(ep, skb, GFP_KERNEL);
} else { }
abort_connection(ep, skb, GFP_KERNEL); mutex_unlock(&ep->parent_ep->com.mutex);
} }
mutex_unlock(&ep->parent_ep->com.mutex);
return; return;
} }
...@@ -2265,7 +2270,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -2265,7 +2270,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
disconnect = 0; disconnect = 0;
break; break;
case MORIBUND: case MORIBUND:
stop_ep_timer(ep); (void)stop_ep_timer(ep);
if (ep->com.cm_id && ep->com.qp) { if (ep->com.cm_id && ep->com.qp) {
attrs.next_state = C4IW_QP_STATE_IDLE; attrs.next_state = C4IW_QP_STATE_IDLE;
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
...@@ -2325,10 +2330,10 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -2325,10 +2330,10 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
case CONNECTING: case CONNECTING:
break; break;
case MPA_REQ_WAIT: case MPA_REQ_WAIT:
stop_ep_timer(ep); (void)stop_ep_timer(ep);
break; break;
case MPA_REQ_SENT: case MPA_REQ_SENT:
stop_ep_timer(ep); (void)stop_ep_timer(ep);
if (mpa_rev == 1 || (mpa_rev == 2 && ep->tried_with_mpa_v1)) if (mpa_rev == 1 || (mpa_rev == 2 && ep->tried_with_mpa_v1))
connect_reply_upcall(ep, -ECONNRESET); connect_reply_upcall(ep, -ECONNRESET);
else { else {
...@@ -2433,7 +2438,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -2433,7 +2438,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
__state_set(&ep->com, MORIBUND); __state_set(&ep->com, MORIBUND);
break; break;
case MORIBUND: case MORIBUND:
stop_ep_timer(ep); (void)stop_ep_timer(ep);
if ((ep->com.cm_id) && (ep->com.qp)) { if ((ep->com.cm_id) && (ep->com.qp)) {
attrs.next_state = C4IW_QP_STATE_IDLE; attrs.next_state = C4IW_QP_STATE_IDLE;
c4iw_modify_qp(ep->com.qp->rhp, c4iw_modify_qp(ep->com.qp->rhp,
...@@ -3028,7 +3033,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp) ...@@ -3028,7 +3033,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) { if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) {
close = 1; close = 1;
if (abrupt) { if (abrupt) {
stop_ep_timer(ep); (void)stop_ep_timer(ep);
ep->com.state = ABORTING; ep->com.state = ABORTING;
} else } else
ep->com.state = MORIBUND; ep->com.state = MORIBUND;
...@@ -3462,6 +3467,16 @@ static void process_timeout(struct c4iw_ep *ep) ...@@ -3462,6 +3467,16 @@ static void process_timeout(struct c4iw_ep *ep)
__state_set(&ep->com, ABORTING); __state_set(&ep->com, ABORTING);
close_complete_upcall(ep, -ETIMEDOUT); close_complete_upcall(ep, -ETIMEDOUT);
break; break;
case ABORTING:
case DEAD:
/*
* These states are expected if the ep timed out at the same
* time as another thread was calling stop_ep_timer().
* So we silently do nothing for these states.
*/
abort = 0;
break;
default: default:
WARN(1, "%s unexpected state ep %p tid %u state %u\n", WARN(1, "%s unexpected state ep %p tid %u state %u\n",
__func__, ep, ep->hwtid, ep->com.state); __func__, ep, ep->hwtid, ep->com.state);
...@@ -3483,6 +3498,8 @@ static void process_timedout_eps(void) ...@@ -3483,6 +3498,8 @@ static void process_timedout_eps(void)
tmp = timeout_list.next; tmp = timeout_list.next;
list_del(tmp); list_del(tmp);
tmp->next = NULL;
tmp->prev = NULL;
spin_unlock_irq(&timeout_lock); spin_unlock_irq(&timeout_lock);
ep = list_entry(tmp, struct c4iw_ep, entry); ep = list_entry(tmp, struct c4iw_ep, entry);
process_timeout(ep); process_timeout(ep);
...@@ -3499,6 +3516,7 @@ static void process_work(struct work_struct *work) ...@@ -3499,6 +3516,7 @@ static void process_work(struct work_struct *work)
unsigned int opcode; unsigned int opcode;
int ret; int ret;
process_timedout_eps();
while ((skb = skb_dequeue(&rxq))) { while ((skb = skb_dequeue(&rxq))) {
rpl = cplhdr(skb); rpl = cplhdr(skb);
dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *))); dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *)));
...@@ -3508,8 +3526,8 @@ static void process_work(struct work_struct *work) ...@@ -3508,8 +3526,8 @@ static void process_work(struct work_struct *work)
ret = work_handlers[opcode](dev, skb); ret = work_handlers[opcode](dev, skb);
if (!ret) if (!ret)
kfree_skb(skb); kfree_skb(skb);
process_timedout_eps();
} }
process_timedout_eps();
} }
static DECLARE_WORK(skb_work, process_work); static DECLARE_WORK(skb_work, process_work);
...@@ -3521,8 +3539,13 @@ static void ep_timeout(unsigned long arg) ...@@ -3521,8 +3539,13 @@ static void ep_timeout(unsigned long arg)
spin_lock(&timeout_lock); spin_lock(&timeout_lock);
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
list_add_tail(&ep->entry, &timeout_list); /*
kickit = 1; * Only insert if it is not already on the list.
*/
if (!ep->entry.next) {
list_add_tail(&ep->entry, &timeout_list);
kickit = 1;
}
} }
spin_unlock(&timeout_lock); spin_unlock(&timeout_lock);
if (kickit) if (kickit)
......
...@@ -235,27 +235,21 @@ int c4iw_flush_sq(struct c4iw_qp *qhp) ...@@ -235,27 +235,21 @@ int c4iw_flush_sq(struct c4iw_qp *qhp)
struct t4_cq *cq = &chp->cq; struct t4_cq *cq = &chp->cq;
int idx; int idx;
struct t4_swsqe *swsqe; struct t4_swsqe *swsqe;
int error = (qhp->attr.state != C4IW_QP_STATE_CLOSING &&
qhp->attr.state != C4IW_QP_STATE_IDLE);
if (wq->sq.flush_cidx == -1) if (wq->sq.flush_cidx == -1)
wq->sq.flush_cidx = wq->sq.cidx; wq->sq.flush_cidx = wq->sq.cidx;
idx = wq->sq.flush_cidx; idx = wq->sq.flush_cidx;
BUG_ON(idx >= wq->sq.size); BUG_ON(idx >= wq->sq.size);
while (idx != wq->sq.pidx) { while (idx != wq->sq.pidx) {
if (error) { swsqe = &wq->sq.sw_sq[idx];
swsqe = &wq->sq.sw_sq[idx]; BUG_ON(swsqe->flushed);
BUG_ON(swsqe->flushed); swsqe->flushed = 1;
swsqe->flushed = 1; insert_sq_cqe(wq, cq, swsqe);
insert_sq_cqe(wq, cq, swsqe); if (wq->sq.oldest_read == swsqe) {
if (wq->sq.oldest_read == swsqe) { BUG_ON(swsqe->opcode != FW_RI_READ_REQ);
BUG_ON(swsqe->opcode != FW_RI_READ_REQ); advance_oldest_read(wq);
advance_oldest_read(wq);
}
flushed++;
} else {
t4_sq_consume(wq);
} }
flushed++;
if (++idx == wq->sq.size) if (++idx == wq->sq.size)
idx = 0; idx = 0;
} }
...@@ -678,7 +672,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe, ...@@ -678,7 +672,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
{ {
struct c4iw_qp *qhp = NULL; struct c4iw_qp *qhp = NULL;
struct t4_cqe cqe = {0, 0}, *rd_cqe; struct t4_cqe uninitialized_var(cqe), *rd_cqe;
struct t4_wq *wq; struct t4_wq *wq;
u32 credit = 0; u32 credit = 0;
u8 cqe_flushed; u8 cqe_flushed;
......
...@@ -682,7 +682,10 @@ static void c4iw_dealloc(struct uld_ctx *ctx) ...@@ -682,7 +682,10 @@ static void c4iw_dealloc(struct uld_ctx *ctx)
idr_destroy(&ctx->dev->hwtid_idr); idr_destroy(&ctx->dev->hwtid_idr);
idr_destroy(&ctx->dev->stid_idr); idr_destroy(&ctx->dev->stid_idr);
idr_destroy(&ctx->dev->atid_idr); idr_destroy(&ctx->dev->atid_idr);
iounmap(ctx->dev->rdev.oc_mw_kva); if (ctx->dev->rdev.bar2_kva)
iounmap(ctx->dev->rdev.bar2_kva);
if (ctx->dev->rdev.oc_mw_kva)
iounmap(ctx->dev->rdev.oc_mw_kva);
ib_dealloc_device(&ctx->dev->ibdev); ib_dealloc_device(&ctx->dev->ibdev);
ctx->dev = NULL; ctx->dev = NULL;
} }
...@@ -722,11 +725,31 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) ...@@ -722,11 +725,31 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
} }
devp->rdev.lldi = *infop; devp->rdev.lldi = *infop;
devp->rdev.oc_mw_pa = pci_resource_start(devp->rdev.lldi.pdev, 2) + /*
(pci_resource_len(devp->rdev.lldi.pdev, 2) - * For T5 devices, we map all of BAR2 with WC.
roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size)); * For T4 devices with onchip qp mem, we map only that part
devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa, * of BAR2 with WC.
devp->rdev.lldi.vr->ocq.size); */
devp->rdev.bar2_pa = pci_resource_start(devp->rdev.lldi.pdev, 2);
if (is_t5(devp->rdev.lldi.adapter_type)) {
devp->rdev.bar2_kva = ioremap_wc(devp->rdev.bar2_pa,
pci_resource_len(devp->rdev.lldi.pdev, 2));
if (!devp->rdev.bar2_kva) {
pr_err(MOD "Unable to ioremap BAR2\n");
return ERR_PTR(-EINVAL);
}
} else if (ocqp_supported(infop)) {
devp->rdev.oc_mw_pa =
pci_resource_start(devp->rdev.lldi.pdev, 2) +
pci_resource_len(devp->rdev.lldi.pdev, 2) -
roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size);
devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
devp->rdev.lldi.vr->ocq.size);
if (!devp->rdev.oc_mw_kva) {
pr_err(MOD "Unable to ioremap onchip mem\n");
return ERR_PTR(-EINVAL);
}
}
PDBG(KERN_INFO MOD "ocq memory: " PDBG(KERN_INFO MOD "ocq memory: "
"hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n", "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
...@@ -1003,9 +1026,11 @@ static int enable_qp_db(int id, void *p, void *data) ...@@ -1003,9 +1026,11 @@ static int enable_qp_db(int id, void *p, void *data)
static void resume_rc_qp(struct c4iw_qp *qp) static void resume_rc_qp(struct c4iw_qp *qp)
{ {
spin_lock(&qp->lock); spin_lock(&qp->lock);
t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc); t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc,
is_t5(qp->rhp->rdev.lldi.adapter_type), NULL);
qp->wq.sq.wq_pidx_inc = 0; qp->wq.sq.wq_pidx_inc = 0;
t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc); t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc,
is_t5(qp->rhp->rdev.lldi.adapter_type), NULL);
qp->wq.rq.wq_pidx_inc = 0; qp->wq.rq.wq_pidx_inc = 0;
spin_unlock(&qp->lock); spin_unlock(&qp->lock);
} }
......
...@@ -149,6 +149,8 @@ struct c4iw_rdev { ...@@ -149,6 +149,8 @@ struct c4iw_rdev {
struct gen_pool *ocqp_pool; struct gen_pool *ocqp_pool;
u32 flags; u32 flags;
struct cxgb4_lld_info lldi; struct cxgb4_lld_info lldi;
unsigned long bar2_pa;
void __iomem *bar2_kva;
unsigned long oc_mw_pa; unsigned long oc_mw_pa;
void __iomem *oc_mw_kva; void __iomem *oc_mw_kva;
struct c4iw_stats stats; struct c4iw_stats stats;
......
...@@ -259,8 +259,12 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, ...@@ -259,8 +259,12 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) { if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
stag_idx = c4iw_get_resource(&rdev->resource.tpt_table); stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
if (!stag_idx) if (!stag_idx) {
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.fail++;
mutex_unlock(&rdev->stats.lock);
return -ENOMEM; return -ENOMEM;
}
mutex_lock(&rdev->stats.lock); mutex_lock(&rdev->stats.lock);
rdev->stats.stag.cur += 32; rdev->stats.stag.cur += 32;
if (rdev->stats.stag.cur > rdev->stats.stag.max) if (rdev->stats.stag.cur > rdev->stats.stag.max)
......
...@@ -328,7 +328,7 @@ static int c4iw_query_device(struct ib_device *ibdev, ...@@ -328,7 +328,7 @@ static int c4iw_query_device(struct ib_device *ibdev,
props->max_mr = c4iw_num_stags(&dev->rdev); props->max_mr = c4iw_num_stags(&dev->rdev);
props->max_pd = T4_MAX_NUM_PD; props->max_pd = T4_MAX_NUM_PD;
props->local_ca_ack_delay = 0; props->local_ca_ack_delay = 0;
props->max_fast_reg_page_list_len = T4_MAX_FR_DEPTH; props->max_fast_reg_page_list_len = t4_max_fr_depth(use_dsgl);
return 0; return 0;
} }
......
...@@ -212,13 +212,23 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, ...@@ -212,13 +212,23 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
wq->db = rdev->lldi.db_reg; wq->db = rdev->lldi.db_reg;
wq->gts = rdev->lldi.gts_reg; wq->gts = rdev->lldi.gts_reg;
if (user) { if (user || is_t5(rdev->lldi.adapter_type)) {
wq->sq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) + u32 off;
(wq->sq.qid << rdev->qpshift);
wq->sq.udb &= PAGE_MASK; off = (wq->sq.qid << rdev->qpshift) & PAGE_MASK;
wq->rq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) + if (user) {
(wq->rq.qid << rdev->qpshift); wq->sq.udb = (u64 __iomem *)(rdev->bar2_pa + off);
wq->rq.udb &= PAGE_MASK; } else {
off += 128 * (wq->sq.qid & rdev->qpmask) + 8;
wq->sq.udb = (u64 __iomem *)(rdev->bar2_kva + off);
}
off = (wq->rq.qid << rdev->qpshift) & PAGE_MASK;
if (user) {
wq->rq.udb = (u64 __iomem *)(rdev->bar2_pa + off);
} else {
off += 128 * (wq->rq.qid & rdev->qpmask) + 8;
wq->rq.udb = (u64 __iomem *)(rdev->bar2_kva + off);
}
} }
wq->rdev = rdev; wq->rdev = rdev;
wq->rq.msn = 1; wq->rq.msn = 1;
...@@ -299,9 +309,10 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, ...@@ -299,9 +309,10 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
if (ret) if (ret)
goto free_dma; goto free_dma;
PDBG("%s sqid 0x%x rqid 0x%x kdb 0x%p squdb 0x%llx rqudb 0x%llx\n", PDBG("%s sqid 0x%x rqid 0x%x kdb 0x%p squdb 0x%lx rqudb 0x%lx\n",
__func__, wq->sq.qid, wq->rq.qid, wq->db, __func__, wq->sq.qid, wq->rq.qid, wq->db,
(unsigned long long)wq->sq.udb, (unsigned long long)wq->rq.udb); (__force unsigned long) wq->sq.udb,
(__force unsigned long) wq->rq.udb);
return 0; return 0;
free_dma: free_dma:
...@@ -425,6 +436,8 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe, ...@@ -425,6 +436,8 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
default: default:
return -EINVAL; return -EINVAL;
} }
wqe->send.r3 = 0;
wqe->send.r4 = 0;
plen = 0; plen = 0;
if (wr->num_sge) { if (wr->num_sge) {
...@@ -555,7 +568,8 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe, ...@@ -555,7 +568,8 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32); int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32);
int rem; int rem;
if (wr->wr.fast_reg.page_list_len > T4_MAX_FR_DEPTH) if (wr->wr.fast_reg.page_list_len >
t4_max_fr_depth(use_dsgl))
return -EINVAL; return -EINVAL;
wqe->fr.qpbinde_to_dcacpu = 0; wqe->fr.qpbinde_to_dcacpu = 0;
...@@ -650,9 +664,10 @@ static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc) ...@@ -650,9 +664,10 @@ static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc)
spin_lock_irqsave(&qhp->rhp->lock, flags); spin_lock_irqsave(&qhp->rhp->lock, flags);
spin_lock(&qhp->lock); spin_lock(&qhp->lock);
if (qhp->rhp->db_state == NORMAL) { if (qhp->rhp->db_state == NORMAL)
t4_ring_sq_db(&qhp->wq, inc); t4_ring_sq_db(&qhp->wq, inc,
} else { is_t5(qhp->rhp->rdev.lldi.adapter_type), NULL);
else {
add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
qhp->wq.sq.wq_pidx_inc += inc; qhp->wq.sq.wq_pidx_inc += inc;
} }
...@@ -667,9 +682,10 @@ static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) ...@@ -667,9 +682,10 @@ static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc)
spin_lock_irqsave(&qhp->rhp->lock, flags); spin_lock_irqsave(&qhp->rhp->lock, flags);
spin_lock(&qhp->lock); spin_lock(&qhp->lock);
if (qhp->rhp->db_state == NORMAL) { if (qhp->rhp->db_state == NORMAL)
t4_ring_rq_db(&qhp->wq, inc); t4_ring_rq_db(&qhp->wq, inc,
} else { is_t5(qhp->rhp->rdev.lldi.adapter_type), NULL);
else {
add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
qhp->wq.rq.wq_pidx_inc += inc; qhp->wq.rq.wq_pidx_inc += inc;
} }
...@@ -686,7 +702,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ...@@ -686,7 +702,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
enum fw_wr_opcodes fw_opcode = 0; enum fw_wr_opcodes fw_opcode = 0;
enum fw_ri_wr_flags fw_flags; enum fw_ri_wr_flags fw_flags;
struct c4iw_qp *qhp; struct c4iw_qp *qhp;
union t4_wr *wqe; union t4_wr *wqe = NULL;
u32 num_wrs; u32 num_wrs;
struct t4_swsqe *swsqe; struct t4_swsqe *swsqe;
unsigned long flag; unsigned long flag;
...@@ -792,7 +808,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ...@@ -792,7 +808,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
} }
if (!qhp->rhp->rdev.status_page->db_off) { if (!qhp->rhp->rdev.status_page->db_off) {
t4_ring_sq_db(&qhp->wq, idx); t4_ring_sq_db(&qhp->wq, idx,
is_t5(qhp->rhp->rdev.lldi.adapter_type), wqe);
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
} else { } else {
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
...@@ -806,7 +823,7 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, ...@@ -806,7 +823,7 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
{ {
int err = 0; int err = 0;
struct c4iw_qp *qhp; struct c4iw_qp *qhp;
union t4_recv_wr *wqe; union t4_recv_wr *wqe = NULL;
u32 num_wrs; u32 num_wrs;
u8 len16 = 0; u8 len16 = 0;
unsigned long flag; unsigned long flag;
...@@ -858,7 +875,8 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, ...@@ -858,7 +875,8 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
num_wrs--; num_wrs--;
} }
if (!qhp->rhp->rdev.status_page->db_off) { if (!qhp->rhp->rdev.status_page->db_off) {
t4_ring_rq_db(&qhp->wq, idx); t4_ring_rq_db(&qhp->wq, idx,
is_t5(qhp->rhp->rdev.lldi.adapter_type), wqe);
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
} else { } else {
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
...@@ -1352,6 +1370,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, ...@@ -1352,6 +1370,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
switch (attrs->next_state) { switch (attrs->next_state) {
case C4IW_QP_STATE_CLOSING: case C4IW_QP_STATE_CLOSING:
BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2); BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
t4_set_wq_in_error(&qhp->wq);
set_state(qhp, C4IW_QP_STATE_CLOSING); set_state(qhp, C4IW_QP_STATE_CLOSING);
ep = qhp->ep; ep = qhp->ep;
if (!internal) { if (!internal) {
...@@ -1359,18 +1378,18 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, ...@@ -1359,18 +1378,18 @@ 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);
} }
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:
t4_set_wq_in_error(&qhp->wq);
set_state(qhp, C4IW_QP_STATE_TERMINATE); set_state(qhp, C4IW_QP_STATE_TERMINATE);
qhp->attr.layer_etype = attrs->layer_etype; qhp->attr.layer_etype = attrs->layer_etype;
qhp->attr.ecode = attrs->ecode; qhp->attr.ecode = attrs->ecode;
t4_set_wq_in_error(&qhp->wq);
ep = qhp->ep; ep = qhp->ep;
disconnect = 1; disconnect = 1;
c4iw_get_ep(&qhp->ep->com);
if (!internal) if (!internal)
terminate = 1; terminate = 1;
else { else {
...@@ -1378,11 +1397,10 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, ...@@ -1378,11 +1397,10 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
if (ret) if (ret)
goto err; goto err;
} }
c4iw_get_ep(&qhp->ep->com);
break; break;
case C4IW_QP_STATE_ERROR: case C4IW_QP_STATE_ERROR:
set_state(qhp, C4IW_QP_STATE_ERROR);
t4_set_wq_in_error(&qhp->wq); t4_set_wq_in_error(&qhp->wq);
set_state(qhp, C4IW_QP_STATE_ERROR);
if (!internal) { if (!internal) {
abort = 1; abort = 1;
disconnect = 1; disconnect = 1;
...@@ -1677,11 +1695,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, ...@@ -1677,11 +1695,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
mm2->len = PAGE_ALIGN(qhp->wq.rq.memsize); mm2->len = PAGE_ALIGN(qhp->wq.rq.memsize);
insert_mmap(ucontext, mm2); insert_mmap(ucontext, mm2);
mm3->key = uresp.sq_db_gts_key; mm3->key = uresp.sq_db_gts_key;
mm3->addr = qhp->wq.sq.udb; mm3->addr = (__force unsigned long) qhp->wq.sq.udb;
mm3->len = PAGE_SIZE; mm3->len = PAGE_SIZE;
insert_mmap(ucontext, mm3); insert_mmap(ucontext, mm3);
mm4->key = uresp.rq_db_gts_key; mm4->key = uresp.rq_db_gts_key;
mm4->addr = qhp->wq.rq.udb; mm4->addr = (__force unsigned long) qhp->wq.rq.udb;
mm4->len = PAGE_SIZE; mm4->len = PAGE_SIZE;
insert_mmap(ucontext, mm4); insert_mmap(ucontext, mm4);
if (mm5) { if (mm5) {
......
...@@ -179,8 +179,12 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx) ...@@ -179,8 +179,12 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
kfree(entry); kfree(entry);
} else { } else {
qid = c4iw_get_resource(&rdev->resource.qid_table); qid = c4iw_get_resource(&rdev->resource.qid_table);
if (!qid) if (!qid) {
mutex_lock(&rdev->stats.lock);
rdev->stats.qid.fail++;
mutex_unlock(&rdev->stats.lock);
goto out; goto out;
}
mutex_lock(&rdev->stats.lock); mutex_lock(&rdev->stats.lock);
rdev->stats.qid.cur += rdev->qpmask + 1; rdev->stats.qid.cur += rdev->qpmask + 1;
mutex_unlock(&rdev->stats.lock); mutex_unlock(&rdev->stats.lock);
...@@ -322,8 +326,8 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size) ...@@ -322,8 +326,8 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6); unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6); PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
if (!addr) if (!addr)
printk_ratelimited(KERN_WARNING MOD "%s: Out of RQT memory\n", pr_warn_ratelimited(MOD "%s: Out of RQT memory\n",
pci_name(rdev->lldi.pdev)); pci_name(rdev->lldi.pdev));
mutex_lock(&rdev->stats.lock); mutex_lock(&rdev->stats.lock);
if (addr) { if (addr) {
rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT); rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT);
......
...@@ -84,7 +84,14 @@ struct t4_status_page { ...@@ -84,7 +84,14 @@ struct t4_status_page {
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge)) sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
#define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \ #define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
sizeof(struct fw_ri_immd)) & ~31UL) sizeof(struct fw_ri_immd)) & ~31UL)
#define T4_MAX_FR_DEPTH (1024 / sizeof(u64)) #define T4_MAX_FR_IMMD_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
#define T4_MAX_FR_DSGL 1024
#define T4_MAX_FR_DSGL_DEPTH (T4_MAX_FR_DSGL / sizeof(u64))
static inline int t4_max_fr_depth(int use_dsgl)
{
return use_dsgl ? T4_MAX_FR_DSGL_DEPTH : T4_MAX_FR_IMMD_DEPTH;
}
#define T4_RQ_NUM_SLOTS 2 #define T4_RQ_NUM_SLOTS 2
#define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS) #define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS)
...@@ -292,7 +299,7 @@ struct t4_sq { ...@@ -292,7 +299,7 @@ struct t4_sq {
unsigned long phys_addr; unsigned long phys_addr;
struct t4_swsqe *sw_sq; struct t4_swsqe *sw_sq;
struct t4_swsqe *oldest_read; struct t4_swsqe *oldest_read;
u64 udb; u64 __iomem *udb;
size_t memsize; size_t memsize;
u32 qid; u32 qid;
u16 in_use; u16 in_use;
...@@ -314,7 +321,7 @@ struct t4_rq { ...@@ -314,7 +321,7 @@ struct t4_rq {
dma_addr_t dma_addr; dma_addr_t dma_addr;
DEFINE_DMA_UNMAP_ADDR(mapping); DEFINE_DMA_UNMAP_ADDR(mapping);
struct t4_swrqe *sw_rq; struct t4_swrqe *sw_rq;
u64 udb; u64 __iomem *udb;
size_t memsize; size_t memsize;
u32 qid; u32 qid;
u32 msn; u32 msn;
...@@ -435,15 +442,67 @@ static inline u16 t4_sq_wq_size(struct t4_wq *wq) ...@@ -435,15 +442,67 @@ static inline u16 t4_sq_wq_size(struct t4_wq *wq)
return wq->sq.size * T4_SQ_NUM_SLOTS; return wq->sq.size * T4_SQ_NUM_SLOTS;
} }
static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc) /* This function copies 64 byte coalesced work request to memory
* mapped BAR2 space. For coalesced WRs, the SGE fetches data
* from the FIFO instead of from Host.
*/
static inline void pio_copy(u64 __iomem *dst, u64 *src)
{
int count = 8;
while (count) {
writeq(*src, dst);
src++;
dst++;
count--;
}
}
static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, u8 t5,
union t4_wr *wqe)
{ {
/* Flush host queue memory writes. */
wmb(); wmb();
if (t5) {
if (inc == 1 && wqe) {
PDBG("%s: WC wq->sq.pidx = %d\n",
__func__, wq->sq.pidx);
pio_copy(wq->sq.udb + 7, (void *)wqe);
} else {
PDBG("%s: DB wq->sq.pidx = %d\n",
__func__, wq->sq.pidx);
writel(PIDX_T5(inc), wq->sq.udb);
}
/* Flush user doorbell area writes. */
wmb();
return;
}
writel(QID(wq->sq.qid) | PIDX(inc), wq->db); writel(QID(wq->sq.qid) | PIDX(inc), wq->db);
} }
static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc) static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5,
union t4_recv_wr *wqe)
{ {
/* Flush host queue memory writes. */
wmb(); wmb();
if (t5) {
if (inc == 1 && wqe) {
PDBG("%s: WC wq->rq.pidx = %d\n",
__func__, wq->rq.pidx);
pio_copy(wq->rq.udb + 7, (void *)wqe);
} else {
PDBG("%s: DB wq->rq.pidx = %d\n",
__func__, wq->rq.pidx);
writel(PIDX_T5(inc), wq->rq.udb);
}
/* Flush user doorbell area writes. */
wmb();
return;
}
writel(QID(wq->rq.qid) | PIDX(inc), wq->db); writel(QID(wq->rq.qid) | PIDX(inc), wq->db);
} }
...@@ -568,6 +627,9 @@ static inline int t4_next_hw_cqe(struct t4_cq *cq, struct t4_cqe **cqe) ...@@ -568,6 +627,9 @@ static inline int t4_next_hw_cqe(struct t4_cq *cq, struct t4_cqe **cqe)
printk(KERN_ERR MOD "cq overflow cqid %u\n", cq->cqid); printk(KERN_ERR MOD "cq overflow cqid %u\n", cq->cqid);
BUG_ON(1); BUG_ON(1);
} else if (t4_valid_cqe(cq, &cq->queue[cq->cidx])) { } else if (t4_valid_cqe(cq, &cq->queue[cq->cidx])) {
/* Ensure CQE is flushed to memory */
rmb();
*cqe = &cq->queue[cq->cidx]; *cqe = &cq->queue[cq->cidx];
ret = 0; ret = 0;
} else } else
......
...@@ -282,6 +282,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, ...@@ -282,6 +282,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
props->sig_guard_cap = IB_GUARD_T10DIF_CRC | props->sig_guard_cap = IB_GUARD_T10DIF_CRC |
IB_GUARD_T10DIF_CSUM; IB_GUARD_T10DIF_CSUM;
} }
if (flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)
props->device_cap_flags |= IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) &
0xffffff; 0xffffff;
......
...@@ -807,6 +807,15 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, ...@@ -807,6 +807,15 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
spin_lock_init(&qp->sq.lock); spin_lock_init(&qp->sq.lock);
spin_lock_init(&qp->rq.lock); spin_lock_init(&qp->rq.lock);
if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) {
mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n");
return -EINVAL;
} else {
qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK;
}
}
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE; qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
...@@ -878,6 +887,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, ...@@ -878,6 +887,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
if (qp->wq_sig) if (qp->wq_sig)
in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_ENABLE_SIG); in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_ENABLE_SIG);
if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK)
in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_BLOCK_MCAST);
if (qp->scat_cqe && is_connected(init_attr->qp_type)) { if (qp->scat_cqe && is_connected(init_attr->qp_type)) {
int rcqe_sz; int rcqe_sz;
int scqe_sz; int scqe_sz;
......
...@@ -858,13 +858,9 @@ static int mthca_enable_msi_x(struct mthca_dev *mdev) ...@@ -858,13 +858,9 @@ static int mthca_enable_msi_x(struct mthca_dev *mdev)
entries[1].entry = 1; entries[1].entry = 1;
entries[2].entry = 2; entries[2].entry = 2;
err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); err = pci_enable_msix_exact(mdev->pdev, entries, ARRAY_SIZE(entries));
if (err) { if (err)
if (err > 0)
mthca_info(mdev, "Only %d MSI-X vectors available, "
"not using MSI-X\n", err);
return err; return err;
}
mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector;
mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector;
......
...@@ -197,46 +197,47 @@ static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, ...@@ -197,46 +197,47 @@ static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt,
struct qib_msix_entry *qib_msix_entry) struct qib_msix_entry *qib_msix_entry)
{ {
int ret; int ret;
u32 tabsize = 0; int nvec = *msixcnt;
u16 msix_flags;
struct msix_entry *msix_entry; struct msix_entry *msix_entry;
int i; int i;
ret = pci_msix_vec_count(dd->pcidev);
if (ret < 0)
goto do_intx;
nvec = min(nvec, ret);
/* We can't pass qib_msix_entry array to qib_msix_setup /* We can't pass qib_msix_entry array to qib_msix_setup
* so use a dummy msix_entry array and copy the allocated * so use a dummy msix_entry array and copy the allocated
* irq back to the qib_msix_entry array. */ * irq back to the qib_msix_entry array. */
msix_entry = kmalloc(*msixcnt * sizeof(*msix_entry), GFP_KERNEL); msix_entry = kmalloc(nvec * sizeof(*msix_entry), GFP_KERNEL);
if (!msix_entry) { if (!msix_entry)
ret = -ENOMEM;
goto do_intx; goto do_intx;
}
for (i = 0; i < *msixcnt; i++) for (i = 0; i < nvec; i++)
msix_entry[i] = qib_msix_entry[i].msix; msix_entry[i] = qib_msix_entry[i].msix;
pci_read_config_word(dd->pcidev, pos + PCI_MSIX_FLAGS, &msix_flags); ret = pci_enable_msix_range(dd->pcidev, msix_entry, 1, nvec);
tabsize = 1 + (msix_flags & PCI_MSIX_FLAGS_QSIZE); if (ret < 0)
if (tabsize > *msixcnt) goto free_msix_entry;
tabsize = *msixcnt; else
ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); nvec = ret;
if (ret > 0) {
tabsize = ret; for (i = 0; i < nvec; i++)
ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize);
}
do_intx:
if (ret) {
qib_dev_err(dd,
"pci_enable_msix %d vectors failed: %d, falling back to INTx\n",
tabsize, ret);
tabsize = 0;
}
for (i = 0; i < tabsize; i++)
qib_msix_entry[i].msix = msix_entry[i]; qib_msix_entry[i].msix = msix_entry[i];
kfree(msix_entry); kfree(msix_entry);
*msixcnt = tabsize; *msixcnt = nvec;
return;
if (ret) free_msix_entry:
qib_enable_intx(dd->pcidev); kfree(msix_entry);
do_intx:
qib_dev_err(dd, "pci_enable_msix_range %d vectors failed: %d, "
"falling back to INTx\n", nvec, ret);
*msixcnt = 0;
qib_enable_intx(dd->pcidev);
} }
/** /**
......
...@@ -179,6 +179,7 @@ enum { ...@@ -179,6 +179,7 @@ enum {
MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9, MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9,
MLX5_DEV_CAP_FLAG_APM = 1LL << 17, MLX5_DEV_CAP_FLAG_APM = 1LL << 17,
MLX5_DEV_CAP_FLAG_ATOMIC = 1LL << 18, MLX5_DEV_CAP_FLAG_ATOMIC = 1LL << 18,
MLX5_DEV_CAP_FLAG_BLOCK_MCAST = 1LL << 23,
MLX5_DEV_CAP_FLAG_ON_DMND_PG = 1LL << 24, MLX5_DEV_CAP_FLAG_ON_DMND_PG = 1LL << 24,
MLX5_DEV_CAP_FLAG_CQ_MODER = 1LL << 29, MLX5_DEV_CAP_FLAG_CQ_MODER = 1LL << 29,
MLX5_DEV_CAP_FLAG_RESIZE_CQ = 1LL << 30, MLX5_DEV_CAP_FLAG_RESIZE_CQ = 1LL << 30,
......
...@@ -146,6 +146,7 @@ enum { ...@@ -146,6 +146,7 @@ enum {
enum { enum {
MLX5_QP_LAT_SENSITIVE = 1 << 28, MLX5_QP_LAT_SENSITIVE = 1 << 28,
MLX5_QP_BLOCK_MCAST = 1 << 30,
MLX5_QP_ENABLE_SIG = 1 << 31, MLX5_QP_ENABLE_SIG = 1 << 31,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment